2009. július 8., szerda

JAX-RS és JAX-WS

Köszi a hozzászólásaitokat az előző postra, egész sok inspirációt kaptunk ahhoz hogy hogy írjuk át a teszteket!

Igazából most is a véleményetekre lennék kiváncsi.

Szintén munkahelyi projectben azon mesterkedtem, hogy SOAP-os REST-es web service-t is meghagyom egészen addig, amíg teljesen világossá nem válik hogy az adott környezetben melyik a nyerő megoldás. Természetesen spring-gel inicializálom a service bean-eket, CXF-fel exportálom ki, JSR 181 web services és JSR 311 rest annotációkkal látom el a service metódusokat és a beaneket még JAXB annotációval is helyenként. Sikerült is, bár szerintem kicsit szőrös a dolog.
  1. Elösször is a JAX-RS a beanjeid Collection (list, map) mezőire megköveteli, hogy legyen mindnek alapértéke és csak gettere. Azaz ne lehessen null soha, legfejebb üres. Viszont a JAX-WS elvárja hogy mindenkinek legyen szép gettere és settere, különben nem számít proprtynek. Ez a kettő nem feltétlenül zárja ki egymást, csak kicsit megcsúfítja a bean-eket.

    Például így fog kinézni egy bean:



    /**
    * Szerintem gáz, amikor magyar neve van egy osztálynak :)
    * Majdnem mint amikor a javadoc is magyar.
    */
    @XmlRootElement(name="csirke")
    public class Csirke {
    boolean isKopaszNyaku;
    boolean isKendermagos;
    List<Tojas> tojasok = new ArrayList<Tojas>();
    @XmlTransient // Nem ezt a property-t hasznaljuk a rest apival
    public List<Tojas> getTojasok() {return tojasok;}
    public void setTojasok(List<Tojas> tojasok) {this.tojasok = tojasok;}
    @XmlElement(name="tojas")
    @XmlElementWrapper(name="tojasok")
    public List<Tojas> getTojasLista(){ return getTojasok();}
    }


    Szóval szerintem kicsit összetúrkáltuk az alkalmazás legérzékenyebb részét: az adatmodellt. Ha az adatmodell csúnya, az mindennek rossz alaphangulatot ad.
  2. A CXF-nek kicsit nehéz volt megmagyarázni, hogy ha pl a /services/ alá mappeltem a CXFServlet-et, akkor mit kell csinálnia akkor, amikor kap a /services/-re egy kérést. Azt hiszem az lehetett a baj, hogy nem állítottam be at address-t.



    <jaxrs:server name="jaxrs-server" bus="rest" address="/rest">
    <jaxrs:servicebeans>
    <ref bean="csirkefarm">
    </jaxrs:serviceBeans>
    </jaxrs:server>



  3. A service interfacekre raktam az annotációkat, hogy ha lecserélem az implementációt, akkor az új service-re már ne kelljen másolgatnom. Hát elég cifrán meg lett annotálva egy-egy ilyen metódus.



    @WebService(name = "csirekFarm")
    @Path("/csirkeFarm/")
    public interface CsirkeDAO {
    @WebMethod(operationName = "getCsirke")
    @WebResult(name = "getCsirkeResult")
    @GET
    @Path("/csirke/{csirkeId}")
    public void Csirke getCsirkeById(@Webparam(name="csirkeId") Long id);



Most, hogy az annotációk legyőzték az XML konfigurációkat, a kódunk tele van konfigurációval :-) A hétvégén összedobok hozzá egy archetype-ot, ha elég időm marad rá.

2009. június 25., csütörtök

Logging

Belekeveredtem egy problémába a OpenJPA unenhanced osztályaival és úgy döntöttem hogy inkább visszatérek kicsit Hibernate-re. Nos magában a visszatérés nem lett volna nagy ügy: kiszedni az OpenJPA-t a pom.xml-ből, betenni a hibernate-entitymanagert, kicsit módosítani a jpa konfiguráción és kész is lenne...
Viszont a hibernate időközben nagyon szépen áttért a log4j logolásról a slf4j logolásra. Őszintén szólva teljesen lusta voltam egész idáig akár belenézni is, hogy mit kínál az új logging api. Nos a Simple Logging Facade 4 Java azt találta ki, hogy az régi logging apik helyére tesz egyetlen loging rendszert. Azaz kidobtak egy halom jar file-t, amiben például benne lehet a jó öreg org.apache.log4j.Logger, és emiatt nem tűri meg maga mellett az eredeti log4j-t. Dependency hell. Akármelyik csomagom is hozott be log4j függőséget, azonnal ki kell vadásznom a teljes dependency fából. Most még be kell dobálni a slf4j api-t, majd a log4j-over-slf4j csomagot...

