printStackTrace()
Monday, December 7th, 2009 | exception | 4 Comments
Régóta tervezem, hogy indítok egy blogot, amiben csak exceptionok vannak. Egy munkahelyi csatorna már van, ahol ilyenekkel bombázom a kolegákat, nem mintha megoldást várnék tőlük, sőt. De úgy gondolom, hogy az exceptionok olyan méltatlanul mellőzőtt ipari képződmények, amik maguk egyszerűségében és monotonitásában valódi művészi értéket hordoznak.
Persze igazából egy stack trace megosztó social site lenne jó. Napi exception, hasonló exceptionnel barátkozó fejlesztők, ismerős exceptionok bejelölése, stb.
Amíg a nagyra törő álmok megvalósulnak, addig is itt egy kategória, ahová mintegy ilusztárcióként feltöltök egy-egy szép darabot.
javax.ejb.EJBException: The bean encountered a non-application exception; nested exception is: java.lang.reflect.UndeclaredThrowableException at org.apache.openejb.core.ivm.BaseEjbProxyHandler.convertException(BaseEjbProxyHandler.java:358) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:286) at $Proxy54.existsValami(Unknown Source) at hu.xxx.xxx.xxx.ValamiServiceV1X0Test.testExistsValami(ValamiServiceV1X0Test.java:59) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41) at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.junit.runners.ParentRunner.run(ParentRunner.java:220) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:165) at org.apache.maven.surefire.Surefire.run(Surefire.java:107) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:289) at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:993) Caused by: java.lang.reflect.UndeclaredThrowableException at $Proxy55.getEM(Unknown Source) at hu.xxx.xxx.xxx.ValamiServiceV1X0.queryValamiFind(ValamiServiceV1X0.java:52) at hu.xxx.xxx.xxx.ValamiServiceV1X0.existsValami(ValamiServiceV1X0.java:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:158) at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:141) at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:122) at org.apache.openejb.core.stateless.StatelessContainer._invoke(StatelessContainer.java:221) at org.apache.openejb.core.stateless.StatelessContainer.invoke(StatelessContainer.java:174) at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:217) at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:77) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:281) ... 30 more Caused by: java.io.NotSerializableException: org.apache.openejb.persistence.JtaEntityManager at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.copyObj(BaseEjbProxyHandler.java:501) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.copy(BaseEjbProxyHandler.java:301) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:283) ... 45 more
(Élesebb észrevehetik, hogy egy maven által futtato junit tesztből próbálok standalone összerántani egy EJB konténert OpenEJB-vel, hogy konténeren kívül futtathassam az integrációs teszteket. Egyelőre kevés sikerrel)
Db4o tapasztalatok
Sunday, December 6th, 2009 | Uncategorized | 2 Comments
Aktuálisan kedvenc állatorvosi lovam, egy wicket + guice + warp-persistes alkalmazás. Illetve a technológiák gyakran változnak benne, például alig egy órája dobtam ki az utolsó JPA függőséget is belőle, és teljesen átáltam db4o-ra. (A JasperReport helyét is könnyen átveheti a BIRT, illetve a Salve is sorban áll tesztelésre)
Az első tapasztalatok:
- Nem árt tudni, hogy GPL, tehát az über titkos üzleti alkalmazásban nem használhatom.
- Érezhetően gyors. Mondjuk iszonyú kis adatbázisom van, gondolom jól betölti az egészet a memóriába.
- Az API-ja csábítóan egyszerű. Queryket írni annonymous-inner-class-okkal igazi fényűzés.
- Cascade-ra ugyanúgy gondolni kell. Objektum lekérésnél alapból 5 mélységű a rekurzió, de update/store-nál default nincs rekurzió. Eltartott egy ideig míg rájöttem, miért nem megy rendesen. A rekurzió szintje állítható teljes adatbázis, entitás és mező szinten is. Csak kérni kell.
- A séma változásra ez is érzékeny (különösen, ha az objektum hierarhia változik)
- A managed-detached objektumokra ugyanúgy figyelni kell. Amíg nem sikerült összeraknom számos esetben elszabadultak az objektumok, és megsokszorozódtak. (Csak egy oc.store() metódus van, és ha detached-et akarok updatelni, akkor lelkiismeret furdalás nélkül létrehoz új objektumot.)
- Alapból tud olyat, hogy minden objektumnak van ID-ja (van UUID-ja is, de az nem kellett). Ebben az a furcsa, hogy az ID egy belső dolog, és nem az entitásban van tárolva, hanem API-ból lekérdezhető: kedves konténer, ennek a managed objektumnak mennyi az ID-ja? Az viszont nem meglepő, hogy egy detached objektumnak már nem lehet elkérni. Talán van valami merge itt is, de még nem találtam meg. Igaz nem is nagyon kellett, mert a Wicket detachable modeljei pont tudják azt, hogy az ID-t eltárolják, amíg még managed az entitás, és az alapján visszatöltik, amikor kell.
- Nagyon barátságosan tesztelhető, mert egy statikus függvény meghívásával át lehet az egészet in-memory db-re állítani. Onnantól kezdve csak iniciaálizálni kell benle pár adatot, és mehetnek az integráiós(abb) tesztek.
- Constraintek Java API-ból adhatóak meg. A Bean Validation Frameworkot valószínű 5 sorból be fogom tudni kötni.
- Nincs jó felület, ahol meg tudom nézni a tartalmát, és alap szerkesztéseket tudok végrehajtani. Egy BeanShell-t próbáltam már rá állítani, de még nem sikerült összelőni.
- Elég jó doksija van, pedig még csak főleg a tutorialt olvastam, a reference manualnak csak a részeit.
- Érdekes következménye van annak, hogy minden objektumot el tud menteni. Pl. a JPA-ból kiszelektált csoda objektumokat nem érdemes rögtön elmenteni, mert előhúzás után a lazy mezők rosszul fogják érezni magukat. Ugyanígy a BigDecimal serializálása alapból nem triviális, ennek a kezelésére külön kiterjesztést kell bekapcsolni (bekapcsolt kiterjesztéssel szerkesztett db fájlt olvasni legközelebb szintén csak bekapcsolt kiterjesztéssel rendelkező konténerrel lehet).
Szóval egyelőre barátok maradunk és bent marad. Még meg kell nézni a tranzakciókat, a Bean Validation Frameworkot bele reszelni, és majd byte[]-el kell még tesztelni.
Wicket + IoC
Monday, November 30th, 2009 | Uncategorized | 2 Comments
Ha wicketben elnavigálunk egy statfull oldalról, akkor azt a keretrendszer leserializálja és elrakja. Ha az új oldalról mondjuk a backkel visszamegyünk, akkor az előző oldal példányt vissza serializálja és azt rendereli le. Ha azonban a serializálás közben egy nem serializálható mezőt talál az oldal objektumon, akkor dob egy kivételt (nem a felületen, csak az alkalmazás szerver logjában), és amikor vissza akarunk térni, már csak egy Page Expired oldal fogad.
A Wicket és az IoC kapcsolódási pontja az IComponentInstantiationListener osztály. A beregisztrált listenerek minden komponens létrehozásakor meghívódnak a Component osztály konstruktorában. Mivel a leszármaztatott komponensben első lépésben meghívjuk a szülő osztály konstruktorát, ezért ha egy beregisztrált guice-os listener injektál az annotált mezőkebe, akkor azoknak értéke már a konstruktorban elérhető lesz. Ilyen okos konstruktor, azonban csak a Component osztályban van, a Model-ek és DataProviderekben nem.
Van még egy másik dolog, amire épül a Wicket, hogy a Model-ek egy jó része Detachable, azaz az oldal elrakásakor nem serializálódik úgy ahogy van, hanem csak a fontos mezők kerülnek elmentésre (hogy mi fontos, azt mi implementáljuk). Ezzel csökkenthető az oldal állapotok által elfoglalt hely nagysága. Tipikusan pl. ha egy model egy JPA entitást tárol, akkor elég elrakáskor a primary key-t elrakni, és amikor a komponens fát előhúzza a wicket, akkor az Id alapján újra betölti az entitást az adatbázisból.
Már ha éppen kéznél van a Modelben egy EntityManager. ServiceLocator.getInstance() típusú trükkel mindenhol kéznél lehet, de IoC-vel már bonyolultabb a probléma, mert az EntityManager nem serializálható, és a jól beinjektált objektumot nem tudja elserializálni a wicket. Ha meg transient, akkor a Modelt el tudja serializálni, de elővétel után az EntityManager helyett egy nagy null lesz, mert elővételkor nem fut le a Listener, hogy injektáljon.
Mi a megoldás? A wicket-guice azt csinálja, hogy egy un. LazyInitProxy-t használ. Ez a nevének megfelelően egy olyan proxy, ami az első híváskor inicializál a hasába egy adott osztályt, amihez majd híváskor proxyzza a kérést. A wicket-guice amikor a Component-ekbe kéne injektálnia, nem az Guice-os Injectort használja, hanem kézzel végig szánkázik a potenciális injektálandó mezőkön, és ahová injektálni kell, oda ő injektál egy proxy-t, amibe belírja a cél mező típusát és a rajta lévő annotációt. A proxy tehát tudja ezt a két értéket, ami már elég kulcs, hogy szükség esetén ez alapján az Injectortól elkérje a megfelelő példányt, aminek tovább kell adni a kérést. És persze a csak mező és annotáció típust hordozó proxy szerű objektum vidáman serializálható.
Ezzel a trükkel a Component szinten lévő @Injectálandó szolgáltatások helyére egy speciális serializálható referencia kerül. Viszont az ily módon beinjektált osztály által hivatkozott szolgáltatók már hagyományos Guice IoC szinten jönnek létre.
A megoldás tehát az, hogy a Page-ekbe rakunk @Inject-eket, és a Modelek és DataProviderek megkapják konstruktor paraméterbe a beinjektált szolgáltatásokat, hiszen mi tudjuk, hogy első szinten azok serializálható visszatölthető referenciák.
PS: kitakarítottam a commentek közül az 500 spamet, találtam három értékes kommentet (miért nem kaptam róluk emailt??), amire mindjárt válaszolok. kicsit újra rendet raktam itt. Jól megült itt a por, mióta utoljára itt jártam.
openjpa:sql
Monday, September 14th, 2009 | Uncategorized | 4 Comments
A probléma: a JPA entitás struktúra folyamatosan fejlődik. Bármikor képes szeretnék lenni az entitásoknak megfelelő adatbázis struktúrát létrehozni, illetve egy meglévő adatbázis struktúrát minél kevesebb adatvesztéssel frissíteni.
Az első követelményt szinte minden JPA provider tudja, a második viszont már keményebb dió. Az Eclipselink pl. csak a drop-and-create szolgáltatást ajánlja, azaz törli az összes táblámat, és újra létrehozza a sémát, még akkor is, ha csak egy új mezőt, vagy egy új táblát hoztam létre.
Az openjpa viszont még az én igényeimet is kielégíti. Erre egyrészt ad egy Java osztályt, de van hozzá Maven plugin is. Megnézi az entitásaimat és tud generálni belőle create DDL-t, illetve refresh-t is, azaz egy meglévő adatbázishoz képest a különbséget. Az adatbázis kapcsolatot a persistence.xml-ből veszi, vagy konzol paraméterből is megadható. Az SQL parancsokat kiírja fájlba, vagy rögtön frissíti/létrehozza az adatbázist is. Elvileg ugyanerre be lehet konfigurálni a Persistence Unitot is, de azt még nem próbáltam ki.
Az első próbák ígéretesek. Új oszlopot, táblát felvesz anélkül, hogy a többit törölné. Ha mezőt törlök, akkor persze nem törli a megfelelő mezőt, de ezt akár tervezési döntésnek is be tudhatjuk.
Nekünk volt erre egy sufni toolunk régen, ami felépítésében sokat ígérő volt, de persze a JPA-ból csak a triviális dolgokat implementáltuk, most viszont ez úgy tűnik el lehet dobni, mert az openjpa jó lesz minderre. Lehet hogy providerként is megpróbálkozom vele.
Guice 2.0
Monday, May 25th, 2009 | Uncategorized | No Comments
Kijött a Guice 2.0. Sok egyébb mellett az én problémámra is megoldást nyújt. Azaz listener-ek segjtségével teljesen dinamikus bindingokat lehet létrehozni.
Eddig a @PersistenceContext injektálásokhoz előre meg kellett adni a a Module-ba a használni kívánt PU-kat. Most már lehet dinamikusan a classpathba keresni igény esetén, hogy létezik a megjelölt PU, és elég első injektáláskor betölteni. Tehát most már lehetne vele EJB konténert emulálni rendesen integrációs tesztkörnyezetben. (Kristóf ajánlotta wrap-persist mellett (emi elsősorban JPA barát) van egy GuiceFruit is, ami mintha részben tudná is ezt.(EJB barát is)).
Ez a Guice egyre jobban tetszik. Már több kissebb-nagyobb projektembe beszivárgott, és lassan kezdek függővé vállni.
ps: akinek volt commentje, ami moderácóra várt (ilyen eddig nem nagyon volt), az kérem írja újra, mert legalább 2000 spamet kaptam, és kénytelen voltam SQL-ből törölni.
OSGi névsorolvasás
Sunday, May 10th, 2009 | Uncategorized | 1 Comment
pax-runner: Az ops4j-sek azok, ahol nem csak a forráskód a szabad, hanem a fejlesztés is, tehát odamész, és ha akarsz, commitolsz. Az ő legnépszerűbb projekt csokruk a pax, amik mind OSGi-al foglalkoznak. A pax-runner pl. OSGi konténert indít el. Bármilyet, csak paraméterezni kell. Azt is megmondhatod, hogy milyen alap szolgáltatások legyenek benne. Ha nincs meg a konténer, amit szeretnél, akkor letölti. Nagyon jól lehet vele tesztelni bundle-t több konténerbe.
modulefusion: (K.-tól tanultam.) A recept egyszerű: végy egy csomó OSGi bundle-t (ha nincs elég jó, csinálj), és az egészet rakd össze valami alkalmazás szerver jellegű dolognak, és nevezd el. Ezt csinálja a Spring Source is, és ilyen a modulfusion is. Van benne wicket, guice, hibernate mindezt pax-runner indítja el, jól összerakott szakmunka. Példák is vannak, hogy hogy csináljunk JPA+Wicket+guice varázslatot OSGi konzolon.
equinox: az Eclipse OSGI konténere. Az izgalom az benne, hogy van hozzá egy server bridge. Ez egy war file, amit bedeployolsz bárhová, de közben OSGi konténer is. A servletre érkező kéréseket OSGi HttpService szolgáltatásként adja tovább. Valami ősöreg 3-as OSGi bundleok vannak benne.
Felix: Apache OSGi konténer. Kicsi, könnyű, beágyazható. Akik nem eclipse hívők (pl. Glassfish), azok általában ezt használják. Szerethető cucc, de nincs servlet bridge-hozzá. (még)
Http Service: OSGi kiegészítő specifikáció része. Kicsit buta, csak Servletet lehet regisztrálni. Azt is úgy, hogy lekéred a servicet, amin meg tudod hívni a regisztráló metódust. Mindenkinek szokott lenni implementációja, általában Jetty alapú.
Pax-web: egy másik pax. Olyan mint a Http Service (extend), csak van mellette még filter támogatás is, meg resource és jsp regisztráció, welcome file támogatás, stb. Servlet bridge nem tudja, mivel ez önmagában egy jettyre épülő bundle. Kicsit vendor lock-in, de szükség lehet rá (modulefusion a Wicketet servleten keresztül működteti, nem filteren, tehát megkerülhető).
Pax web extender, whiteboard: a http service-ek regisztrációját könyíti meg. Nem kell megkeresni a szolgáltatást, amin keresztül regisztrálni lehet a Servletet, hanem elég felírni a táblára, hogy én vagyok X Servlet az Y url-en, és már megy is. Meglepően okosan összerakott cucc: megy csak Http Service szolgáltatással, és pax-web-bel is. Megnézi milyen osztályok vannak, és azzal főz.
Felix File Install: egy okos bundle, ami sasol egy könyvtárat, és az ott feltünő bundle-okat hot deployolja.
modulefusion dir install: egy mégokosabb bundle, ami a modulfusion része, és nem csak a bundle-okat nyomja fel, de a config fájlokat is beolvassa.
Recept: fogom a Felix-et, berakom egy szervletbe, és onnan indítom, tehát elértem azt, amit az equinox servlet bridge is. Az OSGi compendium libraryt kicsit megpatkolva, pár class-t az OSGi class loadernek kiajánlva, és a HttpRequest wrappolása után, a pax web whiteboardon keresztül, a felix dir installt mellőzve, hanem az eredeti modulefusion-osat használva, a modulefusionos wicket-es guice-os OSGi-s csoda tökéletesen fut szervlet konténerbe. peace.

