<?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:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3476707669923401512</id><updated>2012-03-17T06:26:45.953+02:00</updated><category term='4developers'/><category term='konferencja'/><category term='JavaFX'/><title type='text'>Krzysztof Adamczyk - Java Developer's Diary</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-3340464691913674403</id><published>2009-12-14T19:16:00.006+02:00</published><updated>2010-02-17T17:38:45.550+02:00</updated><title type='text'>Przenosiny Bloga</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Blog został przeniesiony pod adres:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:180%;"&gt;&lt;a href="http://www.krzysztofadamczyk.com/"&gt;&lt;span style="font-weight: bold;"&gt;www.krzysztofadamczyk.com&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Zapraszam :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/3340464691913674403/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=3340464691913674403' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/3340464691913674403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/3340464691913674403'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/12/przenosiny-bloga.html' title='Przenosiny Bloga'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-2434914662642357754</id><published>2009-09-03T16:07:00.014+03:00</published><updated>2009-09-03T17:03:02.654+03:00</updated><title type='text'>Configuring HermesJMS to work with Tibco</title><content type='html'>I assume that you have Tibco installed in &amp;lt;TIBCOHOME&amp;gt;&lt;br /&gt;&lt;br /&gt;1) Download &amp;amp; install &lt;a href="http://sourceforge.net/projects/hermesjms/"&gt;HermesJMS&lt;/a&gt;.  I assume that &amp;lt;HERMES_HOME&amp;gt; is the installation directory for Hermes.&lt;br /&gt;2) Copy &lt;span style="font-weight: bold;"&gt;&amp;lt;TIBCOHOME&amp;gt;/ems/clients/java/*.*&lt;/span&gt;   into  &lt;span style="font-weight: bold;"&gt;&amp;lt;HERMES_HOME&amp;gt;/lib&lt;/span&gt;. &lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; There is no need to overwrite existing files.&lt;br /&gt;3) For next steps, there is a presentation prepared &lt;a href="http://www.hermesjms.com/confluence/display/HJMS/EMS+Tutorial"&gt;here&lt;/a&gt; and we will follow it with the following note: See the first step of the presentation, then stop and come back here :) In the first step the presentation shows already prepared, long list of providers. To work with Tibco, we will only need one provider, which we have to add manually. To add a provider, go to &lt;span style="font-style: italic;"&gt;Providers&lt;/span&gt; tab in &lt;span style="font-style: italic;"&gt;Preferences&lt;/span&gt; dialog,  right click under &lt;span style="font-style: italic;"&gt;Classpath Groups,&lt;/span&gt; select &lt;span style="font-style: italic;"&gt;Add Group&lt;/span&gt; and type the name (i.e. Tibco Ems). When the provider appears on the list, expand it's subtree to see the &lt;span style="font-style: italic;"&gt;Library&lt;/span&gt; item. Right click on &lt;span style="font-style: italic;"&gt;Library&lt;/span&gt; and select &lt;span style="font-style: italic;"&gt;Add JAR(s)&lt;/span&gt;. Add all JARs in&lt;span style="font-weight: bold;"&gt;  &amp;lt;TIBCOHOME&amp;gt;/ems/clients/java &lt;/span&gt;directory. Click Apply, then OK to close &lt;span style="font-style: italic;"&gt;Preferences&lt;/span&gt; window. Continue with &lt;span style="font-weight: bold;"&gt;step 2&lt;/span&gt; of the presentation.&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In &lt;span style="font-weight: bold;"&gt;Step 3&lt;/span&gt;, don't be surprised if just after selecting the &lt;span style="font-style: italic;"&gt;Loader&lt;/span&gt;  from the dropdown list, the list will disappear. It actually didn't dissapear, it's just behind the right edge of the dialog, and you can see it again, if you resize the dialog.&lt;br /&gt;&lt;br /&gt;Good luck!</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/2434914662642357754/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=2434914662642357754' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2434914662642357754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2434914662642357754'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/09/configuring-hermesjms-to-work-with.html' title='Configuring HermesJMS to work with Tibco'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-8108600486641468291</id><published>2009-08-31T16:18:00.003+03:00</published><updated>2009-08-31T16:35:21.153+03:00</updated><title type='text'>JDK5, Ubuntu i Summer Time</title><content type='html'>Zacznijmy od tego że jestem właśnie w trakcie przesiadki na Linuksa, a konkretnie Kubuntu.&lt;br /&gt;&lt;br /&gt;Pierwszy poważny problem który napotkałem dotyczy strefy czasowej widzianej przez Jave.  Konfiguracja:&lt;br /&gt;&lt;br /&gt;1) JRE6 zainstalowane "z paczki" (za pomocą aptitude), aby za jego pomocą uruchamiać Javowe narzędzia, aplety w przeglądarce itp.&lt;br /&gt;2) JDK5 ściągnięte od Suna i rozpakowane. Służy do celów deweloperskich. Tutaj wskazuje JAVA_HOME.&lt;br /&gt;&lt;br /&gt;Problem polegał na tym że Java w JDK nie uwzględniała przesunięcia czasu letniego (w zainstalowanym "z paczki" JRE jest OK). Po kilku godzinach rwania włosów z głowy znalazłem &lt;a href="https://bugs.launchpad.net/ubuntu/+source/sun-java6/+bug/49068/comments/13"&gt;to zgłoszenie buga&lt;/a&gt;. W tytule mowa jest co prawda o JDK6, ale jak się okazuje pasuje również do wersji 5. Wykonałem z drobną zmianą to co tam jest opisane, czyli:&lt;pre&gt;&lt;br /&gt;sudo cp /etc/localtime /etc/localtime.bak&lt;br /&gt;sudo ln -s -f /usr/share/zoneinfo/Europe/Warsaw /etc/localtime&lt;br /&gt;&lt;/pre&gt; i po problemie. Weird...&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Jaki komunikator polecacie? Najlepsze by było coś co obsłuży zarówno GG jak i Jabbera.</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/8108600486641468291/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=8108600486641468291' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/8108600486641468291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/8108600486641468291'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/08/jdk5-ubuntu-i-summer-time.html' title='JDK5, Ubuntu i Summer Time'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5046921828191634727</id><published>2009-08-12T14:28:00.003+03:00</published><updated>2009-08-12T14:44:31.838+03:00</updated><title type='text'>Testowalny kod</title><content type='html'>Mamy sezon ogórkowy, więc tylko krótki post o tym co niezwykle ważne, nawet w wakacje. Świetny artykuł Misko &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Hevery&lt;/span&gt; zatytułowany &lt;a href="http://misko.hevery.com/code-reviewers-guide/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Writing&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Testable&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Code&lt;/span&gt;&lt;/a&gt;. Artykuł kieruje do &lt;a href="http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf"&gt;mini-książki&lt;/a&gt; w formacie &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;PDF&lt;/span&gt; zawierającej praktyczne przykłady jak istniejący, kiepski kod doprowadzić do sensownej i &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;testowalnej&lt;/span&gt; postaci. Autorzy &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;wykorzystują&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;framework&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Guice&lt;/span&gt;, ale koncepcyjnie proponowane rozwiązania są uniwersalne.&lt;br /&gt;Planuję również przyjrzeć się projektowi &lt;a href="http://code.google.com/p/testability-explorer/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Testability&lt;/span&gt; Explorer&lt;/a&gt;, którego współautorem jest Misko, a który umożliwia analizowanie kodu pod względem &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;testowalności&lt;/span&gt; (statyczna analiza &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;bytecodu&lt;/span&gt; z tego co na szybko wyczytałem). Na razie ściągnąłem źródła i przekonałem się na własne oczy, że możliwości oferowane przez &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;Guice&lt;/span&gt; są naprawdę bardzo ciekawe.&lt;br /&gt;&lt;br /&gt;Miłej lektury!</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5046921828191634727/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5046921828191634727' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5046921828191634727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5046921828191634727'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/08/testowalny-kod.html' title='Testowalny kod'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5500729101526915190</id><published>2009-07-07T17:21:00.006+03:00</published><updated>2009-07-07T17:40:02.581+03:00</updated><title type='text'>Manifesto for Software Craftsmanship</title><content type='html'>&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0zhWBYvrXoE/SlNeL2UDpGI/AAAAAAAAALc/T-gHbYLKAlM/s1600-h/craft.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 366px;" src="http://4.bp.blogspot.com/_0zhWBYvrXoE/SlNeL2UDpGI/AAAAAAAAALc/T-gHbYLKAlM/s400/craft.JPG" alt="" id="BLOGGER_PHOTO_ID_5355727939524863074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Nie ma już odwrotu :) Świadomy praw i obowiązków, pełen chęci ciągłego doskonalenia swego &lt;a href="http://en.wikipedia.org/wiki/Software_Craftsmanship"&gt;rzemiosła&lt;/a&gt; podpisałem dziś &lt;a href="http://manifesto.softwarecraftsmanship.org/"&gt;manifest&lt;/a&gt;. Do czego gorąco także i Ciebie zachęcam, jeśli nie jest Ci obca troska o jakość Twojej pracy.</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5500729101526915190/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5500729101526915190' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5500729101526915190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5500729101526915190'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/07/manifesto-for-software-craftsmanship.html' title='Manifesto for Software Craftsmanship'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_0zhWBYvrXoE/SlNeL2UDpGI/AAAAAAAAALc/T-gHbYLKAlM/s72-c/craft.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5356834923798973864</id><published>2009-07-05T15:28:00.009+03:00</published><updated>2009-07-05T16:28:41.318+03:00</updated><title type='text'>Javarsovia 2009 za nami</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0zhWBYvrXoE/SlCcjln3DKI/AAAAAAAAALE/4767eXOc_WE/s1600-h/javarsovia2009.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 239px; height: 119px;" src="http://4.bp.blogspot.com/_0zhWBYvrXoE/SlCcjln3DKI/AAAAAAAAALE/4767eXOc_WE/s400/javarsovia2009.jpg" alt="" id="BLOGGER_PHOTO_ID_5354952092152171682" border="0" /&gt;&lt;/a&gt;Największa bezpłatna konferencja polskiej społeczności javowej niestety już za nami. Piszę niestety, ponieważ to wydarzenie było niewątpliwym sukcesem i chciałoby się mieć takie konferencje co tydzień ;) Na Javarsovii nie zabrakło ciekawych prezentacji i niejednokrotnie ciężko było mi się zdecydować który wykład o danej godzinie wybrać. Szkoda mi kilku wykładów, które zmuszony byłem ominąć - mam nadzieję że organizatorzy szybko udostępnią filmy z konferencji i będzie można nadrobić tę stratę. Szczególnie żałuję wykładu &lt;a href="http://monkeyisland.pl/"&gt;Szczepana&lt;/a&gt;&lt;a href="http://monkeyisland.pl/"&gt; Fabra&lt;/a&gt; na temat testowania - ten temat od dłuższego czasu coraz bardziej mnie wciąga a wczoraj nie wiedzieć czemu poszedłem na Cloud Computing, który szczerze mówiąc trochę rozczarował... Uczestniczyłem już kiedyś w (rewelacyjnej zresztą) prezentacji Szczepana na temat Mockito (chyba było to na JDD) i tym razem pomyślałem że również będzie o Mockito - dlatego wybrałem inny wykład... Ominęła mnie także prezentacja &lt;a href="http://lukaszlipka.blogspot.com/"&gt;Łukasza Lipki&lt;/a&gt; z naszego rodzimego &lt;a href="http://groups.google.com/group/silesia-jug?pli=1"&gt;Silesia JUG&lt;/a&gt; nt. Mule ESB. Łukasz mówił już kiedyś o Mule na spotkaniu JUGa, chociaż na Javarsovii na pewno rozszerzył jeszcze i tak ciekawą prezentację ;)&lt;br /&gt;&lt;br /&gt;To może teraz coś o wykładach na których byłem :) Wymienię trzy, które zrobiły na mnie największe wrażenie, dostarczyły najwięcej nowej wiedzy - wybór oczywiście subiektywny.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Konrad Kamiński&lt;/span&gt; przedstawił &lt;span style="font-style: italic;"&gt;Garbage First&lt;/span&gt; - nowy garbage collector w maszynie HotSpot. Szczerze przyznam, że przed tym wykładem nie miałem pojęcia jak działają wewnętrzne algorytmy GC a wykład Konrada dał dużo światła na ten jakże ważny temat. Nowy GC wygląda ciekawie, a możliwość określenia ile maksymalnie czasu może zajmować jego praca w danym odcinku czasu jest w aplikacjach serwerowych bardzo pożądana.&lt;br /&gt;&lt;br /&gt;Kolejnym świetnym wykładem był wykład &lt;a href="http://kijanowski.blogspot.com/"&gt;Jarosława Kijanowskiego&lt;/a&gt; na temat &lt;span style="font-weight: bold;"&gt;Drools Guvnor&lt;/span&gt;. Temat mi osobiście bliski, ponieważ używam Drools w projekcie nad którym obecnie pracuję. Jarek poprowadził prezentację w bardzo ciekawy, luźny sposób oraz - co należy podkreślić - pominął wiele niepotrzebnych detali technicznych które z punktu widzenia meritum tematu były nieistotne a jedynie zaciemniłyby obraz. Tej umiejętności niestety wciąż brakuje wielu polskim prelegentom, którzy potrafią zasypać słuchacza tonami XMLi wylewających się z projektora... Oprócz Guvnor'a Jarek zaprezentował również Drools CEP (Complex Event Processing) które pozwala na podejmowanie decyzji nie tylko na podstawie bieżących faktów, ale również "patrząc wstecz" (np 10 ostatnich zdarzeń, zdarzenia z ostatnich 20min) - ciekawa sprawa. Nie próbowałem jeszcze użyć Drools CEP, ale wygląda na to, że może być on darmową, opensource'ową konkurencją dla Oracle CEP.&lt;br /&gt;&lt;br /&gt;Ostatnim wykładem na który się wybrałem był &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/testing.html#testcontext-framework"&gt;Spring TestContext Framework&lt;/a&gt; &lt;a href="http://jmilkiewicz.blogspot.com/"&gt;Jakuba Milkiewicza&lt;/a&gt;. Bardzo, bardzo ciekawy wykład poprowadzony w świetnym stylu. Publiczność wręcz domagała się przedłużenia prezentacji i przedstawienia jeszcze kilku przykładów. Do tej pory używałem małej części tego mini-frameworku, ale po tym wykładzie na pewno to się zmieni. Muszę się również przyjrzeć &lt;a href="http://code.google.com/p/hamcrest/"&gt;HamCrest&lt;/a&gt;'owi, którego Jakub używał do tworzenia asercji.&lt;br /&gt;&lt;br /&gt;Na koniec dygresja na temat organizacji konferencji. To że organizatorzy &lt;span style="font-weight: bold;"&gt;DARMOWEJ&lt;/span&gt; konferencji zorganizowali &lt;span style="font-weight: bold;"&gt;DARMOWY lunch&lt;/span&gt; dla wszystkich uczestników - to jak dla mnie (jako głodomora) &lt;span style="font-weight: bold;"&gt;mistrzostwo świata&lt;/span&gt;!!! Poza tym ogólnie nie było rzeczy do której można by się przeczepić :) Wykłady ciekawe, żołądek pełny, sale dobre, miejsca dosyć, widoczność dobra itd itp. &lt;span style="font-weight: bold;"&gt;Podnieśliście poprzeczkę Panowie!&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5356834923798973864/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5356834923798973864' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5356834923798973864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5356834923798973864'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/07/javarsovia-2009-za-nami.html' title='Javarsovia 2009 za nami'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_0zhWBYvrXoE/SlCcjln3DKI/AAAAAAAAALE/4767eXOc_WE/s72-c/javarsovia2009.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5183941113212416835</id><published>2009-06-11T21:58:00.030+03:00</published><updated>2009-06-21T18:18:48.041+03:00</updated><title type='text'>Pragmatyczny programista</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0zhWBYvrXoE/Sj40pbtzF8I/AAAAAAAAAK8/5o20AjGUulo/s1600-h/pp-okladka.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 200px; height: 260px;" src="http://1.bp.blogspot.com/_0zhWBYvrXoE/Sj40pbtzF8I/AAAAAAAAAK8/5o20AjGUulo/s400/pp-okladka.jpg" alt="" id="BLOGGER_PHOTO_ID_5349771293781858242" border="0" /&gt;&lt;/a&gt;Właśnie skończyłem czytać książkę  &lt;a href="http://merlin.pl/Pragmatyczny-programista-Od-czeladnika-do-mistrza_Andrew-Hunt-David-Thomas/browse/product/1,299928.html"&gt;"Pragmatyczny programista. Od czeladnika do mistrza"&lt;/a&gt;. Nie będę odosobniony, jeśli powiem,  że każdy programista powinien tę książkę przeczytać. Ten post jest zgrupowaniem haseł i zasad, które dla mnie osobiście były najciekawszą nauką płynącą z tej lektury. Większość z nich to tematy znane, ale moim zdaniem na tyle ważne żeby jeszcze raz o nich powiedzieć i podkreślić ich znaczenie.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-weight: bold;"&gt;Wybite okno&lt;/span&gt;&lt;/div&gt;Kiedy w bloku pojawi się wybite okno i nikt dostatecznie szybko tego nie naprawi, szybko pojawią się kolejne wybite okna i inne oznaki postępującego zniszczenia. Podobna zasada dotyczy kodu źródłowego - nie pozostawiaj w swoich systemach &lt;span style="font-style: italic;"&gt;wybitych okien &lt;/span&gt;(zły kod, antywzorce, błędne decyzje projektowe, work-around'y). Nie dopuszczaj do powstania "ogniska rozkładu" Twojego systemu.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;&lt;div style="text-align: left;"&gt;&lt;div style="text-align: left;"&gt;Ortogonalność&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_0zhWBYvrXoE/Sj4mx9IWg4I/AAAAAAAAAK0/WK_RjiKZHXw/s1600-h/wektory.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 184px; height: 109px;" src="http://2.bp.blogspot.com/_0zhWBYvrXoE/Sj4mx9IWg4I/AAAAAAAAAK0/WK_RjiKZHXw/s400/wektory.jpg" alt="" id="BLOGGER_PHOTO_ID_5349756047027766146" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;Poruszając się wzdłuż osi pionowej, rzut aktualnego położenia na oś poziomą nie zmienia się. Tak powinny być zaprojektowane systemy informatyczne: zmiany w module A nie powinny być zauważone przez moduł B. Oba moduły powinny komunikować się za pomocą dobrze zdefiniowanych interfejsów, a szczegóły implementacji powinny być ukryte tak, aby każdy z modułów mógł zostać zmieniony, a nawet zastąpiony bez konieczności zmian w pozostałych modułach.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prawo Demeter&lt;/span&gt; (zasada minimalnej wiedzy)&lt;br /&gt;W dużym skrócie: rozmawiaj tylko z obiektami z własnego otoczenia. Nie wyciągaj z nich innych obiektów ("wnętrzności") aby z nimi porozmawiać (byłoby to wnikanie w implementację).  Niech obiekt nadrzędny odpowiednio oddeleguje wywołania, sam decydując jak chce zrealizować zadany cel. Zamiast: &lt;pre name="code" class="java"&gt;car.getOnboardComputer().getGPS().getLocation();&lt;/pre&gt;napisz&lt;br /&gt;&lt;pre name="code" class="java"&gt;car.getLocation()&lt;/pre&gt;pozostawiając klasie Car decyzję, jak zaimplementować określanie lokalizacji.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Pociski smugowe&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Autorzy nazwali tak technikę podobną nieco do prototypowania, która zaleca stworzenie na początku rozwiązania bardzo ubogiego, ale przechodzącego przez wszystkie warstwy i stanowiącego bazę dla dalszego rozwoju systemu. W odróżnieniu od prototypu, rozwiązanie to nie trafia do kosza po sprawdzeniu że działa, lecz staje się integralną częścią systemu, wokół której tworzone są kolejne funkcjonalności aż do zakończenia projektu. Nazwa &lt;span style="font-style: italic;"&gt;pociski smugowe&lt;/span&gt; wzięła się z tego, że stworzony kod pozwala stwierdzić, czy  projekt "trafia do celu" czyli idzie w dobrym kierunku już na początku, posiadając zaimplementowaną jedynie najmniejszą możliwą część funkcjonalności. Dziś w dobie &lt;span style="font-weight: bold;"&gt;agile&lt;/span&gt;, chyba bardzo często stosowana technika ;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Odwracalność&lt;/span&gt;&lt;br /&gt;Podejmuj decyzje odwracalne. Przygotuj się na to, że klient zechce zmienić wersję, lub nawet producenta bazy danych, serwer aplikacyjny etc...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Programowanie przypadkowe&lt;/span&gt;&lt;br /&gt;Fred nie wie dlaczego program nie działa, ponieważ wcześniej nie wiedział, dlaczego program działał.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Poznaj API&lt;/span&gt;&lt;br /&gt;i technologie które używasz, aby nie tworzyć kodu na oślep, kodu który &lt;span style="font-style: italic;"&gt;działa przez przypadek&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Testowanie jednostkowe&lt;/span&gt;&lt;br /&gt;jest jak testowanie układów scalonych - sygnały podane na odpowiednie wejścia powodują odpowiednie stany na wyjściach.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DRY&lt;/span&gt;&lt;br /&gt;Na temat tej zasady nie będę się powtarzał :)&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5183941113212416835/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5183941113212416835' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5183941113212416835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5183941113212416835'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/06/pragmatyczny-programista.html' title='Pragmatyczny programista'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_0zhWBYvrXoE/Sj40pbtzF8I/AAAAAAAAAK8/5o20AjGUulo/s72-c/pp-okladka.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-2872960108811030808</id><published>2009-05-21T16:57:00.064+03:00</published><updated>2009-06-11T21:34:23.496+03:00</updated><title type='text'>JBoss Drools - działająca aplikacja w 10 minut</title><content type='html'>Postanowiłem stworzyć minimalną aplikację JavaSE korzystającą z silnika reguł JBoss Drools oraz tablic decyzyjnych zapisanych w postaci arkuszy Excela. Poniżej przedstawiam moje wyniki. Najważniejszą wytyczną podczas tworzenia tej aplikacji była prostota, aby zobaczyć jakie minimalne kroki są konieczne aby uruchomić Drools. Dlatego też aplikacja jest pozbawiona kontroli błędów, walidacji parametrów itp - nie o to tu chodziło.&lt;br /&gt;&lt;br /&gt;No to się wytłumaczyłem - teraz do dzieła :)&lt;br /&gt;&lt;br /&gt;Zaczynamy od stworzenia tablicy decyzyjnej:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0zhWBYvrXoE/ShqRAi4m2LI/AAAAAAAAAJI/ITzakJG_lsU/s1600-h/drools1.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 121px;" src="http://1.bp.blogspot.com/_0zhWBYvrXoE/ShqRAi4m2LI/AAAAAAAAAJI/ITzakJG_lsU/s400/drools1.JPG" alt="" id="BLOGGER_PHOTO_ID_5339739746751404210" border="0" /&gt;&lt;/a&gt;Podstawowym pojęciem w tematyce tablic decyzyjnych jest &lt;span style="font-style: italic;"&gt;fakt&lt;/span&gt; - na nasze potrzeby możemy zdefiniować to pojęcie jako &lt;span style="font-style: italic;"&gt;obiekt Javowy&lt;/span&gt; umieszczony w pamięci roboczej (working memory) silnika reguł w trakcie jego uruchamiania, lub też powstały "wewnątrz silnika" jako rezultat działania którejś reguły. W naszym przykładzie występują tylko fakty umieszczone w pamięci roboczej "z zewnątrz". Fakty posiadają atrybuty, czyli w naszym przypadku właściwości (&lt;span style="font-style: italic;"&gt;properties&lt;/span&gt;) obiektów Javowych. Drools umożliwia tworzenie warunków na konkretną wartość pola obiektu - oczywiście musimy trzymać się konwencji JavaBeans.&lt;br /&gt;&lt;br /&gt;Definicja tabeli zaczyna się w komórce oznaczonej tekstem &lt;span style="font-style: italic;"&gt;RuleTable &lt;name&gt;&lt;/name&gt;&lt;/span&gt;. W kolejnym wierszu wpisujemy nagłówki oznaczające rolę danej kolumny w tabeli - &lt;span style="font-weight: bold;"&gt;condition&lt;/span&gt; (warunek) lub &lt;span style="font-weight: bold;"&gt;action&lt;/span&gt; (konsekwencja, akcja). Kolejne dwa wiersze służą do definiowania szczegółów warunku lub akcji. Warunkiem może być np. istnienie jakiegoś faktu (komórka B9) lub konkretna wartość atrybutu faktu (komórki C8 i C9 - tutaj odnosimy się do wartości atrybutu &lt;span style="font-style: italic;"&gt;name &lt;/span&gt;faktu typu &lt;span style="font-weight: bold;"&gt;Activity&lt;/span&gt; a kolejne wiersze są potencjalnymi wartościami tego pola). Tabela zawiera dwie reguły (wiersze 11 i 12):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Istnieje Student oraz istnieje Activity o nazwie &lt;span style="font-weight: bold;"&gt;fun&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Istnieje Student oraz istnieje Activity o nazwie &lt;span style="font-weight: bold;"&gt;learning&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt; Dla obu reguł istnieje wspólna akcja, zdefiniowana jako fragment kodu Javy - dodanie Stringa do listy. $param oznacza wartość z komórki wybranej jako przecięcie bieżącej kolumny (akcji) i wiersza uruchomionej reguły. Jeśli więc silnik reguł zostanie zasilony faktem &lt;span style="font-weight: bold;"&gt;Student &lt;/span&gt;oraz faktem &lt;span style="font-weight: bold;"&gt;Activity &lt;/span&gt;o atrybucie &lt;span style="font-style: italic;"&gt;name &lt;/span&gt;równym &lt;span style="font-style: italic;"&gt;learning&lt;/span&gt; - wówczas zostanie uruchomiona akcja pierwszej reguły. Jeśli dodatkowo pojawi się fakt &lt;span style="font-weight: bold;"&gt;Activity &lt;/span&gt;o atrybucie &lt;span style="font-style: italic;"&gt;name&lt;/span&gt;=&lt;span style="font-style: italic;"&gt;fun&lt;/span&gt;&lt;span style="font-style: italic;"&gt;, &lt;/span&gt;zostanie również uruchomiona akcja drugiej reguły. Kilka faktów umieszczonych w &lt;span style="font-style: italic;"&gt;pamięci roboczej&lt;/span&gt; (working memory) silnika reguł może spowodować uruchomienie wielu reguł. Bardziej szczegółowe informacje można znaleźć w &lt;a href="http://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html/index.html"&gt;dokumentacji&lt;/a&gt;. Na uwagę zasługuje jeszcze sekcja &lt;span style="font-weight: bold;"&gt;Variables&lt;/span&gt;, która umożliwia zdefiniowanie zmiennych. Pozwala to na bardzo proste zwracanie wyników działania reguł - uruchamiając silnik reguł można za pomocą metody &lt;span style="font-style: italic;"&gt;setGlobal&lt;/span&gt; przekazać referencję do obiektu Javowego, który będzie reprezentował daną zmienną zdefiniowaną w regułach. W naszym przykładzie do zwrócenia listy jako rezultatu działania reguł stosujemy konstrukcję:&lt;br /&gt;&lt;pre name="code" class="java"&gt;...&lt;br /&gt;List rulesEvaluationResult = new ArrayList();&lt;br /&gt;statelessDroolsSession.setGlobal("resultList", rulesEvaluationResult);&lt;br /&gt;Uruchom_reguły&lt;/pre&gt;&lt;br /&gt;Po jej wykonaniu &lt;span style="font-style: italic;"&gt;rulesEvaluationResult &lt;/span&gt;zawiera wynik działania reguł czyli to co wewnątrz tablicy decyzyjnej wkładamy do zmiennej &lt;span style="font-style: italic;"&gt;resultList&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Mając już gotową tablicę decyzyjną możemy przystąpić do tworzenia aplikacji. Zaczynamy od stworzenia projektu wykorzystując Maven'a:&lt;br /&gt;&lt;pre class="command"&gt;mvn archetype:create -DgroupId=pl.kadamczyk.droolssample -DartifactId=DroolsSample&lt;/pre&gt;&lt;br /&gt;Edytujemy plik &lt;b&gt;pom.xml&lt;/b&gt; tak aby znajdowały się w nim następujące zależności:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;pl.kadamczyk.droolssample&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;DroolsSample&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;name&amp;gt;DroolsSample&amp;lt;/name&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt; &amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt; &amp;lt;/dependency&amp;gt;&lt;br /&gt; &amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;org.drools&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;drools-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;4.0.7&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;/dependency&amp;gt;&lt;br /&gt; &amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;org.drools&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;drools-compiler&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;4.0.7&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;/dependency&amp;gt;&lt;br /&gt; &amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;org.drools&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;drools-decisiontables&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;4.0.7&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Jeszcze tylko &lt;pre&gt;mvn install&lt;/pre&gt; oraz &lt;pre&gt;mvn eclipse:eclipse&lt;/pre&gt; i importujemy projekt do Eclipse.&lt;br /&gt;&lt;br /&gt;Dodajemy do projektu klasę, której zadaniem jest stworzenie bazy reguł (RuleBase) na podstawie dostarczonego do niej pliku XLS (jego nazwy):&lt;br /&gt;&lt;pre name="code" class="java"&gt;package pl.kadamczyk.droolssample;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.Reader;&lt;br /&gt;import java.io.StringReader;&lt;br /&gt;import java.util.Properties;&lt;br /&gt;&lt;br /&gt;import org.drools.RuleBase;&lt;br /&gt;import org.drools.RuleBaseFactory;&lt;br /&gt;import org.drools.compiler.DroolsParserException;&lt;br /&gt;import org.drools.compiler.PackageBuilder;&lt;br /&gt;import org.drools.compiler.PackageBuilderConfiguration;&lt;br /&gt;import org.drools.decisiontable.InputType;&lt;br /&gt;import org.drools.decisiontable.SpreadsheetCompiler;&lt;br /&gt;import org.drools.rule.Package;&lt;br /&gt;&lt;br /&gt;public class DecisionTableXlsCompiler {&lt;br /&gt;&lt;br /&gt;    public RuleBase compileToRuleBase(final String decisionTablesXlsFile) throws Exception {&lt;br /&gt;        RuleBase result = RuleBaseFactory.newRuleBase();&lt;br /&gt;&lt;br /&gt;        final InputStream resourceAsStream = DecisionTableXlsCompiler.class.getResourceAsStream(decisionTablesXlsFile);&lt;br /&gt;        final String drl = compileXlsToDlr(resourceAsStream);&lt;br /&gt;        Package rulePackage = this.buildPackageFromDrl(drl);&lt;br /&gt;        result.addPackage(rulePackage);&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private Package buildPackageFromDrl(final String drlString) throws DroolsParserException, IOException {&lt;br /&gt;        Properties properties = new Properties();&lt;br /&gt;        properties.setProperty("drools.dialect.java.compiler", "JANINO");&lt;br /&gt;        properties.setProperty("drools.dialect.java.lngLevel", "1.5");&lt;br /&gt;&lt;br /&gt;        final PackageBuilderConfiguration pkgBuilderCfg = new PackageBuilderConfiguration(properties);&lt;br /&gt;        final PackageBuilder builder = new PackageBuilder(pkgBuilderCfg);&lt;br /&gt;&lt;br /&gt;        Reader drlReader = new StringReader(drlString);&lt;br /&gt;        builder.addPackageFromDrl(drlReader);&lt;br /&gt;&lt;br /&gt;        Package result = builder.getPackage();&lt;br /&gt;&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private String compileXlsToDlr(final InputStream xlsStream) {&lt;br /&gt;        final SpreadsheetCompiler compiler = new SpreadsheetCompiler();&lt;br /&gt;        final String drl = compiler.compile(xlsStream, InputType.XLS);&lt;br /&gt;        return drl;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Oraz klasę, która uruchamia silnik reguł ze skompilowaną wcześniej bazą reguł, zasilając go &lt;span style="font-style: italic;"&gt;faktami&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="java"&gt;package pl.kadamczyk.droolssample;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import org.drools.RuleBase;&lt;br /&gt;import org.drools.StatelessSession;&lt;br /&gt;&lt;br /&gt;public class DroolsEvaluator {&lt;br /&gt;&lt;br /&gt;    public &amp;lt;T&amp;gt; void run(RuleBase ruleBase, final String outParamName, T outParamRef, final List&amp;lt;Object&amp;gt; facts) {&lt;br /&gt;        final StatelessSession statelessDroolsSession = ruleBase.newStatelessSession();&lt;br /&gt;        statelessDroolsSession.setGlobal(outParamName, outParamRef);&lt;br /&gt;        statelessDroolsSession.execute(facts);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;I już możemy tą aplikację uruchomić:&lt;br /&gt;&lt;pre name="code" class="java"&gt;package pl.kadamczyk.droolssample;&lt;br /&gt;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import org.drools.RuleBase;&lt;br /&gt;&lt;br /&gt;import pl.kadamczyk.droolssample.model.Activity;&lt;br /&gt;import pl.kadamczyk.droolssample.model.Student;&lt;br /&gt;&lt;br /&gt;public class Runner {&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        DecisionTableXlsCompiler compiler = new DecisionTableXlsCompiler();&lt;br /&gt;        DroolsEvaluator evaluator = new DroolsEvaluator();&lt;br /&gt;&lt;br /&gt;        List&amp;lt;Object&amp;gt; rulesResult = new ArrayList&amp;lt;Object&amp;gt;();&lt;br /&gt;&lt;br /&gt;        RuleBase ruleBase = compiler.compileToRuleBase("decisiontable.xls");&lt;br /&gt;        evaluator.run(ruleBase, "resultList", rulesResult, prepareFacts());&lt;br /&gt;&lt;br /&gt;        for (Object obj : rulesResult) {&lt;br /&gt;            System.out.println(obj);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static List&amp;lt;Object&amp;gt; prepareFacts() {&lt;br /&gt;        List&amp;lt;Object&amp;gt; facts = new ArrayList&amp;lt;Object&amp;gt;();&lt;br /&gt;        Activity learningActivity = new Activity();&lt;br /&gt;        learningActivity.setName("learning");&lt;br /&gt;        facts.add(learningActivity);&lt;br /&gt;        Activity funActivity = new Activity();&lt;br /&gt;        funActivity.setName("fun");&lt;br /&gt;        facts.add(funActivity);&lt;br /&gt;        facts.add(new Student());&lt;br /&gt;&lt;br /&gt;        return facts;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Uruchomienie powyższego przykładu spowoduje wypisanie na konsoli napisu:&lt;br /&gt;&lt;pre&gt;Student is having fun&lt;br /&gt;Student is learning&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;co jest zgodne z oczekiwaniami, ponieważ przekazane do silnika reguł fakty (obiekty utworzone w metodzie prepareFacts() ) spełniają obie reguły.</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/2872960108811030808/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=2872960108811030808' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2872960108811030808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2872960108811030808'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/05/jboss-drools-dziaajaca-aplikacja-w-10.html' title='JBoss Drools - działająca aplikacja w 10 minut'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_0zhWBYvrXoE/ShqRAi4m2LI/AAAAAAAAAJI/ITzakJG_lsU/s72-c/drools1.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-2742845367728044529</id><published>2009-05-10T18:33:00.017+03:00</published><updated>2009-05-10T20:41:36.694+03:00</updated><title type='text'>GeeCON 2009</title><content type='html'>Miniony tydzień upłynął pod znakiem konferencji &lt;a href="http://www.geecon.org/"&gt;GeeCON&lt;/a&gt; - czas podsumować 2 dni spędzone w Krakowie.&lt;br /&gt;&lt;br /&gt;Organizatorzy na miejsce konferencji wybrali kino (Multikino Kraków) co miało swoje plusy dodatnie i ujemne ;) Świetny efekt daje olbrzymi ekran za plecami prelegenta na którym wyświetlane są slajdy - i to jest krok we właściwym kierunku. Problemem jest jednak właściwe oświetlenie - aby na przyciemnionej sali kinowej widoczny był prelegent, a światło nie oświetlało ekranu. Niestety kompletnie nie udało się to podczas pierwszego wykładu &lt;span style="font-weight: bold;"&gt;Simona Rittera&lt;/span&gt; "JavaFX: The Platform for Rich Internet Applications". Z miejsca w którym siedziałem niektóre slajdy były praktycznie niewidoczne. Wspomniał o tym także sam prelegent, który niejednokrotnie musiał opisywać, co powinno być widoczne na ekranie.&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/b-7HP6qVRvyRyqsSVIlUrA?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_0zhWBYvrXoE/SgbwEOEawSI/AAAAAAAAAGk/5wV_kjaQVZk/s400/P07-05-09_09.46%5B01%5D.JPG" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td face="arial,sans-serif" size="11px" style="text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/krzysztof.adamczyk/GeeCON?feat=embedwebsite"&gt;GeeCON&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/center&gt;Problemy z oświetleniem zostały częściowo rozwiązane i później było już znacznie lepiej. Ciekawą i udaną prelekcję wygłosili panowie ze SpringSource: &lt;span style="font-weight: bold;"&gt;Alef Arendsen i Arjen Poutsma&lt;/span&gt;. Mówili o nowościach w Spring 3.0, a Arjen rozpoczął również drugi dzień konferencji ciekawym wykładem na temat Springa i RESTful WebServices.&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/ir0aoc_uqtLlcQZC0af3Cg?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_0zhWBYvrXoE/Sgb0jD_eMfI/AAAAAAAAAHI/nZLxcED_50g/s400/P07-05-09_11.31.JPG" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td face="arial,sans-serif" size="11px" style="text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/krzysztof.adamczyk/GeeCON?feat=embedwebsite"&gt;GeeCON&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/center&gt;Dalej przyszedł czas na wykład &lt;span style="font-weight: bold;"&gt;Waldka Kota&lt;/span&gt; na temat wirtualizacji - ciekawy, ale chyba troszkę zbyt szczegółowy, oraz nieco stremowanego &lt;a style="font-weight: bold;" href="http://www.jaceklaskowski.pl/"&gt;Jacka Laskowskiego&lt;/a&gt; który przedstawił temat OpenEJB. Jacek podszedł do prelekcji chyba trochę zachowawczo, nie przedstawiając na początku żadnego przykładu "live". Wydaje się, że trochę zjadła go trema związana z wystąpieniem po angielsku. Obawy były niepotrzebne, bo językowo było dobrze - przydałby się jednak jakiś ciekawszy temat, w którym Jacek mógłby bardziej rozwinąć skrzydła ;)&lt;br /&gt;&lt;br /&gt;W pierwszym dniu uczestniczyłem jeszcze w świetnym wykładzie &lt;span style="font-weight: bold;"&gt;Vaclava Pecha&lt;/span&gt; "Practical Groovy" - sposób prowadzenia prezentacji, pokazane przykłady, kontakt z publicznością - wszystko na szóstkę. Vaclav pokazał jak bardzo Groovy ułatwia rozwiązanie niektórych problemów i jak łatwo zintegrować go z Javą.&lt;br /&gt;&lt;br /&gt;Drugi dzień zapamiętam głównie ze względu na dwa bardzo dobre wykłady &lt;span style="font-weight: bold;"&gt;Antonio Goncalves&lt;/span&gt;'a oraz świetny, prowadzony na wesoło wykład Bruno Bossoli. Antonio poproszony o zastępstwo jednego z prelegentów przedstawił serwer aplikacyjny GlassFish, a drugi (planowy) wykład poświęcił nowościom w JavaEE6.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bruno Bossola&lt;/span&gt;, członek Torino JUG, omawiał zasady projektowania oprogramowania w bardzo charyzmatyczny, okraszony sporą dawką humoru sposób. Co jakiś czas pojawiały się slajdy zawierające najzabawniejsze fragmenty komentarzy znalezionych w kodzie:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/9MAQJgzBvYz1r9Je59T0_w?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_0zhWBYvrXoE/Sgb86DK10WI/AAAAAAAAAHQ/TqB3hFAyeOE/s400/P08-05-09_14.50.JPG" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td face="arial,sans-serif" size="11px" style="text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/krzysztof.adamczyk/GeeCON?feat=embedwebsite"&gt;GeeCON&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/center&gt;Bardzo ważnymi elementami konferencji były "atrakcje dodatkowe", wśród których najciekawszą była Beer Certification Path, czyli rundka po krakowskich pubach w czwartkowy wieczór. W każdym z czterech pubów do odebrania było piwo od Sun'a :) oraz pieczątka - jedna z liter słowa JAVA:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/WqF4OAGnMCIYKsgoyl7KCA?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_0zhWBYvrXoE/Sgb-IozowDI/AAAAAAAAAII/qnHEs_kF6Uc/s400/beer.JPG" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td face="arial,sans-serif" size="11px" style="text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/krzysztof.adamczyk/GeeCON?feat=embedwebsite"&gt;GeeCON&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/center&gt;Świetny pomysł :D Przy okazji mamy kolejny argument wyższości Javy nad C# - Java ma więcej liter ;)&lt;br /&gt;&lt;br /&gt;Podsumowując - kilka ciekawych wykładów, piwko w Krakowie wieczorem - to sprawiło że konferencje ogólnie uważam za udaną. Na pewno blask sukcesu przyćmiły problemy techniczne na początku ze światłem, później z podłączeniem laptopów, szczególnie "makówek" do projektorów, ale wszyscy uczymy się na błędach i jestem pewien że GeeCON 2010 będzie jeszcze lepszy - a im więcej takich wydarzeń, tym lepiej dla nas :)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/2742845367728044529/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=2742845367728044529' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2742845367728044529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2742845367728044529'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/05/geecon-2009_10.html' title='GeeCON 2009'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_0zhWBYvrXoE/SgbwEOEawSI/AAAAAAAAAGk/5wV_kjaQVZk/s72-c/P07-05-09_09.46%5B01%5D.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-7477933634834213599</id><published>2009-04-17T15:46:00.027+03:00</published><updated>2009-05-11T09:20:56.011+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaFX'/><title type='text'>O co chodzi w JavaFX</title><content type='html'>Ostatnio mam okazję zapoznawać się z technologią JavaFX i chciałbym podzielić się z Wami moimi spostrzeżeniami na jej temat.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Statyczne typowanie&lt;/span&gt;&lt;br /&gt;JavaFX jest językiem statycznie (silnie) typowanym, z rozwiniętym mechanizmem Type Inference, czyli - z angielskiego na nasze - "zgadywaniem typów". Jest to o tyle fajne, że oszczędzamy trochę pisania podczas deklaracji zmiennej, ponieważ zapis (poprawny)&lt;br /&gt;&lt;pre name="code" class="java"&gt;var napis : String = "Hello World!"&lt;/pre&gt;możemy zastąpić równie poprawnym zapisem&lt;br /&gt;&lt;pre name="code" class="java"&gt;var napis = "Hello World!"&lt;/pre&gt;i kompilator od tego momentu już wie (zgaduje), że napis jest Stringiem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bindowanie&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;na poziomie języka&lt;/span&gt;&lt;br /&gt;Na uwagę zasługuje &lt;span&gt;mechanizm bindowania&lt;/span&gt; wprowadzony &lt;span&gt;na poziomie języka&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;. &lt;/span&gt;Jest to bardzo ciekawe i w wielu miejscach użyteczne. Np zapis:&lt;br /&gt;&lt;pre name="code" class="java"&gt;var currentTextBoxValue = "";&lt;br /&gt;....&lt;br /&gt;TextBox {&lt;br /&gt;   value: bind currentTextBoxValue with inverse&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;oznacza, że ilekroć użytkownik wpisze coś w pole tekstowe (TextBox), zawartość tego pola zostanie automatycznie przepisana do zmiennej &lt;span style="font-style: italic;"&gt;currentTextBoxValue&lt;/span&gt;, oraz ilekroć zmieniona zostanie wartość zmiennej &lt;span style="font-style: italic;"&gt;currentTextBoxValue&lt;/span&gt;, zaktualizowana zostanie zawartość pola tekstowego. Mechanizm ten oszczędza czasem pisania wielu listenerów, choć wydaje mi się, że źle użyty, może być również źródłem konsternacji kiedy zmienne zaczną "magicznie" zmieniać swoje wartości ;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Domknięcia (closures)&lt;/span&gt;&lt;br /&gt;Temat znany miłośnikom Javy chociażby z dyskusji czy wprowadzić ten mechanizm w kolejnej wersji czy nie :) W JavaFX dostępny:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;var x = 1;&lt;br /&gt;SwingButton {&lt;br /&gt;   action: function (): Void {&lt;br /&gt;     x++;&lt;br /&gt;   }&lt;br /&gt;   text: "Increment"&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Koncepcyjnie polega to na przekazaniu funkcji (domknięcia, ang. closure) jako parametru "gdzieś dalej", przy czym kiedy odbiorca tej funkcji postanowi ją wykonać, jej wykonanie nastąpi w kontekście, w którym funkcja została utworzona. Również bardzo wygodne rozwiązanie pozwalające szybko uzyskać porządane efekty.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Modyfikatory dostępu&lt;/span&gt;&lt;br /&gt;Twórcy JavaFX postanowili chyba odwieść programistów od stosowania jakże nam bliskich &lt;span style="font-style: italic;"&gt;getterów &lt;/span&gt;i &lt;span style="font-style: italic;"&gt;setterów&lt;/span&gt;, udostępniając kilka nowych modyfikatorów dostępu do pól np:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;public-init&lt;/span&gt; - pozwala na modyfikację pola wyłącznie w trakcie tworzenia obiektu&lt;br /&gt;public-read - pozwala na dostęp tylko do odczytu z zewnątrz&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Brak konstruktorów, bloki init i postinit&lt;/span&gt;&lt;br /&gt;Tak tak - w JavaFX zabrakło miejsca dla konstruktorów. Obiekty tworzymy używając specjalnego wyrażenia postaci:&lt;br /&gt;&lt;pre name="code" class="java"&gt;var circle = Circle {&lt;br /&gt;      fill: null&lt;br /&gt;      stroke: Color.BLACK&lt;br /&gt;      strokeWidth: 3&lt;br /&gt;      centerX: 22,&lt;br /&gt;      centerY: 33,&lt;br /&gt;      radius: 44&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;W obrębie nawiasów klamrowych ustawiamy wartości pól klasy, przy czym nie panuje tutaj kompletna dowolność, ponieważ ograniczają nas modyfikatory dostępu tych pól.&lt;br /&gt;&lt;br /&gt;Aby zagwarantować integralność obiektu możemy wewnątrz klasy stworzyć blok &lt;span style="font-style: italic;"&gt;postinit&lt;/span&gt;, który będzie wykonany tuż po stworzeniu obiektu i ustawieniu wartości pól:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;postinit {&lt;br /&gt;  if( model == null) {&lt;br /&gt;      throw new IllegalStateException("Model cannot be null!");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Integracja z Javą&lt;/span&gt;&lt;br /&gt;Bardzo ważna informacja - z poziomu JavaFx można korzystać z klas Javowych (widać to chociażby w przykładzie powyżej, kiedy rzucam stary dobry IllegalStateException). Ograniczenie dotyczy bindowania - nie można bindować do pól klas napisanych w Javie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Dostępność gotowych rozwiązań&lt;/span&gt;&lt;br /&gt;I tu jest moim zdaniem póki co krucho. Oczekiwałem np. dużo bogatszego zbioru widgetów. Gdy potrzebowałem DatePickera, zmuszony zostałem do wzięcia komponentu kalendarza z &lt;a href="http://javafx.com/samples/Calendar/index.html"&gt;przykładów Suna&lt;/a&gt; i trochę go przerabiając stworzyć własną kontrolkę zawierającą pole tekstowe i przycisk wyświetlający kalendarz. Dobrze rokuje na przyszłość biblioteka &lt;a href="http://code.google.com/p/jfxtras/"&gt;JFXtras&lt;/a&gt;, ale jak na razie to i tak trochę za mało.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wsparcie ze strony IDE&lt;/span&gt;&lt;br /&gt;Od razu powiem że moim ulubionym środowiskiem jest Eclipse. Niestety - na obecnym etapie aby walka z JavaFX miała jakikolwiek sens, musiałem przesiąść się (tymczasowo! zaraz wracam!) na Netbeans 6.5. Nie chcę urazić fanów NB, więc nie będę się rozpisywał na temat oczywistych różnic tych środowisk, które z oczywistych powodów (oczywista oczywistość) utrudniały mi pracę ;) Netbeansowy plugin do JavaFX również nie jest pozbawiony błędów, a te najbardziej dokuczliwe dotyczą podpowiadania, organizacji importów i formatowania kodu. Nie działa również refaktoring (o zgrozo), oraz różne sposoby nawigacji w kodzie (np. call hierarchy, które akurat często używam).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Przyszłość&lt;/span&gt;&lt;br /&gt;JavaFX jest wciąż nową technologią, wymagającą okrzepnięcia, ustabilizowania się i mocnego wsparcia ze strony &lt;span style="font-style: italic;"&gt;community&lt;/span&gt;. Również Sun powinien położyć duży nacisk na stworzenie gotowych bibliotek komponentów, efektów itp. "gadżetów" które umożliwiałyby łatwiejsze rozpoczęcie tworzenia złożonych, dobrze wyglądających aplikacji internetowych.&lt;br /&gt;JavaFX wciąż mocno się zmienia - widać to chociażby po przykładach znajdowanych w sieci, z których część po prostu już nie działa, z powodu zmian API. Idea jest jednak bez wątpienia ciekawa i obiecująca, dlatego trzymam kciuki za tą technologię :)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/7477933634834213599/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=7477933634834213599' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/7477933634834213599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/7477933634834213599'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/04/o-co-chodzi-w-javafx.html' title='O co chodzi w JavaFX'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5636424069920173631</id><published>2009-03-11T10:42:00.028+02:00</published><updated>2009-04-14T00:43:40.792+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='konferencja'/><category scheme='http://www.blogger.com/atom/ns#' term='4developers'/><title type='text'>4Developers - wrażenia</title><content type='html'>Ostatnio miałem przyjemność uczestniczyć w konferencji &lt;a href="http://4developers.org.pl/"&gt;4Developers&lt;/a&gt;, która bardzo pozytywnie mnie zaskoczyła pod względem merytorycznym. Cztery równoległe ścieżki sprawiły że naprawdę było w czym wybierać.&lt;br /&gt;&lt;br /&gt;Na pierwszy ogień &lt;a href="http://www.adam-bien.com/roller/abien/"&gt;&lt;span&gt;Adam Bien&lt;/span&gt;&lt;/a&gt; z wykładem zatytułowanym &lt;span style="font-style: italic;"&gt;EJB 3.1 - Killing The Top Eleven Myths, Tales and Biases&lt;/span&gt;. Przez dość długi czas pracowałem w technologii EJB3, dlatego przyszedłem na ten wykład ze sporymi oczekiwaniami i - muszę przyznać - nie zawiodłem się. Adam poprowadził rzeczowy, przekonywujący wykład i ani przez moment nie przynudzał :) Tempo w sam raz, a i elementy humorystyczne się zdarzały. Celem Adama była walka z mitami, które mówią że EJB3.x są "ciężkie", trudne do testowania, implementacji etc. Adam położył duży nacisk na nadchodzące EJB3.1, gdzie będzie można np. "ręcznie" (w kodzie) wystartować kontener EJB (już teraz możliwe z OpenEJB, ale wejdzie do standardu). Ujednoliceniu ulegną też JNDI-names komponentów, co przyczyni się do osiągnięcia prawdziwej przenośności aplikacji pomiędzy serwerami aplikacyjnymi.&lt;br /&gt;&lt;br /&gt;Jako drugi w sekcji Javy wystąpił &lt;a href="http://www.nealford.com/"&gt;Neal Ford&lt;/a&gt; z wykładem zatytułowanym &lt;em&gt;The Productive Programmer: Mechanics.&lt;/em&gt; W tym przypadku również bez rozczarowań - Neal przedstawił ciekawy temat optymalizacji pracy developera, prezentując różne narzędzia wspomagające. Pokazał, że usprawniając najprostsze czynności, jak kopiowanie do schowka czy nawigowanie w drzewie katalogów, możemy zyskać naprawdę dużo czasu. Neal duży nacisk położył na konieczność dobrego poznania swojego IDE, a szczególnie jego obsługi za pomocą samej klawiatury.&lt;br /&gt;&lt;br /&gt;Jako trzeci na ścieżce Javowej wystąpił &lt;span style="font-weight: bold;"&gt;Cornel Creanga&lt;/span&gt; prezentując możliwości Flexa w połączeniu z Javą. Niestety ten wykład nie zachwycił treścią, ani stylem prezentacji, choć byćmoże moja opinia jest po części spowodowana tym, że ten temat nieco mniej mnie interesuje. Prezentacja sprowadzała się do przeklikania aplikacji demonstracyjnej korzystającej z możliwości Flexa. Dość nieprzyjemną niespodzianką był jakiś element (chyba głośnik) który spadł z sufitu i zawisł na kablach nad głową jednego z uczestników wykładu - niewiele brakowało...&lt;br /&gt;&lt;br /&gt;Następnie przeniosłem się do sali, w której odbywały się  wykłady ze ścieżki Zarządzania projektami, aby posłuchać &lt;span style="font-weight: bold;"&gt;Adama Krosnego&lt;/span&gt; z firmy &lt;a href="http://www.alan-systems.com/"&gt;&lt;span style="font-weight: bold;"&gt;Alan Systems&lt;/span&gt;&lt;/a&gt;. Adam poprowadził bardzo ciekawy, obszerny wykład na temat praktyki wprowadzania metodologi SCRUM. Opisał proces wdrażania tej metodologii z punktu widzenia praktyka, przedstawiając również teoretyczne podstawy. Także w "kuluarach" słyszałem wiele pozytywnych opini na temat tej prelekcji (m.in. ktoś powiedział, że był to najbardziej merytoryczny wykład ze wszystkich wykładów sponsorowanych).&lt;span style="font-style: italic;"&gt; &lt;/span&gt;&lt;span&gt;Temat przedstawiony przez Adama spotkał się z dużym zainteresowaniem wypełnionej chyba w 100% sali - wiele osób zadawało pytania, przez co wykład nieco się przedłużył, ale było warto :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Marcin Żuchowicz&lt;/span&gt; z &lt;span style="font-weight: bold;"&gt;e-point&lt;/span&gt; przedstawił problem prowadzenia dużych projektów informatycznych z praktycznego punktu widzenia. Wykład ciekawy, momentami zabawny (np. opis projektu Ajax z kilkoma pokojami wypełnionymi dokumentacją ;) ) Główny wniosek do którego zmierzał prelegent to konieczność mocnego zaangażowania managera po stronie klienta i jego umiejętność przekonania swoich mocodawców, że czasami warto zmienić wymagania w imię dobra projektu.&lt;br /&gt;&lt;br /&gt;Następnie wybrałem się na wykład &lt;span style="font-weight: bold;"&gt;Teda Neward&lt;/span&gt;'a, który opowiadał o Scali. Ted, podobnie jak Neal Ford (obaj z ThoughtWorks) to konferencyjny "wyjadacz", tym razem również nie zawiódł. Przedstawił w skrócie podstawy Scali jako języka samodzielnego, jak również możliwego do wykorzystania z poziomu Javy. Niejednokrotnie podkreślał zalety kompilatora Scali w porównaniu z &lt;span style="font-style: italic;"&gt;javac&lt;/span&gt; - np. w kwestii wymagalności średnika na końcu wyrażenia (Scala tego nie wymaga), czy konieczności określania typu zmiennej przy deklaracji (po lewej stronie).&lt;br /&gt;&lt;br /&gt;Jako ostatni wystąpił &lt;a href="http://jaceklaskowski.pl/"&gt;Jacek Laskowski&lt;/a&gt;  który rozbudził zmęczoną już nieco publiczność. Jacek mówił o Groovy i Grails i choć - jak to czasami bywa na prezentacjach- nie wszystko zadziałało, dowiedziałem się przynajmniej teoretycznie czegoś więcej na temat tych mechanizmów. Pomimo późnej pory Jackowi udało się zaangażować widownię w swój wykład i nawet drobne wpadki związane z działaniem przykładów zostały nagrodzone brawami ;) &lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Po&lt;/span&gt;&lt;span&gt;ziom merytoryczny konferencji był moim zdaniem wysoki. Powiedziałbym nawet że było lepiej niż na dwóch poprzednich JDD. Jedyne czego zabrakło to lunch i parking. Przerwa na lunch w której wszyscy wybiegają na miasto, a tam we wszystkich najbliższych restauracjach hordy developerów -  to nie jest dobry pomysł ;) &lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;em&gt;&lt;/em&gt;</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5636424069920173631/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5636424069920173631' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5636424069920173631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5636424069920173631'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/03/4developers-wrazenia.html' title='4Developers - wrażenia'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-2196493241219355771</id><published>2009-01-07T09:27:00.009+02:00</published><updated>2009-01-07T10:03:38.885+02:00</updated><title type='text'>Spring + Hibernate - migracja z XML do adnotacji</title><content type='html'>Duuużo czasu minęło od mojego ostatniego posta :( Powód prozaiczny - miałem wolne :) Plany na grudzień były ogromne - rozwój bloga, dopieszczanie frameworku nad którym pracuję itp. itd... Jak widzicie w grudniu nie pojawił się ani jeden post, więc te chwalebne plany legły w gruzach. Udało mi się jednak załatwić parę innych pożytecznych rzeczy. Okazuje się że więcej czasu można wygospodarować prowadząc regularny tryb życia (praca itp.). Mam nadzieję że teraz uda mi się napisać częściej o moich zmaganiach z Javą ;)&lt;br /&gt;&lt;br /&gt;Do rzeczy więc - dzisiaj modyfikujemy projekt napisany z użyciem Springa i Hibernate'a. Modyfikacja polegać będzie na stopniowym wycofywaniu plików .hbm i wprowadzaniu w ich miejsce adnotacji. Nie będę opisywał samego sposobu adnotowania encji, ponieważ uznaję że w tym nie ma nic szczególnie trudnego (no może za wyjątkiem jakichś specyficznych elementów XML'owego opisu mapowania). To co chcę opisać to kroki konfiguracyjne które pozwolą na działanie adnotacji w projekcie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Krok 1 - dodanie wymaganych bibliotek&lt;/span&gt;&lt;br /&gt;Do projektu należy dodać następujące plik JAR:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;    - hibernate-annotations.jar&lt;/li&gt;&lt;li&gt;    - hibernate-commons-annotations.jar&lt;/li&gt;&lt;li&gt;    - slf4j-api-1.5.6jar&lt;/li&gt;&lt;li&gt;    - slf4j-log4j12-1.5.6.jar&lt;/li&gt;&lt;li&gt;    - ejb3-persistence.jar&lt;/li&gt;&lt;/ul&gt;Ważne aby oba JARy slf4j były w tej samej wersji - w przeciwnym wypadku możemy spodziewać się ciekawych błędów :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Krok 2 - modyfikacje w kontekście Springa&lt;/span&gt;&lt;br /&gt;1) Zmieniamy klasę sessionFactory&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="sessionFactory"&lt;br /&gt;class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&amp;gt;&lt;/pre&gt;&lt;br /&gt;na&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="sessionFactory"&lt;br /&gt;class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2) Dodajemy następujący wpis:&lt;br /&gt;&lt;pre&gt;&amp;lt;property name="configurationClass"&amp;gt;&lt;br /&gt;    &amp;lt;value&amp;gt;org.hibernate.cfg.AnnotationConfiguration&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3) Listujemy klasy opisane za pomocą adnotacji:&lt;br /&gt;&lt;pre&gt;&amp;lt;property name="annotatedClasses"&amp;gt;&lt;br /&gt;   &amp;lt;list&amp;gt;&lt;br /&gt;       &amp;lt;value&amp;gt;pl.kadamczyk.model.User&amp;lt;/value&amp;gt;&lt;br /&gt;   &amp;lt;/list&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Co ważne część klas w projekcie może być opisana adnotacjami, a pozostała część XMLem, ponieważ obok właściwości &lt;span style="font-style: italic;"&gt;annotatedClasses&lt;/span&gt; może występować także właściwość np. &lt;span style="font-style: italic;"&gt;mappingDirectoryLocations&lt;/span&gt; pozwalająca wskazać katalog zawierający pliki .hbm</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/2196493241219355771/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=2196493241219355771' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2196493241219355771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2196493241219355771'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2009/01/spring-hibernate-migracja-z-xml-do.html' title='Spring + Hibernate - migracja z XML do adnotacji'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-8275075954042112477</id><published>2008-11-20T15:26:00.000+02:00</published><updated>2008-11-21T13:50:33.841+02:00</updated><title type='text'>NetBeans Platform - wrażenia po 2. spotkaniu Silesia JUG</title><content type='html'>Za nami drugie spotkanie &lt;a href="http://groups.google.com/group/silesia-jug"&gt;Silesia JUG&lt;/a&gt;, którego tematem była Platforma NetBeans. &lt;a href="http://marekklis.blogspot.com/"&gt;Marek Kliś&lt;/a&gt; przez ponad 1,5 godziny prezentował możliwości tej platformy korzystając z nowiutkiego NetBeans 6.5, który (zapewne z racji swej nowości) miewał czasami dość długie momenty zawahania. Widownia tym razem była o wiele mniejsza niż na pierwszym spotkaniu, co moim zdaniem w dużej mierze spowodowane jest tematem spotkania - Eclipse wciąż ma się dobrze i to z niego korzysta zdecydowana większość developerów. Sam przyznam, że NetBeansa odpaliłem dosłownie kilka razy w życiu i to wyłącznie z chęci poeksperymentowania. Na prezentację wybrałem się aby dowiedzieć się czegoś na temat możliwości platformy NB i jej wykorzystania do tworzenia aplikacji desktopowych. Nie ukrywam, że moje podejście było na początku sceptyczne choć oczywiście miałem nadzieję, że Marek pokaże coś rewolucyjnego. Jako że od dawna tworzę aplikacje oparte o Eclipse RCP, chciałem porównać obie platformy/frameworki/szkielety..... etc.&lt;br /&gt;&lt;br /&gt;Trzeba przyznać, że wizualnie wygląda to ładnie, choć mi osobiście bardziej podoba się UI aplikacji zbudowanych na Eclipse. Podstawową aplikację (bez funkcjonalności) da się stworzyć wpisując &lt;span style="font-style: italic;"&gt;zero&lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; &lt;/span&gt;linii kodu ;) Dalej już bez znajomości API ani rusz, ale to zrozumiałe.&lt;br /&gt;&lt;br /&gt;Marek starał się jak najlepiej przekazać temat i - biorąc pod uwagę obszerność zagadnienia i dość ograniczony czas - jego starania oceniam dobrze :) Nie obeszło się jednak w kilku momentach bez zbytniego wchodzenia w szczegóły, ale to chyba problem większości prelegentów. (Zobaczymy co będzie jak kiedyś mi przyjdzie stanąć przed publicznością ;) )&lt;br /&gt;&lt;br /&gt;Netbeans Platform jest opcją do rozważenia jeśli jednym z wymagań jest to, aby aplikacja była oparta o Swing. W tym środowisku jego konkurentami są chyba tylko SpringRCP i Swing Application Framework, a spośród nich NB wydaje mi się opcją najdojrzalszą i dającą na dzień dzisiejszy największe możliwości. Jeżeli mamy dowolność Swing/SWT- ja zdecydowanie wybiorę Eclipse RCP, ale nie jestem w tym temacie obiektywny :) Niestety zbyt mało wiem na temat NB aby dokładniej porównać obie platformy. To co udało mi się zaobserwować podczas prezentacji to dość powolny start tworzonej aplikacji (ale Eclipse czasem też daje w kość).&lt;br /&gt;&lt;br /&gt;Obie platformy już od dłuższego czasu rozwijają się dynamicznie. Bardzo dobrze że istnieje swoista konkurencja pomiędzy tymi produktami zarówno w sferze IDE jak i platformy tworzenia oprogramowania, ponieważ na takiej rywalizacji wszyscy zyskują, a najbardziej my - deweloperzy, otrzymując coraz ciekawsze narzędzia i rozwiązania.</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/8275075954042112477/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=8275075954042112477' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/8275075954042112477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/8275075954042112477'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/netbeans-platform-wraenia-po-2_20.html' title='NetBeans Platform - wrażenia po 2. spotkaniu Silesia JUG'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-3695837542957736124</id><published>2008-11-18T13:37:00.000+02:00</published><updated>2008-11-18T23:36:05.799+02:00</updated><title type='text'>Wstrzykiwanie zależności w aplikacji webowej</title><content type='html'>Znasz to uczucie, gdy robisz coś po raz N-ty i za każdym razem działało a teraz za nic w świecie nie chce? No właśnie... Potrzebowałem do wykonania pewnego testu stworzyć malutki projekt EJB3 a w nim jeden SLSB. Obok tego stworzyłem projekt aplikacji webowej (Dynamic Web Project), w środku jedna klasa implementująca ServletContextListener, która będzie notyfikować wstrzykniętego beana podczas deployu EAR'a tudzież startu serwera aplikacyjnego:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class MyStartupListener implements ServletContextListener {&lt;br /&gt;&lt;br /&gt;   @EJB&lt;br /&gt;   private LifecycleMonitorRemote lifeCycleMonitor&lt;br /&gt;&lt;br /&gt;   public void contextDestroyed(final ServletContextEvent arg0) {&lt;br /&gt;       lifeCycleMonitor.shutdown();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void contextInitialized(final ServletContextEvent arg0) {&lt;br /&gt;       lifeCycleMonitor.startup();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Dodałem odpowiednie wpisy do web.xml:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&amp;gt;&lt;br /&gt; &amp;lt;display-name&amp;gt;test.startup.web&amp;lt;/display-name&amp;gt;&lt;br /&gt; &amp;lt;welcome-file-list&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.html&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.htm&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.jsp&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.html&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.htm&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.jsp&amp;lt;/welcome-file&amp;gt;&lt;br /&gt; &amp;lt;/welcome-file-list&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;listener&amp;gt;&lt;br /&gt;   &amp;lt;listener-class&amp;gt;listeners.MyStartupListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;&amp;lt;/listener&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;   &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;   &amp;lt;display-name&amp;gt;MyStartupListener&amp;lt;/display-name&amp;gt;&lt;br /&gt;   &amp;lt;servlet-name&amp;gt;MyStartupListener&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;   &amp;lt;servlet-class&amp;gt;listeners.MyStartupListener&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;   &amp;lt;servlet-name&amp;gt;MyStartupListener&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;   &amp;lt;url-pattern&amp;gt;/MyStartupListener&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;br /&gt;&lt;/pre&gt;Ruszamy... I co? I NullPointerException w linii&lt;br /&gt;&lt;pre name="code" class="java"&gt; lifeCycleMonitor.startup();&lt;/pre&gt;Znaczy &lt;span style="font-weight: bold;"&gt;dependency injection&lt;/span&gt; jakby nie zadziałało... Ale zawsze działało...&lt;br /&gt;Kilkukrotne przejrzenie całego kodu i nic (!) W takich sytuacjach zwykle pomaga Google - wskazówkę znalazłem na &lt;a href="http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&amp;amp;f=11&amp;amp;t=015438"&gt;JavaRanch&lt;/a&gt;, a błąd okazał się bardziej prozaiczny niż przypuszczałem. Jak widać powyższy plik web.xml odnosi się do specyfikacji Java Servlet w wersji 2.4, podczas gdy dependency injection działa w servletach od wersji 2.5. Po poprawce ten fragment web.xml wygląda tak:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"&lt;br /&gt;xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&lt;br /&gt;xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&lt;br /&gt;id="WebApp_ID" version="2.5"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Uff...</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/3695837542957736124/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=3695837542957736124' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/3695837542957736124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/3695837542957736124'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/wstrzykiwanie-zalenoci-w-aplikacji.html' title='Wstrzykiwanie zależności w aplikacji webowej'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-2219090556148781166</id><published>2008-11-14T18:32:00.000+02:00</published><updated>2008-11-17T16:08:34.444+02:00</updated><title type='text'>Tworzymy plugin do Eclipse - Hello World</title><content type='html'>Jak pewnie większość z Was wie, Eclipse nie jest tylko środowiskiem programistycznym (IDE), ale również - a może przede wszystkim - platformą tworzenia oprogramowania, na której "przy okazji" powstało świetne IDE. U podstaw tego wszystkiego leży OSGi, o które będziemy się ocierać tworząc aplikacje na platformie Eclipse. Chociażby podstawowy byt w rozumieniu środowiska Eclipse - plugin - jest w istocie pakunkiem (bundle) OSGi.&lt;br /&gt;&lt;br /&gt;Postanowiłem przybliżyć trochę tematykę tworzenia aplikacji na bazie Eclipse, a dzisiejszy artykuł, jak nakazuje tradycja, przedstawia podstawowe &lt;span style="font-style: italic;"&gt;Hello World&lt;/span&gt; w świecie Eclipse Platform.&lt;br /&gt;&lt;br /&gt;Do stworzenia najprostszego projektu nie potrzeba wiele - wystarczy Eclipse z zainstalowanym PDE (Plugin Development Environment). Ja skorzystam z wersji  3.3 na której akurat mam dograne PDE.&lt;br /&gt;&lt;br /&gt;Zanim zaczniemy, potrzebny jest krótki wstęp teoretyczny. Jednym z podstawowych pojęć platformy Eclipse jest punkt rozszerzeń (Extension point). Za pomocą punktów rozszerzeń nasze pluginy mogą wzbogacać w funkcje już istniejące pluginy (w tym te rdzennie Eclipsowe), a zarazem pozwalać innym pluginom rozszerzać swoją funkcjonalność. Przykładowo Eclipse udostępnia Extension point za pomocą którego możemy dodać kolejne menu do menu górnego (co za chwilkę pokażę).&lt;br /&gt;&lt;br /&gt;Z drugiej strony wyobraźmy sobie aplikację, która służy np. konwersji bitmapy na różne formaty graficzne. Otwieramy plik BMP i w okienku widzimy combo box z dostępnymi docelowymi formatami graficznymi. Z platformą Eclipse projekt takiej aplikacji może zyskać na modularności i rozszerzalności, jeśli każdy konwerter wykonamy jako rozszerzenie (extension) udostepnionego przez siebie punktu rozszerzeń (Extension point'a). Platforma umożliwia pobranie wszystkich rozszerzeń, które "wpinają się" w dany punkt, więc bardzo prosto stworzyć listę dostępnych docelowych formatów konwersji. Jeśli postanowimy dopisać konwerter do nowego formatu pliku, wystarczy zadeklarować (poprzez XML), że on również wpina się w dany punkt rozszerzeń i bez modyfikacji istniejącego kodu stanie się on dostępny w aplikacji.&lt;br /&gt;&lt;br /&gt;Punkt rozszerzeń ma nazwę (np. pl.kadamczyk.bmpconverter) oraz definicję w postaci schematu XSD. W tworzenie punktów rozszerzeń nie będziemy narazie wchodzić, ale mam nadzieję że uda mi się napisać o tym w przyszłości. Najważniejsze na teraz, aby zapamiętać że punkt rozszerzeń jest miejscem styku w którym moduły mogą dostarczać swoją funkcjonalność innym modułom.&lt;br /&gt;&lt;br /&gt;Ok, po tym przydługawym wstępie stwórzmy wreszcie pierwszy, bardzo prosty projekt:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR2r0H2VZaI/AAAAAAAAADE/xGmabAp44Ac/s1600-h/nowy+plugin+projekt.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 305px;" src="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR2r0H2VZaI/AAAAAAAAADE/xGmabAp44Ac/s320/nowy+plugin+projekt.jpg" alt="" id="BLOGGER_PHOTO_ID_5268556051041838498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Określamy nazwę projektu, nie zmieniając pozostałych opcji:&lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0zhWBYvrXoE/SR24eWD70aI/AAAAAAAAADU/QwLXsQQLeSw/s1600-h/nowy+plugin+projekt2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 318px;" src="http://4.bp.blogspot.com/_0zhWBYvrXoE/SR24eWD70aI/AAAAAAAAADU/QwLXsQQLeSw/s320/nowy+plugin+projekt2.jpg" alt="" id="BLOGGER_PHOTO_ID_5268569970551017890" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;img src="file:///C:/Users/Krzysiek/AppData/Local/Temp/moz-screenshot.jpg" alt="" /&gt;Na kolejnych ekranach nie zmieniamy żadnych opcji i kończymy kreatora, który po zakończeniu swojej pracy otwiera graficzny edytor pliku plugin.xml.&lt;br /&gt;&lt;br /&gt;Będziemy chcieli do naszego Eclipse'a dodać nowe menu, a w nim opcję, po wybraniu której wyświetli się okno informacyjne.&lt;br /&gt;&lt;br /&gt;W tym celu otwieramy zakładkę &lt;span style="font-weight: bold;"&gt;Extensions&lt;/span&gt;. Na tej zakładce definiujemy w jaki sposób nasz plugin ma rozszerzać "otoczenie" (czyli pluginy tworzące Eclipse w tym przypadku). Chcemy dodać element do górnego menu Eclipse'a, a do tego służy punkt rozszerzeń &lt;span style="font-weight: bold;"&gt;org.eclipse.ui.actionSets&lt;/span&gt;. Na zakładce Extensions wybieramy Add, i w dostępne pole tekstowe &lt;span style="font-style: italic;"&gt;Extension point filter&lt;/span&gt; wpisujemy &lt;span style="font-weight: bold;"&gt;org.eclipse.ui.actionSets. &lt;/span&gt;Zamykamy okno, co powoduje dodanie rozszerzenia. Teraz należy to rozszerzenie skonfigurować.&lt;br /&gt;Extension point &lt;span style="font-style: italic;"&gt;actionSets&lt;/span&gt; zawiera już jeden element który konfigurujemy jak na rysunku:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR25mHGZfWI/AAAAAAAAADc/L8W4iD07qic/s1600-h/nowy+plugin+projekt2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 112px;" src="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR25mHGZfWI/AAAAAAAAADc/L8W4iD07qic/s320/nowy+plugin+projekt2.jpg" alt="" id="BLOGGER_PHOTO_ID_5268571203485400418" border="0" /&gt;&lt;/a&gt;Następnie dodajmy menu do skonfigurowanego właśnie Action Seta. Klikamy prawym przyciskiem na "Pierwszy action set", wybieramy New-&gt;Menu.&lt;br /&gt;Jako label wpisujemy np. "Menu Hello World" - to będzie widoczne w pasku menu Eclipse po uruchomieniu. Zostawmy wygenerowane automatycznie ID (PluginHelloWorld.menu1)&lt;br /&gt;Następnie analogicznie do menu dodajemy separator, nie zmieniając mu właściwości (wygenerowany ID: "PluginHelloWorld.separator1").&lt;br /&gt;Na końcu tym samym sposobem do action seta dodajemy akcję (action) i konfigurujemy ją jak na rysunku:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_0zhWBYvrXoE/SR271l445JI/AAAAAAAAADk/FZEmyAi7wv4/s1600-h/nowy+plugin+projekt2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 177px;" src="http://2.bp.blogspot.com/_0zhWBYvrXoE/SR271l445JI/AAAAAAAAADk/FZEmyAi7wv4/s320/nowy+plugin+projekt2.jpg" alt="" id="BLOGGER_PHOTO_ID_5268573668471530642" border="0" /&gt;&lt;/a&gt;Pozostało jeszcze zdefiniowanie najważniejszego, czyli tego, co akcja ma robić. Edytor umożliwia wprowadzenie nazwy klasy która jest odpowiedzialna za działanie akcji jako parametr &lt;span style="font-weight: bold; font-style: italic;"&gt;class&lt;/span&gt; w dolnej części rysunku. Można również kliknąć na link &lt;span style="font-weight: bold;"&gt;class&lt;/span&gt; co spowoduje uruchomienie mini-kreatora. Wystarczy wybrać pakiet i wpisać nazwę klasy, a kreator sam "zmajstruje" klasę z odpowiednimi metodami, które my musimy "tylko" wypełnić:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR28ujr_pWI/AAAAAAAAADs/0qMQcmYAjls/s1600-h/nowy+plugin+projekt2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 275px; height: 320px;" src="http://1.bp.blogspot.com/_0zhWBYvrXoE/SR28ujr_pWI/AAAAAAAAADs/0qMQcmYAjls/s320/nowy+plugin+projekt2.jpg" alt="" id="BLOGGER_PHOTO_ID_5268574647133119842" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Definiujemy klasę akcji jak poniżej:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package sampleeclipseplugin;&lt;br /&gt;&lt;br /&gt;import org.eclipse.jface.action.IAction;&lt;br /&gt;import org.eclipse.jface.dialogs.MessageDialog;&lt;br /&gt;import org.eclipse.jface.viewers.ISelection;&lt;br /&gt;import org.eclipse.ui.IWorkbenchWindow;&lt;br /&gt;import org.eclipse.ui.IWorkbenchWindowActionDelegate;&lt;br /&gt;&lt;br /&gt;public class SayHelloAction implements IWorkbenchWindowActionDelegate {&lt;br /&gt;&lt;br /&gt;  private IWorkbenchWindow window;&lt;br /&gt;&lt;br /&gt;  public void dispose() {&lt;br /&gt;      // empty&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void init(final IWorkbenchWindow window) {&lt;br /&gt;      this.window = window;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void run(final IAction action) {&lt;br /&gt;      MessageDialog.openInformation(window.getShell(), "Hello!",&lt;br /&gt;              "Jestem pierwszym pluginem do Eclipse'a");&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void selectionChanged(final IAction action,&lt;br /&gt;          final ISelection selection) {&lt;br /&gt;      // empty&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;W tym momencie plik plugin.xml wygląda tak:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;?eclipse version="3.2"?&amp;gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;extension&lt;br /&gt;     id="myActionSet"&lt;br /&gt;     point="org.eclipse.ui.actionSets"&amp;gt;&lt;br /&gt;  &amp;lt;actionSet&lt;br /&gt;        id="PluginHelloWorld.actionSet1"&lt;br /&gt;        label="Mój prosty plugin"&lt;br /&gt;        visible="true"&amp;gt;&lt;br /&gt;     &amp;lt;menu&lt;br /&gt;           id="PluginHelloWorld.menu1"&lt;br /&gt;           label="Moje proste menu"&amp;gt;&lt;br /&gt;        &amp;lt;separator&lt;br /&gt;              name="PluginHelloWorld.separator1"&amp;gt;&lt;br /&gt;        &amp;lt;/separator&amp;gt;&lt;br /&gt;     &amp;lt;/menu&amp;gt;&lt;br /&gt;     &amp;lt;action&lt;br /&gt;           class="sampleeclipseplugin.SayHelloAction"&lt;br /&gt;           id="PluginHelloWorld.action1"&lt;br /&gt;           label="Przedstaw siê"&lt;br /&gt;           menubarPath="PluginHelloWorld.menu1/PluginHelloWorld.separator1"&amp;gt;&lt;br /&gt;     &amp;lt;/action&amp;gt;&lt;br /&gt;  &amp;lt;/actionSet&amp;gt;&lt;br /&gt;&amp;lt;/extension&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;Aby uruchomić plugin przenosimy się na pierwszą zakładkę edytora pliku plugin.xml, a tam w sekcji Testing wybieramy &lt;span style="font-weight: bold;"&gt;Launch an Eclipse application&lt;/span&gt;. Uruchomiona zostaje nowa instancja Eclipse'a z dołączonym naszym pluginem. W górnym menu jest już widoczne zdefiniowane przez nas rozszerzenie (nowa pozycja menu).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_0zhWBYvrXoE/SSBXwCcsZyI/AAAAAAAAAD0/5w9y5rC5nk8/s1600-h/res1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 148px;" src="http://3.bp.blogspot.com/_0zhWBYvrXoE/SSBXwCcsZyI/AAAAAAAAAD0/5w9y5rC5nk8/s320/res1.jpg" alt="" id="BLOGGER_PHOTO_ID_5269308046826039074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tym sposobem ukończyliśmy pierwszy, najprostszy plugin do Eclipse - może nie dysponuje on zaawansowanymi "ficzerami", ale jest to pierwszy krok do stworzenia czegoś ciekawszego. Postaram się w jednym z kolejnych postów rozszerzyć funkcjonalność pluginu i - kto wie - może przy okazji uda się stworzyć coś pożytecznego ;)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/2219090556148781166/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=2219090556148781166' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2219090556148781166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/2219090556148781166'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/tworzymy-plugin-do-eclipse-hello-world.html' title='Tworzymy plugin do Eclipse - Hello World'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_0zhWBYvrXoE/SR2r0H2VZaI/AAAAAAAAADE/xGmabAp44Ac/s72-c/nowy+plugin+projekt.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5526340079447277172</id><published>2008-11-12T09:45:00.000+02:00</published><updated>2008-11-12T13:23:59.332+02:00</updated><title type='text'>PropertyChangeSupport - wywołanie za pomocą Spring AOP</title><content type='html'>W poprzednim tekście opisałem jak poradzić sobie z problemem opisanym na pl.comp.lang.java w poście zatytułowanym &lt;a href="http://groups.google.pl/group/pl.comp.lang.java/browse_thread/thread/4943ffc5edd78f4c#"&gt;JavaBeans - zła koncepcja&lt;/a&gt; używając czystego AspectJ. Dziś pokażę jak zrobić to samo wykorzystując Spring AOP (przypomnę - chodzi o notyfikację obiektu PropertyChangeSupport przy każdym wywołaniu settera na JavaBean'ie).&lt;br /&gt;&lt;br /&gt;Najważniejszym elementem rozwiązania jest interceptor, który przechwytuje wywołania setterów:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package pl.kadamczyk.springpropertychange.interceptors;&lt;br /&gt;&lt;br /&gt;import java.lang.reflect.Field;&lt;br /&gt;&lt;br /&gt;import org.aopalliance.intercept.MethodInterceptor;&lt;br /&gt;import org.aopalliance.intercept.MethodInvocation;&lt;br /&gt;&lt;br /&gt;import pl.kadamczyk.springpropertychange.model.BaseModelObject;&lt;br /&gt;&lt;br /&gt;public class SetterMethodInterceptor implements MethodInterceptor {&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Otacza faktyczne wywołanie metody&lt;br /&gt;  */&lt;br /&gt; public Object invoke(final MethodInvocation method) throws Throwable {&lt;br /&gt;     String jointPoint = method.getMethod().getName();&lt;br /&gt;&lt;br /&gt;     // wyznaczamy nazwe pola na podstawie nazwy wywolanego settera&lt;br /&gt;     String fieldName = jointPoint.replaceFirst("set", "");&lt;br /&gt;     fieldName = Character.toLowerCase(fieldName.charAt(0))&lt;br /&gt;             + fieldName.substring(1);&lt;br /&gt;&lt;br /&gt;     try {&lt;br /&gt;         Object target = method.getThis();&lt;br /&gt;&lt;br /&gt;         Class clazz = target.getClass();&lt;br /&gt;         // pobieramy pole klasy o wyznaczonej wczesniej nazwie&lt;br /&gt;         Field field = clazz.getDeclaredField(fieldName);&lt;br /&gt;         field.setAccessible(true);&lt;br /&gt;&lt;br /&gt;         // pobieramy stara wartosc pola&lt;br /&gt;         Object oldValue = field.get(target);&lt;br /&gt;         // zezwalamy na wywolanie settera&lt;br /&gt;         Object result = method.proceed();&lt;br /&gt;         if (method.getArguments().length == 1) {&lt;br /&gt;             triggerPropertyChange(target, method.getArguments()[0],&lt;br /&gt;                     oldValue, fieldName);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         return result;&lt;br /&gt;     } catch (NoSuchFieldException e) {&lt;br /&gt;         throw new RuntimeException(e);&lt;br /&gt;     } catch (IllegalArgumentException e) {&lt;br /&gt;         throw new RuntimeException(e);&lt;br /&gt;     } catch (IllegalAccessException e) {&lt;br /&gt;         throw new RuntimeException(e);&lt;br /&gt;     } catch (Throwable e) {&lt;br /&gt;         throw new RuntimeException(e);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Sprawdza, czy metoda została wykonana na obiekcie klasy dziedziczącej&lt;br /&gt;  * po BaseModelObject, a jeśli tak, wywołuje na nim firePropertyChange&lt;br /&gt;  */&lt;br /&gt; private void triggerPropertyChange(final Object target,&lt;br /&gt;         final Object newVal, final Object oldValue, final String fieldName) {&lt;br /&gt;     System.out.println("MethodInterceptor: Zmieniamy wartosc pola "&lt;br /&gt;             + fieldName);&lt;br /&gt;&lt;br /&gt;     if (target instanceof BaseModelObject) {&lt;br /&gt;         // wywolujemy metode z klasy bazowej&lt;br /&gt;         ((BaseModelObject) target).firePropertyChange(fieldName, oldValue,&lt;br /&gt;                 newVal);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Jest to częściowo zmieniona wersja aspektu z poprzedniego posta, dostosowana do Springowego API.&lt;br /&gt;&lt;br /&gt;Drugim krokiem jest odpowiednie skonfigurowanie interceptora:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xmlns:aop="http://www.springframework.org/schema/aop"&lt;br /&gt;xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;xsi:schemaLocation="&lt;br /&gt;http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd&lt;br /&gt;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&lt;br /&gt;http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;aop:aspectj-autoproxy /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="someModelObject"&lt;br /&gt;class="pl.kadamczyk.springpropertychange.model.SomeModelObject"&lt;br /&gt;scope="prototype" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean name="setterInterceptor"&lt;br /&gt;class="pl.kadamczyk.springpropertychange.interceptors.SetterMethodInterceptor" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&amp;lt;bean name="pointcut.setterAdvisor"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;  class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;  &amp;lt;property name="advice" ref="setterInterceptor" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;  &amp;lt;property name="mappedName" value="set*" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; &amp;lt;/bean&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;Na uwagę zasługuje bean &lt;span style="font-weight: bold;"&gt;pointcut.setterAdvisor&lt;/span&gt; który odpowiada za powiązanie interceptora z pointcut'ami w których ma być zaaplikowany.&lt;br /&gt;&lt;br /&gt;W odróżnieniu od pierwszego rozwiązania w którym zastosowałem czysty &lt;span style="font-weight: bold;"&gt;AspectJ&lt;/span&gt; oraz compile-time-weaving, tutaj aplikowanie &lt;span style="font-style: italic;"&gt;porady&lt;/span&gt; wykonywane jest w trakcie działania.&lt;br /&gt;Konsekwencją tego jest zmiana sposobu korzystania z klas modelu. Aby Spring AOP mógł wygenerować odpowiednie &lt;span style="font-weight: bold;"&gt;proxy&lt;/span&gt; w runtime, konieczne jest pobranie obiektu z fabryki - w naszym przypadku będzie to ClassPathXmlApplicationContext:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public static void main(final String[] args) {&lt;br /&gt;     AbstractApplicationContext context = new ClassPathXmlApplicationContext(&lt;br /&gt;             "beans.xml");&lt;br /&gt;&lt;br /&gt;     SomeModelObject modelObject = (SomeModelObject) context&lt;br /&gt;             .getBean("someModelObject");&lt;br /&gt;&lt;br /&gt;     modelObject.setSomeIntProperty(23);&lt;br /&gt;     modelObject.setSomeStringProperty("ala");&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;Zwróćmy uwagę, że bean someModelObject w pliku konfiguracyjnym Spring'a zdefiniowany jest z atrybutem &lt;span style="font-weight: bold;"&gt;scope="prototype" &lt;/span&gt;aby wywołanie context.getBean zwracało za każdym razem nową instancję.&lt;br /&gt;&lt;br /&gt;Podobnie jak poprzednio, wynikiem działania metody &lt;span style="font-style: italic;"&gt;main&lt;/span&gt; jest napis na konsoli:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: courier new;"&gt;MethodInterceptor: Zmieniamy wartosc pola someIntProperty&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: courier new;"&gt;MethodInterceptor: &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: courier new;"&gt;Zmieniamy wartosc pola someStringProperty&lt;/span&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5526340079447277172/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5526340079447277172' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5526340079447277172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5526340079447277172'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/propertychangesupport-wywoanie_11.html' title='PropertyChangeSupport - wywołanie za pomocą Spring AOP'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5841070252435921518</id><published>2008-11-06T15:43:00.000+02:00</published><updated>2008-11-12T11:58:56.123+02:00</updated><title type='text'>PropertyChangeSupport - wywołanie za pomocą AspectJ</title><content type='html'>Zainspirowany &lt;a href="http://groups.google.pl/group/pl.comp.lang.java/browse_thread/thread/4943ffc5edd78f4c#"&gt;postem &lt;span&gt;Krzyśka&lt;/span&gt;&lt;/a&gt;  (aka Kolszew) zatytułowanym &lt;span style="font-style: italic;"&gt;JavaBeans - zła koncepcja&lt;/span&gt; na pl.comp.lang.java postanowiłem przygotować przykład demonstrujący użycie &lt;span style="font-style: italic;"&gt;Aspect Oriented Programming&lt;/span&gt; (konkretnie &lt;span style="font-weight: bold;"&gt;AspectJ&lt;/span&gt;) do rozwiązania przedstawionego przez Krzyśka problemu.&lt;br /&gt;Interesuje mnie uzyskanie zachowania setterów wybranych klas identycznego z poniższym zapisem:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void setText(String txt) {&lt;br /&gt;    String oldValue = this.text;&lt;br /&gt;    this.text = txt;&lt;br /&gt;    propertyChangeSupport.firePropertyChange("text", oldValue, txt);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;bez konieczności dodawania w każdym setterze pierwszej i trzeciej z powyższych linii kodu.&lt;br /&gt;&lt;br /&gt;Pierwszy krok to stworzenie projektu. Plugin AJDT (&lt;span style="font-style: italic;"&gt;AspectJ Development Tools&lt;/span&gt;) do Eclipse umożliwia stworzenie projektu AspectJ (New-&gt;AspectJ Project) zawierającego od razu podpięte bilbioteki AJ.&lt;br /&gt;&lt;br /&gt;Tworzę klasę bazową dla klas modelu, udostępniającą metodę &lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;firePropertyChange &lt;/span&gt;&lt;/span&gt;która po prostu deleguje wywołanie do prywatnego pola typu PropertyChangeSupport.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.beans.PropertyChangeSupport;&lt;br /&gt;&lt;br /&gt;public class BaseModelObject {&lt;br /&gt;&lt;br /&gt;    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(&lt;br /&gt;            this);&lt;br /&gt;&lt;br /&gt;    public void firePropertyChange(final String propertyName,&lt;br /&gt;            final Object oldValue, final Object newValue) {&lt;br /&gt;        propertyChangeSupport.firePropertyChange(propertyName, oldValue,&lt;br /&gt;                newValue);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Stwórzmy testową klasę, która dziedziczy po BaseModelObject:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package pl.kadamczyk.ajpropertychange.model;&lt;br /&gt;&lt;br /&gt;public class SomeModelObject extends BaseModelObject {&lt;br /&gt;&lt;br /&gt;    private String someStringProperty;&lt;br /&gt;    private int someIntProperty;&lt;br /&gt;&lt;br /&gt;    public String getSomeStringProperty() {&lt;br /&gt;        return someStringProperty;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setSomeStringProperty(final String someStringProperty) {&lt;br /&gt;        this.someStringProperty = someStringProperty;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getSomeIntProperty() {&lt;br /&gt;        return someIntProperty;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setSomeIntProperty(final int someIntProperty) {&lt;br /&gt;        this.someIntProperty = someIntProperty;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nadszedł najciekawszy moment: tworzymy &lt;span style="font-weight: bold;"&gt;aspekt&lt;/span&gt; który będzie odpowiedzialny za wywoływanie metody firePropertyChange z klasy BaseModelObject:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package pl.kadamczyk.ajpropertychange.aspects;&lt;br /&gt;&lt;br /&gt;import pl.kadamczyk.ajpropertychange.model.BaseModelObject;&lt;br /&gt;&lt;br /&gt;public aspect PropertyChangeAspect {&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * Określamy "miejsca", gdzie aplikowana będzie Porada&lt;br /&gt;     */&lt;br /&gt;    pointcut callSetter(Object target, Object param): target(target) &amp;&amp; args(param) &amp;&amp;  &lt;br /&gt;             execution(void pl.kadamczyk.ajpropertychange.model.*.set*(..));&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Porada typu &lt;b&gt;around&lt;/b&gt; - pozwala wykonać kod przed i po właściwym&lt;br /&gt;     * wywołaniu metody.&lt;br /&gt;     * &lt;br /&gt;     */&lt;br /&gt;    Object around(Object target, Object newVal) : callSetter(target, newVal)  {&lt;br /&gt;        String jointPoint = thisJoinPoint.getSignature().getName();&lt;br /&gt;        // wyznaczamy nazwe pola na podstawie nazwy wywolanego settera&lt;br /&gt;        String fieldName = jointPoint.replaceFirst("set", "");&lt;br /&gt;        fieldName = Character.toLowerCase(fieldName.charAt(0))&lt;br /&gt;                + fieldName.substring(1);&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;            Class clazz = target.getClass();&lt;br /&gt;            // pobieramy pole klasy o wyznaczonej wczesniej nazwie&lt;br /&gt;            java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);&lt;br /&gt;            field.setAccessible(true);&lt;br /&gt;&lt;br /&gt;            // pobieramy stara wartosc pola&lt;br /&gt;            Object oldValue = field.get(target);&lt;br /&gt;            // zezwalamy na wywolanie settera&lt;br /&gt;            Object result = proceed(target, newVal);&lt;br /&gt;            triggerPropertyChange(target, newVal, oldValue, fieldName);&lt;br /&gt;            return result;&lt;br /&gt;        } catch (NoSuchFieldException e) {&lt;br /&gt;            throw new RuntimeException(e);&lt;br /&gt;        } catch (IllegalArgumentException e) {&lt;br /&gt;            throw new RuntimeException(e);&lt;br /&gt;        } catch (IllegalAccessException e) {&lt;br /&gt;            throw new RuntimeException(e);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Sprawdza, czy metoda została wykonana na obiekcie klasy dziedziczącej&lt;br /&gt;     * po BaseModelObject, a jeśli tak, wywołuje na nim firePropertyChange&lt;br /&gt;     */&lt;br /&gt;    private void triggerPropertyChange(final Object target,&lt;br /&gt;            final Object newVal, final Object oldValue, final String fieldName) {&lt;br /&gt;        System.out.println("Zmieniamy wartosc pola " + fieldName);&lt;br /&gt;        if (target instanceof BaseModelObject) {&lt;br /&gt;            // wywolujemy metode z klasy bazowej&lt;br /&gt;            ((BaseModelObject) target).firePropertyChange(fieldName, oldValue,&lt;br /&gt;                    newVal);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Zdefiniowany &lt;span style="font-weight: bold;"&gt;pointcut&lt;/span&gt; określa wywołanie wszystkich metod we wszystkich klasach w pakiecie&lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;span style="font-weight: bold;"&gt; pl.kadamczyk.ajpropertychange.model &lt;/span&gt;&lt;/span&gt;o nazwie rozpoczynającej się od "set" oraz typie zwracanym "void".&lt;br /&gt;&lt;br /&gt;Zdefiniowanie Porady (advice) typu &lt;span style="font-weight: bold;"&gt;around &lt;/span&gt;umożliwia wykonanie czynności zarówno przed jak i po wykonaniu właściwej metody, którą wyzwalamy wywołując &lt;span style="font-weight: bold;"&gt;proceed()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Na uwagę zasługuje również użycie zmiennej specjalnej &lt;span style="font-weight: bold;"&gt;thisJoinPoint&lt;/span&gt; - jest to analogia do standardowego Javowego &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt; - zmienna ta może być używana jedynie w kontekście Porady (advice). Zawiera ona wiele przydatnich informacji na temat bieżącego Join Pointa, czyli w naszym przypadku konkretnego wywołanego settera. W szczególności wywołanie:&lt;br /&gt;&lt;pre&gt;thisJoinPoint.getSignature().getName()&lt;/pre&gt;zwraca nazwę aktualnie wywoływanej metody set*.&lt;br /&gt;&lt;br /&gt;Aby zobaczyć rezultat działania powyższego &lt;span style="font-weight: bold;"&gt;aspektu&lt;/span&gt; uruchomimy prostą klasę z metodą &lt;span style="font-weight: bold;"&gt;main()&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package pl.kadamczyk.ajpropertychange.launcher;&lt;br /&gt;&lt;br /&gt;import pl.kadamczyk.ajpropertychange.model.SomeModelObject;&lt;br /&gt;&lt;br /&gt;public class Launcher {&lt;br /&gt;&lt;br /&gt;public static void main(final String[] args) {&lt;br /&gt;    SomeModelObject mo = new SomeModelObject();&lt;br /&gt;    mo.setSomeIntProperty(23);&lt;br /&gt;    mo.setSomeStringProperty("ala ma kota");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;na konsoli otrzymujemy wynik:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;Zmieniamy wartosc pola someIntProperty&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Zmieniamy wartosc pola someStringProperty&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jeszcze uwaga na koniec - ten kod nie zadziała odpalony z odpowiednim menadżerem bezpieczeństwa, ponieważ nie dopuści on do wywołania metody setAccesible(true) na polach.&lt;br /&gt;Biorąc to pod uwagę należy w inny sposób pobrać wartość pola - ja tutaj zastosowałem 'hack' z metodą setAccesible ponieważ było to najszybsze rozwiązanie ;)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5841070252435921518/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5841070252435921518' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5841070252435921518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5841070252435921518'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/propertychangesupport-wywoanie.html' title='PropertyChangeSupport - wywołanie za pomocą AspectJ'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-5867335445782405481</id><published>2008-11-06T10:43:00.000+02:00</published><updated>2008-11-12T11:35:10.703+02:00</updated><title type='text'>JPA, transakcje rozproszone i MS SQL Server</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;Po raz pierwszy przyszło mi zmierzyć się z tematem transakcji rozproszonych, i to od razu w styczności z MS SQL Serverem, który - moim zdaniem - jest średnio przyjazny Javie.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;Sama konieczność zastosowania transakcji rozproszonych wynikła z wymagania eksportowania danych z jednej bazy (baza A - PostgreSQL) do drugiej (baza B - MS SQL). W trakcie tegoż eksportu dane z bazy A muszą być oznaczane jako pomyślnie wyeksportowane. W przypadku, gdy w trakcie zapisu do bazy B coś pójdzie nie tak transakcja jest rollbackowana i dane w bazie A nie otrzymują flagi "wyeksportowane".&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;W założeniu wszystko pięknie - gorzej w praktyce. Okazało się że włączenie obsługi transakcji XA w MS SQL tymaga wykonania sporej liczby kroków, które opiszę poniżej:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:georgia;"&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Włącz obsługę transakcji rozproszonych w systemie Windows, na którym jest zainstalowany SQL Server - zostało to opisane &lt;a href="http://www.andornot.com/about/developerblog/2008/05/when-distributed-transactions-go-boing.aspx"&gt;tutaj&lt;/a&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Skonfiguruj usługę systemowego Koordynatora Transakcji Rozproszonych (Distributed Transactions Coordinator) aby uruchamiałą się automatycznie podczas startu systemu&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Pobierz &lt;a href="http://msdn.microsoft.com/en-us/data/aa937724.aspx"&gt;sterownik JDBC&lt;/a&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;W pobranej paczce sterowników znajdź plik &lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;sqljdbc_xa.dll&lt;/span&gt;&lt;span style="font-size:100%;"&gt; (odpowiedni dla danej architektury) i umieść go w strukturze katalogów SQL Servera.&lt;br /&gt;Plik ten zawiera implementacje procedur składowanych odpowiedzialnych za transakcje rozproszone.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Wskaż systemowi operacyjnemu lokalizację powyższego pliku. Aby to zrobić, należy dodać do rejestru w kluczu &lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;&lt;br /&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\XADLL&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;wpis typu "&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;wartość ciągu" (REG_SZ) &lt;/span&gt;&lt;span style="font-size:100%;"&gt;o nazwie będącej nazwą pliku DLL oraz o wartości będącej ścieżką do tego pliku (wraz z samą nazwą). W moim przypadku było to :&lt;br /&gt;nazwa: sqljdbc_xa.dll&lt;br /&gt;wartość:&lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt; &lt;/span&gt;&lt;span style="font-size:100%;"&gt;C:\Program Files\Microsoft SQL Server\100\Shared\sqljdbc_xa.dll&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Na zainstalowanej instancji SQL Servera uruchom skrypt SQL instalujący potrzebne procedury składowane. Skrypt ten może być następującej postaci:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;use master&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;go&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_init', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_start', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_end', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_prepare', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_commit', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_rollback', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_forget', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_recover', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_rollback_ex', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_forget_ex', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;exec sp_addextendedproc 'xp_sqljdbc_xa_prepare_ex', 'SQLJDBC_XA.dll'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;go&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_init to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_start to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_end to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_prepare to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_commit to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_rollback to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_recover to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_forget to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_rollback_ex to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_forget_ex to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;grant execute on xp_sqljdbc_xa_prepare_ex to public&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=""&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;go&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span&gt;&lt;span style="font-family:georgia;"&gt;&lt;span&gt;Konfiguracja Connection Pool:&lt;br /&gt;DataSource classname = &lt;span style="font-weight: bold;font-family:georgia;" &gt;com.microsoft.sqlserver.jdbc.SQLServerXADataSource&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;Resource type = &lt;span style="font-weight: bold;"&gt;javax.sql.XADataSource&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;Należy pamiętać o wyborze właściwej wersji sterownika JDBC:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:georgia;"&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;plik sqljdbc.jar  dla Javy 5&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;plik sqljdbc4.jar- dla Javy 6&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;W przypadku problemów z połączeniem z SQL Serverem sprawdź artykuł &lt;a href="http://lijinjoseji.wordpress.com/2008/03/31/possible-solutions-for-jdbc-sql-server-connection-problem/"&gt;Six Possible Solutions For JDBC - SQL Server Connection Problems&lt;/a&gt;.&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Aha! I uwaga na SQL Server 2008 (nie wiem czy wcześniejsze wersje też) - standardowo włączona jest jedynie opcja logowania użytkownika z Autoryzacją Windows, a więc nie da się&lt;br /&gt;zalogować poprzez JDBC na użytkownika bazodanowego. Dopiero ręczne włączenie tej opcji pomaga ;)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/5867335445782405481/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=5867335445782405481' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5867335445782405481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/5867335445782405481'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/jpa-transakcje-rozproszone-i-ms-sql.html' title='JPA, transakcje rozproszone i MS SQL Server'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3476707669923401512.post-4980618283826322049</id><published>2008-11-06T10:28:00.000+02:00</published><updated>2008-11-06T10:36:24.415+02:00</updated><title type='text'>Ruszamy :)</title><content type='html'>Witam na moim "świeżo upieczonym" blogu :) Postaram się (w miarę wolnego czasu, którego jest niewiele a będzie coraz mniej ;)) opisywać na tych stronach problemy z którymi borykam się w codziennej pracy. Mam nadzieję, że stanie się on w przyszłości miejscem, w którym będzie można znaleźć ciekawe informacje, a także przedyskutować problemy o których piszę i rozwiązania które proponuję. Blog ten traktuję jako pewnego rodzaju wyzwanie, i - oczywiście - oczekuję na słowa konstruktywnej krytyki. No to startujemy! :)</content><link rel='replies' type='application/atom+xml' href='http://k-adamczyk.blogspot.com/feeds/4980618283826322049/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3476707669923401512&amp;postID=4980618283826322049' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/4980618283826322049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3476707669923401512/posts/default/4980618283826322049'/><link rel='alternate' type='text/html' href='http://k-adamczyk.blogspot.com/2008/11/ruszamy.html' title='Ruszamy :)'/><author><name>Krzysztof Adamczyk</name><uri>http://www.blogger.com/profile/17911372970569864021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_0zhWBYvrXoE/TCCOWwZpA7I/AAAAAAAABAM/S8vdS_2PGmE/S220/krzysztof_adamczyk.png'/></author><thr:total>0</thr:total></entry></feed>