A végeredmény az, hogy a JPA implementáció cseréje sokkal kevesebb időt vett igénybe mint a logging api cseréje. A logging az a dolog amitől azt várnám hogy nem zavarhat semmit, nem romolhat el és nem okoz semmiképpen sem futási hibát.

"Lassan haladunk, de nem baj, mert rossz irányba"

2009. június 21., vasárnap

Rémálom a JPA utcában

Ezt a problémát próbáltam felvázolni Tvik-nek a eclipse democamp elött, de azt hiszem túl alacsonyan volt akkor még az agytevékenységem hogy sikerrel járjak. Meg talán viccnek túl hosszú ez az egész.

Szóval egyik nap áthívott az egyik srác egy másik projecttől, hogy segítsek elindulni a JPA persistence tesztek fejlesztésével a projecthez. Eléggé félfüllel követtem a project életét, szóval igazából csak nagyon kevés ötletem van arról hogy mi miért jutott oda ahol van az architektúra fejlődése során, de ehhez a feladathoz ezen a ponton rendelkezésünkre állt:
  • Netbeans-ben kigenerált JPA controller kód (ahogy én értettem ez ugyanaz mint a DAO pattern)
  • persistence.xml kitöltve a production környezethez (JNDI datasource inside)
  • Azt hiszem szintén generált perzisztens osztályok
  • Maven-es build
Feladat: A kódot teszteljük úgy, hogy használjuk fel hozzá kigenerált kódot is. Szóval sima DAO tesztelés.
A generált kód nemnyúkapiszka tárgya.

Első nekifutásra egyszerűen azt javasoltam a kollégámnak, hogy egyszerűen dobjon be egy új persistence.xml-t a teszteknek, és használja azt a tesztekből. Biztosan lehet valahogy, mert a spring és a unitils is meg tudja mondani a persistence layernek, hogy melyik persistence.xml-t használjuk fel. Mondani könnyű persze.
Párhuzamosan én is elkezdtem keresni, hogy vajon a JPA-nak hogy is kell ezt megmondani, de látványosan sehol semmit nem találtam, csak akkor nem foglalkoztam vele tovább mert persze én másik projecten vagyok és azt kell hegeszteni.

Második nekifutás: Be kellett látnunk hogy kicsit alaposabban kell foglalkozzunk a JPA kérdéssel ahhoz hogy a teszteket élesbe állítsuk. Összeültünk egy eredetileg rövidre tervezett pair programming sessionre és nekiláttunk átnézni a teszt menetet. Hamarosan kiderült hogy a spring valami nagyon hosszú tréfát használ arra, hogy a persistence.xml-t más néven keresse meg és ezt nem akartuk átmásolni tőlük, inkáb az volt az alapötlet, hogy a spring-gel inicializáltatunk egy JPA EntityManager-t és azt odaadjuk az érintett DAO objektumoknak. A JPA init ment is mint a karikacsapás, de amikor odaértünk, hogy beletömjük a DAO objektumokba az eredményt, akkor elmúlt a jókedv: a generált osztályok konstruktora inicializálta és private mezőként tartotta az EntityManagert. Azaz szépen udvariasan nem tudunk hozzányúlni. Ráadásul a kódba bele van generálva a persistence unit neve is. Ezt az egészet úgy látszik úgy találták ki, hogy a végleges környezeten kívül máshol ne lehessen futtatni. Azaz nem tesztelő-barát.

Harmadik nekifutás: Override-oljuk a konstruktort. Ja, de az ősosztály default konstruktora akkor is meghívódik. Rövid roham, fejvesztett menekülés.

Negyedik nekifutás: Jó, akkor használjuk a production-ra szánt persistence.xml-t és mielött mindezt felstartoljuk, dobjunk össze egy JNDI contextet a teszt DataSource objektummal. Ez tűnt vagy fél órán keresztül a nagy és tökéletes ördögi tervnek, én teljesen hittem a sikerben amíg a tesztbe drótoztam a spring-test csomag JNDI mock csomagját és startnál elmondtam a varázsigét is, hogy "Fuss QA!!!".... és nem működött. Azért nem, mert a spring JNDI mock csomaga pár metódust nem implementált a JNDI standardból, amit a JPA implementáció akkor is meg akart hívni. Na igen, régen használtam a spring JNDI implementációját és fogalmam nem volt a korlátairól.

