Archive for December, 2009
YAML
Tuesday, December 15th, 2009 | Uncategorized | 3 Comments
Ahogy azt egy kedves szomszéd szokta monda, a törpök élete se mindig csak játék és mese. Ez különösen így van, ha a törpök db4o-t használnak. Ráadásul BigDecimal-t akarnak perzisztálni, amihez tartozó kiterjesztés csak a legújabb SNAPSHOT artifactokban van benne.
És valószínű ennek a folyománya az, ami rendszeresen szembe jön, egy exception (hová is lenne az életünk exceptionök nélkül), ami valahogy így néz ki:
Caused by: com.db4o.ext.InvalidSlotException: id: 5182 at com.db4o.internal.marshall.UnmarshallingContext.invalidSlot(UnmarshallingContext.java:81) at com.db4o.internal.marshall.UnmarshallingContext.read(UnmarshallingContext.java:49) at com.db4o.internal.ObjectReference.read(ObjectReference.java:281) at com.db4o.internal.ObjectReference.read(ObjectReference.java:267) at com.db4o.internal.ObjectContainerBase.getHardObjectReferenceById(ObjectContainerBase.java:956) at com.db4o.internal.marshall.AbstractReadContext.classMetadataForObjectId(AbstractReadContext.java:85) at com.db4o.internal.marshall.AbstractReadContext.readObject(AbstractReadContext.java:57) at com.db4o.internal.marshall.AbstractReadContext.readAtCurrentSeekPosition(AbstractReadContext.java:46) at com.db4o.internal.OpenTypeHandler.read(OpenTypeHandler.java:172) at com.db4o.internal.Handlers4.readValueType(Handlers4.java:313) at com.db4o.internal.marshall.AbstractReadContext.readAtCurrentSeekPosition(AbstractReadContext.java:48)
És így tovább.
A hiba teljesen kiszámíthatatlanul, ugyanakkor jól reprodukálhatóan előjön. Pl. előveszek egy backup db4o file-t, megnyitom, teszek-veszek benne, lezárom az alkalmazást. A következő megnyitáskor már nem nyílik meg az adatbázis. Ha viszont ugyanazt a cselekmény sort újra végigviszem az elmentett db4o file-on ugyanúgy elszáll.
Tehát előszőr is ki kéne dobni a db4o-ból a BigDecimal-okat, amihez át kéne konvertálni a sémát. (Tegyük fel, hogy egy számlázó programban sosem fogok beleütközni a float korlátaiba). Ha nincs több BigDecimal mezőm, akkor használhatom a stabil db4o változatot. A másik meg, hogy szükségem lesz egy dump file formátumra. Egyrészt mivel féltem a már bent lévő adatokat, másrészt mert a mező típus konvertálás is nagy szívás egy meglévő db4o adatbázison, az egyik legegyszerűbb megoldás, hogy kidumpolom az adatbázist, majd típus refaktor után vissza.
Mi legyen a dump formátum. Kapásból a JAXB és Json jutnak eszembe, de ezek ahogy én tudom nem támogatják a referenciák kezelését. (Ha az objektum fában többszőr is előfordul ugyanaz az objektum, akkor visszatöltés után ne két, hanem csak egy objektum legyen, amire két helyről mutat referencia.
És itt jön kébe a YAML, amit pont tudja mindezt.
Előszőr a jYaml-t próbáltam, ami alapból egyszerűen működik, de régóta nem fejlesztik, és túlságosan is elnézően bánt a Yaml fájl hibáival. Aztán jött a Snakeyaml. Ez már tette a dolgát mint a kisangyal.
Objektum mentése:
Yaml yaml = new Yaml(); yaml.dump(eztmentemel, new FileWriter(file));
Objektum betöltése:
Yaml yaml = new Yaml(); DatabaseBackup backup = (DatabaseBackup) yaml.load(new FileInputStream(file));
Maga a Yaml file meg valahogy így néz ki.
!!net.anzix.nona.entity.DatabaseBackup felhasznalok: - email: geza@hutira.net partner: &id001 partnerek: - &id005 partnerek: [] szamlak: [] torzs: {adoszam: null, bankszamlaSzam: null, nev: Asztal kft., szamlaCim: Sötét út 20., szamlaIrsz: '1111', szamlaVaros: Budapest} tulajdonos: *id001 ....
Itt már rögtön látszik is a referencia kezelése. A partner objektum instance azonosítója id001, és a partnerek listában található egyik partner tulajdonos mezője pont erre mutat vissza referenciával.
Mivel a db4o-val egy paranccsal elmenti az objektumfát, ezért 3 sorban tudok backupolni és visszatölteni a backupot, és a yaml file-t minimálisan módosítgatva (segít a nagyerejű grep parancs) még a típus konverziókat is sikerült viszonylag kis fájdalom árán meglépni.
Yaml a mi barátunk.
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.
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