Most ez
Wednesday, April 29th, 2009 | Uncategorized | 1 Comment
Munka fronton éppen nagy kocka alakú dobozokban tárolt un. termékekkel kell megváltani a világot, ezen kívül csak lehulló morzsák, ezekről gyorsjelentés:
Guice: az egyik hobbi projektbe észrevétlen beszivárgott. Kb. azt adta amit vártam, meg vannak a korlátai, de azon belül okos kis kütyü. Egyelőre több könnyebbséget mint bosszúságot hozott, de ezzel az extension-nal még inkább csillogóbbá válhat a kép. Spring hívőknek nem való, de a hozzám hasonló egyszerű emberek ráérezhetnek a szépségére, hogy nem XML-eket kell túrni, hanem típusos Java kóddal kell definiálni a bindingokat (mégha cserépe tele szemeteljük a kódonkat annotációkkal).
Hg: egy két új projekt már ezen fut. Régebben nem tudtam elképzelni, hogy egy fejlesztő + egy központi szerver felállásban is lehet értelme, de most már abszolút úgy érzem, hogy igen. Egyre jobban kézreáll, csak az a baj, hogy egy LTS szerveren a pythonnal való összekalapáltság még eléggé durva (durván warningol de azért megy.) Meg a http feletti elérhetőséget se volt időm még előállítani.
Dbunit: eddig csak Unitils-el használtam, de Maven pluginjével DB környezetek közötti váltására is elég jó. Kárhogy sémát nem tárol. TODO: az inkrementális sémageneráló Maven plugint mégis csak be kéne fejezni.
Ezen kívül Wicket, Darkstar és mindenféle WS varázslat van most az erdőben, de ezekből még nem tudom mi lesz.
Google App Engine
Monday, April 13th, 2009 | Uncategorized | 2 Comments
Egyfelől egy elég jó hosting környezet, ugyan korlátozásokkal, de azokkal együtt lehet élni. Webes felület, áttekintés a használt erőforrásokról, verziózott deploy, nincs PermGen hiba, stb.
Másfelől habár elég sok mindent lehet futtatni rajta, korántsem problémamentes olyan alkalmazást fejleszteni, amit GAE-be is, és hagyományos webkonténerbe is ugyanúgy lehet futtatni.
Én rögtön a JPA kortlátozásaiba futottam bele. Egyrészt itt is örörm, hogy szép szabványos felületen adnak a BigTable fölé, még az se nagyon baj, hogy @ManyToMany-t nem használhatok, és hogy az entitás osztályaimat precompile-olni kell DataNucleus-szal.
De az már sokkal szűkebb keresztmetszet, hogy ha szülő-gyerek relációt szeretnék, akkor az elsődleges kulcsnak Stringnek, vagy Google specifikus Key osztálynak kell lennie. Egyiket se könnyű egy az egybe átültetni mondjuk Mysql + Hibernate JPA-ra. Persze tudom, itt nem az a cél, hogy a meglévő alkalmazások rögtön deployolhatók legyenek a GAE-be, hanem hogy az induló startup-omat kifejezetten Google-re fejlesztve skálázható teljesítményt kapjak, és azt is tudom, hogy a BigTable azért nem egy relációs adatbázis. És azt se mondhatom, hogy nem korrekt Java környezetet kapok hozzá. Csak valahogy jó lett volna, hogy ha kis ember Java hostingjának is jó lenne az egész. (Pl. ha az XWIKI-be fejlesztene valaki BigTable perzisztens layert…)
Maven vs. scripting
Saturday, March 14th, 2009 | Uncategorized | No Comments
Van egy régi félkész projekt, ami az előző munkánkból potyogott ki, mint újrahasznosítható alkatrész. A központi része egy absztrakt adatbázisséma reprezentáció Java osztályokból. Ezt az absztrakt fát fel lehet építeni többfajta forrásból (pl. Oracle DB connection alapján leképezi egy meglévő DB felépítését, vagy egy Jar-t megadva leképezi a Jpa entitások által meghatározott sémát az absztrakt adatbázis sémává). Természetesen az absztrakt DB sémát ki is lehet iratni (célszerűen mindenféle adatbázis specifikus SQLé). Illetve egy eszköz meg tudja mondani két sémadefiníció különbségét, és azt is le tudja képezni SQL parancsokká.
Mire jó? Mi két dologra használtuk. Egyrészt a JPA osztályokból előállítottuk azokat a fájlokat, amikben az SQL parancsok voltak, amivel a sémát fel tudtuk építeni. Ez már csak a Unitils-es teszt környezetünk miatt is kellett, ami, ha érezte, hogy az SQL-ek megváltoztak, a teszt adatbázist rögtön törölte, és felépített egy teljesen új adatbázist. Másrészt a fejlesztési adatbázist is tudta frissíteni, mert beolvasta a jelenlegi sémát (Oracle system táblákból), és az új sémát (JPA osztályokból), összehasonlította a kettőt, és a különbséget SQLben mondta el. Így a fejlesztési adatbázist (és akár az éleset is) tudtuk inkrementálisan frissíteni, úgy hogy a meglévő tartalom ne vesszen el.
Most jön a lényeg. A projektet kicsit kipofoztam múltkoriban, és már ott tartok, hogy csináljak hozzá ANT taskot és Maven plugint. Azon gondolkoztam, hogy hogyan tudnám a konfigurálhatóságot úgy megragadni, hogy az egyes elemeket bármilyen párosításban lehessen használni. Bárhonnan tudjak sémát beolvasni (létező Oracle vagy Mysql séma, JPA osztályok), és bármit meg tudjak velük csinálni (Mysql vagy Oracle specifikus kiiratás, összehasonlítás különbség számítás).
Arra gondoltam, hogy a legrugalmasabb az lenne, ha nem az XMLen kéne erőszakot tenni, hanem mondjuk valami scrip nyelvel lehetne megfogalmazi, hogy mit akarok, és milyen összetételben.Az első tesztek szerint a JSR-223 teljesen jó megoldást adna, mindenki abban írhatná meg a logikát, amiben akarná, akinek meg mindegy, annak ott az alapértelmezésben is elérhető JavaScript motor a Rhino. Ez utóbbival (a még teljesen átgondolatlan API) valahogy így föst:
new DDLWriter();.generateDDL(new JPAReader(“target/test-classes”).readDefinition()).printAll();
Az elképzelés az, hogy csinálok egy Maven plugint, amibe ezt bele lehet írni konfigurációként. Persze ez rögtön általános Maven plugin lenne, amibe bármit lehetne írni bármilyen JSR-233az script nyelv segítsévégel. Akár már létezhetne is ilyen plugin (rákerestem, nem találtam), amivel ha mást nem a Maven kicsit merev logikáján és deklaratív eszméjén sikerülne rést ütni. Valahogy úgy mint az antrun plugin, csak itt ráadásul scripteket lehetne írni ANT XML részletek helyett.
És itt, hogy ne nyúljak túl hosszúra, inkább Szczepan Faber-t a Mockito szerzőjét idéznem:
“After Jason Van Zyl’s session I had an impression that he believes the best fit for the build system is a declarative architecture. I tend to disagree and I believe the build has inherent scripting nature.”
JMeter
Sunday, March 8th, 2009 | Uncategorized | No Comments
Bár amikor terheléses teszt kell, mindenhol fel szokott az Apache Jmeter neve is merülni, huzamosabban most használtam előszőr.
Ami tetszett:
Felépítés: Tetszett, ahogy ki vannak találva az egyes építőkockkák, amikből tesztet lehet csinálni. Külön van protokoll függő meghajtó, külön vannak logikai elemek, külön mindenféle eredményt analizáló elem. A GUI-n ezekből az elemekből lehet viszonylag könnyen terheléses tesztet összerakni. Mégha nem akartam volna a meglévő komponenseit használni, mint keretrendszer, az interface-eket akkor is valószínű használtam volna.
Dokumentáció: a honlapon elég tisztességesen le van írva minden a használatról, és a használható elemekről.
Szállított elemek: okos ötletek vannak az alapból szállítótt teszt elemekben: pl. tud olyat, hogy egy webszerver logja alapján ismétli meg a hívásokat a szererre, és így valós felhasználói viselkedést lehet szimulálni vele. Van olyan elem is, amivel hagyományos Java kódot tud meghajtani, amibe már azt írunk, amit csak szeretnénk.
Könnyen kiterjeszthető: Egyszerű interfacek, használható absztrakt osztályok. Csak leszármaztatunk egy osztályt, bedobjuk a lib/ext könyvtárba, és már is megjelenik a mi építőkockánk is. (Durván végig scanneli a classpathnak ezt a részét osztályról osztályra, ezért a saját komponensünk függőségeit érdemes a sima lib könyvtárba tenni, mivel abban nem kell keresni a leszármaztatott JMeteres osztályokat, és túl nagy osztályok az indítást nagyon vissza tudják fogni.)
Ami nem tetszett:
Szállított elemek: A szállított elemek sokszor elég szegényesek. Főleg a grafikonokat megjelenítő elemek elég fapadosak (a managerednek nem lesz elég szép), de pl. a JMS Sampler-ben is voltak gondjaink a Correlation ID beállítása körül, illetve a külső paraméterek kezelése is kissé fapados.
Paraméterek átadása: paraméterezett teszteket csinálni két féle képpen lehet: User Definied Variableket használva, és System propertyket. Az előbbik vannak kényelmesebben integrálva a rendszerben, az utóbbiakkal lehet rendesen paraméterezni command line-ból indítot teszteket. A kettő között van átjárás, de nem túl kezes.
Gyanús hibák: Nem volt idő végigdebuggolni, de volt egy olyan jelenség, hogy sok-sok szálon nyomtam épp egy web service-t, valószínű hibás paraméterekkel. Feltehetően loggolni akarta a hibákat, én csak azt láttam, hogy teljesen megállt minden. jconsole azt mondta, hogy a sok szál általában vár egy lock-ra, ami valami apache logos osztályban keletkezett (Illetve iszonyú lassan mindig eg yszál loggolt, amíg a többi várt a szemaforra)). Magyarul a logolás szinkronizációja miatt kicsit megroppant az egész teszt.
Összességében nem rossz, a használatáról az egyik koléga mesélte még rémtörténetet: ha jól emlékszem egy IIOP-s vastag klienset sikerült velük meghajtani, úgy, hogy előtte AOP-vel le loggolták a kéréseket a kliensben, és utána ezeket az adatokat táplálták be a JMeterbe, ami megterhelte a rendszert velük. Szép dolgokat építeni belőle.
Archive
- September 2010
- July 2010
- June 2010
- April 2010
- February 2010
- January 2010
- December 2009
- November 2009
- September 2009
- May 2009
- April 2009
- March 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006