<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>dev garden</title>
	<atom:link href="http://darekzon.com/feed" rel="self" type="application/rss+xml" />
	<link>http://darekzon.com</link>
	<description>when technology meets nature</description>
	<lastBuildDate>Mon, 19 Mar 2012 23:02:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Globalne łapanie wyjątków w Spring 3.1</title>
		<link>http://darekzon.com/2012/03/globalne-lapanie-wyjatkow-w-spring-3-1</link>
		<comments>http://darekzon.com/2012/03/globalne-lapanie-wyjatkow-w-spring-3-1#comments</comments>
		<pubDate>Mon, 19 Mar 2012 23:01:40 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[J2EE]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Projektowanie aplikacji]]></category>
		<category><![CDATA[Spring framework]]></category>
		<category><![CDATA[exception]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring3.1]]></category>
		<category><![CDATA[wyjątki]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1416</guid>
		<description><![CDATA[Wielokrotnie wchodząc na przeróżne strony zamiast oczekiwanej przeze mnie treści pojawiała się strona z błędami aplikacji, i nie był to tylko komunikat w stylu &#8222;Błąd strony&#8221; a pełne kody błędów, łącznie ze stacktracem czy też kodem strony (jeśli była pisana &#8230; <a href="http://darekzon.com/2012/03/globalne-lapanie-wyjatkow-w-spring-3-1">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Wielokrotnie wchodząc na przeróżne strony zamiast oczekiwanej przeze mnie treści pojawiała się strona z błędami aplikacji, i nie był to tylko komunikat w stylu &#8222;Błąd strony&#8221; a pełne kody błędów, łącznie ze stacktracem czy też kodem strony (jeśli była pisana w języku skryptowym). Nie trzeba chyba nikomu tłumaczyć, że tego typu treść nigdy nie powinna być widoczna dla użytkownika końcowego. I nie tylko dlatego, że strona taka brzydko wygląda i może odstraszyć użytkowników. Treści wyjątków jakie powoduje aplikacja, czy też część kodu jakie pojawią się mogą być bez problemu wykorzystane przez osoby interesujące się zabezpieczeniami.<span id="more-1416"></span></p>
<p>W bibliotece SpringFramework, istnieje coś takiego jak ExceptionHandler, który działa lokalnie i jest implementowany per kontroler co przy większej aplikacji może być mało wygodne. Niestety globalny mechanizm przechwytywania powstanie najwcześniej w wersji 3.2(kiedyś przeczytałem pewien komentarz programisty Springa w ich systemie Jira) więc puki co musimy radzić sobie sami. Prosty system przechwytujący wyjątki można napisać samemu i nawet specjalnie się przy tym nie napracujemy.<br />
Do stworzenia takiego systemu będziemy potrzebować najnowszych bibliotek Springa oraz bibliotek wspomagających programowanie aspektowe (aspectjweaver)</p>
<p>Na początek skonfigurujemy klasę która będzie obsługiwać wyjątki, konfigurację umieszczamy w applicationContext.xml</p>
<pre class="brush: xml; title: ; notranslate">&lt;/pre&gt;
&lt;aop:aspectj-autoproxy /&gt;
 &lt;aop:config&gt;
 &lt;aop:aspect id=&quot;exceptionHandler&quot; ref=&quot;globalExceptionHandler&quot;&gt;
 &lt;!-- find all methods that returns ModelAndView objects --&gt;
 &lt;aop:pointcut expression=&quot;execution(org.springframework.web.servlet.ModelAndView+ *(..))&quot; id=&quot;returningMav&quot; /&gt;
 &lt;!-- and execute them inside exceptionHandler --&gt;
 &lt;aop:around method=&quot;exceptionHandler&quot; pointcut-ref=&quot;returningMav&quot; /&gt;
 &lt;/aop:aspect&gt;
 &lt;/aop:config&gt;
 &lt;bean id=&quot;globalExceptionHandler&quot; class=&quot;com.darekzon.spring.exhandler.aop.ExceptionHandler&quot; /&gt;
&lt;pre&gt;</pre>
<p>Powyższy zapis konfiguruje system tak aby wyłapał wszystkie metody zwracające obiekt &#8222;ModelAndView&#8221; (czyli zazwyczaj metody mapujące URL-e) i przekazywał je do naszego obiektu, a dokładniej do metody &#8222;exceptionHandler&#8221; w klasie &#8222;ExceptionHandler&#8221;.<br />
Metody te będą przekazywane w formie obiektu ProceedingJoinPoint posiadającego metodę &#8222;proceed&#8221; która służy do wywołania domyślnej akcji.</p>
<p>Nasza metoda obsługująca wyjątki wygląda jak poniżej</p>
<pre class="brush: java; title: ; notranslate">
public ModelAndViewexceptionHandler(ProceedingJoinPoint pjp)throws Throwable{
        ModelAndView mav=newModelAndView();
        try{
            mav=(ModelAndView) pjp.proceed();
        }catch(Exceptionae){
            mav.addObject(&quot;exceptionMessage&quot;,ae.getMessage());
            mav.setViewName(&quot;exception&quot;);
        }
        return mav;
    }
</pre>
<p>Działanie jest proste, wywołaj metodę która może rzucić wyjątek (tj. metodę obsługującą url) i jeśli taki wyjątek zostanie rzucony, złap go, dodaj jego wiadomość do widoku jako &#8216;exceptionMessage&#8217; oraz wygeneruj widok o nazwie &#8216;exception&#8217;. A co za tym idzie, jeśli nasza metoda kontrolera wyrzuci wyjątek, zostanie on złapany a zamiast niego zostanie zwrócony poprawny obiekt ModelAndView.</p>
<p>Oczywiście zamiast prostej podmiany widoków możemy przekierować użytkownika do innej strony, zapisać logi, czy też wysłać maila.</p>
<h3>Działający projekt</h3>
<blockquote><p>Działający projekt można pobrać przeglądać pod adresem <a title="Spring 3.1 globalne łapanie wyjątków" href="https://github.com/darek/spring.3.examples/tree/master/aop-global-exception-handler" target="_blank">https://github.com/darek/spring.3.examples/tree/master/aop-global-exception-handler</a></p></blockquote>
<div class="shr-publisher-1416"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2012/03/globalne-lapanie-wyjatkow-w-spring-3-1/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Książka: Pro Git</title>
		<link>http://darekzon.com/2012/02/ksiazka-pro-git</link>
		<comments>http://darekzon.com/2012/02/ksiazka-pro-git#comments</comments>
		<pubDate>Fri, 10 Feb 2012 21:20:34 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Książki]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[książka]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1402</guid>
		<description><![CDATA[Pracując w kilkuosobowym zespole nie sposób uciec od systemów kontroli wersji. Ba, jeśli pracujesz w zespole który nie korzysta z takiego systemu to wiedz, że coś się dzieje. Systemy kontroli wersji bardzo mocno upraszczają obieg kodu w grupie, pozwalają na &#8230; <a href="http://darekzon.com/2012/02/ksiazka-pro-git">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p><img class="alignleft  wp-image-1403" title="Pro Git" src="http://www2.darekzon.com/wp-content/uploads/2012/02/book-big.jpg" alt="Pro Git" width="135" height="135" />Pracując w kilkuosobowym zespole nie sposób uciec od systemów kontroli wersji. Ba, jeśli pracujesz w zespole który nie korzysta z takiego systemu to wiedz, że coś się dzieje. Systemy kontroli wersji bardzo mocno upraszczają obieg kodu w grupie, pozwalają na szybką naprawę błędów i ewentualne cofnięcie niefortunnych zmian, ale to tylko czubek góry lodowej ich możliwości. Aktualnie najpopularniejszym (biorąc pod uwagę internet, bo w wielu dużych firmach nadal używa się SVN-a) jest system GiT stworzony przez społeczność programistów linuksowych. Ma on wiele zalet które deklasują poczciwe stare systemy kontroli takie jak CVS czy SVN więc na pewno warto go poznać. A w poznaniu tego systemu na pewno pomoże książka <a title="Książka ProGit" href="http://progit.org/book/" target="_blank">Pro Git</a> której autorem jest <a title="Strona domowa Scotta Chacona" href="http://scottchacon.com/" target="_blank">Scott Chaco</a>. Autor w swojej książce w bardzo przystępny sposób opisuje zasady działania GITa, oraz typowy workflow jaki jest wykorzystywany podczas pracy w grupie. Książkę jest przejrzysta i napisana przystępnym językiem, czyta się ją przyjemnie a zdobyta wiedza nie wypada szybko z głowy. Polecam każdemu</p>
<div class="shr-publisher-1402"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2012/02/ksiazka-pro-git/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Źródła IntelliJ Community dostępne za darmo, inne wersje tańsze</title>
		<link>http://darekzon.com/2011/10/zrodla-intellij-community-dostepne-za-darmo-inne-wersje-tansze</link>
		<comments>http://darekzon.com/2011/10/zrodla-intellij-community-dostepne-za-darmo-inne-wersje-tansze#comments</comments>
		<pubDate>Fri, 07 Oct 2011 20:47:18 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[IDE]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Swing/SWT]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[ant]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[cvs]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[intellij]]></category>
		<category><![CDATA[jetbrains]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[scala]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[testng]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1397</guid>
		<description><![CDATA[Firma Jetbrains znana z wysokiej jakości środowisk programistycznych (IDE) postanowiła kilka dni temu wypuścić kod źródłowy swojego flagowego produktu. Kod źródłowy został umieszczony na serwerach GitHuba w ramach konsolidacji projektów open-source-owych prowadzonych w firmie. Na serwerach GitHuba dostępna jest wersja &#8230; <a href="http://darekzon.com/2011/10/zrodla-intellij-community-dostepne-za-darmo-inne-wersje-tansze">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Firma Jetbrains znana z wysokiej jakości środowisk programistycznych (IDE) postanowiła kilka dni temu wypuścić <a title="IntelliJ - Community Edition" href="https://github.com/JetBrains/intellij-community" target="_blank">kod źródłowy</a> swojego flagowego produktu. Kod źródłowy został umieszczony na serwerach GitHuba w ramach konsolidacji projektów open-source-owych prowadzonych w firmie.</p>
<p><span id="more-1397"></span>Na serwerach GitHuba dostępna jest wersja Community Edition która posiada pełne wsparcie dla języków Java, Groovy, Xml, Sala, Clojure (dwa ostatnie po zainstalowaniu darmowych wtyczek), a także posiada GUI builder, integrację frameworków testujących (JUnit oraz TestNG) oraz wsparcie dla Maven-a i Ant-a. Dla tych którzy wolą programować aplikacje mobilne zaimplementowane jest wsparcie platformy Android, a dla pracujących w grupie przewidziane jest wsparcie systemów kontroli wersji CVS, Subversion, Git (wraz z integracją GitHub-a) oraz Mercurial. Jeśli nie macie gdzie publikować swoich źródeł polecam BitBucket który ostatnimi czasy przeszedł <a title="Atlassian Bitbucket – wreszcie wsparcie dla GIT-a" href="http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a">małą modernizację</a>.</p>
<p>Niestety w tych wszystkich wspaniałościach zabrakło dla mnie najważniejszej rzeczy, czyli pełnego wsparcia dla frameworków webowych (JSP, Spring, Hibernate, etc.) które to są dostępne dopiero w płatnych edycjach.</p>
<p>Gdyby ktoś tak jak ja potrzebował funkcjonalności nie zawartych w wersji Community może wybrać wersję Ultimate i skorzystać z nowych cen jakie zaproponował Jetbrains, za najtańszą wersję (Personal License) zapłacimy 175€ czyli o 44€ mniej (poprzednia cena 219€), natomiast licencja dla firm i organizacji (Commercial License) to wydatek rzędu 439€ o 88€ mniej (poprzednia cena 527€). Oczywiście możliwe jest też otrzymanie licencji na wersję Ultimate za darmo o ile prowadzimy w miarę popularny projekt Open Source.</p>
<div class="shr-publisher-1397"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/10/zrodla-intellij-community-dostepne-za-darmo-inne-wersje-tansze/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SourceTree za darmo od Atlassian</title>
		<link>http://darekzon.com/2011/10/sourcetree-za-darmo-od-atlassian</link>
		<comments>http://darekzon.com/2011/10/sourcetree-za-darmo-od-atlassian#comments</comments>
		<pubDate>Fri, 07 Oct 2011 17:31:29 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[atlassian]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[sourcetree]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[vcs]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1393</guid>
		<description><![CDATA[Ledwie kilka dni temu Atlassian zaprezentował nową wersję swojego serwisu hostingującego kod, a znów głośno o tej firmie. Tym razem za sprawą przejęcia firmy SourceTree odpowiedzialnej za stworzenie makowej aplikacji (pod tą samą nazwą) ułatwiającej obsługę projektów opartych o Git, Mercurial oraz &#8230; <a href="http://darekzon.com/2011/10/sourcetree-za-darmo-od-atlassian">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Ledwie kilka dni temu <a title="Atlassian - Software development and collaboration software" href="http://atlassian.com/" target="_blank">Atlassian</a> zaprezentował nową wersję swojego serwisu <a title="Atlassian Bitbucket – wreszcie wsparcie dla GIT-a" href="http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a" target="_blank">hostingującego kod</a>, a znów głośno o tej firmie. Tym razem za sprawą przejęcia firmy <a title="SourceTree" href="http://www.sourcetreeapp.com/" target="_blank">SourceTree</a> odpowiedzialnej za stworzenie makowej aplikacji (pod tą samą nazwą) ułatwiającej obsługę projektów opartych o Git, Mercurial oraz Subversion.</p>
<p><span id="more-1393"></span>SourceTree jest zaawansowanym narzędziem które ułatwia obsługę komend systemów kontroli wersji. Dzięki niemu przy użyciu graficznego interfejsu możemy tworzyć commity, łatki, branche, tagi. Wywoływać komendy Fetch, Pull, Push&#8230;</p>
<p>&nbsp;</p>
<div id="attachment_1395" class="wp-caption aligncenter" style="width: 310px"><a href="http://www2.darekzon.com/wp-content/uploads/2011/10/source-tree.jpg" rel="lightbox[1393]"><img class="size-medium wp-image-1395" title="source-tree" src="http://www2.darekzon.com/wp-content/uploads/2011/10/source-tree-300x170.jpg" alt="" width="300" height="170" /></a><p class="wp-caption-text">SourceTree - okno aplikacji</p></div>
<p>Prócz wsparcia dla kompletu komend możemy również zintegrować naszą aplikację z hostingami kodu, mamy tu do wyboru oczywiście Bitbucket ale również GitHub oraz Kiln, czy dwa ostatnie przetrwają przejęcie SourceTree przez Atlassian? Moim zdaniem tak. Firma od dawna znana jest z bardzo dobrego podejścia do programistów i braku &#8222;zachłanności&#8221; wobec innych co bardzo cieszy.</p>
<h2>Cena</h2>
<p>Zanim SourceTree został przejęty przez Atlassian kosztował 59,99 USD, w tej chwili jest dostępny za darmo <strong>PRZEZ OGRANICZONY CZAS</strong> wiec jeśli akurat korzystacie z maka polecam pobrać aplikację. Można to zrobić na dwa sposoby, albo zarejestrować się na <a title="SourceTree - rejestracja" href="http://www.sourcetreeapp.com/register-free/" target="_blank">stronie aplikacji</a>, albo skorzystać z <a title="SourceTree w App Store" href="http://itunes.apple.com/pl/app/sourcetree-git-hg/id411678673?mt=12" target="_blank">App Store</a>.</p>
<div class="shr-publisher-1393"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/10/sourcetree-za-darmo-od-atlassian/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Atlassian Bitbucket &#8211; wreszcie wsparcie dla GIT-a</title>
		<link>http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a</link>
		<comments>http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a#comments</comments>
		<pubDate>Mon, 03 Oct 2011 19:48:15 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Projektowanie aplikacji]]></category>
		<category><![CDATA[bitbucket]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[hosting]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[private]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1388</guid>
		<description><![CDATA[Jak dowiedziałem się przed chwilą, Atlassian wypuścił nową wersję swojego serwisu Bitbucket który służył jako hosting dla naszych projektów. Jeszcze do niedawna Bitbucket obsługiwał jedynie Mercurial jednak to się zmieniło. Wraz z nową wersją serwisu doszła obsługa Git-a co bardzo &#8230; <a href="http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Jak dowiedziałem się przed chwilą, Atlassian wypuścił nową wersję swojego serwisu <a title="Bitbucket" href="https://bitbucket.org/" target="_blank">Bitbucket</a> który służył jako hosting dla naszych projektów. Jeszcze do niedawna Bitbucket obsługiwał jedynie Mercurial jednak to się zmieniło. Wraz z nową wersją serwisu doszła obsługa Git-a co bardzo mnie cieszy. Prócz wsparcia dla <a title="GIT" href="http://gitscm.com/" target="_blank">Git</a>-a mamy możliwość zintegrowania z wieloma serwisamy (Jenkins &#8211; dawny Hudson, Jira, Twitter itd.)</p>
<p><span id="more-1388"></span>Jak dla mnie to duży krok, do tej pory w moim przekonaniu nie istniał żaden serwis (godny zaufania) udostępniający darmowe prywatne repozytoria dla Git-a (co prawda <a title="Beanstalkapp" href="http://beanstalkapp.com/" target="_blank">Beanstalkapp</a> ma darmowe konta nazwane Trial ale są mocno ograniczone) na taką skalę. Z dużym prawdopodobieństwem bitbucket wprowadzi odrobinę zamieszania.</p>
<p>&nbsp;</p>
<div class="shr-publisher-1388"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/10/atlassian-bitbucket-wreszcie-wsparcie-dla-git-a/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Prosta aplikacja RESTful w Struts2 (Convention i REST plugin), Guice i MongoDB</title>
		<link>http://darekzon.com/2011/09/prosta-aplikacja-restful-w-struts2-convention-i-rest-plugin-guice-i-mongodb</link>
		<comments>http://darekzon.com/2011/09/prosta-aplikacja-restful-w-struts2-convention-i-rest-plugin-guice-i-mongodb#comments</comments>
		<pubDate>Fri, 30 Sep 2011 20:40:08 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[J2EE]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[convention-plugin]]></category>
		<category><![CDATA[guice]]></category>
		<category><![CDATA[jee]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[morphia]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[rest-plugin]]></category>
		<category><![CDATA[struts2]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1366</guid>
		<description><![CDATA[Ponieważ od jakiegoś czasu zdobywam wiedzę na temat nowych frameworków i technologii postanowiłem stworzyć właśnie projekt który integruje je wszystki. Wykorzystam w nim frameworki Guice oraz Struts2, a za przechowywanie danych odpowiadać będzie MongoDB wspierana przez bibliotekę Morphia. Dodatkowo z &#8230; <a href="http://darekzon.com/2011/09/prosta-aplikacja-restful-w-struts2-convention-i-rest-plugin-guice-i-mongodb">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Ponieważ od jakiegoś czasu zdobywam wiedzę na temat nowych frameworków i technologii postanowiłem stworzyć właśnie projekt który integruje je wszystki. Wykorzystam w nim frameworki <a title="Guice - lightweight dependency injection framework" href="http://code.google.com/p/google-guice/" target="_blank">Guice</a> oraz <a title="Struts2 - extensible framework for creating enterprise-ready Java web applications" href="http://struts.apache.org/2.x/" target="_blank">Struts2</a>, a za przechowywanie danych odpowiadać będzie <a title="MongoDB" href="http://www.mongodb.org/" target="_blank">MongoDB</a> wspierana przez bibliotekę <a title="Morphia: A type-safe java library for MongoDB" href="http://code.google.com/p/morphia/" target="_blank">Morphia</a>. Dodatkowo z racji, że ostatnio co chwile mówi się o aplikacjach REST-owych postanowiłem wykorzystać ten wzorzec w mojej aplikacji &#8211; &#8222;<a title="Struts2 REST shopping list (with struts2-convention plugin, struts2-rest plugin, guice, mongodb and morphia)" href="https://github.com/darek/struts2-rest-shopping-list" target="_blank">liście zakupowej</a>&#8222;.</p>
<p><span id="more-1366"></span></p>
<h2>Skąd pobrać projekt</h2>
<blockquote><p>Projekt dostępny jest w formie repozytorium GIT pod adresem <a title="Struts2 REST shopping list (with struts2-convention plugin, struts2-rest plugin, guice, mongodb and morphia)" href="https://github.com/darek/struts2-rest-shopping-list" target="_blank">https://github.com/darek/struts2-rest-shopping-list</a></p></blockquote>
<h2>Struts2 oraz Guice</h2>
<p>Jeśli ktoś nie zna frameworka Struts2 to wspomnę tylko, że jest to jeden z bardziej popularnych bibliotek do tworzenia aplikacji JEE. Cechuje się elastycznością oraz rozszerzalnością (poprzez pluginy).<br />
Guice jest dość świeży na polu frameworków, służy do wstrzykiwania zależności, a jego twórcami są inżynierowie Google.</p>
<h2>MongoDB</h2>
<p>Jak wspomniałem na wstępie MongoDB to baza danych oparta o dokumenty, oznacza to tyle, że dane w niej zawarte nie reprezentowane są w formie tabel posiadającej sztywny schemat a raczej w formie łatwo rozszerzalnego dokumentu (wykorzystywany jest tu format <a title="BSON" href="http://bsonspec.org/" target="_blank">BSON</a>). Największą zaletą (prócz łatwej skalowalności i wydajności) jest brak schematu, możemy wrzucić do niej co tylko chcemy bez potrzeby aktualizacji struktur tabel, każdy dokument nawet jeśli jest w tej samej kolekcji może się różnić od innych. Dokumenty te jednak nie posiadają powiązań więc trudniej jest zaimplementować schemat typu jeden do wielu, wiele do wielu. Pomimo tego baza ta idealnie nadaje się do mojej aplikacji. W końcu każda lista zakupowa posiada swój własny zestaw produktów do kupienia, nie potrzebujemy tu oddzielnej tabeli do składowania produktów.</p>
<h2>REST</h2>
<p>Od dłuższego czasu coraz większą popularność zyskuje wzorzec architektury zwany <a title="REST" href="http://pl.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">REST</a> (Representational State Transfer) zaproponowany przez <a title="Strona domowa Roy-a Thomasa Fieldinga" href="http://www.ics.uci.edu/~fielding/" target="_blank">Roya T. Fieldinga</a> w publikacji <a title="Principled Design of Modern Web Architecture, Roy T. Fielding (REST)" href="http://www.ics.uci.edu/~taylor/documents/2002-REST-TOIT.pdf" target="_blank">Principled Design of the Modern Web Architecture</a>. W wielkim skrócie chodzi o takie przygotowanie aplikacji by zasoby którymi operuje były dostępne pod unikalnymi linkami (URI), czyli żeby wyświetlić szczegóły użytkownika naszej aplikacji wykorzystamy adres http://example.com/user/23 (gdzie 23 to jego unikalny identyfikator). Dzięki takiemu rozwiązaniu zapewniony jest warunek bezstanowości aplikacji (nie ma ukrytego wysyłania danych aby zobaczyć dany zasób, np. http://example.com/user + cookie.id=23 do wyświetlenia zasobu użytkownika). Drugą chyba najbardziej widoczną cechą jest użycie większej ilości operacji protokołu HTTP. Zwykła aplikacja zazwyczaj używa tylko dwóch metod: POST i GET podczas gdy aplikacje napisane z wykorzystaniem REST-u mogą dodatkowo wykorzystać metody CREATE, PUT, DELETE  dzięki czemu jeden adres URI może służyć do wielu celów, gdy wywołamy adres http://example.com/user/23 metodą DELETE aplikacja powinna usunąć użytkownika o identyfikatorze 23, wywołując ten sam adres metodą PUT zaktualizujemy dane użytkownika itd. Więcej o architekturze REST możecie poczytać w sieci.</p>
<h2>Aplikacja</h2>
<h3>Założenia aplikacji</h3>
<ul>
<li>Aplikacja ma być bardzo uproszczona, powinna posiadać 2 główne widoki, pierwszy do tworzenia list zakupowych i wybierania ich poprzez wpisanie specjalnego identyfikatora, drugi widok powinien wyświetlać szczegóły listy wraz z produktami, oraz powinien pozwalać na dodawanie i usuwanie produktów.</li>
<li>Tworzenie listy ma następować po wpisaniu w formularzu nazwy listy i wysłaniu go metodą POST do odpowiedniego kontrolera</li>
<li>Otwieranie listy następować będzie poprzez wpisanie jej identyfikatora w odpowiednim formularzu i wysłanie go metodą GET do kontrolera list</li>
<li>Dodawanie produktów odbywać się będzie poprzez wysłanie danych z formularza (nazwa i ilość) metodą POST do kontrolera produktów</li>
<li>Kasowanie produktów odbywać się będzie poprzez wysłanie identyfikatora produktu metodą DELETE do kontrolera produktów</li>
</ul>
<h3>Konfigurowanie projektu</h3>
<p>Na początek skonfigurujemy wszystkie zależności wymagane w projekcie przy użyciu maven-owskiego pliku pom.xml.</p>
<pre class="brush: xml; title: ; notranslate">

&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;groupId&gt;shopping-list&lt;/groupId&gt;
&lt;artifactId&gt;shopping-list&lt;/artifactId&gt;
&lt;version&gt;0.1.0&lt;/version&gt;
&lt;packaging&gt;war&lt;/packaging&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
&lt;version&gt;2.1.1&lt;/version&gt;
&lt;configuration&gt;
&lt;!-- &lt;packagingExcludes&gt;**/web.xml&lt;/packagingExcludes&gt; --&gt;
&lt;webXml&gt;web/WEB-INF/web.xml&lt;/webXml&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;repositories&gt;
&lt;repository&gt;
&lt;id&gt;morphia&lt;/id&gt;
&lt;url&gt;http://morphia.googlecode.com/svn/mavenrepo/&lt;/url&gt;
&lt;/repository&gt;
&lt;/repositories&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;aopalliance&lt;/groupId&gt;
&lt;artifactId&gt;aopalliance&lt;/artifactId&gt;
&lt;version&gt;1.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.google.inject&lt;/groupId&gt;
&lt;artifactId&gt;guice&lt;/artifactId&gt;
&lt;version&gt;3.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.google.inject.extensions&lt;/groupId&gt;
&lt;artifactId&gt;guice-servlet&lt;/artifactId&gt;
&lt;version&gt;3.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.mongodb&lt;/groupId&gt;
&lt;artifactId&gt;mongo-java-driver&lt;/artifactId&gt;
&lt;version&gt;2.5.2&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.google.code.morphia&lt;/groupId&gt;
&lt;artifactId&gt;morphia&lt;/artifactId&gt;
&lt;version&gt;0.99&lt;/version&gt;
&lt;type&gt;jar&lt;/type&gt;
&lt;scope&gt;compile&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
&lt;artifactId&gt;struts2-rest-plugin&lt;/artifactId&gt;
&lt;version&gt;2.2.3.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
&lt;artifactId&gt;struts2-core&lt;/artifactId&gt;
&lt;version&gt;2.2.3.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;log4j&lt;/groupId&gt;
&lt;artifactId&gt;log4j&lt;/artifactId&gt;
&lt;version&gt;1.2.16&lt;/version&gt;
&lt;scope&gt;compile&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;javax.servlet&lt;/groupId&gt;
&lt;artifactId&gt;servlet-api&lt;/artifactId&gt;
&lt;version&gt;2.5&lt;/version&gt;
&lt;type&gt;jar&lt;/type&gt;
&lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
&lt;artifactId&gt;struts2-convention-plugin&lt;/artifactId&gt;
&lt;version&gt;2.2.3.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.google.inject.extensions&lt;/groupId&gt;
&lt;artifactId&gt;guice-struts2&lt;/artifactId&gt;
&lt;version&gt;3.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;modules&gt;
&lt;/modules&gt;
&lt;/project&gt;
</pre>
<p>Poza podstawowymi frameworkami (Guice i Struts) użyjemy również dwóch pluginów Strutsa2 które ułatwią pisanie aplikacji, oraz pozwolą zaimplementować architekturę REST, zostaną one opisane później. Aby dodać biblioteki Morphia potrzebne było skonfigurowanie dodatkowego repozytorium (jako repozytorium służy strona google code).</p>
<p>Naszym głównym frameworkiem będzie Struts2 który będzie odpowiadać za przekierowywanie naszych żądań do odpowiednich klas i generowanie odpowiedzi, Guice będzie pełnił rolę narzędzia do wstrzykiwania zależności (zob. <a title="Wstrzykiwanie zależności" href="http://pl.wikipedia.org/wiki/Wstrzykiwanie_zale%C5%BCno%C5%9Bci" target="_blank">Dependency Injection</a>) dlatego też potrzebujemy plugin Guice-Struts2 który to pozwoli ładnie połączyć oba frameworki.</p>
<p>Jak w każdej aplikacji webowej tak i w tej potrzebujemy skonfigurowany plik web.xml. Ponieważ nasza aplikacja nie jest szczególnie skomplikowana tak i tutaj nie będzie niczego nadzwyczajnego. No może poza jedną rzeczą.</p>
<pre class="brush: xml; title: ; notranslate">

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:web=&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
id=&quot;WebApp_ID&quot; version=&quot;2.5&quot;&gt;
&lt;display-name&gt;shopping-list&lt;/display-name&gt;
&lt;listener&gt;
&lt;listener-class&gt;com.darekzon.shoppinglist.listener.GuiceStruts2PluginListener&lt;/listener-class&gt;
&lt;/listener&gt;

&lt;filter&gt;
&lt;filter-name&gt;struts&lt;/filter-name&gt;
&lt;filter-class&gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&lt;/filter-class&gt;
&lt;/filter&gt;

&lt;filter-mapping&gt;
&lt;filter-name&gt;struts&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;

&lt;/web-app&gt;
</pre>
<p>Poza skonfigurowaniem Struts-owego flitra i przekierowaniem do niego wszystkich zapytań musieliśmy utworzyć Listener który odpowiadać będzie za wstrzykiwanie zależności. Listener stworzył <a title="Crazy Bob" href="http://blog.crazybob.org/" target="_blank">Bob Lee</a> jednak nie pamiętam skąd go pobrałem (zapewne jakaś strona w Google Code lub z forum), poza skopiowaniem Listenera zainstalowałem w nim mój moduł który będzie wstrzykiwał zależności (entity manager oraz repozytorium).</p>
<pre class="brush: java; title: ; notranslate">
public class GuiceStruts2PluginListener extends GuiceServletContextListener {

public Injector getInjector() {
return Guice.createInjector(
new Struts2GuicePluginModule(),
new ServletModule() {
@Override
protected void configureServlets() {
// Struts 2 setup
bind(StrutsPrepareAndExecuteFilter.class).in(Singleton.class);
filter(&quot;/*&quot;).through(StrutsPrepareAndExecuteFilter.class);

install(new ShoppingListModule());
}
});
}

}
</pre>
<p>Pora na konfigurację głównego frameworka, ponieważ ostatnio zniechęciłem się do XML-a użyję plików *.properties które umieszczam w głównym folderze z źródłami.<br />
Plik struts.properties odpowiedzialny jest za konfigurację Strutsa i wygląda następująco:</p>
<pre class="brush: plain; title: ; notranslate">

struts.objectFactory = guice

# Fix exception &quot;Cannot cast HttpHeaders to String&quot;
struts.rest.namespace =

struts.mapper.class = rest
struts.convention.action.suffix = Controller
struts.convention.action.mapAllMatches = true
struts.convention.action.alwaysMapExecute = true

struts.convention.relative.result.types    = dispatcher
struts.convention.default.parent.package = rest-default
struts.convention.package.locators  = actions

struts.devMode = true
</pre>
<p>Na samym początku konfigurujemy fabrykę obiektów (czyli wskazujemy Strutsowi aby używał pluginu Struts2Guice o którym wspomniałem wcześniej).<br />
Opcja <em>struts.rest.namespace</em> to przestrzeń nazw dla serwisów REST-owych (tak jakby kontekst pod którym będą dostępne). Ustawienie tej wartości na &#8222;<strong>nic</strong>&#8221; pozwoli uniknąć bardzo uciążliwego problemu przez którego nie można było używać HttpHeaders jako rezultatu metod (zob. <a title="Issue: org.apache.struts2.rest.DefaultHttpHeaders cannot be cast to java.lang.String" href="https://issues.apache.org/jira/browse/WW-3616" target="_blank">błąd 3616</a> ), warto dodać, że wartość tą należy zostawić pustą, wstawienie &#8222;&#8221; spowoduje wyrzucanie wcześniej wspomnianych błędów.</p>
<p><em>struts.mapper.class</em> pozwala ustalić jak żądania URL będą mapowane (co będzie wywoływane po wpisaniu adresu url), rozwinięcie tej nazwy znajdziecie w plikach konfiguracyjnych konkretnego pluginu (w tym przypadku wystarczy wejść do biblioteki struts2-rest-plugin i otworzyć plik struts-plugin.xml).Kolejne wartości ustalają jak ma działać plugin Convention, aby dowiedzieć się co oznaczają możecie przejść do odpowiedniej sekcji na <a title="Struts2 Convention Plugin" href="https://cwiki.apache.org/confluence/display/WW/Convention%20Plugin#ConventionPlugin-Configurationreference" target="_blank">stronie pluginu</a>.</p>
<p>Konfiguracja bazy danych jest bardzo prosta, wystarczy podać dane dostępowe takie jak host, port, login oraz haslo, a także tzw. datastore (czyli nazwę bazy). To wszystko odbywa się w pliku database.properties którego nie trzeba przytaczać.</p>
<h3>Jak działają pluginy Strutsa</h3>
<p>W aplikacji mamy doczynienia z dwoma pluginami Struts2, pierwszy z nich Convention będzie mapować nasze adresy URL na pakiety i klasy co to znaczy?<br />
Załóżmy, że mamy dwie klasy<em> com.darekzon.application.UserController</em> oraz <em>com.darekzon.application.user.DetailsController.</em> Niech nasza aplikacja będzie dostępna pod adresem <em>http://example.com/</em>. W takim przypadku adres <em>http://example.com/user</em> wywoła nam klasę UserController, natomiast adres <em>http://example.com/user/details </em>wywoła klasę DetailsController znajdującą się w pakiecie <strong>user</strong>.<br />
Rest-plugin działa trochę inaczej, on do mapowania używa metod HTTP. Mając nasz kontroler UserController możemy go wywołać na 4 sposoby za każdym razem zostanie wywołana inna metoda.</p>
<pre class="brush: plain; title: ; notranslate">
 GET         - http://example.com/user  - zostanie wywołana metoda INDEX
POST       - http://example.com/user  - zostanie wywołana metoda CREATE
 GET         -  http://example.com/user/ID  - zostanie wywołana metoda SHOW
 PUT         - http://example.com/user/ID - zostanie wywołana metoda UPDATE
 DELETE - http://example.com/user/ID - zostanie wywołana metoda DELETE
</pre>
<p>Metoda PUT oraz Delete muszę mieć dodatkowy parametr ID (identyfikator obiektu) ponieważ są wykonywane na obiekcie (więc logiczne, że trzeba wskazać obiekt). Gdy do metody GET dodamy identyfikator zostanie wywołana metoda SHOW ponieważ aplikacja wie że w tym wypadku, nie chcemy listy a konkretny obiekt.</p>
<h3>Drugi kontroler</h3>
<p>Nie będę pokazywał jak powstał pierwszy kontroler, bo jest on na tyle prosty, że nie wymaga opisu, zabawę zaczniemy z drugim, najważniejszym kontrolerem który  odpowiadać będzie za obsługę całej listy, a zwie się <em>ShoppingListController</em>.<br />
Ponieważ ShoppingListController będzie operować na danych, musimy wskazać mu klasę która będzie do tego przeznaczona, w tym przypadku jest to ShoppingListRepository a dodajemy ją do kontrolera poprzez wstrzyknięcie</p>
<pre class="brush: java; title: ; notranslate">
ShoppingListRepository shoppingListRepository;

@Inject
publicvoid setShoppingListRepository(ShoppingListRepository pr){
this.shoppingListRepository = pr;
}
</pre>
<p>Szczegółowa implementacja tej klasy dostępna jest w źródłach.<br />
Ważny jest również fakt, że klasa ta implementuje interfejs <strong>ModelDriven&lt;T&gt;</strong>, dzięki temu gdy poprosimy o dane w formacie XML nasza aplikacja będzie wiedziała jaki obiekt przetworzyć do żądanej postaci. Gdyby nie było tego interfejsu, przy prośbie o format XML dostalibyśmy przetkonwerterowaną całą klasę ShoppingListController czego chcemy uniknąć. Interfejs ten wymaga od nas zaimplementowania jednej metody &#8222;<strong>public T getModel()</strong>&#8221; zwracającej obiekt który będziemy konwertować (w razie konieczności).</p>
<h4>Strona początkowa:</h4>
<p>Strona początkowa aplikacji posiada dwa formularze, pierwszy otwiera listę o zadanym przez nas identyfikatorze, druga po podaniu nazwy tworzy taką listę. Widok prezentuje się następująco:</p>
<div id="attachment_1374" class="wp-caption aligncenter" style="width: 310px"><a href="http://www3.darekzon.com/wp-content/uploads/2011/09/shopping-list-forms.jpg" rel="lightbox[1366]"><img class="size-medium wp-image-1374" title="Shopping-list formularze" src="http://www3.darekzon.com/wp-content/uploads/2011/09/shopping-list-forms-300x175.jpg" alt="" width="300" height="175" /></a><p class="wp-caption-text">Strona początkowa</p></div>
<p>Pierwsza metoda jaką wywołujemy (czyli index wchodząc pod adres <em>http://example.com/shopping-list/index.xhtml</em>) wygląda następująco:</p>
<pre class="brush: java; title: ; notranslate">
public HttpHeaders index(){
if(this.id != null &amp;&amp; this.list==null){
returnnew DefaultHttpHeaders(&quot;notfound&quot;).withStatus(404);
}
if(this.id !=null &amp;&amp; this.list!=null){
// BUG - even with directly setted 302 status application is returning 201 (created) status.
return new DefaultHttpHeaders(&quot;show&quot;).setLocationId(this.id).withStatus(302);
}
return new DefaultHttpHeaders(&quot;index&quot;);
}
</pre>
<p>Tak naprawdę mogłaby być ona pusta z racji, że jej jedynym zadaniem jest wyświetlenie dwóch formularzy, ale wysyłanie formularza otwierającego listę powoduje wywołanie w/w metody (a nie metody show jak mogłoby się zdawać) dzieje się tak ponieważ wysłanie formularza przenosi nas pod adres <em>http://example.com/shopping-list/index.xhtml?id=IDENTYFIKATOR</em>  &#8211; a tego plugin rest nie potrafi zmapować do metody SHOW. W metodziej tej sprawdzamy oczywiście, czy lista istnieje, jeśli nie, wyświetlamy komunikat (cały widok) z informacją o braku listy oraz co ważne wysyłamy status HTTP 404 (<strong>NOT FOUND</strong>).<br />
Jeśli lista została znaleziona wysyłamy jej identyfikator oraz status 302 (<strong>FOUND</strong>) który powinien wymusić na przeglądarce automatyczne przekierowanie pod prawidłowy adres (tj. http://example.com/shopping-list/ID.xhtml)</p>
<h4>Tworzenie listy:</h4>
<p>Lista tworzona jest po wysłaniu formularza metodą post pod adres http://example.com/shopping-list/index.xhtml, wtedy wywoływana jest metoda create która wygląda następująco:</p>
<p>@Validations(requiredStrings = {@RequiredStringValidator(type = ValidatorType.FIELD, fieldName = &#8222;list.name&#8221;, message = &#8222;You must set shopping list name a value for string.&#8221;)})<br />
public HttpHeaders create(){<br />
String id = this.shoppingListRepository.create(this.list);<br />
returnnew DefaultHttpHeaders(&#8222;create&#8221;).withStatus(201).setLocationId(id.toString());<br />
}</p>
<p>Nad wyraz prosta (jak cała aplikacja) metoda składa się z 3 części:</p>
<ol>
<li>ustawienie walidatora tak by wymagał podania nazwy listy</li>
<li>przesłanie listy (z wypełnionym polem nazwy) do repozytorium w celu zapisania w bazie</li>
<li>zwrócenie nagłówków ze statusem 201 (CREATED) oraz identyfikatorem listy w celu przejścia do strony z listą</li>
</ol>
<p>Metodę tą możemy wywołać na 3 sposoby, poprzez wypełnienie formularza na stronie oraz wciśnięcie przycisku, poprzez wysłanie zapytania w formie XML-a (metodą <strong>CREATE</strong>) pod adres http://example.com/shopping-list.xml lub wysłanie zapytania w formie JSON (również <strong>CREATE</strong>) pod ten sam adres lecz z rozszerzeniem json.</p>
<p>Po wywołaniu tej metody zostajemy automatycznie przekierowani pod adres <em>http://example.com/shopping-list/ID.xhtml</em> który wywołuje metodę show.<br />
Strona z listą zakupów prezentuje się jak poniżej:</p>
<div id="attachment_1376" class="wp-caption aligncenter" style="width: 310px"><a href="http://www1.darekzon.com/wp-content/uploads/2011/09/Shopping-list-Testowa-1.jpg" rel="lightbox[1366]"><img class="size-medium wp-image-1376" title="Shopping list - Testowa-1" src="http://www1.darekzon.com/wp-content/uploads/2011/09/Shopping-list-Testowa-1-300x230.jpg" alt="" width="300" height="230" /></a><p class="wp-caption-text">Lista zakupowa</p></div>
<pre class="brush: java; title: ; notranslate">

public HttpHeaders show(){
 if(this.list == null){
 returnnew DefaultHttpHeaders(&quot;notfound&quot;).withStatus(404);
 }
 returnnew DefaultHttpHeaders(&quot;show&quot;).withStatus(200);
 }
</pre>
<p>W metodzie tej sprawdzamy jedynie czy lista istnieje, jeśli nie, generujemy informację o braku listy (jak w metodzie index) oraz zwracamy status 404 (<strong>NOT FOUND</strong>), w innym przypadku wyświetlamy listę oraz zwracamy status 200 (OK).</p>
<h4>Dodawanie produktów</h4>
<p>Dodawanie produktów następuje poprzez wysłanie formularza z nazwą produktu oraz ilością jaką chcemy kupić metodą POST do klasy ProductController co ma insynuować tworzenie nowego Produktu gdy tak naprawdę będziemy jedynie aktualizować naszą listę. Poniżej znajduje się wynik wysłania formularza.</p>
<div id="attachment_1378" class="wp-caption aligncenter" style="width: 310px"><a href="http://www3.darekzon.com/wp-content/uploads/2011/09/Dodawanie-produktu-do-listy-1.jpg" rel="lightbox[1366]"><img class="size-medium wp-image-1378" title="Dodawanie produktu do listy" src="http://www3.darekzon.com/wp-content/uploads/2011/09/Dodawanie-produktu-do-listy-1-300x150.jpg" alt="" width="300" height="150" /></a><p class="wp-caption-text">Dodawanie produktu do listy</p></div>
<p>Po dodaniu produktu wysyłamy status 204 (<strong>NO CONTENT</strong>) ponieważ nie chcemy wysyłać niczego, zamiast tego odświeżamy naszą stronę dzięki czemu dostajemy świeże dane. Gdybyśmy zamiast tego chcieli wysłać naszą listę i odświeżyć ją poprzez javascript musimy wysłać status 200 (<strong>OK</strong>)</p>
<h4>Kasowanie produktów</h4>
<p>Aby wykasować produkt z listy należy kliknąć w ikonę koszyka która pojawia się po najechaniu na nasz produkt. Po kliknięciu javascript automatycznie wyśle żądanie typu <strong>DELETE</strong> w odpowiedzi dostając status taki sam jak przy dodawaniu.</p>
<h4>Inne formaty</h4>
<p>Aby zobaczyć naszą listę zakupową w innym formacie wystarczy otworzyć stronę z rozszerzeniem XML:</p>
<div id="attachment_1379" class="wp-caption aligncenter" style="width: 310px"><a href="http://www1.darekzon.com/wp-content/uploads/2011/09/localhost_8080_shopping-list__shopping-list_4e84c6a230049d8994e8a74f.xml_.jpg" rel="lightbox[1366]"><img class="size-medium wp-image-1379" title="Lista zakupowa w formacie XML" src="http://www1.darekzon.com/wp-content/uploads/2011/09/localhost_8080_shopping-list__shopping-list_4e84c6a230049d8994e8a74f.xml_-300x189.jpg" alt="" width="300" height="189" /></a><p class="wp-caption-text">Lista zakupowa w formacie XML</p></div>
<p>bądź JSON:</p>
<div id="attachment_1380" class="wp-caption aligncenter" style="width: 310px"><a href="http://www1.darekzon.com/wp-content/uploads/2011/09/localhost_8080_shopping-list__shopping-list_4e84c6a230049d8994e8a74f.json_.jpg" rel="lightbox[1366]"><img class="size-medium wp-image-1380" title="Lista zakupowa w formacie JSON" src="http://www1.darekzon.com/wp-content/uploads/2011/09/localhost_8080_shopping-list__shopping-list_4e84c6a230049d8994e8a74f.json_-300x189.jpg" alt="" width="300" height="189" /></a><p class="wp-caption-text">Lista zakupowa w formacie JSON</p></div>
<p>Dzięki temu możemy zintegrować naszą aplikację z aplikacjami zewnętrznymi bez zbędnego nakładu pracy.</p>
<h4>Podobne tematy</h4>
<ol>
<li>Podobny tutorial: <a title="Struts2 rest web app" href="http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/" target="_blank">http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/</a></li>
<li>Hypertext Transfer Protocol: <a title="Hypertext Transfer Protocol" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" target="_blank">http://www.w3.org/Protocols/rfc2616/rfc2616.html</a></li>
<li>Nieco krytycznie o REST: <a title="Rest to zuo" href="http://michalorman.pl/blog/2011/02/bullshit-bingo-rest-i-restful/" target="_blank">http://michalorman.pl/blog/2011/02/bullshit-bingo-rest-i-restful/</a></li>
<li>Prezentacja na temat REST: <a title="Usługi sieciowe REST" href="https://www.soa.edu.pl/c/document_library/get_file?uuid=46b0faf6-6743-4184-ab16-dbddfd413685&amp;groupId=10122" target="_blank">https://www.soa.edu.pl/c/document_library/get_file?uuid=46b0faf6-6743-4184-ab16-dbddfd413685&amp;groupId=10122</a></li>
</ol>
<div class="shr-publisher-1366"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/09/prosta-aplikacja-restful-w-struts2-convention-i-rest-plugin-guice-i-mongodb/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nauka wielozadaniowości z IBM</title>
		<link>http://darekzon.com/2011/09/nauka-wielozadaniowosci-z-ibm</link>
		<comments>http://darekzon.com/2011/09/nauka-wielozadaniowosci-z-ibm#comments</comments>
		<pubDate>Sun, 18 Sep 2011 18:09:27 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[kurs]]></category>
		<category><![CDATA[wątki]]></category>
		<category><![CDATA[wielowątkowość]]></category>
		<category><![CDATA[współbierzność]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1359</guid>
		<description><![CDATA[Jakiś czas temu IBM wypuścił mały poradnik jak tworzyć aplikacje wielozadaniowe, co zrobić by uchronić się przed deadlock-ami, co zrobić by nie stracić wydajności naszej aplikacji. Wszystko to napisane przystępnym językiem wraz z masą przykładowego kodu. Kurs dostępny jest pod adrese,: http://www.ibm.com/developerworks/training/kp/j-kp-concurrency/index.html?ca=drs-]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Jakiś czas temu IBM wypuścił mały poradnik jak tworzyć aplikacje wielozadaniowe, co zrobić by uchronić się przed deadlock-ami, co zrobić by nie stracić wydajności naszej aplikacji.<br />
Wszystko to napisane przystępnym językiem wraz z masą przykładowego kodu.</p>
<p>Kurs dostępny jest pod adrese,: <a title="Java concurrency - IBM" href="http://www.ibm.com/developerworks/training/kp/j-kp-concurrency/index.html?ca=drs-" target="_blank">http://www.ibm.com/developerworks/training/kp/j-kp-concurrency/index.html?ca=drs-</a></p>
<div class="shr-publisher-1359"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/09/nauka-wielozadaniowosci-z-ibm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wysyłanie wiadomości w Javie: JavaMail i Gmail</title>
		<link>http://darekzon.com/2011/09/wysylanie-wiadomosci-w-javie-javamail-i-gmail</link>
		<comments>http://darekzon.com/2011/09/wysylanie-wiadomosci-w-javie-javamail-i-gmail#comments</comments>
		<pubDate>Sun, 11 Sep 2011 10:53:18 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[javax.mail]]></category>
		<category><![CDATA[mail]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1353</guid>
		<description><![CDATA[Bardzo często chcemy aby nasza aplikacja miała możliwość wysyłania maili, czy to aby wysłać mail aktywacyjny dla nowo zarejestrowanych użytkowników czy też w postaci formularza kontaktowego. Na szczęście biblioteki Java zawierają w sobie klasy dzięki którym bardzo łatwo osiągniemy nasz &#8230; <a href="http://darekzon.com/2011/09/wysylanie-wiadomosci-w-javie-javamail-i-gmail">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Bardzo często chcemy aby nasza aplikacja miała możliwość wysyłania maili, czy to aby wysłać mail aktywacyjny dla nowo zarejestrowanych użytkowników czy też w postaci formularza kontaktowego. Na szczęście biblioteki Java zawierają w sobie klasy dzięki którym bardzo łatwo osiągniemy nasz cel. Jeśli nie mamy własnego serwera który odpowiedzialnyby był za wysyłanie poczty możemy użyć do tego celu serwerów Google i usługi Gmail.</p>
<p><span id="more-1353"></span></p>
<p>Aby wysyłać maile w aplikacjach javowych potrzebujemy biblioteki Javax Mail, możemy ją dodać poprzez zależności w maven-ie:</p>
<pre class="brush: xml; title: ; notranslate">

&lt;dependency&gt;

&lt;groupId&gt;javax.mail&lt;/groupId&gt;

&lt;artifactId&gt;mail&lt;/artifactId&gt;

&lt;version&gt;1.4.1&lt;/version&gt;

&lt;type&gt;jar&lt;/type&gt;

&lt;scope&gt;compile&lt;/scope&gt;

&lt;/dependency&gt;
</pre>
<p>lub pobierając ze <a title="Oracle JavaxMail" href="http://www.oracle.com/technetwork/java/javamail/index.html">strony projektu</a>.</p>
<p>Po pobraniu i dołączeniu bibliotek do naszego projektu musimy skonfigurować połączenie z serwerem smtp (odpowiedzialnym za wysyłanie maili), aby to zrobić tworzymy plik konfiguracyjny.</p>
<p>Plik &#8222;<em>mail.properties</em>&#8221; zawierający ustawienia umieszczamy w folderze głównym zawierającym źródła tak aby był łatwy do znalezienia, jego zawartość powinna wyglądać następująco:</p>
<pre class="brush: plain; title: ; notranslate">
mail.smtp.host= smtp.gmail.com
mail.smtp.port= 587
mail.smtp.auth= true
mail.smtp.starttls.enable = true
mail.smtp.quitwait= false
mail.user= username
mail.password = password
mail.encoding= &quot;utf8&quot;
mail.debug= false
</pre>
<p>W powyższym pliku ustawiamy host, port oraz dane autoryzacyjne. Opcja <em>mail.smtp.starttls.enable=true</em> wymusza na aplikacji aby używała operacji <strong><em>StartTLS</em></strong> która to ustanawia szyfrowanie <strong>TLS</strong> w połączeniu sieciowym.<br />
Opcja <em>mail.smtp.quitwait</em> odpowiada za rozłączanie się z serwerem, w normalnych warunkach, nasza aplikacja wysyła polecenie <strong>QUIT</strong> i czeka na potwierdzenie rozłączenia, my nie musimy czekać, więc zaraz po wysłaniu polecenia rozłączamy się od serwera.<br />
Mając plik konfiguracyjny potrzebujemy kodu który go wczyta i utworzy sesje mailową która odpowiada za wysłanie wiadomości., robimy to wykorzystując mechanizmy Javy a dokładniej klasę Properties</p>
<pre class="brush: java; title: ; notranslate">

Properties properties = new Properties();

try {

properties.load(this.getClass().getResourceAsStream(&quot;/mail.properties&quot;));
} catch (IOException e) {
e.printStackTrace();
 throw new RuntimeException(&quot;Fatal error&quot;);
}
</pre>
<p>Jeśli mamy wczytane ustawienia możemy przejść do wysyłania maila. Aby to zrobić tworzymy nową sesję (połączenie z serwerem smtp) oraz wiadomość.</p>
<p><span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;">
<pre class="brush: java; title: ; notranslate">&lt;/span&gt;
&lt;pre&gt;
Session session = Session.getInstance(properties);

MimeMessage mm = new MimeMessage(session);

try {
    mm.setFrom(new InternetAddress(properties.getProperty(&quot;ADRES_NADAWCY@example.com&quot;),properties.get Property(&quot;NAZWA_NADAWCY&quot;)));
    mm.setRecipient(Message.RecipientType.TO, new InternetAddress(&quot;ADRES_ODBIORCY@example.com&quot;,&quot;NAZWA_ODBIORCY&quot;));
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

mm.setText(&quot;WIADOMOSC&quot;);
mm.setSubject(&quot;TEMAT_MAILA&quot;);
Transport t = session.getTransport(&quot;smtp&quot;);
t.connect(this.getProperty(&quot;mail.user&quot;),this.getProperty(&quot;mail.password&quot;));
t.sendMessage(mm, mm.getAllRecipients());
</pre>
<p>Wszystko powinno działać od ręki, z tego co pamiętam, Gmail ma ograniczenie do 500 maili dziennie (w darmowej usłudze) o czym trzeba pamiętać, choć możliwe, że już się to zmieniło.</p>
<div class="shr-publisher-1353"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/09/wysylanie-wiadomosci-w-javie-javamail-i-gmail/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Książka: Wielkie umysły programowania</title>
		<link>http://darekzon.com/2011/09/ksiazka-wielkie-umysly-programowania</link>
		<comments>http://darekzon.com/2011/09/ksiazka-wielkie-umysly-programowania#comments</comments>
		<pubDate>Sat, 10 Sep 2011 21:35:42 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Książki]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[książki]]></category>
		<category><![CDATA[programowanie]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1344</guid>
		<description><![CDATA[Czego James Gosling używa do debugowania? Jaka jest przyszłość C++? Dlaczego język SQL stał się popularny? Jaką opinię na temat mechanizmu odśmiecania ma Brad Cox? Odpowiedzi na te oraz wiele innych ciekawych pytań można znaleźć w książce &#8222;Wielkie umysły programowania&#8221; &#8230; <a href="http://darekzon.com/2011/09/ksiazka-wielkie-umysly-programowania">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p><a href="http://www3.darekzon.com/wp-content/uploads/2011/09/wieumy.jpg" rel="lightbox[1344]"><img class="alignleft size-full wp-image-1345" style="padding: 5px 10px 10px 0px;" title="Wielkie umysły programowania" src="http://www3.darekzon.com/wp-content/uploads/2011/09/wieumy.jpg" alt="" width="125" height="163" /></a>Czego <a title="James Gosling na Wikipedii" href="http://pl.wikipedia.org/wiki/James_Gosling">James Gosling</a> używa do debugowania? Jaka jest przyszłość C++? Dlaczego język SQL stał się popularny? Jaką opinię na temat mechanizmu odśmiecania ma <a title="Brad Cox na Wikipedii" href="http://en.wikipedia.org/wiki/Brad_Cox">Brad Cox</a>?<br />
Odpowiedzi na te oraz wiele innych ciekawych pytań można znaleźć w książce &#8222;Wielkie umysły programowania&#8221; którą napisali Federico Biancuzzi oraz Shane Warden.</p>
<p><span id="more-1344"></span></p>
<p>Książa napisana jest w formie rozmowy/wywiadu, czytając ją można zauważyć, że autorzy bardzo dobrze przygotowali się do przepytania każdego z bohaterów. Z samej książki możemy dowiedzieć się wielu zaskakujących rzeczy o procesie powstawania i rozwoju języków oraz o problemach z jakimi napotykali się ich autorzy. Nie będę zdradzał szczegółów, jedynie zaproszę do czytania.</p>
<p>Książkę polecam każdemu programiście, nie jako lekturę która wniesie dodatkową wiedzę z konkretnego zakresu, raczej jako odskocznię i relaks od wydań typowo technicznych jednak ciągle znajdującą się w okolicach okołoinformatycznych.</p>
<div class="shr-publisher-1344"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/09/ksiazka-wielkie-umysly-programowania/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Gosling odchodzi z Google</title>
		<link>http://darekzon.com/2011/08/gosling-odchodzi-z-google</link>
		<comments>http://darekzon.com/2011/08/gosling-odchodzi-z-google#comments</comments>
		<pubDate>Wed, 31 Aug 2011 19:58:17 +0000</pubDate>
		<dc:creator>darek</dc:creator>
				<category><![CDATA[Inne javove]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[gosling]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[sun]]></category>

		<guid isPermaLink="false">http://darekzon.com/?p=1341</guid>
		<description><![CDATA[Jak podają chyba wszystkie zagraniczne blogi twórca Javy James Gosling opuścił firmę Google (do której przeszedł po przejęciu Sun-a przez Oracle). Jak głosza plotki pan Gosling zajął stanowisko głównego architekta oprogramowania w firmie Liquid Robotics która zajmuje się tworzeniem robotów oceanicznych. &#8230; <a href="http://darekzon.com/2011/08/gosling-odchodzi-z-google">kontynuuj czytanie <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop Automatic --><!-- End Shareaholic LikeButtonSetTop Automatic --><p>Jak podają chyba wszystkie zagraniczne blogi twórca Javy James Gosling opuścił firmę Google (do której przeszedł po przejęciu Sun-a przez Oracle). Jak głosza plotki pan Gosling zajął stanowisko głównego architekta oprogramowania w firmie <a title="Strona firmy Liquid Robotics" href="http://liquidr.com/" target="_blank">Liquid Robotics</a> która zajmuje się tworzeniem robotów oceanicznych.</p>
<p>Więcej możecie przeczytać w źródłach:</p>
<ol>
<li><a title="Java founder Gosling leaves google" href="http://www.infoworld.com/d/the-industry-standard/java-founder-gosling-leaves-google-startup-171199" target="_blank">Infoworld - Java founder Gosling leaves Google for startup<br />
</a></li>
<li><a title="Java founder Gosling leaves google" href="http://liquidr.com/files/2011/08/JamesGosling_8_30_11.pdf&quot;" target="_blank">Liquid Robotics &#8211; James Gosling joins Liquid Robotics</a></li>
</ol>
<div class="shr-publisher-1341"></div><!-- Start Shareaholic LikeButtonSetBottom Automatic --><!-- End Shareaholic LikeButtonSetBottom Automatic -->]]></content:encoded>
			<wfw:commentRss>http://darekzon.com/2011/08/gosling-odchodzi-z-google/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

