Flex IoC
Napisałem więc mikrokontener IoC dla FLEX, i udostępniłem go społeczności opensource.
Mały test, źródła i przykład użycia.
netConnection.call( "calculatorService.add", new Responder( onAdd ), 2, 2 );Do tworzenia testów jednostkowych w Flex zalecana jest biblioteka FlexUnit. Wkładając ten kod do FlexUnit, zauważmy, że nie radzi on sobie z metodami asynchronicznymi – chyba że je specjalnie zaznaczymy:
netConnection.call( "calculatorService.add", new Responder( addAsync(onAdd,5000) ), 2, 2 );Jednak to jeszcze nie działa. Metoda
addAsync dostosowana jest do pracy z zdarzeniami. Próbując uruchomić ten kod otrzymam błąd: TypeError: Error #1034: Type Coercion failed: cannot convert "4" to flash.events.Event. Poradziłem sobie z tym w następujący sposób:
netConnection.call("calculatorService.add", new Responder( myAddAsync( testSum ) ), 2, 2 );
public function testSum(a:Number):void {
assertEquals(4,a);
}
//
public function myAddAsync(f:Function):Function {
// wyciąga dane z eventa
var f1:Function = function(e:DynamicEvent):void {
f.call(this,e.result);
}
// buduje asynchroniczną funkcję, operującą na zdarzeniach
var f2:Function = addAsync(f1, 5000);
// pakuje odpowiedź serwera do zdarzenia
var f3:Function = function(a:*):void {
var e:DynamicEvent = new DynamicEvent("MyDynamicEvent");
e.result = a;
f2.call(this, e);
}
return f3;
}
Ta ostatnia funkcja wygląda dość dziwnie – ale robi to co musi. Daje mi możliwość budowania testów integracyjnych – współpraca Flex’a z serwerem Red5.
Udało mi się zamapować klasę Java (reprezentującą encję JPA) do klasy Flash AS3. Serwerem jest RED5, protokołem RTMP, kodowanie obiektów AMF0. Miałem dwa problemy:
Zacząłem od OpenJPA. Napotkałem na następujący problem. Obiekty klas Java nie zawsze były mapowane do odpowiedników AS3. Otóż gdy OpenJPA pobiera encje z bazy to zwraca klasy Proxy dziedziczące po klasach encji. RED5 nie potrafi sobie z tym poradzić, i nie wie jak ma mapować klasy Proxy dla Flasha. Doraźnym rozwiązaniem problemu jest wybór innego dostawcy JPA – Hibernate. Fajnie, że tak można.
Drugi problem, to mapowanie typu Number. Typ Number występuje w Flashu i teoretycznie nie należy mu przypisywać wartości NULL. Gdy ustawię w Flashu typ Number na NULL i wyślę go do serwera RED5, to w Javie otrzymam 0 (zero) – prawie to samo a działa bardzo źle. Doraźnym rozwiązaniem problemu jest dla mnie zastąpienie typu Number typem String w klasach AS3.
Adobe Flex to interesująca technologia i warto się z nią zapoznać.
Programując w Flex natrafimy na pewno na zdarzenia (Event). Metodą prób i błędów doszedłem do tego jak je programować, tak by być w zgodzie z Flex Builder. Najpierw rozszerzam klasę flash.events.Event, np.:
package eu.jakubiak.net
{
public class NetConnectionEvent extends Event
{
public static const CONNECTED:String = "connected";
W klasie tej, definiuje stałe – nazwy dla moich nowych zdarzeń. Nazwy stałych powinny być pisane dużymi literami z podkreśleniami, np.: DANE_OTRZYMANE. Wartości powinny być z kolei pisane małymi literami, zgodnie z standardem nazewnictwa w języku Java, np: daneOtrzymane.
flash.events.EventDispatcher (prawie wszystkie klasy Flexa dziedziczą po EventDispatcher). Na przykład:
[Event(name="connected", type="eu.jakubiak.net.NetConnectionEvent")]
public class NetConnection extends flash.net.NetConnection
{
this.dispatchEvent(new NetConnectionEvent(NetConnectionEvent.CONNECTED));
Przed nazwą klasy w nawiasach kwadratowych definiujemy metadane klasy. [Event(name= – nazwa zdarzenia powinna zostać zapisana w notacji Java, czyli zwykle małe litery a kolejne słowo z dużej i musi odpowiadać wartości stałej zadeklarowanej w klasie dziedziczącej po Event, np: CONNECTED na connected lub DANE_OTRZYMANE na daneOtrzymane. Natomiast typ zdarzenia ([Event(type=) powinien być pełną nazwą klasy. Wysyłanie zdarzeń jest proste – tak jak na przykładzie dispatchEvent.
Dzięki takiemu nazywaniu zdarzeń Flex Builder podpowiada mi składnie w metodzie addEventListener oraz podczas edycji dokumentów mxml. Poza tym, godząc się na pewną konwencję nazewniczą mam w kodzie porządek.
cursor: pointer. We Flex można to napisać tak: <mx:.. buttonMode="true"
mencoder Film.avi -o Film.flv -vf scale=400:300 -oac lavc -ovc lavc \ -lavcopts vcodec=flv:acodec=mp3:abitrate=56:vbitrate=128 \ -ffourcc FLV1 -srate 22050 -of lavf \ -lavfopts i_certify_that_my_video_stream_does_not_use_b_framesMPlayer (MEncoder) sporo potrafi! Nie szukam głębi, w parametrach przekazywanych do MEncoder’a, cieszę się tylko że działa.