<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;Dk4BRn0_fSp7ImA9WhBaEU4.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092</id><updated>2013-05-21T13:15:57.345+02:00</updated><category term="jce" /><category term="instrumentation" /><category term="JPA" /><category term="StAX" /><category term="JSP" /><category term="algoritmus" /><category term="cluster" /><category term="MQ" /><category term="Hibernate" /><category term="glassfish" /><category term="Utils" /><category term="JAX-RS" /><category term="vizsga" /><category term="Módszertan" /><category term="open source" /><category term="Oracle" /><category term="IDE" /><category term="SOA" /><category term="scjp" /><category term="Ajax" /><category term="Swing" /><category term="EJB" /><category term="Community" /><category term="JNDI" /><category term="git" /><category term="Tesztelés" /><category term="user interface" /><category term="JAXB" /><category term="Java SE" /><category term="Naplózás" /><category term="Flex" /><category term="lb" /><category term="JAX-WS" /><category term="JMS" /><category term="performance" /><category term="EAI" /><category term="jca" /><category term="Spring" /><category term="Apache" /><category term="xhtml" /><category term="JSON" /><category term="biztonság" /><category term="Design Patterns" /><category term="Servlet" /><category term="xml" /><category term="VisualVM" /><category term="Struts" /><category term="szemantikus web" /><category term="JBoss" /><category term="Java EE" /><category term="scalability" /><category term="Subversion" /><category term="security" /><category term="Library" /><category term="JSR" /><category term="monitorozás" /><category term="könyv" /><category term="UML" /><category term="Oktatás" /><category term="jvm" /><category term="NetBeans" /><category term="batch" /><category term="Tomcat" /><category term="GitHub" /><category term="PKI" /><category term="JMX" /><category term="ha" /><category term="infrastruktúra" /><category term="DocBook" /><category term="oo" /><category term="Maven" /><category term="EclipseLink" /><category term="BI" /><category term="hotspot" /><category term="Ant" /><title>JTechLog</title><subtitle type="html">Java blog</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>115</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/JTechLog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="jtechlog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;D0AMSHY-fSp7ImA9WhBaEEo.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-3351568542494398544</id><published>2013-05-20T20:49:00.002+02:00</published><updated>2013-05-20T20:49:49.855+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-20T20:49:49.855+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Út a szőlőbe</title><content type="html">Biztosan sokan voltatok már úgy egy-egy éjszakába nyúló debugolás közben, hogy most leteszitek a billentyűzetet, és soha többet nem veszitek a kezetekbe. Esetleg &lt;a href="http://www.1000birka.hu"&gt;vesztek ezer birkát, és elmentek birkapásztornak Írországba.&lt;/a&gt; Legtöbbünknek ez azonban csak álom marad, és újra visszatérünk a fejlesztés néha egyhangú, néha azonban sok izgalmat kínáló világába. Viszont van közülünk, aki tényleg megtette, egy fiatal, nagyon tehetséges fejlesztő, egy ifjú titán, aki felhagyott eddigi életével, hivatásával, elköltözött Pestről a Balatonra, a Szent György-hegyre, hogy vidéki szőlész-borász legyen. Olvassátok szeretettel a &lt;a href="http://utaszolobe.blog.hu/"&gt;blogját&lt;/a&gt; erről az útról, és drukkoljunk együtt neki.</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/3351568542494398544/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2013/05/ut-szolobe.html#comment-form" title="1 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3351568542494398544?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3351568542494398544?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2013/05/ut-szolobe.html" title="Út a szőlőbe" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;D0MHRHsyfyp7ImA9WhBXEkk.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-4483245304697303695</id><published>2013-03-25T22:03:00.002+01:00</published><updated>2013-03-25T22:03:55.597+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-25T22:03:55.597+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Szuperdiák Verseny</title><content type="html">A &lt;a href="http://markmyprofessor.com"&gt;Mark My Professzor&lt;/a&gt; oldal Szuperdiák Versenyt szervez olyan hallgatóknak, akik Javát tanulnak vagy tanultak. A jelentkezéshez mindössze egy önéletrajzot kell elküldeni. Ezután egy szakmai zsűri választja ki a döntőbe jutottakat, ahol Java programozással kapcsolatos feladatot kapnak. A legjobb diákokat Apple termékekkel díjazzák. A rendezvény helyszíne a Miskolci Egyetem, ahová a döntőbe jutott, nem miskolci diákok útiköltségét fedezik. A verseny jelentkezési határideje 2013. április 10., időpontja 2013. április 17., további információk a &lt;a href="http://markmyprofessor.com/szuperdiak.html"&gt;http://markmyprofessor.com/szuperdiak.html&lt;/a&gt; címen érhetőek el.</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/4483245304697303695/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2013/03/szuperdiak-verseny.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/4483245304697303695?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/4483245304697303695?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2013/03/szuperdiak-verseny.html" title="Szuperdiák Verseny" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkYNSHo-eSp7ImA9WhBQFUg.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-4963379818802072423</id><published>2013-03-17T22:03:00.001+01:00</published><updated>2013-03-17T22:03:19.451+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-17T22:03:19.451+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><category scheme="http://www.blogger.com/atom/ns#" term="Hibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="JPA" /><title>JPA több one-to-many kapcsolat</title><content type="html">&lt;p&gt;Felhasznált technológiák: Spring 3.2.2, Hibernate 4.1.10&lt;/p&gt;

&lt;p&gt;Már írtam egy &lt;a href="http://jtechlog.blogspot.hu/2012/04/jpa-lazy-loading.html"&gt;postot&lt;/a&gt; a JPA teljesítményhangolásával, valamint a lazy loadinggal kapcsolatban. Ott egy entitáshoz egy másik kapcsolódott, one-to-many kapcsolattal. Ott folytatom, ahol abbahagytam, de most egy entitáshoz két másik entitás kapcsolódik ugyanazon, one-to-many kapcsolattal. Egyrészt megvizsgálom a Hibernate egy jellegzetes hibaüzenetét, valamint elemzek több megoldást is performancia szempontból.&lt;/p&gt;

&lt;p&gt;Az adatmodell a következő osztálydiagramon látható. Egy Employee példányhoz több Phone és több Address példány kapcsolódik.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://yuml.me/d2a0e90e" imageanchor="1" style="display: block; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://yuml.me/d2a0e90e" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;A posthoz tartozó példaprogram &lt;a href="https://github.com/vicziani/jtechlog-jpa-descartes"&gt;letölthető a GitHub-ról&lt;/a&gt;. A projekt letöltése után az 'mvn test' paranccsal futtatható a teszt eset. Ez egy JUnit teszt eset, mely felépíti a Spring contextet, elindít egy beépített HSQLDB adatbázis-kezelőt, létrehozza a táblákat, feltölti adatokkal, majd meghívja a service-t, mely JPA lekérdezéseket használ, és a visszatérési értéket Hamcresttel ellenőrzi. A projekt ebben a postban bemutatott legutolsó megoldást tartalmazza, de megjegyzésben ott van a többi megoldás is.&lt;/p&gt;

&lt;p&gt;Amennyiben elkészítjük a három entitást, és csak a kötelező annotációkkal látjuk el, és azok kötelező paramétereivel, a következő kivételt kapjuk: &lt;code&gt;"org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: jtechlog.descartes.Employee.phones, could not initialize proxy - no Session"&lt;/code&gt;. Az előző postból tudhatjuk, hogy ez azért van, mert a @OneToMany annotáció használatakor a kapcsolódó entitásokat csak akkor tölti be, mikor szükség van rá (default a lazy loading). De mivel a teszt eset kéri le először a kapcsolódó entitásokat, a persistence context már zárva, a session zárva, így a Hibernate ezeket már nem tudja lekérdezni.&lt;/p&gt;

&lt;p&gt;Első megoldás, mely eszünkbe juthat, hogy egészítsük ki a @OneToMany annotációkat a &lt;code&gt;fetch = FetchType.EAGER&lt;/code&gt; paraméterrel. Ekkor a következő kivételt kapjuk, már akkor, mikor elindul a Hibernate: &lt;code&gt;"Deploy time: Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ennek az az oka, hogy a Hibernate ebben az esetben egy joint tartalmazó select utasítást ad ki, és nem tudja kiválasztani, hogy melyik rekord melyik entitáshoz tartozik. A select a következő.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT ...
FROM Employee employee0_
LEFT OUTER JOIN Address addresses1_ 
  ON employee0_.id = addresses1_.employee_id
LEFT OUTER JOIN Phone phones2_ 
  ON employee0_.id = phones2_.employee_id
WHERE employee0_.id = ?
&lt;/pre&gt;

&lt;p&gt;Ezen kivétel mögött igen nagy irodalom áll, és több megoldási javaslatot is találhatunk. Egyrészt használjuk a Hibernate &lt;code&gt;@IndexColumn&lt;/code&gt; annotációját, vagy ha nem akarunk provider függőek lenni, akkor a JPA 2.0-ban megjelent szabványos &lt;code&gt;@OrderColumn&lt;/code&gt; annotációt. Ezt a @OneToMany annotációk mellé kell tenni, valamint a phone és az address táblába kell egy-egy új mező, mely az adott entitás listában elfoglalt pozícióját jelzi, és a JPA provider automatikusan karbantartja (, ahogy a példaprogramban is látható).&lt;/p&gt;

&lt;p&gt;A másik megoldás, hogy mind a két esetben a &lt;code&gt;List&lt;/code&gt; típust átírjuk &lt;code&gt;Set&lt;/code&gt;-re. Az előbbi és ezen megoldás esetében is megmarad a join a lekérdezésben.&lt;/p&gt;

&lt;p&gt;Van még egy megoldás. A @OneToMany annotációk mellé Hibernate specifikus @Fetch annotációt helyezünk el. Ez azt mondja meg, hogy a kapcsolódó rekordokat hogyan töltse be. Paraméterként több módot is meg lehet adni, az alapértelmezett mód a fentebb leírt JOIN, de használhatunk SELECT vagy SUBSELECT értékeket is.&lt;/p&gt;

&lt;p&gt;Mindkettő használata esetén a persistence provider három select utasítást ad ki.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select ... from Employee employee0_ where employee0_.id=?
select ... from Phone phones0_ where phones0_.employee_id=?
select ... from Address addresses0_ where addresses0_.employee_id=?
&lt;/pre&gt;

&lt;p&gt;Itt tehát a két mód között nem látszik különbség. Azonban ha azt a metódust nézzük, mely az összes Employee példányt visszaadja (findEmployees()), azonnal láthatjuk a különbséget. A SELECT mód esetén a phone és az address táblára annyi select utasítást ad ki, amennyi rekordot az employee tábla tartalmazott. A SUBSELECT mód esetén mindig három select utasítást futtat, méghozzá a következőket.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select ... from Employee employee0_ order by employee0_.id
select ... from Phone phones0_ 
  where phones0_.employee_id 
    in (select employee0_.id from Employee employee0_ )
select ... from Address addresses0_ 
  where addresses0_.employee_id 
    in (select employee0_.id from Employee employee0_ )
&lt;/pre&gt;

&lt;p&gt;Láthattuk, hogy hogy működik az eager fetch esetén de én ezt nem szeretem használni, mert ilyenkor mindig eager jönnek le a kapcsolódó entitások, nem tudok választani. Viszont finomabban szabályozható, ha a lekérdezésben adom meg, hogy mit akarok betölteni. Erre a join fetch való. Írjuk is át a lekérdezést, hogy a következő lekérdezést használja:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select distinct e from Employee e 
  join fetch e.phones 
  join fetch e.addresses where e.id = :id
&lt;/pre&gt;

&lt;p&gt;A helyzet ugyanaz, mint az eager fetch esetén, MultipleBagFetchException-t kapunk. Persze megint átállhatunk &lt;code&gt;Set&lt;/code&gt;-re, és ekkor ugyanoda lyukadunk, hogy joint tartalmazó select utasítást kapunk. Mi ezzel a probléma?&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select distinct ... from Employee employee0_ 
  inner join Phone phones1_ 
    on employee0_.id=phones1_.employee_id 
  inner join Address addresses2_ 
    on employee0_.id=addresses2_.employee_id 
  where employee0_.id=?
&lt;/pre&gt;

&lt;p&gt;Igen, jól látható, hogy a fenti select utasítás eredménye egy Descartes-szorzat. Azaz ha a phone táblában van tíz rekord, és a address táblában is van tíz rekord egy adott employee rekordhoz, a lekérdezés száz rekordot fog visszaadni. Ez a probléma az eager fetch-nél is fennáll JOIN mód esetén.&lt;/p&gt;

&lt;p&gt;Mi lehet erre a megoldás? Tudjuk azt, hogy amíg él a persistence context, addig a JPA provider a memóriában tárolja, hogy mik lettek betöltve, és azokat nem kéri be újra. Tehát egyrészt lekérdezzük az Employee entitást joinnal összekötve a Phone entitásokkal, majd egy külön lekérdezésben az Employee entitást joinnal összekötve az Adress entitásokkal. Ez a következőkben látszik.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Transactional(readOnly = true)
public Employee findEmployeeById(long id) {
    em.createQuery("select e from Employee e " +
      "join fetch e.phones where e.id = :id", Employee.class)
        .setParameter("id", id)
        .getSingleResult();
    return em.createQuery("select e from Employee e " +
      "join fetch e.addresses where e.id = :id", Employee.class)
        .setParameter("id", id)
        .getSingleResult();
    }
&lt;/pre&gt;

&lt;p&gt;Megfigyelhetjük, hogy az első lekérdezés eredményével nem csinálunk semmit. Csupán csak arra való, hogy az Employee és a Phone entitásokat a persistence contextbe töltse. A második query igaz, hogy csak a Address entitásokat kéri le, de mivel a Phone entitások már a persistence contextben vannak, hozzáköti őket. Ehhez persze kell a @Transactional annotáció (&lt;code&gt;readOnly = true&lt;/code&gt; paraméterrel a sebesség érdekében), különben mindkét lekérdezéshez külön persistence contextet nyitna, így ugyanúgy LazyInitializationException lenne a jutalmunk. A lefuttatott két select utasítás a következő.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select ... from Employee employee0_ 
  inner join Phone phones1_ 
    on employee0_.id=phones1_.employee_id where employee0_.id=?
select ... from Employee employee0_ 
  inner join Address addresses1_ 
    on employee0_.id=addresses1_.employee_id where employee0_.id=?
&lt;/pre&gt;

&lt;p&gt;Látható, hogy két select fut le, mindegyik eredménye tíz-tíz rekord, szemben a join változattal, ahogy egy select adott vissza száz rekordot.&lt;/p&gt;

&lt;p&gt;A performancia hangolás érdekében még jó tisztában lenni a kiadható hintekkel is, mely persistence providerenként más és más, &lt;a href="http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1215"&gt;Hibernate esetén&lt;/a&gt; hasznos lehet a "org.hibernate.fetchSize" hint, amivel azt állíthatjuk be, hogy hány rekordonként forduljon az adatbázishoz, azaz egyszerre mennyi rekord menjen át Java oldalra. Ennek használatával sikerült akár kétszeres sebességjavulást is elérnem.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/4963379818802072423/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2013/03/jpa-tobb-one-to-many-kapcsolat.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/4963379818802072423?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/4963379818802072423?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2013/03/jpa-tobb-one-to-many-kapcsolat.html" title="JPA több one-to-many kapcsolat" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkEGQ38zfip7ImA9WhNaGE8.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-6577035106335169594</id><published>2013-02-02T16:57:00.000+01:00</published><updated>2013-02-02T16:57:02.186+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-02T16:57:02.186+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="Flex" /><category scheme="http://www.blogger.com/atom/ns#" term="user interface" /><category scheme="http://www.blogger.com/atom/ns#" term="Apache" /><title>Az Apache Flex múltja, jelene, jövője</title><content type="html">&lt;p&gt;Technológiák: Apache Flex 4.9.0&lt;/p&gt;

&lt;p&gt;Sokakat megosztó témáról fogok írni, méghozzá a felhasználói felület technológiákat illetően. Ezeken belül is az &lt;a href="http://flex.apache.org/"&gt;Apache Flex&lt;/a&gt; a vizsgálat tárgya. Próbálok elfogulatlan maradni, de bizonyos kérdésekben óhatatlanul szubjektív leszek. Akár egyetértesz, akár nem, kérlek oszd meg a véleményedet a megjegyzések között.&lt;/p&gt;

&lt;p&gt;A post apropója, hogy az utóbbi pár évben több projektben is használnom kellett az Flexet, valamint érdekelnek és folyamatosan nyomon követem, hogy felhasználói felületek fejlesztésére milyen technológiák vannak, melyek könnyen illeszthetőek a Java platformhoz. A Flex 4.9.0 új verziója 2012. decemberében jelent meg. Ez már a második kiadás, mely új fejlesztéseket is tartalmaz. Az Adobe 2011 novemberében jelentette be, hogy az Apache közösségnek adja a Flex SDK forráskódját. A 4.8.0 verzió még Apache incubator projektként jött ki, az Apache Licence v2 alatt, és nagy újdonságot még nem tartalmazott, főleg az átadás lett formalizálva. Az új verzió azonban már un. top level projectként jött ki. Sőt a cikk írásának pillanatában &lt;a href="https://twitter.com/ApacheFlex/status/296909455612858368"&gt;élesítették az új oldalt is&lt;/a&gt;.

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-qsxYbODPhgM/UQ02tBS5oTI/AAAAAAAAKSk/mYfUevB4aYY/s1600/logo_01_fullcolor_wb.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="190" width="320" src="http://1.bp.blogspot.com/-qsxYbODPhgM/UQ02tBS5oTI/AAAAAAAAKSk/mYfUevB4aYY/s320/logo_01_fullcolor_wb.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;A Flex világra jöttét a RIA (Rich Internet Application) segítette, azaz a cégek olyan eszközöket próbáltak előállítani, melyekkel a desktop alkalmazásokhoz hasonló gazdag felhasználói élményt nyújtó webes alkalmazásokat lehetett készíteni. A Flex eredetileg a Macromedia terméke volt, melyet az Adobe megvásárolt. A Flex 1.0 és 1.5 még komoly szerver oldali komponensekkel járt, de már jelen volt a megjelenítést leíró MXML XML alapú nyelv (Macromedia vagy Magic XML?) és a model és a controller komponensek megírására való ActionScript. A Flex 2 esetén azonban az SDK ingyenesen letölthető volt, csupán a fejlesztőeszközért, a Flex Builder-ért kellett fizetni (, mely Eclipse alapokra épült). Ebben a verzióban már nem volt szükség szerver oldali komponensre, lokálisan buildelhető volt az SWF fájl. A Flex 2-ben került bevezetésre az ActionScript 3 nyelv. A futtatókörnyezete a Flash Player volt.&lt;/p&gt;

&lt;p&gt;A Flex 3 SDK már Mozilla Public License alatt jött ki, és itt jelent meg az AIR (Adobe Integrated Runtime) támogatása. Az AIR nem más, mint egy futtatókörnyezet, mely képes a Flash, Flex alkalmazásokat különböző operációs rendszereken futtatni, desktop alkalmazásként. Sőt, mobilra is elérhető. Az AIR-be telepített alkalmazások persze már több jogosultsággal rendelkeznek, mint a böngészőben futó társaik, pl. elérik a fájlrendszert, nyomtatót, vágólapot, stb. Rendelkezik egy beépített adatbázis kezelővel (SQLite), valamint egy WebKit alapú böngésző komponenssel is. 2010 márciusában jött ki a Flex 4, melynek fejlesztőkörnyezete már Flash Builder néven futott. Fő újítása, hogy megpróbálták közelebb hozni a designert és a fejlesztőt, hogy az előbbi által készített munkák újrafelhasználhatóak legyenek. Lehetővé tette a komponensek egyszerűbb skinezhetőségét is (megjelentek a Spark komponensek). A Flash Builder Premium verziójában már unit tesztelésre alkalmas eszköz is megjelent. A Flex 4.5 újításai a különböző mobil eszközökre való fejlesztést tették lehetővé (Android, BlackBerry Tablet OS és Apple iOS).&lt;/p&gt;

&lt;p&gt;A Flex tehát élt és virágzott, mikor az Adobe sokak meglepetésére az Apache-nak adta a Flex SDK-t. Az ok talán a HTML 5 térnyerése volt, melyet az Adobe is jó iránynak tart. Valamint a Flash platformot akarják speciálisabb irányba vinni, úgymint a játékok (3d támogatás), valamint a prémium kategóriás videólejátszás. Az Adobe azonban nem temeti a Flexet, a nagyvállalati alkalmazások elsődleges platformjaként gondol rá. A nagyvállalati alkalmazásfejlesztésben az érvek a Flex mellett a következők:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gazdag felhasználói felület építhető, mely nem mellesleg tehermentesíti a szerver oldalt.&lt;/li&gt;
&lt;li&gt;Gazdag komponenskészlet, és a komponensek újrafelhasználhatósága a magas fejlesztői produktivitásért.&lt;/li&gt;
&lt;li&gt;Jó beépített és 3rd party komponensek: pl. charting, data visualization, dashboard, OLAP, stb.&lt;/li&gt;
&lt;li&gt;A MVC modell és a binding-ok miatt rendkívül alkalmas data driven alkalmazások kifejlesztésére.&lt;/li&gt;
&lt;li&gt;Modularizáció.&lt;/li&gt;
&lt;li&gt;Nagyvállalati fejlesztésre alkalmas ActionScript nyelv és egységes futtatókörnyezet.&lt;/li&gt;
&lt;li&gt;Nagyvállalati technológiákhoz, mint Java EE, .NET könnyen illeszthető.&lt;/li&gt;
&lt;li&gt;Kifinomult unit és integrációs teszt eszközök.&lt;/li&gt;
&lt;li&gt;Parancssori alkalmazások (fordító, parancssorból futtatható teszt framework) segítségével könnyen illeszthető continuous integration környezetbe.&lt;/li&gt;
&lt;li&gt;Fejlett fejlesztőeszközök (IDE kódszerkesztésre, debug, profile, test, stb.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Talán érdemes egy kicsit azon elmerengeni, hogy miért is jó az ActionScript nyelv, és a sokak által szidott Flash Player vagy AIR környezet. Az ActionScript egy ECMAScript 262 Edition 4 (ES4) szabványon alapuló imperatív, biztonságos, szigorúan típusos, objektumorientált nyelv. Ennek az ECMAScript változat fejlesztése megszakadt, mindenféle csatározások miatt. A mostani böngészők által értelmezett JavaScript amúgy az Edition 5-nek felel meg, és talán már dolgoznak a következő változaton (Harmony). Fontos megjegyezeni, hogy az Adobe aktívan részt vett az ECMAScript szabványok specifikálásában. Az ActionScript ActionScript Byte Code-ra fordul (ABC). A lefordított ActionScript és MXML vagy SWC állományba állítható össze (ShockWave Component) - mely később az SWF-be építhető, vagy közvetlenül SWF állományba (ShockWave File). Ezeket a formátumokat az Open Screen Project keretében tette az Adobe &lt;a href="http://www.adobe.com/devnet/swf.html"&gt;nyílt formátummá&lt;/a&gt;). Ide tartozik még az AMF (Action Message Format) is, mely bináris formátum az ActionScript objektumok hálózaton átvitelére. A fordításkor nyert bájtkód azonban visszafejthető (decompile), obfuszkátorok használata jelenthet részleges megoldást. Ezt a bájtkódot futtatja a Flash Playerbe, vagy az AIR-be épített virtuális gép. Érdekesség, hogy ezekben két virtuális gép van. Az AVM1 az ActionScript 2, míg az AVM2 az ActionScript 3 forrásból fordított bájtkódot futtatja. Az AVM2-ből az Adobe a virtuális gépet, és a benne lévő JIT (Just in time compile-ert) 2006-ban a Mozilla Foundation számára átadta (Tamarin), így nyílt forráskódú. Modern VM-ről beszélünk, hiszen a JIT-tel (, ami futás közben az adott platform gépi kódjára fordít) hatalmas sebességnövekedést értek el (és bevezetésekor a JavaScript interpreterekbe még nem volt ilyen), valamint komplex szemétgyűjtővel is rendelkezik. Érdekes még a nyelvi szintű XML támogatás is, mely szintén szabványon alapul: ECMA-357, azaz ECMAScript for XML (E4X). A virtuális gép használatával nem kell a platformok különbségeivel foglalkozni, a kód hordozható marad közöttük.&lt;/p&gt;

&lt;p&gt;Az Adobe &lt;a href="http://www.adobe.com/devnet/flex/whitepapers/roadmap.html"&gt;közzétette a terveit&lt;/a&gt; a Flex jövőjével kapcsolatban. Továbbra is teljes állású fejlesztőket biztosít a Flex továbbfejlesztésére. Valamint a Flash Buildert továbbra is kereskedelmi termékként árulja, és frissíti, hogy együttműködjön az Apache Flexszel . Az Adobe ígéri, hogy a további öt évben megőrzi a Flash Player és az AIR visszafele kompatibilitását, azaz hogy továbbra is lehessen ezen futtatókörnyezetekben Flex alkalmazást futtatni. Azonban új funkciókat már nem tesz ezekbe a környezetekbe a Flex támogatására.&lt;/p&gt;

&lt;p&gt;(Zárójelben jegyzem meg, hogy érdemes elolvasni az &lt;a href="http://www.adobe.com/devnet/flashplatform/whitepapers/roadmap.html"&gt;Adobe terveit a Flash platformmal kapcsolatban&lt;/a&gt;, mely magában foglalja a Flash Playert és az AIR-t. Természetesen mindkettőt viszi tovább a Windows platformon, és sok ellentétes állítással szemben Apple OS X-en is. Sőt, Adobe AIR alkalmazásokat Mac App Store-on keresztül is lehet értékesíteni. A Linux már kényesebb terület. Az Adobe együtt dolgozik a Google-lel a &lt;a href="https://developers.google.com/native-client/"&gt;PPAPI - kódnevén "Pepper"&lt;/a&gt; kialakításán, mely egy közbülső réteg a böngésző és a különböző pluginok között. A Flash Player azon verzióját, mely ezen az API-n alapszik, a Google a Chrome-ba beágyazva terjeszti. A Google ezen technológiával sokkal biztosabb működést tud elérni, hiszen a plugin összeomlása nem vonja magával a böngésző összeomlását is. Az Adobe Linuxon a Flash Playert más formában nem fejleszti. Sőt, az AIR Linux-os fejlesztésével is leáll. Természetesen a mobil az továbbra is célterület, de kizárólag az Adobe AIR környezetben gondolkozik, de az összes fontosabb platformon - Android, iOS, Blackberry. Az Android browser plugint befejezi, szintén csak a Chrome-os megoldás marad.)&lt;/p&gt; 

&lt;p&gt;Nézzük merre tart az Apache fejlesztés. Az Adobe a következőket adta át:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Flex SDK, mely legfőképp az osztálykönyvtárakat és a fordítót tartalmazza, valamint további eszközöket.&lt;/li&gt;
&lt;li&gt;A Falcon következő generációs ActionScript fordítót.&lt;/li&gt;
&lt;li&gt;A Falcon JS kísérleti fordítót, mely nem Adobe futtatókörnyezetre, hanem JavaScriptre fordít.&lt;/li&gt;
&lt;li&gt;A Mustella funkcionális tesztelésre szolgáló keretrendszert.&lt;/li&gt;
&lt;li&gt;Dolgoznak a BlazeDS átadásán is. Jelenleg a &lt;a href="http://sourceforge.net/adobe/blazeds/wiki/Home/"&gt;SourceForge-on elérhető&lt;/a&gt; LGPL alatt. A BlazeDS egy Java szerver oldali technológia, mely lehetővé teszi a Java szerver oldal és a Flex kliens oldal kommunikációját. Olyan kiváló képességekkel rendelkezik, mint különböző csatornák használata (http, https), Java és ActionScript objektumok automatikus mappelése, publish&amp;subscribe kliensek között, szerver által kezdeményezett kommunikáció, JMS támogatás, &lt;a href="http://www.springsource.org/spring-flex"&gt;Spring integráció&lt;/a&gt;. Úgy kell elképzelni, mint egy Flex-ből indított Java metódushívást. A kommunikáció a már említett AMF-ben történik. A BlazeDS korábban a Adobe LiveCycle Data Services ES része volt.&lt;/li&gt;
&lt;li&gt;Text Layout Framework 3.0.33&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fejlesztés mögött a &lt;a href="http://www.spoon.as/"&gt;Open Spoon Foundation&lt;/a&gt; szervezet is ott áll. A 4.8.0-ban tehát eltávolításra kerültek a trademark bejegyzések, migrálva lett az Adobe issue trackerje &lt;a href="https://issues.apache.org/jira/browse/FLEX"&gt;JIRA-ra&lt;/a&gt;. A 4.9.0 SDK-t már Java 7-tel is lehet fordítani, és jelentős számú hibajavítást tartalmaz. A közösség nagyon pörög. Kijött az új weboldal, a &lt;a href="http://flex.apache.org/installer.html"&gt;Apache Flex SDK Installer 2.0&lt;/a&gt;. A dokumentáció &lt;a href="https://cwiki.apache.org/confluence/display/FLEX/Apache+Flex+Wiki"&gt;Confluence Wikiben&lt;/a&gt; olvasható. Az újdonságokat a &lt;a href="http://blogs.apache.org/flex/"&gt;blogon&lt;/a&gt; lehet követni. A &lt;a href="http://flex.apache.org/community-mailinglists.html"&gt;levelezési lista&lt;/a&gt; is nagyon aktív, a fejlesztői listán csak decemberben több, mint 1800 levél ment.&lt;/p&gt;

&lt;p&gt;Tervek között szerepel még a &lt;a href="http://flex.apache.org/dev-sourcecode.html"&gt;forráskód&lt;/a&gt; Subversion-ről GIT-re átállítása, Maven plugin fejlesztése, dolgoznak a Falcon és Falcon JS fordítón, új komponensek készülnek és fejlődik a tesztelés is.&lt;/p&gt;

&lt;p&gt;Időközben az Adobe is kijött a Flash Builder 4.7.0-val, mely Apache Flex 4.8.0 támogatást tartalmaz. Azonban a kompatibilitási problémák miatt kivették a Design View-t, Data Centric Development Toolst és a Flash Catalist Workflowt.&lt;/p&gt;

&lt;p&gt;Milyen más kliens oldali technológiák vannak, és mikor érdemes az Apache Flexet választani ezek közül? Az Oracle nyomul a JavaFX-szel, a Microsoftnak van egy próbálkozása a Silverlighttal, valamint ott a legnagyobb kihívó, a HTML5/CSS3/JavaScript (innentől csak HTML5-ként hivatkozok rá). A JavaFX még nem elég kiforrott technológia, nagyon változik, bizonytalan még a jövője. A Microsoft felől is ellentmondó hírek jönnek a Silverlighttal kapcsolatban, valamint a Java platformba nehezebben beilleszthető lenne. Versenyben marad tehát a HTML5 irány.&lt;/p&gt;

&lt;p&gt;Abban az esetben, ha speciális követelményeket nem támasztó webes alkalmazásról beszélünk (pl. a legtöbb Interneten megjelenő startup), vagy a fejlesztők már otthonosan mozognak a HTML5 világában, a HTML5 lehet a megfelelő irány. Azonban a Java platformon nevelkedett fejlesztők számára, valamint főként intranetes nagyvállalati vagy a speciális igényekkel rendelkező alkalmazások fejlesztésére (pl. videó, adatvizualizáció) a Flex lehet a legjobb irány.&lt;/p&gt;

&lt;p&gt;A Java fejlesztők számára sokkal egyszerűbb a Flex irányába továbblépni, mint a JavaScript felé. A szigorú típusosság, az objektumorientáltság, a komponensek használata mind e mellett szól. Aki ráadásul esetleg Swingezett is, még egyszerűbb az átállás. Azon keretrendszerekben, melyek Java technológiára épülnek, de HTML5 interfészt generálnak, nem nagyon hiszek. Ott van egy átfordítás, ráadásul két teljesen más célra kifejlesztett technológia között (ne feledjük a HTML dokumentumleíró nyelv!). A HTTP protokoll szintén hatalmas gát, a kérés-válasz alapúságával, a szöveges formátumával, a késleltetéseivel. A HTML 5 nagyon friss, nem hiszem, hogy nagyvállalati alkalmazások fejlesztésére már jó irány. Az Adobe irányt sokan gyűlölik, nagyrészt indokolatlanul. Benne van ebben az, hogy ez volt az első platform, melyben rettentő idegesítő reklámokat lehetett készíteni. A Flash Player stabilitásával is voltak/vannak gondok (tegyük hozzá, hogy bármiben lehet erőforrás pazarló alkalmazásokat fejleszteni). Steve Jobs is célként tűzte ki a Flash eltörlését, melyben szintén sok követője akadt. De azért nézzük végig ezt a fenti történetet. Az Adobe feltűnően sokat tett a nyílt forráskódért rajongó közösségért, valamint a szabványosítási folyamatokért. A technológiai választások is mind logikusak, ha megnézzük, sokban hasonlítanak a Java platformhoz.&lt;/p&gt;

&lt;p&gt;Összegezve úgy gondolom, hogy Java alapú nagyvállalati alkalmazások felhasználói felületének fejlesztésére az egyik leghatékonyabb, legkézenfekvőbb irány a Flex. De igen, benne van, hogy pár év múlva vagy egy nagy közösség által használt elterjedt technológia lesz, de az is lehet, hogy végleg eltűnik. De ez nincs másképp más UI technológiával sem, a verseny még tart, és az Apache Flexnek még vannak esélyei.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/6577035106335169594/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2013/02/az-apache-flex-multja-jelene-jovoje.html#comment-form" title="6 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6577035106335169594?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6577035106335169594?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2013/02/az-apache-flex-multja-jelene-jovoje.html" title="Az Apache Flex múltja, jelene, jövője" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-qsxYbODPhgM/UQ02tBS5oTI/AAAAAAAAKSk/mYfUevB4aYY/s72-c/logo_01_fullcolor_wb.png" height="72" width="72" /><thr:total>6</thr:total></entry><entry gd:etag="W/&quot;A0EMSX49eCp7ImA9WhNUEU4.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-7792248082197894811</id><published>2012-12-26T01:14:00.000+01:00</published><updated>2013-01-02T16:14:48.060+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-02T16:14:48.060+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JSR" /><category scheme="http://www.blogger.com/atom/ns#" term="JSON" /><category scheme="http://www.blogger.com/atom/ns#" term="Java EE" /><title>Java API for JSON processing</title><content type="html">&lt;p&gt;Úgy tűnik, az Oracle eléggé felpörgeti a Java EE 7 (&lt;a href="http://jcp.org/en/jsr/detail?id=342"&gt;JSR 342&lt;/a&gt;) körüli munkálatokat, sorra &lt;a href="https://blogs.oracle.com/jcp/entry/jsr_updates_java_ee_7"&gt;jönnek ki a hírek&lt;/a&gt; az előrehaladásról. Erre szükség is van, hiszen bár a határidőt &lt;a href="http://jcp.org/en/jsr/detail?id=342#updates"&gt;eltolták&lt;/a&gt; 2012 harmadik negyedévéről 2013 első negyedévére, még elég sok specifikáció Early Draftban van.&lt;/p&gt;

&lt;p&gt;A Java EE 7 újdonságai a JCACHE Java Temporary Caching API (&lt;a href="http://jcp.org/en/jsr/detail?id=107"&gt;JSR 107&lt;/a&gt;), Concurrency Utilities for Java EE (&lt;a href="http://jcp.org/en/jsr/detail?id=236"&gt;JSR 236&lt;/a&gt;), Java API for JSON Processing (&lt;a href="http://jcp.org/en/jsr/detail?id=353"&gt;JSR 353&lt;/a&gt;), Java API for WebSocket (&lt;a href="http://jcp.org/en/jsr/detail?id=356"&gt;JSR 356&lt;/a&gt;) , és a &lt;a href="http://jtechlog.blogspot.hu/2012/12/batch-application-for-java-platform-jsr.html"&gt;már említett&lt;/a&gt; Batch Applications for the Java Platform (&lt;a href="http://jcp.org/en/jsr/detail?id=236"&gt;JSR 352&lt;/a&gt;). A többi specifikáció nem új, hanem csak egy új verzió jön ki belőlük.&lt;/p&gt;

&lt;p&gt;A mostani post témája a Java API for JSON Processing (&lt;a href="http://jcp.org/en/jsr/detail?id=353"&gt;JSR 353&lt;/a&gt;), melynek Public Review-ja 2012. december 22-től zajlik. Az JSR oldalán a megszokottakkal ellentétben semmilyen specifikáció nem olvasható, helyette csak az API-t lehet letölteni. Szerencsére a frissebb JCP-nek megfelelően a szabvány fejlesztése átlátható, minden információ megtalálható a projekt &lt;a href="http://json-processing-spec.java.net/"&gt;honlapján&lt;/a&gt;. Az API-t a Batch Applications for the Java Platform szabványhoz hasonlóan szintén újra feltalálták, méghozzá Jitendra Kotamraju (Oracle) vezetésével, bár a támogatók között van a FasterXML cég, mely a &lt;a href="http://jackson.codehaus.org/"&gt;Jackson streaming JSON parser&lt;/a&gt;-ért felelős, valamint Doug Crockford, kinek &lt;a href="http://json.org/"&gt;nagy szerepe volt&lt;/a&gt; a JSON elterjesztésében. Mivel specifikációról beszélünk, az implementációk cserélhetőek lesznek (plug-in provider), és külön &lt;a href="http://java.net/projects/jsonp/"&gt;referencia implementációval&lt;/a&gt; is rendelkezik.&lt;/p&gt;

&lt;p&gt;A JSON kezelés elég gyakori manapság, ezért kívánják szabványosítani a Java berkein belül. Azonban a JSON kezelést két részre kell felbontani. Az egyik a feldolgozás és parse-olás, a másik a binding, mely Java objektumokat feleltet meg JSON struktúrákkal. (Ez a kettősség fennáll az XML esetén is, az előbbire a JAXP, az utóbbira a JAXB ad megoldást.) A Java API for JSON processing csak az előbbivel foglalkozik, ráadásul kétféle módon. Egyrészt áll egy Streaming API-ból, mely a StAX API-hoz hasonlít, valamint egy Object model-ből, mely a DOM API-ra hajaz. A Streaming API csak olvasásra használatos, és a JsonParser interfész a kulcs, ami egy pull parser, azaz mi tudjuk irányítani a feldolgozást, pl. a next() metódus segítségével. Az Object model esetén a JsonReader és JsonWriter használandó, mellyel írni és olvasni is tudunk, és a DOM-hoz hasonlóan a teljes reprezentáció felépül a memóriában. Modern API-hoz méltóan hemzseg tervezési mintáktól. Ritkán fogunk vele közvetlenül találkozni, hiszen általában valamilyen binding megoldást használunk, de amennyiben mégis natívan akarunk JSON-t feldolgozni, a Java EE 7-től kezdődően már szabványos módon tehetjük.&lt;/p&gt;