Ötödik nekifutás: diplomáciai tárgyalások az ellenséggel. Ekkor kitaláltuk, hogy akkor a build eszközzel etetjük meg azt, amit a szőrös apikkal nem tudtunk. Nos a maven esetében ha két ugyanolyan nevű resource van a src/test/resources és src/main/resources alatt, akkor úgy tűnik kb véletlenszerűen fogja egyiket vagy másikat megtalálni. Nincs más választás, külön profile-ba kell tenni az éleset és a tesztet.
Ant-tal pofátlanul egyszerű lenne a junitnak odalökni egy másik classloadert. Rettenetes mellékhatások: nem futhat egy buildben a deploy és a teszt. A CI konfiguráció se lesz persze egyszerűbb.

Tanulságok:
  1. Rájöttem hogy eddig soha nem próbáltam spring nélkül JPA apit használni
  2. És valószinűleg ez az oka annak, hogy nem utáltam meg már az elején a JPA-t. A JEE architektúra csak kicsit lett kevésbé toldott-foldott mint a jó öreg EJB 2.1 időkben.
  3. A generált kódoktól nagyon udvariatlan dolog, hogy ők akarják inicializálni a persistencemanagert és erről nem lehet lebeszélni őket.
  4. A JPA-ban már az elején nem tetszett, hogy a META-INF/persistence.xml-hez ennyire ragaszkodik, de nem gondoltam, hogy nincs is szabványos megoldás ennek a felülbírálására.
  5. A netbeans generált kódjaitól ments meg uram mintket!
  6. Amikor ilyen kavar a kód, a maven szigorú struktúrája is akadállyá válik.

2009. június 18., csütörtök

Eclipse DemoCamp frissen

Ma este betértem az Eclipse DemoCamp 2009 rendezvényre, szocializálódni és telepakolni a szatyromat információkkal. A hely egy kellemes kis teázó a vár aljában, a hőmérséklet és a népsűrűség is sokkal kellemesebb volt mint tavaly. Persze nem azért, mert kevesebben voltunk :) Kicsit lassan rázódtam bele a hangulatba, inkáb már csak az első előadás után kezdtem kommunikálni emberekkel.

Előadások...

Bocsi, még mielött nekivágok... Nem próbálom hitelesen visszaadni az előadások tartalmát, az biztosan elérhető lesz majd valahol, a saját reakcióimat írnám le ide velük kapcsolatban.
  • Nagy Gergely: Dependency Management with Ivy and IvyDE
    Demókkal megtűzdelt előadás volt arról, hogy az Ivy-t hogyan lehet fejlesztőbarátabbá tenni egy eclipse plugin segítségével. Volt is benne apróbb bug, egyszerű javítással. Ahol kicsit nekem elakadt a lélegzetem, az a repository modell volt. Miért lett ez ilyen bonyolult?
    Feltettem az a kérdést, hogy ha "csak például :)" én mavent használok, de a cég egy másik csapata ivy-t és ant-ot, tudnak-e ők nekem olyan mavenes descriptort generálni a ivy dependency-kből, amivel az én mavenes projecteim tudják használni az ivy+ant kombinációval buildelt cuccot. Gergely mondta, hogy nincs ilyen megoldás és Jason hozzátette hogy igazából nem is lehet, a két project classloader rendszere teljesen más és összeegyeztethetetlen.

    Kövekeztetés: a Cégen belül ha valaki ilyet használ, az nekem nem segítség. Továbbra is hímezhetem kézzel a pomokat.

  • Jason van Zyl: Next Generation Enterprise Builds: Maven, Mercury and Tycho
    Külföldi sztárelőadóval folytatódott a build eszközök harca :)

    Szóval Jason elegánsan átsiklott a maven 3.0 téma felett, ahol én meglepődtem, mert a maven 3.0-ról most hallottam elösször és nagyon érdekelt volna erről minnél több infó, de ennyit kaptunk: minden működni fog a maven 2.x-ből 3.0-on is.
    A m2eclipse alias Tycho igazán meggyőző demó volt. Persze volt benne pár apróbb hiba, mint minden live demóban, de talán végre eljött az ideje, hogy beálljak a sorba és elfelejtsem az 'mvn eclipse:eclipse' parancsot. Amúgy is túl geek-es volt, windowson meg rettenetes.
    A nexusról nem sok újat tudtam meg, mondjuk azon amennyire tudtam rajta tartottam a szemem. Az első pár feature requestet én dobtam be rá és igazából elégedett vagyok azzal amit kaptam ingyen :) A kérdésem az volt hogy mi az, ami kiemeli a nexus-t a maven repository managerek versenyéből. Jason alapvetően a stabilítást és a teszteltséget emelte ki, valamint hogy az archiva igazából bebukóban van.
    További információmorzsa: a nexus a jsecurity-t használja azonosításra és csak 1 hét volt beintegrálni, ami jobb mint a spring-security. Volt nekem is pár problémám a spring-security-vel, de soha nem szúrtam el rá 1 hetet. A rekord egy régi grails-es projectemen volt 2 estényi gubancolás, mert akkor még a grails is gyerekcipőben járt, meg groovy-ban is az volt az első dolog amit írtam. Házi feladat: jsecurity


    Félig meddig ide tartozik, és a következő blog postom arról fog szólni hogy milyen torkos szívás volt generált JPA kódra írt teszteket futtatni mavennel. Pff, a kódgenerálás a múlt század. Nekem az idl compilerek jutnak róla eszembe.

  • Bánfai Balázs, Török Zsolt: Transition from classroom to real-life software engineering
    Nos ebből a szempontból az én karrierem - ha beszéljetünk ilyenről- nem a szokásos dolog. Soha semmi hasznosat nem tanultam iskolában főleg nem informatikáról, és bár jártam egyetemre, úgy érzem hogy -persze csak intellektuális- pofonokon kívül mást nem kaptam. Persze kell a karó a virág mellé, de hát... kéne a virág a karó mellé.
    Úgyhogy erről kimentem dumálni a teázó elé, aztán pedig hazatekertem.

