GWT – kliens szerver határán

Lassan 1 éve foglalkozok GWT-vel. Gondoltam eljött az idő, hogy röviden számotvessek magammal, milyen is volt ez az 1 év…
A maga a koncepció, ahogy a megvalósították, hogy java-ban hozhatunk létre böngészőfüggetlen javascriptet, a szabad forráskódú fejlesztés, hogy a rendszer minden részének működését forráskód szinten látjuk, hogy módosíthatók (vagy utánozhatóak) az alap implementációk, és még sorolhatnám. Ez kétségtelenül megérdemel egy + jelet 🙂

Persze az ismerkedés nem volt egyszerű, néhány fejlesztési alapvetést, és nézetet adaptálni kellett, tehát aki gwt-re adja a fejét (szerintem ez ajax-ra, sőt minden asszinkron működésű programra vonatkozik) kénytelen picit „másképp gondolkodni”.
A tapasztalataim részletekbe menő ismertetését most sajnos nem írom le, de néhány gondolatot azért igen.

Nem, nem bántam meg, hogy gwt-be fejlesztek, és ha újra kellene választanom, én ismét ezt választanám. (bár ilyen téren mindegy miben kell fejleszteni, ha valaki elég eltökélt, bármivel tud nagyszerű dolgokat készíteni, max sok idő, és áldozat árán 😉 )

A GWT alkalmazásokban gondolkozik, és ezért „nagy alkalmazás” fejlesztése során felmerülnek problémák (pl. a memória használat, kódok mérete). Ha viszont egy picit tovább gondoljuk a dolgot, minden nagy alkalmazás nem más mint kis alkalmazások összessége, amik viszont játszi könnyedséggel integrálhatóak egy nagy alkalmazásba (ez a megközelítés egyébként is rengeteg előnnyel jár, mint pl. az egymástól független verziókezelés, stb).

Kliens és szerver oldali kódok az RPC hívások miatti duplikálása (ami sajnos mostanában elég bevett szokás), egy hibás koncepció. Rengeteg fejlesztő duplikálja a DAO kódokat (pl. egy tábla leíró osztály), hogy a gwt számára a böngészőbe át tudja adni a benne lévő adatot. Erre nincs szükség. Amikor a gwt fordít, akkor a gwt fordító fordít, amiből javascript lesz. Amikor a java fordít abból pedig szerver oldali java class fájlok. A két folyamat eltéréséből adódik, hogy megtehető az, hogy a gwt fordítás alatt az ember picit más class-okat használ fel, mint a java fordítás alatt.
Egy életből vett példa, hogy érthető legyen:

Tegyük fel, hibernate-t használunk, és csinálunk egy partner osztályt:

@Entity
@Table(name = "Partner")
public class Partner {

@Id
@GeneratedValue
@Column(name = "PARTNER_ID")
public long getId() {
return this.id;
}



Ha ezt gwt oldalon el szeretnénk érni két általános dolgot kell tennünk:
– levinni a kódot a kliens oldalra
– implementálni az IsSerializable típust

A második dolog viszonylag egyszerű, ellenben amikor a kliens oldalra mozgatjuk az osztályt, akkor a gwt fordító kedvesen figyelmeztet, hogy kliens oldalon nem lehet szerver oldali komponenseket használni (mint a hibernate notáció).

Persze azért mondja ezt, mert nem tudja, hogy mi ezeket a kódokat kliens oldalon nem is akarjuk használni. A megoldás kézenfekvő, és egyszerű. A hibernate forrásából ki kell szedni azokat a fájlokat amiket kliens oldalon is használunk. A forrásban használt függvényeket meghagyuk, de az implementációs részt töröljük. Fordítunk belőlle egy olyan jar-t amiben benne van a forrás is, és a fordított funkció nélküli class fájlok, megmondjuk a gwt fordítónak, hogy tessék ezt használni.

A kód lefordul, a javascript a hibernate notációval ellátott, de funkcióval nem rendelkező osztályokat használja, ellenben amikor ez az adat felkerül szerver oldalra, ott már a hibernate funkcionalitás is elérhetővé vállik, nincs szükség az osztályok duplikálására.

Ugyanez az elv használható a validációk során is, a jól megírt validációt végző keretrendszer minden esetben használható mind kliens mind szerver oldalon (optimális esetben notációkkal, pl. a hibernate által használt dao osztályban… ).

Részemről a geek hajlamok ezzel letudva a hétvégére 🙂

Waves WaveShell VST plugin extract

Waves Pluginek
Ha valaki kever digitálisan, és használ plugineket, valószínű nem kell bemutatni neki a Waves cég termékeit. Kicsit sajátos megközelítés, hogy a plugineket nem külön dll-ben szállítják, hanem egy nagy monstre DLL-ben (WaveShell*.dll).

Ez felvet néhány problémát:
• A plugin töltési idő lassul
• Nem rendsezhetőek a Waves pluginek tetszőleges könyvtárakba
• Némelyik plugin „beragad” (főként régebbi waves, és újabb host verziónál)

A problémák megoldására szolgál a shell2vst alkalmazás, amivel lehetőségünk van a WaveShell-ből kivarázsolni a különálló VST plugineket.

A generálás menete:
• A WaveShelleket töröljük a VST könyvtárból
• A generátort másoljuk a WavesShell-ek mellé, pl c:\Program Files\Waves\WaveShells\
• A használat során, paraméternek meg kell adni a WaveShell dll-t és a Waves könyvtárba legenerálja az egyéni vst plugin dll-eket, amit másolhatunk is a VST plugin könyvtárba.

Figyelem! A kigenerált dll-ekbe beleíródik a teljes elérése a WavesShell dll-nek (amit majd a vst használ betöltés után) szóval lehetőleg a WavesShell eredeti helyén végezzük el a generálást, mert a WaveShell-nek továbbra is elérhetőnek kell maradnia!

A shell2vst fájlt letükröztem magamhoz is, el ne vesszen, letölthető innen.

Gwt memory leak

Ezer éve nem volt módom (és időm) írni, de most sikerült, megtaláltam, és megengedek magamnak ekkora pihenőt. Jó ideje egy GWT alapú alkalmazás készülget, és eddig szinte minden „simán” ment a fejlesztés során, volt néhány kisebb trükk, pár gwt-s osztályt át kellett írni, de összességében szerintem a GWT keretrendszer jól teljesített, sőt felül is múlta az elvárásaimat.
Egészen tegnapig, amikor is azt jelezték, hogy az alkalmazás sok memóriát fogyaszt. Ilyenkor az ember hajlamos azt mondani, hogy persze, hiszen nagy alkalmazás, de a C++-hoz szokott énem rögtön kétségbe esett, ez bizony memory leak. Gyors mérések után a tünetek egyértelműek voltak. Az alkalmazás leak-el, menüpontonként pár megát. Az látszott, hogy nem a javascript memóriahasználata nő (google chrome kiírja), hanem a böngésző memória használata. Ekkor kezdtem gyanakodni, hogy ezt pedig mi rontottuk el, és a végén igazolódott is ez az állítás. A hibát csak a tanúsága miatt megosztom mindenkivel.

Az eredeti kód:


private void setLoadingVisible(boolean pVisible) {
if (pVisible) {
waitingPopup=new APopupWaiting(msgs.main_waitingmessage(), Window.getClientWidth(),Window.getClientHeight());
waitingPopup.center();
}
if (!pVisible && waitingPopup.isVisible()) {
waitingPopup.hide();
}

Ez a szolgáltatás arra szolgál, hogy ha tölteni kell, akkor kirak egy töltés dialógust. Első látásra minden rendben van, létrehoz egy újat, megjeleníti, vagy elrejti a megadott paraméter alapján. Az implementáció hibás, az már érdekesebb kérdés miért. Normál esetben maximum egy nem optimális implementáció lenne, hiszen miért hozunk mindig létre valamit, ami már egyszer létre lett hozva, ráadásul sohasem változik. Sokkal nagyobb probléma, hogy ez javascriptben fut, és a GWT a változót (és a hozzá javascript által generált HTML dom-ot) csak akkor szabadítja fel, ha már nincs rá referencia. Ellenben a PopupDialogra igen is lesz referencia, és nem a DOM-on keresztül, hanem azon eseménykezelők miatt, amikre működéséből fakadóan feliratkozott. Tehát az objektum lóg a levegőben, és fogyasztja a memóriát.

Egy lehetséges megoldás:


private void setLoadingVisible(boolean pVisible) {
if (pVisible) {
if (waitingPopup==null) {
waitingPopup=new APopupWaiting(msgs.main_waitingmessage(),
Window.getClientWidth(),Window.getClientHeight());
waitingPopup.center();
} else {
waitingPopup.center();
}
}
if (!pVisible && waitingPopup!=null) {
waitingPopup.hide();
}
}

Végezetül egy kis olvasmány (de az ellen nem véd ;):
http://code.google.com/p/google-web-toolkit/wiki/DomEventsAndMemoryLeaks

voji – third

Most hétvégén rátaláltam a Casio DH-800-amra, amit nem használtam már idestova 10+x éve. Így sok év távlatából sem nagyon veszett el a hangszer varázsa, de ennek inkább az „első hangszerem” érzés az oka, és nem a nagyszerű kivitelezés. Játszogattam kicsit vele, az eredmény lentebb, bár nem foglalkoztam sokat a részek összerakásával, mert a zenét valószínű már csak live 6-ból fogom játszani.
voji – thrid

XFCE Ubuntu alatt

XFCE telepítése:
sudo aptitude update && sudo aptitude install xubuntu-desktop

Az alapértelmezett session managert az alábbi utasítással állíthatjuk be:
sudo update-alternatives --config x-window-manager

Windows XP optimalizáció (zenéhez) #2

A Windows XP a végtelenségig optimalizálható, ezt mi sem mutatja jobban, min a sok több milliószoros sebességnövekedést igérő cikk, leírás, és szoftver. Persze a hardvernek, és a Windows XP-nek is vannak korlátai, de a fölösleges doglok kikapcsolgatásával el lehet érni, hogy inkább a hardver korlátait érezzük mint a Windows korlátait.
Tehát a további optimalizációk:

http://www.connectedinternet.co.uk/2007/02/06/the-complete-guide-to-optimising-windows-xp/

És egy elég részletes, de nem túl terjengős leírás a windows szolgáltatásokról:
http://beemerworld.com/tips/servicesxp.htm

MySpace

Bár még nem egésszen éreztem időszerűnek, csináltam egy myspace oldalt magamnak. Egyenlőre csak régi zenék vannak fennt, de reményeim szerint hamarosan lesz rajta pár új zene is.

Az url mindenki meglepetésére:
http://www.myspace.com/voji

Windows DPC

Amikor az ember időkritikus (valósidejű) dolgokra használja a számítógépét, szeretne biztosra menni. Ennek elengedhetetlen kelléke egy külön telepített Windows 32 bit-es windows xp, és az előző cikkben említett Windows XP Focusrite optimalizációk. De mi a teendő akkor, ha ezek után is a félelmetes Audio Dropout jelenséggel szembesülünk (minden jól működik, csak néha van pár ms szünet amikor nem)?
A valósidejű alkalmazások rendszerint kernel driverek szintjén kommunikálnak. Ha egy valósidejű driver drop-out-ol annak legvalószínűbb oka, hogy egy másik kernel szintű driver belerondít a képbe. Ezt rendszerint Deferred Procedure Calls (DPCs) nevű csodás interfészeken keresztül teszik.
Amennyiben ez a probléma, ezt elég egyszerűen megállapíthatjuk, az alábbi alkalmazással:
DPC latency checker
Segítségével mérhetjük a macimális DPC latency-t. Ha dropout van, és ezt látjuk a DPC latency-k alakulásán is, nem kell mást tenni, mint a Device manageren sorra kikapcsolni a kernel szintű drivereket használó eszközöket. A legintenzivebb ilyen cuccok általában a WLan kártyák, modemek, usb eszközök és vezérlők, integrált hangkártyák, nem standard ide driverek… Ezekre soha sincs szükség, kapcsoljuk ki őket… (érdemes minden esetben, nem csak ha probléma van, nehogy véletlenül legyen).
És kezdőthet is a móka (valós időben!)