</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/7792248082197894811/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/12/java-api-for-json-processing.html#comment-form" title="4 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7792248082197894811?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7792248082197894811?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/12/java-api-for-json-processing.html" title="Java API for JSON processing" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>4</thr:total></entry><entry gd:etag="W/&quot;DE4GRHk6eyp7ImA9WhNVEkQ.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-310150438882392547</id><published>2012-12-22T17:31:00.000+01:00</published><updated>2012-12-23T22:08:45.713+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-23T22:08:45.713+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SOA" /><category scheme="http://www.blogger.com/atom/ns#" term="JAX-WS" /><category scheme="http://www.blogger.com/atom/ns#" term="vizsga" /><category scheme="http://www.blogger.com/atom/ns#" term="JAX-RS" /><category scheme="http://www.blogger.com/atom/ns#" term="könyv" /><title>Oracle Certified Expert, Java EE 6 Web Services Developer</title><content type="html">&lt;p&gt;2012. december 12-én tettem le a &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=458&amp;amp;get_params=p_track_id:JEE6WSD"&gt;Oracle Certified Expert, Java EE 6 Web Services Developer&lt;/a&gt; (1Z0-897) vizsgát. Alapvetően a webszolgáltatások (mind SOAP, mind REST) alapfogalmaira, és a JAX-WS 2.2 és JAX-RS 1.1 specifikációkra koncentrál. Ahogy már &lt;a href="http://jtechlog.blogspot.hu/2012/09/oracle-java-vizsgak.html"&gt;korábban írtam róla&lt;/a&gt;, ez a Oracle Certified Professional, Java (SE 5, SE 6, vagy SE 7) Programmer vizsgára épül, de még a régebbi SCJP-vel is letehető.&lt;/p&gt;

&lt;p&gt;A vizsgát a &lt;a href="http://training360.com/"&gt;Training360-nál&lt;/a&gt; tettem, ők intézték a regisztrációt is. A változatosság kedvéért ez most Pearson VUE-nál történik, küldik is utána szépen a tudnivalókat és a számlát levélben. A vizsga ára jelenleg 63 185 Ft. Hogy ne legyen olyan egyszerű, a Pearson VUE-nál is kell regisztrálni, utána az &lt;a href="http://www.certview.oracle.com/"&gt;Oracle CertView programjában&lt;/a&gt; is, ugyanis csak ott tudom az eredményt megtekinteni.&lt;/p&gt;

&lt;p&gt;A vizsga menete alapvetően változatlan, készítenek rólad egy fényképet, beülsz egy terembe hatodmagaddal egy gép elé minden nélkül, és sorban válaszolsz a feltett kérdésekre. Teszt jellegű, 60 kérdés van, 90 perc alatt kell megoldani, és 60%-ot kell elérni. Bejelölhetők a kérdések, hogy még vissza akarsz rájuk később térni, és bármikor kérheted, hogy vigyen végig újra a bejelölt, vagy az összes kérdéseken. A 90 perc elegendő, belefért, hogy nagyon alaposan végigmenjek az összes kérdésen, majd a bejelölteken, majd gyorsan még átnéztem újra az összeset (a végén már pár kimaradt). Annyi változott mostanság, hogy nem ott nyomtatják ki az eredményt előtted, hanem e-mailben kapsz egy értesítést, és egy PDF-et tudsz letölteni a CertView oldaláról. Gyakorlatilag amint kijöttem, már kaptam az értesítést, annak ellenére, hogy 30 perc türelmet kértek.&lt;/p&gt;

&lt;p&gt;A vizsgára felkészülni az SCJP-hez képest sokkal nehezebb volt, hiszen az utóbbihoz rettentő mennyiségű anyag, mock exam, könyv áll rendelkezésre, itt gyakorlatilag csak egy &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=609&amp;amp;p_org_id=8&amp;amp;lang=HU&amp;amp;get_params=dc:D65185GC10,p_preview:N"&gt;Oracle tanfolyam&lt;/a&gt; áll rendelkezésre, aminek nem is teljesen ugyanaz a tematikája, és el sem végeztem. Az eredményben azonban látható, hogy mely témakörben hány kérdést tettek fel, számomra kicsit meglepő:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legjobb gyakorlatok: 9 kérdés&lt;/li&gt;
&lt;li&gt;RESTful webszolgáltatások: 5 kérdés&lt;/li&gt;
&lt;li&gt;RESTful webszolgáltatások megvalósítása EJB-kkel: 3 kérdés&lt;/li&gt;
&lt;li&gt;SOAP webszolgáltatások EJB-kkel: 4 kérdés&lt;/li&gt;
&lt;li&gt;SOAP webszolgáltatások: 4 kérdés&lt;/li&gt;
&lt;li&gt;Alacsony szintű SOAP webszolgáltatások (Dispatcher): 4 kérdés&lt;/li&gt;
&lt;li&gt;Kliensek implementálása: 4 kérdés&lt;/li&gt;
&lt;li&gt;Java EE webszolgáltatások konfigurációja, biztonság beállítása, telepítése: 8 kérdés&lt;/li&gt;
&lt;li&gt;SOAP üzenetszintű biztonság: 7 kérdés&lt;/li&gt;
&lt;li&gt;MTOM/MIME: 7 kérdés&lt;/li&gt;
&lt;li&gt;WS-Addressing: 7 kérdés&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A DOM, SAX, StaX technológiákról csak koncepcionális szinten esett szó, mikor melyiket kell használni, tudjunk a StaX pull parser-jéről. JAX-B kérdésre nem emlékszem. Számomra az volt meglepő, hogy érzésre rengeteg biztonsággal, MTOM-mal és WS-Addressing-gel kapcsolatos kérdés volt, amit ráadásul a különböző könyvek nem jól tárgyalnak. Övön alulinak éreztem a Jersey kliens használatára vonatkozó kérdést is, hiszen az meg nem a szabvány része.&lt;/p&gt;

&lt;p&gt;Felkészülésként mindenképpen érdemes felkeresni a JavaRanch &lt;a href="https://www.coderanch.com/how-to/java/ScdjwsLinks"&gt;ide vonatkozó oldalát&lt;/a&gt;, valamint Mikalai Zaikin &lt;a href="http://java.boot.by/ocewsd6-guide/"&gt;felkészítő anyagát&lt;/a&gt;, ami kicsit hiányos ugyan, de megéri elolvasni. Kereskedelmi felkészítő anyaga az EPractize-nak és a Whizlabs-nak van, én egyiket sem használtam.&lt;/p&gt;

