<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8478588303162378135</id><updated>2011-07-08T19:17:44.015+02:00</updated><category term='linux'/><category term='xml'/><category term='google app engine'/><category term='obecné'/><category term='programování'/><category term='idea'/><category term='scala'/><category term='java'/><category term='web'/><category term='ajax'/><category term='czjug'/><category term='budoucnost'/><category term='testování'/><category term='databáze'/><category term='výkon'/><category term='gradle'/><category term='groovy'/><category term='dokumentace'/><category term='ipod'/><category term='spring'/><category term='škola'/><category term='orm'/><category term='Scrum'/><category term='bezpečnost'/><category term='konference'/><category term='eclipse'/><category term='vývoj'/><title type='text'>jirablog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>70</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5045469988704659709</id><published>2011-03-30T16:35:00.000+02:00</published><updated>2011-03-30T16:35:04.676+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Team vyhrává když táhne za jeden provaz</title><content type='html'>Po svém posledním příspěvku o &lt;a href="http://jirablog.blogspot.com/2011/03/neopravnena-kritika-scrumu-v-czpodcastu.html"&gt;scrumu&lt;/a&gt; jsem měl v hlavě, že napíšu ještě jeden příspěvek, abych se vyjádřil jasně, proč považuji scrum za to nejlepší v metodikách vývoje. Je to právě jeho orientace na team a ne na jednotlivce. Na samoorganizující team (tj. organizace není určena z venku).&lt;br /&gt;&lt;br /&gt;Ale pak jsem si poslech &lt;a href="http://java.cz/article/czpodcast-39-operations-devops"&gt;czpodcast č. 39 - Operations a Devops&lt;/a&gt; (hostem byl Radim Marek z Gooddata) a ten mé myšlenky posunul trochu jiným směrem. Omlouvám se, že podcasty poslouchám v opačném pořadí než vznikaly a navíc hodně zpětně, že si většina již nepamatuje co se v nich řešilo.&lt;br /&gt;&lt;br /&gt;Nejprve se pochválím. Praktikujeme cosi podobného jako &lt;a href="http://en.wikipedia.org/wiki/DevOps"&gt;Devops&lt;/a&gt; a myslím, že se nám to osvědčilo. Vždy, když píšu v aplikaci logovací string, tak přemýšlím k čemu jej použiju a co chci, aby v něm bylo za informace. Kontakt se zákazníkem mi pomáhá přemýšlet o našem produktu v kontextu zákazníka nikoliv v mém.&lt;br /&gt;&lt;br /&gt;Co mě ale vybudilo napsat tento článeček. Opět zaznělo něco co mi přijde logické. Tj. splynutí developerů a QA. A kritika byla, proč by měl drahý developer dělat testování, když tester je levnější. Argumentace Radima Marka byla do jisté míry správná, developer, který umí napsat automatický test a zárověn udělat performace testování je jistě lepší než ten co to neumí.&lt;br /&gt;&lt;br /&gt;Ale proč nad tím přemýšlet na úrovni jednotlivých vývojářů a ne na urovni teamu (jediný důvod, kterému rozumím je ohodnocení členů teamu - výplata se dává jednotlivcům - ale koneckonců proč ji nedat teamu a nechat na něm její rozdělení mezi jeho členy - třeba by to fungovalo). Vývojář sám nic neudělá, team zvládne víc. Je důležité mít schopný team, který je složen tak, aby zvládl analýzu, návrh, vývoj i testování (v celé jeho šíři). Proč je to lepší? Team je na jedné lodi a táhne za jeden provaz. Nepřehazuje si horkou bramboru. &lt;br /&gt;&lt;br /&gt;Pokud jeden člen neví jak dál s úkolem, který řeší, zeptá se kolegy, který to již dělal, nebo je zkušenější. Nikomu to nevadí, protože aktivita je stále vynaložena na úkol, který řeší celý team. Tj. je to aktivita pro dobro všech. Navíc se lidé vzájemně vzdělávají a roste jejich kvalita. Pokud ovšem sleduji, úkoluji jednotlivé vývojáře, dříve nebo později (čas je dán okamžikem, kdy se toto sledování využije k represivním krokům) přestane být pro jednotlivce zajímavé spolupracovat, protože neřeší to co mají, ale dělají něco co nemají (pomáhají kolegovi).&lt;br /&gt;&lt;br /&gt;Pro mě je to celkem stejné jako rozdělení firmy na oddělení. Funguje to dokud jsou všichni na jedné lodi. Jakmile jsou oddělení dostatečně velká, že si zavedou samostatná účetnictví a "přefakturovávají" si vzájemnou práci, pak je spolupráce ta tam.&lt;br /&gt;&lt;br /&gt;Závěrem. Scrum nabízí pohled na vývoj SW skrze team. Samoorganizující team, který je silně kooperující. To je prostředí, kde vznikají rychle dobré věci. V konkurenčním prostředí se rozvoj zpomaluje, protože se všichni ohlíží na konkurenci. Na vývoj SW už dávno nestačí jeden člověk je jich potřeba víc. Takže chceme, aby spolupracovali a ne si konkurovali.&lt;br /&gt;&lt;br /&gt;PS. Teda to je pěkná všehochuť, snad z toho někdo něco pochopí ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5045469988704659709?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5045469988704659709/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5045469988704659709' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5045469988704659709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5045469988704659709'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2011/03/team-vyhrava-kdyz-tahne-za-jeden-provaz.html' title='Team vyhrává když táhne za jeden provaz'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5232610995081738474</id><published>2011-03-21T20:41:00.000+01:00</published><updated>2011-03-21T20:41:03.320+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Neoprávněná kritika Scrumu v czpodcastu č.46: Kanban agilní vývoj</title><content type='html'>Poslouchám nyní zpětně &lt;a href="http://java.cz/article/czpodcast"&gt;czpodcast&lt;/a&gt; a při poslechu 46. dílu s názven "Kanban agilní vývoj" zazněla, dle mého soudu, neoprávněná kritika na adresu &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)"&gt;scrumu&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Na úvod je nutné si otevřeně říci, že scrum není pro každého. Splnit podmínky pro vývoj pomocí scrumu není úplně triviální, ale pokud se to povede ovoce přinese. Druhá, velmi důležitá věc, je najít kvalitní zdroj, odkud vědomosti čerpat. Existuje spousta knih o scrumu, které jsou zavádějící a nebo špatné. V ideálním případě je vhodný konzultant, který nám poradí, jak scrum správně implementovat v našem konkrétním prostředí. Já žádného dobrého českého konzultanta neznám (rozuměj nemám jej prověřeného), ale účastnil jsem se školení na ScrumMastera s &lt;a href="http://borisgloger.com/ "&gt;Borisem Glogerem&lt;/a&gt;, který mě jednoznačně přesvědčil, že tím schopným konzultantem. Svému řemeslu i scrumu perfektně rozumí.&lt;br /&gt;&lt;br /&gt;A nyní již k obsahu podcastu. Prvním jasným signálem, proč scrum nemůže v &lt;a href="http://www.gooddata.com/"&gt;GoodData &lt;/a&gt;fungovat je oddělení QA od vývoje. Scrum si vynucuje existenci tzv. universálních týmů. Tj. z týmu co sprint vypadne funkční plně otestovaný produkt doplněný o nové položky z backlogu. Pokud máme oddělené QA od vývoje, pak z týmu vypadne cosi, ale není to funkční produkt. Kde je probém? Myslím, že si Jaroslav odpověděl sám. Není známa velocita teamu. Team sice doplní produkt o položky (featury) v obtížnosti např. 100, ale v další iteraci je opravuje a spadne mu velocita na 60. Proto musí být universální teamy, aby to co je jejich výsledkem bylo funkční a plně otestované a vědělo se přesně jakou mají velocitu (ta se po několika prvních iteracích ustálí). Velocita pak pomáhá předpovídat, kolik team udělá položek backlogu za definovaný čas.&lt;br /&gt;&lt;br /&gt;Dalším problém, který byl zmíněn je vynucování si, aby univerzální teamy nebyly moc veliké, řádově deset členů (i méně). Pokud máme vývojářů víc, pak je rozdělíme do více teamů a je samozřejmě možné udělat, aby pracovali "skoro" nad jedním backlogem.&lt;br /&gt;&lt;br /&gt;V podcastu zaznělo, cosi o zarovnávání položek do sprintu a výběr menších položek z backlogu "mimo" prioritu. První jsem slyšel prvně až v podcastu a druhé je naprosto špatně! Team si na začátku sprintu z backlogu vybírá, striktně podle pořadí v jakém jsou uvedeny, položky, které bude realizovat. Chybou je mít položky tak velké, že např. zvolím první, druhou už zvolit nemohu, protože bych ji nestihl, ale první mě zaměstná pouze na 2/3 sprintu. Nikde ovšem není řečeno, že pokud má team velocitu 30, pak si musí vybrat položky v úhrnné složitosti 30, může si zvolit stejně dobře 27, jako 31.&lt;br /&gt;&lt;br /&gt;V neposlední řadě zaznělo, že se jim v GoodData položky špatně odhadují, protože dělají nové věci a u nich člověk nikdy neví. Může to být do jisté míry pravda, ale co je na scrumu kouzelné je to, že u položek v backlogu se neodhaduje jejich pracnost, ale pouze jejich složitost a to ještě poměrově mezi sebou. Používá se k tomu technika planning poker, kdy jednotlivý členové ohodnocují položky složitostí pomocí kartiček s hodnotami 1, 2, 3, 5, 8, 13, 20, 40, 100. Na této technice je úžasné, že porovnat dvě věci mezi sebou a říci, která je složitejší a jak moc nám jde velmi dobře a jsme až překvapivě hodně přesní (na rozdíl v odhadování kolik to zabere času).&lt;br /&gt;&lt;br /&gt;Z mého pohledu je závěr spíš, že scrum v GoodData neměli vůbec používat a navíc jej používali špatně a proto jim nefungoval. Tedy jednoznačně není chyba na jeho straně. Osobně se domnívám, že scrum je nejlepší metodika, kterou máme v současnosti k dispozici, ale bohužel, není pro každého.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5232610995081738474?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5232610995081738474/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5232610995081738474' title='Počet komentářů: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5232610995081738474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5232610995081738474'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2011/03/neopravnena-kritika-scrumu-v-czpodcastu.html' title='Neoprávněná kritika Scrumu v czpodcastu č.46: Kanban agilní vývoj'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5627316375642558082</id><published>2011-03-01T14:45:00.003+01:00</published><updated>2011-03-01T15:01:46.325+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='obecné'/><category scheme='http://www.blogger.com/atom/ns#' term='programování'/><title type='text'>Inovace bez legrace aneb máme se snažit vymýšlet něco nového a nebo jenom přebírat dané</title><content type='html'>Dneska se snad poprvé pustím do polemického příspěvku, který na první pohled je o vývoji softwaru ryze okrajově, ale mám takový pocit, že musím ...&lt;br /&gt;&lt;br /&gt;Jaká je motivace pro tento příspěvek. Nejprve jsem si přečetl Lukášův &lt;a href="http://blog.krecan.net/2011/02/25/jak-nenapsat-framework/"&gt;Jak nepsat framework&lt;/a&gt;, který ve mě zanechal jistou pachuť, ale nevyprovokoval mě k ničemu, ještě jsem nevěděl ...&lt;br /&gt;&lt;br /&gt;Pak se mi dostaly do ruky hodnocení &lt;a href="http://d3s.mff.cuni.cz/teaching/commercial_workshops/"&gt;prezentací pořádaných na MFF&lt;/a&gt; od studentů, kteří je shlédli. A to mě nakoplo, protože jedno hodnocení mé přednášky bylo:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Co se tématu týče, tak na mě to působilo dojmem, že pan Mareš přistupuje k Softwarovému inženýrství dost osobitým způsobem. Přišlo mi, že přednášejícímu je upřímně jedno, jak to či ono realizují v kvalitních společnostech typu NASA, DoD a podobně. Dokonce mi přišlo, že jeho postoj je, že on sám je opravdu chytrý a že to co vymysleli pánové stavějící rakety dvacet let před ním, nestojí za to řešit. Tedy že to všechno on sám už vymyslel a prověřil praxí.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;Bezpochyby toto hodnocení ukazuje, že nejsem výborný prezentátor, spíše podprůměrný, protože pokud má přednáška na někom zanechala tento dojem, pak jsem to nezvládl. Naopak myslím, že podporuji iterativní způsob vývoje SW, který se osvědčil právě v NASA a v DoD (Department of Defence) již před více než 30 lety a favorizují iterativní způsoby vývoje na úkor vodopádu (konkrétně favorizuji Scrum).&lt;br /&gt;&lt;br /&gt;Ale o tom také nechci psát. Co mají tedy tyto příspěvky společného? Otázku: Máme vymýšlet (vyvíjet) něco vlastního nebo jenom přebírat již existující?&lt;br /&gt;&lt;br /&gt;Já si myslím, že není problém vymýšlet něco nového, zkoušet zda to funguje, to je naprosto v pořádku a znamená to MOŽNÝ pokrok. Takže není chyba, pokud někdo napíše vlastní framework nebo vymyslí vlastní způsob práce, to je naprosto v pořádku. Otázkou je, zda je tak geniální, že vymyslí něco prospěšného i pro ostatní a nebo zda to je nějaký nesmysl, který funguje pouze pro jeho zvrácený případ.&lt;br /&gt;&lt;br /&gt;Chybná je jiná věc. Chybné je neumět si přiznat, že jsem udělal chybu a držet se dál toho nesmyslu co jsem vymyslel ... a v ideálním případě komplikovat život mnoha dalším lidem. Není špatně vyvinout vlastní framework, pokud se mi podaří někoho přesvědčit, že to je dobrý krok a dostanu na to peníze (nebo to udělám ve svém volném čase). Špatné je, pokud od začátku tvrdím, že se to povede a bude to úspěch a pokud nakonec, když se to nepovede, tak to nepřiznám.&lt;br /&gt;&lt;br /&gt;Težko bychom, pokud by se nenašli dostateční "šílenci", dneska měli Hibernate, Spring, Groovy, Tapestry atd. Ovšem kolik je těch projektů, které se nezrealizují a nebo neprosadí? Podstatně více, to je nutno si přiznat. Ale vždyť sama evoluce se řídí přístupem "pokus vs. omyl", úspěšné přežije na úkor neúspěšného, takže proč ne my.&lt;br /&gt;&lt;br /&gt;Takže nebojme se vymýšlet nové věci, ale buďme soudní a silní si přiznat, že se nám to nepovedlo. V ideálním případě je veledůležité zpublikovat svůj neúspěch stejně jako (možná víc než) úspěch, aby se i ostatní mohli poučit z naší chyby ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5627316375642558082?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5627316375642558082/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5627316375642558082' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5627316375642558082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5627316375642558082'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2011/03/inovace-bez-legrace-aneb-mame-se-snazit.html' title='Inovace bez legrace aneb máme se snažit vymýšlet něco nového a nebo jenom přebírat dané'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5273976392050207404</id><published>2010-05-19T16:53:00.004+02:00</published><updated>2010-05-21T07:57:32.949+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Jak na porovnávání Comparable objektů či pomocí Comparatoru</title><content type='html'>Nemít přetěžování operátorů skutečně považuji za velký problém Javy. Proč? Např. proto, že porovnávání objektů pomocí instance třídy &lt;code&gt;Comparator&lt;/code&gt; či porovnání objektů implementující rozhraní &lt;code&gt;Comparable&lt;/code&gt; je boj, který pernamentně prohrávám. Mějme např. dva datumy &lt;code&gt;d1&lt;/code&gt; a &lt;code&gt;d2&lt;/code&gt;. Pokud chci zjistit, zda platí &lt;code&gt;d1 &amp;lt;= d2&lt;/code&gt;, pak mám následující možnosti:&lt;ul&gt;&lt;li&gt;&lt;code&gt;!d1.after(d2)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;d1.compareTo(d2) &amp;lt;= 0&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;Přiznám se, že z těchto dvou variant mi přijde čitelnější ta první (druhou mi mozek nějak nebere a vždy mě stojí hrozně přemýšlení co to znamená). Ovšem metody &lt;code&gt;before&lt;/code&gt; a &lt;code&gt;after&lt;/code&gt; má pouze třída &lt;code&gt;java.util.Date&lt;/code&gt; nikoliv obecná třída implementující rozhraní &lt;code&gt;Comparable&lt;/code&gt;. Pokud budeme objekty porovnávat pomocí instance &lt;code&gt;Comparator&lt;/code&gt; pak musíme vystačit s metodou &lt;code&gt;compare&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Z tohoto důvodu jsem si udělal jednoduchý &lt;code&gt;enum&lt;/code&gt;:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public enum Relation {&lt;br /&gt;   eq, ne, lt, le, gt, ge;&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;C extends Comparable&amp;lt;? super C&amp;gt;&amp;gt; boolean rel(C c1, Relation oper, C c2) {&lt;br /&gt;      switch (oper) {&lt;br /&gt;         case eq:&lt;br /&gt;            return c1.compareTo(c2) == 0;&lt;br /&gt;         case ne:&lt;br /&gt;            return c1.compareTo(c2) != 0;&lt;br /&gt;         case lt:&lt;br /&gt;            return c1.compareTo(c2) &amp;lt; 0;&lt;br /&gt;         case le:&lt;br /&gt;            return c1.compareTo(c2) &amp;lt;= 0;&lt;br /&gt;         case gt:&lt;br /&gt;            return c1.compareTo(c2) &amp;gt; 0;&lt;br /&gt;         case ge:&lt;br /&gt;            return c1.compareTo(c2) &amp;gt;= 0;&lt;br /&gt;      }&lt;br /&gt;      throw new IllegalArgumentException("Unsupported operation " + oper);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;C&amp;gt; boolean rel(Comparator&amp;lt;C&amp;gt; comp, C c1, Relation oper, C c2) {&lt;br /&gt;      switch (oper) {&lt;br /&gt;         case eq:&lt;br /&gt;            return comp.compare(c1, c2) == 0;&lt;br /&gt;         case ne:&lt;br /&gt;            return comp.compare(c1, c2) != 0;&lt;br /&gt;         case lt:&lt;br /&gt;            return comp.compare(c1, c2) &amp;lt; 0;&lt;br /&gt;         case le:&lt;br /&gt;            return comp.compare(c1, c2) &amp;lt;= 0;&lt;br /&gt;         case gt:&lt;br /&gt;            return comp.compare(c1, c2) &amp;gt; 0;&lt;br /&gt;         case ge:&lt;br /&gt;            return comp.compare(c1, c2) &amp;gt;= 0;&lt;br /&gt;      }&lt;br /&gt;      throw new IllegalArgumentException("Unsupported operation " + oper);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Díky použití tohoto enumu mohu přepsat výše uvedený příklad porovnávání dvou datumů do podoby:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;rel(d1, le, d2)&lt;/code&gt;&lt;/pre&gt;(pokud použijeme statické importy na metodu &lt;code&gt;rel&lt;/code&gt; a instanci enumu &lt;code&gt;le&lt;/code&gt;). Protože se mi tento zápis ještě stále nezdál dostatečně výmluvný, použil jsem další vylepšení (stačí jej přidat do výše uvedeného enumu):&lt;pre&gt;&lt;code&gt;&lt;br /&gt;   protected static final Map&amp;lt;String, Relation&amp;gt; S2R;&lt;br /&gt;&lt;br /&gt;   static {&lt;br /&gt;      Map&amp;lt;String, Relation&amp;gt; tmp = new TreeMap&amp;lt;String, Relation&amp;gt;();&lt;br /&gt;      tmp.put("==", eq);&lt;br /&gt;      tmp.put("!=", ne);&lt;br /&gt;      tmp.put("&amp;lt;=", le);&lt;br /&gt;      tmp.put("&amp;lt;", lt);&lt;br /&gt;      tmp.put("&amp;gt;=", ge);&lt;br /&gt;      tmp.put("&amp;gt;", gt);&lt;br /&gt;      S2R = unmodifiableMap(tmp);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;C extends Comparable&amp;lt;? super C&amp;gt;&amp;gt; boolean rel(C c1, String oper, C c2) {&lt;br /&gt;      return rel(c1, S2R.get(oper), c2);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;C&amp;gt; boolean rel(Comparator&amp;lt;C&amp;gt; comp, C c1, String oper, C c2) {&lt;br /&gt;      return rel(comp, c1, S2R.get(oper), c2);&lt;br /&gt;   }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Nyní dostaneme již poměrně elegantní zápis:&lt;pre&gt;&lt;code&gt;rel(d1, "&amp;lt;=", d2)&lt;/code&gt;&lt;/pre&gt;Je škoda, že Java nemá přetěžování operátorů, které nás vede k takovýmto vylepšením. Např. Groovy si umí poradit a operace porovnání umí zavolat nad objekty implementující &lt;code&gt;Comparable&lt;/code&gt;. Scala je na tom podobně díky možnosti přetížení operátorů.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5273976392050207404?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5273976392050207404/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5273976392050207404' title='Počet komentářů: 23'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5273976392050207404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5273976392050207404'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2010/05/jak-na-porovnavani-comparable-objektu.html' title='Jak na porovnávání Comparable objektů či pomocí Comparatoru'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4761929654384431164</id><published>2010-01-05T21:31:00.002+01:00</published><updated>2010-01-06T07:35:17.434+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Lekce ze Scaly: Jak se vyvarovat NullPointerException</title><content type='html'>Jak se v jazyce &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; brání &lt;code&gt;NullPointerException&lt;/code&gt;? V hojné míře se používá třída &lt;code&gt;Option&lt;/code&gt;, která zajistí, že nemusí metoda vracet &lt;code&gt;null&lt;/code&gt;, ale vrací existující instanci. Jak to celé funguje si ukážeme v Javě:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public abstract class Option&amp;lt;T&amp;gt; {&lt;br /&gt;  public abstract T get();&lt;br /&gt;  public abstract boolean isNone();&lt;br /&gt;  public abstract boolean isSome();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Pokud potřebujeme aby nějaká metoda vracela něco a nebo &lt;code&gt;null&lt;/code&gt;, použijeme třídu &lt;code&gt;Option&lt;/code&gt;. Díky ní metoda vrátí existující instanci, ze které jednoduše zjistíme, zda návratová hodnota má být &lt;code&gt;null&lt;/code&gt; (&lt;code&gt;isNone()&lt;/code&gt; vrací &lt;code&gt;true&lt;/code&gt;) a nebo je to nějaká smyslu plná hodnota (&lt;code&gt;isSome()&lt;/code&gt; vrací &lt;code&gt;true&lt;/code&gt;) a pak se k této hodnotě dostaneme pomocí metody &lt;code&gt;get()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Teď už to chce jenom nějaký rozumný příklad. Vezněme si např. &lt;code&gt;Map&lt;/code&gt; a její metodu &lt;code&gt;get&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;V get(T key);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Ta v případě, že klíč v mapě neexistuje vrací &lt;code&gt;null&lt;/code&gt;. Takže typicky píšeme něco jako:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;String value = map.get(key);&lt;br /&gt;if (value != null) {&lt;br /&gt;  System.out.println(value);&lt;br /&gt;} else {&lt;br /&gt;  System.out.println("Nic");&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A jak by tedy měla metoda get objektu Map vypadat kdybychom byli ve Scale:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Option&amp;lt;V&amp;gt; get(T key);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;A nyní jak by vypadal náš kód pro čtení z mapy:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Option&amp;lt;String&amp;gt; value = map.get(key);&lt;br /&gt;if (value.isSome()) {&lt;br /&gt;  System.out.println(value.get());&lt;br /&gt;} else {&lt;br /&gt;  System.out.println("Nic");&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A zbavili jsme se ošklivého porovnání na &lt;code&gt;null&lt;/code&gt;, což jsme chtěli. Navíc pokud metoda vrací &lt;code&gt;Option&lt;/code&gt; a ne přímo hodnotu je podstatně větší pravděpodobnost, že nezapomeneme otestovat zda &lt;code&gt;Option&lt;/code&gt; něco obsahuje. Pokud metoda vrací přímo hodnotu nebo &lt;code&gt;null&lt;/code&gt;, pak hrozí, že hodnotu rovnu použijeme a neotestujeme ji na &lt;code&gt;null&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;A nyní přistupme k implementaci:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class None&amp;lt;T&amp;gt; extends Option&amp;lt;T&amp;gt; {&lt;br /&gt;&lt;br /&gt;  public T get() {&lt;br /&gt;    throw new UnsupportedOperationException("The None had no value");&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean isNone() {&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean isSome() {&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean equals(Object obj) {&lt;br /&gt;    return ((obj == this) || (obj instanceof None&lt;?&gt;));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt; public int hashCode() {&lt;br /&gt;   return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Some&amp;lt;T&amp;gt; extends Option&amp;lt;T&amp;gt; {&lt;br /&gt;  protected T value;&lt;br /&gt; &lt;br /&gt;  public Some(T value) {&lt;br /&gt;    super();&lt;br /&gt;    this.value = value;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public T get() {&lt;br /&gt;    return value;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean isNone() {&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean isSome() {&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean equals(Object obj) {&lt;br /&gt;    if (obj == this) return true;&lt;br /&gt;    if (obj instanceof Some&lt;?&gt;) {&lt;br /&gt;      Some&lt;?&gt; other = (Some&lt;?&gt;) obj;&lt;br /&gt;      return value.equals(other.value);&lt;br /&gt;    }&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int hashCode() {&lt;br /&gt;    return value.hashCode();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A jak to celé funguje ve Scale? Díky &lt;a href="http://www.scala-lang.org/node/120"&gt;pattern matchingu&lt;/a&gt; a &lt;a href="http://www.scala-lang.org/node/127"&gt;type inference&lt;/a&gt; ještě elegantněji:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;val value = map.get(key) &lt;br /&gt;value match {&lt;br /&gt;  case None =&gt; print "Nic"&lt;br /&gt;  case Some(x) =&gt; print x&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4761929654384431164?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4761929654384431164/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4761929654384431164' title='Počet komentářů: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4761929654384431164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4761929654384431164'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2010/01/lekce-ze-scaly-jak-se-vyvarovat.html' title='Lekce ze Scaly: Jak se vyvarovat NullPointerException'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8358056933765251042</id><published>2009-10-01T08:23:00.003+02:00</published><updated>2009-10-01T08:34:13.218+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Gradle - druhý krůček</title><content type='html'>V prvním popisku použití &lt;a href="http://gradle.org/"&gt;gradlu&lt;/a&gt; jsem si ukázali jak na jednoduchý projekt, dneska se podíváme, jak jsme zbuildovali projekt do waru.&lt;br /&gt;&lt;br /&gt;Vyjdeme z &lt;a href="http://jirablog.blogspot.com/2009/08/gradle-prvni-krucky.html"&gt;předcházejícího příkladu&lt;/a&gt;. Co musíme změnit, abychom měli jako výsledek projektu war, ve správném layoutu a ne jar? Je toho pekelně málo.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;usePlugin "java"&lt;br /&gt;usePlugin "maven"&lt;br /&gt;usePlugin 'eclipse'&lt;br /&gt;usePlugin 'war'&lt;br /&gt;&lt;br /&gt;sourceCompatibility = 1.6&lt;br /&gt;group = "cz.svt"&lt;br /&gt;version = "${version}"&lt;br /&gt;&lt;br /&gt;manifest.mainAttributes "Implementation-Title": name, ...&lt;br /&gt;&lt;br /&gt;configurations {&lt;br /&gt;   deployerJars  &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;   compile fileTree(dir: "lib", includes: [ "util.jar", "JMSMailer.jar"])&lt;br /&gt;&lt;br /&gt;   compile "org.apache.activemq:activemq-core:5.2.0"&lt;br /&gt;   ...&lt;br /&gt;   &lt;br /&gt;   providedCompile  "javax.servlet:servlet-api:2.4"&lt;br /&gt;   &lt;br /&gt;   runtime "datedFileAppender:datedFileAppender:1.0.2"&lt;br /&gt;   &lt;br /&gt;   deployerJars "org.apache.maven.wagon:wagon-http:1.0-beta-2"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;repositories {&lt;br /&gt;   ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;uploadArchives {&lt;br /&gt;   ...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Tam kde jsou uvedeny 3 tečky jsem build zkrátil, buď protože obsah je totožný s buildem z minula a nebo výpis nepřináší nic zajímavého. Takže co se fakticky změnilo? Jeden řádek. Přidali jsme na úvod:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;usePlugin 'war'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To je celé.  Navíc jsme do struktury adresářů přidali adresáře &lt;code&gt;src/main/webapp/META-INF&lt;/code&gt; a &lt;code&gt;src/main/webapp/WEB-INF&lt;/code&gt;. Mě to přijde úžasně jednoduché a musím říct, že se mi gradle líbí víc a víc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8358056933765251042?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8358056933765251042/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8358056933765251042' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8358056933765251042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8358056933765251042'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/10/gradle-druhy-krucek.html' title='Gradle - druhý krůček'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1330753803260263147</id><published>2009-10-01T08:03:00.003+02:00</published><updated>2009-10-01T08:23:10.882+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='czjug'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>CZJUG - Hans Dockter - Gradle</title><content type='html'>Po velmi dlouhém čase jsem se dostal na CZJUG. Nelituju, spíš lituju, že mi to termínově nevychází se tam dostávat častěji. Přednáška o &lt;a href="http://gradle.org/"&gt;gradle&lt;/a&gt; byla hodně zajímavá. Druhou přednášku o &lt;a href="http://www.jetbrains.com/mps/index.html"&gt;MPS&lt;/a&gt; jsem nepochopil, jestli to bylo tím pivem nevím. Samozřejmě jsem rád, že jsem mohl potkat staré známé z java komunity.&lt;br /&gt;&lt;br /&gt;Hans pojmul přednášku tak jak jsem to nečekal a bylo to hodně zajímavé. V podstatě na úvod nám ukázal jak je gradle inteligentní. Na příkladu přidání source directory do projektu nám ukázal jak na 4 řádcích je možné vyjádřit vše. Závislosti (interní, externí), vytvoření tasků na přeložení, závislostí mezi tasky. Pak přislo na pořad dne základní motivace a tím pádem trochu srovnání s &lt;a href="http://ant.apache.org/"&gt;ANTem&lt;/a&gt; a &lt;a href="http://maven.apache.org/"&gt;mavenem&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Dále se mluvilo o výhodách v podobě vyhodnocování tásků, které se spustí, o multiprojektech atd. Dále jsme se dozvěděli i něco o budoucnosti (především se na nás chystá spolehlivý build bez clean, tj. že gradle bude shopen zaručeně identifikovat co se změnilo a co je díky tomu nutno zbuildovat).&lt;br /&gt;&lt;br /&gt;Nosná myšlenka, pro mě, je, že gradle se snaží být takovým vylepšeným mavenem, tj. používá intenzivně standardní layout projektu, standardní lifecycle buildu, ale navíc nabízí neuvěřitelnou flexibilitu, vše je možno změnit.&lt;br /&gt;&lt;br /&gt;Pro mě je to cesta správným směrem, byť to vyžaduje kontrolu nad tím, jak je gradle používán, aby se nám build nevymkl z ruky. Navíc je gradle stále mladý a hodně se mění, takže použití v dnešní době není úplně bezproblémové. Ale je to systém hodně perspektivní.&lt;br /&gt;&lt;br /&gt;Pokud někoho obsah přednášky zaujal, pak se vše nahrávalo, takže se můžete kouknout na video (odkaz na něj jistě bude na &lt;a href="http://java.cz/detail.do?articleId=2252"&gt;stránkách CZJUGu&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1330753803260263147?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1330753803260263147/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1330753803260263147' title='Počet komentářů: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1330753803260263147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1330753803260263147'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/10/czjug-hans-dockter-gradle.html' title='CZJUG - Hans Dockter - Gradle'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5838384163531629101</id><published>2009-08-16T15:25:00.004+02:00</published><updated>2009-08-16T15:57:27.687+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><title type='text'>iBATIS 3 - nový bojovník přichází</title><content type='html'>Jsem dlouholetý uživatel Hibernate, které používáme na velkém projektu a musím se přiznat, že dnes nám spíš přináší komplikace (především u 50GB databáze už hodně záleží jaká SQL se volají a to nám Hibernate neumožňuje ovlivnit). iBATIS to umí i ve verzi 2. Co se mi líbilo na návrhu připravované verze 3 jsem již &lt;a href="http://jirablog.blogspot.com/2009/01/orm-mych-snu-ibatis-3.html"&gt;psal&lt;/a&gt;. Ale my tu již máme první betu trojky. (Než se pustím do svých postřehů, rád bych zmínil &lt;a href="http://blog.novoj.net/2009/08/16/ibatis-30-preview-cast-prvni/"&gt;seriál&lt;/a&gt; otce Fura, který je vyčerpávajícím popisem novinek v porovnání s dřívější verzí iBATISu.)&lt;br /&gt;&lt;br /&gt;Krom věcí zmíněných již v předcházejícím článku existují další, které mě hodně potěšili:&lt;ul&gt;&lt;li&gt;vytváření TypeHandlerů je o poznání jednodušší než podobných UserTypů v Hibernate&lt;/li&gt;&lt;li&gt;objekty natažené z DB nejsou vytvářené pomocí bezparametrického konstruktoru, ale pomocí ObjectFactory, takže máte způsob vytvoření objektu plně v ruce (objekty půjde vytvářet pomocí DI frameworku - &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt;, &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt;) - to je obrovská bolest Hibernate, která se řešila pomocí &lt;a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;vytváření dynamických SQL&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Jsem moc rád že komunita za iBATISem stojící sebrala odvahu a vrhla se do designu nového frameworku, i když je to za cenu menší zpětné kompatibility. Moc se jim nový iBATIS povedl a řada věcí řeší bolesti, na které musí každý kdo používá Hibernate narazit.&lt;br /&gt;&lt;br /&gt;Spolu s iBATISem byl uvolněn i další produkt a to iBATIS Schema Migration System, který umožnuje automatizovat migraci DB schéma z jedné verze tam i zpět (pokud si SQL skript na zpětnou migraci napíšete). Inspirace jistě pochází z Ruby on Rails Migrations. Bohužel Migrations jak je představil team iBATISu mají jeden zásadní problém: migrační scripty se píší přímo v SQL. Takže jen velmi těžko budeme vytvářet skript, který bude fungovat s různými databázemi nebo s různými konfiguracemi téže databáze.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5838384163531629101?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5838384163531629101/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5838384163531629101' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5838384163531629101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5838384163531629101'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/08/ibatis-3-novy-bojovnik-prichazi.html' title='iBATIS 3 - nový bojovník přichází'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7682318914527244693</id><published>2009-08-11T09:12:00.003+02:00</published><updated>2009-08-11T09:52:39.948+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Gradle - první krůčky</title><content type='html'>O novém build nástroji &lt;a href="http://gradle.org/"&gt;gradle&lt;/a&gt; jsem již &lt;a href="http://jirablog.blogspot.com/2008/07/konecne-build-system-na-urovni-gradle.html"&gt;psal&lt;/a&gt;. Je to už rok a co se za tu dobu stalo? Gradle nám vyrostl z verze 0.2 na verzi 0.7, která je už velmi rozumně použitelná. A proto jsme se rozhodli gradle použít pro náš první projekt.&lt;br /&gt;&lt;br /&gt;Jedná se o velmi jednoduchý projekt (matcher pro &lt;a href="http://easymock.org/"&gt;easymock&lt;/a&gt;). Tento projekt obsahuje 3 třídy, které je potřeba zkompilovat. Neobsahuje testy. Výsledný jar je nutno deploynout do firemní &lt;a href="http://www.jfrog.org/products.php"&gt;artifactory&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;A jak takovéto jednuché věci dosáhnout:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;usePlugin "java"&lt;br /&gt;usePlugin "maven"&lt;br /&gt;&lt;br /&gt;sourceCompatibility = 1.6&lt;br /&gt;group = "cz.svt"&lt;br /&gt;version = "${version}"&lt;br /&gt;&lt;br /&gt;manifest.mainAttributes "Implementation-Title": name, "Implementation-Version": version, "Implementation-Vendor": "ČSAD SVT Praha s.r.o." &lt;br /&gt;&lt;br /&gt;configurations {&lt;br /&gt;   deployerJars&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;   compile "commons-beanutils:commons-beanutils:1.7.0" &lt;br /&gt;   compile "org.easymock:easymock:2.2"&lt;br /&gt;   compile "org.easymock:easymockclassextension:2.2.1"&lt;br /&gt;   &lt;br /&gt;   deployerJars "org.apache.maven.wagon:wagon-http:1.0-beta-2"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;repositories {&lt;br /&gt;   mavenRepo urls: "${artifactoryURL}/repo1"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;uploadArchives {&lt;br /&gt;   repositories.mavenDeployer {&lt;br /&gt;      name = 'httpDeployer'&lt;br /&gt;      configuration = configurations.deployerJars&lt;br /&gt;      repository(url: "${artifactoryURL}/libs-releases-local") {&lt;br /&gt;         authentication userName: "${artifactoryUid}", password: "${artifactoryPwd}"&lt;br /&gt;      }&lt;br /&gt;      snapshotRepository(url: "${artifactoryURL}/libs-snapshots-local") {&lt;br /&gt;         authentication userName: "${artifactoryUid}", password: "${artifactoryPwd}"&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Maven uživatel může jenom závidět, jak je tento script kompaktní a krátký. Nyní si postupně projdeme co musíme ve scriptu udělat, aby vše fungovalo.&lt;br /&gt;&lt;br /&gt;Nejprve definujeme, které pluginy budeme používat. &lt;code&gt;java&lt;/code&gt; plugin potřebujeme pro překlad Javy a &lt;code&gt;maven&lt;/code&gt; pro deployment do artifactory (jedná se o maven repository).&lt;br /&gt;&lt;br /&gt;Další 3 řádky definují, že používáme Javu 1.6, skupina deployovaného artefaktu je "cz.svt" a na verzi se odvoláváme jako na property (o těch si povíme dále). Následuje řádek s definicí manifestu (hojně používáme property dříve nastavené).&lt;br /&gt;&lt;br /&gt;Další 3 řádky definují novou konfiguraci &lt;code&gt;deployerJars&lt;/code&gt;, kterou použijeme v tasku na deployment jaru do naší sdílené firemní artifactory.&lt;br /&gt;&lt;br /&gt;A začínáme tím zajímavým, závislostmi. Stačí nám na ně 7 řádků. Závislosti se definují podobně jako v &lt;a href="http://maven.apache.org/"&gt;mavenu&lt;/a&gt;, ale skupiona, název, verze se oddělují dvojtečkou. Jinak gradle umí díky &lt;a href="http://ant.apache.org/ivy/"&gt;ivy&lt;/a&gt; pracovat nejen s ivy, ale i maven repository. Poslední závislost říká, že deployování bude potřebovat &lt;code&gt;wagon-http&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Následně defunujeme repository pro resolvování závislostí (opět pomocí property). Poslední je task &lt;code&gt;uploadArchives&lt;/code&gt;, který je nejsložitější z celého scriptu. Složitost ovšem spočívá v definování rozdílné repository pro snapshoty a pro finální verze (v podstatě dvakrát to samé). Protože deployment do artifactory nemůže provést každý, je nutné specifikovat už. jméno a heslo (není přímo ve scriptu, ale je to properta).&lt;br /&gt;&lt;br /&gt;Jak gradle resolvuje property? Gradle hledá v aktuálním adresáři soubor &lt;code&gt;gradle.properties&lt;/code&gt; a dále se kouká do adresáře &lt;code&gt;$HOME/.gradle/&lt;/code&gt; po stejnojmenném souboru. V těchto souborech můžeme definovat property, jenž můžeme využít v buildu. Takže v projektu uvádíme verzi a v domovském adresáři definujeme adresu repository a už. jméno a heslo.&lt;br /&gt;&lt;br /&gt;A jaké budou další krůčky? Nejprve přidáme testy, pak generování standardních reportů (javadocs, findbugs, cobertura) a nakonec groovy, aspectj atd...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7682318914527244693?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7682318914527244693/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7682318914527244693' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7682318914527244693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7682318914527244693'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/08/gradle-prvni-krucky.html' title='Gradle - první krůčky'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8738282024873989654</id><published>2009-07-16T20:04:00.004+02:00</published><updated>2009-08-07T07:14:53.451+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programování'/><category scheme='http://www.blogger.com/atom/ns#' term='škola'/><title type='text'>Super myšlenka učení programovat na škole - programovat open source projekt</title><content type='html'>Když jsme byli na &lt;a href="http://www.jopenspace.cz/"&gt;jOpenSpace 2009&lt;/a&gt; tak jsme v hloučku zainteresovaných vedli diskusi na téma: "Co by měla vysoká škola dělat, aby naučila své studenty programovat?". V této diskusi byl hodně aktivní &lt;a href="http://is.muni.cz/lide/?uco=70897"&gt;Petr Adámek&lt;/a&gt;, který jako učitel na Masarykově univerzitě, měl k tématu hodně co říci.&lt;br /&gt;&lt;br /&gt;Já jsem šel do diskuse s nosnou myšlenkou, že škola musí více do svého programu zatáhnout komerční sféru (u nás ve firmě pracuje řada studujících), aby se studenti dostali do kontaktu s realitou. Pracovali na skutečných projektech, se skutečným zadáním, spolupracovali s již protřelými programátory atd.&lt;br /&gt;&lt;br /&gt;Petr se mnou de facto souhlasil, ale tvrdil, že to je nemožné zrealizovat, že zájem firem není.&lt;br /&gt;&lt;br /&gt;Dneska jsem poslouchal &lt;a href="http://javaposse.com/index.php?post_id=498054"&gt;Java Posse #263 - Interview with Cay Horstmann&lt;/a&gt; (profesor na universitě), kde zazněla ona geniální myšlenka. Jak pracovat na reálném projektu, když firmy nemají zájem. No přeci pracovat na open source projektu. Cay Horstmann řekl, že mají na universitě předmět, jehož náplní je pracovat na již existujícím open source projektu (existujícím - dle výběru studenta). Student se naučí psát kvalitní kód, spolupracovat s kolegy, číst cizí kód, inteligentně se ptát atd.&lt;br /&gt;&lt;br /&gt;Řekl bych, že tato myšlenka rozsekla onen pomyslný &lt;a href="http://cs.wikipedia.org/wiki/Gordick%C3%BD_uzel"&gt;gordický uzel&lt;/a&gt;, který vznikl v diskusi mezi mnou a Petrem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8738282024873989654?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8738282024873989654/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8738282024873989654' title='Počet komentářů: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8738282024873989654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8738282024873989654'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/07/super-myslenka-uceni-programovat-na.html' title='Super myšlenka učení programovat na škole - programovat open source projekt'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-365896634331771166</id><published>2009-06-25T16:26:00.003+02:00</published><updated>2009-06-25T16:49:38.383+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Byl jsem na Scrum Master Training</title><content type='html'>A stal jsem se certifikovaným Scrum Masterem.&lt;br /&gt;&lt;br /&gt;O tom, ale nechci psát, chci psát o tom jak moc bylo toto &lt;a href="http://devcamp.cz/"&gt;školení&lt;/a&gt; prospěšné a co vše mi přineslo. Školení vedl &lt;a href="http://borisgloger.com/"&gt;Boris Gloger&lt;/a&gt;, který se ukázal jako perfektní přednášející. Přednášenou oblast dokonale zná, nejenom z již uskutečněných školení, ale i z praxe. Navíc jeho skušenosti se zaváděním &lt;a href="http://en.wikipedia.org/wiki/Scrum_%28development%29"&gt;Scrumu&lt;/a&gt; byly hodně veliké, takže na jakoukoliv otázku byl velmi promptně připraven odpovědět a vždy si věděl rady. Opravdu perfektní školitel.&lt;br /&gt;&lt;br /&gt;Školení bylo dvoudenní a konalo se na jihu Čech. Provedlo nás postupně všemi částmi Scrumu, které se Scrum Mastera týkají, o všem jsme si příjemně popovídali a řadu věcí jsme si díky šikovně vybraným cvičením i vyzkoušeli.&lt;br /&gt;&lt;br /&gt;Co si ze školení odnáším? Především jde o to, že Scrum Master ze mě zatím nebude, protože vývoj softwaru mám moc rád a hodně těžko bych se bez něj obcházel. A Boris striktně nedoporučuje, aby Scrum Master byl zároveň vývojářem, protože Scrum Master má za úkol podporovat a chránit team před okolními vlivy a to by zároveň jako vývojář nemohl dělat na 100%.&lt;br /&gt;&lt;br /&gt;Dále jsem si odnesl velmi důležitou část Scrumu a to: čím více jsou lidé z teamu zatáhnuti do možnosti určovat si práci, rozhodovat o ní jak ji udělají a kolik ji udělají (kolik stihnou udělat za následující sprint), pak se o to více snaží, aby to co slíbili také zvládli. Pokud to rozhodne někdo za ně, pak nebojují za svou čest, ale za čest někoho jiného a to se bojuje podstatně laxněji.&lt;br /&gt;&lt;br /&gt;To jsou hlavní poznání, které mi školení přineslo. Pak jsem si ještě odnesl pár drobností: neohodnocovat požadavky (Story) pomocí člověkodnů, ale pomocí bodů (díky tomu, že se určí kolik bodů je schopen team zvládnout za jeden sprint, ví se kolik udělá požadavků), skvělá je metodika ohodnocování složitosti požadavků (opět to dělá team pomocí &lt;a href="http://en.wikipedia.org/wiki/Planning_poker"&gt;Planning Pokeru&lt;/a&gt;), team v jeden okamžik vždy pracuje na jednom požadavku (aby byl software co nejméně rozvrtaný a aby si vzájemně pomohl, protože chce mít požadavek co nejdříve hotový) atd.&lt;br /&gt;&lt;br /&gt;Vřele všem podobné školení doporučuji, i když nehodláte být Scrum Master, ani nehodláte vyvíjet software podle Scrumu. Proč? Protože chytrých nápadů je ve Scrumu spousta a spousta se jich dá použít.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-365896634331771166?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/365896634331771166/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=365896634331771166' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/365896634331771166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/365896634331771166'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/06/byl-jsem-na-scrum-master-training.html' title='Byl jsem na Scrum Master Training'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7654163404417144365</id><published>2009-05-07T07:42:00.003+02:00</published><updated>2009-05-07T07:47:05.775+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Tapestry 5. 1 je mezi námi</title><content type='html'>A je to ... verze 5.1.0.5 prošla hlasováním a stala se finální verzí &lt;a href="http://tapestry.apache.org/tapestry5.1/"&gt;Tapestry 5.1&lt;/a&gt;. Co je nového? Především na straně výkonu aplikace bylo podniknuto hodně kroků: zrychleni vykreslení složitých stránek, sloučení více statických JavaScriptových knihoven do jedné, gzipová komprese statického i dynamického obsahu atd. (blíže viz. &lt;a href="http://tapestry.apache.org/tapestry5.1/release-notes.html"&gt;release notes&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7654163404417144365?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7654163404417144365/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7654163404417144365' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7654163404417144365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7654163404417144365'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/05/tapestry-5-1-je-mezi-nami.html' title='Tapestry 5. 1 je mezi námi'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5959134458303152350</id><published>2009-04-08T08:07:00.002+02:00</published><updated>2009-04-08T08:13:11.272+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='google app engine'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Google App Engine &amp; Java + Groovy</title><content type='html'>Skvělé partnerství!&lt;br /&gt;&lt;br /&gt;Od mé účasti na &lt;a href="http://jirablog.blogspot.com/2008/10/google-developer-day-2008.html"&gt;Google Developer Day 2008&lt;/a&gt; jsem si říkal, že se musím na &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; podívat, abych mohl &lt;a href="http://appengine.google.com"&gt;Google App Engine&lt;/a&gt; vyzkoušet a ejhle, už nemusím. &lt;a href="http://googleappengine.blogspot.com/2009/04/seriously-this-time-new-language-on-app.html"&gt;Google App Engine podporuje Javu a Groovy&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5959134458303152350?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5959134458303152350/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5959134458303152350' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5959134458303152350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5959134458303152350'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/04/google-app-engine-java-groovy.html' title='Google App Engine &amp; Java + Groovy'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8077883275548546607</id><published>2009-03-03T17:34:00.002+01:00</published><updated>2009-03-03T17:38:05.539+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Jak jednoduše v groovy implementovat rozhraní s jednou metodou?</title><content type='html'>Vše je až trapně jednoduché (např. &lt;code&gt;FilenameFilter&lt;/code&gt;):&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;{ dir, name -&gt; name.endsWith(".txt") } as FilenameFilter&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Miluju jednoduché věci.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8077883275548546607?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8077883275548546607/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8077883275548546607' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8077883275548546607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8077883275548546607'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/03/jak-jednoduse-v-groovy-implementovat.html' title='Jak jednoduše v groovy implementovat rozhraní s jednou metodou?'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1640156828904251077</id><published>2009-02-23T21:34:00.003+01:00</published><updated>2009-02-23T22:11:02.837+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Tapestry 5.1 - co se na nás chystá?</title><content type='html'>Pro ty co nečtou &lt;a href="http://tapestryjava.blogspot.com/"&gt;Howardův blog&lt;/a&gt;, přináším &lt;a href="http://tapestryjava.blogspot.com/2009/02/speeding-up-tapestry-51.html"&gt;odkaz&lt;/a&gt; na zajímavý příspěvek týkající se novinek, které nás čekají v oblasti výkonu v chystané verzi 5.1.&lt;br /&gt;&lt;br /&gt;Howard chystá zrychlení vykreslování stránek, především díky optimalizaci volání metod jednotlivých stavů komponent. Zrychlení se bude týkat i vytváření instancí komponent. V profileru Howard zjistil, že volání jistých metod se neustále při vytváření komponent opakuje, takže jejich vytváření bude rozděleno na dvě fáze: fáze analýzy a fáze vytváření. To pomůže stránkám s velkým množstvím komponent.&lt;br /&gt;&lt;br /&gt;A co zrychlení na klientu. Context assets (soubory uložené v kontextu aplikace) budou moci být poskytovány pomocí URL, které bude obsahovat verzi a tudíž budou moci být agresivně cachovány (dlouhá doba expirace). Dále Tapestry bude podporovat kompresi posílanáho obsahu (snížení objemu přenášených dat), navíc se chystá cachování zakompreseného obsahu na servru, čímž se ulehčí procesoru od opakované komprese.&lt;br /&gt;&lt;br /&gt;A to vše téměř bez porušení zpětné kompatibility. SUPER!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1640156828904251077?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1640156828904251077/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1640156828904251077' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1640156828904251077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1640156828904251077'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/02/tapestry-51-co-se-na-nas-chysta.html' title='Tapestry 5.1 - co se na nás chystá?'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4454057827507885858</id><published>2009-02-23T20:52:00.003+01:00</published><updated>2009-02-23T21:34:17.256+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ipod'/><title type='text'>iPod Touch - nechám si ho, je super!</title><content type='html'>Tak už i já, a to jsem tak dlouho "odolával". Ale vezmu celý příběh hezky popořadě. &lt;br /&gt;&lt;br /&gt;Na konci ledna mě zase po letech přepadla myšlenka, že nahradím svům aktuální mobil nějakým tím chytrým modelem. Samozřejmě, že první volba padla na telefon s &lt;a href="http://www.android.com/"&gt;Androidem&lt;/a&gt;. Ale pak jsem zjistil, že jediným dostupným je model &lt;a href="https://shop.client.tmo.cz/phone_details.do?phoneId=561"&gt;G1&lt;/a&gt; od T-Mobilu. Už jsem byl skoro rozhodnut, když mi kolega povídá, že by to nedělal, že to není moc hardwareově povedený mobil a že by volil raději &lt;a href="http://t-mobile.cz/Web/Residential/Telefony/Telefon.aspx/Apple/iPhone-3G-8GB/Telefon/409"&gt;iPhone&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tak jsem začal své myšlenku ubírat tímto směrem. Ovšem bál jsem se koupit si tak velký telefon, nechtěl bych takovou "plachtu" nosit všude s sebou. Takže jsem zvolil variantu zkouška. Zašel jsem na &lt;a href="http://www.aukro.cz/"&gt;aukro&lt;/a&gt; a vydražil jsem nový &lt;a href="http://www.apple.com/ipodtouch/"&gt;iPod Touch&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Je to 14 dní co jsem majitelem a jaký je závěr. Začnu negativní stránkou věci. &lt;a href="http://www.apple.com/itunes/"&gt;iTunes&lt;/a&gt; fungují pouze pod Mac Os X a Windows. A výhody? Skoro všechny audio podcasty co poslouchám, jsou na iTunes a stahují se mi přímo do iPodu automaticky (pánové z CZpodcastu, je ještě co zlepšovat). Ale co spatřuji jako opravdu skvělou věc je sledování videa. Funguje skvěle, displej je prostě super. Dále jsem se pomocí &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/3006"&gt;pluginu&lt;/a&gt; do &lt;a href="http://firefox.czilla.cz/"&gt;Firefoxu&lt;/a&gt; naučil stahovat Flashová videa ze stránek (jako &lt;a href="http://www.youtube.com/"&gt;YouTube&lt;/a&gt; a &lt;a href="http://www.infoq.com/"&gt;InfoQ&lt;/a&gt;). Ty jsem pomocí &lt;a href="http://www.videora.com/en-us/Converter/iPod/"&gt;softwaru na konvertování videa pro iPod&lt;/a&gt; zkonvertovat do MP4, které je přehratelné na iPodu. A už mám konečně čas se na tato videa podívat (dřív jsem neustále řešil, kdy se na ně kouknu -  v práci i doma to byla škoda času), protože cestou v autobuse je to docela příjemná zábava. Druhou skvělou funkčností je prohlížení webu, které přes wifi funguje opravdu super. Především čtení novinek v &lt;a href="http://www.google.com/reader/view/"&gt;Google Readeru&lt;/a&gt; je promakané na jedničku s hvězdičkou.&lt;br /&gt;&lt;br /&gt;Takže můj závěr. Jednoznačně mohu doporučit, jenom velká škoda, že iTunes nejsou i pro Linux. Ale jak dopadne rozřešení mého problému s telefonem? Asi počkám na nějaký Androidí telefon, protože iPhone bych musel jailbrakenout, abych do něj dostal všechen software co bych chtěl, což u Androidu není potřeba. Dále si spíš napíšu aplikaci pro Android než pro iPhone (jako javista).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4454057827507885858?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4454057827507885858/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4454057827507885858' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4454057827507885858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4454057827507885858'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/02/ipod-touch-necham-si-ho-je-super.html' title='iPod Touch - nechám si ho, je super!'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7982732172591709940</id><published>2009-02-04T21:40:00.005+01:00</published><updated>2009-02-04T22:14:07.779+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='bezpečnost'/><title type='text'>XSS, XSRF - o bezpečnosti je potřeba neustále mluvit a o webu to platí dvojnásob</title><content type='html'>A já jsem si toto téma oživil pomocí prezentace Jeffa Williamse publikovanou na &lt;a href="http://www.infoq.com/"&gt;InfoQ&lt;/a&gt;: &lt;a href="http://www.infoq.com/presentations/Security-Attacks-Jeff-Williams"&gt;Stopping Attacks in a Web 2.0 World&lt;/a&gt;. Velmi povedená prezentace zaměřená na &lt;a href="http://www.owasp.org/index.php/Cross-site_Scripting_(XSS)"&gt;XSS&lt;/a&gt; a &lt;a href="http://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)"&gt;XSRF&lt;/a&gt; (nenechme se zmát názvem prezentace, příklady v ní uvedené se nijak nevážou pouze na Web 2.0 aplikace). Velmi podstatnou součástí prezentace jsou příklady použití těchto útoků. Čeho se dá dosáhnout pomocí XSS je až neuvěřitelné (přiznám se, že mi skoro běhal mráz po zádech).&lt;br /&gt;&lt;br /&gt;XSRF je novější než XSS, obrana proti němu je relativně náročná (jedinou možností je posílání serverem generovaného tokenu s každým requestem na aplikaci). Zneužití je komplikovanější, protože se útočník nemůže dostat k response, kterou server poslal.&lt;br /&gt;&lt;br /&gt;Co se XSS týče, jedná se o velmi starý druh útoku, který se neustále vyvíjí (přicházejí nové a nové nápady, jak útok zamaskovat, aby nebyl odhalen). Podíváme-li se na &lt;a href="http://ha.ckers.org/"&gt;ha.ckers.org&lt;/a&gt; na &lt;a href="http://ha.ckers.org/xss.html"&gt;příklady XSS útoků&lt;/a&gt;, pak u řady z nich nechápu, jak se dají použít. Např. útoky pomocí zakódování textu do &lt;a href="http://en.wikipedia.org/wiki/Base64"&gt;Base64&lt;/a&gt; vypadají opravdu nevinně. Nebezpečnost XSS je opravdu velmi vysoká. Obrana je opět relativně prostá, validace jakéhokoliv textu, který do aplikace přichází pomocí whitelistu (tj. pomocí povolených znaků). Nejedná se jenom o data z formulářů, ale i o hidden fieldy, cookies i hlavičky HTTP protokolu.&lt;br /&gt;&lt;br /&gt;Kdo se chce dozvědět více, především ohledně popisu útoků, pak nechť použije již zmíněný &lt;a href="http://ha.ckers.org/"&gt;ha.ckers.org&lt;/a&gt;, který je velmi vyčerpávající (z hlediska příkladů utoků). Druhým výborným zdrojem je &lt;a href="http://www.owasp.org/"&gt;owasp.org&lt;/a&gt;, který je (dle mého soudu) lépe přístupný z hledika podání informací jednoduchou a čitelnou formou. Popisy zde poskytují i návrhy ochrany, případně postupy pro review aplikace z pohledu odolnosti oproti útokům.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7982732172591709940?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7982732172591709940/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7982732172591709940' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7982732172591709940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7982732172591709940'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/02/xss-xsrf-o-bezpecnosti-je-potreba.html' title='XSS, XSRF - o bezpečnosti je potřeba neustále mluvit a o webu to platí dvojnásob'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-359060466203048526</id><published>2009-01-29T10:02:00.002+01:00</published><updated>2009-01-29T10:10:45.788+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Porovnání jQuery a Prototype (odkaz)</title><content type='html'>Právě jsem si přečetl velmi zajímavé porovnání dvou populárních JavaScriptových knihoven &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; a &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; od Glenna Vanderburga pod názvem &lt;a href="http://blog.thinkrelevance.com/2009/1/12/why-i-still-prefer-prototype-to-jquery"&gt;Why I still prefer Prototype to jQuery&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Text je psaný velmi seriózně, žádné pocity, subjektivní dojmy, ale holá fakta, proto je, dle mého soudu, hodně cenný a zajímavý.&lt;br /&gt;&lt;br /&gt;Co se mě a JavaScriptu týče používám jQuery, ale je pravda, že převážně na manipulaci s DOMem, což je jeho silná stránka oproti Prototype. A navíc jsem měl kliku, že jsem nepotřeboval zatím nic, co se v jQuery jeví jako problematické. Každopádně se budu muset na Prototype podívat blížeji.&lt;br /&gt;&lt;br /&gt;Hezké počteníčko&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-359060466203048526?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/359060466203048526/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=359060466203048526' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/359060466203048526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/359060466203048526'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/porovnani-jquery-prototype-odkaz.html' title='Porovnání jQuery a Prototype (odkaz)'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7865330576084657987</id><published>2009-01-21T20:51:00.002+01:00</published><updated>2009-01-21T21:25:54.608+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Moduly pro Tapestry 5</title><content type='html'>Poslouchat &lt;a href="http://www.javaposse.com/"&gt;Java Posse&lt;/a&gt; se vyplácí. Dozvěděl jsem se o projektu &lt;a href="http://www.chenillekit.org/"&gt;Chenille Kit&lt;/a&gt;, který nabízí poměrně velké množství komponent a služeb, které jsou založené na &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-ioc/"&gt;Tapestry IoC&lt;/a&gt;, tj. služby jsou použitelné i mimo &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;K dispozici jsou následující moduly:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Access&lt;/b&gt; - pro řízení přístupu ke stránkám aplikace&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Google&lt;/b&gt; - přístup ke službácm Google (např. geocoding)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Hibernate&lt;/b&gt; - zjednodušení práce s &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Hivemind&lt;/b&gt; - zpřístupnění komponent z &lt;a href="http://hivemind.apache.org/"&gt;Hivemindu&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Image&lt;/b&gt; - jednoduché změny velikosti obrázku&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;LDAP&lt;/b&gt; - služba na provádění dotazů do &lt;a href="http://en.wikipedia.org/wiki/LDAP"&gt;LDAP&lt;/a&gt;u&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Lucene&lt;/b&gt; - služba na indexování a vyhledávání pomocí &lt;a href="http://lucene.apache.org/java/docs/"&gt;Lucene&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Mail&lt;/b&gt; - služba na posílání mailů založená na &lt;a href="http://commons.apache.org/email/"&gt;Commons Mail&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Quartz&lt;/b&gt; - služba na plánování založená na &lt;a href="http://www.opensymphony.com/quartz/"&gt;Quartzu&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Reports&lt;/b&gt; - služba pro generování reportů pomocí &lt;a href="http://jasperforge.org/plugins/project/project_home.php?group_id=102"&gt;JasperReports&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Scripting&lt;/b&gt; - služba na plánování založená na &lt;a href="http://jakarta.apache.org/bsf/index.html"&gt;BSF&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Tapestry&lt;/b&gt; - zajímavé komponenty pro Tapestry&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Templating&lt;/b&gt; - templatovací služba založena na &lt;a href="http://velocity.apache.org/"&gt;Velocity&lt;/a&gt; a &lt;a href="http://freemarker.org/"&gt;FreeMakeru&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Hodně zajímavá snůška. Ukazuje se, že Tapestry má velmi dobře udělaný design a zakomponovat do něj další služby je triviální. A množství služeb se bude jenom rozšiřovat, takže se můžeme těšit na zelené zítřky s Tapestry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7865330576084657987?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7865330576084657987/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7865330576084657987' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7865330576084657987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7865330576084657987'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/moduly-pro-tapestry-5.html' title='Moduly pro Tapestry 5'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7625435636372767719</id><published>2009-01-21T12:32:00.007+01:00</published><updated>2009-01-21T13:47:56.582+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Jak selektivně podle třídy mazat objekty z Hibernate session</title><content type='html'>Moje honba za &lt;code&gt;LazyInitializationException&lt;/code&gt; byla úspěšná (musím se přiznat, že velkým pomocníkem mi byl &lt;a href="http://www.eclipse.org/mat/"&gt;Eclipse Memory Analyzer&lt;/a&gt;, který mi pomohl zjistit, kdo se na objekt odkazuje). Problém byl v tom, že jsem chtěl vymazat objekty ze &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html"&gt;&lt;code&gt;Session&lt;/code&gt;y&lt;/a&gt;, ale protože jsem neznal jednotlivé instance, zavolal jsem metodu &lt;code&gt;clear&lt;/code&gt; a znova zaasocioval to co jsem si myslel, že je důležité (a na něco jsem samozřejmě zapomněl).&lt;br /&gt;&lt;br /&gt;V první fázi opravy chyby jsem tedy zaasocioval i další objekty a vše začalo fungovat. Pak mě ovšem postihla myšlenka, proč se mám já a můj kód, který by ideálně měl být na použitém ORM nezávislý, přizpůsobovat Hibernate. Tak jsem začal pátrat v &lt;a href="http://www.hibernate.org/hib_docs/v3/api/"&gt;javadoc&lt;/a&gt;, zda neexistuje nějaká možnost, jak zjistit jaké objekty jsou v Sessioně uložené. Pak by je stačilo selektivně odstranit pomocí metody &lt;code&gt;evict&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;Odpověď zní: existuje. Session má metodu &lt;code&gt;getStatistics&lt;/code&gt;, která vrací &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/stat/SessionStatistics.html"&gt;&lt;code&gt;SessionStatistics&lt;/code&gt;&lt;/a&gt;. Ten nám umožní zjistit jaké kolekce a jaké entity (včetně jejich identifikátoru) máme v sessioně uloženy. Takže stačí projít tyto údaje a v klidu vymazat co potřebujeme. Napsal jsem na to takovou drobnou třídu:&lt;br /&gt;&lt;tt class="java"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.ArrayList;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.Arrays;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.List;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.SortedSet;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.TreeMap;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;java.util.TreeSet;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.apache.commons.logging.Log;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.apache.commons.logging.LogFactory;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.hibernate.HibernateException;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.hibernate.Session;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.hibernate.engine.CollectionKey;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.hibernate.engine.EntityKey;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;org.hibernate.stat.SessionStatistics;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;cz.svt.util.Tuple;&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;import &lt;/span&gt;&lt;span class="java10"&gt;cz.svt.util.Tuple2;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;* This class is capable to print the summary of Hibernate cache content and also is able to evict objects from cache.&lt;br /&gt;&amp;#xA0;*/&lt;br /&gt;&lt;/span&gt;&lt;span class="java4"&gt;public class &lt;/span&gt;&lt;span class="java10"&gt;HibernateCachceEvicter &lt;/span&gt;&lt;span class="java8"&gt;{&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/** The Hibernate session. */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;protected &lt;/span&gt;&lt;span class="java10"&gt;Session session;&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;protected static final &lt;/span&gt;&lt;span class="java10"&gt;Log log = LogFactory.getLog&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;HibernateCachceEvicter.&lt;/span&gt;&lt;span class="java4"&gt;class&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Creates the empty evicter.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java10"&gt;HibernateCachceEvicter&lt;/span&gt;&lt;span class="java8"&gt;() {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;super&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Creates the evicter and sets the transaction.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;session The session&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java10"&gt;HibernateCachceEvicter&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Session session&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;super&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; setSession&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;session&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Sets the Hibernate session. &lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;session The session&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java10"&gt;HibernateCachceEvicter setSession&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Session session&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;this&lt;/span&gt;&lt;span class="java10"&gt;.session = session&lt;/span&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;return this&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Prints the content of the Hibernate cache grouped by the collections role and entity name.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@return &lt;/span&gt;&lt;span class="java14"&gt;The cache content, first is entities and second collections&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java10"&gt;Tuple2&amp;lt;TreeMap&amp;lt;String, Counter&amp;gt;, TreeMap&amp;lt;String, Counter&amp;gt;&amp;gt; logCacheContent&lt;/span&gt;&lt;span class="java8"&gt;() {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;if &lt;/span&gt;&lt;span class="java8"&gt;((&lt;/span&gt;&lt;span class="java10"&gt;session != &lt;/span&gt;&lt;span class="java4"&gt;null&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java10"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;log.isInfoEnabled&lt;/span&gt;&lt;span class="java8"&gt;())) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;try &lt;/span&gt;&lt;span class="java8"&gt;{&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;SessionStatistics statistics = session.getStatistics&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; TreeMap&amp;lt;String, Counter&amp;gt; entities = &lt;/span&gt;&lt;span class="java4"&gt;new &lt;/span&gt;&lt;span class="java10"&gt;TreeMap&amp;lt;String, Counter&amp;gt;&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Object key : statistics.getEntityKeys&lt;/span&gt;&lt;span class="java8"&gt;())&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;getCounter&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;entities, &lt;/span&gt;&lt;span class="java8"&gt;((&lt;/span&gt;&lt;span class="java10"&gt;EntityKey&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;.getEntityName&lt;/span&gt;&lt;span class="java8"&gt;())&lt;/span&gt;&lt;span class="java10"&gt;.inc&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; TreeMap&amp;lt;String, Counter&amp;gt; collections = &lt;/span&gt;&lt;span class="java4"&gt;new &lt;/span&gt;&lt;span class="java10"&gt;TreeMap&amp;lt;String, Counter&amp;gt;&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Object key : statistics.getCollectionKeys&lt;/span&gt;&lt;span class="java8"&gt;())&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;getCounter&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;collections, &lt;/span&gt;&lt;span class="java8"&gt;((&lt;/span&gt;&lt;span class="java10"&gt;CollectionKey&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;.getRole&lt;/span&gt;&lt;span class="java8"&gt;())&lt;/span&gt;&lt;span class="java10"&gt;.inc&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;The hibernate cache contains &amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ statistics.getEntityCount&lt;/span&gt;&lt;span class="java8"&gt;() &lt;/span&gt;&lt;span class="java10"&gt;+ &lt;/span&gt;&lt;span class="java5"&gt;&amp;#34; entities.&amp;#34;&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;String key : entities.keySet&lt;/span&gt;&lt;span class="java8"&gt;())&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;&amp;#xA0; &amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ key + &lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;=&amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ entities.get&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;.getValue&lt;/span&gt;&lt;span class="java8"&gt;())&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;The hibernate cache contains &amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ statistics.getCollectionCount&lt;/span&gt;&lt;span class="java8"&gt;() &lt;/span&gt;&lt;span class="java10"&gt;+ &lt;/span&gt;&lt;span class="java5"&gt;&amp;#34; collections.&amp;#34;&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;String key : collections.keySet&lt;/span&gt;&lt;span class="java8"&gt;())&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;&amp;#xA0; &amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ key + &lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;=&amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ collections.get&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;.getValue&lt;/span&gt;&lt;span class="java8"&gt;())&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;return &lt;/span&gt;&lt;span class="java10"&gt;Tuple.newTuple&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;entities, collections&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;} &lt;/span&gt;&lt;span class="java4"&gt;catch &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;HibernateException e&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;log.warn&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;Exception during walking through Hibernate cache to log its content&amp;#34;&lt;/span&gt;&lt;span class="java10"&gt;, e&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; }&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;return &lt;/span&gt;&lt;span class="java10"&gt;Tuple.newTuple&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;null, &lt;/span&gt;&lt;span class="java4"&gt;null&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Returns the counter from the map. If there is no such counter yet, creates new one and put it into map.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;map The map&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;key The key&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@return &lt;/span&gt;&lt;span class="java14"&gt;The counter&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;protected &lt;/span&gt;&lt;span class="java10"&gt;Counter getCounter&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;TreeMap&amp;lt;String, Counter&amp;gt; map, String key&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;Counter counter = map.get&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;if &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;counter == &lt;/span&gt;&lt;span class="java4"&gt;null&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java10"&gt;map.put&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key, counter = &lt;/span&gt;&lt;span class="java4"&gt;new &lt;/span&gt;&lt;span class="java10"&gt;Counter&lt;/span&gt;&lt;span class="java8"&gt;())&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;return &lt;/span&gt;&lt;span class="java10"&gt;counter;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Evicts the object of the specified classes from Hibernate cache.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;classNames The array of the classNames to evict from cache&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java9"&gt;void &lt;/span&gt;&lt;span class="java10"&gt;evictFromCache&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;String... classNames&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;evictFromCache&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java4"&gt;new &lt;/span&gt;&lt;span class="java10"&gt;TreeSet&amp;lt;String&amp;gt;&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Arrays.asList&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;classNames&lt;/span&gt;&lt;span class="java8"&gt;)))&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Evicts the object of the specified classes from Hibernate cache.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@param &lt;/span&gt;&lt;span class="java14"&gt;classNames The sorted set of the classNames to evict from cache&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java9"&gt;void &lt;/span&gt;&lt;span class="java10"&gt;evictFromCache&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;SortedSet&amp;lt;String&amp;gt; classNames&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;if &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;session == &lt;/span&gt;&lt;span class="java4"&gt;null&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java4"&gt;return&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;Cache before evicting:&amp;#34;&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; TreeMap&amp;lt;String, Counter&amp;gt; entities = logCacheContent&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;.getV1&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;try &lt;/span&gt;&lt;span class="java8"&gt;{&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java9"&gt;int &lt;/span&gt;&lt;span class="java10"&gt;entitiesToEvictCount = &lt;/span&gt;&lt;span class="java7"&gt;0&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;String key : entities.keySet&lt;/span&gt;&lt;span class="java8"&gt;())&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;if &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;classNames.contains&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)) &lt;/span&gt;&lt;span class="java10"&gt;entitiesToEvictCount += entities.get&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;key&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;.getValue&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; List&amp;lt;Object&amp;gt; entitiesToEvict = &lt;/span&gt;&lt;span class="java4"&gt;new &lt;/span&gt;&lt;span class="java10"&gt;ArrayList&amp;lt;Object&amp;gt;&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;entitiesToEvictCount&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Object key : session.getStatistics&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;.getEntityKeys&lt;/span&gt;&lt;span class="java8"&gt;()) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;EntityKey eKey = &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;EntityKey&lt;/span&gt;&lt;span class="java8"&gt;) &lt;/span&gt;&lt;span class="java10"&gt;key;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;if &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;classNames.contains&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;eKey.getEntityName&lt;/span&gt;&lt;span class="java8"&gt;()))&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;entitiesToEvict.add&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;session.load&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;eKey.getEntityName&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;, eKey.getIdentifier&lt;/span&gt;&lt;span class="java8"&gt;()))&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;for &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;Object entityToEvict : entitiesToEvict&lt;/span&gt;&lt;span class="java8"&gt;)&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;session.evict&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;entityToEvict&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; log.warn&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;Evicted &amp;#34; &lt;/span&gt;&lt;span class="java10"&gt;+ entitiesToEvictCount + &lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;entities.&amp;#34;&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;} &lt;/span&gt;&lt;span class="java4"&gt;catch &lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java10"&gt;HibernateException e&lt;/span&gt;&lt;span class="java8"&gt;) {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;log.warn&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;Exception during evicting objects from cache&amp;#34;&lt;/span&gt;&lt;span class="java10"&gt;, e&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;log.info&lt;/span&gt;&lt;span class="java8"&gt;(&lt;/span&gt;&lt;span class="java5"&gt;&amp;#34;Cache after evicting:&amp;#34;&lt;/span&gt;&lt;span class="java8"&gt;)&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; logCacheContent&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; * This class is counter.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;protected static class &lt;/span&gt;&lt;span class="java10"&gt;Counter &lt;/span&gt;&lt;span class="java8"&gt;{&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/** The value of the counter. */&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java9"&gt;int &lt;/span&gt;&lt;span class="java10"&gt;value;&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Creates the counter a resets the value.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java10"&gt;Counter&lt;/span&gt;&lt;span class="java8"&gt;() {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;super&lt;/span&gt;&lt;span class="java8"&gt;()&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;value = &lt;/span&gt;&lt;span class="java7"&gt;0&lt;/span&gt;&lt;span class="java10"&gt;;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Increments the value of the counter.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java9"&gt;void &lt;/span&gt;&lt;span class="java10"&gt;inc&lt;/span&gt;&lt;span class="java8"&gt;() {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java10"&gt;value++;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java14"&gt;/**&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; * Returns the value.&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; * &lt;/span&gt;&lt;span class="java11"&gt;@return &lt;/span&gt;&lt;span class="java14"&gt;The actual counter value&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; */&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;public &lt;/span&gt;&lt;span class="java9"&gt;int &lt;/span&gt;&lt;span class="java10"&gt;getValue&lt;/span&gt;&lt;span class="java8"&gt;() {&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java4"&gt;return &lt;/span&gt;&lt;span class="java10"&gt;value;&lt;br /&gt;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0;&amp;#xA0; &lt;/span&gt;&lt;span class="java8"&gt;}&lt;br /&gt;&lt;br /&gt;&amp;#xA0;&amp;#xA0; }&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;Zajímavé je metoda &lt;code&gt;evictFromCache&lt;/code&gt;, která provádí mazání objektů ze sessiony. Nejprve si pomocí &lt;code&gt;logCacheContent&lt;/code&gt; vypíšu obsah cache (seskupený podle tříd) před mazáním. Pak si zjistím kolik instancí budu mazat (podle výstupu z vypsání obsahu sessiony) a vytvořím patřičně veliké pole. Následuje procházení sessiony a pokud narazím na třídu, kterou chci vymazat, podle identifikátoru instance ji natáhnu metodou &lt;code&gt;load&lt;/code&gt; a vložím do pole. Teprve poté je mažu (byl jsem línej, zkoušet, zda by se to nějak nepralo, kdybych zároveň procházel obsah sessiony a zároveň z ní mazal). Na závěr si jenom pro porovnání udělám výpis obsahu po mazání.&lt;br /&gt;&lt;br /&gt;Protože nechci mít v kódu odkaz na takovou ošklivou Hibernatí záležitost, udělal jsem si jednoduchý aspect, který mi na požadovaná místa dotlačí vymazání instancí patřičných tříd.&lt;br /&gt;&lt;br /&gt;Předpokládám, že to již někdo řešil, ale pokud to někomu pomůže, pak jen berte inspiraci.&lt;br /&gt;&lt;br /&gt;PS. Třídu &lt;code&gt;Counter&lt;/code&gt; jsem v příkladu nechal jenom pro úplnost.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7625435636372767719?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7625435636372767719/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7625435636372767719' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7625435636372767719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7625435636372767719'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/jak-selektivn-podle-tdy-mazat-objekty-z.html' title='Jak selektivně podle třídy mazat objekty z Hibernate session'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8289163484390657556</id><published>2009-01-17T21:35:00.003+01:00</published><updated>2009-01-17T23:39:06.331+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='testování'/><title type='text'>Parametrizované testy v TestNG</title><content type='html'>Jak už jsem &lt;a href="http://jirablog.blogspot.com/2008/06/on-se-jeste-pouziva-junit-vzdyt-mame.html"&gt;psal dříve&lt;/a&gt;, jako testovací framework používáme &lt;a href="http://testng.org/"&gt;TestNG&lt;/a&gt;. A protože jsem se konečně dostal ke knize &lt;a href="http://www.amazon.com/Next-Generation-Java-Testing-Advanced/dp/0321503104/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1232225831&amp;sr=8-1"&gt;Next Generation Java Testing: TestNG and Advanced Concepts&lt;/a&gt; od autora TestNG, &lt;a href="http://beust.com/"&gt;Cédrica Beusta&lt;/a&gt;, mohu se s vámi podělit o novinky, které jsem načerpal (každopádně ta kniha stojí za přečtení, zabývá se totiž nejen unitovým testováním).&lt;br /&gt;&lt;br /&gt;Jak jsem již naznačil v minulém textu, hlavní výhodou, kterou vidím, jsou data providery. Proč se tedy tento článek nejmenuje data providery v TestNG? Protože jsem se dozvěděl i o jiné možnosti parametrizace testů v TestNG. Jedná se o factories (český název továrny mi nepřijde tak jasný), které jsou podobné parametrům v &lt;a href="http://www.junit.org/"&gt;jUnitu 4&lt;/a&gt;. Takže jak to funguje (příklad je lepší než 1000 slov, opráším příklad z minulého článku):&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class SquareTest {&lt;br /&gt;&lt;br /&gt;  private Calculator calculator = new Calculator();&lt;br /&gt;  private int param;&lt;br /&gt;  private int result;&lt;br /&gt;&lt;br /&gt;  @Factory&lt;br /&gt;  public static Object[] create() {&lt;br /&gt;    return new Object[] { new SquareTest(0, 0), &lt;br /&gt;      new SquareTest(1, 1), new SquareTest(2, 4), new SquareTest(4, 16) };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public SquareTest(int param, int result) {&lt;br /&gt;    this.param = param;&lt;br /&gt;    this.result = result;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void square() {&lt;br /&gt;    calculator.square(param);&lt;br /&gt;    assertEquals(result, calculator.getResult());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Na první pohled je rozdíl oproti jUnit velmi malý (pomineme-li míň anotací a jejich jiná jména). Nevracíme paramtery, ale již vytvořené instance tříd. Jaká je v tom výhoda? Factory metoda může vracet instance jakýchkoliv tříd, nejenom té ve které je definovaná. Tyto třídy mohou obsahovat nejenom testovací metody (označené anotací &lt;code&gt;@Test&lt;/code&gt;) a i factory metody. Je to o hodně flexibilnější.&lt;br /&gt;&lt;br /&gt;A proč TestNG podporuje jak factory metody tak data providery, když de facto realizují totéž? Protože pokud parametry využijeme u většiny testovacích metod v třídě, je pohodlnější je předat pomocí konstruktoru z factory metody. Data providery se hodí, pokud potřebujeme více skupin dat pro různé testovací metody. A samozřejmě nic nám nebrání obě věci kombinovat.&lt;br /&gt;&lt;br /&gt;Na závěr jsem si nechal dotažení konceptu data provideru k dokonalosti. Co když chceme zavolat testovací metodu hodně krát, opravdu hodně hodně moc krát. Pak asi není ideální vytvořit všechny parametry dopředu, vložit je do dvourozměrného pole a vrátit z data provideru, to zblajzne moc paměti. Jak tedy na to? Data provider bude místo &lt;code&gt;Object[][]&lt;/code&gt; vracet &lt;code&gt;Iterator&lt;/code&gt;, jehož metoda &lt;code&gt;next()&lt;/code&gt; vrátí jednorozměrné pole s hodnotami parametrů.&lt;br /&gt;&lt;br /&gt;Pokud jsem vás stále nepřesvědčil, že TestNG stojí za zkoušku, pak to jistě zkusím zase příště.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8289163484390657556?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8289163484390657556/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8289163484390657556' title='Počet komentářů: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8289163484390657556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8289163484390657556'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/parametrizovane-testy-v-testng.html' title='Parametrizované testy v TestNG'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-3055879494307373649</id><published>2009-01-14T21:30:00.004+01:00</published><updated>2009-01-14T22:22:37.009+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>ORM mých snů - iBatis 3</title><content type='html'>Všechny velké zajímavé projekty aplikací, na kterých jsem se podílel jako &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt; používali &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;. Přiznám se, že jsem byl tímto frameworkem zpočátku nadšen. Pak moje nadšení trochu ochablo, ale verze 3 zase přinesla vylepšení, která jsem kvitoval (především z hlediska mapování).&lt;br /&gt;&lt;br /&gt;Postupem času, ale čím dál tím víc cítím, že Hibernate (a v podstatě jakýkoliv &lt;a href="http://java.sun.com/developer/technicalArticles/J2EE/jpa/"&gt;JPA&lt;/a&gt; framework) není to pravé ořechové. Proč? &lt;br /&gt;&lt;br /&gt;Nelíbí se mi, že je velmi těžké se z DataTypu dostat na connection, což je potřeba např. pro uložení XML do DB přes datový typ &lt;a href="http://java.sun.com/javase/6/docs/api/java/sql/SQLXML.html"&gt;SQLXML&lt;/a&gt;, který je nutno vytvářet pomocí metody &lt;a href="http://java.sun.com/javase/6/docs/api/java/sql/Connection.html#createSQLXML()"&gt;createSQLXML&lt;/a&gt; objectu &lt;a href="http://java.sun.com/javase/6/docs/api/java/sql/Connection.html"&gt;Connection&lt;/a&gt;. O tom, že tuto instanci musím po provedení dotazu zase uvolnit pomocí její metody &lt;a href="http://java.sun.com/javase/6/docs/api/java/sql/SQLXML.html#free()"&gt;free&lt;/a&gt; ani nemluvě.&lt;br /&gt;&lt;br /&gt;Dále se mi nelíbí, že nemám plně pod kontrolou SQL dotazy (jsou generovány z HQL), tj. případná optimalizace dotazů není úplně triviální. Samozřejmě je možné si vyžádat od Hibernate spojení a provést dotaz ručně, ale metoda &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#connection()"&gt;connection&lt;/a&gt; objektu &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html"&gt;Session&lt;/a&gt; je deprecated, tak nevím jak to bude v Hibernate 4.&lt;br /&gt;&lt;br /&gt;Šíleně mě začíná obtěžovat cache natažených objektů, Session. Pokud provádím nějaké batchové operace, které manipulují s velkým množstvím objektů (desetisíce), pak je problém jak to celé výkonově optimalizovat. Je nutné průběžně dělat commit, session vyclearovat a znova zaasociovat všechny objekty, které budu potřebovat. Nejen je to pracné, ale velmi často dohledávám původce nějaké &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/LazyInitializationException.html"&gt;LazyInitializationException&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Ale co jiného, co lepšího. Vždy jsem pokukoval po &lt;a href="http://ibatis.apache.org/"&gt;iBatisu&lt;/a&gt;. Zkoušel jsem jej, ale něco mi vždy řeklo, že to nějak s Hibernate zmáknu (přeci jenom ten framework znám a málo co mě při práci s ním překvapí). Ale &lt;a href="http://opensource.atlassian.com/confluence/oss/display/IBATIS/iBATIS+3.0+Whiteboard"&gt;návrh na verzi 3&lt;/a&gt;, který se mi dostal pod ruku mě nadchl. Proč?&lt;br /&gt;&lt;br /&gt;Šíleně se mi zalíbila myšlenka definice rozhraní, které se zove Mapper, ale de facto je to DAO. Implementaci vytvoří iBatis sám. Např: &lt;pre&gt;&lt;code&gt;public interface EmployeeMapper {&lt;br /&gt;  Employee getEmployee (int employeeId);&lt;br /&gt;  List&lt;Employee&gt; listAllEmployees();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Navíc se případné anotace, jak mapovat budou umísťovat do tohoto rozhraní a ne do modelu (jsem absolutním nepřítelem anotování modelu anotacemi pro DAO vrstvu).&lt;br /&gt;&lt;br /&gt;Dále se mi zalíbila představa generování dynamických SQL dotazů pomocí DSL v Javě. Obávám se, že to není správný přístup. SQL by mělo být mimo aplikaci, takže v XML. Ale myšlenka je to jistě zajímavá.&lt;br /&gt;&lt;br /&gt;Teď už nezbývá nic jiného než se těšit jak to celé dopadne.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-3055879494307373649?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/3055879494307373649/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=3055879494307373649' title='Počet komentářů: 10'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3055879494307373649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3055879494307373649'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/orm-mych-snu-ibatis-3.html' title='ORM mých snů - iBatis 3'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-423432838592731467</id><published>2009-01-13T21:21:00.003+01:00</published><updated>2009-01-13T21:33:29.103+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='výkon'/><category scheme='http://www.blogger.com/atom/ns#' term='databáze'/><title type='text'>Optimalizace výkonu databáze DB2 - db2top utility</title><content type='html'>Jak optimalizovat výkon databáze? Těžko. Jak optimalizovat výkon databáze DB2? Také těžko. Nebo ne?&lt;br /&gt;&lt;br /&gt;Tak těď už to neplatí, alespoň si to myslím. Ještě jsem nově objevenou utilitku &lt;a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/com.ibm.db2.luw.admin.cmd.doc/doc/r0025222.html"&gt;db2top&lt;/a&gt; nezkoušel v případě nouze, ale podle popisu a prvního vyzkoušení je hodně mocná.&lt;br /&gt;&lt;br /&gt;Dříve jsem k monitoringu databáze využíval pár utilit operačního systému (v Linuxu např. ps, iostat) a pak řadu nástrojů databáze (např. monitory, snapshoty). db2top integruje všechny tyto schopnosti do jednoho programu. &lt;br /&gt;&lt;br /&gt;Utilitky umí pracovat nejenom v interaktivním režimu, ale i v režimu záznamu a následného vyhodnocení. Dokonce je možné hodnoty exportovat do csv a následně importovat např. do Excelu (já používám OpenOffice) a vytvářet grafy.&lt;br /&gt;&lt;br /&gt;Koho jsem nalákal rozhodně doporučuji přečíst si &lt;a href="http://www.ibm.com/developerworks/data/library/techarticle/dm-0812wang/"&gt;DB2 problem determination using db2top utility&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-423432838592731467?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/423432838592731467/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=423432838592731467' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/423432838592731467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/423432838592731467'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/optimalizace-vykonu-databaze-db2-db2top.html' title='Optimalizace výkonu databáze DB2 - db2top utility'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4729454347665676115</id><published>2009-01-12T20:49:00.005+01:00</published><updated>2009-01-12T21:20:22.013+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Java 7 - máme se na co těšit</title><content type='html'>Máme zde nový rok 2009 a první téma v novém roce nemůže patřit ničemu jinému než nově přicházející Javě - tj. Javě 7. Dostalo se ke mně pár zajímavých informací, které oblažily mé srdíčko.&lt;br /&gt;&lt;br /&gt;Za prvé: Java Modularity mimo jiné nahradí classpath (také proto, že nepodporuje více verzí jedné knihovny). Konečně se zbavíme classpath: skutečnosti, které přinášela jenom starosti a žádné slasti. Každopádně, kdo kdy řešil nějaký problém spojený classpath, především na serveru je to lahůdka, pak jistě zaplesá.&lt;br /&gt;&lt;br /&gt;Za druhé: closures se odkládají. Další moudré rozhodnutí (představení closures vyvolalo velké množství debat). Vzniklo více návrhů a není jasné, který je nejlepší. Proto oddálení uvedení této featurky je rozumné, uvidíme zda je budeme v budoucnu potřebovat (v Javě 7 budou změny podporující dynamické jazyky, jejichž existence možná tuto potřebu zašlape do země).&lt;br /&gt;&lt;br /&gt;Věřím, že vás tyto informace potěší alespoň tak, jak potěšili mě. A když to tak náhodnou zase nedopadne, pak se nebojme, chleba kvůli tomu dražší nebude. Rozhodně vám přeji vše nej... do nového roku.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4729454347665676115?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4729454347665676115/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4729454347665676115' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4729454347665676115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4729454347665676115'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2009/01/java-7-mame-se-na-co-tesit.html' title='Java 7 - máme se na co těšit'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7575295392712930028</id><published>2008-12-10T20:11:00.005+01:00</published><updated>2008-12-10T21:51:06.845+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Překlad výjímek z databáze při použití Hibernate</title><content type='html'>Kdo používá &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;, ten možná již tuší, kam budu dnešním příspěvkem mířit. Jde o to, že chyby, které detekuje Hibernate se snaží do výjimky dávat jméno třídy a atributu, který chybu vyvolal. Ovšem pokud vám chybu vyhodí databáze, pak vás Hibernate nechá ve štichu a předhodí vám výjimku datábáze a dělejte si s ní co chcete.&lt;br /&gt;&lt;br /&gt;Toto chování se mi nikdy nelíbilo, protože mu moc nerozumím, Hibernate má vše co potřebuje. Zná dialekt, který by umožnil překlad databázově závislých výjimek, do obecné formy obsahující jméno tabulky a názvy sloupců. Následně je možné využít mapování a přeložit název tabulky a názvy sloupců na jméno třídy a atributů. Proč to Hibernate nedělá? Nevím ...&lt;br /&gt;&lt;br /&gt;My jsme vždy chtěli mít vlastní DAO výjimky, které by byly nezávislé na použitém ORM. A zároveň jsme chtěli aby obsahovaly jméno třídy a atributů. Nikoliv tabulky a sloupce, protože tyto výjimky jsou většinou zpracovávány vrstvami aplikace, které o databázi nemají mít nejmenší tušení. &lt;br /&gt;&lt;br /&gt;Řešení jsme měli, ale nelíbilo se nám, protože jsme de facto museli mapování zapisovat dvakrát (jednou z objektů do relací pro Hibernate a podruhé z relací do objektů). Dodnes nevím proč nejsou programátorsky přístupné mapovací soubory, nebo nevím jak je z Hibernate dostat, což jsme chtěli pro překlad sloupců na atributy použít. Občas jsme diskutovali co s tím, ale ne a ne přijít na ten správný nápad. Až takhle jednou jdeme z oběda a s kolegou Lubošem jsme si dali brain storming a triviální řešení jsme našli (nechápu jak to, že nás nenapadlo dřív).&lt;br /&gt;&lt;br /&gt;Je až trapně triviální. Stačí si rozparsovat Hibernate mapovací soubory a vytvořit z nich mapování opačné, než jaké reprezentují. Tato akce představuje nesložitý algoritmus, jedinou složitostí je dědičnost, kde je nutno vytvořit vhodnou reprezentaci, aby se při zpětném překladu zvolilo správné jméno třídy (to nejkonkrétnější), v případě překladu více atributů umístěných různě hluboko v hierarchii tříd. &lt;br /&gt;&lt;br /&gt;Druhým krokem je vytažení informace z &lt;a href="http://java.sun.com/javase/6/docs/api/java/sql/SQLException.html"&gt;SQLException&lt;/a&gt;, kterou vyhodí databáze. Zde je pár drobných oříšků, např. získání jmen sloupců v případě chyby unikátního klíče (námi použitá DB2 vrátí jméno unikátního klíče, které je nutno pomocí katalogu překlopit na jména sloupců).&lt;br /&gt;&lt;br /&gt;Takže cca. po 3 dnech programování (nejprve jsem si dělal prototyp v groovy a pak jsem vytvořil kompletní implementaci v javě) máme řešení, se kterým jsme maximálně spokojeni. Stačí nám zapisovat Hibernate mapování a kód za nás udělá zbytek. My pak už pouze zachytáváme např. DARequiredException, která obsahuje jméno objektu a jeho atributu.&lt;br /&gt;&lt;br /&gt;PS. Kód jsem neuváděl, protože není složitý, akorát ho je poměrně dost, takže by se velmi pravděpodobně jednoduchost sdělení hodně zkomplikovala.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7575295392712930028?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7575295392712930028/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7575295392712930028' title='Počet komentářů: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7575295392712930028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7575295392712930028'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/12/preklad-vyjimek-z-databaze-pri-pouziti.html' title='Překlad výjímek z databáze při použití Hibernate'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2633052366476622569</id><published>2008-12-01T20:40:00.002+01:00</published><updated>2008-12-01T21:53:16.590+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='testování'/><title type='text'>Lze testovat aplikaci, která s tím nepočítá</title><content type='html'>Motivací pro dnešní psaní je &lt;a href="http://java.cz/detail.do?articleId=13277"&gt;28 czpodcast&lt;/a&gt;. Takže zpět k titulku, jde to, ale težko a to je ten problém. Ať už je to metoda, třída, modul nebo celá aplikace, vše musí být navrženo a naimplementováno s ohledem na testovatelnost. &lt;br /&gt;&lt;br /&gt;A teď k jádru pudla. Testovatelnost UI je skoro to nejhorší. Ať je to UI webové, swingové a nebo nějaké jiné. Proč? Protože se mění. Většina změn aplikace se projeví v jeho uživatelském rozhraní. Proto se testy musí neustále měnit a modifikovat. Takže není ani tak problém v tom testy napsat, ale udržovat. &lt;br /&gt;&lt;br /&gt;Dá se z této situace nějak vybruslit? Nedá, ale dá se řada věcí eliminovat. Tím co se eliminovat dá, je skutečnost, že se rozložení prvků v uživatelském rozhraní mění. Dojde-li k takové změně, pak špatně napsaný test prvek nenajde a nebo najde špatný prvek. Je nutno prvky UI identifikovat spíš než podle umístění (ať fyzického nebo logického) identifikovat podle nějakého logického jména. Tj. ve swingu musíme komponentám dávat jména a v HTML musíme tagům, které pro nás symbolizují komponenty, dávat speciální hodnoty atributům (&lt;code&gt;id&lt;/code&gt; nebo &lt;code&gt;class&lt;/code&gt;, ale i jiné), tak abychom je v kódu stránky dokázali jednoduše najít.&lt;br /&gt;&lt;br /&gt;Pak i když s komponentami trochu hneme, tak nám to nevadí, protože podle tohoto logického názvu je vždy spolehlivě v okně nebo stránce najdeme.&lt;br /&gt;&lt;br /&gt;Takže jako musíme komponentu napsat tak, abychom ji byli schopni otestovat, musíme i UI napsat, tak abychom jej otestovali. Rozhodně si tím ušetříme spoustu času a kolikrát si testování de facto umožníme.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2633052366476622569?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2633052366476622569/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2633052366476622569' title='Počet komentářů: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2633052366476622569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2633052366476622569'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/12/lze-testovat-aplikaci-ktera-s-tim.html' title='Lze testovat aplikaci, která s tím nepočítá'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2557916124681152259</id><published>2008-11-14T10:03:00.002+01:00</published><updated>2008-11-14T10:05:12.141+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>JSF vs. Tapestry - tentokrát AJAX</title><content type='html'>Zase trochu přileju olej do ohně, tentokrát se podíváme na jednoduchý AJAX příklad. Opět začneme na blogu Jima Driscolla, který napsal &lt;a href="http://weblogs.java.net/blog/driscoll/archive/2008/11/a_simple_ajax_j.html"&gt;A simple Ajax JSF 2.0 example&lt;/a&gt;. Při pohledu na tento příklad se opět nemohu ubránit dojmu, že vývoj stránek je v JSF opravdu děs, no posuďte sami (pro jednoduchost ukazuji pouze to co je zajímavé a ne celou stránku):&lt;pre&gt;&amp;lt;h:body&amp;gt;&lt;br /&gt;    &amp;lt;h:form id="form1" prependId="false"&amp;gt;&lt;br /&gt;        &amp;lt;h:outputScript name="ajax.js" library="javax.faces" target="head"/&amp;gt;&lt;br /&gt;        &amp;lt;h:outputText id="out1" value="#{count.count}"/&amp;gt;&lt;br /&gt;        &amp;lt;br/&amp;gt;&lt;br /&gt;        &amp;lt;!-- Increment the counter on the server, and the client --&amp;gt;&lt;br /&gt;        &amp;lt;h:commandButton id="button1" value="Count"&lt;br /&gt;                         onclick="javax.faces.Ajax.ajaxRequest(this, event, {execute: this.id, render: 'out1'}); return false;"/&amp;gt;&lt;br /&gt;        &amp;lt;br/&amp;gt;&lt;br /&gt;        &amp;lt;!-- Resets the counter --&amp;gt;&lt;br /&gt;        &amp;lt;h:commandButton id="reset" value="reset"&lt;br /&gt;                            onclick="javax.faces.Ajax.ajaxRequest(this, event, {execute:'reset', render: 'out1'}); return false;"&lt;br /&gt;                            actionListener="#{count.reset}"/&amp;gt;&lt;br /&gt;    &amp;lt;/h:form&amp;gt;&lt;br /&gt;&amp;lt;/h:body&amp;gt;&lt;/pre&gt;A jak to samé uděláme v Tapestry nám ukáže Howard L. Ship na svém blogu v příspěvku &lt;a href="http://tapestryjava.blogspot.com/2008/11/tapestry-5-ajax-screencast.html"&gt;Tapestry 5 Ajax Screencast&lt;/a&gt;. Šablona bude:&lt;pre&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;t:zone t:id="output"&amp;gt;${index}&amp;lt;/t:zone&amp;gt;&lt;br /&gt;    &amp;lt;p&amp;gt;&lt;br /&gt;        &amp;lt;t:actionlink t:id="increment" zone="output"&amp;gt;increment&amp;lt;/t:actionlink&amp;gt;&lt;br /&gt;    &amp;lt;/p&amp;gt;&lt;br /&gt;    &amp;lt;p&amp;gt;&lt;br /&gt;        &amp;lt;t:actionlink t:id="reset" zone="output"&amp;gt;reset&amp;lt;/t:actionlink&amp;gt;&lt;br /&gt;    &amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;/pre&gt;A nyní přistupme k Java kódu, ten je v JSF malinko jednodušší, protože definuje pouze beanu s hodnotou počítadla:&lt;pre&gt;@ManagedBean(name = "count")&lt;br /&gt;@SessionScoped&lt;br /&gt;public class Count {&lt;br /&gt;    Integer count = 0;&lt;br /&gt;&lt;br /&gt;    public Integer getCount() {&lt;br /&gt;        return count++;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void reset(ActionEvent ae) {&lt;br /&gt;        count = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;A nyní ta "složitější" Java třída, tedy Tapestry verze:&lt;pre&gt;public class Index {&lt;br /&gt;    @Property&lt;br /&gt;    @Persist&lt;br /&gt;    private int index;&lt;br /&gt;&lt;br /&gt;    @InjectComponent&lt;br /&gt;    private Zone output;&lt;br /&gt;&lt;br /&gt;    Object onActionFromIncrement() {&lt;br /&gt;        index++;&lt;br /&gt;        return output.getBody();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    Object onActionFromReset() {&lt;br /&gt;        index = 0;&lt;br /&gt;        return output.getBody();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Navíc zde máme definováno co se má měnit po provedení AJAX requestu, toť celá komplikace navrch. &lt;br /&gt;Pro mě je to stále jasné, JSF je špatná volba proto, že je hrozně komplikované a těžko mě někdo bude přesvědčovat o opaku.&lt;br /&gt;PS. Letěl okolo mě moc hezký článek o porovnání Wicket a JSF s názvem &lt;a href="http://ptrthomas.wordpress.com/2007/05/14/a-wicket-user-tries-jsf/"&gt;A Wicket user tries JSF&lt;/a&gt;. Ukázky, které jsou tam uvedeny na mě budí dojem, že Tapestry je kombinací toho dobrého z obou těchto světů: jednoduchou Java část z JSF a jednoduché šablony z Wicket.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2557916124681152259?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2557916124681152259/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2557916124681152259' title='Počet komentářů: 13'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2557916124681152259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2557916124681152259'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/11/jsf-vs-tapestry-tentokrat-ajax.html' title='JSF vs. Tapestry - tentokrát AJAX'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1500513862389729535</id><published>2008-11-13T10:35:00.005+01:00</published><updated>2008-11-13T10:50:07.141+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Co to je čitelný kód aneb Literate Programming</title><content type='html'>Obdivuji lidi co mají tu vlastnost, že dokáží naprosto přesně vyjádřit to co ostatní jenom tuší (řada ani to ne). Teď jsem zase narazil na jednoho takového člověka, kterým je Donald E. Knuth, jenž mě dostal svým spiskem o &lt;a href="http://www.literateprogramming.com/knuthweb.pdf"&gt;Literate Programming&lt;/a&gt;. Nosnou myšlenkou, která mne zaujala je:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;Nesnažme se svým programem počítači sdělit co má dělat. Snažme se programem vysvětlit druhým programátorům, co chceme aby počítač dělal.&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;To je přeci ono. Nepíšeme program jenom proto, aby dělal co má dělat, ale také proto, aby ho dokázal někdo udržovat (to je ten člověk, kterému vysvětluje, co chceme aby počítač dělal).&lt;br /&gt;Již dlouho jsem náš vývojový proces přizpůsoboval této myšlence, možná jsem ji měl někde zakopanou v podvědomí, ale nedokázal jsem ji tak krásně vyjádřit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1500513862389729535?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1500513862389729535/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1500513862389729535' title='Počet komentářů: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1500513862389729535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1500513862389729535'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/11/co-to-je-citelny-kod-aneb-literate.html' title='Co to je čitelný kód aneb Literate Programming'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-3439383243313950968</id><published>2008-11-03T08:28:00.004+01:00</published><updated>2008-11-03T08:44:09.087+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>JSF vs. Tapestry - jak jednoduché je dělání komponent</title><content type='html'>Opět jsem narazil na velmi zajímavý blog, který porovnává složitost vytváření komponent v &lt;a href="http://blogs.jsfcentral.com/jsf2group/"&gt;JSF 2.0&lt;/a&gt; a &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry 5&lt;/a&gt; (&lt;a href="http://tapestryjava.blogspot.com/2008/11/simple-jsf-20-component-vs-tapestry.html"&gt;"Simple" JSF 2.0 Component vs. Tapetry&lt;/a&gt;). &lt;br /&gt;Samotného mě takové porovnání již dlouho zajímalo, protože jsem se o JSF přestal zajímat někdy okolo verze 1.0, přišlo mi zkrátka moc složité a komplikované. Navíc mělo veliké problémy na úrovni integrace s JSP (to už je snad minulost). Takže pokud se někdo nechce koukat na originál, pak vězte, že napsat komponentu v JSF, která vypíše text na žlutém pozadí je realizováno následující komponentou:&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;br /&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&lt;br /&gt;      xmlns:h="http://java.sun.com/jsf/html"&lt;br /&gt;      xmlns:f="http://java.sun.com/jsf/core"&lt;br /&gt;      xmlns:ui="http://java.sun.com/jsf/facelets"&lt;br /&gt;      xmlns:composite="http://java.sun.com/jsf/composite"&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;This will not be present in rendered output&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;composite:interface name="yellowOut"&lt;br /&gt;                     displayName="Very Basic Output Component"&lt;br /&gt;                     preferred="true"&lt;br /&gt;                     expert="false"&lt;br /&gt;                     shortDescription="A basic example"&amp;gt;&lt;br /&gt;    &amp;lt;composite:attribute name="value" required="false"/&amp;gt;&lt;br /&gt;&amp;lt;/composite:interface&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;composite:implementation&amp;gt;&lt;br /&gt;    &amp;lt;h:outputText value="#{compositeComponent.attrs.value}" style="background-color: yellow"/&amp;gt;&lt;br /&gt;&amp;lt;/composite:implementation&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;Uf. To je skoro jako těžká dřina. V Tapestry stačí velmi krátká třída:&lt;pre&gt;&lt;code&gt;public class Out {&lt;br /&gt;  @Property&lt;br /&gt;  @Parameter(defaultPrefix = BindingConstants.LITERAL)&lt;br /&gt;  private String value;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;A ještě kratší šablona:&lt;pre&gt;&lt;code&gt;&amp;lt;span style="background-color: yellow"&amp;gt;${value}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;Takže já mám zase jasněji v tom, co je lepší používat.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-3439383243313950968?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/3439383243313950968/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=3439383243313950968' title='Počet komentářů: 10'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3439383243313950968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3439383243313950968'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/11/jsf-vs-tapestry-jak-jednoduche-je.html' title='JSF vs. Tapestry - jak jednoduché je dělání komponent'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-3089822219603872383</id><published>2008-10-27T21:18:00.011+01:00</published><updated>2008-10-29T22:29:00.014+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>jOpenSpace 2008 - Java vs. dynamické jazyky - více návratových hodnot v Javě (aktualizováno)</title><content type='html'>&lt;span style="font-style:italic;"&gt;Opravil jsem špatně uvedenou ukázku &lt;code&gt;Tuple3&lt;/code&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;V záznamu z &lt;a href="http://jopenspace.cz/"&gt;jOpenSpace&lt;/a&gt; na téma Java vs. dynamické jazyky jsem zaznamenal postesknutí: &lt;span style="font-style:italic;"&gt;jediné co mi v Javě chybí je možnost, aby metoda měla více návratových hodnot&lt;/span&gt;. Ovšem je nutné si přiznat, že to je možné již nyní. Správný název pro objekt, který je de facto kolekcí s tou vlastností, že každý prvek je jiného typu. &lt;br /&gt;&lt;br /&gt;Simulovat tuto funkcionalitu pomocí &lt;code&gt;List&amp;lt;Object&amp;gt;&lt;/code&gt;, ale to není cesta správným směrem. Dále jsem našel knihovnu &lt;a href="http://javatuple.com/index.shtml"&gt;javatuple&lt;/a&gt;, ta se mi nelíbila, protože místo universálního slova tuple se třídy jmenují &lt;code&gt;Tuple&lt;/code&gt;, &lt;code&gt;Triple&lt;/code&gt;, ... Nakonec jsme si implementaci napsali sami, a nelitujeme.&lt;br /&gt;&lt;br /&gt;Takže třída &lt;code&gt;Tuple2&lt;/code&gt; vypydá:&lt;pre&gt;&lt;code&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&amp;lt;A,&amp;nbsp;B&amp;gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;implements&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Serializable&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;protected&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;v1;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;protected&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;B&amp;nbsp;v2;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;private&amp;nbsp;static&amp;nbsp;final&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;long&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;serialVersionUID&amp;nbsp;=&amp;nbsp;-&lt;/font&gt;&lt;font color="#000000"&gt;4987109478796050933L&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;v1,&amp;nbsp;B&amp;nbsp;v2&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;setV1&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;v1&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;setV2&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;v2&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;getV1&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;v1;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setV1&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;v1&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.v1&amp;nbsp;=&amp;nbsp;v1;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;B&amp;nbsp;getV2&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;v2;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setV2&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;B&amp;nbsp;v2&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.v2&amp;nbsp;=&amp;nbsp;v2;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;@Override&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;boolean&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;obj&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;this&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;==&amp;nbsp;obj&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;true&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;((&lt;/font&gt;&lt;font color="#000000"&gt;obj&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;||&amp;nbsp;!&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;obj&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;instanceof&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&lt;/font&gt;&lt;font color="#000000"&gt;))&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;false&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&amp;lt;?,&amp;nbsp;?&amp;gt;&amp;nbsp;other&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&amp;lt;?,&amp;nbsp;?&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;obj;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ObjectUtils.equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;getV1&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;other.getV1&lt;/font&gt;&lt;font color="#000000"&gt;())&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&amp;amp;&amp;amp;&amp;nbsp;ObjectUtils.equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;getV2&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;other.getV2&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;@Override&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;getV1&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;!=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&amp;nbsp;+=&amp;nbsp;getV1&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.hashCode&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&amp;nbsp;*=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;31&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;getV2&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;!=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&amp;nbsp;+=&amp;nbsp;getV2&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.hashCode&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;Dále následuje &lt;code&gt;Tuple3&lt;/code&gt;:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&amp;lt;A,&amp;nbsp;B,&amp;nbsp;C&amp;gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;extends&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&amp;lt;A,&amp;nbsp;B&amp;gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;protected&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;C&amp;nbsp;v3;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;private&amp;nbsp;static&amp;nbsp;final&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;long&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;serialVersionUID&amp;nbsp;=&amp;nbsp;-&lt;/font&gt;&lt;font color="#000000"&gt;4987109478796050933L&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;v1,&amp;nbsp;B&amp;nbsp;v2,&amp;nbsp;C&amp;nbsp;v3&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;v1,&amp;nbsp;v2&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;setV3&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;v3&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;C&amp;nbsp;getV3&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;v3;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setV3&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;C&amp;nbsp;v3&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.v3&amp;nbsp;=&amp;nbsp;v3;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;@Override&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;boolean&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;obj&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;this&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;==&amp;nbsp;obj&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;true&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;((&lt;/font&gt;&lt;font color="#000000"&gt;obj&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;||&amp;nbsp;!&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;obj&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;instanceof&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&lt;/font&gt;&lt;font color="#000000"&gt;))&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;false&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&amp;lt;?,&amp;nbsp;?,&amp;nbsp;?&amp;gt;&amp;nbsp;other&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&amp;lt;?,&amp;nbsp;?,&amp;nbsp;?&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;obj;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;super&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;obj&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&amp;amp;&amp;amp;&amp;nbsp;ObjectUtils.equals&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;getV3&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;other.getV3&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;@Override&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;hashCode&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;super&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.hashCode&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;31&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;+&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;((&lt;/font&gt;&lt;font color="#000000"&gt;getV3&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;==&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;?&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;0&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;:&amp;nbsp;getV3&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.hashCode&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;Kód pro &lt;code&gt;Tuple4&lt;/code&gt; je již jednoduše vytvořitelný. Zbývá vytvořit implementace až kam potřebujete (my jsme se zastavili na čísle 7). Na závěr jsem vytvořil factory objekt, aby bylo vytváření pohodlnější:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&amp;lt;A,&amp;nbsp;B&amp;gt;&amp;nbsp;Tuple2&amp;lt;A,&amp;nbsp;B&amp;gt;&amp;nbsp;newTuple&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;a,&amp;nbsp;B&amp;nbsp;b&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple2&amp;lt;A,&amp;nbsp;B&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;a,&amp;nbsp;b&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;public&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;&amp;lt;A,&amp;nbsp;B,&amp;nbsp;C&amp;gt;&amp;nbsp;Tuple3&amp;lt;A,&amp;nbsp;B,&amp;nbsp;C&amp;gt;&amp;nbsp;newTuple&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;A&amp;nbsp;a,&amp;nbsp;B&amp;nbsp;b,&amp;nbsp;C&amp;nbsp;c&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;b&gt;return&amp;nbsp;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Tuple3&amp;lt;A,&amp;nbsp;B,&amp;nbsp;C&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;a,&amp;nbsp;b,&amp;nbsp;c&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;...&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;font color="#ffffff"&gt;&lt;br /&gt;&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;Když na tuto implementaci koukám, není mi jasné proč standardní knihovna neobsahuje něco podobného. I bez podpory přímo v jazyce je to řešení použitelné.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-3089822219603872383?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/3089822219603872383/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=3089822219603872383' title='Počet komentářů: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3089822219603872383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3089822219603872383'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/jopenspace-2008-java-vs-dynamick-jazyky.html' title='jOpenSpace 2008 - Java vs. dynamické jazyky - více návratových hodnot v Javě (aktualizováno)'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5489404566373202451</id><published>2008-10-27T20:20:00.003+01:00</published><updated>2008-10-27T21:17:04.180+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='konference'/><title type='text'>Google Developer Day 2008</title><content type='html'>V pátek 24. října jsem se zúčastnil akce pořádané společností Google s názvem Google Developer Day v Hotelu Clarion ve Vysočanech. Protože mi to klasicky trvá déle než něco napíšu, pak vás mohu odkázat na Postřehy &lt;a href="http://blog.softeu.cz/byli-jsme-na-google-developer-day-2008/"&gt;Martina Hassmana&lt;/a&gt; a &lt;a href="http://blog.softeu.cz/byli-jsme-na-google-developer-day-2008/"&gt;Pavla Cvrčka&lt;/a&gt;, kteří byli rychlejší. Také jsem k celé akci přistupoval s despektem a vzhledem k naléhavosti úkolů z práce jsem se málem nezúčastnil. Ale nakonec musím říci, že mé pocity jsou podstatně pozitivnější než např. z poslední návštevy Sun Tech Days.&lt;br /&gt;&lt;br /&gt;Úvodní key note se nesla v duchu toho, že pokud bude žít web bude žít i Google. A dále uvedla do kontextu všechna témata, kterých se celý den měl týkat, tj. &lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt;, &lt;a href="http://appengine.google.com"&gt;AppEngine&lt;/a&gt;, &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;, Apps (&lt;a href="http://code.google.com/apis/ajaxsearch/"&gt;Search&lt;/a&gt;, &lt;a href="http://http://code.google.com/apis/maps/"&gt;Maps&lt;/a&gt;, &lt;a href="http://code.google.com/apis/gdata/"&gt;Data API&lt;/a&gt;, ...), &lt;a href="http://code.google.com/apis/opensocial/"&gt;OpenSocial&lt;/a&gt; a &lt;a href="http://code.google.com/android/"&gt;Android&lt;/a&gt;. Pak již paralelně probíhaly jednotlivé přednášky ve 4 sálech, v pátem se konaly workshopy a v šestém byla relax zóna. Můj vkus byl malinko jiný než ostatních, tak alespoň přispěji k zacelení mezer v popisu přednášek. &lt;br /&gt;&lt;br /&gt;Jako první jsem zvolil úvod do AppEnginu - &lt;span style="font-weight:bold;"&gt;Dive into Google App Engine&lt;/span&gt; (zvažoval jsem &lt;a href="http://code.google.com/p/v8/"&gt;JavaScriptový engine V8&lt;/a&gt;, ale nakonec jsem se rozhodl pro AppEngine, který spíš využiju). Přednáška byla nakonec tím nejzajímavějším co jsem viděl. Vždy mě trápilo, když bych chtěl psát nějakou aplikaci pro web, kde ji pustím. AppEngine je odpovědí na tyto starosti. Programuje se v něm velmi jednoduše, &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; není složitý jazyk, navíc se chystá další jazyk (pokličku se pozvednout nepodařilo, takže není jasné o jaký jazyk se jedná). Kdo píšete aplikace pro web, hledáte hosting a nechcete psát v PHP, mrkněte na něj.&lt;br /&gt;&lt;br /&gt;Následovala přednáška o výkonu aplikací napsaných v GWT potažmo všech webových aplikací - &lt;span style="font-weight:bold;"&gt;Measure in millseconds: Performance tips for GWT (and AJAX in general)&lt;/span&gt;. GWT nepoužívám takže jsem si jej trochu přiblížil (v podstatě ještě z doby programování v C++ mám odpor k jakémukoliv generovanému kódu a proto jde i nějak GWT mimo mě). Ovšem mile mě překvapilo, jak je to sofistikovaný systém. Co se dalších tipů týče, nic nového jsem se nedozvěděl, snažit se mít co nejméně CSS a JavaScript souborů, mít je co nejmenší a používat &lt;a href="http://jirablog.blogspot.com/2007/10/jednodue-na-css-sprite.html"&gt;CSS Sprite&lt;/a&gt;, to jsou dnes již design pattern webového vývojáře.&lt;br /&gt;&lt;br /&gt;Pak jsem si řekl, že to risknu a dozvím se něco o social networks. Zavítal jsem na přednášku &lt;span style="font-weight:bold;"&gt;Best practice for OpenSocial development&lt;/span&gt;. Pro mě nejslabší zážitek. Měl jsem pocit, že jsem buď moc starej a nebo z jiné planety, protože jsem nějak nechápal, kdo používá takové věci, zkrátka nejsem nějak in.&lt;br /&gt;&lt;br /&gt;Zasklil jsem i Android (o tom se dá načíst ledacost) a zavítal jsem na jedinou českou přednášku &lt;span style="font-weight:bold;"&gt;Large-scale computing, Google-style: MapReduce, BigTable, Hadoop, HDFS and others&lt;/span&gt; přednášenou Peter Kukolem. Na &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;MapReduce&lt;/a&gt; se moc nedostalo. Ale bylo to hodně zajímavé, protože se řešilo co to znamená computing v rozměrech Googlu, co vše se stává problémem při počítání v takovém měřítku.&lt;br /&gt;&lt;br /&gt;Na závěr jsem shlédl &lt;span style="font-weight:bold;"&gt;Integrating 'Google' into your applications: Google Data APIs &amp; AJAX APIs&lt;/span&gt;, týkající se popisu rozhraní k aplikacím Googlu. Zde jsem se dozvěděl o různých rozhraních ke Google Search (JavaScriptové či REST) či o Google Data API, které se používá pro přístup (čtení i zápis) k datům v kalendáři či Google Apps.&lt;br /&gt;&lt;br /&gt;Zbaběle jsem utekl před večírkem a pelášil domů za rodinkou. Dojmy pozitivní, jsem moc rád že jsem se mohl zúčastnit, příště rád půjdu zas. PS. Moc se mi líbil přístup k lidem s notebookem, všude halda prodlužovaček a přístup na net, prostě super. Já dávám jedničku s hvězdičkou.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5489404566373202451?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5489404566373202451/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5489404566373202451' title='Počet komentářů: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5489404566373202451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5489404566373202451'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/google-developer-day-2008.html' title='Google Developer Day 2008'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-6269038301327879943</id><published>2008-10-27T09:22:00.001+01:00</published><updated>2008-10-27T09:59:32.280+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>jOpenSpace 2008 - Spring - otevřenost novinkám</title><content type='html'>Už jsem se bál, že zbytek záznamů z nultého ročníku &lt;a href="http://jopenspace.cz/"&gt;jOpenSpace&lt;/a&gt; neexistují a hned jsem dostal odpověď v podobě dalších pěti záznamů. Šestým v pořadí je záznam od &lt;a href="http://www.sweb.cz/pichlik/"&gt;Dagiho&lt;/a&gt; Spring adoption in large enterprise project. Spring používáme a převážně jako IoC container, tak mě toto téma zajímalo. Bohužel kvalita zvuku je hodně špatná, takže jsem spíš neslyšel než slyšel.&lt;br /&gt;&lt;br /&gt;Přesto jsem zaslechl jednu poznámku, která mě vybudila zamyslet se na téma: &lt;span style="font-style:italic;"&gt;Kde se v lidech bere touha poznávat a používat nové vs. držet se v zajetých kolejích?&lt;/span&gt; Řadil bych se spíš k těm zvídavým, které nové věci zajímají a přemýšlejí o jejich aplikaci.&lt;br /&gt;&lt;br /&gt;Je to dáno tím, že mě programování zajímá? Že to je i můj koníček. Nebo je to tím, že chci něčeho ve své profesi dosáhnout a proto se snažím? Nebo je to prostě tím, že věci většinou dělám pořádně a nesnažím se něco odfláknout, jenom proto abych už to měl za sebou? Asi je nutná kombinace všech zmíněných důvodů, aby programátor měl chuť se sebevzdělávat a tím byl otevřený novým věcem. &lt;br /&gt;&lt;br /&gt;Vždyť všechny lidské činnosti podléhají zubu času, stále se hledají lepší a dokonalejší řešení čehokoliv, jenom v oblasti IT je to všechno trochu markantnější a rychlejší. Ovšem pozor, i s prosazováním nových věcí to není tak jednoduché. Je nutné se na ně vždy podívat i skepticky, protože hrozí 2 věci. První je &lt;a href="http://en.wikipedia.org/wiki/Overengineering"&gt;over-engineering&lt;/a&gt; projektu, kdy na řešení problému používáme příliš složité technologie. A druhým problémem je vklouznutí do slepé uličky, protože ne vše co se v době svého vzniku jeví jako dobré se dobrým ukáže i po čase používání.&lt;br /&gt;&lt;br /&gt;Ve svém důsledku se obávám, že i ty skeptiky, kteří neradi posouvají své znalosti někam dál, potřebujeme. Není přeci nic podnětnějšího než přesvědčování takového člověka, protože je nutné vymýšlet argumenty a při této činnosti se kolikrát ukáže, že jsme měli na očích růžové brýle.&lt;br /&gt;&lt;br /&gt;Takže závěrem: doufám, že budeme mít vždy šťastnou ruku ve volbě novinek a že se budu potkávat spíš s těmi nadšenci pro nové věci, které budeme moci probírat a řešit, zda jsou užitečné.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-6269038301327879943?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/6269038301327879943/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=6269038301327879943' title='Počet komentářů: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6269038301327879943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6269038301327879943'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/jopenspace-2008-spring-otevrenost.html' title='jOpenSpace 2008 - Spring - otevřenost novinkám'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2160313242634631217</id><published>2008-10-21T20:08:00.000+02:00</published><updated>2008-10-21T22:39:24.364+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>jOpenSpace 2008 - Metodiky vývoje - jak děláme review kódu</title><content type='html'>Dneska vám předkládám poslední reakci na první dávku audií z &lt;a href="http://jopenspace.cz/"&gt;jOpenSpace&lt;/a&gt;, po &lt;a href="http://jirablog.blogspot.com/2008/10/jopenspace-2008-orm-hibernate-klientska.html"&gt;ORM&lt;/a&gt; a &lt;a href="http://jirablog.blogspot.com/2008/10/jopenspace-2008-dokumentace.html"&gt;dokumentaci&lt;/a&gt; mě oslovila diskuse na téma metodiky vývoje. Poslední 2 zaznamenaná témata mě k nějakým poznámkám nevyburcovala.&lt;br /&gt;&lt;br /&gt;Co se metodiky vývoje v podstatě mě velmi mile překvapilo, že se již naplno prosazují iterativní a agilní způsoby vývoje, které začínají odsouvat nevhodný vodopád. To je velmi potěšující. Je až nepochopitelně překvapující, že se vodopád udržel tak dlouho (mimo jiné podle knihy &lt;a href="http://www.craiglarman.com/"&gt;Craiga Larmana&lt;/a&gt; &lt;a href="http://www.amazon.com/Agile-Iterative-Development-Managers-Software/dp/0131111558/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1224181138&amp;sr=8-1"&gt;Agile and Iterative Development: A Manager's Guide&lt;/a&gt; je zjištění jeho nefunkčnosti hodně staré).&lt;br /&gt;&lt;br /&gt;Poslední věc z diskuse je taky všude stejná. Zapojit zákazníka do vývoje je velmi težké, ale pokud se to podaří, je to super věc. My se především staráme o jednu už né-malou aplikaci, kterou poskytujeme jako službu. Je-li zákazník interní (vymyslíme si nějakou funkcionalitu, či vyvíjíme něco dovnitř) pak je to super, je-li zákazník externí, pak je odezva většinou pomalá.&lt;br /&gt;&lt;br /&gt;Co ovšem vzbudilo mou chuť napsat tento příspěvek, je poměrně složitý způsob reviewováví kódu, které bylo nastíněno. Protože s naším systémem jsem poměrně hodně spokojen a mám pocit, že je na úrovni, rád se s ním s vámi podělím. Review jsem od začátku zamýšlel tak, aby každý kód, který vytvoříme byl reviewován. Z počátku jsme kontrolovali příchozí změny z &lt;a href="http://ximbiot.com/cvs/cvshome/"&gt;CVSka&lt;/a&gt;. Pak nás začlo být v teamu víc než 2 a tento postup přestal fungovat. &lt;br /&gt;&lt;br /&gt;Zhruba v tu dobu jsme nasadili systém &lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt; pro evidenci požadavků. Tím se nám nabídla možnost evidovat jakoukoliv práci na projektu jako požadavek, který definuje, kdo jej bude implementovat a zároveň kdo jej bude reviewovat. Požadavek nemůže být zavřen, pokud nebylo provedeno review. Jednoznačnou výhodou je přehled toho, co se na projektu děje. Dále review provádíme průběžně a nikoliv až na konci iterace (přecijenom dělání review není moc populární a zajímavé), navíc je review skutečně provedeno na každý změněný řádek a to považuji za podstatné (víc očí víc vidí a rozumí-li kódu dva mozky, pak jim pravděpodobně bude rozumět i třetí).&lt;br /&gt;&lt;br /&gt;Jako vývojový nástroj používáme Eclipse a proto jsem hledal podporu review kódu integrovatelnou do Eclipse. Jediné co jsem našel byl &lt;a href="http://code.google.com/p/jupiter-eclipse-plugin/"&gt;Jupiter&lt;/a&gt; (koukám, že se na něm usilovně pracuje, tak třeba se zlepší). Dlouho jsme jej používali a zjistili jsme, že má řadu nevýhod a proto jsem hledal náhradu. Koukal jsem na &lt;a href="http://www.atlassian.com/software/crucible/"&gt;Crucible&lt;/a&gt;, ale nelíbilo se mi, že by evidence review byla mimo již existující infrastrukturu (podobně jako v případě Jupiteru).&lt;br /&gt;&lt;br /&gt;Jako zatím top volba se ukazuje integrovat systém JIRA s naším &lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt; serverem (pomocí &lt;a href="http://confluence.atlassian.com/display/JIRAEXT/JIRA+Subversion+plugin"&gt;subversion pluginu&lt;/a&gt;) tak, aby u každého požadavku zobrazoval change sety, které se jej týkají (k tomu stačí, aby komentář commitu do subversion obsahoval kód požadavku). Následně jsme potřebovali nástroj na zobrazení obsahu subversion a volba padla na &lt;a href="http://www.atlassian.com/software/fisheye/"&gt;Fisheye&lt;/a&gt;, protože je sofistikovanější než &lt;a href="http://www.viewvc.org/"&gt;ViewVC&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A jak samotné review probíhá? Je-li požadavek vyřešen, pak je nutno provést review. Podívám se na požadavek a vidím jaké soubory, byly v souvislosti s jeho řešením commitovány. Přímo ze systému JIRA je možno se prokliknout do Fisheye, kde potřebuji další klik na zobrazení změn souboru s požadavkem souvisejících. Je-li vše v pořádku, pak stačí požadavek označit jako reviewovaný a pak už jej může vedoucí projektu zavřít.&lt;br /&gt;&lt;br /&gt;Není-li vše v pořádku, pak přijde na řadu diskuse. Tu nijak nedokomuntujeme a je věcí programátorů, jak ji zrealizují. Pokud se ukáže, že je nutné provést změnu kódu (překvapivě se to děje docela často), pak je v systému JIRA vytvořen další požadavek na změnu (nepřehledný kód, nějaká chyba v kódu, chybějící test atd.). Tento požadavek je normálně řešen a je i reviewován jako každý jiný. Commit do subversion obsahuje kódy obou požadavků, aby byl v systému JIRA spojen s oběma (jak s původním, tak s review).&lt;br /&gt;&lt;br /&gt;A jaký má systém výhody a nevýhody? Řadu už jsem jich zmínil, ovšem další výhoda tkví v přesné evidenci toho co se děje, v jakém stavu je který požadavek a co se v souvislosti s jeho plněním měnilo a jak. To je neocenitelné. A nevýhody? Pokud je požadavek hodně rozsáhlý, pak je složitější se v souborech vyznat. Je-li to umocněno více change sety (tj. více commity), je to skutečně náročné.&lt;br /&gt;&lt;br /&gt;A uplným závěrem motivační větu: Review kódu skutečně zvyšuje jeho kvalitu a napomáhá dřívějšímu odhalení chyb. Navíc se programátoři učí číst kód druhých, orientovat se v něm, komunikovat o něm a lépe poznávají systém, který programují.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2160313242634631217?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2160313242634631217/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2160313242634631217' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2160313242634631217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2160313242634631217'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/jopenspace-2008-metodiky-vyvoje-jak.html' title='jOpenSpace 2008 - Metodiky vývoje - jak děláme review kódu'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-9068516620075815862</id><published>2008-10-14T13:43:00.004+02:00</published><updated>2008-10-14T13:56:51.479+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Spring bean z Java enumu</title><content type='html'>Dneska jsem potřeboval vytvořit ve &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt; IoC Java enum, ale jak na to. Než jsem začal vytvářet nějakou factory, řekl jsem si, že to už musí být vyřešené. &lt;a href="http://www.google.cz/"&gt;Google&lt;/a&gt; pomohl a našel jsem blog post Creating a &lt;a href="http://robertmaldon.blogspot.com/2007/05/creating-spring-bean-from-java-5-enum.html"&gt;Spring Bean from a Java 5 Enum&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Ve stručnosti se věc dá shrnout do dvou ukázek, první jest pro Spring 1.2.2 a menší:&lt;pre&gt;&lt;code&gt;&amp;lt;bean id="latte" class="cz.xxx.PersonType" factory-method="valueOf"&amp;gt;&lt;br /&gt;   &amp;lt;constructor-arg&amp;gt;&lt;br /&gt;      &amp;lt;value&amp;gt;ADULT&amp;lt;/value&amp;gt;&lt;br /&gt;   &amp;lt;/constructor-arg&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Kde &lt;code&gt;ADULT&lt;/code&gt; je jméno konkrétního enumu. Domnívám se (nezkoušel jsem), že tuto variantu je nutné použít i ve Springu 1.2.2 a vyšším, pokud se odkazujete na enum v okamžiku, kdy není jasné, že výsledkem má být enum (např. položky listu, mapy).&lt;br /&gt;&lt;br /&gt;Používáte-li Spring 1.2.2 a starší, pak na místě kde má být enum stačí použít:&lt;pre&gt;&lt;code&gt;&amp;lt;bean id="person" class="cz.xxx.Person"&amp;gt;&lt;br /&gt;   &amp;lt;property name="type" value="STUDENT"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;Jednoduché, ale moc šikovné. Tak to mám rád.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-9068516620075815862?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/9068516620075815862/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=9068516620075815862' title='Počet komentářů: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/9068516620075815862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/9068516620075815862'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/spring-bean-z-java-enumu.html' title='Spring bean z Java enumu'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1885823360681996580</id><published>2008-10-13T10:15:00.003+02:00</published><updated>2008-10-13T15:22:20.383+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dokumentace'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>jOpenSpace 2008 - Dokumentace - nezatracujme FOP</title><content type='html'>A máme tu pokračování inspirované poslechem audio záznamů z &lt;a href="http://jopenspace.cz/"&gt;jOpenSpace&lt;/a&gt; konference. Již jsem psal o &lt;a href="http://jirablog.blogspot.com/2008/10/jopenspace-2008-orm-hibernate-klientska.html"&gt;ORM&lt;/a&gt; a nyní mé poznámky k tématu Dokumentace. Toto téma mě opravdu hodně zajímalo, protože jsem měl dojem, že na našem projektu dokumentace moc nevzniká a hrozně mě zajímalo, jak to dělají druzí.&lt;br /&gt;&lt;br /&gt;V podstatě vývojářskou dokumentaci neděláme žádnou, takže pro nováčka může být dost obtížné se v kódu zorientovat. Proč to tak je? No v podstatě se snažíme psát přehledný a jasný kód, což je pohlídané především systémem review, který používáme (o něm více v příštím příspěvku). Navíc je to vše umocněno skutečností, že mé schopnosti orientovat se v kódu jsou nadstandardní a protože &lt;span style="font-style:italic;"&gt;podle sebe soudím tebe&lt;/span&gt;, myslím si, že to dovedou všichni. Ve výsledku se ukazuje, že to chvilku trvá, ale ve výsledku je struktura aplikace poměrně dobře pochopitelná. Hlavním problémem stejně zůstává skutečnost co aplikace dělá a proč, a o tom bych dokumentaci psal hodně nerad, protože by to bylo na hrozně dlouho.&lt;br /&gt;&lt;br /&gt;Byl jsem potěšen, jak i v tomto ohledu je tvorba naší dokumentace v souladu s okolím. Především pro uživatelskou dokumentaci používáme &lt;a href="http://www.docbook.org/"&gt;DocBook&lt;/a&gt;, který v poslední době editujeme pomocí &lt;a href="http://www.xmlmind.com/xmleditor/"&gt;XMLMind&lt;/a&gt;u. A nyní se začínáme malinko odlišovat. Obecně se hovoří o různých způsobech převodu DocBooku do výstupního formátu. Zde jsme šli standardní cestou a tou je XSLT transformace, kterou získáváme jak manuál v HTML tak v PDF (přes &lt;a href="http://xmlgraphics.apache.org/fop/"&gt;FOP&lt;/a&gt;). Protože jsme si vybrali jenom podmnožinu DocBooku, kterou podporujeme, máme vlastní šablony, které nejsou komplikované a vše funguje ke 100% spokojenosti. Konfigurace fontů, která byla zmiňovaná jako komplikovaná, zas tak složitá není (v porovnání např. s &lt;a href="http://www.lowagie.com/iText/"&gt;iTextem&lt;/a&gt; je srovnatelně složitá).&lt;br /&gt;&lt;br /&gt;Samozřejmě FOP má své mouchy a nedostatky, ale současné verze se od 0.20.5 liší a dosahují uspokojivých výsledků. Navíc se FOP docela vyvíjí a každá nová verze je lepší než ta předchozí.&lt;br /&gt;&lt;br /&gt;Jako podpora nanáviděných formátu od nejmenované firmy, bylo zmíněno, že uživatelé stejně vyžadují Wordový dokument, který umějí zpracovat a proto nejde DocBook použít. To není pravda, protože převod DocBooku do RTF není problém a pak pomocí revizí zanést změny zpět do DocBooku také není složité.&lt;br /&gt;&lt;br /&gt;Z diskuse je zřejmé, že s dokumentací se bojuje všude a najít vyvážení mezi dost a né příliš záleží projekt od projektu. Ale obecně platí, čím více dokumentace jsme schopní vygenerovat na základě jednoho zdroje (ať už je jím DocBook, kód, UML model atd.) tím lépe pro všechny zúčastněné. Jakmile začneme přepisovat myšlenky z UML, či z kódu do dokumentace je to cesta do pekel, dřív nebo později se dokumentace rozejde s originálem (a když se nerozejde, bude nás to stát velmi vysoké úsilí).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1885823360681996580?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1885823360681996580/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1885823360681996580' title='Počet komentářů: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1885823360681996580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1885823360681996580'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/jopenspace-2008-dokumentace.html' title='jOpenSpace 2008 - Dokumentace - nezatracujme FOP'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-3382141244145506769</id><published>2008-10-05T20:49:00.006+02:00</published><updated>2008-10-06T12:18:19.070+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>jOpenSpace 2008 - ORM - Hibernate a klientská aplikace</title><content type='html'>Konečně jsem se dostal k tomu, abych si poslechl audia z akce &lt;a href="http://jopenspace.cz/"&gt;jOpenSpace&lt;/a&gt;. Pro zájemce bych odkázal především na blog &lt;a href="http://blog.novoj.net/2008/08/31/jopenspace-2008-audio-1/"&gt;otce Fura&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Konference musela být jisto jistě velmi zajímavá a prospěšná. Moc mě mrzí, že jsem se nezúčastnil, ale mohu si za to především sám, protože jsem zasklil call-for-papers v konference java.cz. Dám si závazek, že napřezrok se to již nebude opakovat.&lt;br /&gt;&lt;br /&gt;První záznam je z diskuse o &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt;. Nosným tématem je použití Hibernate v klientských aplikacích. Problematické v tomto případě je, že Hibernate session object není &lt;a href="http://en.wikipedia.org/wiki/Thread_safe"&gt;thread-safe&lt;/a&gt; a Hibernate si hodně zakládá na lazy nahrávání čehokoliv (tj. k nahraným objektům je připojena session a atributy, asociace se dohrávají až v okamžiku, kdy je potřeba).&lt;br /&gt;&lt;br /&gt;Klientské aplikace napsané v &lt;a href="http://en.wikipedia.org/wiki/Abstract_Windowing_Toolkit"&gt;AWT&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Swing_(Java)"&gt;Swingu&lt;/a&gt; nebo &lt;a href="http://http://en.wikipedia.org/wiki/Standard_Widget_Toolkit"&gt;SWT&lt;/a&gt; mají jedno velké specifikum oproti  aplikacím webovým. Tím specifikem je jednovláknovost těchto knihoven. Tj. kód, který přistupuje k UI tak musí činit z UI vlákna (ve webové aplikaci má každý request své vlákno - skoro vždy). Z tohoto vlákna tedy není vhodné provádět náročné akce, protože dojde k zamrznutí UI. A jak v tomto prostředí řešit přístup k datům (pomocí Hibernate a jeho nesynchronizovaného objektu session)?&lt;br /&gt;&lt;br /&gt;Varianty jsou v podstatě tři:&lt;ol&gt;&lt;li&gt;používat session pouze z UI vlákna&lt;/li&gt;&lt;li&gt;používat session pouze z jiného vlákna&lt;/li&gt;&lt;li&gt;používat session jak z UI tak z jiného vlákna&lt;/li&gt;&lt;/ol&gt;První varianta je špatně, protože provádět dlouho trvající dotazy z UI vlákna zhorší odezvu UI. Druhá varianta je ideální, ale má jedno úskalí. Jak zařídit nahrání všech vlastností a vazeb objektu, které budou v UI potřeba tak, aby již nebylo nutné dotahovat žádná data (tj. jak obejít Hibernate laziness). Třetí varianta spočívá v nahrání dat v jiném vlákně a následném nahrání lazy atributů a vazeb z UI vlákna (dotahují se, až když k nim UI přistoupí a to tak učiní z UI vlákna).&lt;br /&gt;&lt;br /&gt;Ještě je nutno zmínit jak to bude se správou session objektů. V prvním případě nám stačí jedna session, protože ji používáme pouze z jednoho vlákna. Pro druhý případ může session potřebovat víc, ale ve své podstatě to záleží na počtu výkonných vláken pro provádění komunikace s DB přes Hibernate. Ve třetím případě určitě potřebujeme pro každou událost (řekněme, že se jedná o obdobu requestu v klientské aplikaci) vlastní session, protože ji použijeme pro nahrání objektů a případné další lazy nahrávání z UI vlákna. Tyto 3 strategie je možné komplikovat dodáním synchronizace a využitím menšího počtu session objektů.&lt;br /&gt;&lt;br /&gt;Mě osobně se nejvíce zamlouvá druhá varianta, protože veškerá režie s nahráním dat je mimo UI vlákno. Ale jak nahrát vše co je potřeba? Velmi jednoduše. Stačí, aby model každého UI prvku  implementoval speciální rozhraní, které bude vracet ty atributy a vazby, které bude pro své vykreslení potřebovat. Díky tomuto kroku a stromové struktuře UI elementů stačí získat tento seznam pro model root elementu (ten se rekurzivně poptá u svých potomků). Inicializaci lazy atributů a vazeb je možné provést pouhým přistoupením k nim pomocí get metod (nebo pomocí metody &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Hibernate.html#initialize(java.lang.Object)"&gt;&lt;code&gt;initialize&lt;/code&gt;&lt;/a&gt;). &lt;br /&gt;&lt;br /&gt;Bohužel klientskou aplikaci jsem již hodně dlouho nedělal, takže tento návrh je pouze z mé hlavy a né z praktické zkušenosti.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-3382141244145506769?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/3382141244145506769/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=3382141244145506769' title='Počet komentářů: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3382141244145506769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3382141244145506769'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/10/jopenspace-2008-orm-hibernate-klientska.html' title='jOpenSpace 2008 - ORM - Hibernate a klientská aplikace'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2331281601587041368</id><published>2008-09-26T20:17:00.004+02:00</published><updated>2008-09-26T20:58:27.557+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='databáze'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Jak mě vypekla DB2</title><content type='html'>Začnu zeširoka. Možnost ukládat &lt;a href="http://www-01.ibm.com/software/data/db2/xml/"&gt;XML do databáze v DB2&lt;/a&gt; se mi moc líbí. &lt;a href="http://en.wikipedia.org/wiki/XQuery"&gt;XQuery&lt;/a&gt; je plně integrováno s &lt;a href="http://en.wikipedia.org/wiki/XQuery"&gt;SQL, &lt;/a&gt;je možno tedy dělat dotazy i na XML data z SQL. Navíc jsou plně podporovány indexy, takže vyhledávání může být i rychlé.&lt;br /&gt;&lt;br /&gt;Navíc v aplikaci, kterou vyvíjíme je velký tlak na uložení různorodých dat. Vytvářet velké množství tabulek nechci. Ukládat je rozložením do universální tabulky, kde bude více řádků pro jednu entitu (jeden sloupec nese název atributu a druhý jeho hodnotu), taky nechci. Takže jsem si vysnil ukládat je do XML. &lt;br /&gt;&lt;br /&gt;10 dní jsem realizoval framework, který mi toto umožní a bude fungovat ruku v ruce s Hibernate. Vše jsem otestoval, vyzkoušel a funguje to super. No a dnes jsem se pustil do realizace v našem produktu. A ejhle, hned jsem narazil na problémy, které mě zastavily.&lt;br /&gt;&lt;br /&gt;Není možné mít sloupec typu XML v tabulce, která používá MDC (&lt;a href="http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/admin/c0007201.htm"&gt;MultiDimesional Clustering&lt;/a&gt;). Velmi špatná zpráva, protože MDC používáme pro zvýšení výkonu přistupu k datům v našich obřích tabulkách. Asi budu muste udělat druhou tabulku, kde budu ukládat pouze XML ... půjde to, ale výkon nebude nic moc ...&lt;br /&gt;&lt;br /&gt;A druhá rána, sloupec typu XML nemůže být ve view, které používá INSTEAD OF triggery. Tak to zase používáme pro zápis dat do logovacích tabulek, abychom dokázali trackovat jak se měnila data. To asi budu muset obejít buď logováním přímo z aplikace (pomocí &lt;a href="http://www.hibernate.org"&gt;Hibernate&lt;/a&gt; a jeho &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Interceptor.html"&gt;Interceptoru&lt;/a&gt;), což se mi nelíbí. Přišel bych o tuto funkcionalitu při přímém přístupu přes SQL. A nebo budu muset udělat trigger přímo na tabulku, což není jednoduché, protože jsem do view často dotahoval data i z jiných tabulek.&lt;br /&gt;&lt;br /&gt;Každopádně ... jsou to problémy řešitelné. Ale opět jsem se přesvědčil, že vývoj aplikací není předvídatelná činnost a nedá se naplánovat. Kolikrát si myslíme, že jsme na konci cesty a musíme se zase pěkný kus vracet. &lt;br /&gt;&lt;br /&gt;Termín nám straší za dveřmi ... vysvětlete to obchodníkům ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2331281601587041368?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2331281601587041368/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2331281601587041368' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2331281601587041368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2331281601587041368'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/09/jak-me-vypekla-db2.html' title='Jak mě vypekla DB2'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4475697000588052600</id><published>2008-09-22T21:42:00.004+02:00</published><updated>2008-09-22T22:22:29.205+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Tapestry - jak dělat webové aplikace konfortně</title><content type='html'>Už je to zase příšerně dlouho co jsem si našel chvíli a navíc jsem měl chuť něco sepsat a protože se mi nahromadilo pár zajímavých čtení o &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry&lt;/a&gt;, pak je logické, že můj první příspěvek po takové době patří právě Tapetry. Navíc je to pár hodin, co vyšlo Tapestry 5.0.15, které mělo být prvním release candidatem. Bohužel se tak nestalo, kvůli chybičkám objeveným v pozdní stádiu releasu (&lt;a href="http://tapestryjava.blogspot.com/2008/09/tapestry-5015-released.html"&gt;blíže&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;První článek, který vám chci naservírovat, je zajímavý, protože se mu podařilo velmi přehlednou formou shrnout proč je Tapestry zajímavé. &lt;a href="http://joshuajava.wordpress.com/2008/08/21/why-you-should-consider-tapestry-5/"&gt;Why you should consider Tapestry 5&lt;/a&gt;. Bohužel je už malinko starší. Ze stejného blogu pochází i porovnání s Wicket: &lt;a href="http://joshuajava.wordpress.com/2008/09/11/a-glimpse-of-wicket-14-and-tapestry-5/"&gt;A glimpse of Wicket 1.4 and Tapestry 5&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tapestry se vždy hlásilo k následujícím pravidlům: rychlost a škálovatelnost vytvořených aplikací, pohodlný vývoj aplikace bez potřeby speciální podpory v IDE a vysoká produktivita vývojáře. A o produktivitě je &lt;a href="http://moatazanany.wordpress.com/2008/09/13/boost-your-productivity-using-apache-tapestry/"&gt;Boost Your Productivity Using Apache Tapestry&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Specialitou Tapestry již od verze 4 je vlastní &lt;a href="http://en.wikipedia.org/wiki/Inversion_of_control"&gt;IoC&lt;/a&gt; framework. Ve verzi 4 se jednalo o &lt;a href="http://hivemind.apache.org/"&gt;HiveMind&lt;/a&gt;, ve verzi 5 jde prostě o &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-ioc/"&gt;Tapestry IoC&lt;/a&gt;. Proč má Tapestry vlastní IoC framework, co umí je možné se dočíst ve dvou článcích napsaných přímou autorem Howardem L. Shipem: &lt;a href="http://tapestryjava.blogspot.com/2008/08/tapestry-5-ioc-binding-and-building.html"&gt;Tapestry 5 IoC: Binding and Building Services&lt;/a&gt; a &lt;a href="http://tapestryjava.blogspot.com/2008/09/tapestry-5-ioc-introducing-service.html"&gt;Tapestry 5 IoC: Introducing Service Configuration&lt;/a&gt;s.&lt;br /&gt;&lt;br /&gt;V neposlední řadě: pozitivní krok je i vznik &lt;a href="http://code.google.com/p/tapestry5-appfuse/"&gt;AppFuse pro Tapestry 5&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4475697000588052600?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4475697000588052600/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4475697000588052600' title='Počet komentářů: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4475697000588052600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4475697000588052600'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/09/tapestry-jak-delat-webove-aplikace.html' title='Tapestry - jak dělat webové aplikace konfortně'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1637531677398801970</id><published>2008-07-21T20:06:00.006+02:00</published><updated>2009-08-11T09:53:05.517+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Konečně build systém na úrovni - Gradle</title><content type='html'>Již hodně dlouho se na mě ze všech stran valí, že &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt; je překonaný a že bychom měli používat &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;. Jistě Maven přináší spoustu zajímavých myšlenek, především zavedl jednoutnou strukturu projektů a správu závislostí. Ovšem přinesl i spoustu problémů, jako pevně daný build cycle či buildování multi-projektu.&lt;br /&gt;&lt;br /&gt;Na trhu open source projektů se objevuje nový hráč, který si řadu těchto nešvarů bere za své a snaží se je napravit. A o jakém projektu, že píši? O projektu &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;. Gradle je teprve ve verzi 0.2, ale vyvíjí se mílovými kroky.&lt;br /&gt;&lt;br /&gt;A co je to převratné, co mě zaujalo. Build skripty se píší v jazyce &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;. Má to řadu výhod, skript je programován, je možné používat (zavolat) jakýkoliv kód (díky Groovy, jakýkoliv Javovský kód). Navíc je možné opakující se části volat jako funkce (které se dají vytvářet přímo v build scriptu). Bezvadná integrace s Antem. Kolik z nás má v Antu poměrně složité skripty na generování kde čeho. Jejich převod pod Maven je hotovým peklem. Dále build multi-projektu v maven jde pouze z kořenového projektu, díky čemuž se buildu celý multi-projekt. V Gradle je možné multi-projekt build spustit z libovolného projektu a tím se buildují jenom ty podprojekty, které jsou potřeba.&lt;br /&gt;&lt;br /&gt;Konvence ohledně build cycle jsou v Gradle definovány pomocí pluginů. Tj. pokud použiji plugin &lt;code&gt;java&lt;/code&gt;, pak je nadefinován konkrétní build cycle. Tento může být dle potřeby modifikován, buď jiným pluginem (např. plugin &lt;code&gt;groovy&lt;/code&gt;) či samotným build skriptem. To znamená konec dvojí pouštění testů, aby mohl vzniknout &lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt; code coverage.&lt;br /&gt;&lt;br /&gt;A co zatím chybí. Je toho stále dost, není nativní podpora pro &lt;a href="http://http://testng.org/doc/"&gt;TestNG&lt;/a&gt;, Coberturu. Neexistují integrace s IDE.&lt;br /&gt;&lt;br /&gt;Zatím jsem lákání Mavenu odolal a doufám, že Gradle dospěje a pomůže mi vyřešit problémy, které s Antem máme. Hrozně nerad bych naše skripty převáděl a ladil v Mavenu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1637531677398801970?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1637531677398801970/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1637531677398801970' title='Počet komentářů: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1637531677398801970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1637531677398801970'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/07/konecne-build-system-na-urovni-gradle.html' title='Konečně build systém na úrovni - Gradle'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1971972799720651299</id><published>2008-06-09T18:13:00.006+02:00</published><updated>2008-12-01T21:54:35.719+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='testování'/><title type='text'>On se ještě používá jUnit? Vždyť máme TestNG.</title><content type='html'>Konečně jsem si poslechl záznam přednášky Jana Novotného &lt;a href="http://blog.novoj.net/2008/05/09/podcast-zaznam-z-prednasky-automaticke-testovani-v-praxi/"&gt;Automatické testování v praxi&lt;/a&gt;. Jen více takových ...&lt;br /&gt;&lt;br /&gt;Ale proč píšu tento příspěvek? Stále mě překvapuje jak velké množství lidí neustále používá &lt;a href="http://www.junit.org/"&gt;jUnit&lt;/a&gt;, který mi přijde v porovnání s &lt;a href="http://testng.org/doc/"&gt;TestNG&lt;/a&gt; jak chudý příbuzný. Proto jsem se rozhodl nastínit 2 hlavní výhody TestNG, alespoň z mého pohledu.&lt;br /&gt;&lt;br /&gt;Přecházel jsem na TestNG v době, kdy po jUnit4 nebylo ani vidu ani slechu, takže jsem měl rozhodování o hodně jednodušší. Ale i po uvolnění jUnit4 je TestNG lepší. Ovšem jako jUnit4 vyžaduje Javu 1.5, takže pro vás co běžíte na Javě 1.4 a méně, pak máte smůlu (ovšem testy můžete překládat jinou verzí Javy než produkční kód).&lt;br /&gt;&lt;br /&gt;Na úvod porovnání uvedu: jako vývojové nástroje používám &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;, builduji &lt;a href="http://ant.apache.org/"&gt;Antem&lt;/a&gt; nebo &lt;a href="http://maven.apache.org/"&gt;Mavenem&lt;/a&gt; a necítím se být nijak limitován užíváním TestNG oproti jUnitu.&lt;br /&gt;&lt;br /&gt;Nyní k výhodám. Hlavní skutečnost, která mě hnala za změnou jUnitu za něco jiného je skutečnost, kterou se sice podařilo vyřešit, ale neskutečmě se mi nelíbila. Jde o to, že každý test nejenom dostává vlastní novou instanci &lt;code&gt;TestCase&lt;/code&gt;u, ale tato instance je zároveň použita jako objekt nesoucí informaci o výsledku testu (proběhl / neproběhl). Proč mi to vadí? Protože pokud máte hodně testů a u hodně z nich si naplníte instanční proměnné nějakými instancemi, pak vám běh testů sežere hodně paměti (protože se instance &lt;code&gt;TestCase&lt;/code&gt;ů neuvolní pro &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"&gt;garbage collection&lt;/a&gt;), pokud nespadnou na nedostatek paměti. Takže buď musíte ručně nastavovat hodnotu &lt;code&gt;null&lt;/code&gt; do všech instančních proměnných (pracné a náročné na nezapomenutí) a nebo mít připraveného předka, který bude mít &lt;code&gt;tearDown&lt;/code&gt; s funkcí nastavování hodnoty &lt;code&gt;null&lt;/code&gt; instančním proměnným.&lt;br /&gt;&lt;br /&gt;Druhou obrovskou výhodou, kterou jsem dokázal ocenit až po chvíli užívání testNG jsou data-providery. jUnit4 nabízí něco podobného v podobě parametrizovaných testů, ovšem to co nabízí TestNG se to podobá hodně vzdáleně. Když se podíváme na příklad z &lt;a href="http://www.devx.com/Java/Article/31983/1954"&gt;článku o jUnit4 na devx.com&lt;/a&gt;:&lt;pre&gt;&lt;code&gt;@RunWith(Parameterized.class)&lt;br /&gt;public class SquareTest {&lt;br /&gt;&lt;br /&gt;  private static Calculator calculator = new Calculator();&lt;br /&gt;  private int param;&lt;br /&gt;  private int result;&lt;br /&gt;&lt;br /&gt;  @Parameters&lt;br /&gt;  public static Collection data() {&lt;br /&gt;    return Arrays.asList(new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} });&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public SquareTest(int param, int result) {&lt;br /&gt;    this.param = param;&lt;br /&gt;    this.result = result;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void square() {&lt;br /&gt;    calculator.square(param);&lt;br /&gt;    assertEquals(result, calculator.getResult());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Z příkladu je zřejmé, že jUnit parametrizuje na úrovní třídy, protože parametry se ze statické metody předávají do konstruktoru třídy. Naproti tomu TestNG:&lt;pre&gt;&lt;code&gt;public class SquareTest {&lt;br /&gt;&lt;br /&gt;  private Calculator calculator = new Calculator();&lt;br /&gt;&lt;br /&gt;  @DataParameter(name = "square")&lt;br /&gt;  protected Object[][] data() {&lt;br /&gt;    return new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test(dataProvider = "square")&lt;br /&gt;  public void square(int param, int result) {&lt;br /&gt;    calculator.square(param);&lt;br /&gt;    assertEquals(calculator.getResult(), result);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Data providerů můžu mít v TestNG víc, dokonce může data provider být z jiné třídy, než test, který jej využívá. Jediné, co si mi nelíbilo, je přehození parametrů metod assert, tj. první je &lt;code&gt;actual&lt;/code&gt; a druhý &lt;code&gt;expected&lt;/code&gt;. Naštěstí existuje třída &lt;code&gt;AssertJUnit&lt;/code&gt;, která zachovává zvyklost z jUnitu.&lt;br /&gt;&lt;br /&gt;Tyto dvě skutečnosti jsou pro mě tak silnými argumety, že jsem přešel a nelituji. Navíc použití data  providerů je tak jednoduché, že dnes je používám možná více než je zdrávo, ale když jsou tak elegantní.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1971972799720651299?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1971972799720651299/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1971972799720651299' title='Počet komentářů: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1971972799720651299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1971972799720651299'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/06/on-se-jeste-pouziva-junit-vzdyt-mame.html' title='On se ještě používá jUnit? Vždyť máme TestNG.'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-747309331571035683</id><published>2008-05-25T21:13:00.005+02:00</published><updated>2008-12-01T21:54:14.164+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='testování'/><title type='text'>Test prošel. To je špatně!</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test Driven Development&lt;/a&gt; má jednu obrovskou výhodu. Tj. napsat test na neexistující funkcionalitu, pustit jej a ... ano správně ověřit, že test neprošel. Co je to za výhodu? &lt;br /&gt;&lt;br /&gt;Přiznám se, že TDD stále není můj šálek kávy. Jestli jsem moc starej a nebo jsem ještě nevyspěl, nevím. Ale stále píšu kód a ten pak testuju a ne obráceně. Stále je moje myšlení tam, že vymýšlím jak věc udělat, když ji tvořím a ne, když vymýšlím test.&lt;br /&gt;&lt;br /&gt;No a tady je zakopanej pes, protože pokud chci být korektní, musím manuálně a naprosto proti směru vývoje věcí, nakonec kus kódu pozměnit a zjistit, zda se nestane to co inzeruju v nadpise.&lt;br /&gt;&lt;br /&gt;Pokud totiž tento krok neudělám, pak se může stát co se mi už nejednou stalo a to, že testy prošli, ale ne proto, že jsem měl dobře napsanej kód, ale protože test netestoval to co měl.&lt;br /&gt;&lt;br /&gt;Stále se přesvědčuji, že &lt;a href="http://www.extremeprogramming.org/"&gt;Extreme Programming&lt;/a&gt; je domyšlené do posledního puntíku a je jenom otázkou času, než to zjistím.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-747309331571035683?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/747309331571035683/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=747309331571035683' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/747309331571035683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/747309331571035683'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/05/test-prosel-to-je-spatne.html' title='Test prošel. To je špatně!'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-195797425499613170</id><published>2008-05-15T12:35:00.004+02:00</published><updated>2008-12-01T21:53:52.038+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><category scheme='http://www.blogger.com/atom/ns#' term='testování'/><title type='text'>Na unit testy si vždy čas udělám ...</title><content type='html'>Přečetl jsem si příspěvek &lt;a href="http://javicka.blogspot.com/2008/05/mte-as-na-unit-testy.html"&gt;Máte čas na unit testy?&lt;/a&gt; od Petra Jůzy a po dlouhé době, mě nějaký text přiměl k reakci (Kde je dagi se svými kontroverzními tematy).&lt;br /&gt;&lt;br /&gt;Přiznám se, že s testováním jsem začínal nějakým 8 let zpátky za pomocí &lt;a href="http://www.junit.org/"&gt;jUnit&lt;/a&gt; knihovny a měl jsem dobrý pocit. Spíš mě to ale zdržovalo. Postupem času jsem se naučil (alespoň si to myslím) testy psát, začal jsem používat &lt;a href="http://cobertura.sourceforge.net/"&gt;Coberturu&lt;/a&gt; a přešel jsem na &lt;a href="http://testng.org/doc/"&gt;TestNG&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Nedokážu si představit, že bych neměl unit testy. Proč? Jak píšu kód, píšu testy, kterými ověřím, že to celé funguje ještě předtím, než začnu integrovat komponenty dohromady. Jak to dělají ti, co testy nepíšou netuším. Pokud si vše otestuju, pak v návazných objektech používám mock implementaci téhož (díky &lt;a href="http://www.easymock.org/"&gt;EasyMock&lt;/a&gt; knihovně) a testuju dál. Nejednou jsem kód měnil, abych ho dokázal otestovat a nejednou jsem se setkal s tím, že se mi taková změna v budoucnu vyplatila.&lt;br /&gt;&lt;br /&gt;Psát testy stojí čas, ale i když testy nepíšete, nějak musíte testovat a to také stojí čas. Pokud dojde na nějaké úpravy v budoucnu, pak jsou testy k nezaplacení, protože vzpomenout si, jak jsem to vlastně před půl rokem testoval, to už chce sakra dobrou paměť. Při opravě chyb je to podobné, testy opět pomůžou.&lt;br /&gt;&lt;br /&gt;Psát testy až po odladění aplikace je zvěrstvo a plýtvání časem. Má to význam pouze pokud chceme opravit chybu nebo udělat změnu. Pak se může vyplatit napsat na ni testy a teprve poté se pustit do změn.&lt;br /&gt;&lt;br /&gt;Nepoužívám &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;TDD&lt;/a&gt; a tudíž testy píšu až po napsání výkonného kódu. Nějak na tuto myšlenku nejsem ještě připraven. &lt;br /&gt;&lt;br /&gt;A co my testy přinášejí především? Jistotu ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-195797425499613170?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/195797425499613170/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=195797425499613170' title='Počet komentářů: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/195797425499613170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/195797425499613170'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/05/na-unit-testy-si-vzdy-cas-udelam.html' title='Na unit testy si vždy čas udělám ...'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8479664424655413834</id><published>2008-02-18T20:30:00.005+01:00</published><updated>2008-02-19T12:25:50.355+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Jak nás vypek DateFormat.parse</title><content type='html'>Tak jsme zase objevili jednu, pro mě překvapivou, skutečnost. Ale vezmu to popořadě. Chceme parsovat datumy s časem reprezentované stringem. Používáme Javu, takže jednoduchý úkol pro &lt;code&gt;DateFormat&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");&lt;br /&gt;Date datum = format.parse(retez);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Tento postup má pro mě nelogickou nevýhodu. Tj. pokud si například někdo zplete pořadí měsíce a dne v měsící (u tohoto formátu to není moc pravděpodobné, ale jsou jiné, kde to jde velmi jednoduše), stejně nám to datum vytvoří. Např. parserování textu &lt;code&gt;2008-24-04 1:30:43&lt;/code&gt; neznamá chybu, ale datum &lt;code&gt;2009-12-04 1:30:43&lt;/code&gt;.&lt;br /&gt;Absolutně tuto vlastnost nechápu, ale třeba se někomu hodí. Proč je ovšem implicitní, to nepochopím nikdy. Naštěstí se dá jednoduše vypnout:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");&lt;br /&gt;format.setLenient(false);&lt;br /&gt;Date datum = format.parse(retez);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Takže tentokrát už dostaneme, pro mě očekávanou, &lt;code&gt;ParseException&lt;/code&gt;.&lt;br /&gt;A teď se pomalu blížíme k dnešnímu překvapení. Co se stane, pokud na vstupu bude řetěz &lt;code&gt;2008-04-24 1:30:43 PM&lt;/code&gt;? Možnosti jsou tři: &lt;code&gt;ParseException&lt;/code&gt;, datum &lt;code&gt;2008-04-24 13:30:43&lt;/code&gt; nebo datum &lt;code&gt;2008-04-24 1:30:43&lt;/code&gt;? Osobně jsem předpokládal možnost první, přežil bych možnost druhou, ale pravdou je možnost třetí. &lt;code&gt;DateFormat&lt;/code&gt; si i v ne-lenient módu odignoruje část vstupního řetězce. To jsem opravdu nečekal a dost mě to zarazilo. Takže pokud někdo chce skutečně správnou funknci parserování data z řetězce, musí použít:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");&lt;br /&gt;format.setLenient(false);&lt;br /&gt;ParsePosition p = new ParsePosition(0);&lt;br /&gt;Date datum = format.parse(retez, p);&lt;br /&gt;if (p.getIndex() &lt; retez.length() - 1) {&lt;br /&gt;   throw new ParseException(...);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Pozor, v případě použití &lt;code&gt;ParsePosition&lt;/code&gt; metoda &lt;code&gt;parse&lt;/code&gt; nevyhazuje výjimku, musíte si chybu ošetřit sami.&lt;br /&gt;Tak a máme konečně, dle mého názoru, správné parserování řetězce na text. Kód je o poznání složitější než ten, se kterým jsme začínali. Škoda, zřejmě chceme to, co není normální pro ostatní.&lt;br /&gt;&lt;br /&gt;PS. Díky Luboši ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8479664424655413834?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8479664424655413834/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8479664424655413834' title='Počet komentářů: 15'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8479664424655413834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8479664424655413834'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/02/jak-nas-vypek-dateformatparse.html' title='Jak nás vypek DateFormat.parse'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2691706694809246803</id><published>2008-02-01T20:57:00.000+01:00</published><updated>2008-02-01T22:43:48.281+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Jak z toho ven ...</title><content type='html'>Už je to nějaký pátek, co jsem se zabýval vlastnostmi, které bych rád viděl v Javě 7. Něco málo se na mém názoru změnilo: jsem ještě radikálnějsí. Proč? Jsem přesvědčen, že není možné rozšířit Javu tak, aby byla zpětně kompatibilní a zároveň nabízela prvjky, které by moderní jazyk měl mít. Sun se snaží udržen nejen zpětně kompatibilní bytecode, ale i zdroják. A to je ten problém.&lt;br /&gt;&lt;br /&gt;A jak z toho ven. Současnou Javu bych nechal takovou jakou je. Cestu ven by nám ukázala nová Java, říkejme jí např. JavaNW (New Way). JavaNW by byla překládána do stejného bytecode, ale byla by nekompatibilní na úrovni zdrojového kódu. Co to znamená? Nepřijdeme o nic z existující infrastruktury: JRE, &lt;a href="http://java.sun.com/javase/technologies/hotspot/"&gt;HotSpot&lt;/a&gt;, &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt;, &lt;a href="http://tomcat.apache.org/"&gt;Tomcat&lt;/a&gt;, ... všechno funguje. Ale to není ještě konec seznamu, protože všechny knihovny budou také použitelné: standardní knihovny Javy, &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;, &lt;a href="http://tapestry.apache.org/"&gt;Tapestry&lt;/a&gt;, &lt;a href="http://xmlgraphics.apache.org/fop/"&gt;FOP&lt;/a&gt;, ... vše budeme moci používat i nadále. Takže vlastně skoro o nic nepřijdeme, ale co vlastně získáme? To co získáme je absolutně závislé na tom, jaká bude JavaNW? &lt;br /&gt;&lt;br /&gt;Bude JavouNW &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;? Poslední dobu jsem vyplnil studiem tohoto opěvovaného jazyka. Musím přiznat, že jeho prvky jsou opravdu úchvatné (snad se o nich někdy rozepíšu podrobněji), ale je to jiný jazyk. Syntaxe je jiná, pravda kompaktnější (není tolik upovídaná a všechny vlastnosti jsou zakomponovány tak, že do sebe krásně zapadají). Je možné použít stávající knihovny, ale Scala má také vlastní, a ty je potřeba poznat. Je mi to moc líto, protože se mi Scala opravdu moc líbí, ale nemyslím, že se Scala stane JavouNW (nikdy jsem nevěštil, tak spoléhám na to, že to neumím ...).&lt;br /&gt;&lt;br /&gt;Tak co třeba některý ze skriptovacích jazyků: &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;, &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;, &lt;a href="http://www.jython.org/Project/index.html"&gt;Jython&lt;/a&gt;, ... Ne nemyslím si, že budoucnost je v netypových jazycích, Scala nabízí spoustu (netroufám si napsat všechny) vlastnosti, pro které se mi tyto jazyky zamlouvají, ale je typová. Nemyslím, že jsme schopni a ochotni se připravit o výhody typového jazyka: odhalení řady chyb již při překladu, lépe fugující Code Assist, refaktoring, ... Takže JavaNW musí být něco jiného.&lt;br /&gt;&lt;br /&gt;Takže kde vzít JavuNW? Za rozumné považuji více vyjít z Javy, aby se syntaxe nového jazyka Javě více podobala a přechod nebyl tak bolestný. Zakomponovat do něj všechny "potřebné" prvky pořádně: generiky, closures, paralelní zpracování a další. Pak by přechod mohl být pozvolný, poklidný a měli bychom nový "nabušený" jazyk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2691706694809246803?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2691706694809246803/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2691706694809246803' title='Počet komentářů: 10'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2691706694809246803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2691706694809246803'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/02/nova-java-jak-z-toho-ven.html' title='Nová Java: Jak z toho ven ...'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2797607240915553041</id><published>2008-01-21T20:24:00.000+01:00</published><updated>2008-01-21T20:41:48.711+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Jak vnést trochu pořádku do CSS</title><content type='html'>Jsem puntičkář, mám rád, když věci mají jasný řád. Ale todle nějak nejde dohromady s našimi CSS soubory. Snažil jsem se malinko upravit layout stránky a &lt;font style="font-style: italic;"&gt;vztekal&lt;/font&gt; jsem se s tím skoro půl dne. A pak mi srazil vaz Explorer a začal iterativní proces sbližování vzhledu Firefox vs. Explorer.&lt;br /&gt;&lt;br /&gt;Nakonec jsem se poohlídl na webu po nějakých radách a typech, jak zanést řád do změti selectorů, atributů a jejich hodnot. Našel jsem pár šikovných rad, které jsou zřejmě lidem pracujícím s CSS delší dobu již známy, protože si je velmi pravděpodobně již vymysleli nebo přečetli. Ale pro Javisty, kteří považují CSS spíš za nutné zlo, snad budou tyto rady prospěšné (i když všechny popisované principy jsou nám již dávno známé).&lt;h4&gt;Modulárnost&lt;/h4&gt;První věcí je modulárnost a její striktní dodržování. Přivede nás k opakovanému použití celých CSS souborů. Takže náš styl jsme rozdělili do následujících souborů:&lt;ul&gt;&lt;li&gt;&lt;font style="font-weight: bold;"&gt;Typografie&lt;/font&gt; - definuje základní vlastnosti HTML elementů včetně fontů, velikostí atd. Tento soubor je nezávislý na projektu.&lt;/li&gt;&lt;li&gt;&lt;font style="font-weight: bold;"&gt;Formuláře&lt;/font&gt; - asi nejsložitější část stylů, spousta hacků, aby formuláře vypadaly stejně ve většině prohlížečů apod.&lt;/li&gt;&lt;li&gt;&lt;font style="font-weight: bold;"&gt;Navigace&lt;/font&gt; - velmi často se menu aplikace dá použít napříč více projekty, takže proto jej umístěme do zvláštního souboru.&lt;/li&gt;&lt;li&gt;&lt;font style="font-weight: bold;"&gt;Layout&lt;/font&gt; - základní layout stránky je velmi jednoduše oddělitelný od zbytku a navíc je silně projektově závislý.&lt;/li&gt;&lt;li&gt;&lt;font style="font-weight: bold;"&gt;Barvy&lt;/font&gt; - definice barev je samostatná, což umožňuje jednoduché přebarvení stránek, vše máte na jednom místě.&lt;/li&gt;&lt;/ul&gt;Abychom neměli 5 CSS souborů (v souladu se &lt;a href="http://jirablog.blogspot.com/2007/09/zamerte-se-na-frontend.html"&gt;závěry z Yahoo!&lt;/a&gt;) pak je vhodné mít ještě šestý soubor, který složí 5 zmíněných v jeden pomocí &lt;code&gt;@import url("file_name.css");&lt;/code&gt;.&lt;h4&gt;Sjednocení marginu a paddingu mezi Explorerem a Firefoxem&lt;/h4&gt;Následuje zjednošení počtu hacků, které používají jiné definice pro Explorer a Firefox. Celá věc je velmi jednoduchá a ušetří spoustu kódu:&lt;pre&gt;&lt;br /&gt;&lt;code&gt;* {&lt;br /&gt;  padding:0;&lt;br /&gt;  margin:0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;h1, h2, h3, h4, h5, h6, p, pre, blockquote, label, ul, ol, dl, fieldset, address {&lt;br /&gt;  margin:1em 5%;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;li, dd {&lt;br /&gt;  margin-left:5%;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;fieldset {&lt;br /&gt;  padding: .5em;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Speciální CSS soubor pro Explorer&lt;/h4&gt;Protože jsme stále potřebovali řadu hacků, speciálně pro Explorer (primární platformou pro vývoj je u nás Firefox), pomocí podmíněného komentáře dotahujeme styl pro Explorer (nakonec jsme použili stejnou hierarchii jako v kapitole o modulárnosi):&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;!--[if IE] &amp;gt;&lt;br /&gt;&amp;lt; link rel="stylesheet" href="IE.css" media="screen" /&amp;gt;&lt;br /&gt;&amp;lt;![endif]-- &amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Závěr&lt;/h4&gt;Celé nám to chvíli trvalo, protože ve stylech skutečně panovala anarchie, ale nyní je velmi jednoduché představit nějaké změny, odstartovat nový projekt a podobně. Ukázalo se, že je možné zanést pořádek i tam, kde mi bylo tvrzeno, že to nejde ...&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Odkazy&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.contentwithstyle.co.uk/Articles/12/modular-css/"&gt;Modular CSS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://leftjustified.net/journal/2004/10/19/global-ws-reset"&gt;Global White Space Reset&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.contentwithstyle.co.uk/Articles/17/a-css-framework"&gt;A CSS Framework&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.contentwithstyle.co.uk/Articles/70/playing-nice-with-the-other-css-kids/"&gt;Playing Nice with the Other CSS Kids&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://leftjustified.net/journal/2004/10/07/css-negotiation/"&gt;CSS Negotiation And a Sanity Saving Shortcut&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2797607240915553041?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2797607240915553041/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2797607240915553041' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2797607240915553041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2797607240915553041'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/jak-vnest-trochu-poradku-do-css.html' title='Jak vnést trochu pořádku do CSS'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7148597264113325504</id><published>2008-01-14T11:13:00.000+01:00</published><updated>2008-01-14T11:37:54.147+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Používám Linux a nelituju ...</title><content type='html'>Nějak se rozhořelo téma Linuxu na desktopu (&lt;a href="http://www.sweb.cz/pichlik/archive/2007_11_04_archive.html"&gt;dagi&lt;/a&gt; či &lt;a href="http://finc.ic.cz/?p=43"&gt;Aleš Dostál&lt;/a&gt;), i když na specifickém desktopu a to jest desktopu vývojáře. Ja používám Linux na svém desktopu už skoro 5 let (od února roku 2003) a jsem s ním nad míru spokojen. Od jakživa používám SUSE, nyní openSUSE (altuálně 10.2) ve spojení s KDE (GNOME bylo zkraje hodně velký žrout paměti a už jsem zvyklý na KDE, takže měnit nebudu). Nově jsem si openSUSE nainstaloval i na své nové VAIO a světe div se, vše funguje (jenom původní token iKey 1000 není pod linuxem podporován, takže potřebuju iKey 3000 - to vše pro přístup do firemní sítě). &lt;br /&gt;&lt;br /&gt;A proč nechci už Windows ani vidět? Důvody jsou 3: KWrite, terminal a ssh. &lt;br /&gt;&lt;br /&gt;KWrite je ten nej editor na cokoliv, který jsem kdy viděl, přepínání kódování, blokové kopírování, podpora XML. Command line v podobě terminálu je naprosto k nezaplacení, nedokážu si představit, že bych pracoval bez ní (už v ní i kopíruju soubory, rozbaluju archivy apod.) a ve Windows jsem zatím nenašel solidní náhradu (ani jsem moc nehledal ...). A ssh je prostě víc než PuTTY, fungují všechny klávesy jak mají (např. ctrl + end).&lt;br /&gt;&lt;br /&gt;Největším problémem je asi přenos dokumentů mezi MS Office a OpenOffice, ale zvykl jsem si. Podpora se za těch pět let hodně zlepšila, opravdu hodně moc ... není to na to, abych něco napsaného v MS Office vytiskl a vypadalo to, jako vytištěné z MS Office, ale čitelné je vše (včetně poznámek, tj. není pravda co psal &lt;a href="http://weblog.ronnieweb.net/?p=147"&gt;ronnie&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;A proč se mi líbí právě SUSE a né třeba Fedora nebo Ubuntu? Je to kvůli YASTu, protože funguje jak v terminálu tak v Xkách a nastavím s ním většinu věcí, které běžně potřebuju ...&lt;br /&gt;&lt;br /&gt;Tj. nebojte se linuxu, je to jiný než myšoidní přístup Windows, asi nevypadá tak líbivě jako Windows, ale funguje spolehlivě a bezproblémově.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7148597264113325504?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7148597264113325504/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7148597264113325504' title='Počet komentářů: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7148597264113325504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7148597264113325504'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/01/pouzivam-linux-nelituju.html' title='Používám Linux a nelituju ...'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8849475103116746435</id><published>2008-01-08T17:24:00.000+01:00</published><updated>2008-01-10T08:44:16.152+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Chceme ji? - tvrdá realita</title><content type='html'>Dneska jsem si pročítal nějaké články o Closures v Javě a narazil jsem na článek &lt;a href="http://www.infoq.com/news/2007/12/closures-preserving-feel-of-java"&gt;Closures and Preserving the Feel of Java&lt;/a&gt;, který nepřináší nic nového, ale v jeho komentářích jsem našel perličku od  Kurta Christensena:&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;I remember a great presentation by Bjarne Stroustrup back around 1997 at the Computer Literacy bookstore. Someone said that Java looked like a much better, cleaner C++, to which Stroustrup replied that we should ask him about it again in 10 years after everyone was finished adding the features they want. Well, it's 10 years later, and new Java code is starting to look an awful lot like C++.&lt;/span&gt;&lt;/blockquote&gt;Tak trochu střílím do vlastních řad, protože jsem pro rozšiřování jazyka, ale nechci jej rozšiřovat za každou cenu, pokud se nějaké, byť prospěšné, rozšíření ukáže jako problématické, či zesložiťující syntaxi, pak jej nechme být ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8849475103116746435?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8849475103116746435/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8849475103116746435' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8849475103116746435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8849475103116746435'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/01/nova-java-cheme-ji-tvrda-realita.html' title='Nová Java: Chceme ji? - tvrdá realita'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-92911837971196569</id><published>2008-01-06T20:11:00.000+01:00</published><updated>2008-01-06T21:40:02.682+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Chceme ji? - počtvrté</title><content type='html'>Myslím, že jsem se dostal do finále, alepoň pro tento okamžik, protože poslední věc, která by jistě zasloužila vylepšení je vytváření naplněných collections. Dneska je nutné vytvořit instanci (Collection nebo Map) a postupně do ní přidávat prvky.&lt;br /&gt;&lt;br /&gt;Jistě existují různé "zkratky" přes pole, která můžeme vytvářet pomocí inicialiazátoru. Další pokrok přináší &lt;a href="http://code.google.com/p/google-collections/"&gt;Google Collections Library&lt;/a&gt;, ale stále to není ono. A přitom jednoduchou syntaxi již máme vymyšlenou, např. &lt;a href="http://groovy.codehaus.org/Collections"&gt;pro Groovy&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Takže proč collection nevytvořit:&lt;pre&gt;&lt;code&gt;Collection&amp;lt;Object&amp;gt; col = [ 1, 2, "33", new Long(10) ];&lt;/code&gt;&lt;/pre&gt;Je to jistě jednodušší než:&lt;pre&gt;&lt;code&gt;Collection&amp;lt;Object&amp;gt; col = new ArrayList&amp;lt;Object&amp;gt;();&lt;br /&gt;col.add(1);&lt;br /&gt;col.add(2);&lt;br /&gt;col.add("33");&lt;br /&gt;col.add(new Long(10));&lt;/code&gt;&lt;/pre&gt;Jen pro dolnění, prázdná mapa je: &lt;code&gt;[]&lt;/code&gt;.&lt;br /&gt;Pokud přejdeme na na mapy, je věc identická. Nejprve klasicky v Javě:&lt;pre&gt;&lt;code&gt;Map&amp;lt;Integer, String&amp;gt; map = new HashMap&amp;lt;Integer, String&amp;gt;();&lt;br /&gt;map.put(1, "1");&lt;br /&gt;map.put(2, "dva");&lt;br /&gt;map.put(3, "3");&lt;/code&gt;&lt;/pre&gt;A jak by tyto 4 řádky vypadaly, kdyby se vylepšila syntaxe vytváření map:&lt;pre&gt;&lt;code&gt;Map&amp;lt;Integer, String&amp;gt; map = [ 1:"1", 2:"dva", 3:"3" ];&lt;/code&gt;&lt;/pre&gt;Jenom pro doplnění prázdná mapa se vytvoří &lt;code&gt;[:]&lt;/code&gt;.&lt;h4&gt;Závěr&lt;/h4&gt;Nedokážu odpovědět na otázku, zda takovou Javu chceme? Za sebe mohu říci, že změny, které jsem navrhoval podporuju. Ale nesmí dojít k nejasnostem jako v případě implementace generik. Vše musí zapadnout do již existujícího jazyka a fungovat. Pokud se ukáže nějaký problém, jsem pro, aby se z implementace vycouvalo.&lt;br /&gt;Otázkou samozřejmě je, zda je nutné zachovat zpětnou kompatibilitu. Myslím si, že není problém udělat nekompatibilní &lt;span style="font-style:italic;"&gt;JavuX&lt;/span&gt; a vní implementovat vše co potřebujeme, ale je to co chceme? Ja myslím, že ne, protože to už by nebyla Java ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-92911837971196569?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/92911837971196569/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=92911837971196569' title='Počet komentářů: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/92911837971196569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/92911837971196569'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/01/nova-java-chceme-ji-poctvrte.html' title='Nová Java: Chceme ji? - počtvrté'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-9156547725867808474</id><published>2008-01-05T22:26:00.000+01:00</published><updated>2008-01-05T22:33:20.050+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Chceme ji? - potřetí</title><content type='html'>Původně jsem si myslel, že na tenký led typu closures se pouštět nebudu, protože to je hodně pálivé téma, ale když už se do toho pustil &lt;a href="http://www.sweb.cz/pichlik/archive/2007_12_30_archive.html#7915527453354164397"&gt;Dagi&lt;/a&gt;, chci přidat svůj pohled.&lt;br /&gt;&lt;br /&gt;Předně co si pod pojmem closures představuji já: v podstatě zavolatelný kód, takový pointer na funkci. Nespojoval bych to se správou zdrojů (Automatic Resource Management).&lt;br /&gt;&lt;br /&gt;Nejprve jsem si prošel všechny návrhy, které se okolo closures v Javě 7 přetřásají (&lt;a href="http://www.javac.info/consensus-closures-jsr.html"&gt;JSR&lt;/a&gt;, &lt;a href="http://www.javac.info/"&gt;BGGA&lt;/a&gt;, &lt;a href="http://docs.google.com/View?docid=k73_1ggr36h"&gt;CICE&lt;/a&gt;, &lt;a href="http://docs.google.com/View?docid=ddhp95vd_0f7mcns"&gt;FCM&lt;/a&gt;, &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=182412"&gt;C3S&lt;/a&gt;). Musím se přiznat, že přestože jsem relativně dost nakloněn novinkám v Javě, tak BGGA návrh mi přijde hodně špatný. Kód je složitý, closures není možné použít všude, kde to dává smysl, a tzv. closures se nechovají jako kus Java kódu (nejde použít &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt; ani dokonce &lt;code&gt;return&lt;/code&gt;). Takže pokud otázka stojí: &lt;span style="font-style:italic;"&gt;Chceme BGGA návrh jako closures do Javy?&lt;/span&gt; říkám jasně a nahlas &lt;span style="font-weight:bold;"&gt;Ne&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Je jasné, že přidat do Javy closures tak jak je známe např. z &lt;a href="http://groovy.codehaus.org/Closures"&gt;Groovy&lt;/a&gt; se asi nepovede. Takže potřebujeme nějakou zjednodušenou variantu. A ty vidím dvě. První, která se mi líbí kvůli velmi jednoduché syntaxi a široké nabídce možností, je FCM (First Class Methods). Jsem přesvědčen, že mi pomůže skutečně zjednodušit všechny typy algoritmů, kde si na closures vzpomenu, když je píšu v Javě.&lt;br /&gt;&lt;br /&gt;Kdyby existoval argument proč FCM nepoužít, pak se kloním k CICE, které není tak jednoduché jako FCM a není tak moc komplexní, ale přesto nabízí hodně. Bohužel neodstraňuje nutnost existence rozhraní, které bude "closure" implementovat...&lt;br /&gt;&lt;br /&gt;Věřím, že se BGGA v Javě 7 nedočkáme ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-9156547725867808474?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/9156547725867808474/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=9156547725867808474' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/9156547725867808474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/9156547725867808474'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2008/01/nova-java-chceme-ji-potreti.html' title='Nová Java: Chceme ji? - potřetí'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4883333043098293650</id><published>2007-12-30T21:51:00.000+01:00</published><updated>2007-12-30T23:17:01.201+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Chceme ji? - podruhé</title><content type='html'>Blíží se nám konec roku 2007 tak proč nepokračovat v mých představách změny jazyka, tj. takový malý výhled toho co by se v roce 2008 mohlo změnit.&lt;br /&gt;&lt;br /&gt;V předchozím příspěvku jsem se &lt;span style="font-style:italic;"&gt;rozjel&lt;/span&gt; na téma vylepšení programovaní paralelních programů. Dneska se pustím spíš do oblasti vylepšení psaní kódu, tj. změny, které cítím, že zpřehlední kód.&lt;h4&gt;Vylepšení příkazu &lt;code&gt;switch&lt;/code&gt;&lt;/h4&gt;Jistě všichni víme, že příkaz &lt;code&gt;switch&lt;/code&gt; funguje pouze  nad typy &lt;code&gt;int&lt;/code&gt; a &lt;code&gt;char&lt;/code&gt;. Takže žádný &lt;code&gt;long&lt;/code&gt;, &lt;code&gt;fload&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, natož např. &lt;code&gt;String&lt;/code&gt; (o tomto konkrétním typu hovořili pánové v &lt;a href="http://javaposse.com/index.php?post_id=281768"&gt;JavaPosse #151&lt;/a&gt;). Kdo se podíval pod pokličku překladu &lt;code&gt;switch&lt;/code&gt; příkazu do bytecodu, zjistil, že k tomu slouží dvě instrukce, buď &lt;code&gt;lookupswitch&lt;/code&gt; nebo &lt;code&gt;tableswitch&lt;/code&gt;. V podstatě jde o to, že tato instrukce na základě hodnoty výrazu ve &lt;code&gt;switch&lt;/code&gt;  příkazu skočí na správný &lt;code&gt;case&lt;/code&gt;. Pokud chceme vytvořit ekvivalent např. pro &lt;code&gt;String&lt;/code&gt;, pak použijeme kaskádu &lt;code&gt;if - else if - else if ... &lt;/code&gt;.&lt;br /&gt;Proč, ale nepovolit &lt;code&gt;switch&lt;/code&gt; i pro jiné výsledné typy výrazu (např. &lt;code&gt;String&lt;/code&gt;) a až překladačem vše přeložit stejně jako onu kaskádu &lt;code&gt;if&lt;/code&gt;ů?&lt;h4&gt;Odchytávání více typů výjimek najednou při zachování typu výjimky&lt;/h4&gt;I v tomto případě jsem se nechal inspirovat povídáním pánů z JavaPosse. No představme si následující metodu:&lt;pre&gt;&lt;code&gt;protected Object invokeMethod(String s) throws IllegalArgumentException, &lt;br /&gt; IllegalAccessException, InvocationTargetException, &lt;br /&gt; SecurityException, NoSuchMethodException &lt;br /&gt;{&lt;br /&gt; Method m = String.class.getMethod("toString", new Class[0] );&lt;br /&gt; return m.invoke(s, new Object[0]);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Nyní chceme tuto metodu zavolat a vyhodit jinou výjimku v případě, že se nepodařilo najít metodu a jinou v případě, že se ji nepodařilo zavolat. Nemáme jinou volbu než:&lt;pre&gt;&lt;code&gt;try {&lt;br /&gt; invokeMethod("A");&lt;br /&gt;} catch (IllegalArgumentException e) {&lt;br /&gt; throw new CantInvokeException(e);&lt;br /&gt;} catch (IllegalAccessException e) {&lt;br /&gt; throw new CantInvokeException(e);&lt;br /&gt;} catch (InvocationTargetException e) {&lt;br /&gt; throw new CantInvokeException(e);&lt;br /&gt;} catch (SecurityException e) {&lt;br /&gt; throw new CantFindMethodException(e);&lt;br /&gt;} catch (NoSuchMethodException e) {&lt;br /&gt; throw new CantFindMethodException(e);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;A to je vskutnu &lt;span style="font-style:italic;"&gt;zvěrstvo&lt;/span&gt;. Nebylo by přeci jenom lepší něco následujícího:&lt;pre&gt;&lt;code&gt;try {&lt;br /&gt; invokeMethod("A");&lt;br /&gt;} catch (IllegalArgumentException, IllegalAccessException, &lt;br /&gt; InvocationTargetException: Exception e) {&lt;br /&gt; throw new CantInvokeException(e);&lt;br /&gt;} catch (SecurityException, NoSuchMethodException: Exception e) {&lt;br /&gt; throw new CantFindMethodException(e);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Máme možnost specifikovat libovolný počet typů vyjímek, které chceme odchytit jediným &lt;code&gt;catch&lt;/code&gt; příkazem, za seznam přidáme dvojtečku a specifikujeme typ proměnné (v našem případě je nejbližším společným předkem výjimek typ &lt;code&gt;Exception&lt;/code&gt;, který je zároveň typem proměnné &lt;code&gt;e&lt;/code&gt;). Kloním se k variantě, že programátor musí specifikovat typ proměnné, nenechával bych to na překladači.&lt;br /&gt;Co znamená dodatek &lt;span style="font-style:italic;"&gt;při zachování typu výjimky&lt;/span&gt; z názvu kapitoly? Pokud bychom kód z předchozího úryvku změnili na:&lt;pre&gt;&lt;code&gt;try {&lt;br /&gt; invokeMethod("A");&lt;br /&gt;} catch (IllegalArgumentException, IllegalAccessException, &lt;br /&gt; InvocationTargetException: Exception e) {&lt;br /&gt; //něco&lt;br /&gt; throw e;&lt;br /&gt;} catch (SecurityException, NoSuchMethodException: Exception e) {&lt;br /&gt; //něco jiného&lt;br /&gt; throw e;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;a uvedli ho v metodě se stejnou klauzulí &lt;code&gt;throws&lt;/code&gt; jako má metoda &lt;code&gt;invokeMethod&lt;/code&gt;, pak bude vše v pořádku. Překladač se nebude zlobit, že se snažíme vyhodit výjimku typu &lt;code&gt;Exception&lt;/code&gt; z metody, která ji nemá uvedenou ve &lt;code&gt;throws&lt;/code&gt;, protože proměnná &lt;code&gt;e&lt;/code&gt; je typu &lt;code&gt;Exception&lt;/code&gt;, ale může nabývat pouze hodnot typů uvedených před dvojtečkou. Samozřejmě musí být &lt;code&gt;final&lt;/code&gt; (není tak uvedená, ale je).&lt;h4&gt;Závěr&lt;/h4&gt;Obě tyto vychytávky rozhodně nezesložití jazyk, a když tak jenom nepatrně. Ale přinesou bezesporu větší čitelnost řadě algoritmů. To je přínos, který jednoznačně stojí minimálně za zamyšlení.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4883333043098293650?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4883333043098293650/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4883333043098293650' title='Počet komentářů: 12'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4883333043098293650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4883333043098293650'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/12/nova-java-chceme-ji-podruhe.html' title='Nová Java: Chceme ji? - podruhé'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-713690614124991439</id><published>2007-12-21T21:31:00.000+01:00</published><updated>2007-12-21T23:19:02.378+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='budoucnost'/><title type='text'>Nová Java: Chceme ji?</title><content type='html'>Zamýšlel jsem se nad myšlenkou, změny jazyka Java tak, aby lépe odrážel dnešní potřeby a obsahoval moderní prvky představené především ve skriptovacích jazycích. V poslední době se objevilo pár příspěvků na toto téma, na jedné straně příznivci změn reprezentovaní například &lt;a href="http://javaposse.com/index.php?post_id=281768"&gt;JavaPosse #151&lt;/a&gt; a na straně druhé spíše odpůrci, např. &lt;a href="http://www.sweb.cz/pichlik/archive/2007_12_02_archive.html#6145492790000353"&gt;Dagi&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Já se spíš stavím za to, aby se jazyk vyvíjel a měnil. Jsem přesvědčen o tom, že požadavky kladené na dnešní "moderní" programovací jazyky jsou diametrálně odlišné od požadavků kladených před oněmi 12 lety, kdy byla Java představena.&lt;br /&gt;&lt;br /&gt;Co považuji za nejdůležitejší změnu? Jednoduše použitelná podpora programování multithreadových aplikací. Jistě od roku 1995 máme &lt;code&gt;synchronized&lt;/code&gt;, nyní již máme i &lt;code&gt;java.util.concurrent&lt;/code&gt;. Do Javy 7 se blíží implementace &lt;a href="http://www.ibm.com/developerworks/java/library/j-jtp11137.html"&gt;fork-join algoritmu (pod vedením JSR 166)&lt;/a&gt;, ale stále si myslím, že je to málo.&lt;br /&gt;&lt;br /&gt;Proč chci víc? Programování multithreadových aplikací je stále složitá věc, rozhodně to není pro široké masy programátorů. A dneska je každý nový počítač více-procesorový a abychom využili jejich schopností, pak potřebujeme multithreadovou aplikaci.&lt;br /&gt;&lt;br /&gt;Kde bych hledal inspiraci? Co třeba &lt;a href="http://x10.sourceforge.net/x10home.shtml"&gt;programovací jazyk X10&lt;/a&gt;. Ten je dokonce překládán do Javy. Obsahuje řadu konstruktů, které k programování fork-join konstruktů přímo vybízejí (&lt;code&gt;async&lt;/code&gt;, &lt;code&gt;atomic&lt;/code&gt;, &lt;code&gt;finish&lt;/code&gt;, &lt;code&gt;when&lt;/code&gt;, atd.). &lt;br /&gt;&lt;br /&gt;Myslím, ře prostorů, ve kterých by se Java mohla zlepšovat je jistě nepřeberné množství, a Java bude muset tuto hozenou rukavici zvednout.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-713690614124991439?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/713690614124991439/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=713690614124991439' title='Počet komentářů: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/713690614124991439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/713690614124991439'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/12/nova-java-chceme-ji.html' title='Nová Java: Chceme ji?'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-7705309213325065961</id><published>2007-12-07T07:39:00.000+01:00</published><updated>2007-12-07T08:00:21.500+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='idea'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><title type='text'>Eclipse, Mylyn, IntelliJ IDEA a Teamcity v CZPodcast #19</title><content type='html'>Ještě jsem poslední (#19) CZ Podcast nedoposlouchal celý, ale když se věci začali točit okolo &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; &lt;a href="http://www.eclipse.org/mylyn/"&gt;Mylynu&lt;/a&gt;, tak bych si troufl provést malé doplnění. Mylyn už nějaký pátek (přesně už to bude přes čtvrt roku) používám a už se dlouho chystám, že se s vámi podělím o své, ve skrze pozitivní, zkušenosti, ale nějak nenacházím tolik potřebnou sílu ...&lt;br /&gt;&lt;br /&gt;Takže &lt;a href="http://www.jetbrains.com/teamcity/"&gt;Teamcity&lt;/a&gt;, není Mylyn, ale je to skutečně &lt;a href="http://en.wikipedia.org/wiki/Continuous_Integration"&gt;Continuous Integration&lt;/a&gt; server. Mylyn má ve skrze 3 oblasti, kam upírá svou pozornost:&lt;ul&gt;&lt;li&gt;práce s bug tracking systémem, plánování požadavků, jejich zobrazování, ukládání kontextu k nim atd.&lt;/li&gt;&lt;li&gt;zaměření prostředí na zobrazování pouze relevantních informací v IDE (týkajících se aktuálně zpracovávaného požadavku) = založeno na kontextu, jenž se dá k požadavku uložit - především se to týká filtrování toho, co není k právě realizovanému požadavku relevantní&lt;/li&gt;&lt;li&gt;vytváření change setů pro commit do &lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt; (&lt;a href="http://ximbiot.com/cvs/cvshome/"&gt;CVS&lt;/a&gt;) na základě kontextu&lt;/li&gt;&lt;/ul&gt;Co je mi známo, pak &lt;a href="http://www.jetbrains.com/idea/"&gt;IDEA&lt;/a&gt; má podporu pro podobnou věc, ale není navázána na bug tracking systém (tj. požadavky si vytváříte ručně) a UI projektu se nijak nemění (nezaměřuje). Tj. sleduje, který soubor se modifikuje a pak vytváří change set pro commit zdrojáků. Podporuje přepínání požadavků a vytvoření správných change setů podobně jako Mylyn.&lt;br /&gt;&lt;br /&gt;Sice IDEAu nepoužívám, a nikdy neříkej nikdy .. Třeba mě tento příspěvek nakopne, abych sepsal ten MYLYN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-7705309213325065961?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/7705309213325065961/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=7705309213325065961' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7705309213325065961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/7705309213325065961'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/12/eclipse-mylyn-intellij-idea-teamcity-v.html' title='Eclipse, Mylyn, IntelliJ IDEA a Teamcity v CZPodcast #19'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1024378049817169434</id><published>2007-11-30T07:34:00.000+01:00</published><updated>2007-11-30T07:50:11.343+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Unit testy - ty přece píše kodér, ne?</title><content type='html'>Tentokrát spíš chci prodiskutovat jedno téma, než vám něco sdělit. Právě jsem dočetl článek Akshay Sharmi o návrhu, který myslí na testovatelnost kódu (&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=DesigntoUnitTest"&gt;Design to Unit Test&lt;/a&gt;). Jediná věc, která mě na tomto článku přímo praštila do očí, je skutečnost, že je psán tak, jako že unit testy píše někdo jiný, než ten, kdo testovaný kód psal. &lt;br /&gt;&lt;br /&gt;Já jsem vždy přemýšlel o unit testech jako o věci, kterou si kodér ověřuje, že jeho kód funguje tak, jak má. Navíc si kodér musí již dopředu rozmyslet, jak svůj kód otestuje, což bezesporu vede k jeho větší kvalitě. V neposlaení řadě unit testy vnímám také jako "dokumentaci" ke kódu, což v případě, že je píše někdo jiný opět selhává. &lt;br /&gt;&lt;br /&gt;Je pravdou, že psaní testů je trochu jiná káva, než psaní kódu. Je nutné se to naučit. Ale není to zase tak složité. V případě integračních a akceptačních testů je již zřejmé, že je může (nebo má?) implementovat někdo jiný než kodér.&lt;br /&gt;&lt;br /&gt;Obávám se, že tento přístup není pro mě. Navíc bych si troufl s ním nesouhlasit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1024378049817169434?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1024378049817169434/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1024378049817169434' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1024378049817169434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1024378049817169434'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/11/unit-testy-ty-prece-pise-koder-ne.html' title='Unit testy - ty přece píše kodér, ne?'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1723592211036923596</id><published>2007-11-29T23:00:00.000+01:00</published><updated>2007-11-29T23:58:55.012+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>XML Signature - použít nebo ne?</title><content type='html'>V naší aplikaci přenášíme poměrně velké XML soubory a přenášíme jich více najednou. Proto jsou zazipované v ZIP archivu. Ovšem potřebujeme nějak zabezpečit, aby nebylo možné měnit obsah archivu (tj. nemožnost přidávat či mazat soubory) a dále aby nešlo měnit jednotlivé XML soubory. Navíc tato komunikace neprobíhá mezi naším softwarem, ale mezi naším a cizím. Jak věc vyřešit? &lt;br /&gt;&lt;br /&gt;Použít &lt;a href="http://en.wikipedia.org/wiki/XML_Signature"&gt;XML Signature&lt;/a&gt; (&lt;a href="http://www.w3.org/TR/xmldsig-core/"&gt;specifikace&lt;/a&gt;) nebo ne? Než jsem se pustil do zkoušení hledal jsem na netu a našel jsem pár mailů v konferencích a blogů, že XML Signature implementace nefunguje dobře na "large documents". Už jsem přemýšlel o vlastním řešení, kde bych hashoval XML soubory jako stream bytů, nebo bych vytvořil nějaký vlastní algoritmus pracující přímo nad &lt;a href="http://en.wikipedia.org/wiki/Simple_API_for_XML"&gt;SAXem&lt;/a&gt;, který používáme jak pro čtení tak i pro zápis dokumentů. Ale nakonec jsem si řekl, že to zkusím přímo s XML Signature a šáhl jsem po implementací, která je součástí JDK 6. Pro XML Signature hovoří skutečnosti, že je to standard (nemusím specifikovat jak se podpis vypočítá) a existuje implementace pro skoro všechny rozšířené jazyky.&lt;br /&gt;&lt;br /&gt;Napsal jsem tedy velmi jednoduchou třídu &lt;code&gt;XMLSignatureTest&lt;/code&gt; (při jejím psaní jsem převážně vycházel z &lt;a href="http://java.sun.com/webservices/docs/1.5/tutorial/doc/XMLDigitalSignatureAPI8.html"&gt;příkladu v XML Digital Signature API Examples&lt;/a&gt;): &lt;pre&gt;&lt;code&gt;public class XMLSignatureTest {&lt;br /&gt;&lt;br /&gt;   protected static final String KEY_ALIAS = "ALIAS";&lt;br /&gt;&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      try {&lt;br /&gt;         long milis = System.currentTimeMillis();&lt;br /&gt;         if ("sign".equals(args[0])) {&lt;br /&gt;            signing(new File(args[1]), new File(args[2]));&lt;br /&gt;         } else {&lt;br /&gt;            System.out.println(verify(new File(args[1])) ? "Verified - ok" : "Changed");&lt;br /&gt;         }&lt;br /&gt;         System.out.println("Done in " + (System.currentTimeMillis() - milis) + " ms.");&lt;br /&gt;      } catch (Throwable t) {&lt;br /&gt;         t.printStackTrace();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   protected static void signing(File xmlFile, File signatureFile) throws Exception {&lt;br /&gt;      //načti vstupní XML dokument&lt;br /&gt;      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();&lt;br /&gt;      dbf.setNamespaceAware(true);&lt;br /&gt;      DocumentBuilder builder = dbf.newDocumentBuilder();&lt;br /&gt;      Document doc = builder.parse(new FileInputStream(xmlFile));&lt;br /&gt;&lt;br /&gt;      //otevři keystore a načti z něj privátní klíč k podpisu hashe&lt;br /&gt;      KeyStore keyStore = KeyStore.getInstance("JKS");&lt;br /&gt;      keyStore.load(new FileInputStream("keystore"), "XMLSig".toCharArray());&lt;br /&gt;      PrivateKey key = (PrivateKey) keyStore.getKey(KEY_ALIAS, "MEkeypwd".toCharArray());&lt;br /&gt;&lt;br /&gt;      //nadefinuj context podpisu&lt;br /&gt;      DOMSignContext dsc = new DOMSignContext(key, doc.getDocumentElement());&lt;br /&gt;      XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");&lt;br /&gt;      &lt;br /&gt;      //podepiš celý dokument, na canonicalizaci použij metodu INCLUSIV, jako hash použij SHA1 algoritmus&lt;br /&gt;      //podpis bude vložen do podepisovaného dokumentu a výsledný hash bude zakryptovát DSA klíčem &lt;br /&gt;      Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), &lt;br /&gt;            Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (XMLStructure) null)), &lt;br /&gt;            null, null);&lt;br /&gt;      SignedInfo si = fac.newSignedInfo(&lt;br /&gt;            fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (XMLStructure) null), &lt;br /&gt;            fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null), Collections.singletonList(ref));&lt;br /&gt;&lt;br /&gt;      //do podpisu jako informaci o použitém klíči vložíme jeho alias&lt;br /&gt;      //tj. obě strany se musí domluvit na aliasech a předat si veřejné klíče&lt;br /&gt;      KeyInfoFactory kif = fac.getKeyInfoFactory();&lt;br /&gt;      KeyName kn = kif.newKeyName(KEY_ALIAS);&lt;br /&gt;      KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kn));&lt;br /&gt;&lt;br /&gt;      //spočítej podpis&lt;br /&gt;      XMLSignature signature = fac.newXMLSignature(si, ki);&lt;br /&gt;      signature.sign(dsc);&lt;br /&gt;&lt;br /&gt;      //ulož výsledný dokument do souboru&lt;br /&gt;      OutputStream os = new FileOutputStream(signatureFile);&lt;br /&gt;      TransformerFactory tf = TransformerFactory.newInstance();&lt;br /&gt;      Transformer trans = tf.newTransformer();&lt;br /&gt;      trans.transform(new DOMSource(doc), new StreamResult(os));&lt;br /&gt;      os.flush();&lt;br /&gt;      os.close();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   protected static boolean verify(File xmlFile) throws Exception {&lt;br /&gt;      //načti XML document s vloženým podpisem&lt;br /&gt;      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();&lt;br /&gt;      dbf.setNamespaceAware(true);&lt;br /&gt;      DocumentBuilder builder = dbf.newDocumentBuilder();&lt;br /&gt;      Document doc = builder.parse(new FileInputStream(xmlFile));&lt;br /&gt;&lt;br /&gt;      //najdi v dokumentu podpis&lt;br /&gt;      NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");&lt;br /&gt;      if (nl.getLength() == 0) {&lt;br /&gt;         throw new Exception("Cannot find Signature element");&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      //otevři keystore pro načtení veřejného klíče&lt;br /&gt;      KeyStore keyStore = KeyStore.getInstance("JKS");&lt;br /&gt;      keyStore.load(new FileInputStream("keystore"), "XMLSig".toCharArray());&lt;br /&gt;&lt;br /&gt;      //vytvoř validační kontext (node s podpisem a KeySelector pro získání &lt;br /&gt;      //klíče podle identifikace v podpisu - v našem případě je to ALIAS)&lt;br /&gt;      DOMValidateContext valContext = &lt;br /&gt;         new DOMValidateContext(new KeyNameKeySelector(keyStore), nl.item(0));&lt;br /&gt;      XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");&lt;br /&gt;      XMLSignature signature = factory.unmarshalXMLSignature(valContext);&lt;br /&gt;&lt;br /&gt;      //ověř podpis&lt;br /&gt;      return signature.validate(valContext);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //tato třída slouží k nalezení veřejného klíče použitelného k odkryptování podpisu&lt;br /&gt;   private static class KeyNameKeySelector extends KeySelector {&lt;br /&gt;      protected KeyStore keyStore;&lt;br /&gt;&lt;br /&gt;      public KeyNameKeySelector(KeyStore keyStore) {&lt;br /&gt;         super();&lt;br /&gt;         this.keyStore = keyStore;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      //tato metoda je volána knihovnou&lt;br /&gt;      public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, &lt;br /&gt;            AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException {&lt;br /&gt;&lt;br /&gt;         if (keyInfo == null) {&lt;br /&gt;            throw new KeySelectorException("Null KeyInfo object!");&lt;br /&gt;         }&lt;br /&gt;         SignatureMethod sm = (SignatureMethod) method;&lt;br /&gt;         List&lt;?&gt; list = keyInfo.getContent();&lt;br /&gt;&lt;br /&gt;         for (int i = 0; i &lt; list.size(); i++) {&lt;br /&gt;            XMLStructure xmlStructure = (XMLStructure) list.get(i);&lt;br /&gt;            //my hledáme klíč podle jména (aliasu)&lt;br /&gt;            if (xmlStructure instanceof KeyName) {&lt;br /&gt;               try {&lt;br /&gt;                  //natáhnem veřejný klíč z keystoru&lt;br /&gt;                  Certificate certificate = keyStore.getCertificate(((KeyName) xmlStructure).getName());&lt;br /&gt;                  PublicKey pk = certificate.getPublicKey();&lt;br /&gt;                  //ověříme, že v podpisu je stejný algoritmus jako používá klíč&lt;br /&gt;                  if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {&lt;br /&gt;                     return new SimpleKeySelectorResult(pk);&lt;br /&gt;                  }&lt;br /&gt;               } catch (KeyStoreException kse) {&lt;br /&gt;                  throw new KeySelectorException(kse);&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;         throw new KeySelectorException("No KeyValue element found!");&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      //pouze porovnává algoritmy&lt;br /&gt;      static boolean algEquals(String algURI, String algName) {&lt;br /&gt;         if (algName.equalsIgnoreCase("DSA") &lt;br /&gt;               &amp;&amp; algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {&lt;br /&gt;            return true;&lt;br /&gt;         } else if (algName.equalsIgnoreCase("RSA") &lt;br /&gt;               &amp;&amp; algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {&lt;br /&gt;            return true;&lt;br /&gt;         } else {&lt;br /&gt;            return false;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      //jenom holder pro klíč&lt;br /&gt;      private static class SimpleKeySelectorResult implements KeySelectorResult {&lt;br /&gt;         private Key pk;&lt;br /&gt;&lt;br /&gt;         SimpleKeySelectorResult(Key pk) {&lt;br /&gt;            this.pk = pk;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         public Key getKey() {&lt;br /&gt;            return pk;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Úpravy spočívají pouze v použití key-storu pro získání klíču a nepřenášení veřejného klíče v podpisu, ale pouze jeho aliasu.&lt;br /&gt;&lt;br /&gt;A nyní k samotným testům. Zajímal jsem se o dva faktory: rychlost a peměťová náročnost. &lt;br /&gt;&lt;br /&gt;Takže nejprve jsem test prováděl na XML dokumentu o velikosti 6,5 kB. Výpočet podpisu i ověření proběhlo i s nejmenším možným heapem, tj. 2M (1M nestačilo ani na nastartování JDKčka) a výpočet podpisu a serializace trvala 0,6 s. Co se verifikace podpisu týče, došel jsem k úplně stejnému číslu.&lt;br /&gt;&lt;br /&gt;Následně jsem přitvrdil a použil jsem soubor o velikost 4,1 MB. Minimální heap, nad kterým jsem se dobral výsledku a nedostav pouze OOM exception byl 53MB a výpočet podpisu včetně serializace výsledku trval 10s, ověření podpisu trvalo pouze 4,8s a dokonce potřebovalo minimálně pouze 47MB. Při použití heapu o velikosti 400MB jsem se u podpisu dostal na čas 4,8s a u ověření na 2,8s.&lt;h4&gt;Závěr&lt;/h4&gt;V podstatě jsem byl velmi mile překvapen, jak vše hladce a na první pokus proběhlo a spíš jsem hledal skulinu, jak XML Signature použít. Z prvu mi vadilo, že je nutné použít &lt;a href="http://cs.wikipedia.org/wiki/Document_Object_Model"&gt;DOM&lt;/a&gt;, protože používáme SAX (a použít &lt;code&gt;Transaformer&lt;/code&gt; se vstupem &lt;code&gt;SAXSource&lt;/code&gt; a s výstupem &lt;code&gt;DOMResult&lt;/code&gt; se mi nechtělo). Pak jsem si uvědomil, že bych stejně nemohl výpočet podpisu zařadit přímo do zpracování dokumentu, protož zpracování může trvat i dost dlouho (třeba i desítky minut). Souborů se může zpracovávat více najednou. Pokud by každý, nedejbože, byl rovnou podepisován a vytváření podpisu by si slízlo 50MB heapu, pak bych měl na serveru pamět jenom pro podepisování.&lt;br /&gt;&lt;br /&gt;Nakonec jsem se rozhodl, že prvním krokem zpracování bude načtení dokumentu pomocí DOM a ověření podpisu. Následně teprve, pokud bude vše v pořádku, budu dokument načítat pomocí SAX (do budoucna stejně přejdeme na &lt;a href="http://en.wikipedia.org/wiki/StAX"&gt;StAX&lt;/a&gt;) a dokument budu zpracovávat a zároveň budu generovat výstup (také pomocí SAX) a ten budu serializovat do souboru. Na závěr výstupní soubor načtu pomocí DOM a vygeneruju podpis.&lt;br /&gt;&lt;br /&gt;V neposlední řadě, tak trochu pod čarou, zmíním canonicalizaci, která funguje opravdu pěkně, přidávání mezer, nových prázdných řádků, přehazování pořadí atributů neovlivní platnost podpisu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1723592211036923596?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1723592211036923596/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1723592211036923596' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1723592211036923596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1723592211036923596'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/11/xml-signature-pouzit-nebo-ne.html' title='XML Signature - použít nebo ne?'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-6312121179586021233</id><published>2007-11-19T21:04:00.000+01:00</published><updated>2007-11-19T21:52:34.961+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>JavaScript a Dependency Injection</title><content type='html'>Všichni jste už asi slyšeli o &lt;a href="http://www.springframework.org/"&gt;Spring IoC&lt;/a&gt;, &lt;a href="http://www.picocontainer.org/"&gt;Picocontaineru&lt;/a&gt;, &lt;a href="http://hivemind.apache.org/"&gt;HaveMindu&lt;/a&gt; či &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-ioc/"&gt;Tapestry IoC&lt;/a&gt;. Ale což takhle &lt;a href="http://martinfowler.com/articles/injection.html"&gt;IoC&lt;/a&gt; pro JavaScript?&lt;br /&gt;&lt;br /&gt;Ano je to možné. Jmenuje se &lt;a href="http://code.google.com/p/squirrel-ioc/"&gt;Squirel Ioc&lt;/a&gt;. Jedná se o velmi jednoduchou knihovna, která má 4kB a používá &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Použití je velmi jednoduché (jak už se v mých příspěvcích stalo pravidlem). Máme následující třídy, které budeme &lt;span style="font-style:italic;"&gt;propojovat&lt;/span&gt;:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function MyModel(){&lt;br /&gt;  //obsah třídy MyModel&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function MyDAO(model){&lt;br /&gt;  var _model=model;&lt;br /&gt;&lt;br /&gt;  this.get = function() { &lt;br /&gt;    return _model;&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  this.save = function() { &lt;br /&gt;    //uloz&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  this.delete = function() {&lt;br /&gt;    //smaz&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function MyService(){&lt;br /&gt;  var _dao = null;&lt;br /&gt;    &lt;br /&gt;  this.get = function() {&lt;br /&gt;    return _dao.get();&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  this.getDao = function() {&lt;br /&gt;    return _dao;&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  this.setDao = function(dao) {&lt;br /&gt;    _dao = dao;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function MyApp(){&lt;br /&gt;  var _service=null;                 &lt;br /&gt;  //rikame IoC containeru, ze az vse nastavi, ma zavolat metodu onContextSupport&lt;br /&gt;  ContainerSupport.call(this);        &lt;br /&gt;    &lt;br /&gt;  this.onContextSupport = function(containerContext){  &lt;br /&gt;    var model=_service.get();&lt;br /&gt;    //udelej cokoliv dalsiho s hodnotou ...&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  this.setService = function(service){&lt;br /&gt;    _service = service;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Z pohledu IoC v Javě máme &lt;a href="http://en.wikipedia.org/wiki/POJO"&gt;POJO &lt;/a&gt;objekty a teď je potřebuje spolu nějak svázat (ve Springu se k tomu např. používá xml soubor nebo anotace). Při použití Squirrel IoC nám poslouží velmi jednoduchý kód:&lt;pre&gt;&lt;code&gt;var definition={&lt;br /&gt;  'model':{type:MyModel},&lt;br /&gt;  'dao':{type:MyDAO,args:[{ref:'model'}]},&lt;br /&gt;  'service':{type:MyService,props:[{name:'dao',ref:'dao'}]},&lt;br /&gt;  'app':{type:MyApp,props:[{name:'containerContext',ref:'containerContext'},{ref:'service'}]}&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;  var container = new IContainer();&lt;br /&gt;  container.load(definition);&lt;/code&gt;&lt;/pre&gt;V příkladu je vidět constructor injection (na příkladu definice &lt;code&gt;dao&lt;/code&gt; objektu) či setter injection (na příkladu objektu &lt;code&gt;service&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;Když to funguje v Javě, proč ne v JavaScriptu. Opět se ukazuje jednoduchost, kterou nám JavaScript jako dynamický jazyk nabízí. A příště až budete potřebovat propojit pár objektů mezi sebou, zamyslete se, zda vám Squirrel Ioc neusnadní práci.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-6312121179586021233?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/6312121179586021233/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=6312121179586021233' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6312121179586021233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6312121179586021233'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/11/javascript-dependency-injection.html' title='JavaScript a Dependency Injection'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8549861095508600359</id><published>2007-11-10T22:43:00.000+01:00</published><updated>2007-11-10T23:27:13.228+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Nejde říci co je cennější, zda znalosti nebo zkušenosti</title><content type='html'>Jak je naznačeno v příspěvku &lt;a href="http://blog.krecan.net/2007/11/10/znalosti-a-zkusenosti/"&gt;Znalosti a zkušenosti&lt;/a&gt;, zkušenost je víc než znalost.&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;Podle mě jde hlavně o rozdíl mezi znalostí a zkušeností. Znalosti jsou laciná věc. Stačí zajít do školy, projít si pár článku na internetu a nebo nedej bože přečíst knihu. Pokud máte funkční paměť nejen v počítači ale i v hlavě, tak znalosti nabudete velice snadno.&lt;/span&gt;&lt;/blockquote&gt;A hned jsem si vzpomněl na strýčka z Jirotkova Saturnina, který měl malou chemickou továrnu a nebyl vzdělán v oboru, na všechno si přišel sám. Vše co bylo napsáno v moudrých knihách on složitě vymýšlel. Neměl žádné znalosti, ale nespočetně mnoho zkušeností. Bohužel, vždy když vyráběl nové mýdlo, netušil co se mu v kádích uvaří ...&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;Jsou to zkušenosti co se počítá. Můžu si přečíst kolik knih chci o tom jak se mají správně dělat softwarové projekty. Dokud to ale nezažiji na vlastní kůži, mají tyto znalosti malou váhu (bojím se že nulovou). Zkušenosti mají také jednu obrovskou výhodu. Málo stárnou. Když mám zažito jak psát software, jaká pravidla dodržovat a čeho se vyvarovat, je mi více méně jedno jakou technologii používám. Detaily si dokáži nastudovat.&lt;/span&gt;&lt;/blockquote&gt;Není přeci nutné mít zkušenost s popáleninou od rozpálených kamen, když mám znalost, že to je dost hrozné. Zkušenost dává znalostem rozměrem. Dává jim ten osobní kontakt s nimi. Ale zároveň nám umožňuje tento rozměr v budoucnu dát znalostem přímo, bez zkušenosti.  Znalost nás směřuje správným směrem a zaměřuje naše zkoumání a vytváření zkušeností k užitečným cílům.&lt;br /&gt;&lt;br /&gt;A teď musím navázat na Vlastůvovu reakci &lt;a href="http://vavru.cz/ostatni/co-se-pocita/"&gt;Co se počítá&lt;/a&gt;, ve které zase uhodil hřebíček na hlavičku (jak on to dělá?). Nejde o to, jak své dovednosti získáme, či zkušeností nebo znalostí, každý jsme jiný (někomu vyhovuje si přečíst referenční příručku, někdo jiný si věc raději osahá), ale jde o to, jak svých schopností využijeme k plnění cílů, které jsou nám předkládány.&lt;br /&gt;&lt;br /&gt;Takže čtěme, vzdělávejme se, nebojme se poučit od druhých, zkušenějších, berme jejich rady vážně, protože jenom tak nezopakujeme chyby, kterých se dopustili, a získáme více drahoceného času. A třeba to dotáhneme ještě dál než oni.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8549861095508600359?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8549861095508600359/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8549861095508600359' title='Počet komentářů: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8549861095508600359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8549861095508600359'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/11/nejde-rici-co-je-cenejsi-zda-znalosti.html' title='Nejde říci co je cennější, zda znalosti nebo zkušenosti'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5927838368041683720</id><published>2007-11-01T22:48:00.000+01:00</published><updated>2007-11-01T23:49:56.615+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='databáze'/><title type='text'>A je to tady - XQuery Update v pureXML</title><content type='html'>Kdo si počká, ten se dočká. Od &lt;a href="http://www-01.ibm.com/common/ssi/cgi-bin/ssialias?infotype=AN&amp;amp;subtype=CA&amp;amp;htmlfid=897/ENUS207-261&amp;amp;appname=USN"&gt;včera&lt;/a&gt; je možné si stáhnout IBM DB2 UDB 9.5. A proč tolik povyku. Kromě mnoha &lt;a href="https://publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/com.ibm.db2.luw.wn.doc/doc/r0051514.html"&gt;další vylepšení&lt;/a&gt;, je konečně implementován i &lt;a href="http://www.w3.org/TR/xqupdate/"&gt;draft XQuery Update Facility&lt;/a&gt;. Asi nebudu sám, kdo cítil velký nedostatek v nemožnosti updatovat část XML dokumentu uloženého pomocí &lt;a href="http://www-306.ibm.com/software/data/db2/9/editions_features_purexml.html"&gt;pureXML&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Nebudu dlouho běhat okolo horké kaše a ukážeme si pár příkladů.&lt;br /&gt;&lt;br /&gt;Máme tabulku &lt;code&gt;friend&lt;/code&gt;, která má sloupec &lt;code&gt;info&lt;/code&gt;. V této tabulce máme jeden záznam:&lt;pre&gt;&lt;code&gt;&amp;lt;friend&amp;gt;&lt;br /&gt;  &amp;lt;name&gt;Jiri Mares&amp;lt;/name&amp;gt;&lt;br /&gt;  &amp;lt;phone type="work"&amp;gt;222 222 222&amp;lt;/phone&amp;gt;&lt;br /&gt;  &amp;lt;phone type="home"&amp;gt;333 333 333&amp;lt;/phone&amp;gt;&lt;br /&gt;&amp;lt;/friend&amp;gt;&lt;/code&gt;&lt;/pre&gt;A nyní si ukážeme prostou změnu mého čísla do práce (využiji skutečnosti, že mám v tabulce jeden řádek a vypustím klauzili &lt;code&gt;where&lt;/code&gt; z SQL update příkazu):&lt;pre&gt;&lt;code&gt;update friend&lt;br /&gt;set info = xmlquery( 'copy $new := $INFO&lt;br /&gt;  modify do replace value of $new/friend/phone[@type="work"] with "111 111 111"&lt;br /&gt;  return  $new');&lt;/code&gt;&lt;/pre&gt;Což přidat telefon na mobil:&lt;pre&gt;&lt;code&gt;update friend&lt;br /&gt;set info = xmlquery('copy $new := $INFO&lt;br /&gt;  modify do insert &amp;lt;phone type="cell"&amp;gt;444 444 444&amp;lt;/phone&amp;gt;&lt;br /&gt;     as last into $new/friend&lt;br /&gt;  return  $new' );&lt;/code&gt;&lt;/pre&gt;Nebo můžeme přejmenovat tag &lt;code&gt;name&lt;/code&gt; na &lt;code&gt;full-name&lt;/code&gt;:&lt;pre&gt;&lt;code&gt;update friend&lt;br /&gt;set info = xmlquery('copy $new := $INFO&lt;br /&gt;  modify do rename $new/friend/name as "full-name"&lt;br /&gt;  return  $new' );&lt;/code&gt;&lt;/pre&gt;Dále jsem neukázal mazání nodu:&lt;pre&gt;&lt;code&gt;update friend&lt;br /&gt;set info = xmlquery('copy $new := $INFO&lt;br /&gt;  modify do delete $new/friend/phone[@type="cell"]&lt;br /&gt;  return  $new');&lt;/code&gt;&lt;/pre&gt;Můžeme nahradit více tagů najednou:&lt;pre&gt;&lt;code&gt;update friend&lt;br /&gt;set info = xmlquery(' copy $new := $INFO&lt;br /&gt;  modify (&lt;br /&gt;     do replace value of $new/friend/phone[@type="home"] with "999 999 999",&lt;br /&gt;     do replace value of $new/friend/phone[@type="work"]/@type with "cell")&lt;br /&gt;  return  $new' );&lt;/code&gt;&lt;/pre&gt;Začíná se mi XQuery líbit čím dál tím víc, je jednoduché, čitelné, skoro bych řekl sexy :-).&lt;br /&gt;&lt;br /&gt;Na závěr nutno říci, že XQuery Update nemusíte používat jenom při SQL updatu, ale i v selectu. Takže pokud nechcete vracet uživateli hodnotu telef. čísel na mobil, pak stačí udělat dotaz:&lt;pre&gt;&lt;code&gt;xquery copy $new := db2-fn:sqlquery("select info from friend")&lt;br /&gt;modify  for $j in $new/friend/phone[@type="cell"] return&lt;br /&gt;  do replace value of $j with "XXX XXX XXX"&lt;br /&gt;return $new;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;A co mě ještě v pureXML zaujalo&lt;/h4&gt;Je toho hodně nového, ale ... zajímavá je rychlost, takže je fajn, když se XML dokument může uložit ve stejné stránce jako ostatní sloupce řádku tabulky, protože celý řádek je k dispozici pomocí jediné I/O operace (i když platí omezení na velikost XML dokumentu max. 32k - nebojte, je-li dokument větší, neznamená to chybu, ale pouze se standardně uloží do XDA).&lt;br /&gt;&lt;br /&gt;Zajímavá je intergrace XSLT enginu přímo do DB2 (když už je XML uloženo v podobě stromu, přímo si to o tuto integraci říká). Díky nové funkci &lt;code&gt;parameter&lt;/code&gt; padá nemožnost předávat parametry do &lt;code&gt;sqlquery&lt;/code&gt; funkce. &lt;a href="http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0711sardana/?S_TACT=105AGX11&amp;amp;S_CMP=FP"&gt;A další ...&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5927838368041683720?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5927838368041683720/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5927838368041683720' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5927838368041683720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5927838368041683720'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/11/je-to-tady-xquery-update-v-purexml.html' title='A je to tady - XQuery Update v pureXML'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-770497622092484771</id><published>2007-10-26T22:02:00.000+02:00</published><updated>2007-10-26T22:58:26.932+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Programujeme nebo lepíme</title><content type='html'>Přiložím si také trochu do mlýna k diskusi, zda jsou vizuální nástroje dobré nebo špatné. Diskuse se nejprve rozvinula v konferenci konference@java.cz, na to se GUI nástrojů zastal Dagi v příspěvku &lt;a href="http://www.sweb.cz/pichlik/archive/2007_10_21_archive.html#4106786679625201208"&gt;Potřebujeme silné nástroje&lt;/a&gt; a následně Pavel Kolesnikov přidal &lt;a href="http://www.jablok.cz/java/20071022-archiv.html#1193392523"&gt;Potřebujeme domyšlené nástroje&lt;/a&gt;. Já se chci trochu vrátit k jádru pudla, zda GUI nástroje ano nebo ne.&lt;br /&gt;&lt;br /&gt;Na úvod se přiznám, že nejsem velký přívrženec GUI klikátek, asi už jsem &lt;span style="font-style: italic;"&gt;z moc starý školy a jsem moc zakořeněnej v unix shellu&lt;/span&gt;. Ale napadlo mě, že dneska už vlastně tolik neprogramujem, spíš skládáme (lepíme) dohromady existující kousky. Však se potichu šušká, že vše už bylo alespoň jednou napsáno.&lt;br /&gt;&lt;br /&gt;Ale jaký je rozdíl v použití haldy frameworků, které vše řeší za mě, či GUI klikátka, které ten kód vygeneruje? Ja si myslím, že v podstatě rozdíl není. Cíl je stejný, ale cesta je různá. Mám aplikaci a nemusím moc programovat.&lt;br /&gt;&lt;br /&gt;Takže proč vzbuzují GUI klikátka negativnější pocity (alepoň v některých lidech, např. jako já) než frameworky. Za sebe mohu říci že, když jsem je používal já, tak mi hezky zpívaly když mě lapaly. A když jsem je začal používat a následně jsem je potřeboval, pak mě hodily přes palubu, protože složitější věci nešlo realizovat, jak jsem chtěl. A já nerad ustupuju.&lt;br /&gt;&lt;br /&gt;A jaký je tedy závěr? I nadále programujeme, ale stále více se uchylujeme k lepení. A zda lepíme pomocí GUI klikátek nebo ne, to si musí každý rozhodnout sám, ale já jsem se rozhodl: "Raději ne, děkuji".&lt;br /&gt;&lt;br /&gt;PS: Nejlepším lepidlem posledních let jsou anotace. Abychom se do toho lepidla, ale nezalepili sami.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-770497622092484771?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/770497622092484771/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=770497622092484771' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/770497622092484771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/770497622092484771'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/programujeme-nabo-lepime.html' title='Programujeme nebo lepíme'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5115634659272803899</id><published>2007-10-25T08:18:00.000+02:00</published><updated>2007-10-25T08:32:58.516+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Architektura naruby</title><content type='html'>Právě jsem si přečetl Dagiho příspěvek &lt;a href="http://www.sweb.cz/pichlik/archive/2007_10_21_archive.html#2953300892787564807"&gt;Do pranice: Spring Web Flow a nebo JBoss Seam&lt;/a&gt; a nemohl jsem se nepřidat se stížností na dnešní frameworky. Už toho mám dost, jak se neustále pod rouškou jednoduššího vývoje a já nevím čeho všeho porušují základní pravidla vrstvení aplikace: nižší vrstva nemá vědět, ža nad ní je nějaká vrstva vyšší a využívat pouze služeb svých a nebo služeb vrstev pod ní.&lt;br /&gt;&lt;a href="http://www.jboss.com/products/seam"&gt;&lt;br /&gt;JBoss Seam&lt;/a&gt; je úplně klasickým příkladem této šílenosti, protože vrstvy nižší (v tomto případě např. session beany) jsou oanotovány vším možným co se týká jejich komunikace s JSF (přes Seam) jako vrstvou vyšší. Cestou ven je samozřejmě použití XML konfigurace, ale ta se v souvislosti se Seamem skoro neprezentuje.&lt;br /&gt;&lt;br /&gt;Z podobného důvodu používám s &lt;a href="http://hibernate.org/"&gt;Hibernate&lt;/a&gt; vždy XML konfiguraci. Prostě nechci aby můj model byl zaneřáděn anotacemi, které ke své funkci vůbec nepotřebuje. Mapování uložení do DB je přeci věc &lt;a href="http://en.wikipedia.org/wiki/Data_Access_Object"&gt;DAO vrstvy&lt;/a&gt; a model se o něj rozhodně nemá starat.&lt;br /&gt;&lt;br /&gt;Ano, je to složitější, pracnější, ale rozhodně je to flexibilnější. Řada čtenářů my možná namítne, že na to není čas, že je jim tato flexibilita na nic atd. Je to každého věc, ale já mám flexibilitu rád a nevzdám se jí. Navíc mám rád pokud je kód přehledný, hezky strukturovaný a provázaný jenom jedním směrem, shora dolů a ne i naopak.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5115634659272803899?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5115634659272803899/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5115634659272803899' title='Počet komentářů: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5115634659272803899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5115634659272803899'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/architektura-naruby.html' title='Architektura naruby'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-5337725025863464297</id><published>2007-10-22T11:11:00.000+02:00</published><updated>2007-10-22T11:13:29.088+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Jednoduše na CSS Sprite</title><content type='html'>O CSS Sprite už jsem psal v příspěvku &lt;a href="http://jirablog.blogspot.com/2007/09/zamerte-se-na-frontend.html"&gt;Zaměřte se na fronted&lt;/a&gt;, takže jenom z rychlíku. Jedná se o více obrázků rozložených v jednom velkém, které jsou následně pomocí &lt;a href="http://cs.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;CSS&lt;/a&gt; backgroup zobrazovány. Získává se tím větší výkon stránky, protože pro její zobrazení není nutné natahovat 30 malých obrázků (=30 requestů), ale pouze jeden větší.&lt;br /&gt;&lt;br /&gt;A já vám nyní předkládám odkaz na &lt;a href="http://spritegen.website-performance.org/"&gt;stránku&lt;/a&gt;, kde si takový CSS Sprite můžete vytvořit. Zazipujte své malé obrázky, uploadněte je a získáte zpět jeden velký. Proč se s tím pachtit v &lt;a href="http://www.gimp.cz/"&gt;GIMPu&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-5337725025863464297?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/5337725025863464297/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=5337725025863464297' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5337725025863464297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/5337725025863464297'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/jednodue-na-css-sprite.html' title='Jednoduše na CSS Sprite'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-8007606580974161837</id><published>2007-10-19T08:13:00.000+02:00</published><updated>2007-10-19T08:13:53.962+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Jak na vlastní design File Input položek formulářů</title><content type='html'>Každý již jistě někdy psal stránku, která umžňovala upload nějakého souboru. To je problém celkem jednoduše řešitelný, ovšem problém nastává, pokud máte nějaký design tlačítek na stránce a chcete, aby i tlačítko pro výběr souboru mělo jednotný design. A zde se už naráží.&lt;br /&gt;&lt;br /&gt;Ovšem i toto je věc řešitelná (ve světě počítačů snad neexistují neřešitelné problémy). Celý postup názorně popisuje &lt;a href="http://www.shauninman.com/archive/2007/09/10/styling_file_inputs_with_css_and_the_dom"&gt;Shaun Inman ve svém blogu&lt;/a&gt;. V principu jde o kombinaci &lt;a href="http://cs.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;CSS&lt;/a&gt;, &lt;a href="http://cs.wikipedia.org/wiki/Document_Object_Model"&gt;DOM&lt;/a&gt; a JavaScriptu.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_w-Wca0Ms2Yc/RxeyRJTL7RI/AAAAAAAAACQ/YGZCQFIjng8/s1600-h/custom-file-input.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_w-Wca0Ms2Yc/RxeyRJTL7RI/AAAAAAAAACQ/YGZCQFIjng8/s400/custom-file-input.gif" alt="" id="BLOGGER_PHOTO_ID_5122759108781141266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Funguje to tak, že se &lt;code&gt;input&lt;/code&gt; obalí wrapper-tagem (např. &lt;code&gt;label&lt;/code&gt;), jemuž se nastaví pozadí na námi požadovaný vzhled. Následně se nastaví neprůhlednost (opacity) tagu &lt;code&gt;input&lt;/code&gt; na &lt;code&gt;0&lt;/code&gt;, čímž se zneviditelní, ovšem stále je klikatelný. No a zavěrečný krůček nám pomůže udělat JavaScript, kterým zařídíme, že tlačítko pro výběr souboru bude vždy umístěno pod ukazatelem myši, pokud je uvnitř našeho wrapper-tagu.&lt;br /&gt;&lt;br /&gt;A teď v jakých prohlížečích to funguje? Překvapivě IE 5.5+, Firefox 1.5+, Safari 2+. Uspokojivě je použitelné v IE 5.01 a Opeře.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-8007606580974161837?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/8007606580974161837/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=8007606580974161837' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8007606580974161837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/8007606580974161837'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/jak-na-vlastni-design-file-input.html' title='Jak na vlastní design File Input položek formulářů'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_w-Wca0Ms2Yc/RxeyRJTL7RI/AAAAAAAAACQ/YGZCQFIjng8/s72-c/custom-file-input.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4363440735162117266</id><published>2007-10-18T20:02:00.000+02:00</published><updated>2007-10-18T20:50:33.581+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><title type='text'>Jak ovládat Eclipse pomocí prohlížeče</title><content type='html'>O &lt;a href="http://www.eclipse.org/rap/"&gt;Eclipse RAP&lt;/a&gt; se už blogovalo (např. &lt;a href="http://www.sweb.cz/pichlik/archive/2007_10_14_archive.html#2503121162218994"&gt;dagi&lt;/a&gt;), ale o integraci Eclipse s prohlížečem zatím ne. Celé se to jmenoje &lt;a href="http://www.alphaworks.ibm.com/tech/eclifox?open&amp;amp;S_TACT=106AH21W&amp;amp;S_CMP=AWRSSECL"&gt;Web Broser-Based Integration with Eclipse IDE&lt;/a&gt;,  a jde o skutečné ovládání Eclipse pomocí prohlíče. Nainstalujete &lt;a href="https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?source=AW-0RE&amp;amp;S_TACT=106AH21W&amp;amp;S_CMP=AWRSSECL"&gt;speciální plugin&lt;/a&gt; včetně &lt;a href="http://jetty.mortbay.org/"&gt;Jetty&lt;/a&gt; serveru a to je celé. V nastavení eclipse spustíte server, do prohlížeče (pozor celé to funguje pouze ve &lt;a href="http://firefox.czilla.cz/"&gt;Firefoxu&lt;/a&gt;) zadáte adresu http://localhost:9008/ a zobrazí se vám váš Eclipse.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_w-Wca0Ms2Yc/RxeoCpTL7OI/AAAAAAAAAB4/fTx2oYmqlC4/s1600-h/Eclipse-firefox.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_w-Wca0Ms2Yc/RxeoCpTL7OI/AAAAAAAAAB4/fTx2oYmqlC4/s400/Eclipse-firefox.gif" alt="" id="BLOGGER_PHOTO_ID_5122747864556760290" border="0" /&gt;&lt;/a&gt;A takhle vypadá originál:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_w-Wca0Ms2Yc/RxeofJTL7PI/AAAAAAAAACA/IRD2HWcklJc/s1600-h/Eclipse.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_w-Wca0Ms2Yc/RxeofJTL7PI/AAAAAAAAACA/IRD2HWcklJc/s400/Eclipse.gif" alt="" id="BLOGGER_PHOTO_ID_5122748354183032050" border="0" /&gt;&lt;/a&gt;Celé to funguje velmi jednoduše, skoro se mi chce napsat trapně jednoduše, UI Eclipsu se překládá do &lt;a href="http://www.mozilla.org/projects/xul/"&gt;XUL &lt;/a&gt;Firefoxu, který jej pak zobrazuje.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_w-Wca0Ms2Yc/Rxeo7pTL7QI/AAAAAAAAACI/Or62RP0K92M/s1600-h/eclifox01overview.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_w-Wca0Ms2Yc/Rxeo7pTL7QI/AAAAAAAAACI/Or62RP0K92M/s400/eclifox01overview.jpg" alt="" id="BLOGGER_PHOTO_ID_5122748843809303810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Zatím je to jenom preview, ale možnosti jsou opravdu velmi široké, od přístupu ke své Eclipse instalci pomocí prohížeče (či k centrální instalaci s definovanými pluginy a projekty), při podpoře více uživatelů (zatím chybí) dokonce může více uživatelů sdílet jednu instalaci Eclipse až po vývoj webových aplikací pomocí Eclipse RCP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4363440735162117266?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4363440735162117266/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4363440735162117266' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4363440735162117266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4363440735162117266'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/jak-ovladat-eclipse-pomoci-prohlizece.html' title='Jak ovládat Eclipse pomocí prohlížeče'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_w-Wca0Ms2Yc/RxeoCpTL7OI/AAAAAAAAAB4/fTx2oYmqlC4/s72-c/Eclipse-firefox.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-1968135998768838361</id><published>2007-10-12T20:30:00.000+02:00</published><updated>2007-10-13T22:08:50.892+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Vývoj aplikace za běhu</title><content type='html'>Dostala se mi pod nos opravdu zajímavá věcička, která si říká &lt;a href="http://www.zeroturnaround.com/javarebel/"&gt;JavaRebel&lt;/a&gt;. O co se jedná? Jedná se o udělátko, které za běhu aplikace dokáže reloadovat třídy. A pozor, nepoužívá k tomu class loader (tak problém řeší &lt;a href="http://howardlewisship.com/"&gt;Howard Lewis Ship&lt;/a&gt; pro &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry 5&lt;/a&gt;) ani hot swap (jenž je v javě od verze 1.4).&lt;br /&gt;&lt;br /&gt;Ale jak to tedy dělají? Jak sami říkají, pomocí změny bytecodu a trochu kouzel. Každopádně JavaRebel podporuje všechny změny tříd až na změnu v dědičnosti (tj. &lt;code&gt;extends&lt;/code&gt; a &lt;code&gt;implements&lt;/code&gt;). Dá se použít jak při vývoji webových tak klientských aplikací.&lt;br /&gt;&lt;br /&gt;Po &lt;a href="http://www.terracotta.org/"&gt;Terracotte&lt;/a&gt; je to další technologie, která používá manipulace s bytecodem k docílení až zázračných věcí.&lt;br /&gt;&lt;br /&gt;Jediné mínus je, že se jedná o komerční produkt, a stojí 100$ na vývojáře. Ovšem to je investice, která se vrátí snad už za týden.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Odkazy&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.zeroturnaround.com/docs/javarebel-jpetstore-screencast"&gt;JavaRebel Screencast&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-1968135998768838361?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/1968135998768838361/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=1968135998768838361' title='Počet komentářů: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1968135998768838361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/1968135998768838361'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/vyvoj-aplikace-za-behu.html' title='Vývoj aplikace za běhu'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4073736867297998421</id><published>2007-10-08T21:59:00.000+02:00</published><updated>2007-10-08T22:33:17.734+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Kam se ztrácí zkušení programátoři</title><content type='html'>Přečetl jsem si velmi zajímavý článek &lt;a href="http://acmqueue.com/modules.php?name=Content&amp;pa=showpage&amp;pid=488"&gt;API: Design Matters&lt;/a&gt; od Michi Henninga. Je velmi poučný a vhodně doplňuje prezentaci Jaroslava Tulacha Jak psát API, které přežije nástrahy času (&lt;a href="http://java.cz/dwn/1003/5802_apidesign-jug-praha-2007.pdf"&gt;slidy&lt;/a&gt;, &lt;a href="http://www.avc-cvut.cz/avc.php?id=4671"&gt;video&lt;/a&gt;). Takže rozhodně si ho přečtěte, protože API navrhuje každý z nás.&lt;br /&gt;&lt;br /&gt;Ovšem co mě skutečně praštilo do očí je jedna z posledních kapitol, která se designem API zaobírá spíše okrajově. Hovoří o tom, že zkušení programátoři (a v podstatě i designéři či architekti) přestávají existovat. Jak je to možné?&lt;br /&gt;&lt;br /&gt;Upřímně kolik znáte programátorů, kterým je přes 40? Já jsem zatím poznal tři (a zkušenost je jednoznačně pozitivní), takže mladší jednoznačně převládají. Proč? Protože je sociální tlak, aby programátor skončil s programováním včas a přeorientoval se na designéra nebo architekta, v nejhorším případě na project managera, protože přeci nemůže na ty mladé kluky, co se nové technologie učí na škole, stačit.&lt;br /&gt;&lt;br /&gt;Ovšem co umí mladý kluk, když opouští univerzitu. Umí minimálně 5 programovacích jazyků (což by jistě s knihou a chvilkou času zvládl i bez učitele), umí řadu děsně zajímavých algoritmů, které většinou nikdy nepoužije a když tak velmi vyjímečně. Ale to co by měl používat denně: objektový design, psaní přehledného kódu, test driven development, code coverage, continuous integration, nedej bože jiné metodiky vývoje než vodopád (nejlépe scrum). To nezná.&lt;br /&gt;&lt;br /&gt;A kde je problém designérů a architektů? Jsou drazí a je jich málo. Proto nemohou na projektu zůstávat po celý jeho životní cyklus a tím se odtrhávájí od reality, protože netuší jaké dopady mají jejich rozhodnutí. Chybí jim zpětná vazba.&lt;br /&gt;&lt;br /&gt;Takže kdeže jsou ti zkušení? Neexistují ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4073736867297998421?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4073736867297998421/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4073736867297998421' title='Počet komentářů: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4073736867297998421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4073736867297998421'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/kam-se-ztraci-zkuseni-programatori.html' title='Kam se ztrácí zkušení programátoři'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-6317841679931505093</id><published>2007-10-04T23:09:00.000+02:00</published><updated>2007-10-13T22:45:38.201+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Velmi jednoduchá validace HTML formulářů JavaScriptem</title><content type='html'>Dneska mi padla do oka velmi jednoduchá knihovnička na validování HTMl formulářů pomocí JavaScriptu - &lt;a href="http://www.jsvalidate.com/"&gt;JSValidate&lt;/a&gt;. V podstatě bych řekl, že se mi víc líbí nápad, jak jsou položky formuláře označovány na co mají být validovány, než samotná knihovna, protože obsahuje validaci pouze JavaScriptem, tj. na klientu, a to je pro mě málo.&lt;br /&gt;A co je to tedy za nápad? Prostě a jednoduše položky formuláře, tj. &lt;code&gt;input&lt;/code&gt; tagy označíte CSS třídou podle toho, jak jej chcete validovat a přidáte následující 3 řádky na začátek stránky:&lt;pre&gt;&lt;code&gt;&amp;lt;script type="text/javascript" language="javascript" src="scriptaculous/lib/prototype.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" language="javascript" src="scriptaculous/src/scriptaculous.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" language="javascript" src="jsvalidate.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;A jste hotovy.&lt;h4&gt;Příklady&lt;/h4&gt;Jednoduchá položka, jejíž hodnota je povinná:&lt;pre&gt;&lt;code&gt;&amp;lt;input type="text" name="name" class="jsrequired" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Nebo položka pro číslo:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;input type="text" name="number" class="jsvalidate_number" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;A nebo položka na email, který je nutné zadat:&lt;pre&gt;&lt;code&gt;&amp;lt;input type="text" name="email" class="jsrequired jsvalidate_email" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Jaké jsou dostupné třídy&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsrequired&lt;/span&gt; - musí být vyplněna&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_number&lt;/span&gt; - číslo&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_digits&lt;/span&gt; - pouze číslice&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_alpha&lt;/span&gt; - pouze písmena&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_alphanum&lt;/span&gt; - písmena, číslice a podtržítko&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_email&lt;/span&gt; - email&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_uscanzip&lt;/span&gt; - ZIP code USA nebo Kanady&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_usstate&lt;/span&gt; - 2 znakový kód státu v USA&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_usphone&lt;/span&gt; - telefonní číslo v USA&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_creditcard&lt;/span&gt; - číslo kreditní karty&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jsvalidate_ssn&lt;/span&gt; - Social Security Number - číslo sociálního pojištění (USA)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;select-notfirst&lt;/span&gt; - používá se u selectů, kde zajistí, že první položka ze seznamu nemůže být vybrána&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Závěr&lt;/h4&gt;Myslím, že existuje problém, kde se tato knihovná dá nasadit. Asi to nebude do žádné větší aplikace, kde bude na validační framework kladen podstatně větší nárok, především mám na mysli prováznost s validací na serveru.&lt;br /&gt;Co se mi jeví jako hodně zajímavé je využití CSS tříd pro identifikaci, to je velmi jednoduché a elegantní.&lt;h4&gt;Odkazy&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.jsvalidate.com/demo/"&gt;Příklady&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-6317841679931505093?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/6317841679931505093/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=6317841679931505093' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6317841679931505093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6317841679931505093'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/10/velmi-jednoducha-validace-html.html' title='Velmi jednoduchá validace HTML formulářů JavaScriptem'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-3523888391983982216</id><published>2007-09-17T21:57:00.000+02:00</published><updated>2007-09-18T11:43:30.797+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='výkon'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Zaměřte se na frontend</title><content type='html'>Potřebujete zvýšit výkon vašich stránek z pohledu koncového uživatele? Zaměřte se na frontend,  ne na backend. To je obsah &lt;a href="http://ajaxian.com/archives/video-steve-souders-chief-performance-yahoo-for-yahoo-discusses-site-performance"&gt;prezentace&lt;/a&gt; Steva Sounderse z Yahoo. A proč? Při analýze výkonu Yahoo stránek se ukázalo, že pouze 12% z doby potřebné pro zobrazení stránek je čas strávený generováním obsahu na serveru. Zbytek je přenos dat a práce klienta. Tento průzkum byl potvrzen na výkonu 9 z 10 TOP10 amerických webů, kdy více jak 20% zlepšení v rychlosti zobrazení stránek po natažení všeho cachevatelného do cache zaznamenal pouze Google.&lt;br /&gt;&lt;br /&gt;A jaké jsou tedy rady:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;čím méně HTTP requestů, tím lépe&lt;/span&gt; - spojujte jvascriptové a CSS soubory, používejte &lt;a href="http://www.dmxzone.com/Downloads/Tutorial_2AprShea.zip/2apr%20SHEA%20Sprites.pdf"&gt;CSS Sprites&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;používejte CDN (&lt;/span&gt;&lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/Content_Delivery_Network"&gt;Content Delivery Network&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;)&lt;/span&gt; - distribuujte nejprve statický a pak dynamický obsah&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;používejte &lt;code&gt;Expires&lt;/code&gt; hlavičky&lt;/span&gt; - umožní cachování obsahu&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;gzipujte posílaný obsah&lt;/span&gt; - 90% klientů podporuje kompresi obsahu pomocí gzipu, využijte jej&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CSS stylesheety dejte na začátek stránky&lt;/span&gt; - IE zobrazí stránku, až když má nateženy všechny stylesheety, proto je nutné je začít stahovat co nejdřív&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;javascript naopak dejte na konec&lt;/span&gt; - máte-li javascript inline v dokumentu, pak blokuje renderování něčeho viditelného, je-li jako externí soubor, pak blokuje (&lt;a href="http://blogs.msdn.com/ie/archive/2005/04/11/407189.aspx"&gt;především v IE&lt;/a&gt;) stahování něčeho vizuálního&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;nepoužívejte CSS výrazy&lt;/span&gt; - něco jako &lt;code&gt;width: expression (document.body.clientWidth &amp;lt; 600 ? "600px" : "auto");&lt;/code&gt; příšerně zpomaluje stránku, protože takový výraz se vyhodnocuje pořád (při pohybu myši, při stisku klávesy, ...)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CSS a javascript mají být v externích souborech&lt;/span&gt; - sice přidávají HTTP request, ale mohou být cachovány&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;minimalizovat počet DNS lookupů&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://code.google.com/p/minify/wiki/UserGuide"&gt;Minify&lt;/a&gt; Javascript (případně obfuscate)&lt;/span&gt; - zmenší objem javascriptu, ale nemění funkci&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;vyvarujte se redirectů&lt;/span&gt; - zablokují renderování stránky a oddalují jej&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;odstraňte duplicity&lt;/span&gt; - ve scriptech, stylesheetech, ...&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;snažte se používat &lt;a href="http://en.wikipedia.org/wiki/HTTP_ETag"&gt;ETags&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;udělejte AJAX cachovatelný&lt;/span&gt; - i requesty prováděné pomocí AJAX by měly být cachovány&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Musím říci, že tato prezentace byla pro mě překvapující, protože bych čekal, že za zvýšením výkonu stránek bude nějaká magická serverová technologie nebo vychytávka. A ejhle ono ne. Je pravda, že na přizpůsobení stránek rychlejšímu zpracování na klientu se moc velká pozornost nevěnuje, zde je taková malá kapesní kuchařka.&lt;br /&gt;&lt;br /&gt;Tento příspěvek je spíše lákáním na shlédnutí ani ne 40 min prezentace, jistě je to zajímavé poslouchání.&lt;br /&gt;&lt;br /&gt;PS: v prezentaci se hovoří o plugin do Firefoxu &lt;a href="http://developer.yahoo.com/yslow"&gt;YSLOW&lt;/a&gt;, který analyzuje stránky a říka proč jsou pomalé, rozhodně stojí za vyzkoušení, jistě se dozvíte zajímavé věci.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-3523888391983982216?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/3523888391983982216/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=3523888391983982216' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3523888391983982216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/3523888391983982216'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/09/zamerte-se-na-frontend.html' title='Zaměřte se na frontend'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-6090521012838320794</id><published>2007-09-17T20:23:00.000+02:00</published><updated>2007-09-17T20:44:09.968+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vývoj'/><title type='text'>Code review je jistě užitečná věc</title><content type='html'>Když jsem si přečetl &lt;a href="http://www.sweb.cz/pichlik/archive/2007_09_16_archive.html#1752105705132510935"&gt;dagiho příspěvek o code review&lt;/a&gt; vyskočil jsem jak čertík z krabičky. Než jsem došel domu, málem jsem na své rozhodnotí reagovat zapomněl, ale už jsem si zase vzpomněl.&lt;br /&gt;&lt;br /&gt;Jsem zvyklý code review používat a považuji jej za skvělou věc. Ovšem nejprve co to je code review? Jak jej vnímám já, není to kontrola, že kód splňuje nějaký coding standard, není to náhrada testů, tj. kontrola správnosti (ve smyslu fungování) a ani to není kontrola na neexistenci známých chybových paternů. Jsem tedy plně v souladu s dagim, že code review nemá plnit úkoly, které může plnit automat (počítač) pomocí &lt;a href="http://pmd.sourceforge.net/"&gt;PMD&lt;/a&gt;, &lt;a href="http://checkstyle.sourceforge.net/"&gt;Checkstyle&lt;/a&gt;, &lt;a href="http://findbugs.sourceforge.net/"&gt;FindBugs &lt;/a&gt;apod.&lt;br /&gt;&lt;br /&gt;Co tedy má plnit code review? Řekl bych, s trochou nadsázky, že má plnit to co pair-programming, akorát, že prográmátoři se baví už nad hotovým kódem. Tj. ten co dělá code review, sleduje kód, jak je napsán, zda mu rozumí (podstatná věc, protože pak je pravděpodobé, že to pochopí i někdo další), zda je kód rozumně strukturován a pod. Samozřejmě se jeden učí od druhého, protože buď se koukám na kód, který mě něčím inspiruje a nebo se mi v něm něco nelíbí, požaduju změnu a inspiruji autora.&lt;br /&gt;&lt;br /&gt;U nás v týmu provádíme code review po jednotlivých požadavcích, které programátoři plní. Každý požadavek má přidělen implementátora a reviewera. Teprve pokud je review hotové, všechny připomínky vyřešeny, pak se požadavek zavírá jako hotový.&lt;br /&gt;&lt;br /&gt;Tento postup se nám v praxi ověřil, jako kontrolní mechanismus, jako princip vzdělávání, jako postup pro zlepšování kvality kódu. Takže závěr, code review ano, ale ne na automatizovatelné úkony.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-6090521012838320794?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/6090521012838320794/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=6090521012838320794' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6090521012838320794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/6090521012838320794'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/09/code-review-je-jiste-uzitecna-vec.html' title='Code review je jistě užitečná věc'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4774203648092109518</id><published>2007-09-15T21:36:00.000+02:00</published><updated>2007-09-17T22:26:38.484+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>OpenAjax Hub = javascriptový messaging v 5kB</title><content type='html'>Dneska si ještě více rozšíříme znalosti na poli AJAX technologií. Z blízka se podíváme na  &lt;a href="http://www.openajax.org/OpenAjax%20Hub.html"&gt;OpenAjax Hub&lt;/a&gt; z pod pokličky &lt;a href="http://www.openajax.org/"&gt;OpenAjax Alliance&lt;/a&gt;. V podstatě jde o messaging pro JavaScript napsaný v JavaScriptě, nebo o jednoduchý, ale mocný, publish/subscribe hub.&lt;br /&gt;&lt;br /&gt;Pokud děláte AJAX aplikace, které jsou složené z komponent, jenž si mezi sebou posílají události, pak čtěte dále. Pokud použijeme &lt;a href="http://en.wikipedia.org/wiki/Comet_%28programming%29"&gt;comet&lt;/a&gt;, pak komponentou může být i server (jak na to je popsáno v &lt;a href="http://jirablog.blogspot.com/2007/09/dwr-jetty-vkon-ajax-naruby.html"&gt;DWR a Jetty = výkoný AJAX naruby&lt;/a&gt;). Obzvláště výhodné je použití OpenAjax Hubu v případech, kdy jedna komponenta generuje události, které přijímá více komponent. Navíc hub sebou nese nezávislost jednotlivých komponent, tj. komponenty komunikují pouze s hubem a ne mezi sebou, tj. čím více komponent, tím větší zjednodušení.&lt;br /&gt;&lt;br /&gt;My jsme měli např. problém v naší aplikaci, která sleduje pohyb autobusů (autobus se ohlašuje pomocí &lt;a href="http://en.wikipedia.org/wiki/General_Packet_Radio_Service"&gt;GPRS&lt;/a&gt; a posílá svou polohu získanou z &lt;a href="http://en.wikipedia.org/wiki/Global_Positioning_System"&gt;GPS&lt;/a&gt;). Chtěli jsme polohu zobrazit nejenom v mapě, ale také pomocí tabulky, která by zobrazovala další informace (např. zda jede na čas, jak je daleko na své trase).&lt;br /&gt;&lt;h4&gt;Jak Hub použít&lt;/h4&gt;&lt;br /&gt;Pokud se proklikáte na &lt;a href="http://openajaxallianc.sourceforge.net/"&gt;sourceforge stránky projektu&lt;/a&gt; a stáhnete si OpenAjax Hub možná budete překvapeni, protože soubor OpenAjax.js, který obsahuje implementaci Hubu má plných 5744 B. Ano není to překlep, méně než 6 kB.&lt;br /&gt;&lt;br /&gt;Nejprve začnu serverovou částí, kde použijeme Reverse AJAX. Oproti &lt;a href="http://jirablog.blogspot.com/2007/09/dwr-jetty-vkon-ajax-naruby.html"&gt;příspěvku s chatem&lt;/a&gt;, kde jsme volali funkci &lt;code&gt;newMsg(msg)&lt;/code&gt; budeme volat funkci &lt;code&gt;OpenAjax.hub.publish("bus.location", busLocation)&lt;/code&gt; (použijeme k tomu objekt &lt;code&gt;ScriptBuffer&lt;/code&gt; jako minule). Jako první parametr do funkce &lt;code&gt;publish&lt;/code&gt; předáme jméno události a druhým parametrem je samotná událost (využijeme DWR, které převede java objekt do javasriptového).&lt;br /&gt;&lt;br /&gt;Na klientu musíme zapnout reverse Ajax v DWR. Dále se zaregistrujeme k odběru událostí, což provedeme kódem:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var subscription = OpenAjax.hub.subscribe("bus.location", showBusLocationInMap);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Prvním parametrem je jméno události. Pokud se chceme přihlásit k odběru všech událostí týkajících se autobusů, pak použijeme wildcard a zapíšeme jméno události &lt;code&gt;bus.*&lt;/code&gt;. To znamená i &lt;code&gt;bus.state&lt;/code&gt; nebo &lt;code&gt;bus.message&lt;/code&gt;. Pokud se chceme přihlásit i k odběru &lt;code&gt;bus.data.check&lt;/code&gt; pak použijeme &lt;code&gt;bus.**&lt;/code&gt;.&lt;br /&gt;Druhým parametrem je callbak funkce, kterou si popíšeme dále. Dalšími parametry, které v příkladu nevyužíváme jsou:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;scope&lt;/code&gt; - objekt, který bude &lt;code&gt;this&lt;/code&gt; při volání callbacku (je-li &lt;code&gt;null&lt;/code&gt;, pak je použit objekt &lt;code&gt;window&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;&lt;code&gt;subscriberData&lt;/code&gt; - objekt, který je předán callback funkci jako parametr&lt;/li&gt;&lt;li&gt;&lt;code&gt;filter&lt;/code&gt; - funkce, která vrací &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; v případě, že akceptujeme/odmítáme předanou událost&lt;/li&gt;&lt;/ul&gt;Návratovou hodnotou funkce &lt;code&gt;subscribe&lt;/code&gt; je objekt, který se použije jako parametr při volání &lt;code&gt;unsubscribe&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Callback bude mít následující podobu:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function showBusLocationInMap(name, event, subscriberData) {&lt;br /&gt;  //změň polohu autobusu na mapě - data jsou v objektu event&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Nemůžu se stále ubránit dojmu, že je to geniální. Skvělý nápad, skvělá implementace, velmi jednoduché použití.&lt;br /&gt;&lt;h4&gt;Závěr&lt;/h4&gt;&lt;br /&gt;Dneska jsem vám ukázal co to je OpenAjax Hub. Jak jej použít pro distribuci událostí na principu publish / subscribe. Ve spolupráci s DWR a jeho reverse AJAX implementací jsme navíc velmi jednoduše vytvářeli události na serveru.&lt;br /&gt;&lt;br /&gt;To co je &lt;a href="http://en.wikipedia.org/wiki/Enterprise_service_bus"&gt;ESB&lt;/a&gt; pro distribuované systémy, to je OpenAjax Hub pro AJAX aplikace. Pokud tvoříte portálová řešení, &lt;a href="http://en.wikipedia.org/wiki/Mashup_%28web_application_hybrid%29"&gt;mashupy&lt;/a&gt;, či složitější aplikace, pak se vám zjednodušení vnitřní komunikace, které vám nabízí OpenAjax Hub bude určitě hodit.&lt;br /&gt;&lt;h4&gt;Odkazy&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification"&gt;OpenAjax Hub Specifikace&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4774203648092109518?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4774203648092109518/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4774203648092109518' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4774203648092109518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4774203648092109518'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/09/openajax-hub-javascriptov-messaging-v.html' title='OpenAjax Hub = javascriptový messaging v 5kB'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-2072784178356744877</id><published>2007-09-14T08:43:00.000+02:00</published><updated>2007-12-07T17:04:36.371+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>DWR a Jetty = výkoný AJAX naruby</title><content type='html'>Nebudu přímo reagovat, ale spíš doplním vlastův blog &lt;a href="http://vavru.cz/java/dwr-ajax-knihovna-pro-remotovani-java-objektu/"&gt;DWR - AJAX knihovna pro remotování Java objektů&lt;/a&gt; o ,z mého hlediska hodně zajímavou ,vlastnost frameworku &lt;a href="http://getahead.org/dwr"&gt;DWR 2.0&lt;/a&gt;, tj. &lt;a href="http://en.wikipedia.org/wiki/Reverse_Ajax"&gt;Reverse AJAX&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Reverse AJAX je když dokážeme ze serveru volat clienta, toď velmi jednoduchá definice. A jak této skutečnosti dosáhnout? Existují 3 možné způsoby:&lt;p&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;polling&lt;/span&gt; - asi nejstarší dostupná varianta, klient se v pravidelných intervalech dotazuje serveru, zda není něco nového - nevýhoda je zřejmá, velmi často dotaz běží na server jenom proto, aby se dozvěděl, že nic nového není&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;piggyback&lt;/span&gt; - dotaz na server se přiloží k nejbližšímu následujícímí regulérnímu požadavku na server - nevýhodou je, že se o změnách ze serveru můžeme dozvědět s poměrně velkým zpožděním&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;comet&lt;/span&gt; - vytvoří se spojení se serverem, toto spojení se neuzavře a server jej využívá k odesílání dat klientovi v okamžiku, kdy má taková data k dispozici - výhodou je, že se klient o změnách dozví okamžitě a toto řešení nevyvolává nežádoucí provoz (blíže např. &lt;a href="http://www.sweb.cz/pichlik/archive/2007_04_15_archive.html#8041729033016633360"&gt;dagiho příspěvek&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Ovšem přeci jenom jednu nevýhodu tento přístup má. Pokud bychom nevytvářeli aplikace "inteligentně", pak každé spojení klienta se serverem, které se používá k posílání dat ze serveru na klienta, nám použije jedno vlákno na serveru, což bude řešení, které nebude moc škálovatelné.&lt;br /&gt;&lt;h4&gt;DWR + Jetty = výkoný reverse AJAX&lt;/h4&gt;Nyní se dostaneme k řešení, které framework DWR dovoluje použít, pokud je nasazen v kontejneru &lt;a href="http://www.mortbay.org/"&gt;Jetty 6.0&lt;/a&gt;. Ve verzi 6.0 totiž Jetty obsahuje podporu pro &lt;a href="http://docs.codehaus.org/display/JETTY/Continuations"&gt;&lt;span style="font-style: italic;"&gt;continuations&lt;/span&gt;&lt;/a&gt;, které umožňují "uspat" obsloužení aktuálního požadavku a vyvolat jej později (za podpory &lt;code&gt;java.nio&lt;/code&gt; toto uspání neznamená uspání a blokování obslužného vlákna požadavku).&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nyní se pomalu dostaneme k příkladu chat serveru. V první řadě si představíme třídu, která bude reprezentovat zprávu:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public class ChatMessage {&lt;br /&gt;&lt;br /&gt; protected String nick;&lt;br /&gt; protected String message;&lt;br /&gt;&lt;br /&gt; public ChatMessage(String nick, String message) {&lt;br /&gt;   super();&lt;br /&gt;   this.nick = nick;&lt;br /&gt;   this.message = message;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getNick() {&lt;br /&gt;   return nick;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getMessage() {&lt;br /&gt;   return message;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Nic překvapujícího není k vidění. Následuje rozhraní pro příjemce nových zpráv a třída, která bude &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singleton&lt;/a&gt; a bude implementovat vstupní bránu pro všechny došlé zprávy (doručené např. AJAX requestem a nebo obyčejným odesláním formuláře - implementaci takového jednoduchého servletu nechám na vás). Jdu rovnou na &lt;code&gt;ChatListener&lt;/code&gt; a &lt;code&gt;ChatGateway&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public void class ChatListener {&lt;br /&gt;&lt;br /&gt; public void onMessage(ChatMessage msg);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void class ChatGateway {&lt;br /&gt;&lt;br /&gt; private static final ChatGateway instance = new ChatGateway();  //singleton instance&lt;br /&gt;&lt;br /&gt; protected List&amp;lt;ChatListener&amp;gt; lsts;&lt;br /&gt;&lt;br /&gt; private ChatGateway() {&lt;br /&gt;   super();&lt;br /&gt;   lsts = new ArrayList&amp;lt;ChatListener&amp;gt;();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void addListener(ChatListener lst) { //přidej posluchače&lt;br /&gt;   ...&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void newMessage(ChatMessage msg) {&lt;br /&gt;   List&amp;lt;ChatListener&amp;gt;  lsts2 = lsts;&lt;br /&gt;   for (ChatListener lst : lsts2) {&lt;br /&gt;     lst.onMessage(msg); //každému sděl novou zprávu&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;V tomto kódu stále ještě není žádné moudro, které by nějak přibližovalo naše řešení a proto pojďme dále k &lt;code&gt;ChatTracker&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;import org.directwebremoting.*;&lt;br /&gt;&lt;br /&gt;public class CharTracker implements ChatListener {&lt;br /&gt;&lt;br /&gt; protected static final String URL = "...";  //URL stránky, kde se chat odehrává&lt;br /&gt;&lt;br /&gt; protected ServerContext srvCtx;  //to je celé DWR kouzlo&lt;br /&gt;&lt;br /&gt; public void ChatTracker() {&lt;br /&gt;   super();&lt;br /&gt;&lt;br /&gt;   //vytvoříme server context&lt;br /&gt;   WebContext webCtx = WebContextFactory.get();&lt;br /&gt;   srvCtx = ServerContextFactory.get(webCtx.getServletContext());&lt;br /&gt;&lt;br /&gt;   //gateway o nás musí vědět&lt;br /&gt;   ChatGateway.getInstance().addListener(this);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void onMessage(ChatMessage msg) {&lt;br /&gt;   //vytvoříme script, který bude odeslán všem klientům&lt;br /&gt;   ScriptBuilder sb = new ScriptBuilder();&lt;br /&gt;   sb.appendScript("newMsg(").appendData(msg).appendScript(");");&lt;br /&gt;&lt;br /&gt;   //pošli script všem klientům, kteří jsou na stránce s definovaným URL&lt;br /&gt;   for (ScriptSession ss: serCtx.getScriptSessionsByPage(URL)) {&lt;br /&gt;   ss.addScript(sb);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;V tomto útržku kódu je velmi podstatný &lt;code&gt;ServerContext&lt;/code&gt;, což je DWR třída, která pro nás bude prostředníkem pro zjišťování, kteří klienti jsou právě na stránce chatu a má se jim poslat informace o nové zprávě. Každý takový klient je reprezentován instancí třídy &lt;code&gt;ScriptSession&lt;/code&gt;, která je použita k posílání událostí (v našem příkladu k posílání JavaScriptového kódu).&lt;br /&gt;&lt;br /&gt;Podstatnou drobností je metoda &lt;code&gt;appendData&lt;/code&gt; třídy &lt;code&gt;ScriptBuilder&lt;/code&gt;, která zakóduje Java objekt do JavaScriptové implementace, přesně v duchu DWR (viz. konfigurace dále).&lt;br /&gt;&lt;br /&gt;Pro jednoduchost nepoužiji integraci se &lt;a href="http://www.springframework.org/"&gt;SpringFrameworkem&lt;/a&gt; a použiji přímou konfiguraci DWR pomocí souboru &lt;code&gt;dwr.xml&lt;/code&gt;, jenž bude umístěn v adresáři &lt;code&gt;WEB-INF&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;dwr&amp;gt;&lt;br /&gt; &amp;lt;allow&amp;gt;&lt;br /&gt;   &amp;lt;create creator="new" javascript="chatTracker" scope="application"&amp;gt;&lt;br /&gt;     &amp;lt;param name="class" value="ChatTracker"/&amp;gt;&lt;br /&gt;   &amp;lt;/create&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;convert converter="bean" match="ChatMessage"/&amp;gt;&lt;br /&gt; &amp;lt;/allow&amp;gt;&lt;br /&gt;&amp;lt;/dwr&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;S přihlédnutím k vlastově příspěvku zde není nic neznámého a představíme si definici DWR servletu ve &lt;code&gt;web.xml&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt; &amp;lt;servlet-name&amp;gt;dwr-invoker&amp;lt;/servlet-name&amp;gt;&lt;br /&gt; &amp;lt;servlet-class&amp;gt;org.directwebremoting.servlet.DwrServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt; &amp;lt;init-param&amp;gt;&lt;br /&gt;   &amp;lt;param-name&amp;gt;activeReverseAjaxEnabled&amp;lt;/param-name&amp;gt;&lt;br /&gt;   &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;&lt;br /&gt; &amp;lt;/init-param&amp;gt;&lt;br /&gt; &amp;lt;init-param&amp;gt;&lt;br /&gt;   &amp;lt;param-name&amp;gt;initApplicationScopeCreatorAtStartup&amp;lt;/param-name&amp;gt;&lt;br /&gt;   &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;&lt;br /&gt; &amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Servlet &lt;code&gt;DwrServlet&lt;/code&gt; je v jiné package, než uváděl vlasta, což je dáno použitím verze 2.0. Parametr &lt;code&gt;activeReverseAjaxEnabled&lt;/code&gt; povoluje reverse AJAX a &lt;code&gt;initApplicationScopeCreatorAtStartup&lt;/code&gt; zařídí vytvoření instance&lt;br /&gt;třídy  &lt;code&gt;ChatTracker&lt;/code&gt; při startu aplikace, nikolivěk při jejím prvním použití.&lt;br /&gt;&lt;br /&gt;A co na straně klienta. Asi už je vám jasné, že to bude opět velmi jednoduché:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;window.onload = function() {&lt;br /&gt; dwr.engine.setActiveReverseAjax(true);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function newMsg(msg) {&lt;br /&gt; if(msg) {&lt;br /&gt;   //zde přidej kód pro zobrazení zprávy&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A je to. Je to úžasně jednoduché, to je přesně podle mého gusta. Jediné co mi dělá vrásky na čele, je implementace pouze pro Jetty 6.0, ale už existuje požadavek na vytvoření podpory pro Tomcat 6.0 (&lt;a href="http://getahead.org/bugs/browse/DWR-143"&gt;DWR-143&lt;/a&gt;), tak snad se v budoucnu dočkáme.&lt;br /&gt;&lt;h4&gt;Závěr&lt;/h4&gt;&lt;br /&gt;Ukázal jsem vám, jak pomocí DWR 2.0 a Jetty 6.0 implementovat posílání událostí ze serveru na klienty na příkladu chatu. DWR vám jednoznačně hodně ulehčí v implementování detailů, čímž vám ušetří nejenom čas, ale i nervy. Navíc můžete velmi jednoduše přepínat mezi pollováním, piggybackem a cometem bez zásahu do vašeho kódu, všechny detaily jsou schované uvnitř DWR.&lt;br /&gt;&lt;h4&gt;Odkazy&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.webtide.com/downloads/whitePaperAjaxJetty.html"&gt;Ajax, Comet and Jetty&lt;/a&gt; (Greg Wilkins, Webtide, 2006)&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.codehaus.org/display/JETTY/Continuations"&gt;Jetty Continuations&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-2072784178356744877?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/2072784178356744877/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=2072784178356744877' title='Počet komentářů: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2072784178356744877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/2072784178356744877'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/09/dwr-jetty-vkon-ajax-naruby.html' title='DWR a Jetty = výkoný AJAX naruby'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8478588303162378135.post-4919452988501220163</id><published>2007-09-10T20:01:00.000+02:00</published><updated>2007-09-10T23:12:04.136+02:00</updated><title type='text'>Něco úvodem</title><content type='html'>&lt;span style="font-family:arial;"&gt;Nejprve vám napíšu něco o sobě. Primárně jsem programátor. Takže se na těchto stránkách budete potkávat s různými věcmi týkajícími se programování, tj. od serveru po klienta, od Javy po SQL, od IDE po profiler atd. A abych nezapomněl, asi se tu budete potkávat i s detaily o projektu &lt;a href="http://cobertura.sf.net/"&gt;cobertura&lt;/a&gt;, protože to je už i moje dítě.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;A proč mít vlastní blog? Vede mě k tomu pocit, že se chci podělit o svoje zkušenosti, které věřím nejsou malé a budou čím dál větší. Snad budu mít stále i chuť sepisovat své zážitky, aby zde bylo co číst.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8478588303162378135-4919452988501220163?l=jirablog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jirablog.blogspot.com/feeds/4919452988501220163/comments/default' title='Komentáře k příspěvku'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8478588303162378135&amp;postID=4919452988501220163' title='Počet komentářů: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4919452988501220163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8478588303162378135/posts/default/4919452988501220163'/><link rel='alternate' type='text/html' href='http://jirablog.blogspot.com/2007/09/nco-vodem.html' title='Něco úvodem'/><author><name>Jira</name><uri>http://www.blogger.com/profile/08468747543558661137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://2.bp.blogspot.com/_w-Wca0Ms2Yc/SaPRnITsDiI/AAAAAAAAAEI/LNQ7uB7WyQI/S220/me.jpg'/></author><thr:total>0</thr:total></entry></feed>