Köszi a szervezésért és a kajáért a B2 International-os arcoknak!

Sziasztok, boldog csütörtököt!

2009. május 29., péntek

easyb próbakör

A CÉG másik fele (nem az amelyikben én működök, hanem a gonosz fele) nagyon kedveli a fitnesse-ben írt teszteket. Az első alkalomtól kezdve nekem nem volt szimpatikus ötlet az, hogy a programomat browserből teszteljem, wiki-ben editáljam a teszteket és ráadásul összelőni a builddel is egy borzalom (ebben a legfőbb gonoszok is egyetértettek). Másoknak se jött át az ötlet. Elkezdtem hát más, kicsit elterjedtebb megoldást keresni.
Kipróbáltam mennyire tud fájni a easyb-vel történő tesztelés és megosztanám veletek:
  • A teszt tulajdonképpen groovy forráskód. Editálhatja az ember eclipse-ből -ha van groovy pluginja-, vagy alighanem netbeans-ből is (nem próblátam ki). Valamennyi highlight-olást kapunk hozzá, meg egy kics code-completiont-t is. Nem sokat egyikből sem.

  • Futtatni ezt így eclipse-ből is lehetséges, de kicsit fapados (mondjuk a fitnesse-hez képest még mindig sci-fi)
  • Maven-ből hajtva kicsit lassú, de rendesen fut.
  • A példa kimenet szerintem viszonylag jól öndokumentáló (fájjon csak az angoloknak amit csinálunk a nyelvükkel):
    3 scenarios executed, but status is failure! Total failures: 1

    Story: situation

    scenario normal everyday life
    given a normal situation
    when there are some problems
    then that is just usual


  • Példa projectet ide pakoltam fel.

2009. május 20., szerda

JUM 2009-05-20