&lt;p&gt;A következő könyvekből készültem: &lt;a href="http://jtechlog.blogspot.hu/2012/08/soa-using-java-web-services.html"&gt;már írtam&lt;/a&gt; Mark D. Hansen: SOA Using Java Web Services (Prentice Hall) könyvéről, mely egy jó kiinduló alap, bár talán a vizsgához nem elég mély. SOAP fronton ezen kívül a Martin Kalin: Java Web Services Up and Running (O'Reilly) könyvből készültem. Ez utóbbi egy rendkívül jó könyv, és bár sokan ezt mondják magukról, ez tényleg gyakorlatias. Már az elején elmondja, hogy hogyan kell debugolni, hogy lehet a dróton átmenő üzenettartalmaz kiíratni, amit még egy könyvben sem láttam ilyen részletesen kifejtve, különböző operációs rendszereken. A felépítése is ilyen, szóval nem a specifikáció alapján, hanem egy természetes íve van, ahogy kellenek az újabb és újabb feature-ök. A mintapéldák sem voltak annyira mondvacsináltak. Egyedül az nem tetszett, ahogy mind a két könyv a REST-ről beszél, feltehetőleg akkr még nem volt ekkora hype, így egyrészt keveset írnak róla, másrészt a JAX-WS specifikációval próbálják megugrani, ami erre alkalmatlan, pláne a JAX-RS-hez hasonlítva. Az utóbbi könyv említi ugyan a Jersey-t, de nagyon felületesen, ennél a vizsgára jóval több kell.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-jYtpOSmP_R8/UNYflaj0amI/AAAAAAAAJ4I/PC-wK8B2_tU/s1600/up_and_running.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="244" src="http://2.bp.blogspot.com/-jYtpOSmP_R8/UNYflaj0amI/AAAAAAAAJ4I/PC-wK8B2_tU/s320/up_and_running.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Ezen kívül a következő dokumentációkat érdemes elolvasni. A &lt;a href="http://metro.java.net/guide/ch01.html"&gt;Metro projekt dokumentációját&lt;/a&gt; mindenképp a security, MTOM, WSIT, WS-Addressing fejezetek miatt, máshol erre nem találunk jó dokumentációt. A &lt;a href="http://docs.oracle.com/javaee/6/tutorial/doc/bnayk.html"&gt;Java EE 6 tutorial&lt;/a&gt; ide vonatkozó fejezete is elég rövid ahhoz, hogy érdemes legyen átlapozni. A SAAJ-ról ugyan nem ír, de az &lt;a href="http://docs.oracle.com/javaee/5/tutorial/doc/bnbhf.html"&gt;előző verzió igen&lt;/a&gt;. Amennyiben nem tiszta, hogy mi a különbség az RPC/Literal, Document/Literal, Wrapped Document/Literal között, &lt;a href="http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/"&gt;itt egy gyakran idézett cikk&lt;/a&gt;. &lt;a href="https://blogs.oracle.com/artf/entry/using_jax_ws_2_1"&gt;Ez a bejegyzés&lt;/a&gt; pedig a WS-Addressing használatáról ír a JAX-WS 2.1-ben.&lt;/p&gt;

&lt;p&gt;A REST témával kapcsolatban a Bill Burke: RESTful Java with JAX-RS (O'Reilly) könyvet ajánlom. Kötelező olvasmány mindenkinek, aki JAX-RS-t fejleszt. Két részből áll. Az egyik leírja a teljes JAX-RS szabványt, 14 fejezetben, példákkal együtt, a másik pedig egy workbook, gyakorlatilag egy tutorial, 10 fejezeten keresztül. Olyan dolgokat mutatott be, melyek létezéséről nem is tudtam a JAX-RS-ben, mindezt példás részletességgel.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-Rh6fHLiDF-k/UNYftpuVQ_I/AAAAAAAAJ4U/DzKhJEA5208/s1600/restful_java.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="244" src="http://4.bp.blogspot.com/-Rh6fHLiDF-k/UNYftpuVQ_I/AAAAAAAAJ4U/DzKhJEA5208/s320/restful_java.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;



&lt;p&gt;Még egy kis magyarázkodás, hogy mi értelme is volt letenni a vizsgát, hiszen közvetlen előnye nincs. Egyrészt én oktatom ezt az anyagot, ezért kapóra jött, hogy egyúttal a vizsgát is leteszem. Másrészt nem árt egy kis vizsgadrukk, az ember munkakörnyezetben már ritkán kerül olyan helyzetbe, hogy egy nagyobb átfogó témakört ilyen alaposan fel kelljen dolgoznia, megtanulnia úgy, hogy még számonkérés is van, ezt a rutint sem szeretném elveszíteni. Persze a papírgyűjtés is motivál, újabb &lt;a href="http://en.wikipedia.org/wiki/Achievement_%28video_gaming%29"&gt;achivement&lt;/a&gt;. Ha a munkahely meg támogatja, akár a vizsgadíj megfizetésével, akár felkészülési idővel, egyszerűen bűn kihagyni.&lt;/p&gt;

&lt;p&gt;A további rész azoknak hasznos, akik vagy komolyan foglalkoznak a témával, vagy le akarják tenni a vizsgát. Megpróbáltam minden fogalmat összeszedni, nekem volt egy vázlat. Talán egy öntesztnek sem utolsó, hogy tényleg tisztában vagy-e mindennel.&lt;/p&gt;

&lt;p&gt;SOAP webszolgáltatások JAX-WS-sel&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java EE 6 2009. dec. 10-én jött ki: JAX-WS 2.2 (JSR 224), JAX-RS 1.1, Web Services Metadata for the Java Platform 2.0 (JSR 181), SOAP with Attachments API for Java (SAAJ) 1.3&lt;/li&gt;
&lt;li&gt;MEP: Message Exchange Pattern, típusai: request/response, oneway, async callback, async polling&lt;/li&gt;
&lt;li&gt;SOAP: 1.2-től kezdve nem rövidítés&lt;/li&gt;
&lt;li&gt;WSDL felépítése: definitions, types: adattípusok definíciója, message: üzenetek defincíciója, message part-(ok)ból áll, portType: operációk halmaza, binding: protokoll és adatformátum specifikációk, pl. soap, ezen belül operáció, input-tal, output-tal, majd service, port: portType (interfész) és binding (implementáció összekapcsolása)&lt;/li&gt;
&lt;li&gt;WS-I: csak RPC/literal vagy document, de az utóbbinál body-n belül csak max egy elem lehet&lt;/li&gt;
&lt;li&gt;WS-I Basic Profile 1.1 egy dokumentum, mely a SOAP 1.1 és WSDL 1.1 szabványokat &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Style és encoding&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RPC/Literal
&lt;ul&gt;
&lt;li&gt;Paramétereket tartalmaz a híváshoz&lt;/li&gt;
&lt;li&gt;Mindig wrapped&lt;/li&gt;
&lt;li&gt;Wrapper element az operation neve&lt;/li&gt;
&lt;li&gt;Állhat több part-ból az input message&lt;/li&gt;
&lt;li&gt;Part mindig type attribútummal van deklarálva (szemben a document element-tel)&lt;/li&gt;
&lt;li&gt;csak a part-ok vannak a types részben leírva&lt;/li&gt;
&lt;li&gt;Part-nak megfelelő elemek névtér nélkül&lt;/li&gt;
&lt;li&gt;Válasz neve nem deklarált&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Document/Literal
&lt;ul&gt;
&lt;li&gt;Dokumentumot tartalmaz a híváshoz&lt;/li&gt;
&lt;li&gt;Lehet több part&lt;/li&gt;
&lt;li&gt;Part mindig element-tel van megadva&lt;/li&gt;
&lt;li&gt;A teljes body tartama a sémában van definiálva&lt;/li&gt;
&lt;li&gt;Operation neve nem szerepel a soap üzenetben&lt;/li&gt;
&lt;li&gt;Part-ok közvetlenül a body-ban vannak, nincs wrapper, névtérrel ellátottak&lt;/li&gt;
&lt;li&gt;Response ugyanígy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Document/Literal wrapped
&lt;ul&gt;
&lt;li&gt;input message-nek csak egy gyereke van, a wrapper&lt;/li&gt;
&lt;li&gt;element-ként leírva, sémával meghatározva&lt;/li&gt;
&lt;li&gt;konvenció szerint operation neve = wrapper neve&lt;/li&gt;
&lt;li&gt;ugyanígy a response-nál is, konvenció szerint a wrapper neve az operation neve + "Response"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JAX-WS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEI&lt;/li&gt;
&lt;li&gt;Kötelező: SIB&lt;/li&gt;
&lt;li&gt;Nem muszáj a SIB-nek implementálnia a SEI-t, megadható az annotációban is, csak nem biztonságos -&gt; futás idejű hiba&lt;/li&gt;
&lt;li&gt;Ha annotációban sincs megadva, implicit SEI&lt;/li&gt;
&lt;li&gt;Opcionális: SEI, WSDL, webservices.xml&lt;/li&gt;
&lt;li&gt;Osztály, public, nem lehet final vagy abstract&lt;/li&gt;
&lt;li&gt;Default public constructor-nak lennie kell, nem lehet finalize, nem tárolhat állapotot&lt;/li&gt;
&lt;li&gt;Metódusai nem lehetnek static vagy final&lt;/li&gt;
&lt;li&gt;Wsgen, wsimport&lt;/li&gt;
&lt;li&gt;A JAX-WS 2.1.6-tól változott az implicit esetén, több esetben lesz kiajánlva a metódus&lt;/li&gt;
&lt;li&gt;Explicit sei esetén az összes publikus metódust kiajánlja, a WebMethod csak további konfigurációkra való&lt;/li&gt;
&lt;li&gt;A wsimport generál: SEI, service, fault-hoz tartozó osztályt, ha kell; paraméter osztályokat, ha kell; Async Reponse Bean, ha kell&lt;/li&gt;
&lt;li&gt;external/embedded binding declaration: sei, exception, service neve, package neve, wrapper style&lt;/li&gt;
&lt;li&gt;JAXB: sémában annotation/appinfo tag-en belül&lt;/li&gt;
&lt;li&gt;JAX-WS kliens: Service.create(url, qname); service.getPort(SEI.class);&lt;/li&gt;
&lt;li&gt;Deploy JDK-ban: Endpoint.publish, egyszálú&lt;/li&gt;
&lt;li&gt;Default: Wrapped Document/Literal, RPC: @SOAPBinding(style = Style.RPC)&lt;/li&gt;
&lt;li&gt;@WebService annotáció targetNamespace attribútuma adja meg a névteret, amúgy a package alapján&lt;/li&gt;
&lt;li&gt;@RequestWrapper, @ResponseWrapper&lt;/li&gt;
&lt;li&gt;WebParam.Mode.OUT, Holder&lt;/li&gt;
&lt;li&gt;Ne wrapper-ek legyenek: customized binding, enableWrapperStyle&lt;/li&gt;
&lt;li&gt;@SoapBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)&lt;/li&gt;
&lt;li&gt;Ha aszinkron klienst akarunk, akkor ismét customized binding: enableAsyncMapping&lt;/li&gt;
&lt;li&gt;AsyncHandler&lt;/li&gt;
&lt;li&gt;Response&lt;/li&gt;
&lt;li&gt;wsimport -extension: SOAP 1.2 esetén&lt;/li&gt;
&lt;li&gt;Overload-olt metódusok esetén problémás&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dynamic Invocation Interface (DII)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dispatcher, Provider&lt;/li&gt;
&lt;li&gt;@WebServiceProvider&lt;/li&gt;
&lt;li&gt;public Source invoke(Source)&lt;/li&gt;
&lt;li&gt;@ServiceMode: PAYLOAD - csak a tartalom, MESSAGE - az egész http kérés, fejlécestől&lt;/li&gt;
&lt;li&gt;@BindingType() - http&lt;/li&gt;
&lt;li&gt;Dispatch - Service.createDispatch&lt;/li&gt;
&lt;li&gt;Https: HttpsURLConnection, HttpsServer&lt;/li&gt;
&lt;li&gt;@WebService-t felismeri a Glassfish, de a @WebServiceProvider-t nem&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Handler&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chain of responsibility tervezési minta&lt;/li&gt;
&lt;li&gt;Logical handler: Source, JAXB - protokollfüggetlen - csak a payload-hoz tud hozzáférni&lt;/li&gt;
&lt;li&gt;SOAP/protocol handler: SOAP, SAAJ, hozzáfér a teljes envelope-hoz&lt;/li&gt;
&lt;li&gt;Kliens oldalon a handler chain-ben nem csak a konfig sorrend dönt, hanem előbb futnak le a logical handler-ek, és csak utána a soap handler-ek&lt;/li&gt;
&lt;li&gt;Programozottan handler hozzáadása: HandlerResolver&lt;/li&gt;
&lt;li&gt;SOAPFaultException&lt;/li&gt;
&lt;li&gt;SOAP 1.2: BindingType annotáció&lt;/li&gt;
&lt;li&gt;SOAP 1.2: mustUnderstand&lt;/li&gt;
&lt;li&gt;Szerver oldalon: WebServiceContext.getMessageContext -&gt; hozzáférés a context-hez (map), és abból a http header-ökhöz&lt;/li&gt;
&lt;li&gt;Kliens oldalon: a port BindingProvider-ré cast-olható, van getRequestContext metódusa&lt;/li&gt;
&lt;li&gt;Dependency injection: WebServiceContext&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MTOM&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MTOM: XSD, @BindingType, publikálásnál: ((SOAPBinding) endpoint.getBinding()).setMTOMEnabled(true); &lt;/li&gt;
&lt;li&gt;Kliens: activation.DataHandler&lt;/li&gt;
&lt;li&gt;Kliens file küldés: ((SOAPBinding)((BindingProvider) port).getBinding()).setMTOMEnabled(true);&lt;/li&gt;
&lt;li&gt;@MTOM annotáció&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WSIT&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metro: azon része mely az MS-sel való együttműködés: WSIT - Webservice Interoperability Technologies - Security, Reliability, Transaction, bootstrapping, optimalization (régen project Tango)&lt;/li&gt;
&lt;li&gt;Bootstrapping: WS-MetadataExchange&lt;/li&gt;
&lt;li&gt;Reliable messaging: egyszeri, pontosan egyszeri üzenettovábbítás - acknowledge-al, sorrend (opcionálisan bekapcsolható)&lt;/li&gt;
&lt;li&gt;Atomic: AtomicTransaction, Coordination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XML and WebServices Security Project (XWSS)&lt;/li&gt;
&lt;li&gt;WS-Security: message content integrity and confidentality, Prompter, Verifier implements CallbackHandler&lt;/li&gt;
&lt;li&gt;WS-Security (x) felett: WS-Policy felette WS-SecurityPolicy (x), WS-PolicyAttachment (x), WS-Trust (x), WS-Privacy, afelett WS-Secure Conversation (x), WS-Federation, WS-Authorization&lt;/li&gt;
&lt;li&gt;WS-Secure conversation - shared security context, több kérés/válasz esetén nem kell mindig az összes security információt küldeni - new security token type&lt;/li&gt;
&lt;li&gt;Trust: security token&lt;/li&gt;
&lt;li&gt;SecurityPolicy, mely a Policy-ra épül: security követelmények és tulajdonságok leírására&lt;/li&gt;
&lt;li&gt;WS-Trust: security token, Security Token Service - STS, az STS SAML tokent küld a kliensnek&lt;/li&gt;
&lt;li&gt;Signing and encription: WSDL-be plusz tag-ek&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WS-Addressing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WS-Addressing: protokollfüggetlen címzés&lt;/li&gt;
&lt;li&gt;Kettő spec van: W3C WS-Addressing, Member Submission WS-Addressing, a Metro mindkettőt támogatja&lt;/li&gt;
&lt;li&gt;Standard tag-ek: To, From, ReplyTo, FaultTo, MessageID, Action, RealtesTo&lt;/li&gt;
&lt;li&gt;Végpont referencia: EPR&lt;/li&gt;
&lt;li&gt;MI header: message information&lt;/li&gt;
&lt;li&gt;Message Addressing Properties (MAPs) &lt;/li&gt;
&lt;li&gt;Anonymous uri: nem címezhető, pl. request/response request párja&lt;/li&gt;
&lt;li&gt;Annotáció: @javax.xml.ws.soap.Addressing, @Action, @FaultAction&lt;/li&gt;
&lt;li&gt;WSDL-ben: wsdl11:port vagy wsdl11:binding tag-be új tag&lt;/li&gt;
&lt;li&gt;Kliens oldal: WebServiceFeature -&gt; AddressingFeature&lt;/li&gt;
&lt;li&gt;BindingProvider.SOAPACTION_URI_PROPERTY-t kell kliens oldalon beállítani&lt;/li&gt;
&lt;li&gt;Két paraméter: enabled, required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SAAJ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Új SOAPMessage létrehozásánál létrehozza a Part-ot, Envelope-ot és Header-t&lt;/li&gt;
&lt;li&gt;Attachment Part, mime headers, Content&lt;/li&gt;
&lt;li&gt;SOAPConnection&lt;/li&gt;
&lt;li&gt;Attachment: Content-Type, -Id, -Location&lt;/li&gt;
&lt;li&gt;Attachment setContent: String, stream, javax.xml.transform.Source vagy javax.activation.DataHandler&lt;/li&gt;
&lt;li&gt;A SOAP 1.1 specifikáció közvetlenül a header-ben csak a következő attribútumokat engedi: actor and mustUnderstand&lt;/li&gt;
&lt;li&gt;A SOAP 1.2 spec. ellenben: role (actor új neve), mustUnderstand, és relay&lt;/li&gt;
&lt;li&gt;Ha van SOAPFault a Body-n belül, nem lehet más&lt;/li&gt;
&lt;li&gt;code, string kötelező, lehet actor, SOAP 1.2-nél code, role, reasonText (locale-lal)&lt;/li&gt;
&lt;li&gt;A kódok QName-ek - SOAP specifikáció definiálja&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RESTful&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Roy Fielding: Architectural Styles and the Design of Network-based Software Architectures, 2000 (HTTP specifikáció egyik írója), Apache Software Foundation egyik alapítója&lt;/li&gt;
&lt;li&gt;Egyedileg címezhető erőforrások: resource, URI&lt;/li&gt;
&lt;li&gt;Uniform, constrained interface for manipulate resources&lt;/li&gt;
&lt;li&gt;Representation-oriented, content negotiation&lt;/li&gt;
&lt;li&gt;Stateless&lt;/li&gt;
&lt;li&gt;Hypermedia As The Engine Of Application State (HATEOAS): embedded links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JAX-RS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JAX-RS 1.1 (JSR 311)&lt;/li&gt;
&lt;li&gt;Referencia implementáció: Jersey&lt;/li&gt;
&lt;li&gt;POJO, annotation alapú&lt;/li&gt;
&lt;li&gt;Annotációk öröklése: super-class előnyt élvez az interfészen lévővel szemben&lt;/li&gt;
&lt;li&gt;Ha az implementáción van annotáció, akkor a többi helyen lévő annotációt nem veszi figyelembe&lt;/li&gt;
&lt;li&gt;Application osztály, kiterjeszteni kell, osztályokat ad vissza, melyet a provider példányosít, illetve példányokat, melyeket singleton-ként használ. Mindkettőn elvégzi az injection-t. &lt;/li&gt;
&lt;li&gt;Application erőforrásokat (@Path annotációval ellátott osztályokat), és provider-eket adhat vissza&lt;/li&gt;
&lt;li&gt;A JAX-RS provider cserélhető, erre van a RuntimeDelegate, saját alkalmazásban nem kell használni&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Provider&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A provider, melyen rajta van a @Provider annotáció, és valamilyen JAX-WS interfészt implementál&lt;/li&gt;
&lt;li&gt;Kell minimum egy publikus konstruktor, akár paraméterezett. Mindig a legtöbb paraméterrel rendelkező konstruktort választja&lt;/li&gt;
&lt;li&gt;Provider pl. a MessageBodyReader, Writer&lt;/li&gt;
&lt;li&gt;Provider pl. a ContextResolver, mellyel saját Context, pl. JAXBContext példányosítható&lt;/li&gt;
&lt;li&gt;ExceptionMapper-ek is provider-ek&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Context&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per request esetén nincs párhuzamossági probléma&lt;/li&gt;
&lt;li&gt;Per request esetén attribútum is injektálható&lt;/li&gt;
&lt;li&gt;Konstruktor paraméter mindig injektálható&lt;/li&gt;
&lt;li&gt;A három első olvasó, aki ide eljut, vendégem egy sörre a következő JUM-on. Dobj egy e-mailt!&lt;/li&gt;
&lt;li&gt;@Context annotációval injektálunk&lt;/li&gt;
&lt;li&gt;A következőkbe injektálhatók: resource, provider, Application leszármazott&lt;/li&gt;
&lt;li&gt;A következők injektálhatók: Application (önmagába nem), UriInfo, HttpHeaders, Request, SecurityContext, Providers&lt;/li&gt;
&lt;li&gt;A Providers-en keresztül hozzá tudunk férni a MessageBodyReader, Writer-ekhez, ContextResolver-hez, ExceptionMapper-hez, azaz amit a Provider annotációval elláthatunk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Erőforrások&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Path&lt;/li&gt;
&lt;li&gt;Root resource class: vagy @Path-tal annotált, vagy van legalább egy Path-tal vagy request method designatorral (@GET, stb.) annotált metódusa&lt;/li&gt;
&lt;li&gt;Request method: request method designator-ral annotált metódus&lt;/li&gt;
&lt;li&gt;Egy metóduson csak egy @GET, @PUT, stb. annotáció lehet, különben deployment error&lt;/li&gt;
&lt;li&gt;A @HttpMethod annotáció egy metaannotáció, mely rajta van a @GET, stb. metódusokon&lt;/li&gt;
&lt;li&gt;HEAD kérés esetén először @HEAD metódust keres, ha nincs, akkor a @GET-et hívja, csak nem ad Response-t&lt;/li&gt;
&lt;li&gt;OPTIONS kérés először @OPTIONS metódust keres, ha nincs választ generál az annotációk alapján -&gt; WADL&lt;/li&gt;
&lt;li&gt;@ApplicationPath globális url megadásra, ehhez jön hozzá a resource-onkénti&lt;/li&gt;
&lt;li&gt;A /{foo} path-ra nem illeszkedik a /foo/bar, de a /{foo: .+} path-ra igen (lásd perjelek értelmezése)&lt;/li&gt;
&lt;li&gt;Amennyiben egy url több path-ra is illeszkedik, a provider a legpontosabbra próbálja illeszteni. Van egy nem minden esetet lefedő precedencia szabály, mely általában jó. Először a literálok számát nézi, majd a template-ek számát, majd a reguláris kifejezésekkel ellátott template-ek számát.&lt;/li&gt;
&lt;li&gt;Nem minden karakter megengedett az uri-ban, valamint van, aminek speciális jelentése van. A többit escape-elni kell. A @Path annotációban nem kötelező escape-elni.&lt;/li&gt;
&lt;li&gt;A subresource olyan POJO, melyhez egy resource POJO továbbítja a kiszolgálást. Nem kell rá @Path annotáció, hiszen nem a root uri-hoz képest figyel, valamint nem kell az Application osztályban regisztrálni.&lt;/li&gt;
&lt;li&gt;Ha az illeszkedő path-ban két mátrix paraméter ugyanazon a néven szerepel, akkor PathSegment-et kell használni, mert nem egyértelmű a @MatrixParam injection. @PathParam List &amp;lt;PathSegment&amp;gt; formában&lt;/li&gt;
&lt;li&gt;@FormParam esetén implicit dekódolás van, @Consumes("application/x-www-form-urlencoded")&lt;/li&gt;
&lt;li&gt;Primitív típus, String mappelésén kívül minden olyan típust mappel, melynek van String paramétert váró konstruktora, vagy statikus valueOf metódusa String paraméterrel&lt;/li&gt;
&lt;li&gt;Van automatikus collection konverzió&lt;/li&gt;
&lt;li&gt;@HeaderParam, @CookieParam mappelési hiba esetén 400-as hiba, amúgy 404&lt;/li&gt;
&lt;li&gt;@DefaultValue annotációval adhatjuk meg az alapértelmezett értékeket&lt;/li&gt;
&lt;li&gt;@Encoded annotációval adhatjuk meg, hogy mi akarjuk dekódolni, tehát azt kapjuk, amit a HTTP ad, dekódolás nélkül&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Content Handlers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A következő típusokat standard MessageBodyReader-ek és Writer-ek kezelik, ezek entity provider-ek&lt;/li&gt;
&lt;li&gt;StreamingInput, StreamingOutput - callback model, általában performancia okokból jobb, ha a provider hív vissza (pl. lehet, hogy új szálon), valamint illeszkedik az aszinkron modellbe.&lt;/li&gt;
&lt;li&gt;InputStream, Reader&lt;/li&gt;
&lt;li&gt;File, byte[], String, char[] is használható input/output paraméterként&lt;/li&gt;
&lt;li&gt;Activation DataSource is kezelendő&lt;/li&gt;
&lt;li&gt;MultivaluedMap&amp;lt;String, String&amp;gt; form értékekhez, dekódolja a provider, használható az @Encoded annotáció&lt;/li&gt;
&lt;li&gt;javax.xml.transform.Source, a Document-et nem definiálja a specifikáció&lt;/li&gt;
&lt;li&gt;JAXB: XmlRootElement, XmlType annotációval jelölt osztályok és JAXBElement példányba burkolt objektumok leképzését is támogatja&lt;/li&gt;
&lt;li&gt;JAXBContext-et tud példányosítani, de felüldefiniálhatjuk ContextResolver&amp;lt;JAXBContext&amp;gt;-ben (pluggable factories), amit az Application-ben definiálhatunk&lt;/li&gt;
&lt;li&gt;JSON-höz nem kell speciális kezelés, egyedül a mime type-ot kell application/json-ként jelölni&lt;/li&gt;
&lt;li&gt;Saját marshallinghoz: MessageBodyWriter, sorbarendezés, legjobb illesztés a mime type-ra, @Provider annotáció, @Produces annotáció&lt;/li&gt;
&lt;li&gt;MessageBodyReader, @Provider, @Consumes annotáció&lt;/li&gt;
&lt;li&gt;isWritable, isReadable - a paraméterként adott objektumot tudja-e kezelni (+generikus típus, annotáció, media type)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Response code, response, exception&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ResponseBuilder-rel előállítható a Response&lt;/li&gt;
&lt;li&gt;WebApplicationException saját kivétel&lt;/li&gt;
&lt;li&gt;Megadható benne saját Response&lt;/li&gt;
&lt;li&gt;Error vagy unchecked exception megy a konténer felé, a többit viszont be kell csomagolni, és úgy megy a konténer felé&lt;/li&gt;
&lt;li&gt;ExceptionMapper a kivételek kezelésére, generikussal paraméterezhető, mindig a kivételre legjobban illeszkedőt keresi&lt;/li&gt;
&lt;li&gt;ExceptionMapper-t a @Provider annotációval kell ellátni&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Content Negotiation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Produces, @Consumes, tehető resource-ra, metódusra, és a content handler-re is&lt;/li&gt;
&lt;li&gt;Variant: media type, language, encoding&lt;/li&gt;
&lt;li&gt;VariantListBuilder: builder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HATEOAS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UriBuilder URI-k összeállítására, template paraméter is használható&lt;/li&gt;
&lt;li&gt;Az UriBuilder egy resource osztályt kapva parmaéterként is képes összeállítani az URI-t&lt;/li&gt;
&lt;li&gt;UriInfo-val is létrehozható UriBuilder, ekkor adott a séma, szerver, port, context&lt;/li&gt;
&lt;li&gt;Cache-elés a CacheControl osztályon keresztül, nincs rá annotáció&lt;/li&gt;
&lt;li&gt;EntityTag osztály az ETag kezelésére&lt;/li&gt;
&lt;li&gt;Szerver oldalon kezelni a If-Modified-Since vagy ETag header-eket: Request interfész (injektálható) evaluatePreconditions metódusai.&lt;/li&gt;
&lt;li&gt;Nem csak cache-elésre használható, hanem konkurrencia kezelésre is, hogy csak akkor történjen a módosítás, ha nem változott az erőforrás&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deploy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy: JAX-RS unaware konténerben egy servlet-et, és annak int-param-ként kell megadni az Application-t, aware konténerben az Application tehető közvetlenül a web.xml-be. Java EE 6-nál nem kell semmi az xml-be, classpath-t bejárja, és nézi az annotációkat.&lt;/li&gt;
&lt;li&gt;@Context annotációval a ServletContext és a ServletConfig injektálható&lt;/li&gt;
&lt;li&gt;Java EE 6 konténerben a szokásos dolgok injektálhatók: @Resource,  @PersistenceContext,  @PersistenceUnit, és  @EJB, támogatja Java EE 6-ban a JSR-299 szabványt.&lt;/li&gt;
&lt;li&gt;Java EE konténer által biztosított autentikáció és authorizáció adott. Programozott esetben a SecurityContext @Context annotációval injektálható&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kliens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Szabvány nem szól róla&lt;/li&gt;
&lt;li&gt;Legegyszerűbb esetben HttpURLConnection&lt;/li&gt;
&lt;li&gt;setDoOutput - request body-ba is lehet írni&lt;/li&gt;
&lt;li&gt;Jersey Client API&lt;/li&gt;
&lt;/ul&gt;
</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/310150438882392547/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/12/oracle-certified-expert-java-ee-6-web.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/310150438882392547?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/310150438882392547?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/12/oracle-certified-expert-java-ee-6-web.html" title="Oracle Certified Expert, Java EE 6 Web Services Developer" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-jYtpOSmP_R8/UNYflaj0amI/AAAAAAAAJ4I/PC-wK8B2_tU/s72-c/up_and_running.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUFQX85fSp7ImA9WhNVEU4.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-7947881624525191071</id><published>2012-12-22T02:03:00.000+01:00</published><updated>2012-12-22T02:03:30.125+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-22T02:03:30.125+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JSR" /><category scheme="http://www.blogger.com/atom/ns#" term="batch" /><category scheme="http://www.blogger.com/atom/ns#" term="Java SE" /><category scheme="http://www.blogger.com/atom/ns#" term="Java EE" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Batch Application for the Java Platform (JSR 352)</title><content type="html">&lt;p&gt;A Java EE 7 szabványba &lt;a href="https://blogs.oracle.com/arungupta/entry/java_ee_7_key_features"&gt;tervezik beletenni&lt;/a&gt; a Batch Application for the Java Platform (&lt;a href="http://jcp.org/en/jsr/detail?id=352"&gt;JSR 352&lt;/a&gt;) szabványt is. Egy kicsit csúszásban vannak, 2012 első negyedévére tervezték a Public Review-t, de csak novemberre sikerült eljutni idáig, és nemrég, december 4-én lett elfogadva.&lt;/p&gt;

&lt;p&gt;A szabvány a Java azon hiányosságát próbálja pótolni, hogy nem nyújtott egységes fogalomrendszert, modellt, leíró nyelvet és környezetet batch alkalmazások fejlesztésére, habár nagyvállalati környezetben az alkalmazások nagy része ilyen jellegű, és a technológia sem friss, hiszen ez a megállapítás már a Cobol alkalmazásokra is igaz volt, és már ott kialakultak az egységes fogalmak, best practice-ek. A batch feldolgozás általában nagy tömegű adattal dolgozó és/vagy számításigényes, nem interaktív, háttérben futó folyamat. Vagy az egész, vagy csak bizonyos részei párhuzamosíthatóak. Gyakori követelmények között szerepel a újraindíthatóság, checkpoint kezelés (leállás esetén honnan lehet újraindulni), párhuzamosság, naplózás, management. A specifikáció erre próbál standard megoldást adni, mind a Java, mind a Java EE környezetben, javax.batch csomagban lévő API-val. A negyedik fejezetben definiálja a fogalmakat, mely egy az egyben a Spring Batch felhasználói kézikönyvének &lt;a href="http://static.springsource.org/spring-batch/reference/html/domain.html"&gt;idevágó fejezete&lt;/a&gt;. A Spring Batch egyedül itt van megemlítve hivatkozásképp.&lt;/p&gt;

&lt;p&gt;A dolog érdekessége éppen ez. A specifikációt &lt;a href="https://sites.google.com/site/chrisvignola/"&gt;Chris Vignola&lt;/a&gt; készítette, aki az IBM színeiben versenyez, és &lt;a href="http://www.ibm.com/developerworks/websphere/techjournal/0801_vignola/0801_vignola.html"&gt;ismeri annak technológiáját&lt;/a&gt;, mely a WebSphere Extended Deployment Compute Grid névet viseli. Azonban megvizsgálta a Spring Batch-t is, és arra jutott, hogy inkább azt veszi alapul. Azonban nem teljes mértékben, hanem bizonyos dolgokat átalakítva, átnevezve (pl. tasklet -&gt; batchlet), bizonyos dolgokat elhagyva, és pár dolgot az IBM megoldásából beemelve. A vicces még az, hogy a referencia implementációt és a TCK-t is az IBM kívánja elkészíteni. Az IBM XML leírója (Job Specification Language) ebben a témában az xJCL nyelv, mely a régi JCL nyelv XML reinkarnációja, és elég egyszerűnek tűnik a Spring leírója mellett. A szabvány számomra meglehetősen szegényes a Spring Batch dokumentációjához képest. A csapatban amúgy szerepel képviselő a Spring oldaláról is.&lt;/p&gt;

&lt;p&gt;Az elfogadás körül is voltak problémák, ugyanis az első verziót azért nem fogadta el két szereplő (London Java Community, Twitter, Inc.), mert nem felelt meg a JCP akkori (2.8) kívánalmainak, miszerint a JSR készítése legyen teljesen átlátható. A specifikáció körüli megbeszélések ugyanis privát levelezési listákon folytak. Ezt javították azzal, hogy a projekt &lt;a href="http://java.net/projects/jbatch"&gt;immár követhető a Java.net&lt;/a&gt;-en. Most már el is lett fogadva a Public Review azzal a feltétellel, hogy az annotációk használatát a végleges verzióban közelíteni kell a Java EE konvenciókhoz, hiszen most jelentősen eltér attól. (A Java EE szerint minden konfigurálható annotációval és XML-lel is, amennyiben mindkettő meg van adva, az XML megadási mód nyer.)&lt;/p&gt;

&lt;p&gt;Véleményem szerint teljesen logikátlan lépés az IBM ilyen erős jelenléte ebben a specifikációban, ha már a Spring Batch lett véve alapul. Érdekes, hogy erről alapvetően nem is lehet olvasni, a fórumon lehet egy két üzenetváltásból elcsípni, hogy a szerző tényleg mindkét megoldást alaposan megvizsgálta. Persze érthető, hogy az IBM-nek ebben a témában sokkal nagyobb a múltja és a részesedése is a rengeteg legacy rendszer miatt. Amennyiben azonban a közösség nem áll a specifikáció mögé, megy a Sun/Oracle többi elfelejtett próbálkozása közé (lásd pl. JDO).&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/7947881624525191071/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/12/batch-application-for-java-platform-jsr.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7947881624525191071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7947881624525191071?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/12/batch-application-for-java-platform-jsr.html" title="Batch Application for the Java Platform (JSR 352)" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D04HR34_cCp7ImA9WhNSGEQ.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-6087464391832021768</id><published>2012-11-02T23:38:00.001+01:00</published><updated>2012-11-02T23:38:56.048+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-02T23:38:56.048+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JMX" /><title>JMX példaprogram</title><content type="html">&lt;p&gt;A &lt;a href="http://jtechlog.blogspot.hu/2009/09/java-monitorozas-es-menedzsment.html"&gt;JMX-ről szóló postomhoz&lt;/a&gt; felkerült egy kis példaprogram a &lt;a href="https://github.com/vicziani/jtechlog-jmx"&gt;https://github.com/vicziani/jtechlog-jmx&lt;/a&gt; címre. Maven-nel build-elhető, és a letöltést követően a 'mvn jetty:run' paranccsal futtatható.&lt;/p&gt;
</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/6087464391832021768/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/11/jmx-peldaprogram.html#comment-form" title="2 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6087464391832021768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6087464391832021768?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/11/jmx-peldaprogram.html" title="JMX példaprogram" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;C0UFQn46cCp7ImA9WhNSGEQ.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-2324167374630342322</id><published>2012-10-14T23:54:00.001+02:00</published><updated>2012-11-02T22:20:13.018+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-02T22:20:13.018+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Design Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="Ajax" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring" /><title>Eseményküldés szerver oldalról</title><content type="html">&lt;p&gt;Technológiák: Spring 3.1.1, DWR 3.0, Guava 13.0.1&lt;/p&gt;

&lt;p&gt;Egy projektben olyan webes keretrendszert használtam, mely képes volt szerver oldalról üzeneteket küldeni a kliens oldal felé. Ezt ugyan a klasszikus http nem teszi lehetővé, hiszen az egy kérés-válasz alapú kommunikációs mód, ahol mindig a kliens kérdez, azonban vannak kerülő megoldások, melyekről később lesz szó. Az első probléma ugyanis nem itt, hanem korábban jelentkezett, méghozzá hogyan lehet egy n-rétegű alkalmazást felkészíteni erre a kommunikációs formára, anélkül, hogy megzavarnánk az eddig kialakult architektúrát és szabályokat. A postban írok ennek a megoldásáról, de két Springes érdekesség is bemutatásra kerül, a contextek hierarchiája, a beépített eseménykezelés, szó lesz a Guava Event Busról is, valamint hogyan lehet &lt;a href="http://directwebremoting.org/dwr/index.html"&gt;Direct Web Remoting&lt;/a&gt; (DWR) használatával a kliens oldalt értesíteni.&lt;/p&gt;

&lt;p&gt;Az alapvető probléma az, hogy ez ellentmond a legtipikusabb esetnek, mikor van egy webes komponensünk, mely behív az üzleti logikába. Középen helyezkedik el ugyanis az üzleti logika réteg, és arra épül rá a webes réteg. A webes réteg az üzleti logikát egy API-n keresztül éri el, viszont jobb esetben erről az üzleti logika nem tud, ő csak az alatt lévő réteget (perzisztens) réteget hívja. Itt viszont pont az ellentettjére van szükségünk, mikor az üzleti logika hív ki a webes rétegbe. Hogy is oldjuk fel az itt lévő ellentmondást?&lt;/p&gt;

&lt;p&gt;Egy megoldás lehet az Observer tervezési minta használata. Gyakori tervezési minta, főleg felhasználói felületeknél használatos, pl. ez húzódik meg az (MVC) Model-View-Controller mögött is, valamint ismerős lehet, ha már használtunk eseménykezelőket, listenereket. Az alapprobléma, hogy van egy objektumunk, és annak állapotának változása esetén egy másik objektumnak el kell valamit végeznie. Ez történhetne úgy is, hogy az egyik objektum közvetlenül hívja a másik objektumot, azonban ennek több hátránya is. Egyrészt szoros kapcsolat van a két objektum között, melyet nem szeretünk, valamint amennyiben újabb és újabb műveleteket kellene elvégeznünk, mindig bővítenünk kell a hívást is. Erre megoldás az, hogy az érdekes állapot változással rendelkező objektumot kinevezzük megfigyeltnek (Observable), és definiálunk egy interfészt, melyeket a megfigyelők implementálnak (Observer). Az Observable objektumon bármennyi Observer implementációt lehet regisztrálni, és amennyiben bekövetkezik az állapotváltozás, az végighívja az összes megfigyelőt. Ezzel megszüntettük a szoros kapcsolatot, a plusz interfész bevezetésével, valamint bármennyi megfigyelőt hozzáadhatunk anélkül, hogy a megfigyeltet módosítani kéne.&lt;/p&gt;

&lt;p&gt;Természetesen jelen példánkban a megfigyelt az üzleti logika, és a megfigyelő pedig a webes rétegben egy olyan komponens, mely a böngészőt tudja értesíteni. Több megoldást is meg fogok mutatni, melyek közül az igényeknek megfelelően lehet választani, és tetszőlegesen személyre szabni.&lt;p&gt;

&lt;p&gt;Példaprogram is született, mely &lt;a href="https://github.com/vicziani/jtechlog-event"&gt;itt elérhető a GitHub-on.&lt;/a&gt; A következő három példát lehet itt találni:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jtechlog-event-eo: java.util.EventObject használatával&lt;/li&gt;
&lt;li&gt;jtechlog-event-ae: Spring ApplicationEvent küldése&lt;/li&gt;
&lt;li&gt;jtechlog-event-geb: Guava Event Busszal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mindhárom példa Maven-nel buildelhető, és a letöltést követően a 'mvn jetty:run' paranccsal futtatható.&lt;/p&gt;

&lt;p&gt;Az alkalmazás a következőképp működik. Be kell hívni egy vagy több böngészőben/böngészőablakban az alkalmazást, majd a szövegbeviteli mezőbe beírni egy szöveget. Ennek a szövegnek az összes kliensen meg kell jelennie.&lt;/p&gt;

&lt;p&gt;A választott webes keretrendszer, mely képes kliens oldalra hívni a DWR. A post végén kitérek ennek mikéntjére, de most minket az érdekel, hogy üzleti oldalról hogy jut el az esemény a DWR-ig. A jtechlog-event-eo projektben erre a standard Java megoldást használom, ahogy az AWT eseménykezelés is működik.&lt;/p&gt;

&lt;p&gt;A service rétegben lévő StatusService osztály fogadja a felhasználó felől az interakciót, és szeretné ezt a többi webes kliensnek továbbítani. Az első példában (jtechlog-event-eo) a service rétegben deklarálok egy StatusEvent esemény osztályt, mely a Javas EventObject osztály leszármazottja. Valamint egy StatusEventListener interfészt, mely a java.util.EventListener leszármazottja. Ezt implementálja webes rétegben a StatusEventSender osztály, mely a böngészőnek továbbítja az eseményt, az implementált onStatusEvent metódusban:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusEventSender implements StatusEventListener {

    @Override
    public void onStatusEvent(StatusEvent statusEvent) {
   // Küldés a böngésző felé, lásd később
    }
}
&lt;/pre&gt;

&lt;p&gt;A StatusService ilyen Listenereket képes regisztrálni, és állapotváltozás esetén hívni. Először egy Spring-es trükköt próbáltam elkövetni, méghozzá az Autowired annotációval automatikusan beállítani ezeket a Listenereket:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusService {

  private List&amp;lt;StatusEventListener&amp;gt; statusEventListeners 
    = new ArrayList&amp;lt;StatusEventListener&amp;gt;();

  public void postStatus(String status) {
    for (StatusEventListener statusEventListener: 
      statusEventListeners) {
        statusEventListener.onStatusEvent(
          new StatusEvent(this, status));
      }
  }

  @Autowired
  public void setStatusEventListeners(List&amp;lt;StatusEventListener&amp;gt; 
      statusEventListeners) {
    this.statusEventListeners = statusEventListeners;
  }
}
&lt;/pre&gt;

&lt;p&gt;A Spring ezt alapból tudná, ugyanis amennyiben az Autowired annotáció rajta van a metóduson, próbálja begyűjteni az összes StatusEventListener interfészt implementáló osztályt, és azt tenni a listába, és azt értékül adni az attribútumnak. A szép elképzelést azonban a Spring context kezelése meghiúsította. Röviden a web contextben lévő beanek nem látszanak a service contextben lévő beanek számára. (Ez alapjában véve elfogadható. A Spring context hierarchia kezeléséről amúgy kevés dokumentáció van, itt található &lt;a href="http://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/"&gt;egy kis kivétel&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Amennyiben a StatusEventSendert átmozgatjuk a service-ek közé, a probléma megoldódik. De amennyiben a klasszikus modellnél akarunk maradni, nekünk kell gondoskodnunk a listenerek regisztrációjáról. Egyrészt így módosul a StatusService:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusService {

  private List&amp;lt;StatusEventListener&amp;gt; statusEventListeners 
    = new ArrayList&amp;lt;StatusEventListener&amp;gt;();

  public void postStatus(String status) {
    for (StatusEventListener statusEventListener: 
        statusEventListeners) {
      statusEventListener.onStatusEvent(new StatusEvent(this, status));
    }
  }

  public void addStatusEventListener(
      StatusEventListener statusEventListener) {
    statusEventListeners.add(statusEventListener);
  }
}
&lt;/pre&gt;

&lt;p&gt;Másrészt a StatusEventSendert kell kiegészíteni a regisztráció hívásával. Gyakorlatilag a bean elkészítése után értesítjük a StatusServicet a meglétéről.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusEventSender implements StatusEventListener {

    @Autowired
    private StatusService statusService;

    @PostConstruct
    private void register() {
        statusService.addStatusEventListener(this);
    }

    @Override
    public void onStatusEvent(StatusEvent statusEvent) {
   // Kliens értesítése
    }
}
&lt;/pre&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-WsVLmQnVWaA/UHszMAPNQEI/AAAAAAAAJXA/QXlIncO4R_s/s1600/event-osztalydiagram.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="155" width="320" src="http://3.bp.blogspot.com/-WsVLmQnVWaA/UHszMAPNQEI/AAAAAAAAJXA/QXlIncO4R_s/s320/event-osztalydiagram.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Ezzel már teljesítettük a feladatot, a StatusService lazán csatolt a StatusEventSenderrel, hiszen nincs rá referenciája, de mégis értesíti azt az állapotváltozásáról.&lt;/p&gt;

&lt;p&gt;A második példában (jtechlog-event-ae) a Spring beépített eseménykezelését szeretném bemutatni. A Springben bármilyen beanből eseményt lehet küldeni, amit más beanek fogadni tudnak. Először megcsináljuk az Eventünket, mely a org.springframework.context.ApplicationEvent leszármazottja.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
public class StatusEvent extends ApplicationEvent {

    private String status;

    public StatusEvent(Object source, String status) {
        super(source);
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
&lt;/pre&gt;

&lt;p&gt;Utána a StatusServicet implementáljuk, mely az eseményt elküldi. Ehhez egy ApplicationEventPublisher-re van szükségünk, melyhez a ApplicationEventPublisherAware használatával lehet hozzáférni. Aztán a publishEvent metódussal tudunk eseményt küldeni.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusService implements ApplicationEventPublisherAware {

  private ApplicationEventPublisher applicationEventPublisher;

  public void postStatus(String status) {
    applicationEventPublisher
        .publishEvent(new StatusEvent(this, status));
  }

  public void setApplicationEventPublisher(ApplicationEventPublisher 
      applicationEventPublisher) {
    this.applicationEventPublisher = applicationEventPublisher;
  }
}
&lt;/pre&gt;

&lt;p&gt;Utána a StatusEventSendert írjuk meg, mely fogadja az eseményt, és értesíti a böngészőt. Implementálja az ApplicationListener interfészt, az onApplicationEvent metódussal.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusEventSender implements 
    ApplicationListener&amp;lt;StatusEvent&amp;gt; {

  @Override
  public void onApplicationEvent(StatusEvent statusEvent) {
    // Böngésző hívása
  }
}
&lt;/pre&gt;

&lt;p&gt;A megoldással pontosan az a baj, melybe az előbbi esetben is belefutottunk, méghozzá a service contextben lévő beanek nem dobhatnak üzenetet a web contextben lévő beaneknek, csupán fordítva. Azaz itt is igaz az állítás, hogy a service réteg nem tudhat a web rétegből. Az a megoldás, hogy a StatusEventSendert áttesszük a service-ek közé, ismét működik.&lt;/p&gt;

&lt;p&gt;Amennyiben komolyabb megoldásra van szükségünk, használhatjuk a Guava könyvtár (Google core Java libraryje, collection komponensekkel, cache-eléssel, párhuzamosságot, Stringeket és fájlokat kezelő segédosztályokkal) Guava EventBus komponensét. A &lt;a href="http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/eventbus/package-summary.html"&gt;csomag leírásában van egy nagyon jó dokumentáció&lt;/a&gt;, hogy miért jobb, mint a Java beépített eseménykezelése, ezért erre most nem térnék ki.&lt;/p&gt;

&lt;p&gt;Először a Springben definiálni kell az EventBust, majd definiálni kell egy POJO eseményt. Az EventBushoz dependency injectionnel hozzá lehet férni.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusService {

    @Autowired
    private EventBus eventBus;

    public void postStatus(String status) {
        eventBus.post(new StatusEvent(status));
    }
}
&lt;/pre&gt;

&lt;p&gt;Az EventBusra regisztrálni kell, és eseményt fogadni a @Subscribe annotáció használatával lehet.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Service
public class StatusEventSender {

    @Autowired
    private EventBus eventBus;

    @PostConstruct
    private void register() {
        eventBus.register(this);
    }

    @Subscribe
    public void onStatusEvent(StatusEvent statusEvent) {
   // Küldés kliens felé
    }
}
&lt;/pre&gt;

&lt;p&gt;A Spring integrációhoz jól jöhet a &lt;a href="https://github.com/armsargis/guava-eventbus-spring"&gt;guava-eventbus-spring&lt;/a&gt; projekt is, de mivel nincs fenn a központi Maven repositoryban, én nem használtam. Ez definiál Spring névteret, így sokkal könnyebben lehet az EventBust konfigurálni, valamint annotáció alapján automatikusan képes beregisztrálni a subscribereket, nem kell nekünk ezt manuálisan megtennünk.&lt;/p&gt;

&lt;p&gt;Most már csak azt az adósságomat kell törleszteni, hogy hogyan lehet DWR-ben a kliens oldal felé üzenetet küldeni. Erre egy nagyon hatékony megoldás áll a rendelkezésünkre: szerver oldali Javaból tudunk JavaScript függvényt hívni! Hogy ez a HTTP-n hogyan történik, a DWR &lt;a href="http://directwebremoting.org/dwr/documentation/reverse-ajax/index.html"&gt;három lehetőséget biztosít&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polling: nem kell magyarázni, szabványos időközönként megkérdezi a szervert, hogy van-e függvényhívás&lt;/li&gt;
&lt;li&gt;Comet: nyit egy HTTP kérést, és az addig blokkolódik, míg nem történik valami, vagy timeout&lt;/li&gt;
&lt;li&gt;Piggyback: ha történik amúgy is egy szerver oldali kérés, abban adott válaszban küldi vissza a DWR a függényhívás tényét is&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mindegyiknek megvan az előnye és hátránya. Alapban csak a Piggyback van bekapcsolva, a web.xml-ben, valamint a JavaScriptben kell kavarni a Reverse Ajax bekapcsolásához.&lt;/p&gt;

&lt;p&gt;Nézzük a JavaScript oldalt:&lt;/p&gt;

&lt;pre class="brush: js"&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
 // http://docs.jquery.com/Using_jQuery_with_Other_Libraries
 $j(function () {
  dwr.engine.setActiveReverseAjax(true);
  $j(&amp;quot;#statusForm&amp;quot;).submit(function () {
   statusDwrService.postStatus($j(&amp;quot;#statusInput&amp;quot;).val());
   return false;
  });
 });

 function showStatus(status) {
  $j(&amp;quot;#statusDiv&amp;quot;).html(status);
 }
&amp;lt;/script&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Egyrészt bekapcsolja a Reverse Ajaxot. Valamint a statusForm HTML form kitöltésekor meghívja a szerver oldali postStatus metódust. Valamint definiál egy showStatus metódust, melyet meghívva megjelenik a szerver oldalról érező üzenet. Mindez JQuery használatával.&lt;/p&gt;

&lt;p&gt;A szerver oldali hívás a következőképp néz ki:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
    public void onStatusEvent(StatusEvent statusEvent) {
        ScriptBuffer scriptBuffer = new ScriptBuffer();
        scriptBuffer.appendCall("showStatus", statusEvent.getStatus());
        WebContext webContext = WebContextFactory.get();
        String currentPage = webContext.getCurrentPage();
        Collection sessions = 
          webContext.getScriptSessionsByPage(currentPage);
        for (Iterator i = sessions.iterator(); i.hasNext(); ) {
            ScriptSession session = (ScriptSession) i.next();
            session.addScript(scriptBuffer);
        }
    }
&lt;/pre&gt;

&lt;p&gt;Ez hívja meg a kliens oldalon a showStatus JavaScript metódust.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/2324167374630342322/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/10/esemenykuldes-szerver-oldalrol.html#comment-form" title="3 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2324167374630342322?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2324167374630342322?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/10/esemenykuldes-szerver-oldalrol.html" title="Eseményküldés szerver oldalról" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-WsVLmQnVWaA/UHszMAPNQEI/AAAAAAAAJXA/QXlIncO4R_s/s72-c/event-osztalydiagram.png" height="72" width="72" /><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;CUAMQn8-cSp7ImA9WhJbFk0.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-1914186509497168462</id><published>2012-09-25T22:09:00.001+02:00</published><updated>2012-09-25T22:09:43.159+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-25T22:09:43.159+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GitHub" /><title>GitHub Pages</title><content type="html">&lt;p&gt;Az egyetemi szerveren lévő honlapom a diploma megszerzése után tizenegy évvel egyik napról a másikra leállt. Így másik megoldás után kellett néznem. A legkézenfekvőbb választásnak a &lt;a href="http://pages.github.com/"&gt;GitHub Pages&lt;/a&gt; tűnt, hiszen egyre többet használom, ráadásul ingyenes. Azért tetszik különösen, mert egyrészt egyszerre meg van oldva az oldalam verziókezelése és publikálása. Valamint sablonokon alapul, így megvalósítható a különböző oldalrészek újrafelhasználása, azaz a fejlécet, menüt és láblécet csak egyszer kell definiálni, ez különösen jól jön karbantartáskor. Az első lépések megtételében segít a kellően részletes &lt;a href="https://help.github.com/categories/20/articles"&gt;dokumentáció&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Az új oldal tehát elérhető a &lt;a href="http://vicziani.github.com/"&gt;http://vicziani.github.com/&lt;/a&gt; címen, valamint a forrása is böngészhető a &lt;a href="https://github.com/vicziani/vicziani.github.com"&gt;https://github.com/vicziani/vicziani.github.com&lt;/a&gt; címen.&lt;/p&gt;

&lt;p&gt;Eddig elég manuális megoldást használtam, &lt;a href="http://jtechlog.blogspot.hu/2009/03/szoveg-generalas.html"&gt;Ant-ból hívtam Apache Texen-t&lt;/a&gt;, mely a háttérben Velocity-t használ. A GitHub megoldása ennél sokkal jobban kézre esik.&lt;/p&gt;

&lt;p&gt;Amennyiben statikus html oldalakat akarunk kirakni, nagyon egyszerű a használata, létre kell hozni egy username.github.com publikus repository-t, ahol értelemszerűen a username a felhasználónevünk. Kizárólag ezt a címet foglalhatjuk le, más névvel nem működik. Generálhatunk oldalt az automatikus generátor segítségével is, ekkor egy témát kell kiválasztanunk, és a &lt;a href="http://daringfireball.net/projects/markdown/syntax"&gt;Markdown&lt;/a&gt; leíró nyelvvel leírni. Én a manuális utat választottam, mikor is a html-t én írom meg. Parancssori klienst használok, a repository-t ugyanúgy kell kezelni, mint bármely mást. Létre kell hozni a könyvtárat, elhelyezni benne az állományainkat, majd kiadni a következő parancsokat (természetesen a felhasználónevet lecserélve):&lt;/p&gt;

&lt;pre&gt;
git init
git add .
git commit -m "First commit"
git remote add origin https://github.com/vicziani/vicziani.github.com.git
git push -u origin master
&lt;/pre&gt;

&lt;p&gt;Ezen parancsokat kiadva rövidesen egy e-mailt kapunk, hogy az oldalunk sikeresen legyártásra került, kicsit várjunk, de a további módosításainkat már azonnal érvénybe lépteti.&lt;/p&gt;

&lt;pre&gt;
From: GitHub noreply@github.com
Subject: Page build successful

Your page has been built. If this is the first time you've pushed, it may take 
a few minutes to appear, otherwise your changes should appear immediately.
&lt;/pre&gt;

&lt;p&gt;Amennyiben kicsit bonyolultabb dolgokra van szükségünk, használhatjuk a Ruby-ban implementált &lt;a href="https://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt; generátort. Ennek használatával valamilyen leíró nyelven meg kell adnunk a tartalmat (HTML, Textile, Markdown, Liquid), és ebből előállítja a HTML kimenetet, melyet bárhová kirakhatunk statikus tartalomként. A Jekyll segítségével akár blogot is írhatunk, amikor csak a blogbejegyzéseket kell megszerkeszteni, hozzá a körítést a Jekyll legenerálja. Könnyebbség ráadásul, hogy nem nekünk kell a generálást meghívni, hanem a push után automatikusan a GitHub szerverein történik, így azonnal láthatjuk az eredményt.&lt;/p&gt;

&lt;p&gt;Nézzünk is egy egyszerű példát. A könyvtárstruktúra kötött, a főkönyvtárba opcionálisan elhelyezhető a _config.yml állomány, mellyel a generálást lehet konfigurálni. Az _includes könyvtár tartalmazhatja az újrafelhasználható oldalelemeket ({% include file.ext %} szintakszissal használandóak), míg a _layouts könyvtár az oldal sablonokat. A _layouts könyvtárba helyezzük el ennek alapján a default.html állományt:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

{{ content }}

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Valamint a főkönyvtárba az index.html állományt:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
---
layout: default
---

Hello GitHub Pages!
&lt;/pre&gt;

&lt;p&gt;Ahogy az várható, a Jekyll végigmegy azokon az állományokon, mely elején a három kötőjelet találja (vigyázzunk, ne szerepeljen a file elején a &lt;a href="http://en.wikipedia.org/wiki/Byte_order_mark"&gt;BOM&lt;/a&gt;, és a sablonban a {{ content }} helyére beszúrja a fájl tartalmát. Persze ezt tovább bonyolíthatjuk, ha pl. oldalanként külön címet akarunk, akkor definiáljunk egy változót a sablonban (default.html):&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
...
&amp;lt;title&amp;gt;{{ page.title }}&amp;lt;/title&amp;gt;
...
&lt;/pre&gt;

&lt;p&gt;Majd állítsuk be az értékét a konkrét oldalon (index.html):&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
---
layout: default
title: GitHub pages
---

Hello GitHub Pages!
&lt;/pre&gt;

&lt;p&gt;A Jekyll a &lt;a href="http://liquidmarkup.org/"&gt;Liquid&lt;/a&gt; template engine-t használja. A standard Liquid &lt;a href="http://liquid.rubyforge.org/classes/Liquid/StandardFilters.html"&gt;filtereket&lt;/a&gt; a Jekyll &lt;a href="https://github.com/mojombo/jekyll/wiki/liquid-extensions"&gt;továbbiakkal egészítette ki&lt;/a&gt;. Például régóta szerettem volna, hogyha generáláskor bekerül az aktuális dátum a Date html meta tag-be. Ráadásul nem is akárhogyan, henm a HTML szabvány által ajánlott ISO 8601 formátumban (pl. 2012-09-25). Ehhez a következőt kellett csinálni:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;meta name=&amp;quot;Date&amp;quot; lang=&amp;quot;hu&amp;quot; content=&amp;quot;{{ site.time | date: '%Y-%m-%d' }}&amp;quot;/&amp;gt;
&lt;/pre&gt;

&lt;p&gt;A Jekyll &lt;a href="https://github.com/mojombo/jekyll/wiki/template-data"&gt;adja&lt;/a&gt; a site.time adatot, és ez a date filterrel formázott.&lt;/p&gt;

&lt;p&gt;Persze jöttek nehézségek is, pl. a title változóba szerettem volna kettőspontot elhelyezni. Ekkor a következő hibaüzenet fogadott:&lt;/p&gt;

&lt;pre&gt;
Building site: /cygdrive/d/download/qqqq -&gt; /cygdrive/d/download/qqqq/_site
/usr/lib/ruby/1.9.1/psych.rb:203:in `parse': (&lt;unknown&gt;): mapping values are not allowed in this context at line 3 column 20 (Psych::SyntaxError)
        from /usr/lib/ruby/1.9.1/psych.rb:203:in `parse_stream'
&lt;/pre&gt;

&lt;p&gt;Megoldásként a címet idézőjelek közé kell tenni:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
title: "GitHub: pages"
&lt;/pre&gt;

&lt;p&gt;Ahhoz, hogy ne csak élesben tudjam kipróbálni a generálást, fel szerettem volna tenni a Jekyllt saját gépre is. (Van olyan lehetőség is, hogy a Jekyll egy web szervert futtat, és úgy lehet kipróbálni a tartalmat.) Linuxon ez valószínűleg egy egyszerűbb művelet, én Windowsra próbáltam, Cygwin környezettel. Ez már varázslás kategória, &lt;a href="http://matt.scharley.me/2012/03/10/windows-cygwin-and-jekyll.html"&gt;ebből a cikkből&lt;/a&gt; indultam ki. (Közben próbálkoztam Python megvalósítással is, létezik az is, &lt;a href="http://obraz.pirx.ru/"&gt;Obraz&lt;/a&gt; néven, de az a &lt;a href="http://jinja.pocoo.org/"&gt;Jinja2&lt;/a&gt; Python-ban implementált template engine-t használja, és vannak ugyan átfedések, de inkompatibilitás is bőven, a fentebb említett filterek például különböznek.&lt;/p&gt;

&lt;p&gt;Ezt feltéve újabb probléma fogadott, nem sikerült a generálás, és a következő jelent meg a konzolon:&lt;/p&gt;

&lt;pre&gt;
Liquid Exception: incompatible character encodings: UTF-8 and CP852 in default
&lt;/pre&gt;

&lt;p&gt;Erre is volt megoldás, természetesen a karakterkódolással volt a probléma, ezt a következőképp lehet orvosolni:&lt;/p&gt;

&lt;pre&gt;
set LC_ALL=en_US.UTF-8
set LANG=en_US.UTF-8
&lt;/pre&gt;

&lt;p&gt;Ezzel tökéletesen tesztelhető lokálisan a Jekyll generálás, így bízhatunk, hogy a Github Pages is ugyanígy fog működni. Nem csak magunknak, hanem egy szervezetnek, és a projektjeinknek is tudunk így oldalakat készíteni. Java projekteknél pl. a mvn site parancs kimenetét lehet így feltenni, sőt akár Maven repository-ként is használhatjuk.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/1914186509497168462/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/09/github-pages.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/1914186509497168462?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/1914186509497168462?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/09/github-pages.html" title="GitHub Pages" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DU4AQno8fCp7ImA9WhJaEkg.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-761129547306460114</id><published>2012-09-16T23:49:00.000+02:00</published><updated>2012-10-03T11:52:23.474+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-03T11:52:23.474+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vizsga" /><title>Oracle Java vizsgák</title><content type="html">&lt;p&gt;Mióta letettem a 6-os Javahoz tartozó &lt;a href="http://jtechlog.blogspot.hu/2009/10/scjp.html"&gt;SCJP&lt;/a&gt; vizsgát, elég sok minden változott, így érdemes még egyszer rátekinteni. Egyrészt az Oracle felvásárolta a Sunt, és ez a vizsgáknál is látszik, próbálja idomítani a jelenlegi Associate, Professional, Master vonalba. Az Sun Certified Java Programmer, majd későbbi nevén az Oracle Certified Professional Java SE Programmer helyét most két vizsga vette át. Egyrészt &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=41&amp;p_org_id=&amp;lang=&amp;p_exam_id=1Z0_803"&gt;1Z0-803 - Java SE 7 Programmer I&lt;/a&gt;, valamint a &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=41&amp;p_org_id=&amp;lang=&amp;p_exam_id=1Z0_804"&gt;1Z0-804 - Java SE 7 Programmer II&lt;/a&gt;. Az előbbi alap Java programozói tudást tesztel, tisztában kell lenni a Java alapjaival, valamint az objektumorientáltság alapfogalmaival. Ez kicsit több, mint a Sun Certified Java Associate, mely nem követelt meg ekkora programozói tudást, inkább egy áttekintő képet próbált adni a Java platformmal kapcsolatban, így egy kicsit a webes technológiákat, mobil programozást és az UML-t is érintette. A Java SE 7 Programmer I ezzel szemben kizárólag a Java programozási nyelvre megy rá. A Java SE 7 Programmer II már sokkal mélyebben kérdez bele az objektumorientált fogalmakba és konstrukciókba és kivételekbe, valamint új téma a generikusok, Collections Framework, String műveletek, Java I/O, Java File I/O (NIO.2), szálak, lokalizáció és nem is az Oracle lenne, ha nem került volna bele a JDBC. Ez az Oracle kommunikációja szerint komolyabb, mint az SCJP volt. A második vizsgának előfeltétele az első vizsga. Akinek SCJA vagy OCJA 5/6 vizsgája van, az sajnos semmit nem ér, újra kell tennie a Java SE 7 Programmer I vizsgát. Szerencsére az Oracle eddigi gyakorlatával szakítva nem kötelező az Oracle tanfolyamok elvégzése, csak erősen ajánlott. (Ezen tanfolyamok elérhetőek a vizsgák oldalairól.) Persze akinek már megvan az SCJP vagy az OCPJP, az se szomorkodjon, ugyanis létezik egy upgrade vizsga &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=41&amp;p_org_id=&amp;lang=&amp;p_exam_id=1Z0_805"&gt;1Z0-805 - Upgrade to Java SE 7 Programmer&lt;/a&gt; néven. Itt a témakörök: Java 7 nyelvi újdonságai, tervezési minták, JDBC, párhuzamos programozás új elemei, lokalizáció és a Java File I/O (NIO.2).&lt;/p&gt;

&lt;p&gt;A többi dolog alapjában véve megmaradt, minden vizsgára jellemző, hogy 90 tesztkérdés, 140-150 perc, 60-77% megfelelés. Lesz könyv is &lt;a href="http://www.amazon.com/Programmer-Study-Guide-1Z0-803-Certification/dp/0071772006"&gt;OCA/OCP Java SE 7 Programmer I &amp; II Study Guide (Exams 1Z0-803 &amp; 804) (Certification Press)&lt;/a&gt;. A vizsgák ára darabja kb. 65 000 Ft, ez azonban több, mint régen, hiszen most ugyanahhoz a szinthez két vizsgát kell letenni, így ennek kétszeresével kell számolni.&lt;/p&gt;

&lt;p&gt;Master szintű vizsga még nincs, arra várnunk kell, a hírek szerint fejlesztés alatt. Azonban szerencsére még bármelyik régebbi vizsgával (valamint az újból a Professional, azaz kettes szintűvel) is letehetők az alábbi Oracle Certified Expert vizsgák: Java EE 6 Enterprise JavaBeans Developer, Java EE 6 Java Persistence API Developer (e kettőről már írtam &lt;a href="http://jtechlog.blogspot.hu/2011/02/ejb-es-jpa-developer-certified-expert.html"&gt;korábban&lt;/a&gt;), Java EE 6 Web Services Developer, Java Platform, EE 6 Web Component Developer, Java ME 1 Mobile Application Developer. Java EE 7 még sehol, valamint a 6-os sorozatból sem létezik Enterprise Architect, ahogyan az 5-öshöz volt (, feltehetőleg EE-ből ez lenne a Master szint).&lt;/p&gt;

&lt;p&gt;A véleményem a vizsgáról azóta sem változott. Amíg az Oracle nem tesz valamit itthon, addig ez nem lesz elfogadott, esetleg megkövetelt vizsga. Viszont az ember kipróbálhatja önmagát, jó juttatás lehet ez a cégek részéről, és mint felvételiztető is becsülöm azt, aki időt és energiát áldozott a vizsga letételére, hiszen biztos, hogy tanult meg új dolgokat, szélesedett a látóköre, és a fogalmakat és elnevezéseket is ezentúl konzisztensen tudja használni, így könnyebb lesz vele a kommunikáció. Viszont a vizsgától még nem lesz senki jó programozó.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/761129547306460114/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/09/oracle-java-vizsgak.html#comment-form" title="8 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/761129547306460114?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/761129547306460114?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/09/oracle-java-vizsgak.html" title="Oracle Java vizsgák" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>8</thr:total></entry><entry gd:etag="W/&quot;CEYCRHwzfyp7ImA9WhJVGEU.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-3605609953726890781</id><published>2012-09-05T23:56:00.000+02:00</published><updated>2012-09-05T23:56:05.287+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-05T23:56:05.287+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>JUM XIX. bejelentés</title><content type="html">&lt;p&gt;Újra megrendezzük a &lt;a href="http://wiki.javaforum.hu/display/JUM/Home"&gt;JUM&lt;/a&gt;-ot, mely egy alkalmi összejövetel, ahol a magyarországi Javaval foglalkozó szakemberek oszthatják meg a tapasztalataikat egymással. Immár 19. alkalommal kerül megrendezésre 2012. szeptember 19-én, a helyszín ezúttal a &lt;a href="http://www.training360.com/"&gt;Training360&lt;/a&gt;. Auth Gábor fog előadni a Java 8 Lambda expressions témakörben, Kovács Richárd beszél a Grailses tapasztalatairól, én pedig két projektet, esettanulmányt és eszközt mutatok be a munkafolyamatok témakörében (Ant, &lt;a href="http://activiti.org"&gt;Activiti&lt;/a&gt;). További információk a &lt;a href="http://wiki.javaforum.hu/pages/viewpage.action?pageId=28442870"&gt;bejelentésben&lt;/a&gt;, regisztráció szükséges. Gyertek minél többen!&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/3605609953726890781/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/09/jum-xix-bejelentes.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3605609953726890781?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3605609953726890781?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/09/jum-xix-bejelentes.html" title="JUM XIX. bejelentés" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0UBR30zcSp7ImA9WhJXGUU.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-7550091435364332920</id><published>2012-08-14T23:52:00.000+02:00</published><updated>2012-08-14T23:54:16.389+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-14T23:54:16.389+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="SOA" /><category scheme="http://www.blogger.com/atom/ns#" term="JAX-WS" /><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><title>Webszolgáltatások integrációs tesztelése soapUI és JUnit használatával</title><content type="html">&lt;p&gt;Használt technológiák: JAX-WS 2.2.6-2, JUnit 4.10, soapUI 4.5.1, Maven 3.0.3&lt;/p&gt;

&lt;p&gt;Már többször említettem a soapUI-t, mely az egyik legelterjedtebb eszköz webszolgáltatások fejlesztéséhez. Alapvetően egy webszolgáltatás teszteléséhez használatos kliensnek indult, de rengeteg mindennel kiegészítették, így szinte minden feladatot képes megoldani ezen a területen. Nagyon intuitív grafikus felülettel rendelkezik, és van ingyenes és kereskedelmi verziója is (&lt;a href="http://www.soapui.org/About-SoapUI/compare-soapui-and-soapui-pro.html"&gt;összehasonlítás&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A legegyszerűbb, és leggyakrabban használt funkció, hogy elég megadni a WSDL URL-jét, és ehhez képes példa kéréseket gyártani. A kitöltendő paramétereket kérdőjellel jelöli meg, az opcionálisakat megjegyzéssel, és kitöltés után azonnal be tudjuk küldeni a kérést, melyre kapott választ azonnal megmutatja (a natív HTTP kérést és választ is). Ennél izgalmasabb talán, hogy teszt suite-okat is össze lehet állítani, benne test case-ekkel. Tudunk generáltatni példa kéréseket, és a válaszokra ellenőrzéseket, asserteket tudunk tenni. Ezek lehetnek egyszerű szöveg tartalmazások, XPath, XQuery kifejezések is, de akár Groovy script is. Felvehetünk property-ket, melyek értékét állíthatjuk, illetve a kérésekbe behelyettesíthetjük. Természetesen Groovy script-ből is használhatjuk őket. Ezekkel lehet pl. megoldani, hogy az első webszolgáltatás kérés visszaad egy sessionid-t, és később azt akarjuk küldeni a további webszolgáltatás kérésekben.&lt;/p&gt;

&lt;p&gt;Írtam is erre egy apró projektet, mely &lt;a href="https://github.com/vicziani/jtechlog-soapui-testing"&gt;elérhető a GitHub-on&lt;/a&gt;. Az ötletet a w3schools-ról vettem, ahol ki van ajánlva egy &lt;a href="http://www.w3schools.com/webservices/tempconvert.asmx"&gt;TempConvert&lt;/a&gt; webszolgáltatás Celsius és Fahrenheit közötti váltásra. Ezt implementálja a TempConvert.java osztály JAX-WS használatával, Maven-nel buildelhető, és a letöltést követően a 'mvn jetty:run' paranccsal futtatható. A webszolgáltatás a http://localhost:8080/services/TempConvert címen érhető el, innen van linkelve a WSDL állomány is. Ezt megadtam a soapUInak, és készítettem két tesztesetet is. A soapUI projekt az src/test/resources/TempConvert-soapui-project.xml állományban található.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-G7GW-TvCFB0/UCrHmf3T9LI/AAAAAAAAJGE/usOu3olByI4/s1600/soapui.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="227" width="320" src="http://1.bp.blogspot.com/-G7GW-TvCFB0/UCrHmf3T9LI/AAAAAAAAJGE/usOu3olByI4/s320/soapui.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Persze úgy gondolom, hogy a funkcionalitást nem ezen a szinten kell tesztelni, hanem alacsonyabb rétegeket kell megszólítani, viszont nem rossz, ha ilyen jellegű teszt esetek is vannak, melyek gyakorlatilag a webszolgáltatás interfész visszafele kompatibilitását tesztelik. Azért, hogy ne kelljen ezeket kézzel indítgatni, a soapUI fejlesztői lehetővé tették, hogy a soapUI teszteket JUnit-ból is meg lehessen hívni, mi több, egy Maven repositoryt is felállítottak.&lt;/p&gt;

&lt;p&gt;Tehát a használathoz először a pom.xml-be kell felvenni a függőségeket. Érdekes, hogy amennyiben a FastInfoset-et nem vettem fel, volt, amikor elszállt.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;repositories&amp;gt;
 &amp;lt;repository&amp;gt;
  &amp;lt;id&amp;gt;eviwareRepository&amp;lt;/id&amp;gt;
  &amp;lt;url&amp;gt;http://www.eviware.com/repository/maven2/&amp;lt;/url&amp;gt;
 &amp;lt;/repository&amp;gt;
&amp;lt;/repositories&amp;gt;

&amp;lt;dependencies&amp;gt;
 &amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;eviware&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;maven-soapui-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;4.5.1&amp;lt;/version&amp;gt;
  &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
 &amp;lt;/dependency&amp;gt;

 &amp;lt;!--&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;com.sun.xml.fastinfoset&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;FastInfoset&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;1.2.12&amp;lt;/version&amp;gt;
 &amp;lt;/dependency&amp;gt; --&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/pre&gt;

&lt;p&gt;A következő lépés a teszteset előkészítése. Először el kell indítani a webszolgáltatást, majd azon lefuttatni a soapUI teszteseteket. Nagyon jó &lt;a href="http://www.jroller.com/gmazza/entry/junit_web_service_testing"&gt;cikk található Glen Mazza's Weblogján&lt;/a&gt;, melyben azokat részletezi, hogy hogyan lehet JUnit-ból tesztelni a webszolgáltatásokat. Leírja, hogy hogyan kell webszolgáltatást elindítani az Endpoint osztály segítségével, beágyazott Jettyvel vagy Tomcattel, vagy hogyan lehet külön Tomcatben futó webszolgáltatást tesztelni. Én a már &lt;a href="http://jtechlog.blogspot.hu/2012/08/soa-using-java-web-services.html"&gt;előző cikkben&lt;/a&gt; is említett Endpointot választottam, mint pehelysúlyú megoldás, mely a Javaban található HTTP serveren indul el.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
public class TempConvertIntegrationTest {

    private static String address;

    private static Endpoint ep;

    @BeforeClass
    public static void beforeClass() throws MalformedURLException {
        address = "http://localhost:9000/TempConvert";
        ep = Endpoint.publish(address, new TempConvert());
    }

    @AfterClass
    public static void afterClass() {
        ep.stop();
    }
}
&lt;/pre&gt;

&lt;p&gt;Csak elindítjuk a beépített HTTP servert a teszteset indításakor, és telepítjük rá a TempConvert webszolgáltatás, valamint a teszteset végén leállítjuk. Látszik, hogy a tesztelés http protokollon keresztül történik, végig a teljes lokális hálózati stacken, tehát olyan, mintha különálló kliens hívta volna meg.&lt;/p&gt;

&lt;p&gt;A következő lépésben már csak a soapUI tesztesetet kell elindítani.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@Test
public void testTempConvert() throws Exception {
  SoapUITestCaseRunner runner = new SoapUITestCaseRunner();
  runner.setProjectFile(
    "src/test/resources/TempConvert-soapui-project.xml");
  runner.setEndpoint(address);
  runner.run();
}
&lt;/pre&gt;

&lt;p&gt;Gyakorlatilag csak a soapUI projektfájl helyét kellett megadni, valamint a projektben definiált címet (ami a WSDL-ből jött) felül lehet írni a setEndpoint metódussal. Első indításkor ('mvn test') elég sokat kell várni, mert sok függősége van a soapUI-nak ('mvn dependency:tree'). A konzolra kiírt üzenetekből nagyon szépen látszik, hogy éppen mi történik, melyik suite-ot, test case-t futtatja, sikeres-e az assertion, stb. A főkönyvtárba *.log állományokat is írogat, hiba esetén megtalálhatók bennük a teljes http kérés és válasz is.&lt;/p&gt;

&lt;p&gt;Érdekességképpen ídeírok egy Groovy assertiont is.&lt;/p&gt;

&lt;pre&gt;
def utils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = utils.getXmlHolder(messageExchange.responseContentAsXml)
def celsius = holder["//fahrenheit"]
log.info(celsius)
assert Integer.parseInt(celsius) == 212
&lt;/pre&gt;

&lt;p&gt;A soapUI ezen kívül még nagyon sok mindenre képes, kedvencem, hogy önmaga is tud webszolgáltatásként viselkedni, embedded Jetty-t indít, és még a választ is meg tudjuk adni, hogy mit adjon vissza, amit szintén script-ezhetünk, így a bejövő paraméterektől függően eltérő válaszokat adhatunk vissza. Ez rendkívül jól jön, amikor egy olyan webszolgáltatáshoz akarunk klienst fejleszteni, mely nem mindig elérhető. Ezen kívül használható terheléses tesztelésre is, valamint akár REST webszolgáltatásokat is hívhatunk, vagy újonnan JMS is tesztelhető vele.&lt;/p&gt; </content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/7550091435364332920/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/08/soapui-junit-teszteles.html#comment-form" title="2 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7550091435364332920?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/7550091435364332920?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/08/soapui-junit-teszteles.html" title="Webszolgáltatások integrációs tesztelése soapUI és JUnit használatával" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-G7GW-TvCFB0/UCrHmf3T9LI/AAAAAAAAJGE/usOu3olByI4/s72-c/soapui.png" height="72" width="72" /><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DkABR30zeyp7ImA9WhJXGE0.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-2800563397160344751</id><published>2012-08-12T22:52:00.001+02:00</published><updated>2012-08-12T22:52:36.383+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-12T22:52:36.383+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JAXB" /><category scheme="http://www.blogger.com/atom/ns#" term="JAX-WS" /><category scheme="http://www.blogger.com/atom/ns#" term="könyv" /><title>SOA Using Java Web Services</title><content type="html">&lt;p&gt;Egy előző bejegyzésben, melyben Java tanuláshoz javasoltam forrásokat, említettem a &lt;a href="http://soabook.com/"&gt;Mark D. Hansen: SOA Using Java Web Services&lt;/a&gt; című könyvet, de most jutott arra időm, hogy végigolvassam a majdnem 600 oldalas könyvet. A post egy könyvleírás, de érdemes végigolvasni, egy-két trükköt, tippet olvasható a webszolgáltatások használatával kapcsolatban. Régebben már írtam egy &lt;a href="http://jtechlog.blogspot.hu/2009/11/jax-ws-melyviz.html"&gt;post-ot a JAX-WS-ről&lt;/a&gt;, ott is merítettem ebből a könyvből.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-6MR__NNLNLg/UCgXZRyqiPI/AAAAAAAAJFw/ojTcdYdnKKY/s1600/cover_300wide.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="240" src="http://2.bp.blogspot.com/-6MR__NNLNLg/UCgXZRyqiPI/AAAAAAAAJFw/ojTcdYdnKKY/s320/cover_300wide.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;A könyv alapvetően a JAX-WS 2.0, JAXB 2.0, WS-Metadata 2.0 és a WSEE 1.2 szabványt mutatja be. A könyv nem új, 2007-ben jelent meg, de aktualitását még nem vesztette el, hiszen ugyan van már JAX-WS 2.2, JAX-B 2.2, de igazán kevés újdonság van benne, módosítás még kevesebb. A &lt;a href="http://jax-ws.java.net/nonav/2.2.1/docs/UsersGuide.html#2.0_Features"&gt;JAX-WS újdonságai&lt;/a&gt; között talán a &lt;a href="http://docs.oracle.com/javase/7/docs/api/javax/xml/ws/WebServiceFeature.html"&gt;WebServiceFeature&lt;/a&gt; megjelenése az érdekes, valamint a WS-Addressing említésre méltó. A JAXB &lt;a href="http://jcp.org/aboutJava/communityprocess/maintenance/jsr222/222ChangeLog.html"&gt;specifikáció&lt;/a&gt; vagy &lt;a href="http://jaxb.java.net/nonav/2.2.6/docs/ch02.html#jaxb-2-0-changelog"&gt;implementáció&lt;/a&gt; újdonságai között talán az &lt;a href="http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/annotation/XmlSeeAlso.html"&gt;XmlSeeAlso&lt;/a&gt; annotáció lehet érdekes.&lt;/p&gt;

&lt;p&gt;Igaz, a könyv címében benne van a SOA, alapvetően nem foglalkozik a SOA architektúrával, csak azzal, hogy egy SOA architektúrába hogyan tudjuk a saját alkalmazásunkat legjobban beilleszteni. Arról viszont nagyon részletesen szól, hogy azt hogyan kell felépíteni, milyen rétegekből álljon, milyen eszközöket érdemes használni, és hogy ezek az eszközök hogyan működnek. Nagyon jó és részletes áttekintés található a könyvben az említett szabványok tulajdonságairól, de a részletekbe már nem annyira megy bele. Említi ugyan a REST-et, de akkor még csak a JAX-WS-be próbálja Provider-rel és Dispatch-csel beilleszteni, a JAX-RS-t meg sem említi. A SOAP, WSDL szabványra csak hivatkozik, nem magyarázza, nem tárgyalja részletesen.&lt;/p&gt;

&lt;p&gt;A könyv egy elég jó bevezetővel indul, ahol megnyugtatja az olvasót, hogy nem meglepő, ha nem tudja elsőre átlátni a webszolgáltatások világát, ugyanis tényleg nem egyszerű. A webszolgáltatások írását biztosító eszközrendszer tulajdonságait három részre bontja: hívás (invocation), szerializáció (serialization) és telepítés (deployment). Az hívás alatt azt érti, hogy hogyan kerül meghívásra egy adott webszolgáltatás az adott architektúrán, milyen rétegeken megy keresztül, hogyan talál a megfelelő helyre. A szerializáció biztosítja a paraméterek, visszatérési értékek, kivételek átvitelét. A telepítés azt írja le, hogyan lehet az adott technológiával implementált webszolgáltatás komponenst telepíteni, és hogyan inicializálja, indítja be az adott környezet.&lt;/p&gt;

&lt;p&gt;A könyv szerintem legerősebb fejezete a második fejezet, amikor végigmegy a fentebb említett szabványokon, és hívás/szerializáció/telepítés aspektusok alapján sorba veszi őket. Ennek a fejezetnek dőltem be, ugyanis itt több olyan dolgot is említ, melyre utána később nem tér ki. Ha kitérne, egy teljes technológiát lefedő könyv lenne, de nem is állna meg 600 oldalnál.&lt;/p&gt;

&lt;p&gt;A könyv már az 1. fejezettől kezdve emlegeti, hogy a JAX-WS inkább a bottom up, általa "Start from Java"-nak hívott megközelítést támogatja. Ez azt jelenti, hogy adott a Java forrás, és az alapján szeretnénk webszolgáltatást kiajánlani. Gyakran azonban a top down megközelítésre (előbb a WSDL adott, ő "Start from WSDL"-nek nevezi), vagy inkább a meet in the middle (általa "Start from Java and WSDL"-nek nevezett) megközelítésre van szükség, mikor adott a WSDL is, és egy létező rendszer is. Ekkor gyakran tapasztalhatjuk, hogy a kettő nem felel meg egymásnak. Az üzleti objektumaink felépítése, elnevezése általában nem felel meg annak, amit interfésznek is ki szeretnénk, vagy ki kell ajánlani. A könyv un. wrapper osztályok alkalmazását javasolja. Gyakorlatilag egyrészt kigenerálja az osztályokat a WSDL-ből, valamint meghagyja az üzleti objektumokat is. A kettő között másolást végez. Ettől egyrészt tisztább lesz a kód, viszont több manuális munka van vele. A másolást getter/setter hívásokkal oldja meg, és javasolja, hogy ezeket érdemes különszervezni. Nem említi, hogy erre vannak kész megoldások, pl. BeanUtils.copyProperties vagy a &lt;a href="http://dozer.sourceforge.net/"&gt;Dozer&lt;/a&gt;. Javasolja még azt is, hogy XSLT-vel is lehet konvertálni a megfelelő formátumra.&lt;/p&gt;

&lt;p&gt;A könyv 3. fejezete a REST-et tárgyalja. Furcsa a sorrend, az író azzal magyarázza, hogy első körben érdemes megérteni a webszolgáltatásokat a SOAP boríték nélkül. Erre ugyanúgy a JAX-WS-t használja, és XML-t küld át. Erre manapság már ott van a JAX-RS. Amúgy nagyon lehúzza a REST-et, hogy alkalmatlan a SOA-ra az interfész leíró nyelv hiánya miatt. Azóta ott a &lt;a href="http://en.wikipedia.org/wiki/Web_Application_Description_Language"&gt;WADL&lt;/a&gt;, de nem annyira elterjedt még.&lt;/p&gt;

&lt;p&gt;A 4. fejezet szól kicsit a WSDL-ről és a SOAP-ról, egy nagyon jó leírás található az RPC/Literal, Document/Literal és Document/Literal Wrapped közötti különbségekről. A fejezet alapul vette a gyakran idézett &lt;a href="http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/"&gt;Which style of WSDL should I use?&lt;/a&gt; cikket is. Az előbb már említett integrációs réteget itt írja le, valamint egy workaroundot, hogy hogy lehet megkerülni azt a kötöttséget, hogy egy WSDL-hez csak egy Java osztály tartozhat. (Igen, két osztály esetén tenni kell elé egy Facade osztályt, mely delegálja tovább a hívásokat.)&lt;/p&gt;

&lt;p&gt;A következő fejezet a JAXB alapfogalmakkal ismertet meg. Érdekes a Binding Language-ről szóló leírás, valamint az XmlAdapter használata típus konverzióra. Ennek használatát nehézkesnek ítéli, nem javasolja nagyobb, bonyolultabb struktúrák konverziójára. Nem igazán megy bele a JAXB részleteibe.&lt;/p&gt;

&lt;p&gt;A 6. és 7. fejezet a JAX-WS fejlesztést mutatja meg a gyakorlatban, az előbbiben egy klienst, az utóbbiban egy szervert fejleszt. Szépen leírja a hívási modellt, majd sorra a példák: natív XML küldése, SOAP küldése, Castor XML mapping használata, aszinkron web szolgáltatás hívás, SOAP message handlerek, hibakezelés. Valamint említi a &lt;a href="http://docs.oracle.com/javase/7/docs/api/javax/xml/ws/Endpoint.html"&gt;Endpoint&lt;/a&gt; osztályt is, mellyel Java SE-ben lehet webszolgáltatás futtatni. A Java SE-ben ugyanis van egy pehelysúlyú &lt;a href="https://blogs.oracle.com/michaelmcm/entry/http_server_api_in_java"&gt;HTTP server&lt;/a&gt;. Ez pl. integrációs tesztelésre tökéletes.&lt;/p&gt;

&lt;p&gt;A 8. fejezet azt írja le, hogy lehet alkalmazásszerverbe webszolgáltatásokat telepíteni. Ezt Glassfish-re írja le. Sajnos hiányzik, hogy mi van csak egy web konténer (pl. Tomcat esetén). Tény, hogy ezzel a szabvány sem foglalkozik. A biztonságot is hamar elintézi egy BASIC autentikációval. Viszont említi az OASIS XML Catalog 1.1-et.&lt;/p&gt;

&lt;p&gt;A 9. fejezet egy példa alkalmazás, mely az eBay, Amazon és Yahoo! szolgáltatásai felé húz egy alkalmazást, melyet szintén meg lehet hívni SOAP és REST webszolgáltatásokon keresztül is. Itt nagyon jó a bridge tervezési minta használata, csak ezért is érdemes elolvasni a fejezetet.&lt;/p&gt;

&lt;p&gt;A 10. fejezet az AJAX és a Java webszolgáltatások kapcsolatáról ír, azt hiszem ma már senki nem így használja. Konkrétan natívan használja a XMLHttpRequest-et, böngészőfüggetlenül implementálja, és XML-t küld. Manapság már valamilyen JavaScript keretrendszerrel oldjuk ezt meg, és JSON-nal. A 11. fejezet egy saját SOA-J keretrendszer fejlesztéséről ír, melyet a könyv szerzőjén kívül szerintem még senki nem használt, így nem is érdemes rá szót vesztegetni.&lt;/p&gt;

&lt;p&gt;A könyv mintapéldái elérhetők, érdekes módon félig Maven-nel build-elődnek, de az alkalmazásszerverre deploy, bizonyos generálások Ant task-kal történnek. Furcsa, hogy nem hív Ant-ot Maven-ből, vagy nem valami Maven JAXB és JAX-WS plugin-eket használ. Bár ez utóbbit megértem, mert elég nagy a kavar körülöttük.&lt;/p&gt;

&lt;p&gt;Kinek érdemes elolvasnia a könyvet? Aki a JAX-WS világában frissen el akar merülni, annak nagyon javaslom. A JAXB-re szerintem jobb a Java EE tutorial, de a JAX-WS-re olvasmányosabb ez, és sokkal több háttérinformációt tartalmaz, kicsit kitekint, hogy valós projektekben milyen problémák szoktak előfordulni, és hogyan kell azokat megoldani. Szerintem a legjobb fejezet a 2. fejezet, mely az említett szabványok összes tulajdonságait, lehetőségeit végigpörgeti, példa nélkül. Aki még nem írt ilyent, annak jók a gyakorlati részek is, de aki már egy-kettőt összedobott, nem fog újdonságot találni, kivéve talán a Dispatch/Provider intenzív használatát. Gyakorlottabb webszolgáltatás fejlesztők sok újdonságot nem fognak találni, nekik elég, ha a 2. fejezetet végigpörgetik, hogy minden tulajdonságáról tudnak-e az adott szabványokról.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/2800563397160344751/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/08/soa-using-java-web-services.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2800563397160344751?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2800563397160344751?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/08/soa-using-java-web-services.html" title="SOA Using Java Web Services" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-6MR__NNLNLg/UCgXZRyqiPI/AAAAAAAAJFw/ojTcdYdnKKY/s72-c/cover_300wide.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0UNQX0-eSp7ImA9WhVWEU8.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-1949829407110462171</id><published>2012-04-22T23:14:00.001+02:00</published><updated>2012-04-22T23:14:50.351+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-22T23:14:50.351+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="EclipseLink" /><category scheme="http://www.blogger.com/atom/ns#" term="Hibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="JPA" /><title>JPA lazy loading</title><content type="html">&lt;p&gt;Technológiák: JPA 2.0, EclipseLink 2.3.2, Hibernate 4.1.2&lt;/p&gt;

&lt;p&gt;Gyakorta találkozunk JPA használatakor a lazy loading fogalmával (vagy más néven deferred loading, lazy 
fetching, on-demand fetching, just-in-time reading, indirection, stb.), azonban használata koránt sem olyan triviális, mint amilyennek tűnik. A &lt;a href="http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-eval-oth-JSpec/"&gt;JSR 317: Java Persistence API, Version 2.0&lt;/a&gt; specifikáció is viszonylag szűkszavúan nyilatkozik róla. Annyit ír, hogy @Basic, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany és az @ElementCollection annotációknál használatos, és ez egy &lt;emp&gt;hint&lt;/emp&gt; a perzisztencia megvalósításnak, hogy az adott property-t vagy kapcsolatot nem kell azonnal betölteni, csak az első hozzáférés alkalmával. Egy helyen emeli még ki, amikor deszerializált objektumot kell merge-ölni, és lazy loading van megadva, akkor a különböző implementációk máshogy viselkedhetnek, ezért amennyiben a persistence provider-t cserélgetni szeretnénk, nem érdemes lazy loadingolt mezőn merge-öt használni. A JPA megfogalmazásában a fetch type lazy késleltetett betöltés esetén, és eager, ha azonnal be kell tölteni.&lt;/p&gt;

&lt;p&gt;Miért is érdemes lazy loadingot alkalmazni? Alapvetően teljesítménynövelés céljából. Először meg kell különböztetni a két esetet, mikor egy entitás egy mezőjére, vagy egy kapcsolatra tesszük rá. Az előbbi akkor lehet hasznos, amennyiben egy entitás nem minden mezőjét akarjuk mindig betölteni, mert vagy túl sok van neki, vagy túl nagyok. Utóbbi esetre egy példa egy hallgatói nyilvántartásban a hallgatóhoz tartozhat egy fénykép is, de ez nagy, blob-ban tároljuk, és egy listázó képernyőn nem akarjuk megjeleníteni, csak a részletek képernyőn. Ezzel vigyázni kell, mert ha nem megfelelően használjuk, azaz nincs nagy mennyiségű mező vagy nem nagy méretű, akkor többet ártunk, mint használunk. Ugyanis az újbóli adatbázishoz fordulás erőforrás igényesebb lehet, mint pár plusz adat lekérése. Kapcsolódó entitások esetében példa, ha egy listázó képernyőn nem akarjuk a számlához tartozó tételeket megjeleníteni, kivéve a részletek képernyőn, ahol szükséges őket felsorolni. Háttérben ez úgy történik, hogy egy proxy osztály kerül generálásra (EclipseLink és Hibernate esetében eltérően), és nem tölti be a lekérdezés esetén a megfelelő mezőt vagy kapcsolatot, és így kerül példányosításra a proxy objektum. Amikor a proxy objektumtól mégis elkérésre kerül a nem betöltött mező vagy osztály, akkor próbálkozik a persistence provider a betöltéssel.&lt;/p&gt;

&lt;p&gt;Postomban a lazy loading viselkedését vizsgálom a két legelterjedtebb provider, az &lt;a href="http://www.eclipse.org/eclipselink/"&gt;EclipseLink&lt;/a&gt; és a &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt; esetében. A &lt;a href="http://jtechlog.blogspot.com/2009/05/hibernate-eclipselink-atallas.html"&gt;Hibernate EclipseLink átállás&lt;/a&gt; post részletesen leírja, hogyan lehet átállni Hibernate-ről EclipseLink-re, valamint ebben leírom, mi az a weaving, Java agent és instrumentation, így ezekre itt nem térek ki részletesebben.&lt;/p&gt;

&lt;p&gt;Példaként már egy &lt;a href="http://jtechlog.blogspot.com/2010/09/entitasok-auditalasa-hibernate-envers.html"&gt;előző postomban&lt;/a&gt; bemutatott esetet használok, kicsit módosítva.&lt;/p&gt;

&lt;img src="http://yuml.me/0946499a" alt="Osztálydiagram" width="500" height="77" /&gt;

&lt;!-- [Employee|id;name;cv]++1-*[Phone|type;number]
[EmployeeService|listEmployees;findEmployeeById;mergeEmployee]-[Employee] --&gt;

&lt;p&gt;A példaprogram letölthető a &lt;a href="https://github.com/vicziani/jtechlog-lazy"&gt;GitHub-ról&lt;/a&gt;. A példaprogram a mvn jetty:run parancs kiadásával már futtatható is. A példaprogram jó példa arra is, hogyan lehet az EclipseLink-et vagy a Hibernate-et Spring-gel integrálni. Az alkalmazásba beágyazott HyperSQL adatbázis-kezelő biztosítja a perzisztenciát. A böngészőbe a http://localhost:8080 címet írva bejön egy oldal (/employees.html), melyet a EmployeeController.listEmployees metódusa szolgál ki, mely a DefaultEmployeeService.listEmployees metódusát hívja. Ez az EntityManager.createNamedQuery-t hívja egy select-tel. Ez adja vissza a List&amp;lt;Employee&gt; struktúrát, melyet a JSP oldal megjelenít. Az alkalmazott nevére kattintva annak részletes adatai jelennek meg, az EmployeeController.findEmployeeById metódusa hívja a EmployeeService.findEmployeeById metódusát, mely a EntityManager.find metódusát hívja, ami azonosító alapján tölti be az adott entitást. Két employee rekord szerepel az adatbázisban, mindkettő 2-2 telefonszámmal (, ahogy az init.sql-ben látható). Az Employee esetén egyrészt a cv mezőt vizsgáljuk, másrészt a List&amp;lt;Phone&amp;gt; kapcsolatot. A service-ben szereplő metódusok hívásakor jön létre a persistence context, majd annak lefutásakor az lezárásra kerül. Az entitások a persistence context lezárásakor detached állapotba kerülnek. A kódot bőséges naplózással láttam el, valamint bekapcsoltam, hogy a persistence provider írja ki a lefuttatott sql parancsokat. Így jól lehet látni, hogy milyen sql-eket ad ki, mikor még él a persistence context, és milyeneket mikor már lezárásra került.&lt;/p&gt;

&lt;h1&gt;EclipseLink&lt;/h1&gt;

&lt;p&gt;Az EclipseLink-et úgy konfiguráltam, hogy static weaving legyen, azaz fordítási időben instrumentálja a class fájlokat. Ehhez a pom.xml-ben a eclipselink-staticweave-maven-plugin-t használtam. Valamint a persistence.xml-ben a eclipselink.weaving property értékét static-ra kellett állítani. Build közben a következőket írja ki a weavinggel kapcsolatban:&lt;/p&gt;

&lt;pre&gt;
[EL Finest]: 2012-04-22 01:41:28.453--ServerSession(3980107)--
Thread(Thread[main,5,main])--Begin predeploying Persistence 
Unit lazyPersistenceUnit; session lazyPersistenceUnit; state 
Initial; factoryCount 0

[EL Finest]: 2012-04-22 01:41:29.062--ServerSession(3980107)--
Thread(Thread[main,5,main])--Begin weaver class transformer 
processing class [jtechlog/lazy/service/Phone].
[EL Finest]: 2012-04-22 01:41:29.078--ServerSession(3980107)--
Thread(Thread[main,5,main])--End weaver class transformer 
processing class [jtechlog/lazy/service/Phone].
&lt;/pre&gt;

&lt;p&gt;Alapértelmezetten az EclipseLink cache be van kapcsolva, ezért a persistence.xml-ben kikapcsoltam azért, hogy követni lehessen, hogy milyen SQL utasításokat ad ki.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;property name="eclipselink.cache.shared.default" value="false"/&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Első körben azt az alapértelmezett esetet vizsgáltam, mikor nem tettem semmilyen annotációt a CV mezőre. A listázó képernyőn a következőt kaptuk:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT ID, CV, EMP_NAME FROM EMPLOYEE
-- Persistence context lezárása
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
&lt;/pre&gt;

&lt;p&gt;Az adott alkalmazott kilistázásakor hasonlóképp működik.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT ID, CV, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
-- Persistence context lezárása
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
&lt;/pre&gt;

&lt;p&gt;Először vizsgáljuk csak a cv mezőt. Azt kaptuk, amit vártunk, minden mezőt lekérdezett mindkét képernyőn. Aztán a CV mezőre rátettem a @Lob annotációt, a helyzet változatlan volt. Amennyiben rátettem a @Basic(fetch = FetchType.LAZY) annotációt a cv mezőre, máris megváltozott a helyzet (, függetlenül attól, hogy a @Lob rajta volt-e vagy sem).&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT ID, EMP_NAME FROM EMPLOYEE
-- Persistence context lezárása
SELECT ID, CV, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
SELECT ID, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)

SELECT ID, CV, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
SELECT ID, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
&lt;/pre&gt;

&lt;p&gt;Valamint az egy entitást bemutató képernyőn:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT ID, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
-- Persistence context lezárása
SELECT ID, CV, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
SELECT ID, PHONE_NUMBER, PHONE_TYPE, EMPLOYEE_ID FROM PHONE 
  WHERE (EMPLOYEE_ID = ?)
SELECT ID, EMP_NAME FROM EMPLOYEE WHERE (ID = ?)
&lt;/pre&gt;

&lt;p&gt;Az addig rendben van, hogy az első select-ben ezek után nem kérdezte le a cv mezőt. Láthatjuk, hogy a persistence context lezárása után lekérdezi immár az alkalmazotthoz tartozó összes mezőt, köztük a CV-t is. Ez az EclipseLink egy speciális viselkedése, hogy a persistence context lezárása után is képes sql utasításokat kiadni, betöltve ezzel a lazy-vel definiált mezőket. Az azonban számomra rejtély, hogy miért kell még egy select-et kiadni az employee táblán.&lt;/p&gt;

&lt;p&gt;Most pedig nézzük a kapcsolatot. Látható, hogy a @OneToMany-n alapértelmezetten a fetch type lazy, ugyanis a persistence context lezárása után kéri le a persistence provider a telefonszámokat. Ráadásul alkalmazottanként egy külön select-ben. Itt is látható az EclipseLink különleges viselkedése, hogy a persistence context lezárása után is le tudja kérdezni a még be nem töltött entitásokat. A szabvány amúgy nem írja le, hogy ilyenkor mi legyen. A persistence provider megpróbálhatja feloldani a nem betöltött kapcsolatokat, mint ahogy az EclipseLink is teszi, kivételt dobhat, ahogy a Hibernate, mint azt később látni fogjuk, vagy inicializálatlanul hagyja az adott mezőket. A @OneToMany, @ManyToMany és @ElementCollection esetén az alapértelmezett fetch type lazy, a @Basic, @OneToOne és @ManyToOne esetén eager.&lt;/p&gt;

&lt;p&gt;A következő lépésben beállítottam a @OneToMany annotációnál a fetch paramétert FetchType.EAGER értéket. Az eredmény mind a két esetben ugyanaz volt, mint az előbb, azzal a különbséggel, hogy a kapcsolódó telefonszámokat nem a persistence context lezárása után kérte el, hanem még előtte. Azaz ugyanúgy több select-et futtatott, de mindet a persistence context lezárása előtt, azaz mielőtt átadta volna a vezérlést a view-nak.&lt;/p&gt;

&lt;p&gt;Azon, hogy ne több select-et futtasson le, egyféleképpen tudtam segíteni, és kizárólag a lekérdezés esetén. Átírtam a következőre:&lt;/p&gt;

&lt;pre&gt;
select distinct e from Employee e join fetch e.phones
&lt;/pre&gt;

&lt;p&gt;A distinct használata kötelező, mert ha nem tettem ki, akkor egy alkalmazottat annyiszor hozott le, amennyi telefonszáma volt. A háttérben ugyanis itt egy join van, a következő lekérdezésnek megfelelő select-et futtatja le a persistence provider:&lt;/p&gt;

&lt;pre&gt;
select distinct e, p from Employee e join e.phones p
&lt;/pre&gt;

&lt;p&gt;Viszont a p eredmény értékét egyszerűen nem használja fel, hanem eldobja. A distinct használata tehát szükséges ilyenkor, ekkor az alkalmazottak listázásakor a következő select futott le:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
SELECT DISTINCT t1.ID, t1.CV, t1.EMP_NAME, t0.ID, t0.PHONE_NUMBER, 
  t0.PHONE_TYPE, t0.EMPLOYEE_ID 
  FROM PHONE t0, EMPLOYEE t1 WHERE (t0.EMPLOYEE_ID = t1.ID)
&lt;/pre&gt;

&lt;p&gt;Különösen érdekes lehet még a lazy loaddal bejelölt, és nem betöltött entitások kezelése cascade merge esetén. Ennek tesztelésére készítettem egy oldalt, mely betölti az alkalmazottat, telefonszámokat lazy fetch-re állítottam, és megjelenít egy űrlapot. Az Employee példányt session-be tettem (EditEmployeeController), majd a detach-elt példányt az űrlap postjakor módosítottam, majd merge-öltem vissza (EmployeeService.mergeEmployee()). Minden hibátlanul működött, a módosítás megtörtént, a telefonszámok érintetlenül maradtak.&lt;/p&gt;

&lt;p&gt;Aztán kipróbáltam azt is, hogy a post után még hozzáadtam egy telefonszámot is. Az EclipseLink betöltötte a telefonszámokat, elvégezte az update-et az employee táblán, majd történt egy insert a phone táblába.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
employee.addPhone(new Phone("home", "123"));
&lt;/pre&gt;

&lt;p&gt;Van egy metódus arra, hogy megvizsgáljuk, hogy az adott kapcsolatok, melyek lazyvel vannak jelölve, betöltésre kerültek-e. A következőképpen használhatjuk:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
Persistence.getPersistenceUtil().isLoaded( 
            em.find(Employee.class, 42), "phoneNumbers"); 
&lt;/pre&gt;

&lt;h1&gt;Hibernate&lt;/h1&gt;

&lt;p&gt;Ugyanazzal az alapfelállással indulok, mint az EclipseLink esetében, azaz nincs plusz annotáció, és a @OneToMany annotációnál sincs plusz paraméter. Az előző cikkem óta a Hibernate 3.3.0.CR2-ben a bájtkód módosítását a CGLib helyett a javassist végzi (, amiről szintén írtam &lt;a href="http://jtechlog.blogspot.com/2011/12/instrumentation-javassist-tal.html"&gt;korábban&lt;/a&gt;) , &lt;a href="https://hibernate.onjira.com/browse/HHH-2506"&gt;ugyanis&lt;/a&gt; az előbbi nagyon inaktív projekt lett, így leváltották. Mindkét oldalt betöltve a következő hibaüzenetet kapom:&lt;/p&gt;

&lt;pre&gt;
org.hibernate.LazyInitializationException: failed to lazily initialize a 
collection of role: jtechlog.lazy.service.Employee.phones, no session or 
session was closed
 at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationException(AbstractPersistentCollection.java:393)
    ...
&lt;/pre&gt;

&lt;p&gt;Ahogy említettem, csak az EclipseLink sajátossága az, hogy lazy loadinggal megjelölt kapcsolatban részt vevő entitásokat a persistence context lezárása után (azaz detach állapotban lévő entitásokat is) be tud tölteni. A Hibernate ezt nem tolerálja, amennyiben nem betöltött mezőre történik hivatkozás, és a persistence context nincs nyitva, ezt a hibaüzenetet kapom. A Hibernate-tel való ismerkedéskor ez a leggyakoribb hiba.&lt;/p&gt;

&lt;p&gt;A probléma megoldására többfajta megoldás létezik:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;Eager fetch-t állítunk be a @OneToMany annotáció paraméterében.&lt;/li&gt;
 &lt;li&gt;Ha entitást akarunk a view rétegnek levinni, akkor megtehetjük azt is, hogy amíg a persistence context aktív, meghívjuk a megfelelő getter metódust.&lt;/li&gt;
 &lt;li&gt;A fentivel ekvivalens, ha a view rétegnek nem entitást adunk, hanem egy un. data transfer object-et. Ezt még addig feltöltöm (gyakorlatilag az előző esethez hasonlóan a gettereket hívom), míg a persistence context aktív, így nincs probléma. Ez több programozási feladattal jár, a DTO-k plusz réteget jelentenek.&lt;/li&gt;
 &lt;li&gt;Külön lekérdezést alkalmazunk fetch join-nal, vagy un. projection query-t, vagy akár JDBC-vel is operálhatunk. Ez utóbbi még tervezési minta is Fast Lane Reader, mikor az ORM réteget kikerüljük, tipikusan teljesítménynövelés miatt, és alacsonyabb technológiával dolgozunk.&lt;/li&gt; 
 &lt;li&gt;Az eddigi megoldások azt célozták meg, hogy legyenek betöltve a megfelelő objektumok. A következők azt célozzák meg, hogy ne kelljen detach-elni. Amíg lehet, nyitva hagyjuk a persistence context-et, ha kell, a view réteg lefutása után zárjuk csak le.&lt;/li&gt;
 &lt;li&gt;Vagy alkalmazás által vezérelt tranzakciókezelést vagy persistence context-et, vagy extended persistence context-et használunk. Ugyanis alapértelmezetten egy persistence context a tranzakció lezárásáig tart. Programból mi is vezérelhetjük a tranzakciókat. Vagy az EntityManager létrehozását EntityManagerFactory-n keresztül (createEntityManager metódus), és lezárását (a close metódusával). Vagy stateful session bean (EJB) esetén használhatunk extended persistence context-et, ez nem csak egy tranzakciónyi, hanem a bean élettartamáig élhet, programozottan lehet lezárni.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amennyiben a @OneToMany annotáció paraméterében eager fetch-t állítunk be, az alkalmazottak listázása ugyanúgy történik, mint az EclipseLink esetén, azaz három query, először az alkalmazottak, majd alkalmazottanként a telefonszámok lekérdezése.&lt;/p&gt;

&lt;p&gt;Azonban a Hibernate az EntityManager.find metódus használatakor már okosabb, mint az EclipseLink, egy left outer joint is tartalmazó lekérdezést futtat:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select employee0_.id as id0_1_, employee0_.cv as cv0_1_, 
  employee0_.EMP_NAME as EMP3_0_1_, phones1_.employee_id 
  as employee4_0_3_, phones1_.id as id3_, phones1_.id as id1_0_, 
  phones1_.employee_id as employee4_1_0_, 
  phones1_.PHONE_NUMBER as PHONE2_1_0_, 
  phones1_.PHONE_TYPE as PHONE3_1_0_ 
  from Employee employee0_ 
  left outer join Phone phones1_ 
  on employee0_.id=phones1_.employee_id where employee0_.id=?
&lt;/pre&gt;

&lt;p&gt;Amennyiben a getter metódusokkal akarjuk az entitást inicializálni, vigyázzunk, nem mindegy, hogy mit hívunk meg, mert pl. a getPhones(), getPhones().get(1).getId() nem megfelelő, sőt a getPhones().size() sem, hanem pl. érdemes az első elem nem id mezőjét lekérni. Ez ezért van így, mert a Hibernate úgy módosítja a bájtkódot, hogy a lista létrejön, abban az Employee objektumok is, de csupán az id mezőjük van feltöltve, a többi getter hívás indukálja a további betöltéseket. Ez számomra egy kicsit visszás, mert a kódot olyan technikai részekkel gyarapítjuk, mely üzleti szempontból teljesen lényegtelen, ráadásul az alsóbb rétegnek kell ilyenkor a felsőbb réteg igényeiről tudnia, hogy a visszaadott adat hogy kerül megjelenítésre.&lt;/p&gt;

&lt;p&gt;A join fetch-es lekérdezés ugyanúgy működik itt is, mint az EclipseLink esetén, itt a legenerált SQL kicsit másképp néz ki, a Hibernate az inner join kulcsszót használja.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select distinct employee0_.id as id0_0_, phones1_.id as id1_1_, 
  employee0_.cv as cv0_0_, employee0_.EMP_NAME as EMP3_0_0_, 
  phones1_.employee_id as employee4_1_1_, 
  phones1_.PHONE_NUMBER as PHONE2_1_1_, 
  phones1_.PHONE_TYPE as PHONE3_1_1_, 
  phones1_.employee_id as employee4_0_0__, 
  phones1_.id as id0__ 
  from Employee employee0_ 
  inner join Phone phones1_ 
  on employee0_.id=phones1_.employee_id
&lt;/pre&gt;

&lt;p&gt;Persze a ebben az esetben az findEmployeeById metódust is át kellett írni, hogy ne az EntityManager.find metódusát használja, hanem szintén fetch join-os lekérdezést:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
return em.createNamedQuery("findEmployeeById", Employee.class)
  .setParameter("id", id).getSingleResult();
&lt;/pre&gt;

&lt;p&gt;Valamint a NamedQuery:&lt;/p&gt;

&lt;pre class="brush: java"&gt;
@NamedQuery(name = "findEmployeeById", 
  query = "select distinct e from Employee e join fetch e.phones where e.id = :id")
&lt;/pre&gt;

&lt;p&gt;Megoldás lehet az is, hogy ha a persistence context tranzakciónyi, akkor a view rétegben kell a tranzakciót nyitni és zárni. Ezt nevezik transactional view-nak. Ennek továbbfejlesztése, hogy nem a tranzakciót nyitjuk a view-ban, hanem az entity manager-t, ennek neve az "Open EntityManager in View" minta használata, és kb. ugyanazon előnyökkel és hátrányokkal rendelkezik. Ehhez a következőt kell hozzáadni a web.xml-hez:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;openEntityManagerInViewFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter&amp;lt;/filter-class&amp;gt;
&amp;lt;/filter&amp;gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;openEntityManagerInViewFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;*.html&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Itt az történik, hogy a http kérés beérkeztekor a filter nyit EntityManager-t, azaz persistence context-et, és az adott szálhoz rendeli. A tranzakció kezdésekor a szolgáltatásrétegben a szálhoz rendelt EntityManager-hez kapcsolódik. Lefut a flush, majd a commit a szolgáltatás végén, ha minden rendben ment. Majd meghívásra kerül a view. Ennek visszaadása után zárja le csak a filter az EntityManager-t. Bár egyszerű és gyors megoldásnak tűnik, én nagy terhelésű rendszer esetén nem javasolnám a használatát. Egyrészt többen írják, hogy lassabb, bár saját mérési eredményeim nincsenek. Valamint ahhoz tartom magam, hogy az ilyen jellegű dolgokat minimális ideig tartsunk nyitva. Egyszerű, párfelhasználós, vagy pilot projekt esetén viszont jól jöhet.&lt;/p&gt;

&lt;p&gt;OpenEntityManagerInViewFilter helyett használhatnánk OpenEntityManagerInViewInterceptor-t is, mely az application contextben jön létre, így hozzáfér az abban lévő bean-ekhez.&lt;/p&gt;

&lt;p&gt;Itt még figyeljük meg a lekérdezéseket:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;
select employee0_.id as id0_, employee0_.cv as cv0_, 
  employee0_.EMP_NAME as EMP3_0_ from Employee employee0_
-- Persistence context lezárása
select phones0_.employee_id as employee4_0_1_, 
  phones0_.id as id1_, phones0_.id as id1_0_, 
  phones0_.employee_id as employee4_1_0_, 
  phones0_.PHONE_NUMBER as PHONE2_1_0_, 
  phones0_.PHONE_TYPE as PHONE3_1_0_ from Phone phones0_ 
  where phones0_.employee_id=?
select phones0_.employee_id as employee4_0_1_, 
  phones0_.id as id1_, phones0_.id as id1_0_, 
  phones0_.employee_id as employee4_1_0_, 
  phones0_.PHONE_NUMBER as PHONE2_1_0_, 
  phones0_.PHONE_TYPE as PHONE3_1_0_ 
  from Phone phones0_ where phones0_.employee_id=?
&lt;/pre&gt;

&lt;p&gt;Gyakorlatilag ugyanaz, mint az EclipseLink esetén, azzal a különbséggel, hogy a Hibernate mindenütt alias-okat használ.&lt;/p&gt;

&lt;p&gt;Az alkalmazás által gyártott EntityManager használatát nem javaslom, hiszen nagyon oda kell figyelni, bonyolítja a kódot, plusz munkával jár, és az újrafelhasználhatóságot is megnehezíti. Az extended persistence context szintén nem befutó nálam, hiszen egyrész Spring-ezek, másrészt EJB esetén is kerülöm a stateful session bean-ek használatát.&lt;/p&gt;

&lt;p&gt;Vizsgáljuk meg most a cv mező működését. Ahogy várható, mindig beolvassa. Azonban az már meglepő, hogy a @Lob, vagy a @Basic(fetch = FetchType.LAZY) vagy mindkét annotáció hatására sem változik semmi, azaz mindig berántja. Erről már &lt;a href="http://jtechlogext.blogspot.com/2010/07/jpa-hibernate-lazy-fetch.html"&gt;írtam&lt;/a&gt;, ennek az az oka, hogy ez csak akkor működik, ha az osztályok instrumentálva vannak. A példa projektben a pom.xml-ben a maven-antrun-plugin futtat egy org.hibernate.tool.instrument.javassist.InstrumentTask-ot. Amennyiben ezt megtesszük, a következő kerül a konzolra.&lt;/p&gt;

&lt;pre&gt;
main:
[instrument] starting instrumentation
[instrument] processing class : jtechlog.lazy.service.Employee;  
  file = D:\projects\jtechlog\jtechlog-lazy\target\classes\
  jtechlog\lazy\service\Employee.class
[instrument] processing class : jtechlog.lazy.service.Phone;  
  file = D:\projects\jtechlog\jtechlog-lazy\target\classes\
  jtechlog\lazy\service\Phone.class
&lt;/pre&gt;

&lt;p&gt;A class állományok is nagyobbak lesznek, és belenézve ilyeneket látunk: org/hibernate/bytecode/internal/javassist/FieldHandler. Azért jó ezt tudni, mert pl. engem a fejlesztőeszköz tévesztett meg azzal, hogy saját maga felülvágta a Maven által generált class állományokat, amik azonban még nem voltak instrumentálva. Innentől lazy mező esetén pont úgy működött, mint ahogyan az elvárható volt, és ugyanúgy figyelni kell arra, hogy ne kapjunk LazyInitializationException-t.&lt;/p&gt;

&lt;p&gt;Merge esetén úgy működött, ahogy várható volt. Amennyiben csak az Employee példányon módosítottunk, és a detached objektumot merge-öltem vissza, sikerült, módosult az alkalmazott, és megmaradtak a telefonszámok. Amennyiben azonban a telefonszámokhoz új telefonszámot akartam felvenni, ugyanúgy kaptam a LazyInitializationException-t. Azaz ugyanúgy nekünk kell gondoskodnunk a betöltésről, ahogy azt Hibernate esetén megszokhattuk.&lt;/p&gt;

&lt;h1&gt;Összegzés&lt;/h1&gt;

&lt;p&gt;Bár nem tűnik túl bonyolult témakörnek, a lazy loading kezelése okozott számomra meglepetéseket. Az EclipseLink kicsit jobban elrejti ezt a dolgot, ezért csak ezt a tulajdonságát figyelembe véve jobb választás lehet. Azt azonban mindenképp javaslom, hogy ne hagyatkozzunk az elképzeléseinkre, hogy hogyan történhet a betöltés, hanem mindig állítsuk be azt, hogy a persistence provider írja ki az általa lefuttatott SQL lekérdezéseket, és minden képernyőnél elemezzük azokat, hogy nincs-e felesleges lekérdezés, vagy nem-e lehet úgy megfogalmazni a JPA lekérdezést, hogy több SQL lekérdezés helyett csak egy fusson.&lt;/p&gt;

&lt;p&gt;Egy másik &lt;a href="http://jtechlog.blogspot.com/2011/02/ejb-es-jpa-developer-certified-expert.html"&gt;postban&lt;/a&gt; már említett &lt;a href="http://apress.com/book/view/9781430219569"&gt;Apress kiadó Pro JPA 2 Mastering the Java Persistence API&lt;/a&gt; könyve elég részletesen ír a lazy loading fogalmáról, de az implementációkat az sem hasonlítja össze.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/1949829407110462171/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/04/jpa-lazy-loading.html#comment-form" title="2 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/1949829407110462171?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/1949829407110462171?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/04/jpa-lazy-loading.html" title="JPA lazy loading" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;D0AMRX08eSp7ImA9WhVQEUk.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-266912075707296739</id><published>2012-03-31T00:16:00.000+02:00</published><updated>2012-03-31T00:16:24.371+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-03-31T00:16:24.371+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><category scheme="http://www.blogger.com/atom/ns#" term="monitorozás" /><category scheme="http://www.blogger.com/atom/ns#" term="Módszertan" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="könyv" /><title>Java Performance</title><content type="html">&lt;p&gt;A &lt;a href="http://jtechlog.blogspot.com/2011/12/java-memoriakezeles-szemetgyujto.html"&gt;Java memóriakezelés, szemétgyűjtő algoritmusok&lt;/a&gt; postom egy részét a &lt;a href="amazon.com/Java-Performance-Charlie-Hunt/dp/0137142528/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1327511447&amp;sr=1-1"&gt;Java Performance&lt;/a&gt; könyv ihlette.&lt;/p&gt;

&lt;p&gt;A könyv a maga nemében egyedülálló. Ebben a témában viszonylag kevés szakirodalom létezik, még kevesebb, ami ebből még aktuális is. (2011. októberében került kiadásra.) A könyvet Charlie Hunt és Binu John írta. Az előbbi az Oracle-nél vezető beosztásban van, ő a JVM performanciájával foglalkozik, és a HotSpot JVM és a Java SE osztálykönyvtárának gyorsításán dolgozik, valamint Java EE környezetben is járatos, foglalkozott a Oracle GlassFish-sel és az Oracle WebLogic Server-rel is. Binu John jelenleg a Ning, Inc.-nél dolgozik, de előtte a Sun-nál több, mint egy évtizedett töltött teljesítményoptimalizálással, az Enterprise Java Performance csapat tagja volt. Hozzáértésük, tapasztalatuk nagyban meglátszik a könyvön is. A könyvvel kapcsolatban &lt;a href="http://www.infoq.com/articles/book-java-performance"&gt;egy interjú&lt;/a&gt; is készült velük.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-EG3yzQP733k/T3YwHWzfs_I/AAAAAAAAIOc/TiFN0mSFgSU/s1600/JavaPerformanceCover_375x500.gif" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="240" src="http://1.bp.blogspot.com/-EG3yzQP733k/T3YwHWzfs_I/AAAAAAAAIOc/TiFN0mSFgSU/s320/JavaPerformanceCover_375x500.gif" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;A könyv egészen az alapoktól indul. A teljesítmény optimalizálás fogalmait, és egy lehetséges módszertanát ismerteti. Két megközelítést is tárgyal, a top down, és a bottom up megközelítést. A top down a leggyakoribb módszer, a teljes rendszert megfigyelik, és egyre mélyebbre fúrnak, és próbálják megtalálni a gyenge pontokat, és azokat kiemelni. A bottom up megközelítés inkább specialisták egyik eszköze, mikor egy kész rendszert visznek át egyik platformról a másikra, és a másik platform előnyeit próbálják minél jobban kiaknázni. Olyan fogalmakat tisztáz, mint performance monitoring, profiling és tuning.&lt;/p&gt;

&lt;p&gt;A második fejezet kizárólag az operációs rendszerről szól. Leírja, hogy különböző rendszereken (Windows, Linux, Solaris) miként monitorozhatjuk a CPU-t, memóriahasználatot, lock-okat, hálózati forgalmat és disk használatot. Tippeket ad, hogy milyen jelenség esetén mire kell gyanakodnunk. Sokat foglalkozik a több magot tartalmazó processzorokkal is.&lt;/p&gt;

&lt;p&gt;A következő fejezet a HotSpot VM felépítésével, alapfogalmaival foglalkozik. A könyv kizárólag az Oracle JVM-jével foglalkozik, nem tér ki más gyártók megoldásaira, de azt hiszem ez igazán elfogadható, nagyon ritkán láttam más JVM-en futó alkalmazásokat (, sőt egy ilyent kiváltásában is részt vettem az akkor még Sun-os JVM-re). A JVM-et három részre bontja, Runtime-ra, JIT compilerre és memory managerre, mely a Garbage Collector-t foglalja magában. Nagyon részletesen leírja a JVM indulását (20 pontban) és leállását is. Olyan részletesen, hogy volt egy pont, mely nem volt tiszta, utána akartam nézni a weben, és semmi információt nem talaltam róla, kivéve a JDK forráskódjában. Egészen C++ mélységekbe merül. Nagyon jó írás található itt az osztálybetöltésről is, valamint a Java 5-ben megjelent Class data sharingról. Itt a kedvenc részem a 32 és 64 bites architektúra összehasonlítása, ahol kiderül, hogy a 64 bites architektúrára átállás átlagos esetekben miért okozhat 8-15%-os sebességlassulást. Áttekintést ad a GC-ről és a JIT compiler-ről is. Megemlíti a JDK 6 update 20-tól elérhető G1 szemétgyűjtőt is, leírja a működését, bár bevallja, hogy értékelhető mennyiségű tapasztalat még nem gyűlt össze ezzel kapcsolatban. Itt egy-két paragrafusnál elő kellett venni a fordítóprogramok és automaták tárgyon tanultakat.&lt;/p&gt;

&lt;p&gt;A 4. fejezet a monitoringról szól. Tisztázza a célokat, leírja a parancssori kapcsolókat, valamint részletesen tárgyalja a Java 6-ban alapból elérhető JConsole-t és VisualVM-et, és annak VisualGC plugin-ját is. Itt főleg a GC és a JIT monitorozására koncentrál. Az 5. fejezet témája a profiling. A profiling már olyan megfigyelés, ami módosítja a megfigyeltet ("tolakodó"). Itt is a terminológiával indít, majd az Oracle Solaris Studio bemutatása következik. Eztán jön a NetBeans Profiler.&lt;/p&gt;

&lt;p&gt;A következő fejezet már gyakorlatibb jellegű, forráskódok is jócskán szerepelnek benne (furcsa, hogy ezek a könyv végén találhatóak, én nem találtam ezeket a neten). E fejezet felépítése úgy néz ki, hogy bemutat egy programozói hibát, annak feltárásának módját, azaz a jelenséget magát, valamint a megoldást. A 7. fejezet egy konkrét algoritmust mutat be (folyamatábrával), hogy a JVM hogyan finomhangolható, milyen parancssori kapcsolókat lehet használni, azoknak milyen kihatása lehetséges. Bevallom őszintén, ez számomra kevésbé érdekes téma, azt vallom ugyanis, hogy alkalmazás szinten sokkal kevesebb energiabefektetéssel sokkal többet lehet hangolni. Ez ott jöhet jól, ahol a forráskód nem elérhető, vagy láttam már olyant is, hogy a fejlesztőknek nem volt idejük finomhangolásra, így az üzemeltetők próbáltak plusz százalékokat kihozni. Itt az az érdekes, hogy definiálnunk kell a célokat. Ezek a magas rendelkezésre állás, könnyű konfigurálhatóság, áteresztő képesség, gyors válaszidő, memóriahasználat, indulási idő. Ezek közül azonban nem lehet mindnek megfelelni, ugyanis több alapból ellentmond egymásnak. Pl. amennyiben magas rendelkezésre állást akarunk, cluster-es környezetben, azt nem olyan egyszerű konfigurálni.&lt;/p&gt;

&lt;p&gt;A 8. fejezet a benchmarking-ról szól. Na ez az a terület, ahol a legtöbb tévhit van, valamint a legegyszerűbb módon tudjuk magunkat félrevezetni. Szó esik it a warmupról, a System.gc() hívással kapcsolatos tévhitekről, a System.currenTimeMillis() és nanoTime() metódusokról, compiler optimalizációjáról (pl. ha egy metódus visszatérési értékét nem használjuk fel, és nincs mellékhatása, símán kioptimalizálja), inliningról. Rengeteg tippet és trükköt oszt meg. A biztosítékot nálam a statisztikai módszerek alfejezet ütötte ki, ahol standard eloszlástól kezdve nagyon sok mindenről szó esik.&lt;/p&gt;

&lt;p&gt;Ez után következnek a könnyed részek. Hogyan vizsgáljunk többrétegű alkalmazásokat, hogyan monitorozzunk Glassfish-t. Szó esik a web konténerről, NIO-ról, HTTP szálakról, thread pool-okról, connection queue-król. Igaz, GlassFish környezetben, de elég könnyen lehet ezt a tudást más webkonténerre is kiterjeszteni. Megemlíti a JMeter-t. Ír Servlet, JSP és JSTL legjobb gyakorlatokról, a cache-elés fontosságáról, és megemlíti, hogy sokszor akkor is létrejön session, mikor nem is gondolunk rá. A 11. fejezetben szó esik a webszolgáltatásokról, és az alapját képző XML feldolgozásról (pl. JAXB). Külön piros pont, hogy részletesen ír az EntityResolver-ekről (lásd &lt;a href="http://xml.apache.org/commons/components/resolver/"&gt;Apache xml-commons resolver&lt;/a&gt;), és a CatalogResolver-ekről is, melyek a szívem csücskei. A különböző XML processzorokat is összehasonlítja, SAX, DOM, StAX, JAXB. Érdekes megfigyelés, hogy az xsd:any használata mennyire lassít, és még egy érdekes adat, hogy az EJB-ből kiajánlott webszolgáltatások sokkal lassabbak a webkonténerből kiajánlott társaiknál. Ezek a fejezetek még mindig egyedülállóak.&lt;/p&gt;

&lt;p&gt;Az utolsó, 12. fejezet a JPA és EJB teljesítményhangolásáról szól. No, ez már olyan fejezet, amely más könyvekben is megjelenik, talán ugyanilyen részletességgel. Szó esik therad pool-ról, cache-ekról, tranzakciókról, és természetesen a kihagyhatatlan lazy loadingról is.&lt;/p&gt;

&lt;p&gt;Az A függelék a HotSpot VM parancssori kapcsolóit sorolja fel, és magyarázza meg, olyan részletességgel, amilyennel talán sehol máshol nem lehet találkozni. B függelék a forráskódoké, majd következik a részletes, nagyon jól használható tárgymutató.&lt;/p&gt;

&lt;p&gt;Sajnos gyakran észreveszem, hogy ezzel a témával kapcsolatban nagyon sokan helytelen, téves fogalmakat használnak. A könyv rendkívül részletesen ismerteti, magyarázza és definiálja ezeket.&lt;/p&gt;

&lt;p&gt;Egyetlen hátránya a könyvnek, melyet a különböző fórumokon többen is jeleznek, az az írok Sun, illetve most már Oracle iránti elfogultsága. Már az első fejezetben indokolatlanul fényezik az UltraSPARCT T-series processzorokat, és ez a teljes könyvön végigvonul, gyakran említi a Solaris-t, illetve a különböző eszközök közül is csak az Oracle-ösöket tárgyalja ki, mint pl. a NetBeans Profiler-t. Ez utóbbi számomra nem zavaró, hiszen nem lehet a teljes palettát bemutatni, és igazából ezen eszközök nem nagyon térnek el egymástól, a Solaris-os fejezeteket is át lehet ugrani, de a CPU hangsúlyozása már kicsit kínos.&lt;/p&gt;

&lt;p&gt;A könyv majdnem 700 oldal, és nagyon sűrűen van szedve, nincs teletűzdelve feleslegesen ábrákkal sem, emiatt a témát nagyon alaposan bemutató, hosszú, részletes könyv. Nem is lehet egyhuzamban elolvasni, inkább részleteiben, mindig arra a témakörre koncentrálva, amit éppen teljesítmény-hangolni kell. Remélem sikerült kedvet hozni hozzá, és mindenkinek a könyvespolcára kerül ez a könyv.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/266912075707296739/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/03/java-performance.html#comment-form" title="1 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/266912075707296739?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/266912075707296739?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/03/java-performance.html" title="Java Performance" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-EG3yzQP733k/T3YwHWzfs_I/AAAAAAAAIOc/TiFN0mSFgSU/s72-c/JavaPerformanceCover_375x500.gif" height="72" width="72" /><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DUYHSX0_fyp7ImA9WhRUF0U.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-2913251681129038831</id><published>2012-01-28T22:43:00.001+01:00</published><updated>2012-01-28T22:45:38.347+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-28T22:45:38.347+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Űrlap eredmények, könyvsorsolás</title><content type="html">A &lt;a href="http://jtechlog.blogspot.com/2012/01/visszatekintes-2011-re.html"&gt;Visszatekintés 2011-re&lt;/a&gt; postomban szerepelt egy kérdőív, melyet összesen 26 válaszadó töltött ki. Ezúttal is köszönöm mindenkinek a segítséget, ötleteket, jókívánságokat! A válaszadók között volt végzős egyetemista, junior, de 10-13 éve Java-ban fejlesztő senior, és vezető fejlesztő is. Kb. kétszer annyi senior fejlesztő töltötte ki, mint junior, pár vezető beosztásban dolgozó. Általában mindennel foglalkoznak (backend és frontend is, ismerik és használják a teljes stack-et), számomra meglepő módon csak kevesen írták csak az egyiket. Emellett kitöltötte olyan is, aki mindennapjaiban üzemeltet (is), oktat, tesztel, vagy a build folyamatokkal foglalkozik.&lt;br /&gt;
&lt;br /&gt;
A témák, melyek érdeklik a válaszadókat, és akár konferenciákra is elmennének azzal kapcsolatban, nagyon változatos. Nem volt egyszerű összesíteni, de nem akartam feleletválasztással megkötni a kezeteket, de így is sokan a zárójelbe tett ötletekből csemegéztek. Amiről a válaszadók legszívesebben olvasnának, az magasan a különböző módszertanok, kb. dupla annyian szavaztak rá, mint a második helyezettre. Ahhoz képest, hogy az az elterjedt hit, hogy a fejlesztők nem szeretnek tesztelni, a második helyen a tesztelés/teszt eszközök bemutatása végzett. Számomra meglepő volt, hogy alap JDK-s dolgokról is szívesen szeretnek olvasni, nem kell mindig más technológia után kutakodni. Ezt megerősíti az is, hogy a &lt;a href="http://jtechlog.blogspot.com/2011/12/java-memoriakezeles-szemetgyujto.html"&gt;Java memóriakezelés, szemétgyűjtő algoritmusok&lt;/a&gt; postom is kiemelkedően látogatott. Számomra furcsa, hogy az OSGi-t egy ember említette meg, úgy látszik csökken a népszerűsége. A konferencia fő érdeklődésre számot tartó témái: Java 7 újdonságok, Java EE, cloud, SOA és mobil fejlesztés. Egyrészt nagyon jól csinálják a mostani konferenciák szervezői, mert minden ezekről szól. Másrészt az nagyon érdekes, hogy a válaszadók ezeket a témákat általában nem jelölték meg, hogy a blogomon olvassanak róla. Harmadrészt a JavaFX szinte senkit nem érdekel. A SOA, bár sokan elcsépelt buzzwordnek tartják, mégis előkelő helyen van. A Java jövőjével kapcsolatban általában nincsenek nagy félelmek. A hype ugyan alábbhagyott, de azért mindenki szereti (különben nem olvasnák a blogot), és kivár. Többeknek nem tetszett az Oracle felvásárlás, de szerintük azért talán a Java jövőjét nem fenyegeti.&lt;br /&gt;
&lt;br /&gt;
És akkor kicsit a statisztikáról is. A legtöbb válaszadó nem kizárólag Java-ról akar olvasni. Az olvasók felének jó így a szint, másik fele azt választotta, hogy legyen általános és technikai is. A válaszadók többségének jó így a postok hossza, sokan nem bánnák, ha a hosszúak között lennének rövidebbek is.&lt;br /&gt;
&lt;br /&gt;
És akkor a jövőről. Az űrlap kitöltése alapján azt látom, hogy gyökeres változtatásra nincs szükség. Témák tekintetében a JDK-val és a teljesítményhangolással foglalkozó postokat is igyekszem írni. A válaszadók gyakran való életbeli példákat szeretnétek. Talán nem hangsúlyozom eléggé, de a postok nagy részének alapja egy probléma, amibe a való életben futok bele. A mögé teszek egy kis hátteret is, és a probléma megoldását is megírom. A későbbiekben igyekszem a konkrét környezetet jobban bemutatni. A elvekkel, módszertanokkal, megmondásokkal kapcsolatban van egy kis félelmem. Ugyanis a technológiák, eszközök általában egzakt valamik, amiről viszonylag objektíven lehet írni (mármint egy probléma egy eszközben való megoldásáról, nem magáról az eszközről). Az elvek nem mindig ilyenek, nagyon kevés általánosan elfogadott alapszabály létezik. Gondoljunk bele, hogy pl. a singleton is mennyire megosztja a fejlesztőket, de beszélhetnénk itt a CI-ről, AOP-ről, agilis fejlesztésről, extrém programozásról, TDD-ről, stb. Általában megpróbálok objektív maradni, de így sem mindig sikerül. Ilyen jellegű postokra inkább az év közepétől számíthattok. Másik téma, amiről mindenképpen többet szeretnék írni, az a tesztelés, teszt vezérelt fejlesztés. Amiről biztos, hogy nem fogok írni a közeljövőben, az a JavaFX, OSGi és a JVM-en futó alternatív nyelvek. Tudom, az utóbbi többeknek kedvence, de jelenlegi munkámban még nem látom az alkalmazhatóságukat, nem tartom őket annyira kiforrottnak sem, és a csapat, amelynek tagja vagyok, sem rendelkezik elegendő kompetenciával, hogy be mernénk vetni. Szabadidőm inkább a Java közli technológiáknak szentelem. Egyedül a Jython, ami néha-néha előkerülhet, a többi addig nem, míg megfelelően el nem terjed. A témákat megpróbálom sokszínűen tartani, a szintet sem módosítom. Alapvetően a hosszabb cikkekre fogok továbbra is koncentrálni, de igyekszem rövidebb cikkeket is beszúrni. Köszönöm a javaslatokat, hogy több forráskódot és képet szerepeltessek, ezeket is igyekszem betartani.&lt;br /&gt;
&lt;br /&gt;
A Java 2 útikalauz programozóknak című könyvet i***a@gmail.com e-mail címmel rendelkező válaszadó nyerte, már tud róla, gratulálok!</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/2913251681129038831/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/01/urlap-eredmenyek-konyvsorsolas.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2913251681129038831?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/2913251681129038831?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/01/urlap-eredmenyek-konyvsorsolas.html" title="Űrlap eredmények, könyvsorsolás" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEADSH8yeCp7ImA9WhRVGEw.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-340189829288615845</id><published>2012-01-16T00:47:00.002+01:00</published><updated>2012-01-17T16:06:19.190+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T16:06:19.190+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Módszertan" /><title>Ki is az a Java architect?</title><content type="html">Manapság Magyarországon is egyre gyakrabban keresnek Java architect-et, de kérdés, hogy ez a pozíció vajon milyen feladatokkal járhat? Egzakt definíciója nincs, az itt leírtak a saját tapasztalataim és véleményem tükrözik. Be kell vallanom, a &lt;a href="http://java.dzone.com/articles/technical-job-interview"&gt;Technical Job Interview Questions for Java EE architects&lt;/a&gt; cikk is nagyon elgondolkodtatott.&lt;br /&gt;
&lt;br /&gt;
Az architect szó a görög arkhitecton szóból származik, ami az arkhi (vezető) és tekton (építész) szóból áll, így nagyjából vezető építészt jelent. A főnököm főkonstruktőrt szokott emlegetni, ami nekem szimpatikus és ráadásul magyar kifejezés. Az informatika ezt a kifejezést is az építészetből vette át, mint pl. blueprint vagy a tervezési minta szavakat.&lt;br /&gt;
&lt;br /&gt;
A szoftverfejlesztés az architect fogalmát kb. az 1990-es évek végén vette át, amikor is a szoftver rendszerek egyre bonyolultabbakká váltak, és a szoftverfejlesztési problémák megoldására elkezdett terjedni az objektumorientált programozás. Már nem egyedülálló, monolitikus, szigetként működő alkalmazásokat kellett fejleszteni, hanem más rendszerekhez illeszkedni tudó, azokkal kommunikáló, komoly üzleti logikát megvalósító szoftver rendszereket. A megoldást a rendszerek kisebb alrendszerekre való szétvágása, illetve az alrendszerek több rétegre való bontása jelentette. Elterjedtek a két, három és n-rétegű architektúrák, lassan minden nagyvállalati (enterprise) lett. A rendszerek közötti kapcsolatok megvalósítását az Enterprise Application Integration-től (EAI) várták, amely nem más, mint olyan architektúrális elvek gyűjteménye, melyek az integrációt hivatottak megoldani. És szükség volt valakire, aki az ilyen bonyolult rendszerekkel kapcsolatban képes volt felmérni az igényeket, azonosítani a kockázatokat, becsülni, magas szinten megtervezni és specifikálni a feladatokat, és ellenőrizni a megvalósítást.&lt;br /&gt;
&lt;br /&gt;
Az előzőekből is kiderül, hogy az architect az üzlet és az informatika között helyezkedik el. Ismeri, megismeri, érti az üzleti területet, valamint a megrendelő által megfogalmazott, a rendszerrel kapcsolatos üzleti elvárásokat, az un. funkcionális követelményeket. Az architect feladata ezen követelmények informatikai vetületeinek feltárása, és az informatika felé ezek közvetítése. Az üzleti problémákra technológiai megoldásokat képes adni.&lt;br /&gt;
&lt;br /&gt;
Vegyük sorba, hogy egy szoftverfejlesztés életciklusát alapul véve, melyik fázisban milyen feladatai lehetnek az architect-nek, és ez alapján azt, hogy milyen képességekkel kell rendelkeznie.&lt;br /&gt;
&lt;br /&gt;
Az architect tehát egy szoftverfejlesztési projekt legelején, már az ajánlatírás fázisában aktívan beszáll a projektbe. Egyrészt megérti a funkcionális követelményeket. Ezen kívül képes felmérni a rendszerrel kapcsolatos nem funkcionális gyakran minőségi követelményeket, melyek azok az elvárások, melyek nem konkrétan egy üzleti használati esethez köthetőek. Ilyen pl. a teljesítmény, magas rendelkezésre állás, hibatűrés, skálázhatóság, biztonság, fenntarthatóság, továbbfejleszthetőség, üzemeltethetőség, tesztelhetőség, használhatóság, felhasználói felülettel kapcsolatos követelmények, stb. Nem funkcionális igényként fontos definiálni az ügyfél oldali megszorításokat is, mint pl. a kötelezően használt platformok, eszközök, valamint a más rendszerekhez való illesztési lehetőségeket és elvárásokat. Meg kell említeni a módszertannal kapcsolatos és dokumentációs követelményeket, jogszabályoknak való megfeleléseket és a szakterületi szabályokat. Ezen igények egy része mérhető bizonyos mérőszámok definiálásával, más követelmények azonban korántsem ennyire egyértelműek. A nem funkcionális követelmények érkezhetnek az üzleti oldal, de a megrendelő informatikai gárdája felől is.&lt;br /&gt;
&lt;br /&gt;
Ugyanígy képes felmérni a szállító oldali lehetőségeket is. Ismeri a fejlesztési csapatot, és annak képességeit, a fejlesztők által használt szabványokat, technológiákat és eszközöket.&lt;br /&gt;
&lt;br /&gt;
Ezáltal már az ajánlati fázisban aktívan szerepet kell vállalnia. A követelmények alapján ugyanis azonosítania kell a technológiai kockázatokat, általánosságban a megvalósíthatóságot. A kockázatokat minél előbb fel kell ismernie, és osztályoznia. Becsülnie kell, egy probléma bekövetkezésének valószínűségét, valamint a bekövetkezése által okozott kárt, az elhárításának erőforrás igényét. Valamint meg kell határoznia, hogy milyen erőforrás szükséges a probléma kialakulásának megakadályozására. Ezek alapján egy rangsort kell felállítania.&lt;br /&gt;
&lt;br /&gt;
Ezek alapján víziót kell alkotnia. Bizonyos helyzetekben lehet, hogy prototípus építésére is szükség lehet. És ez alapján erőforrást is kell becsülnie. Látható tehát, hogy már a projekt elején kiemelt szerepe van, hiszen a projekt alapvető sikeressége függ egy jó architektúrán, egy pontos becslésen, mely kihat az árajánlatra, a projekt költségvetésére is. Nem utolsósorban az architect-nek olyan magas szintű döntéseket kell hoznia, mely a projektben részt vevő összes személyre kihat, hiszen az ő által kidolgozott koncepciót kell megvalósítani az általa megbecsült idő alatt, így rajta is múlhat, mennyire motiváltak a projekt tagok, esetleg mennyi túlórát kell a projektbe fektetni.&lt;br /&gt;
&lt;br /&gt;
A követelmény elemzés és tervezés fázisában szintén nagy részt kell vállalnia. Ki kell választania a problémás használati eseteket, és előre priorizálnia. A szoftverrendszer magas szintű tervezését kell elvégeznie és dokumentálnia. Milyen alrendszerekből álljon, ezek hogyan kommunikáljanak egymással és külső rendszerekkel, valamint hogyan épüljenek fel. Milyen eszközök és technológiák használandóak. Itt lehet szükség bonyolultabb prototípusok építésére is. A prototípusoknak több fajtája lehet, eldobandó, továbbfejleszthető és architektúrális. Az eldobandó csak valaminek a kipróbálására jött létre, a továbbfejleszthető akár a későbbi rendszer alapjául is szolgálhat, és az architektúrális az architektúra elemek helyes együttműködésének tesztelésére szolgál, melyet mintaként használva felépíthető a rendszer. Az architektúrális tervezés és a rendszertervezés között több különbség is van, melyet érdemes tisztázni. Az architektúrális tervezés magasabb absztakciós szinten van, nem olyan részletes. Általában csak rendszer/alrendszer szintig megy, illetve azok rétegeit tárgyalja, de részletesen nem foglalkozik a rétegekben szereplő komponensekkel. Általában a nem funkcionális követelményekre, és a kockázatos funkcionális követelményekre koncentrál. Átnézi az elkészült dokumentációkat.&lt;br /&gt;
&lt;br /&gt;
Az implementáció és tervezés során támogatja és ellenőrzi a fejlesztőcsapatot, az egész fejlesztési folyamat előrehaladását nyomon követi. Kidolgoz belső fejlesztési szabványokat, és folyamatosan figyeli azok betartását. Fejlesztők architektúrális kérdéseit igyekszik megválaszolni, segít az esetleges architektúrális módosítások végrehajtásában. A fejlesztés közben workshop-okat rendez az aktuális fejlesztés közben felmerült problémákról, és moderál úgy. Ezek nem akaszthatják meg a fejlesztést, nem lehet kötelező program. Ismernie kell a fejlesztési metodológiát, a használt eszközöket. Ha kell, felgyűri az ingujját, és akár kódolással segíti egy probléma lokalizálását, megoldását. Otthonosan mozog a build, release, deploy folyamatokban. Ugyanígy magas szintű rálátása van a tesztelési folyamatokra, eszközökre (harness) is, hiszen az architektúrákkal kapcsolatban egyre erősebb igény a minél kényelmesebb tesztelhetőség.&lt;br /&gt;
&lt;br /&gt;
A bevezetés és a támogatás során folyamatosan tartja a kapcsolatot az üzemeltetéssel is, a feltárt hibákat 2nd level support részeként elemzi, kategorizálja, és kommunikálja a fejlesztők felé. Próbálja az üzemeltetés és a fejlesztés közötti gyakran jelentkező szakadékot áthidalni, a feleket egymáshoz közelebb hozni.&lt;br /&gt;
&lt;br /&gt;
Milyen képességekkel kell rendelkeznie egy architect-nek, hogy ezeket a feladatokat el tudja látni? A legfontosabb a megfelelő mennyiségű tapasztalat. Ezt egyrészt megszerezheti tanulás révén, folyamatos képzésekkel, önképzéssel, a trendek figyelésével, tájékozottság fenntartásával. Másrészt rengeteg gyakorlati tapasztalattal kell rendelkeznie. Úgy gondolom, egy cégnél több évig (&amp;gt;5) maradó architect elveszik a napi rutinban, hiszen nem találkozik más problémákkal, emberekkel, megoldásokkal, gondolatokkal. Ezért érdemes vagy váltani, vagy részben máshol is ilyen jellegű tevékenységeket vállalni.&lt;br /&gt;
&lt;br /&gt;
Egy architect-nek rendelkeznie kell menedzsment képességekkel és technikai tudással is. Kockázatokat kell kezelnie. Másrészt becsléseket kell végezni. Ez sajnos nem tanulható, csak tapasztalat segíthet abban, hogy egy probléma megoldása az adott környezetben mennyi erőforrást igényel. Állandóan döntéseket kell hoznia. A döntéseket folyamatosan dokumentálni szükséges, ugyanis nem csak egy döntés, de az ahhoz vezető út is nagyon fontos lehet a projekt szempontjából. Nagyon sok projekt esetében hangzott el a kérdés, mikor a projekt előrehaladása folyamán egy döntés logikátlannak tűnt, hogy vajon az elején miért is ez lett meghozva.&lt;br /&gt;
&lt;br /&gt;
Nagyon jó kommunikációs képességekkel kell rendelkeznie. A projekt során szinte az összes projekttaggal kapcsolatban van. Nagyon fontos a követelmények felmérésénél, a víziójának másokkal való elfogadtatásával. Gondoljunk bele, az ő döntései a csapat minden tagjára kihatnak, nem mindegy, hogy mennyire tudja ezeket a többiekkel elfogadtatni. Nem ülhet elefántcsonttoronyban, és ott olvassa a dokumentációkat, és készíti a specifikációit. A fejlesztés során is végig mentoring tevékenységet kell végeznie.&lt;br /&gt;
&lt;br /&gt;
A jó architect megoszt. Megosztja a tapasztalatait, véleményeit, az érdekességeket, melyekkel találkozik. Megosztja a döntéseihez vezető utak lépéseit, a döntésnél figyelembe vett érveket. Megosztja a specifikációkat, dokumentumokat, a pilot eredményeit. Megosztja a vízióját.&lt;br /&gt;
&lt;br /&gt;
Az architect-nek nem feladata mindennek a felderítése, megtervezése. A kollégáira támaszkodik, az általuk adott specifikus tudásokból állít össze egy architektúrát. Figyelembe veszi infrastruktúrális ügyekben az üzemeltetőket, fejlesztési kérdésekben a programozókat, tesztelési kérdésekben a tesztelőket. De érti mindegyik nyelvét, és az átadottakat tudja az üzlet felé kommunikálni, és fordítva. Darabokból épít egészet.&lt;br /&gt;
&lt;br /&gt;
Nem mehet minden probléma mélyére, tudnia kell, mikor kit kell megkérnie. Ha megtenné, elaprózná az idejét, és újra az elefántcsonttoronyban kötne ki, immár technológiai problémákkal körülvéve. A feladatokat meg kell tudnia osztani.&lt;br /&gt;
&lt;br /&gt;
Gyakori kérdés, hogy jól kódol-e az architect? Nem feltétlenül. Persze nem árt, de a többi dolga mellett erre már kevésbé jut ideje, és valljuk be, ha az ember nem 8 órát kódol folyamatosan, ki lehet menni a gyakorlatból. Nem ismeri az eszközöket és API-kat sem olyan mélységben. De egy adott problémát meg tud valósítani, lehet, hogy nem olyan elegánsan, mint egy fejlesztő, feltehetőleg nem is annyi idő alatt, de hasonló megoldásokkal. Kódot olvasni tud, debugol, optimalizál. Ismeri a legjobb gyakorlatokat és tervezési mintákat. Rengeteg tapasztalata van, hogy egy probléma más rendszerekben hogyan került megoldásra. Valamint dereng még senior vagy vezető programozó korából, hogy akkor hogyan is csinálta. A tudásának ereje nem is a tudásának mélységéből, hanem szélességéből adódik. Tudja mit hol kell keresni. Kódolási képességek nélkül nem fogadják el a fejlesztők.&lt;br /&gt;
&lt;br /&gt;
Jó dokumentálási képességekkel kell rendelkeznie, tudnia kell írnia. Rögzíteni a döntéseket, és azok indokait, valamint a vízióját írásban is át kell tudnia adni a feleknek, akár egy ajánlat, akár egy specifikáció esetén.&lt;br /&gt;
&lt;br /&gt;
Maximális mértékben figyelembe kell vennie a körülményeket, alkalmazkodnia kell. Nem szabad abba a hibába esnie, hogy az önéletrajzának bővítse miatt választ technológiát, nem az adott projekten próbál ki új dolgokat, vagy mert csak ahhoz ért. Figyelembe kell vennie a csapatot. Ahhoz, hogy egy feladatot a leghatékonyabban lehessen elvégezni, a maximális újrafelhasználhatóság szükséges, tudásban is. A csapat tudásának megfelelően kell megoldásokat, módszertanokat, eszközöket, technológiákat, szabványokat választania. Nem választ ki egy programozási nyelvet, mert az menő, vagy alkalmasabb a feladatra, ha a fejlesztők közül egyik sem használta még, akár ő sem. Félre kell tenni a személyes preferenciáit.&lt;br /&gt;
&lt;br /&gt;
Amennyiben egy architect nem csak egy konkrét projekten dolgozik, hanem egy cégnél hosszabb távon alkalmazásban áll, érdemes valamilyen stratégián is dolgoznia. Egyrészt be kell gyűjteni a menedzsment felől érkező, még csak a távolban felvillanó üzleti igényeket, és beszélnie kell a fejlesztést végző csapat minden tagjával, hogy mit éreznek nehéznek, problémásnak. A kettőt egybegyúrva, minden oldallal egyeztetve kell kialakítania egy olyan stratégiát, mely egyre gördülékenyebbé és hatékonyabbá teszi a fejlesztéseket, nem korlátoz, és az új tagok munkába állását is kellően megkönnyíti.&lt;br /&gt;
&lt;br /&gt;
No de evezzünk egy kicsit technikai vizekre, nézzük, miben kell otthonosan mozognia egy ilyen szakembernek. Az elosztott rendszerek térhódításával jelent meg az igény az architect-ekre is. Hiszen minél nagyobb az elosztottság, annál több a kihívás, annál több választási lehetőség van. Egy alrendszer is egyre bonyolultabbá és bonyolultabbá válhat. A problémamegoldás egyik hatékony fegyvere a dekompozíció, komponensekre bontás. A komponensek együttműködnek, köztük interfészek helyezkednek el. Fontos az egységbe zárás (encapsulation). Az interfészek használata megkönnyíti a cserélhetőséget, tesztelhetőséget. A komponenseket megfelelően szét kell tudni választani, mindnek csak a saját feladatát kell tudnia elvégeznie (resposibility). Kialakult az Enterprise Application Integration, valamint a Service Oriented Architecture. Látható, hogy mélyebb szinten, alkalmazáson belül ugyanezeket az elveket kell alkalmazni, és látható, hogy az előbbi fogalmak egy az egyben jelennek meg objektumorientált programozás esetén is. High cohesion, low coupling. Ezeket a komponenseket és a komponensek közötti kapcsolatokat magasabb absztrakciós szintre kell emelni, modellezni kell. A rendszereket különböző nézőpontokból kell megfigyelni, pl. statikus esetben a rendszer felépítését, dinamikus esetben a rendszer működését. Ezeket valahogyan ábrázolni kell, kifejező leíró nyelv erre az UML. Fontos, az architect nem a való világ megfelelő darabját szakítja ki (üzleti terület), mint a tervezők, hanem már rendszer szinten, n agyon magas szintű objektumokban gondolkodik, informatikai fogalmakban. Leghasznosabb eszköze a component, deployment és sequence diagram. Gyakori problémákra gyakori, elterjedt megoldásokat alkalmaz, tehát ismeri a tervezési mintákat és személyre tudja szabni azokat. És itt nem kizárólag a Gang of Four tervezési mintákra kell gondolni, hanem az un. architectural pattern-ekre is. Ide kapcsolódik szorosan a refactoring is.&lt;br /&gt;
&lt;br /&gt;
Be kell vetnem pár bűvös szót is, felsorolásképpen, szigorúan össze-vissza, mely területekkel egy architect-nek már találkoznia kellett a szoftverfejlesztéssel kapcsolatban: webszolgáltatások (SOAP/REST), SOA, cloud, event driven architecture, domain driven design, Behaviour-Driven Development, test driven development, continuous integration, continuous delivery, agile development, dependency injection, inversion of control, AOP, caching.&lt;br /&gt;
&lt;br /&gt;
A Sun, később az Oracle ennél talán behatároltabban kezeli az architect-et. Végighallgattam egy több napos "Architecting and Designing J2EE Applications" képzést. Ennek első fele kb. a fentebb leírtakat ecseteli meglepően kevés technológiai utalással, későbbi részek már a technológiára mennek rá. Ennek megfelelő a &lt;a href="http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=326"&gt;Oracle Certified Master, Java EE 5 Enterprise Architect&lt;/a&gt; vizsga is, érdekes, Java EE 6-ra még nem jelent meg. Az említett linken látható, hogy ez nem csak egy teszt kitöltéséből, hanem azon felül egy esszé megírásából és annak megvédéséből áll.&lt;br /&gt;
&lt;br /&gt;
Természetesen az Oracle a saját komponens architektúráját kéri számon, azaz az EJB technológiát, valamint annak környezetét, a Java EE szabványt. Ez utóbbiból megköveteli a JDBC, JPA, JMS, JCA, Servlet, JSP, JSF, JAXB, JAX-WS ismeretét. Kitér a komponensek környezetét biztosító  alkalmazásszerverekre, valamint a Java EE tervezési mintákra is.&lt;br /&gt;
&lt;br /&gt;
Az EJB mellett azonban ne felejtkezzünk el a Spring-ről és az OSGi-ról sem.&lt;br /&gt;
&lt;br /&gt;
Úgy gondolom, az áttekintő tudás hasznos, de nem megkövetelendő a különböző JVM-re épülő nyelvek, mint pl. a Groovy vagy Scala ismerete, valamint a naprakészség olyan modern irányzatokban, mint pl. a NoSQL eszközök.&lt;br /&gt;
&lt;br /&gt;
Ma már az architect-ek is szakosodhatnak. Lehetnek enterprise architect-ek, akik az alkalmazásintegrációt tartják szem előtt. Lehetnek application vagy system architect-ek, akik az alkalmazások belső felépítéséért felelnek. Lehetnek infrastructure architect-ek, akik az infrastruktúráért felelősek, mint hardver, szerver szoftverek, hálózat, adatbázis, és kedvencük a skálázhatóság, fürtözés, terheléselosztás és újabban a virtualizáció.&lt;br /&gt;
&lt;br /&gt;
Megnéztem több állásportált is, száz Java fejlesztői állásra maximum három-öt Java architect jut. Egyrészt nem annyira elterjedt itthon, másrészt szeretik a cégek a saját szakemberüket kinevelni. Meglepő azonban, hogy ez a pár állás viszont elég pontosan írta le a feladatköröket, azaz tudják, kit keresnek.</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/340189829288615845/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/01/ki-is-az-java-architect.html#comment-form" title="6 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/340189829288615845?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/340189829288615845?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/01/ki-is-az-java-architect.html" title="Ki is az a Java architect?" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>6</thr:total></entry><entry gd:etag="W/&quot;CEQERXYzfSp7ImA9WhRVFk8.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-6156167128518622117</id><published>2012-01-14T22:16:00.006+01:00</published><updated>2012-01-15T11:11:44.885+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-15T11:11:44.885+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><category scheme="http://www.blogger.com/atom/ns#" term="könyv" /><title>Visszatekintés 2011-re</title><content type="html">&lt;p&gt;Így az év elején az ember kicsit visszatekint, és rendszerezi a gondolatait a jövővel kapcsolatban is.&lt;/p&gt;

&lt;p&gt;A 2011-es év folyamán 20 postot írtam. Kicsit próbálkoztam a nem annyira technikai témákkal is, hanem a szoftverfejlesztéssel kapcsolatos általános gondolataimat is próbáltam leírni, pl. a &lt;a href="http://jtechlog.blogspot.com/2011/05/miert-ne-fejlesszunk-sajat.html"&gt;Miért ne fejlesszünk saját keretrendszert?&lt;/a&gt; postban, amihez magasan a legtöbb megjegyzés érkezett, láthatóan titeket is érint a téma. Látható volt az útkeresésem is, ugyanis a Java világ jövője kicsit bizonytalan, nem is ad mindig annyi lelkesedésre okot, és egy kiegészítő eszközt is kerestem, amivel gyakori ismétlődő feladatokat egyszerűen tudok elvégezni, így esett a választásom a Python-ra (&lt;a href="http://jtechlog.blogspot.com/2011/06/masodik-nyelv-python.html"&gt;Második nyelv: Python?&lt;/a&gt;). Természetesen  bejegyzéseim javát így is azok a dolgok tették ki, amivel projektjeim során találkoztam, így került sor a &lt;a href="http://jtechlog.blogspot.com/2011/07/vastag-kliens-java-ban-netbeans.html"&gt;NetBeans Platform&lt;/a&gt; bemutatására, volt egy post sorozat a Subversion, Maven, release témákban, valamint az év végén egy kis &lt;a href="http://jtechlog.blogspot.com/2011/12/java-memoriakezeles-szemetgyujto.html"&gt;Java teljesítményhangolásról&lt;/a&gt; is szó esett.&lt;/p&gt;

&lt;p&gt;Így év elején letisztáztam az egyéb online megjelenéseim is, így látható jobb oldalon az "Elérhetőségek" doboz, melynek első eleme a Google+. A Google Reader az elsődleges hírforrásom, amiben a Google megszüntette a megosztási lehetőséget, a Google+-ba tereli be. Így én is áttértem, így minden érdekes cikket ott fogok megosztani, ha gondoljátok, kövessetek a &lt;a href="https://plus.google.com/115891152269405230539"&gt;Google+-on&lt;/a&gt;. A megosztások itt a blogban is megjelennek a "Google+" dobozban. Még egy változás történt, ezek után a példa kódokat a &lt;a href="https://github.com/vicziani"&gt;GitHub&lt;/a&gt;-on érhetitek el.&lt;/p&gt;

&lt;p&gt;Persze nem maradhatnak el a statisztikák sem. Magasan a legnézettebb post 2011-ben a &lt;a href="http://jtechlog.blogspot.com/2009/10/java-forrasok-tanulashoz.html"&gt;Java források tanuláshoz&lt;/a&gt;, mely egy kezdőknek szóló, 2009-es post. Második a már említett "Miért ne fejlesszünk saját keretrendszert?", és a harmadik a 2010-es &lt;a href="http://jtechlog.blogspot.com/2010/04/maven-kezdolepesek.html"&gt;Maven kezdőlépések&lt;/a&gt;, ami szintén kezdőknek szól. Az idei postok közül a már említett "Vastag kliens Java-ban? NetBeans Platform", és a "Második nyelv: Python?" volt a legnézettebb. Érdekes, hogy annak ellenére, hogy a Java nem a legmegfelelőbb választás vastag kliens fejlesztésére, mégis sokakat érdekelt, míg az utóbbi nem is Java téma.&lt;/p&gt;

&lt;p&gt;A legtöbb látogatót természetesen a Google hozta, a keresési szavak felhőjét mutatja az alábbi kép. Minél nagyobb egy szó, annál többször kerestek rá. Kedvenc keresési kifejezésem a "Honnét lehet rendelni a pom pomt?" Látszik a keresőszavakból, hogy sokan úgy térnek vissza, hogy emlékeznek nagyjából a post címére, és arra keresnek rá. Szomorú azonban, hogy túl sokan akadnak úgy a blogra, hogy könyvet akarnak letölteni. Sláger a Java Útikalauz programozóknak és a J2EE útikalauz java programozóknak című könyv, de sokan keresnek Angstler könyveket és angol nyelvű könyveket is. Úgy gondolom, hogy érdemes ezeket a könyveket megvásárolni, sokszor le lehet ezeket venni a polcról. Egy darabig gyűjtöget az ember, aztán rájön, hogy mire elolvasná, rég elavult, amennyire meg mégis jut idő, annyit meg is lehet vásárolni. A keresőszavakból az is kiderül a számomra, hogy attól függetlenül, hogy kevés Java tartalom van magyar nyelven, az emberek mégis bíznak, hogy magyarul is találnak valamit.&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/-Rjb5aSyqFvY/TxHwxVA8WFI/AAAAAAAAHvk/ruqudhTSNTs/s1600/keresoszavak.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 166px;" src="http://1.bp.blogspot.com/-Rjb5aSyqFvY/TxHwxVA8WFI/AAAAAAAAHvk/ruqudhTSNTs/s320/keresoszavak.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5697599733845743698" /&gt;&lt;/a&gt;

&lt;p&gt;A postokban szereplő gyakori szavak a következők: Java, EJB, NetBeans, Maven, Subversion, build, release, branch, merge, szemétgyűjtő algoritmus.&lt;/p&gt;

&lt;p&gt;Legtöbb látogatót a Google után a &lt;a href="http://www.hup.hu"&gt;HUP&lt;/a&gt; hozott, bár csak pár megjegyzésben szerepel a JTechLog-ra link.&lt;/p&gt;

&lt;p&gt;Azért, hogy a blogot még jobbá tegyem, összeállítottam egy kérdőívet, melynek segítségével megpróbálom felmérni az olvasótábor képzettségi szintjét, az érdeklődésre számot tartó témákat, valamint azt, hogy érdemes-e a blogot valamilyen irányba változtatni. Legyen-e több rövidebb tartalom, vagy a postok szintje legyen más. &lt;a href="https://docs.google.com/spreadsheet/viewform?hl=hu&amp;formkey=dG9EV2dBazlqdjFMenFIb21TWTl0U0E6MQ#gid=0"&gt;Kérlek töltsd ki te is, csak kilenc kérdés!&lt;/a&gt; Mindenki véleménye számít. És azért, hogy lássátok, tényleg odafigyelek az olvasókra, a kérdőívet kitöltők között kisorsolom a három kötetes "Java 2 útikalauz programozóknak" könyvem, CD melléklettel. Amennyiben érdekel a könyv, kérlek mindenképp írd a kérdőívbe az e-mail címedet is. Az eredmény január 28-án várható. Érdemes játszani, mivel viszonylag kicsi az olvasótábor, így nagy esély van a nyereményre. Amennyiben nem érdekel, kérlek a kérdőívet akkor is töltsd ki, ezzel is segítve a blogot, hogy számodra is érdekesebb tartalom jelenjen meg a továbbiakban.&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/-klEoCvGzt54/TxHw5KEt8aI/AAAAAAAAHvw/A6iyBDtHwR8/s1600/Java-utikalauz-programozoknak.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 224px; height: 320px;" src="http://1.bp.blogspot.com/-klEoCvGzt54/TxHw5KEt8aI/AAAAAAAAHvw/A6iyBDtHwR8/s320/Java-utikalauz-programozoknak.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5697599868347740578" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/6156167128518622117/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2012/01/visszatekintes-2011-re.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6156167128518622117?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6156167128518622117?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2012/01/visszatekintes-2011-re.html" title="Visszatekintés 2011-re" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-Rjb5aSyqFvY/TxHwxVA8WFI/AAAAAAAAHvk/ruqudhTSNTs/s72-c/keresoszavak.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C08BQXk_eip7ImA9WhJTE0g.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-8365011667058151286</id><published>2011-12-30T02:10:00.018+01:00</published><updated>2012-06-22T09:57:30.742+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-22T09:57:30.742+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="hotspot" /><category scheme="http://www.blogger.com/atom/ns#" term="jvm" /><title>Java memóriakezelés, szemétgyűjtő algoritmusok</title><content type="html">&lt;p&gt;Technológiák: Java Development Kit 1.6&lt;/p&gt;

&lt;p&gt;A Java tervezésekor egyik legfőbb szempont a biztonság volt. Ez egyrészt megnyilvánul abban, hogy a felhasználó tudja kontrollálni egy nem megbízható forrásból szerzett program hozzáféréseit, másrészt támogatja a programozókat abban, hogy minél kevesebb hibát vétsenek.&lt;/p&gt;

&lt;p&gt;Ez utóbbi egy szelete az, hogy nem explicit kell memóriát lefoglalnunk, és felszabadítanunk, hanem a virtuális gép megteszi ezt helyettünk. Pontosabban a szemétgyűjtő mechanizmus (garbage collector - GC), melynek feladata a nem használt objektumok eltakarítása a memóriaterületről. Így sokkal kisebb a hibalehetőség, cserébe egy automatizmus szabadítja fel a memóriát, aminek külön erőforrásra van szüksége, ami kiélezett helyzetekben (magas terhelés esetén) akár az alkalmazás teljesítményére is hatással lehet. A hibajelenség, amitől megszabadulunk, az a memóriaszivárgás (memory leak). Ez gyakorlatilag akkor történik, mikor már nincs szükségünk egy objektumra, nincs rá referencia, de a memóriaterületet nem szabadítottuk fel. Szerencsére a szemétgyűjtő mechanizmus megteszi ezt helyettünk.&lt;/p&gt;

&lt;p&gt;(Zárójelben jegyzem meg, hogy Java esetén is szoktak memóriaszivárgásról beszélni, azonban ennek kicsit más a jelentése. Ez a leggyakrabban kollekciók használatakor szokott felmerülni. Képzeljük el, hogy egy dinamikus méretű listát egy tömbbel ábrázolunk. Mivel a tömb mérete fix, egy változó jelzi, hogy a tömb épp hány elemét használjuk ki. Amennyiben töröljük az utolsó elemet, a működés szempontjából elegendő csak ennek a változónak az értékét csökkenteni. Ekkor azonban a tömb változón felüli eleme még tart referenciát az adott objektumra, ezért a szemétgyűjtő nem tudja kidobni. Emiatt kell null-ra állítanunk a tömb megfelelő elemét. Tipikus hiba még az eseménykezelők nem használatos objektumon tartása.)&lt;/p&gt;

&lt;p&gt;Fontos megkülönböztetni két memóriaterület, a heap és a stack fogalmát. A példányváltozók és az az összes példányosított objektum a heap-en helyezkedik el. A metódusban definiált, úgynevezett lokális változók vannak a stack-en (, ide tartoznak a metódushívás aktuális paraméterei is). Vigyázzunk, amennyiben a stack-en szereplő lokális változó típusa osztály, az osztály példánya már a heap-en helyezkedik el, a stack-en kizárólag az erre mutató referencia.&lt;/p&gt;

&lt;p&gt;Ezzel kapcsolatban párszor már találkoztam azzal a tévhittel, hogy a Java szemétgyűjtő mechanizmusa referenciaszámláló alapján működik. Azaz nézi, hogy egy objektumra hány hivatkozás van, és amennyiben ez nullára csökken, az objektum eldobható a memóriából. Ez nem így van. Képzeljük el, hogy A objektum hivatkozik B objektumra, és vissza. Amennyiben más hivatkozás nincs rájuk, mindkettő eltávolítható, de a referenciaszámlálója mindegyiknek egy. Ehelyett a JVM a következőképpen működik. Az élő szálak stack-jeiből elérhető objektumokat járja végig. Ez azt jelenti, hogy végigmegy a referenciákon, azaz az objektumokból elérhető objektumokon is. Ezeket megjelöli. (Ezen szabály alkalmazásán kívül még végigmegy a betöltött és még nem kidobott osztályok statikus tagjain, valamint a JNI-ből bejegyzett objektumokon is.) Eztán a nem megjelölt objektumokat kidobja. Azaz kidobja az összes olyan objektumot mely nem érhető el referenciákon keresztül egy élő szálból sem.&lt;/p&gt;

&lt;p&gt;A szemétgyűjtő mechanizmus megvalósítása nem a szabvány része, ezért különböző gyártók különbözőképpen implementálhatják azokat. Én most a legelterjedtebb, Sun (már Oracle) által gyártott, a Java 2 Platform, Standard Edition JDK-ban megtalálható Java HotSpot virtuális gépről fogok írni, továbbiakban JVM. Jó referencia a &lt;a href="http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf"&gt;Memory Management in Java HotSpot Virtual Machine&lt;/a&gt; dokumentum. A JVM-nek három fő része van: runtime, JIT, és a memóriakezelést végző szemétgyűjtő mechanizmus.&lt;/p&gt;

&lt;p&gt;A szemétgyűjtő mechanizmus un. weak generational hypothesis-re épül. Megfigyelték az alkalmazások működését, és a következő szabályokat vették észre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Az objektumok nagy része rövid életű&lt;/li&gt;
&lt;li&gt;Régi objektumból új objektumra viszonylag kevés hivatkozás van&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ezen megfigyelések az alkalmazások nagy részére igazak, persze lehetnek kivételek. Azaz a legtöbb alkalmazás úgy működik, hogy üzemelése közben gyakorta nagyon rövid életű, temporális objektumot gyárt, mely igazából csak az algoritmusok lefutásáig, a felhasználó kiszolgálásáig kellenek, utána el is dobhatóak. Csak viszonylag kevés objektum kell hosszú távon, és ezek utána hosszú életűek, és általában ritkán hivatkoznak újabb objektumokra. Ezen hipotézis alapján építették fel a szemétgyűjtő mechanizmust, és ezen szabályokkal szembe menni akár a szemétgyűjtő működését is megzavarhatják. (Tipikus példa erre az objektum cache, mely tipikusan a legrégebbi objektum, melybe újabb és újabb objektumok kerülhetnek. Ezeket a szemétgyűjtő kevésbé szereti.)&lt;/p&gt;

&lt;p&gt;A Sun mérnökei a JVM-be ráadásul nem csak egy, hanem több szemétgyűjtő mechanizmust is építettek. Ezek közül a JVM automatikusan képes választani, de akár explicit is megmondhatjuk, hogy melyiket használja. Bizonyos szemétgyűjtő algoritmusok más-más alkalmazások esetén, más-más architektúrákon különbözőképpen teljesíthetnek, így nincs mindenre jó megoldás, nekünk kell vagy a JVM-re hagyatkozni, vagy kiválasztani, hogy melyik a legmegfelelőbb. A választásnál a következőket kell figyelembe venni:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Áteresztőképesség (throughput): a futási idő hány százalékát tölti a CPU az alkalmazásunk futtatásakor nem a szemétgyűjtő futtatásával (persze megfelelő nagy időszeletre nézve)&lt;/li&gt;
&lt;li&gt;GC pluszmunka (overhead): az előző inverze, mennyi időt tölt a CPU a GC futtatásával az összes időhöz képest&lt;/li&gt;
&lt;li&gt;Állási idő (pause time): mennyi ideig áll az alkalmazás, míg a GC fut&lt;/li&gt;
&lt;li&gt;Szeméggyűjtő mechanizmus futtatásának gyakorisága (frequency): milyen gyakran fut a GC&lt;/li&gt;
&lt;li&gt;Memóriaigény (footprint): az alkalmazás memóriaigénye, pl. a heap mérete&lt;/li&gt;
&lt;li&gt;Reakcióidő (promptness): az idő aközött, amikor az objektum begyűjthetővé válik, és aközött, hogy a memória újra felhasználhatóvá válik&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ráadásul ezen mérőszámok egyikének javításakor a másik mérőszám rosszabb lesz, hiszen ellentmondanak egymásnak. Pl. amennyiben azt akarjuk, hogy kevesebbet álljon az alkalmazás, pl. a szemétgyűjtő több szálon dolgozzon, akkor a szálak adminisztrációja megnövekedett erőforrásidénnyel (mind CPU, mind memória) jár.&lt;/p&gt;

&lt;p&gt;Ahhoz, hogy megértsük a szemétgyűjtők működését, először meg kell értenünk a JVM memóriamodelljét. Talán legjobb vizuálisan szemléltetni. Az alábbi ábrára klikkelve bejön egy VisualVM-ben futó Visual GC plugin alapján készített GIF animáció, melyen egy JBoss alkalmazásszervert látunk futni. A VisualVM a JDK-ban megtalálható, a jvisualvm paranccsal indítható. A VisualGC plugin a Tools/Plugins menüpontból indítva külön letölthető. Mindkettő ingyenes, nyílt forráskódú eszköz.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://dl.dropbox.com/u/7683931/jtechlog/visualgc_gifanim.gif" rel="lightbox"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 299px;" src="http://4.bp.blogspot.com/-Hgkvfe-YRjA/Tv0QOVMrD1I/AAAAAAAAHrc/M0vJrloT35I/s320/visualgc_gifanim.gif" border="0" alt="Visual GC plugin egy JBoss futtatása közben" id="BLOGGER_PHOTO_ID_5691723342460686162" /&gt;&lt;/a&gt;

&lt;p&gt;A Spaces ablakban a JVM heap-je látható, ami három részre van felosztva: permanent generation (permgen), young és old. A permgen memóriaterületen helyezkednek el a betöltött osztályok definíciói, valamint a String pool (un. Interned Strings). A young területen (un. generation) helyezkednek el a fiatal objektumok, és az old területen helyezkednek el az idősebb objektumok (az előbb említett hipotézis miatt van ez a megbontás). A szemétgyűjtő mechanizmus mindkét területen lefut, de meg kell különböztetni ezeket. Tehát gyakran lefut az un. minor szemétgyűjtő, mely csak az young generation-ön dolgozik, és ritkábban a major/full szemétgyűjtő, ami az old generation-ön is lefut. Ez ritkábban fut, hiszen lassabban nő, és tovább tarthat, hiszen nagyobb területet kell átvizsgálnia a szemétgyűjtőnek.&lt;/p&gt;

&lt;p&gt;A young generation három részből áll: eden, survivor 0, survivor 1. A frissen példányosított objektumok először az eden-re kerülnek, amikor lefut rajtuk a szemétgyűjtő mechanizmus, és túlélnek (nem kerülnek eldobásra, élő objektumok), akkor kerülnek a survivor (túlélő) egyikére. Egyszerre mindig csak az egyik használt a survivor-ök közül. Amikor lefut a szemétgyűjtő, az a használt survivor-ön is lefut, és a túlélő objektumok átkerülnek a másik survivor területre. Az előző survivor tehát teljesen üres marad. Utána a szemétgyűjtő ismételt lefutásakor a fordított irányban vándorolnak a túlélő objektumok a survivor-ök között. Amennyiben az objektum túlélése elért egy megfelelő számot, átkerül az old generation-be.&lt;/p&gt;

&lt;p&gt;A &lt;a href="http://www.devx.com/Java/Article/21977/1954"&gt;Garbage Collection in the Java HotSpot Virtual Machine&lt;/a&gt; cikk ábráit használva a következő lépésekből áll tehát a young generation-ön a szemétgyűjtés. Az eden és az egyik survivor területen is gyűltek az objektumok.&lt;/p&gt;

&lt;img style="display:block; margin:0px auto 10px; text-align:center;width: 400px; height: 203px;" src="http://1.bp.blogspot.com/-pxm2DRTqypQ/Tv0RPi6bNpI/AAAAAAAAHr0/xKb7L8oFg6g/s400/yg_1.png" border="0" alt="Mark-sweep-compact algoritmus első lépése" id="BLOGGER_PHOTO_ID_5691724462833743506" /&gt;

&lt;p&gt;A túlélő objektumok az eden-ből és az egyik survivor-ből is a másik survivor területre kerülnek, valamint az egyik survivor-ből a bizonyos kort megélt objektumok az old generation-be kerülnek.&lt;/p&gt;

&lt;img style="display:block; margin:0px auto 10px; text-align:center;width: 400px; height: 304px;" src="http://4.bp.blogspot.com/-P05oLdHGVQM/Tv0RUwSJQ0I/AAAAAAAAHsA/j653Ofy-d3s/s400/yg_2.png" border="0" alt="Mark-sweep-compact algoritmus második lépése" id="BLOGGER_PHOTO_ID_5691724552322237250" /&gt;

&lt;p&gt;A szemétgyűjtés után mind az eden, mind az egyik survivor teljesen kiürül.&lt;/p&gt;

&lt;img style="display:block; margin:0px auto 10px; text-align:center;width: 400px; height: 304px;" src="http://3.bp.blogspot.com/-QHLWVHlrIvo/Tv0RYcEuD-I/AAAAAAAAHsM/pxCi8Iw0528/s400/yg_3.png" border="0" alt="Mark-sweep-compact algoritmus harmadik lépése" id="BLOGGER_PHOTO_ID_5691724615616696290" /&gt;

&lt;p&gt;Ha megnézünk egy más parancssori paraméterekkel indított JVM-et (a JDK demo\jfc\Java2D\ könyvtárában a Java2D-t demonstráló példaprogramot a &lt;code&gt;java -jar Java2Demo.jar&lt;/code&gt; paranccsal elindítva) kicsit más karakterisztikát láthatunk, de a működés alapvetően hasonlít. Itt megjelent egy Histogram nevezetű ablak, mely százalékosan mutatja a young generation objektumait, hogy hány százaléka hány szemétgyűjtést élt túl. Az ábrán a Tenuring threshold azt jelenti, hogy 15 szemétgyűjtés túlélése után kerül az objektum az old generation-be.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-YzLzSTOkHKI/Tv0Q_JqbAfI/AAAAAAAAHro/6ZIyvELJiHE/s1600/gc1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 230px;" src="http://3.bp.blogspot.com/-YzLzSTOkHKI/Tv0Q_JqbAfI/AAAAAAAAHro/6ZIyvELJiHE/s320/gc1.png" border="0" alt="Visual GC a Java2Demo futtatása közben" id="BLOGGER_PHOTO_ID_5691724181177827826" /&gt;&lt;/a&gt;

&lt;p&gt;Vizsgáljuk meg az első ábrát, az talán látványosabb. Egyrészt kevésbé észrevehető, hogy a Spaces ablakban a háttér világosabb és sötétebb szürke négyzetekkel van behálózva. A sötétszürke a ténylegesen lefoglalt memóriát (utilized, commited), míg a világosabb szürke a JVM által lefoglalható, de még nem lefoglalt memóriát jelzi (uncommited). A konkrét értékek látszanak a Graphs ablakban is. Látható, hogy a young generation esetén az eden-ben lévő objektumok összmérete folyamatosan nő, mígnem a GC grafikonon látjuk, hogy lefut egy szemétgyűjtés (zöld tüske), és ekkor az eden kiürül. Ezzel egy időben azt is látjuk, hogy a túlélő objektumok az egyik survivor-ből átkerülnek a másikba, nagyon szépen látható a narancs grafikonon, hogy egyszerre csak az egyik használt, és mérete nem változik, csak a szemétgyűjtés lefutásakor. Egy normál működésű szerver alkalmazásnál ha ilyen szép fűrészfoggal találkozunk, akkor megnyugodhatunk. Amennyiben a fogak túl sűrűek, ott baj lehet, hiszen a GC-nek gyakran kell futnia, ez egyrészt gyakrabban állítja le az alkalmazást, másrészt több erőforrást is igényel. Amennyiben a szemétgyűjtő lefutása után nem esik vissza a memóriahasználat, akkor is baj van, mert akkor valószínű, hogy memóriaszivárgásunk van. A permgen mérete általában állandó, vagy nagyon lassan növekszik. Ha az telik be, akkor találkozhatunk a java.lang.OutOfMemoryError: PermGen space hibával. Ez általában akkor van, amikor újratelepítgetünk egy alkalmazást az alkalmazásszerveren, és valami osztálybetöltő probléma miatt az előző alkalmazásunkat a konténer nem tudja kidobni, így annak class-ai is a permgen-en maradnak. Ami egy idő után, bizonyos számú telepítés után elfogyhat.&lt;/p&gt;

&lt;p&gt;Amennyiben az egyik survivor betelne, az ide kerülendő objektumok automatikusan az old generation-be kerülnek átmásolásra. Ezt a hibajelenséget premature promotion-nek nevezik. Amennyiben emiatt betelik az old generation is, és le kell futtatni a GC-t, promotion failure-nek nevezik.&lt;/p&gt;

&lt;p&gt;Amennyiben elfogy a memória, az OutOfMemoryError-t kapjuk. Jegyezzük meg azonban, hogy a JVM garantálja, hogy csak akkor dobja, ha a GC lefutott, és ezután nincs szabad memória. Azaz a szemétgyűjtőt mindenképpen meghívja. Emiatt sem érdemes kezelni catch ágban az OutOfMemoryError-t. És azért sem, mert ilyenkor már arra sem lesz memória, hogy kezeljük.&lt;/p&gt;

&lt;p&gt;A memóriakezelésben találunk még egyéb finomságokat, amiket érdemes megjegyezni. Egyrészt úgy kéne kiválogatni a young generation-ből azokat az objektumokat (mark), melyek használtak, hogy ne kelljen az egész old generation-t átvizsgálni, hogy nincs-e visszafele hivatkozás. Ehhez a garbage collector egy card table-t tart nyilván. Az old generation-t 512 bájtos darabokra bontja (chunks), és mindegyikhez egy flag-et társít. Amennyiben az old gen-ben egy objektum referálni kezd egy young gen-ben lévő objektumra, a beállító művelet a hozzá tartozó flag-et is (egy un. write barrier-en keresztül) átbillenti. A végén csak a billentett flag-gel rendelkező old gen-ben lévő objektumokkal kell törődni.&lt;/p&gt;

&lt;p&gt;Másik érdekes technika a gyors memóriafoglaláshoz szükséges. A JVM egy bump-the-pointer mechanizmust alkalmaz, ami egy mutatót használ annak a memóriahelynek a megjelölésére, ahova az új objektumot el lehet tenni. Elteszi az objektumot, majd feljebb emeli a pointer-t. Azonban többszálas környezetben ez macerás lehet, hiszen szinkronizálni kéne erre a mutatóra, és ott szűk keresztmetszet lehet. Ezért a JVM un. Thread-Local Allocation Buffer-eket (TLAB-ok) tart fenn szálanként. Ezek gyakorlatilag szálanként különböző memóriaterületek, így nincs szükség lock-ra.&lt;/p&gt;

&lt;p&gt;Ahhoz, hogy megértsük, mikor melyik szemétgyűjtő fut, valamint hogyan lehet bekapcsolni őket, beszélni kell a parancssori kapcsolókról, valamint az ergonomics-ról.&lt;/p&gt;

&lt;p&gt;A parancssori kapcsolóknak három fajtája van. A standard, non-standard (-X kapcsolóval kezdődnek) és a developer (-XX: kapcsolóval kezdődnek). A szabványos kapcsolókat a Java Virtual Machine Specification definiálja. Az utóbbi két kapcsoló nem szabványos, JVM-enként mások lehetnek. Minden további nélkül változhat a működésük különböző JDK verziók között, tehát mindig érdemes figyelni a release notes-okat. A developer kapcsolók felépítése a következő. Minden paraméternek van egy típusa, általában boolean vagy int. Amennyiben boolean, a paraméter neve előtt + vagy - karakterrel lehet be vagy kikapcsolni (pl. -XX:+UseSerialGC a serial collector bekapcsolására). Amennyiben int, a paraméter neve után kell írni, egyenlőségjellel elválasztva, és gyakran egy mértékegységet is írhatunk utána (pl. -XX:NewSize=64m, amivel az új generáció kezdeti és minimális méretét állítjuk 64 megára). A paraméterek rendelkeznek valamilyen default értékkel. A developer paraméterek egy listája a &lt;a href="http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html"&gt;Java HotSpot VM Options&lt;/a&gt; címmel található az Oracle oldalán.&lt;/p&gt;

&lt;p&gt;A JDK az 1.5 verziótól kezdve felismeri az alatta lévő architektúrát, és két osztály egyikébe sorolja, vagy kliens osztályú, vagy szerver osztályú gépek csoportjába. A JDK 6-ban a detektálásról JDK dokumentációjának &lt;a href="http://docs.oracle.com/javase/6/docs/technotes/guides/vm/server-class.html"&gt;Server-Class Machine Detection&lt;/a&gt; fejezete ír. Alapvetően a legalább 2 CPU-val (maggal) és legalább 2 GB memóriával rendelkező nem Windows-os gépeket soroljuk ide. Az osztályt explicit is meg lehet adni a -client vagy -server parancssori kapcsolók megadásával. Az ergonomics másik része, hogy a egyrészt az osztály alapján választ szemétgyűjtő mechanizmust, valamint a megadott paraméterek alapján automatikusan finomhangolja a heap memóriaterületek méretét, nem nekünk kell megadni azokat. Erről a JDK dokumentációjának &lt;a href="http://docs.oracle.com/javase/6/docs/technotes/guides/vm/gc-ergonomics.html"&gt;Garbage Collector Ergonomics&lt;/a&gt; fejezete ír. Ha egyéb kapcsolót nem adunk meg, kliens osztályú gép esetén client JVM fut, serial collector (lsd. később), 4 mega kezdeti heap méret, és 64 mega maximum heap méret. Szerver esetén a kezdeti heap méret a fizikai memória hatvannegyede, minimum 32 mega, maximum 1 giga. Maximum heap méret a fizikai memória egynegyede, maximum 1 giga.&lt;/p&gt;

&lt;p&gt;És akkor következzenek a szemétgyűjtő mechanizmusok, a következő sorrendben:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serial Collector&lt;/li&gt;
&lt;li&gt;Parallel/Throughput Collector&lt;/li&gt;
&lt;li&gt;Parallel Compacting Collector&lt;/li&gt;
&lt;li&gt;Concurrent Mark-Sweep (CMS) Collector&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Serial Collector&lt;/h4&gt;

&lt;p&gt;A serial collector esetén a young és az old terület szemétgyűjtése is egy szálon történik, un. stop-the-world módon. Ez azt jelenti, hogy a JVM az alkalmazást teljesen leállítja, amíg a szemétgyűjtés folyik. Ez valójában úgy történik, hogy az összes Java szálat leállítja (un. safepoint), hogy ne változzon a heap, sem a szálhoz tartozó stack. Érezhető, hogy ez a megállás gyakorlatilag a szemétgyűjtéses megközelítés legnagyobb hátránya. Ez normális működés esetén észrevehetetlen, de nagy terhelés, intenzív memóriahasználat, sok párhuzamos felhasználó esetén már nagyban ronthatja az alkalmazásunk teljesítményét. A young generation szemétgyűjtése a fentebb leírt módon történik, azaz a túlélő objektumok a survivor-re, majd az old generation területre kerülnek. Az old generation és permanent generation szemétgyűjtése un. mark-sweep-compact algoritmussal történik. Mark fázisban a szemétgyűjtő megjelöli az élő objektumokat, a sweep fázisban kitakarítja a nem élő objektumokat, és a compact fázisban az élő objektumokat a megfelelő memóriaterület elejére tolja. Így a memóriaterületen nem lesznek lyukak, az elején lesznek az élő objektumok, a végén az üres hely. Így használható a fentebb említett bump-the-pointer mechanizmus. Ezt használva nem jelentkezik a memória töredezettsége, melyet később részletezek.&lt;/p&gt;

&lt;p&gt;A serial collector általában remek választás kliens oldali alkalmazások esetén, akár egy 64 megás heap esetén is viszonylag ritka és rövid (&lt; 0,5 mp) leállásokkal jár. Ez felhasználói felületekkel rendelkező, egy felhasználót kiszolgáló alkalmazások esetén megfelelő. Akkor is jól jöhet, ha több JVM osztozik egy processzoron, hiszen ekkor úgysem tud párhuzamosan futni a szemétgyűjtés a processzorok kihasználtsága miatt, ugyanis a többi algoritmus valahogy párhuzamosítani próbál. A serial collector az alapértelmezett a nem szerver-osztályú gépek esetén. Egyéb esetben a &lt;code&gt;-XX:+UseSerialGC&lt;/code&gt; parancssori kapcsolóval lehet bekapcsolni.&lt;/p&gt;

&lt;h4&gt;Parallel/Throughput Collector&lt;/h4&gt;

&lt;p&gt;A parallel/throughput collector annyival másabb, mint a serial collector, hogy a young generation szemétgyűjtése nem egy szálon, hanem több szálon fut. De ugyanúgy megállítja a többi szálat, és másolja az objektumokat a memóriaterületek között. Az old generation szemétgyűjtése megegyezik a serial collector szemétgyűjtésével, ami a mark-sweep-compact algoritmus. Ennek a szemétgyűjtőnek használatát több processzor(mag) kihasználására tervezték, és ott érdemes alkalmazni, ahol nem baj, ha az old generation meg is akasztja az alkalmazás futását. A young generation szemétgyűjtése tehát rövidebb megállást eredményez, de több processzoridőt és memóriát igényel a szálak karbantartása miatt. Hasznos lehet pl. nagytömegű batch feldolgozások, számlázás, tudományos számítások, stb. Automatikusan kiválasztásra kerül szerver osztályú gépeken, egyéb esetben a &lt;code&gt;-XX:+UseParallelGC&lt;/code&gt; parancssori kapcsolóval lehet bekapcsolni.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-tBvK_ai1xjc/Tv0Ru1kfiUI/AAAAAAAAHsk/Ol1AlFrE52A/s1600/serial_parallel.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 224px;" src="http://2.bp.blogspot.com/-tBvK_ai1xjc/Tv0Ru1kfiUI/AAAAAAAAHsk/Ol1AlFrE52A/s320/serial_parallel.png" border="0" alt="Serial és parallel collector összehasonlítása" id="BLOGGER_PHOTO_ID_5691725000417970498" /&gt;&lt;/a&gt;

&lt;h4&gt;Parallel Compacting Collector&lt;/h4&gt;

&lt;p&gt;Ez a szemétgyűjtő algoritmus a J2SE 5.0 update 6-ban került bevezetésre. A young generation szemétgyűjtése megegyezik az előző, parallel/throughput collector működésével. A különbség csak az old generation szemétgyűjtésénél van, konkrétan ez is több szálon képes futni. Ez a szemétgyűjtés három fázisból áll: marking, summary, compaction. A marking fázisban a memória régiókra kerül felosztásra. Az alkalmazásból közvetlenül elérhető objektumokat a szálak szétosztják egymás között, és elkezdenek végigmenni a referenciákon, és megjelölik a használt objektumokat. A második, summary fázis már nem objektumokon, hanem régiókon dolgozik. A szemétgyűjtő működésének eredményeképpen egy olyan állapot jön létre, hogy a memóriaterület elején sűrűbb rész van, a végén ritkább. A sűrűbb azt jelenti, hogy onnan viszonylag ritkán kell objektumokat kidobálni. A szemétgyűjtő az elejétől a végéig végigmegy a régiókon, és kitalálja, hogy melyik régiótól kezdve éri meg kidobálni az objektumokat. Ezen pont előtt lévő terület a dense prefix, ezt a szemétgyűjtő nem bántja. A compaction fázisban történik a lyukak feltöltése a ritkább területen. Tehát ennek a szemétgyűjtésnek is a végén a memóriaterület eleje összefüggő, teli, míg a vége üres.&lt;/p&gt;

&lt;p&gt;Ez a szemétygyűjtő akkor lehet megfelelő, ha a szemétgyűjtő által okozott állási idő igenis fájdalmas, így ezt kell csökkenteni, párhuzamossággal. A &lt;code&gt;-XX:+UseParallelOldGC&lt;/code&gt; parancssori kapcsolóval lehet bekapcsolni.&lt;/p&gt;

&lt;h4&gt;Concurrent Mark-Sweep (CMS) Collector&lt;/h4&gt;

&lt;p&gt;A CMS collector-t olyan alkalmazások számára fejlesztették ki, ahol igen fontos a válaszidő, pl. webes alkalmazásoknál. Mivel a young generation szemétgyűjtése annak kis méretéből adódóan igen gyors, az ugyanúgy működik, mint a Parallel/Throughput Collector esetében. A változás itt is az old generation szemétgyűjtésében van. A szemétgyűjtés itt négy fázisból áll: initial mark, concurrent marking phase/pre-cleaning, remarking, concurrent sweeping. Az első, initial mark fázisban a szemétgyűjtő megjelöli az alkalmazásból közvetlenül elérhető objektumokat. Ekkor stop the world van, azaz az alkalmazás szálai leállnak. Majd a concurrent marking phase fázisban az alkalmazás futásával egyidőben (és ettől konkurens) bejelöli a tranzitíven elérhető objektumokat. A remark fázisban ismét stop the world, a szemétgyűjtő bejárja az előző fázis közben módosult objektumokat, ezzel véglegesíti az élő objektumok bejelölését. Ez már több szálon történik. A concurrent sweep fázis eltávolítja a szemetet. Látható, hogy egyrészt több munkával jár, másrészt lehetnek olyan nem használt objektumok, amik nem takarodnak ki az első szemétgyűjtéskor (ez az un. floating garbage). Ez az ára a rövidebb válaszidőnek. Látható, hogy a CMS collector un. non-compacting szemétgyűjtő, azaz a memóriaterületen nem egybefüggően lesznek az objektumok, hanem lyukak lesznek közöttük. Ez egyrészt megnehezíti a kezelést, hiszen nem egy pointer-t kell nyilvántartani, hanem egy listában kell nyilvántartani a szabad területeket. Másrészt fregmentálódáshoz is vezet, azaz nem egyszerű betenni sem egy újonnan példányosított objektumot. A többi szemétgyűjtővel ellentétben a CMS collector nem akkor fut le, mikor betelik a memóriaterület, hanem hamarabb, hogy még képes legyen lefutni. Ha ez nem sikerül, akkor mindenképpen a jól ismert mark-sweep-compact algoritmus fut le, mely az előző szemétgyűjtőknél is.&lt;/p&gt;

&lt;p&gt;A CMS collector jól alkalmazható ott, ahol fontos a gyors válaszidő, és több processzor tud a szemétgyűjtő munkájában részt venni, valamint viszonylag sok hosszúéletű objektum van. Ilyenek tipikusan a többprocesszoros gépeken futó webes alkalmazások. A &lt;code&gt;-XX:+UseConcMarkSweepGC&lt;/code&gt; parancssori kapcsolóval lehet bekapcsolni.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-11k03z2nctk/Tv0RpKPz9-I/AAAAAAAAHsY/cIXDUtKZI-4/s1600/serial_cms.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 202px;" src="http://3.bp.blogspot.com/-11k03z2nctk/Tv0RpKPz9-I/AAAAAAAAHsY/cIXDUtKZI-4/s320/serial_cms.png" border="0" alt="Serial és CMS collector összehasonlítása" id="BLOGGER_PHOTO_ID_5691724902889158626" /&gt;&lt;/a&gt;

&lt;p&gt;Összefoglalva a következőket lehet megállapítani, a szemétgyűjtőket a következő tulajdonságok alapján lehet vizsgálni:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;A serial szemétgyűjtés jó egy processzoros gépen, de a parallel szemétgyűjtés, amennyiben több processzor tud részt venni, rövidebb ideig tarthat, de több erőforrás szükséges hozzá.&lt;/li&gt;
 &lt;li&gt;A stop the world megközelítés biztosítja, hogy nem módosul a stack/heap, de cserébe leállással jár. A concurrent szemétgyűjtés az alkalmazás mellett fut, így több processzor szükséges, és több erőforrás is szükséges hozzá. Nincs teljesen concurrent szemétgyűjtő, kizárólag olyan, melynek valamely fázisa concurrent.&lt;/li&gt;
 &lt;li&gt;A compacting lassabb ugyan, mert objektumokat kell másolgatni, de egy pointer-rel elintézhető a szabad hely nyilvántartása. Non compacting esetben az adminisztráció is bonyolultabb, valamint töredezettség léphet fel.&lt;/li&gt;
&lt;/ul&gt; 

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-Qgi9Ta1Z2UU/Tv0TcIRlNKI/AAAAAAAAHsw/VKq_a23Nsj4/s1600/tablazat.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 130px;" src="http://1.bp.blogspot.com/-Qgi9Ta1Z2UU/Tv0TcIRlNKI/AAAAAAAAHsw/VKq_a23Nsj4/s400/tablazat.png" border="0" alt="Szemétgyűjtő algoritmusok összehasonlítása" id="BLOGGER_PHOTO_ID_5691724902889158626" /&gt;&lt;/a&gt;

&lt;p&gt;&lt;a href="http://blogs.oracle.com/jonthecollector/entry/our_collectors"&gt;Our Collectors&lt;/a&gt; címmel egy elég jó cikket és grafikát találunk a young és old generation szemétgyűjtő algoritmusainak, valamint parancssori paramétereinek kapcsolatáról.&lt;/p&gt;

&lt;p&gt;A Java 6 update 20-ban megjelent, és a 7-es sorozatban is megtalálható a Garbage First Collector, vagy röviden G1. Ez teljesen más megközelítést használ, viszont kevesebb tapasztalat van vele, ezért erről sem írni nem tudok, és mindenkit óvatosságra intenék ezzel kapcsolatban.&lt;/p&gt;

&lt;p&gt;Mivel nézzük, hogy hogyan működik a szemétgyűjtő? Az első, legegyszerűbb eszköz a JVM &lt;code&gt;-verbose:gc&lt;/code&gt; vagy &lt;code&gt;-XX:PrintGCDetails&lt;/code&gt; paraméterrel való futtatása. Nézzünk szét a JVM developer paraméterei között, rengeteg statisztikát ki lehet nyerni. A másik megoldás, ha a fentebb említett VisualVM Visual GC plugin-ját használjuk.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-GjlUS3xFW4s/Tv2aJr_SwWI/AAAAAAAAHs8/8TuO1vZaPcc/s1600/gc_details.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://4.bp.blogspot.com/-GjlUS3xFW4s/Tv2aJr_SwWI/AAAAAAAAHs8/8TuO1vZaPcc/s320/gc_details.png" border="0" alt="A JVM -XX:PrintGCDetails paraméterrel indítva" id="BLOGGER_PHOTO_ID_5691874995283870050" /&gt;&lt;/a&gt;

&lt;p&gt;Nem szorosan ide tartozik, de nagyon hasznos lehet a JVM un. Fatal Error Handling tulajdonsága. Amennyiben olyan hiba keletkezik, melyet nem tudunk kódból lekezelni, pl. OutOfMemoryError, megadhatunk a JVM-nek olyan kapcsolókat, melyeket használva mégis előrébb vagyunk. Pl. &lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=&amp;lt;path&gt;&lt;/code&gt; paraméterekkel megmondhatjuk, hogy a JVM készítsen egy heap dump-ot. Amit akár VisualVM-be is betölthetünk, és grafikusan elemezhetünk. A &lt;code&gt;-XX:OnOutOfMemoryError=&amp;lt;parancs(ok)&gt;&lt;/code&gt; paraméterekkel operációsrendszerbeli parancsokat adhatunk meg, melyeket lefuttat a JVM hiba esetén (bármilyen script-et hívhatunk itt). A &lt;code&gt;-XX:+ShowMessageBoxOnError&lt;/code&gt; parancssori kapcsoló hatására feldob egy dialógusablakot. Ez azért jó, mert ekkor még nem áll le a JVM, így akár egy profiler-rel is neki tudunk menni.&lt;/p&gt;

&lt;p&gt;Ez alapján el lehet kezdeni a GC tuning-olását, mely egy külön tudomány. Jó kiindulási alap lehet az Oracle &lt;a href="http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html"&gt;Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning&lt;/a&gt; cikke.</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/8365011667058151286/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/12/java-memoriakezeles-szemetgyujto.html#comment-form" title="14 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/8365011667058151286?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/8365011667058151286?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/12/java-memoriakezeles-szemetgyujto.html" title="Java memóriakezelés, szemétgyűjtő algoritmusok" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-Hgkvfe-YRjA/Tv0QOVMrD1I/AAAAAAAAHrc/M0vJrloT35I/s72-c/visualgc_gifanim.gif" height="72" width="72" /><thr:total>14</thr:total></entry><entry gd:etag="W/&quot;CkQAQnY_eCp7ImA9WhRWEUs.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-43432132572840305</id><published>2011-12-13T00:45:00.005+01:00</published><updated>2011-12-29T13:05:43.840+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-29T13:05:43.840+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="instrumentation" /><category scheme="http://www.blogger.com/atom/ns#" term="Java SE" /><category scheme="http://www.blogger.com/atom/ns#" term="JMX" /><title>Instrumentation Javassist-tal</title><content type="html">&lt;p&gt;Technológiák: Javassist 3.15&lt;/p&gt;

&lt;p&gt;Belefutottam egy olyan &lt;a href="http://stackoverflow.com/questions/7096121/profile-entire-java-program-execution-in-visualvm"&gt;problémába&lt;/a&gt;, hogy egy alkalmazást szeretnék monitorozni VisualVM-mel (régebben már írtam &lt;a href="http://jtechlog.blogspot.com/2011/04/visualvm-glassfish-monitorozas.html"&gt;róla&lt;/a&gt;), azonban az alkalmazás számomra szignifikáns része már lefut, mielőtt hozzá tudnák csatlakozni a virtuális géphez. A VisualVM egy monitoring és menedzsment eszköz, nagyon mélyen lehet a virtuális gép működését megfigyelni, és a JDK része. A &lt;code&gt;-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y&lt;/code&gt; parancssori kapcsoló használata nem segít, ugyanis ebben az esetben a megállt alkalmazást csak olyan profiler képes továbblökni, mely beszéli a Java Debug Wire Protocol (JDWP) protokollt, a VisualVM viszont nem ilyen. (Míg a Eclipse TPTP vagy a Netbeans Profiler igen. Más kérdés ugyan, hogy a VisualVM is tartalmaz profiler-t, ráadásul ugyanaz, ami a NetBeans-ben is van, ez utóbbi csak annyival több, hogy a forráskódhoz tud pozícionálni.)&lt;/p&gt;

&lt;p&gt;A problémára több megoldási javaslatot is lehet kapni a neten, pl. más profiler (előbb említetteken kívül még sok van, pl. a JDK részeként szállított parancssori HPROF, vagy a kereskedelmi YourKit vagy JProfiler), debug módban indítás IDE-ből, valamint az alkalmazásban várakozás elhelyezése (sleep, Console input).&lt;/p&gt;

&lt;p&gt;Gondoltam, ez egy megfelelő alkalom az instrumentation és a Javassist kipróbálására. Így készítettem egy egyszerű példaprogramot, mely elérhető a &lt;a href="https://github.com/vicziani/jtechlog-wait4signal"&gt;GitHub&lt;/a&gt;-on. A program egy Java agent, melynek segítségével egy Java alkalmazás adott szálának futása a megadott metódusnál felfüggeszthető, és vagy konzolon bevitt, vagy JMX-en feladott jelre vár. Mindezt az alkalmazás forráskódjának módosítása nélkül.&lt;/p&gt;

&lt;p&gt;Maven-nel build-elhető, és a letöltést követően a 'mvn package assembly:single' parancs kiadásával a target könyvtárban létrejön egy jtechlog-wait4signal-1.0-SNAPSHOT-bin.zip és egy
jtechlog-wait4signal-1.0-SNAPSHOT-tar.gz állomány. Valamelyik lib könyvtárában lévő két jar fájlt kell felhasználni.&lt;/p&gt;

&lt;p&gt;A következő parancs kiadásával lehet az agent-et aktiválni:&lt;/p&gt;

&lt;pre&gt;java -javaagent:jtechlog-wait4signal-1.0-SNAPSHOT.jar=entryPoint=java2d.Java2Demo.main -jar Java2Demo.jar&lt;/pre&gt;

&lt;p&gt;Ekkor a konzolon vár egy Enter lenyomásáig, vagy 5 másodperc múlva mindenképp lefuttatja az alkalmazást.&lt;/p&gt;

&lt;p&gt;A következő parancs kiadásával lehet JMX-en értesítést aktiválni:&lt;/p&gt;

&lt;pre&gt;java -javaagent:jtechlog-wait4signal-1.0-SNAPSHOT.jar=entryPoint=java2d.Java2Demo.main,mode=JMX,timeout=30 -jar Java2Demo.jar&lt;/pre&gt;

&lt;p&gt;Ekkor a &lt;code&gt;jtechlog/SignalMBean signal()&lt;/code&gt; operációjával lehet a futtatást továbbengedni, vagy 30
másodperc múltán timeout.&lt;/p&gt;

&lt;p&gt;Régebben &lt;a href="http://jtechlog.blogspot.com/2009/05/hibernate-eclipselink-atallas.html"&gt;már írtam arról&lt;/a&gt;, hogy az instrumentációt, azaz a bytecode módosítását futásidőben, osztálybetöltéskor a &lt;a href="http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html"&gt;java.lang.instrument&lt;/a&gt; csomag felhasználásával lehet megvalósítani. Az agent fő osztálya a &lt;code&gt;jtechlog.wait4signal.Wait4SignalMain&lt;/code&gt; osztály, melynek &lt;code&gt;premain&lt;/code&gt; metódusa fut le a saját alkalmazásunk main metódusa előtt. Ahhoz, hogy a -javaagent megadásakor ehhez az osztályhoz kerüljön a vezérlés, a anifest.mf fájlban a Agent-Class bejegyzésnek rá kell hivatkoznia.&lt;/p&gt;

&lt;pre class="brush: java"&gt;public static void premain(String agentArgs, Instrumentation inst) {
 System.out.println("Initializing Wait4Signal Java agent.");
 Wait4SignalMain wait4SignalMain = new Wait4SignalMain();
 wait4SignalMain.doInstrumentation(agentArgs, inst);
}
&lt;/pre&gt;

&lt;p&gt;A &lt;code&gt;doInstrumentation&lt;/code&gt; metódus feldolgozza a parancssori paramétereket (a JAR neve és egy egyenlőségjel után megadott String), ezek konvenció szerint név és érték párok, köztük egyenlőségjel, vesszővel elválasztva. Lehetséges paraméterek: entryPoint (kötelező megadni, osztály és metódus neve, mely előtt meg kell állítani a program futását), mode (ha nincs megadva CONSOLE mód, azaz konzolon vár Enter billenytű megnyomását, vagy JMX), és timeout (másodpercben, alapértelmezett értéke 5). Majd a következő utasítás megadásával egy új &lt;code&gt;ClassFileTransformer&lt;/code&gt; implementációt regisztrál:&lt;/p&gt;

&lt;pre class="brush: java"&gt;inst.addTransformer(new WaitTransformer(entryPoint, waiting));
&lt;/pre&gt;

&lt;p&gt;Egy ötlet volt az is, hogy a &lt;code&gt;premain&lt;/code&gt; metódusban állítom meg a program futását, azonban ez nem volt megfelelő, hiszen a JVM ilyenkor olyannyira nem inicializálta magát, hogy a VisualVM sem tudott hozzá kapcsolódni életciklusának ezen pontján.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;WaitTransformer&lt;/code&gt; a &lt;code&gt;transform&lt;/code&gt; metódust definiálja felül, és vizsgálja, hogy az osztály neve megegyezik-e a parancssori kapcsolóként megadottal.&lt;/p&gt;

&lt;pre class="brush: java"&gt;public byte[] transform(ClassLoader loader, String className, 
 Class&amp;lt;?&amp;gt; classBeingRedefined, ProtectionDomain protectionDomain, 
 byte[] classfileBuffer) throws IllegalClassFormatException
&lt;/pre&gt;

&lt;p&gt;A transform metódus számunkra érdekes paraméterei az osztály osztálybetöltője (null, ha bootstrap osztálybetöltő), az osztály neve (vigyázat, pontok helyett perjelekkel), valamint az osztály bytecode-jának byte tömbjét. Ezt szabadon módosíthatjuk, és ezt kell visszaadni a metódus visszatérési értékeként. Vigyázat, az ebből a metódusból kilépő kivételeket a JVM elnyeli.&lt;/p&gt;

&lt;p&gt;Persze nem kell a byte tömböt közvetlenül módosítani, itt jöhet segítségünkre a &lt;a href="http://www.javassist.org/"&gt;Javassist&lt;/a&gt; (Java Programming Assistant), mely egy Java bytecode futásidejű manipulálását megkönnyítő programkönyvtár. Két szintű API-t ad a kezünkbe. A forráskód szintű API segítségével Java utasításokat, mint String-eket szúrhatunk be, ezeket a Javassist on-the-fly fogja átfordítani bytecode-dá. Ekkor persze nem szükséges ismernünk a class fájl szerkezetét. Vagy manipulálhatjuk alacsonyabb szinten is, közvetlen a bytecode-ot. Ezen lehetőségek rendkívül alkalmassá teszik a Javassist-ot AOP keretrendszerek fejlesztésére. Remek &lt;a href="http://www.csg.is.titech.ac.jp/%7Echiba/javassist/tutorial/tutorial.html"&gt;tutorial&lt;/a&gt; is van hozzá.&lt;/p&gt;

&lt;p&gt;A következő részben a Javassist érdekesebb kódrészleteit emelem ki, melyek a bytecode-ot módosítják.&lt;/p&gt;

&lt;pre class="brush: java"&gt;
ClassPool pool = ClassPool.getDefault();
CtClass cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));

if (cl.isInterface() == false) {
 CtBehavior[] methods = cl.getDeclaredBehaviors();

 for (int i = 0; i &lt; methods.length; i++) {
  if (entryPoint.endsWith(methods[i].getName())) {
   ctBehavior.insertBefore(waiting.insertBeforeMethod());
  }
 }
 classfileBuffer = cl.toBytecode();
}
cl.detach();
&lt;/pre&gt;

&lt;p&gt;A fenti kódrészlet először lekér egy ClassPool-t, ez a Javassist-ban lévő osztályok tárolására szolgáló konténer. Ebbe definiál egy CtClass (compile-time class) példányt, mely az osztály absztrakt reprezentációja. Ennek forrása az instrumentálás során átadott byte tömb. Amennyiben ez egy interfész, lekéri ennek metódusait a &lt;code&gt;getDeclaredBehaviors()&lt;/code&gt; metódushívással. Ezeken végigiterál, és ha a metódus neve megfelelő, akkor beszúr kódrészletet az &lt;code&gt;insertBefore&lt;/code&gt; metódushívással. Ennek érdekessége, hogy egy String-et vár, tehát bármilyen Java forráskódot be lehet illeszteni, mintha csak a .java forrásfájlba tettük volna ezt.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;waiting.insertBeforeMethod()&lt;/code&gt; a mode parancssori kapcsoló függvényében más és más String-et ad vissza. Pl. CONSOLE mode esetén példányosít egy &lt;code&gt;ConsoleWaiting&lt;/code&gt; objektumot, majd beállítja a timeout property-jét, majd meghívja a &lt;code&gt;wait4signal()&lt;/code&gt; metódusát.&lt;/p&gt;

&lt;pre class="brush: java"&gt;public String insertBeforeMethod() {
 StringBuilder sb = new StringBuilder();
 sb.append("jtechlog.wait4signal.Waiting waiting = new jtechlog.wait4signal.ConsoleWaiting();");
 sb.append(String.format("waiting.setTimeout(%s);", timeout));
 sb.append("waiting.wait4signal();");
 return sb.toString();
}

&lt;/pre&gt;

&lt;p&gt;Érdekessége, hogy a wait4signal() metódus a &lt;code&gt;ConsoleInput&lt;/code&gt; és &lt;code&gt;ConsoleInputReadTask&lt;/code&gt; osztályokat használja a konzolról való beolvasásra, és a Java 5-ben megjelent ExecutorService-t használja a külön szálon való bekérésre. Erre azért van szükség, hogy itt is működjön a timeout (&lt;a href="http://www.javaspecialists.eu/archive/Issue153.html"&gt;The Java Specialists' Newsletter&lt;/a&gt; cikke alapján).&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;JmxWaiting&lt;/code&gt; osztály ezzel szemben egy BlockingQueue-t használ, és abba vár egy üzenetet. A &lt;code&gt;BlockingQueue.poll(int, TimeUnit)&lt;/code&gt; metódusával vár egy üzenetre, timeout esetén null a visszatérési értéke. A BlockingQueue a &lt;code&gt;SignalMBean&lt;/code&gt; MBean-nek is átadásra kerül. Amennyiben a felhasználó meghívja a &lt;code&gt;signal()&lt;/code&gt; operációját, egy üzenetet tesz a Queue-ba. A &lt;code&gt;JmxWaiting&lt;/code&gt; ekkor beszünteti a várakozást, és fut tovább. A JMX-ről egy &lt;a href="http://jtechlog.blogspot.com/2009/09/java-monitorozas-es-menedzsment.html"&gt;korábbi postban&lt;/a&gt; tettem említést.&lt;/p&gt;

&lt;p&gt;Az agent-nek szüksége van tehát a Javassist JAR fájlra is, ehhez a manifest.mf fájlba fel kell venni a Boot-Class-Path bejegyzésbe a JAR fájl nevét. Abszolút (perjel) nélkül adtam meg, így a jtechlog-wait4signal-1.0-SNAPSHOT.jar állománnyal egy könyvtárban fogja keresni (függetlenül a JVM indítási könyvtárától).&lt;/p&gt;

&lt;p&gt;Látható, hogy a JVM induláskor, az osztálybetöltés során a Java class fájlok manipulálása korántsem akkora varázslat, mint első látásra hinnénk. Több nyílt forráskódú alternatíva is létezik bytecode manipulálásra, többek között a &lt;a href="http://cglib.sourceforge.net/"&gt;cglib&lt;/a&gt;, &lt;a href="http://commons.apache.org/bcel/index.html"&gt;Apache Commons BCEL&lt;/a&gt;, &lt;a href="http://asm.ow2.org/"&gt;ASM&lt;/a&gt;.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/43432132572840305/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/12/instrumentation-javassist-tal.html#comment-form" title="2 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/43432132572840305?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/43432132572840305?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/12/instrumentation-javassist-tal.html" title="Instrumentation Javassist-tal" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CkQBSXk-fSp7ImA9WhNQEEs.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-912143685418710554</id><published>2011-11-28T01:06:00.001+01:00</published><updated>2012-11-16T11:05:58.755+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-16T11:05:58.755+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><category scheme="http://www.blogger.com/atom/ns#" term="DocBook" /><title>Szabad navigáció okozta problémák webes környezetben</title><content type="html">&lt;p&gt;Technológiák: Servlet 3.0/JSP 2.2, DocBook 4.5, Docbkx Tools, Docbkx Maven Plugin, Maven 3&lt;/p&gt;

&lt;p&gt;Legrégebb óta írt cikkem kerül most publikálásra, melynek címe "Szabad navigáció okozta problémák webes környezetben".&lt;/p&gt;

&lt;p&gt;Ez a cikk azon problémával foglalkozik, mely a legtöbb webes alkalmazás fejlesztésekor felmerül, ugyanis nem biztosítható az, hogy a felhasználó olyan sorrendben nézze meg az oldalakat, ahogy azt az alkalmazás fejlesztője eltervezi. Használhatja a Vissza és Tovább műveleteket is navigációra, valamint újratöltheti az oldalt a Frissítés művelettel. Ezen műveletek elérhetők a böngésző szokásos gombjai között, billentyűkombinációval, de jobb kattintásra felugró menüben is. Sokan megszokásból, esetleg türelmetlenség (, a lassú válaszidő) miatt duplán kattintanak egy adott hivatkozásra. A felhasználó kézzel is beírhat egy url-t, vagy a Kedvencek közül is választhat egyet, ami szintén hibás működéshez vezethet, ha erre nem készülünk fel, és bízunk, hogy csak a felületi elemeket (űrlap elemek – gomb, legördülő menü, stb., hivatkozások) fogja használni. A böngészők és tűzfalak gyorsítótár beállításai is megzavarhatják az előre tervezett munkafolyamatot. A probléma a webes technológia, a http(s) protokoll, valamint a böngészők adta lehetőségek miatt jelentkezik.&lt;/p&gt;

&lt;p&gt;A cikk egy jtechlog-repost példa projektre hivatkozik, mely &lt;a href="https://github.com/vicziani/jtechlog-repost"&gt;letölthető a GitHub-ról&lt;/a&gt;. Egyszerű webes alkalmazás, servlet 
controller és JSP view réteggel. Maven-nel build-elhető, és a letöltést követően a 'mvn jetty:run' paranccsal futtatható.&lt;/p&gt;

&lt;p&gt;Példaprogrammal, szekvencia diagramokkal és forráskódokkal szemlélteti a webes alkalmazásokban gyakran felmerülő problémákat, melyek a szabad navigációból erednek. Ha te is találkoztál, vagy írtál olyan alkalmazást, ahol problémát okozott, ha a felhasználó véletlenszerűen használta a Vissza/Előre gombokat, ha a többszöri kattintás felesleges terhelést okozott a szerveren, ha Frissít gomb megnyomásakor a böngésző hibaüzenetet dobott fel, akkor a cikk neked való. Nem csak a problémákat, de a rá adott szabványos megoldásokat is ismerteti, mint a Redirect After Post, vagy a Synchronizer Token. Olyan ide kapcsolódó témákat is érint, mint a hosszú, aszinkron folyamatok kezelése, vagy a problémák megoldása AJAX környezetben.&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;a href="http://vicziani.github.com/artifacts/repost.pdf"&gt;Szabad navigáció okozta problémák webes környezetben cikk letöltése&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A dokumentáció érdekessége, hogy &lt;a href="http://www.docbook.org/"&gt;DocBook-ban&lt;/a&gt; íródott, mely egy XML formátum könyvek, cikkek publikálására. Ugyanis meguntam a Word ezirányú képességeit, hogy hosszabb dokumentációnál elveszti a kontrollt, bizonyos dolgokat sokszor körülményes vele megcsinálni. Mivel az XML egy szöveges állomány, ilyen nem fordulhat elő a megfelelő tag-ek ismeretében. A DocBook XML állományból a Maven &lt;a href="http://docbkx-tools.sourceforge.net/"&gt;Docbkx Tools&lt;/a&gt; fordít PDF állományt. A háttérben először egy XSL-FO állomány generálódik le, majd azt fordítja az &lt;a href="http://xmlgraphics.apache.org/fop/"&gt;Apache FOP&lt;/a&gt; PDF-fé.&lt;/p&gt;

&lt;p&gt;A DocBook forrást tartalmazó, és a PDF-fé build-elést elvégző Maven projekt szintén &lt;a href="https://github.com/vicziani/jtechlog-repost-doc"&gt;elérhető a GitHub-on&lt;/a&gt; jtechlog-repost-doc néven.&lt;/p&gt;

&lt;p&gt;Ezzel kapcsolatban csak egy probléma merült fel, méghozzá az ékezetes karakterek problémája. Egy PDF megjelenítő ugyanis alapban 14 betűtípust ismer (&lt;a href="http://en.wikipedia.org/wiki/Portable_Document_Format"&gt;"base fourteen fonts"&lt;/a&gt;), és ebben nincsenek ékezetes karakterek. Ezért, ha ilyeneket akarunk, akkor azokat be kell építenünk (embedded font) a PDF állományba. Az Apache FOP ezt azonban bizonyos verziónál csak úgy tudja megtenni, ha a beépítendő betűtípus mellett egy metrics állomány is szerepel, mely egy XML és leírja a betűtípus tulajdonságait. Szerencsére a betűtípusból ilyent generálni is lehet a következő paranccsal: &lt;code&gt;java org.apache.fop.fonts.apps.TTFReader -fn sanf-serif micross.ttf micross-fcm.xml&lt;/code&gt;, persze a megfelelő FOP CLASSPATH beállításával. Szerencsére ilyent nem kellett Maven-ből hívni, ugyanis a Docbkx Tools tartalmaz eszközt erre is, csak a következő részeket kellett a pom.xml-be beilleszteni (fontos a false ansi property).&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;com.agilejava.docbkx&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;docbkx-fop-support&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;2.0.13&amp;lt;/version&amp;gt;
 &amp;lt;executions&amp;gt;
  &amp;lt;execution&amp;gt;
   &amp;lt;phase&amp;gt;generate-resources&amp;lt;/phase&amp;gt;
   &amp;lt;goals&amp;gt;
    &amp;lt;goal&amp;gt;generate&amp;lt;/goal&amp;gt;
   &amp;lt;/goals&amp;gt;
   &amp;lt;configuration&amp;gt;
    &amp;lt;ansi&amp;gt;false&amp;lt;/ansi&amp;gt;
   &amp;lt;/configuration&amp;gt;
  &amp;lt;/execution&amp;gt;
 &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;

&amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;com.agilejava.docbkx&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;docbkx-maven-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;2.0.13&amp;lt;/version&amp;gt;
 
 &amp;lt;!-- ... --&amp;gt;
 
 &amp;lt;configuration&amp;gt;
  &amp;lt;bodyFontFamily&amp;gt;TimesNewRoman&amp;lt;/bodyFontFamily&amp;gt;
  &amp;lt;monospaceFontFamily&amp;gt;Courier&amp;lt;/monospaceFontFamily&amp;gt;
  &amp;lt;titleFontFamily&amp;gt;ArialBold&amp;lt;/titleFontFamily&amp;gt;
  &amp;lt;fonts&amp;gt;
   &amp;lt;font&amp;gt;
    &amp;lt;name&amp;gt;Arial&amp;lt;/name&amp;gt;
    &amp;lt;style&amp;gt;normal&amp;lt;/style&amp;gt;
    &amp;lt;weight&amp;gt;normal&amp;lt;/weight&amp;gt;
    &amp;lt;embedFile&amp;gt;${basedir}/src/fonts/Arial.ttf&amp;lt;/embedFile&amp;gt;
    &amp;lt;metricsFile&amp;gt;${basedir}/target/fonts/Arial-metrics.xml&amp;lt;/metricsFile&amp;gt;
   &amp;lt;/font&amp;gt;
   &amp;lt;!-- ... --&amp;gt;
&lt;/pre&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/912143685418710554/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/11/szabad-navigacio-okozta-problemak-webes.html#comment-form" title="2 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/912143685418710554?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/912143685418710554?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/11/szabad-navigacio-okozta-problemak-webes.html" title="Szabad navigáció okozta problémák webes környezetben" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;A0UARHc7cCp7ImA9WhRSFkg.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-6776798504599496909</id><published>2011-11-19T00:05:00.005+01:00</published><updated>2011-11-19T00:34:05.908+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-19T00:34:05.908+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>GitHub</title><content type="html">&lt;p&gt;Mivel ki kellett próbálnom valamit a Spring Security-val, frissítettem az erről szóló &lt;a href="http://jtechlog.blogspot.com/2010/01/spring-security.html"&gt;postot&lt;/a&gt;. Ennek keretében csatlakoztam a &lt;a href="https://github.com/vicziani"&gt;GitHub-hoz&lt;/a&gt;, így ezentúl ott közlöm a postokhoz tartozó példa alkalmazásokat, forráskódokat, érdemes figyelni. Az említett posthoz is megtalálható az első &lt;a href="https://github.com/vicziani/jtechlog-spring-security"&gt;példaprogram&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A példaprogramokban angol megnevezéseket használok, de a megjegyzések, dokumentáció, valamint a felületen megjelenő szövegek (pl. jsp-ben) magyarok lesznek.&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/6776798504599496909/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/11/github.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6776798504599496909?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/6776798504599496909?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/11/github.html" title="GitHub" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEEER38yeSp7ImA9WhRSE0Q.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-9075776410959180550</id><published>2011-09-27T01:15:00.007+02:00</published><updated>2011-11-15T22:30:06.191+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-15T22:30:06.191+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><title>Maven legjobb gyakorlatok</title><content type="html">&lt;p&gt;Technológiák: Maven 3.0.3&lt;/p&gt;

&lt;p&gt;Maven-nel foglalkozó sorozatom részét azzal zárnám, hogy milyen legjobb gyakorlatokat érdemes betartani. Lehet, hogy bizonyos dolgokat ismételni fogok a &lt;a href="http://jtechlog.blogspot.com/2010/04/maven-kezdolepesek.html"&gt;Maven kezdőlépések&lt;/a&gt; post-omból, de álljanak itt összegyűjtve. Lehet, hogy bizonyos szabályok túl szigorúak, azért van lehetőség egy-két helyen lazábbra engedni.&lt;/p&gt;

&lt;h4&gt;Projekt granularitás&lt;/h4&gt;

&lt;p&gt;Talán a legnehezebb témakör, azaz mennyi projektet hozzunk létre egy bonyolultabb rendszer esetén, és ezek milyen függőségekben legyenek egymással. Az egy projekt csak kis alkalmazásoknál, 3rd party library-knél szokott elegendő lenni, kicsit is bonyolultabb alkalmazások esetén szükség van több projektre. Egy projekt esetén a fejlesztés nehézkesebb, hiszen nem tudjuk kisebb részekben kezelni, mindig mindent le kell fordítani, nagy csomagot előállítani, stb. Maven egy kitűnő támpontot ad, ugyanis az alapfilozófiája az, hogy amennyi projekt, annyi artifact, tehát annyi jar, war, ear, zip, stb.&lt;/p&gt;

&lt;p&gt;Másik kérdés, hogy ezek a projektek mennyire mozognak együtt, vagy külön. Együtt történik a release, vagy gyakran előfordul, hogy az alkalmazás csak egy kis részlete kerül mindig javításra, kiadásra? Van-e olyan rész, mely önmagában is megállja a helyét, pl. egy külön grafikai komponens, melyet akár más projektekben is fel lehet használni. Élhetnek-e külön életet, külön verziószámozással?&lt;/p&gt;

&lt;p&gt;Ezt egyedül a gyakorlat tudja megmondani. Láttam olyan rendszert, ami teljesen különálló modulokból állt, és szépen, külön volt fejleszthető. Egy másik projekt esetében bármit kellett módosítani, mindig hozzá kellett nyúlni 3-4 modulhoz is. Sőt, olyan is megeshet, hogy az elején még minden módosul, míg a hibajavításkor, tovább fejesztéskor már elég csak egy-egy modult bolygatni.&lt;/p&gt;

&lt;p&gt;Néhány támpont azonban. Jó gyakorlat az interfész és implementáció különválasztása (, ez pl. interfészek - web szolgáltatások - esetén nagyon gyakori, és a technológia is megköveteli, mert az interfész osztályoknak mindkét oldalon meg kell lennie). Használjunk szervezet és projekt szintű szülő projekteket. Hasznosak lehetnek a prototípus projektek. Gyakran használt utility osztályokat emeljük ki library-ként. Közös erőforrásokat emeljük ki külön projektbe. Integrációs teszt eseteket emeljük ki külön projektbe. Függőségeket is ki lehet emelni külön projektbe. Ezekről még mindről lesz később szó a post-ban.&lt;/p&gt;

&lt;p&gt;Fontos, hogy a projekt granularitása összefügg az issue tracker-ünkben felvett projektekkel is. Hiszen ha a projektek külön életet élnek, külön verziószámokkal rendelkeznek, akkor érdemes ezeket az issue tracker-ben is külön követni. Ha a projektek általában együtt mozognak, és egyszerre kell javítani, kiadni, követni őket, akkor mind a release, mind a verziókezelés, mind az issue tracking folyamán jelentős pluszmunkát veszünk magunkra.&lt;/p&gt;

&lt;h4&gt;pom.xml formázása&lt;/h4&gt;

&lt;p&gt;Mutasd a pom.xml-ed, megmondom, milyen a projekted! A pom.xml-eket is olyan tisztán kell tartani, mint a forráskódot. Ez egy XML állomány, ahol a tag-ek sorrendje nem kötött, azonban mégis javaslom, hogy a projekten belül az összes modulban ugyanazt a sorrendet használjuk. A függőségeknél is ajánlott egy sorrendet meghatározni, pl. előbb a belső függőségek, majd a nem publikus repository-kból nyert függőségek, majd scope-onként a compile, provided, test scope-ú függőségek. Így ahhoz szokik a szemünk, automatikusan tudjuk, hogy mit hol kell keresni, azonnal láthatjuk, hogy valami van-e definiálva, vagy hiányzik. A forráskódhoz hasonlóan ne használjunk felesleges comment-eket, de amit célszerű, azt jegyezzük fel (pl. függőségekkel kapcsolatos tudnivalók). Ne használjunk csupa nagybetűs comment-eket, ahogy sormintákat se.&lt;/p&gt;

&lt;h4&gt;DRY, KISS&lt;/h4&gt;

&lt;p&gt;Forrásokhoz megfelelően próbáljuk a pom.xml-ekben az ismétlődéseket kerülni (Don't Repeat Yourself). Ez megoldható öröklődéssel, azaz a szülőben definiált a gyermek örökli. Használjunk property-ket, akár beépítetteket, akár saját magunk által definiáltakat. Legyenek a pom.xml-ek egyszerűek (Keep it short and simple). Persze ez főleg akkor lehetséges, ha a projektünk alkalmazkodik a konvenciókhoz, és nem használ semmiféle egzotikus megoldást, ami követendő. Használjunk szabványos megoldásokat, a Maven beépített eszközeit és plugin-jeit. (Pl. verziószám megjelenítését &lt;a href="http://jtechlog.blogspot.com/2011/09/verzioszam-megjelenitese-az.html"&gt;resource filtering&lt;/a&gt; segítségével.) Használjuk a default értékeket, ahelyett, hogy konfigurálnánk (convention over configuration). Pl. standard könyvtárstruktúra.&lt;/p&gt;

&lt;h4&gt;Felelős&lt;/h4&gt;

&lt;p&gt;Legyen a pom.xml-eknek egy felelőse. Lehetőleg a vezető programozó, architect. A pom.xml-be felvett változások általában az architektúra, függőségek módosítását jelzik. Sem a modulok között, sem a 3rd party library-ra nem jó, ha bekerül egy új függőség, a felelős tudta nélkül. Igenis figyelni kell, hogy ne kerüljön bevezetésre egy sokadik XML parser. Remélhetőleg a pom.xml a projekt életciklusa során keveset változik.&lt;/p&gt;

&lt;h4&gt;Konvenciók&lt;/h4&gt;

&lt;p&gt;Ha már a Maven alapelve a konvenciók használata, próbáljunk meg mi is alkalmazkodni ehhez több szinten is, vezessünk be projekt konvenciókat. Ilyen pl. a projektek elnevezési konvenciója (javasolt kisbetűkkel, szavakat kötőjellel elválasztva írni), verziószám konvenciók, stb.&lt;/p&gt;

&lt;h4&gt;Build reprodukálhatóság&lt;/h4&gt;

&lt;p&gt;Lehetőleg törekedjünk arra, hogy nem előkészített környezetben, notebook-on, otthon is fusson le a build. Ne legyen szükség külső függőségekre, speciális könyvtárakra, adatbázis szerverre, stb. Lehetőleg csak a céges repository manager elérésével bárhol le tudjuk futtatni a build-et. A Sonatype könyv organizational portability-nek hívja azt, amikor egy cég belső hálóján lévő bármilyen gépen azonnal le tudjuk futtatni a build-et.&lt;/p&gt;

&lt;p&gt;Olvastam olyan ötletről is, hogy a Maven-t se kelljen egyénileg feltelepíteni, és a repository se foglalja mindenki gépén a helyet, egy megosztott meghajtóra lehet ezeket tenni, és mindenki onnan használhatja. A repository helye alapértelmezésben a home könyvtárunk alatt a /.m2/repository könyvtár. Ez sok esetben nem megfelelő, pl. ékezet, space van benne, vagy pl. szerverrel szinkronizált, központilag mentett, vagy egyszerűen nem szeretnénk a rendszer partíciónkon tárolni ezeket. A lokális repository új helyét a settings.xml-ben a localRepository tag-ek között adhatjuk meg.&lt;/p&gt;

&lt;p&gt;Ügyeljünk arra, hogy lehetőleg környezetenként (fejlesztői/teszt/éles) ugyanazokat az artifact-okat használjuk. Minden környezet függő információt az alkalmazáson kívül tároljuk, konfigurációs állományokban, JNDI-ben, adatbázisban. Így ugyanazt az állományt telepíthetjük minden környezetbe.&lt;/p&gt;

&lt;h4&gt;Repository manager és CI&lt;/h4&gt;

&lt;p&gt;Mindig használjunk repository manager-t. Egyrészt proxy a publikus repository-k felé, másrészt a saját artifact-jainkat is tartalmazza, ami nélkülözhetetlen több modulból álló projektek esetén. Ide tölthetjük fel az egyéb forrásból származó 3rd party jar-okat is.&lt;/p&gt;

&lt;p&gt;Bár nem ide tartozik szorosan, használjunk Continuous Integration eszközt is, mely egyrészt segít az integráció idejének csökkentésében azáltal, hogy gyakori időközönként build-el, és lefuttatja a teszt eseteket, így a problémákról mielőbb értesítést kapunk, nem csak akkor mikor mi is elvégeznénk az integrációt. Valamint különösen alkalmas arra, hogy ellenőrizzük, hogy nem csak egy beállított környezetben fut a projekt, egy fejlesztői gépen, hanem egy független build szerveren is.&lt;/p&gt;

&lt;h4&gt;Magas szintű pom.xml-ek&lt;/h4&gt;

&lt;p&gt;Bizonyos konfigurációkat szervezet szinten (corporate), vagy projekt szinten definiáljuk egy szülő pom.xml-ben. A gyermek projektek ebből öröklik a beállítások, melyek leíró információk pl. a szervezettel, projekttel, fejlesztőkkel kapcsolatban. Tartalmazhatja a distributionManagement szekciót, mely a repository manager elérhetőségét írja le (ne a konkrét projekteknél definiáljuk). Valamint tartalmazhatja a plugin konfigurációkat, azok verziószámát (lásd később, a "Függőségek" fejezetben).&lt;/p&gt;

&lt;h4&gt;Függőségek&lt;/h4&gt;

&lt;p&gt;Mindig tartsuk rendben a függőségeinket. Lehetőleg publikus repository-ban található 3rd party library-ből építkezzünk (, ebben segíthet a &lt;a href="http://mojo.codehaus.org/versions-maven-plugin/"&gt;Version Maven Plugin&lt;/a&gt;). Amennyiben van nem ilyen is, tüntessük fel annak a forrását, amennyiben van forráskódjának, dokumentációjának elérhetőségét. Vigyázzunk, ugyanannak a library-nak ne szerepeljenek különböző verziója függőségben. Ez akkor lehet, ha pl. egy artifact-et egyik verzióról a másikra át is neveztek, vagy pl. groupId-t váltottak. Figyeljünk a library-k megfelelő scope-jára. Lehetnek olyan jar-ok, melyek csak teszteléskor kellenek (test), illetve olyanok, melyeket nem kell az artifact-unkba csomagolni, az alkalmazásszerver biztosítja ezeket (provided). A moduljaink között ne legyen körkörös hivatkozás. A függőségek definiálásánál ne használjunk intervallumokat, adjuk meg a pontos verziószámokat. Amennyiben egy függőséghez több artifact is tartozik, pl. Hibernate, Spring sok modulból áll, akkor javasolt a verziószámot egy külön property-be kiemelni, és az összes modulban arra hivatkozni (pl. ${spring.version}).&lt;/p&gt;

&lt;p&gt;A függőségeinket tartsuk karban. Ne engedjük őket elburjánzani (lsd. "Felelős" fejezet). Futtassuk a dependency:analyze goal-t, feltárva ezzel a deklarált, de nem használt függőségeket (töröljük), valamint a használt, de nem deklarált függőségeket. Ez utóbbi akkor jelentkezhet, ha egy függőségre csak tranzitív függőség van, és mégis használjuk az osztályait. Ekkor javítsuk direkt függőségre.&lt;/p&gt;

&lt;p&gt;Plugin-ek esetén is mindig deklaráljuk a verziószámot, szülő projekt létezése esetén annak pluginManagement szekciójában, hiszen az öröklődik, ahogy egy régebbi &lt;a href="http://jtechlog.blogspot.com/2011/08/maven-plugin-ek-verzioszama.html"&gt;post-ban&lt;/a&gt; írtam.&lt;/p&gt;

&lt;p&gt;Amennyiben ugyanazt a függőséget több modul is használja, érdemes a szülő projektben felsorolni a függőségek verziószámát, és exclude tag-eket a dependencyManagement szekcióban, melyet a gyermek projektek örökölnek, így azokban elegendő csak a groupId-t és artifactId-t deklarálni.&lt;/p&gt;

&lt;p&gt;Amikor egy problémát meg akarunk oldani, és van egy bevált receptünk, és erre több 3rd party library-t is mozgósítunk, és mindig ugyanazokat, akkor szervezzük ki a függőségeket egy külön projektbe (dependency group), így elég erre az egyre függőséget definiálni, ami tranzitíven berántja a többi függőséget is. Ez ellentmondhat annak a szabálynak, hogy amit közvetlenül használunk, azt mindig direkt függőségben deklaráljuk. Ez utóbbit tartsuk be inkább.&lt;/p&gt;

&lt;p&gt;Nem csak Java osztályokat, hanem közösen használt erőforrásokat, pl. képeket, stíluslapokat, stb. is kiszervezhetünk külön projektbe. Vagy akár plugin konfigurációkat is, pl. checkstyle, pmd konfigurációkat is, ha különböző projekteken ugyanúgy akarjuk ezeket használni. A Maven dependency pluginnel sok csodát meg lehet csinálni.&lt;/p&gt;

&lt;h4&gt;Prototípus&lt;/h4&gt;

&lt;p&gt;Kicsit furcsa lehet, hogy a projektek közötti szülő-gyermek kapcsolat, és a modul-almodul kapcsolat két külön fogalom. A szülő-gyermek kapcsolat estén a gyermekben definiáljuk a szülőt, a parent tag-ek között. A gyermek ekkor örökölni fogja a szülő beállításait (lsd. még effective pom). A szülő nem tud a gyermek projektjeiről. Míg egy modul a modules tag-ek között felsorolhatja az almoduljait. Ez által megeshet az a furcsa eset is, hogy egy almodult olyan modul tartalmaz, mely az almodulnak nem szülő projektje. Nézzünk erre egy példát. Van több projektünk, mely nagyon hasonló egymáshoz, mind egy Java EE alkalmazás, melynek kimenete egy EAR. Mindegyik projekt több alprojektből áll, külön az EJB réteg, külön a web réteg, stb. Az ejb és web rétegek azonban nagyon hasonlítanak egymáshoz. Ezért, hogy a copy-paste-et elkerüljük, a közös dolgokat kiemeljük egy szülő projektbe, külön az ejb rétegeknek egy, külön a web rétegeknek egy. Ezeket a projekteket hívják prototípus projekteknek.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" rel="lightbox" href="http://4.bp.blogspot.com/-BgONRQSen2k/ToEIxcJT0yI/AAAAAAAAHdc/uwBC1WOIPdc/s1600/maven_prototype.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 140px;" src="http://4.bp.blogspot.com/-BgONRQSen2k/ToEIxcJT0yI/AAAAAAAAHdc/uwBC1WOIPdc/s320/maven_prototype.png" alt="" id="BLOGGER_PHOTO_ID_5656812252415906594" border="0" /&gt;&lt;/a&gt;

&lt;h4&gt;Archetype&lt;/h4&gt;

&lt;p&gt;Ha gyakran kezdünk új projektet, vagy egy létező rendszerbe új modult, akkor lehetőség van archetype deklarálására. Ez tulajdonképpen egy projekt sablon, amiből ki lehet indulni. Így nem úgy kezdünk egy új projektet, hogy veszünk egy létezőt, és lebutítjuk, hanem már egy sablonból. Vannak előregyártott archetype-ok is, pl. egyszerű Java alkalmazás, egyszerű web alkalmazás, Maven plugin, Confluence plugin, NetBeans modul, stb. Vagy pl. nézhetjük &lt;a href="http://raibledesigns.com/"&gt;Matt Raible&lt;/a&gt; tevékenységét is, az &lt;a href="http://appfuse.org/display/APF/Home"&gt;AppFuse-t&lt;/a&gt; is, mely előre gyártott projekt sablonok, melyek különböző technológiák integrálásával (Spring, JSF, Struts 2, Spring MVC, Stripes, Tapestry 5, Wicket, JPA, stb.) jöttek létre. Ezek kis példa alkalmazások, melyek önmagukban is működnek, nem nekünk kell konfigurálgatni, integrálgatni, jó kiinduló alapot biztosítanak. Be kell vallanom, én annyira nem hiszek az archetype-okban, mert mire új projektet kellett indítani, mindig változott valamelyest a technológia, más keretrendszereket használtunk, más megközelítésmódot alkalmaztunk. Ezeknek tényleg inkább alkalmazásgyáraknál van jelentősége.&lt;/p&gt;

&lt;h4&gt;Assembly&lt;/h4&gt;

&lt;p&gt;Az assembly plugin használatának minden könyv külön fejezetet szentel. Arra használható, hogy gyakorlatilag bármilyen artifact-ot elő tudunk vele állítani, attól függően, hogy hogyan szeretnénk terjeszteni az alkalmazásunkat. Vannak &lt;a href="http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html"&gt;előre beépített&lt;/a&gt; struktúrák (ezek közül van, ami csak a binárist tartalmazza, a binárist tartalmazza a függőségekkel, csak a forrást tartalmazza, teljes projektet tartalmazza), de természetesen sajátot is tudunk gyártani.&lt;/p&gt;

&lt;h4&gt;Verziókezelő struktúra&lt;/h4&gt;

&lt;p&gt;Bár nem így kéne lennie, egy kicsit kényszerpályán vagyunk azzal kapcsolatban, hogy hogyan szervezzük a verziókezelőben a projektjeinket, Subversion esetén trunk-ot, tag-eket, branch-eket, stb. Erről már írtam egy korábbi &lt;a href="http://jtechlog.blogspot.com/2010/10/release-maven-nel-es-hudson-nel.html"&gt;post-ban&lt;/a&gt;. Egyszerű szabály, hogy a projekt neve és a könyvtár neve egyezzen meg. Nagyon tervezzük meg, dokumentáljuk, és teszteljük a választott struktúrát, különösen a release folyamat esetén.&lt;/p&gt;

&lt;h4&gt;Teszt, release és deployment&lt;/h4&gt;

&lt;p&gt;A unit tesztek lefutása legyen gyors. Amennyiben integrációs teszteket is alkalmazunk, nyugodtan nyissunk neki külön projektet. Gyorsabb lesz tőle a build folyamat, és megfelelően szeparálva lesz a unit tesztektől.&lt;/p&gt;

&lt;p&gt;Használjuk a Maven release plugin-t, egy release elkészítésére. Egy release egy végleges, megváltoztathatatlan artifact, mely könnyen azonosítható, bármikor később reprodukálható. (Szemben a snapshot verzióval, mely egy folyamatosan változó, fejlesztés alatt lévő verzió.&lt;/p&gt;

&lt;p&gt;A deployment-re is külön projektet érdemes készíteni, mely függőségként definiálja a telepítendő artifact-ot. Ezt aztán telepítés során letölti a telepítendő állományt, és telepíti a megfelelő alkalmazásszerverre. Így nem zavarja a normál fejlesztési munkafolyamatot.&lt;/p&gt;

&lt;h4&gt;Nem erőltetném&lt;/h4&gt;

&lt;p&gt;Természetes, hogy amiket a fentiekben javaslok, azoknak ne használjuk az ellentétét. Tehát pl. ne használjunk version range-eket, hanem mindig pontosan deklaráljuk a verziószámokat.&lt;/p&gt;

&lt;p&gt;Én nem szeretem a profile-ok használatát sem, amennyiben lehetőség van rá, kerülöm őket. Konkrétan ott szoktam alkalmazni, ahol gyorsítják a fejlesztés - telepítés - tesztelés folyamatot. Pl. fejlesztés közben nem érdemes a war-t összecsomagolni, ha az alkalmazásszerver a kibontottat is (exploded war, in place deployment) fel tudja olvasni (persze release-kor meg a fájl kell), vagy release-kor más artifact-ot is elő kell állítani (pl olyan jar állományt, melyben bele vannak csomagolva a függőségek). Ezeket fejlesztés közben nem akarom előállítani.&lt;/p&gt;

&lt;p&gt;Csakis a legvégső esetben folyamodnék ahhoz, hogy saját Maven plugin-t fejlesszek. Szerencsére erre még nem volt szükség, mindig találtam olyat, mely megfelelő volt az igényeimnek.&lt;/p&gt;

&lt;p&gt;Ti használtok Maven-t? Mennyi energiát fektettek a pom struktúra kidolgozásába, szinten tartásába, tökéletesítésébe? Segít, vagy hátráltat? Kedvelt eszköz, vagy a szükséges rossz? Tapasztalatok alternatív eszközökkel?&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/9075776410959180550/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/09/maven-legjobb-gyakorlatok.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/9075776410959180550?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/9075776410959180550?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/09/maven-legjobb-gyakorlatok.html" title="Maven legjobb gyakorlatok" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-BgONRQSen2k/ToEIxcJT0yI/AAAAAAAAHdc/uwBC1WOIPdc/s72-c/maven_prototype.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkABQn49eyp7ImA9WhdUEEU.&quot;"><id>tag:blogger.com,1999:blog-7370998606556338092.post-3642971482325571342</id><published>2011-09-18T14:24:00.010+02:00</published><updated>2011-09-27T01:45:53.063+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-27T01:45:53.063+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><title>Maven bevezetés, modernizáció</title><content type="html">&lt;p&gt;Technológiák: Maven 3.0.3&lt;/p&gt;

&lt;p&gt;Valahogy az elmúlt időszakban úgy alakult, hogy három projektben is Maven szaktanácsadást nyújthattam. Ebből egy egy teljesen nulláról induló projekt, egy Ant-ról migrálós projekt valamint egy már meglévő Maven projekt továbbfejlesztése. Az ezekben szerzett tapasztalatokról szeretnék itt beszámolni.&lt;/p&gt;

&lt;p&gt;Ebből a legizgalmasabb a már létező Maven projekt modernizálása, egy Gibraltáron működő online szerencsejáték cégnek, ahova a meghívást &lt;a href="http://britpalmak.blogspot.com/"&gt;Magyusz&lt;/a&gt; és Cseki haverom intézte, akik ott vezető programozói státuszban tevékenykednek. Ezúttal is köszönöm nekik! &lt;a href="http://britpalmak.blogspot.com/2011/07/magyarok-majd-megoldjak.html"&gt;Három napot töltöttem a projektben&lt;/a&gt;, ami során sikerült megismerni a jelenlegi Maven struktúrát, a legjobb gyakorlatokat alkalmazni, és felderíteni a gyenge pontokat. Persze sok utómunkával jár, és vannak ötletek, hogy merre lehetne tovább fejlődni. A három nap tartalmazta a verziókezelés folyamatának kialakítását is, az előző post-jaim ezekről szóltak.&lt;/p&gt;

&lt;p&gt;Magáról az országról sokat nem tudok írni, az eltöltött öt nap benyomások szerzésére volt elegendő. Egy apró brit tengerentúli terület (7 négyzetkilométer), ami minden egyes pontján erősen érződik is. Angol a hivatalos nyelv, emeletes busz, klasszikus londoni telefonfülke és még sok minden megtalálható itt. Amiről az úti beszámolók a leggyakrabban írnak, hogy az országba jutáskor át kell kelni a repülőtér felszállópályáján, ami keresztezi a határról érkező utat, lámpával irányítva, ami piros, ha épp egy repülőgép száll fel, vagy le. Valamint a szikla tetején (, ahonnan gyönyörű a kilátás minden irányban) élő Európában egyedülállóan szabadon élő majmok híresek itt. Apropó Gibraltár egy hatalmas mészkőszikla, ami ki tudja honnan került ide, és át és át van lyuggatva, mint a sajt, belsejében érdekesebbnél érdekesebb és titkos dolgokkal, valamint egy kis feltöltött terület. Déli pontjáról tiszta időben szépen látszik Afrika. Északon Spanyolországgal határos, a nem éppen legszebb La Linea de la Conception várossal, de kicsit messzebb menve már gyönyörű helyekre lehet eljutni, mint egy &lt;a href="http://britpalmak.blogspot.com/2011/07/sikloernyos-etterem.html"&gt;siklóernyős starthely&lt;/a&gt;, vagy egy &lt;a href="http://britpalmak.blogspot.com/2011/07/kitesurf-paradicsom.html"&gt;kitesurf paradicsom&lt;/a&gt;, az óceánnál.&lt;/p&gt;

&lt;a rel="lightbox" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-PZmnGNKjaMw/TnXnWB8KyjI/AAAAAAAAHZs/F6nx45R1OMg/s1600/gib1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-PZmnGNKjaMw/TnXnWB8KyjI/AAAAAAAAHZs/F6nx45R1OMg/s320/gib1.jpg" alt="" id="BLOGGER_PHOTO_ID_5653679272897464882" border="0" /&gt;&lt;/a&gt;

&lt;p&gt;A cég nagyon meggyőző volt, látszott, hogy komolyan veszik, amit csinálnak. Olyan hangulat uralkodott, hogy érződött, hogy odafigyelnek a munkájukra. A társaság igen vegyes, mind nemzetiségileg, mind szakmailag. Érdekes jelenség, hogy a szerverekkel nem fukarkodnak, azonban az emberi erőforrásokban sokkal inkább. Egyik szobában a sporteseményeket követték, impresszív volt a minden asztalon három LCD monitor, valamint a mennyezetről lógó plazmatévék sora. Természetesen a fejlesztőknél is volt egy tévé, hogy a fontosabb sporteseményeket követni lehessen. Alapvetően különbségeket azonban nem tapasztaltam, sem szakmailag, sem technológiailag. Az irodából kilépve azonban azonnal elöntötte a mediterrán hangulat, a meleg, a késő este is napsütés, tengerpart, a hatalmas és tekintélyt parancsoló, a kikötőben állomásozó hajókkal, vonzották az embert a part menti bárok és kaszinó.&lt;/p&gt;

&lt;a rel="lightbox" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-L9G38OUpUHg/TnXnghWhidI/AAAAAAAAHZ0/kEunQcyTHwI/s1600/gib2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/-L9G38OUpUHg/TnXnghWhidI/AAAAAAAAHZ0/kEunQcyTHwI/s320/gib2.jpg" alt="" id="BLOGGER_PHOTO_ID_5653679453128198610" border="0" /&gt;&lt;/a&gt;

&lt;p&gt;Lássuk, hogy hogyan is telt a szakmai három nap, hogyan lehet egy Maven "rendrakást" kivitelezni. Egy build folyamat modernizációja subproject sem tér el a klasszikus szoftverfejlesztéstől, ugyanúgy van követelményfelmérés, tervezés, implementáció és tesztelés. Ugyanúgy iterációkra kell bontani, és dokumentációval megtámogatni. A következő lépésekből áll a folyamat.&lt;/p&gt;

&lt;h4&gt;Követelmények&lt;/h4&gt;

&lt;p&gt;A projekt célját érdemes tisztázni. Mi a probléma a jelenlegi folyamattal, mi nehezíti a build folyamatban legjobban a szoftverfejlesztést, mi az ami "legjobban fáj"?. Lehet ez a túl durva vagy túl finom granularitású modularizáció, a hosszú build, a nehézkes fejlesztés, a sok szaktudást igénylő release. Meg kell hallgatni az ügyfelet, hogy milyen ötletei vannak, hiszen ő él a projektben, lehet, hogy sejti, esetleg tudja, hogy mit és hogyan szeretne. Hasznosak a mérőszámok, pl. projektek száma, pom.xml állományok száma, benne szereplő sorok száma, build folyamat hossza időben, stb.&lt;/p&gt;

&lt;p&gt;A felmérés során meg kell ismerni a jelenlegi rendszer architektúráját is, én komponens diagramot használok. Milyen alkalmazások futnak, ezek hogyan kapcsolódnak egymáshoz, milyen közös könyvtárakat használnak. Milyen típusú alkalmazások vannak, standalone, web alkalmazások, esetleg Java EE alkalmazások. Milyen környezetben futnak, milyen operációs rendszerek, alkalmazásszerverek használtak, mennyire fontos a platformfüggetlenség. A build folyamat szempontjából ezek cseppet sem elhanyagolhatóak, hiszen ez alapján nagyjából sejteni lehet, hogy mennyi és milyen típusú artifact-okra lehet számítani. Ez esetemben kb. 10 alkalmazás, közte standalone és webes is.&lt;/p&gt;

&lt;p&gt;Fel kell térképezni a jelenlegi Maven struktúrát. Ez a fejlesztői környezet installálása saját gépen (rögzítsük, hogy ez milyen lépésekből áll, mennyire bonyolult, hogyan lehet egyszerűsíteni), valamint annak futtatása. Rögzítsük impresszióinkat, mennyi ideig tart, vannak-e warning-ok, hibaüzenetek. És a legunalmasabb rész, át kell böngészni egyesével a pom.xml-eket, és jegyzeteket készíteni, hol lehet és kell módosítani. Közben rögzítem azokat az eszközöket is, amelyek nem szokványosak, pl. egyedi forráskód generálás, stb. Feljegyzem, hogy hol "bűzlik a kód". Az ügyfelet is kérdezzük meg, hogy hol érzi rossznak, mit miért csináltak, mert ilyenkor lehet rábukkanni arra, hogy valamiért speciális/egyedi-e az adott projekt, valamint vannak-e hiányosságok az ügyfél tudásában, vagy bizonyos megoldások mellett miért döntött.&lt;/p&gt;

&lt;p&gt;Én közben egy függőségi gráfot is rajzolok. Osztálydiagramot szoktam alkalmazni, ahol színekkel jelzem az alkalmazások típusait, valamint dependency-vel a függőségeket, kompozícióval a modul tartalmazást és generalizációval a szülő kapcsolatot.&lt;/p&gt;

&lt;a ref="lightbox" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-Sp5_3iaRpM0/TnXyWTzjFfI/AAAAAAAAHaE/EUlOKwnisUM/s1600/modulok.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 177px;" src="http://4.bp.blogspot.com/-Sp5_3iaRpM0/TnXyWTzjFfI/AAAAAAAAHaE/EUlOKwnisUM/s320/modulok.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5653691372321052146" /&gt;&lt;/a&gt;

&lt;p&gt;Nem javaslom a függőségi gráfok generálását. Egyrészt, ha magunk rajzoljuk, sokkal jobban megértjük, valamint vannak olyan függőségek, amik evidensek, és csak az ábrát bonyolítanák (pl. egy common könyvtárra biztos mindenki hivatkozik). Valamint ezek az eszközök értelmesen sem tudják elhelyezni az artifact-okat.&lt;/p&gt;

&lt;p&gt;Sajnos gyakran futok bele olyan projektekbe is, ahol körkörös függőségre bukkanok. Pl. a common library-ra hivatkozik a service és a ui réteg is, de a common visszahivatkozik az ui rétegre. Kiemelten kezeljük ezeket a problémákat.&lt;/p&gt;

&lt;p&gt;Vizsgáljuk meg a külső függőségeket. Ezeket feltűnően lazán szokták kezelni, bekerül a projektbe, de utána kikerül, de a függőségek közül nem távolítják el. Nem megfelelő scope-ba veszik fel, pl. csak teszteléskor van rá szükség, mégis normál függőségként szerepel. Egymással ütköző library-k vannak, melyek csak a véletlennek köszönhetően működnek együtt (pl. előbb van a classpath-ban), ilyenek pl. az naplózó keretrendszerek, az XML library-k. Láttam olyant is, hogy egy library-nak különböző verziói szerepeltek a függőségek között (pl. változott a library group vagy artifact id-ja). Egy feladatra különböző library-k szerepelnek a projektbe, pl. az előbb említetteken túl több webes keretrendszer, REST API, SOAP API, perzisztencia réteg, stb. Sokan megfeledkeznek róla, de ellenőrizzük a licence-eket is.&lt;/p&gt;

&lt;p&gt;Vizsgáljuk meg a teszt eseteket. Granularitásukat, bonyolultságukat. Gyakran keverednek a fogalmak, pl. unit tesztek között találhatunk integrációs tesztet, ami nagyobb egységet tesztel, esetleg külső rendszerekre, adatbázisra is szüksége van.&lt;/p&gt;

&lt;p&gt;Egyeztessünk, milyen riportokra állnak rendelkezésre, és ezek közül melyekre van szükség?&lt;/p&gt;

&lt;h4&gt;Tervezés&lt;/h4&gt;

&lt;p&gt;Amint felmértük a követelményeket, az ügyfél elvárásait, tervezzük meg a migráció, bevezetés folyamatát. Bontsuk lépésekre, definiáljuk a lépések scope-ját.&lt;/p&gt;

&lt;p&gt;Első esetben mindenképpen az elvárt struktúrát tervezzük meg, a már fentebb említett osztálydiagrammal. Lehet, hogy nem kell rajta változtatni, lehet, hogy gyökeres változtatásokat kell bevezetni. Amit mindenképpen meg kell szüntetni, az a körkörös függősségek. Ki kell találni a megfelelő granularitást, új modulokat bevezetni, modulokat összevonni vagy szétválasztani.&lt;/p&gt;

&lt;p&gt;Válasszuk ki a megfelelő eszközöket. Amennyiben úgy gondoljuk, ne erőltessük a Maven-t. Nem minden projekt, és nem minden fejlesztőgárda tud megfelelően illeszkedni hozzá. Minél szabványosabb a projekt, annál egyszerűbb adoptálni. Amennyiben túl sok egyediség van az architektúrában, a fejlesztési folyamatban, vagy a fejlesztők nem eléggé nyitottak a Maven irányába, alaposan gondoljuk meg, hogy van-e értelme, ilyen környezetben kétes a projekt sikere. Amennyiben azonban a Maven-t válasszuk, jelöljük meg, hogy milyen plugin-eket kívánunk használni. Dokumentáljuk döntéseinket.&lt;/p&gt;

&lt;p&gt;Elemezzük a függőségeket. Tervezzük meg, hogy mely függőségek maradhatnak, azok milyen scope-ban. Nézzük meg, hogy a legfrissebb verziók kerültek-e felhasználásra, és ha nem, ennek van-e valamilyen oka. Tervezzük meg, hogyan szüntethetjük meg az ütközéseket. Nézzük meg, hogy mely függőségek nem publikus repository-ból kerülnek letöltésre, létezik-e publikus megfelelőjük. Ha nem, honnan származnak, megvan-e a forráskódjuk.&lt;/p&gt;

&lt;p&gt;Tervezzük meg, hogy az alkalmazások verziószáma hogyan jelenik meg a felületen, és a build folyamat során hogyan kerül beírásra. Erről szól az előző &lt;a href="http://jtechlog.blogspot.com/2011/09/verzioszam-megjelenitese-az.html"&gt;post-om&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tervezzük meg a test harness-t. Elegendő-e a JUnit, vagy érdemesebb-e a TestNG-t használni. Mivel mérjük a kódlefedettséget? Milyen integrációs teszt keretrendszert használjunk.&lt;/p&gt;

&lt;p&gt;Tervezzük meg a használni kívánt riportokat, azok paraméterezését.&lt;/p&gt;

&lt;p&gt;Én a tervezési fázisban egy olyan dokumentációt is készítek, mely leírja, hogy a fejlesztő csapatnak milyen feladatokat kell elvégeznie. Ez egyrész tartalmazza azokat a feladatokat, melyek előfeltételei a migrációnak. A forráskód, a rendszer megismerésével is találkozni lehet olyan problémákkal, amiket érdemes jelezni, de nem tartoznak szorosan a modernizációhoz - ezeken a fejlesztőcsapat akár párhuzamosan is dolgozhat. Valamint egy olyan dokumentációt is írok, mely a build folyamat továbbfejlesztési lépéseit is tartalmazza, hiszen nem hiszek abban, hogy egyszerre túl nagyot kéne lépni, érdemes kis lépésekben elvégezni a bevezetést. Hiszen az első használatbavételkor pontosodnak majd az igények.&lt;/p&gt;

&lt;h4&gt;Implementáció&lt;/h4&gt;

&lt;p&gt;Amennyiben van olyan teendő, mely blokkolja a Maven build bevezetését, továbbfejlesztését, meg kell várnunk azok befejezését. Találkoztam olyan projekttel, ahol ez több hetet is igénybe vett, hiszen az élet nem állhat meg, a fejlesztő csapat nem minden esetben képes csak a modernizációra figyelni, közben új verziókat kell kiadni, hibákat javítani, stb.&lt;/p&gt;

&lt;p&gt;Első körben, amennyiben a projekt még nem végleges, egy olyan build folyamatot valósítsunk meg, mely bitre pontosan ugyanazokat az artifact-okat gyártja le, mint az előző build folyamat (pl. script-ek, Ant build.xml-ek). Bár lehet, hogy nagyobb refactoring-ot kell elvégeznünk, ez mégis segít a megértésben, a trükkös megoldások felderítésében, a projekt sajátosságainak megértésében. És azonnali eredményt biztosít, hiszen azonnal bevethetjük.&lt;/p&gt;

&lt;p&gt;Alakítsuk ki a könyvtárstruktúrát, lehetőleg a Maven által definiált kvázi szabványoknak megfelelően, és írjuk, módosítsuk a pom.xml állományokat, és alakítsuk ki a verziókezelő struktúrát. A pom.xml-ek megírására most nem térnék ki, a követendő legjobb gyakorlatok a következő post-om tárgya. Konvencióknak megfelelően nevezzük meg a projekteket, adjunk verziószámot, definiáljuk a függőségeket, a plugin-eket (legyenek akár report plugin-ek). Amennyiben szükséges, használjuk profile-okat.&lt;/p&gt;

&lt;p&gt;Az egyik projekt során feladat volt Maven 2-ről Maven 3-ra migrálni. Ezzel csak jó tapasztalataim voltak. Első körben azonnal warning-okat ír ki, ami a nem megfelelő pom.xml bejegyzéseket tartalmazza (pl. nincs definiálva a plugin-ek verziószáma). Ezeket mindenképpen eliminálni szükséges. A build is gyorsabb 3-as Maven-nel, bár nem számottevően. És volt olyan is, hogy egy multimodule projektet a 2-es nem tudott release-elni, mert a modulok közötti függőség esetén nem találta a "testvér" modult a reactor-ban, míg a 3-as gond nélkül megcsinálta.&lt;/p&gt;

&lt;p&gt;Az implementáció során előállt termékek:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verziókezelő struktúra&lt;/li&gt;
&lt;li&gt;A pom.xml állományok&lt;/li&gt;
&lt;li&gt;Különböző segéd script-ek&lt;/li&gt;
&lt;li&gt;Különböző napló állományok&lt;/li&gt;
&lt;li&gt;Build folyamat dokumentációja&lt;/li&gt;
&lt;li&gt;Továbbfejlesztési javaslatok dokumentációja&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Tesztelés&lt;/h4&gt;

&lt;p&gt;A build folyamatot ugyanúgy kell tesztelni. Első körben elegendő összehasonlítani, hogy az előállított artifact-ek bitre megegyeznek-e. Ha már ezen a szinten is módosításokat tettünk, akkor tesztelni kell, hogy az előállított artifact-el ugyanúgy működnek-e (nem hiányzik-e jar, amit egy ClassNotFoundException jelez, stb.). Adjuk oda a fejlesztőknek az eszközt, hogy vegyék használatba. Elemezzük a használati eseteket, hogy mindent lefedtünk-e. Ez az egyszerű fejlesztés, build parancssorban, build és futtatás IDE-ben. Build a CI szerveren. Fejlesztés branch-en, merge-ölés. Release. Artifact-ek deploy-olása különböző környezetekre. Gyűjtsük össze a fejlesztők benyomásait, tapasztalatait. Határozzuk meg újra a mérőszámokat, és hasonlítsuk össze a projekt kezdetén mértekkel. Szükség esetén javítsuk a hibákat, gyűjtsük a továbbfejlesztési ötleteket.&lt;/p&gt;

&lt;p&gt;Befejezésül annyit, hogy egy Maven alapú build folyamat kialakítása nem egyszerű feladat, és nagymértékben meg kell ismerni, meg kell érteni az alkalmazást is, mely build-elésre kerül. A build folyamat megvalósítása egy kis szoftverfejlesztési projekt, ugyanazon lépésekkel, ugyanúgy iteratívan. Szánjunk időt és erőforrást a kialakítására és karbantartására. Ez az ugródeszka, mely a teljes szoftverfejlesztési infrastruktúra alapját képzi, melybe ezen kívül beletartozik a verziókezelő rendszer, issue tracker, tudástár, repository manager, CI, test harness, quality management eszköz, és beletartoznak olyan lépések, mint tesztelés, release, deployment, code review, minőségbiztosítás, stb.&lt;/p&gt;

&lt;a rel="lightbox" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-mBhh7Ya1CSY/TnXnnPNKlyI/AAAAAAAAHZ8/TeQOJXqSLgk/s1600/gib3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-mBhh7Ya1CSY/TnXnnPNKlyI/AAAAAAAAHZ8/TeQOJXqSLgk/s320/gib3.jpg" alt="" id="BLOGGER_PHOTO_ID_5653679568516192034" border="0" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://jtechlog.blogspot.com/feeds/3642971482325571342/comments/default" title="Megjegyzések küldése" /><link rel="replies" type="text/html" href="http://jtechlog.blogspot.com/2011/09/maven-bevezetes-modernizacio.html#comment-form" title="0 megjegyzés" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3642971482325571342?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7370998606556338092/posts/default/3642971482325571342?v=2" /><link rel="alternate" type="text/html" href="http://jtechlog.blogspot.com/2011/09/maven-bevezetes-modernizacio.html" title="Maven bevezetés, modernizáció" /><author><name>István Viczián</name><uri>https://plus.google.com/115891152269405230539</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-WO4Mwoq2oFg/AAAAAAAAAAI/AAAAAAAAHkQ/db6vYh-R_6M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-PZmnGNKjaMw/TnXnWB8KyjI/AAAAAAAAHZs/F6nx45R1OMg/s72-c/gib1.jpg" height="72" width="72" /><thr:total>0</thr:total></entry></feed>