Ma végre összespóroltam rá időt és elhúztam a JUM találkozóra.
Ezek voltak sorrendben:

  1. Révész Tamás: Groovy és Java használata SOA projectekben.
    Cobol backend elé bármit is építeni nem lehet móka. Az előadó nem volt szerintem igazán ellazulva az előadáshoz, kapkodott, amitől nekem kicsit nehezen jött át pár infó, de megpróbálom visszaadni.
    Szóval valamiért cefet sok XSLT-t kell generálniuk, néha egészen nagyokat is, és ezt automatizálták groovy-val. Utánna még kézzel meg kell igazítani (robotok sportja). Szóval csak a build processz és fejlesztés támogatásához használnak groovy-t, élesben nem fut. Gondolom nem tennék szivesen élesbe az 1600 soros scriptet.
  2. Cursin Decurtins: Rapid prototyping with object-oriented databases
    Nyilvánvalóan szívás, amikor egy project elstartolásakor napokig elbíbelődik az ember az architektúra összekalapálásán. Főleg ha csak demó vagy prototype project. Adatbázis, mapping, miegymás. Persze segít valamit, hogy ma már elterjedtek beágyazott relációs adatbázis motorok, mint a derby, de alapvetően sokkal kevesebb meló lehet, ha nem kell mappinget írni. Az objektum adatbázis egyetlen közvetlenül elérhető layer. Példaként a db4o-t mutatta be az előadó. Valóban nagyon egyszerűnek tűnik a lekérdezés, bár volt egy pár példa, ami mögött én csúnya apikat sejtettem. Standard api nincs hozzá, ami talán annyira nem fáj egy prototype-nál. Viszont a mock-os meg a fake-k miért nem jók? Production használatra a szerző nem igazán javasolta egyik terméket sem.
    Szóval ha jól értettem, mitán megcsináltad az egyszerű objektum adatbázison a prototype-t, meg kell írnod relációs adatbázis kezelőre is.
  3. Elek Márton: Amazon WS
    Ez elég pöpec volt. Azt hiszem ideje végre komolyan utánnanézni a témának, bár a bankszámlám számát nem szivesen adnám meg az amazonnak. Mint kiderült az kell nekik, nekem viszont borzasztó rossz tapasztalataim vannak a netes fizetőeszközök megbízhatóságával kapcsolatban.

2009. május 13., szerda

python kitérő

Rövidebb időre átkényszerültem python használatára 3d alkalmazást kalapálni. Nem első ütközés a pythonnal (például itt egy scriptem ami Oracle[TM] MySQL dumpformátumát tömi be PostgreSQL-be... Hmm, lehet ez még hasznos lesz egyszer....), de munkában talán most használtam elösször úgy, hogy nem csak valami gyors egyszeri hegesztés, hanem élesben kell mennie és futnia, ügyfelek nézik majd az eredményeit.
És hát rendesen megszívatott a httplib-bel. Az az alapfelállás, hogy ez a progi egy queue-t polloz melóért, renderel valamit a saját kis 3D enginén és az eredményt szépen visszateszi az queue-ba. Mivel persze az eredmény egy szép nagy kép, gondoltam file uploaddal elpostolom. A probléma már itt elkezdődött, ugyanis a httplib ilyet nem tud. Az urllib sem tud, a későbbi python verziókban megtalálható ezeknek a libraryknak a 2-es verziója (httplib2, nagyon elegáns), de azok sem tudnak ilyesmit.
Valahol megtaláltam, hogy mikorra igérték ennek a javítását, de ezzel inkáb nem keltenék pánikot, nekem amúgy sem volt adott lehetőség, hogy felűbereljek kevésbé régi python verzióra.
Mindenesetre itt van egy nagyon egyszerű és működő megoldás file uploadra. Kis módosítás után már működött is, és boldog voltam hogy ezt is elfelejthetem. Érdemes még ezen a lapon megnézni hányan jöttek alternatív megoldásokkal.
Egészen addig tartott a boldogság, amíg a CI rendszer fel nem kapta a változtatásokat és ki nem próbálta. Az úgy 2-3 perc. Ami a localhoston működött, az valamiért mocsokul nem akart menni a tesztkörnyezeten, legmeglepőbb módon 404-et dobott az MQ, amikor vissza próbálta küldeni a eredményt. Eltartott egy ideig, amíg végigkotorásztam a tesztrendszer konfigurációit, nézegettem a logfilejait, míg végül már wireshark-ot rántottam, és ott is jó ideig néznem kellett míg végre észrevettem: http 1.0-át használt a file uploadhoz. A http 1.0 egy matuzsálem, nem voltak virtuális hostok benne, így az apache-nek végig fogalma sem volt hogy kinek postol a kliens progi.
Innentől még egy szép nagy kalapálás volt, mire sikerült végre rávennem, hogy http 1.1-et használjon a file uploadhoz is.
Úgyhogy a fenti linken látható alternatív megoldásokhoz hozzátenném a saját mégalternatívabb megoldásomat. Még szerencse, hogy mindent tesztelünk, a publikus tesztoldalakon már sokkal nehezebb lett volna kideríteni az igazságot.

Kiváncsi vagyok a profi python programozók ezt hogyan használják. Például a google a legnagyobb python felhasználó. Vajon nekik ez nem fájt?