<?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>Blog Technologiczny ATENA &#187; Java</title>
	<atom:link href="http://blog.atena.pl/category/java/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.atena.pl</link>
	<description>JavaEE, AJAX, xHTML, RIA, JBoss</description>
	<lastBuildDate>Fri, 20 Jan 2012 11:18:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>JavaFx 2.0</title>
		<link>http://blog.atena.pl/javafx-2-0</link>
		<comments>http://blog.atena.pl/javafx-2-0#comments</comments>
		<pubDate>Fri, 14 Oct 2011 06:02:28 +0000</pubDate>
		<dc:creator>Mateusz Lachowicz</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaFX]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1556</guid>
		<description><![CDATA[Jakiś czas temu opisywaliśmy w naszym blogu technologię JavaFX w wersji 1.3 ( http://blog.atena.pl/wprawki-w-javafx ) . Technologie zmieniają się jednak szybciej niż cokolwiek innego i obecnie JavaFx już nie jest językiem skryptowym. Aplikacje stworzone w tej technologii mogą być kompilowane i uruchamiane tak samo jak zwykłe aplikacje Java. Instalacja JavaFX 2.0 Pobieramy i instalujemy JavaFx [...]]]></description>
			<content:encoded><![CDATA[<p>Jakiś czas temu opisywaliśmy w naszym blogu technologię JavaFX w wersji 1.3 ( <a href="http://blog.atena.pl/wprawki-w-javafx">http://blog.atena.pl/wprawki-w-javafx</a> ) . Technologie zmieniają się jednak szybciej niż cokolwiek innego i obecnie JavaFx już nie jest językiem skryptowym. Aplikacje stworzone w tej technologii mogą być kompilowane i uruchamiane tak samo jak zwykłe aplikacje Java.<br />
<span id="more-1556"></span></p>
<h2>Instalacja JavaFX 2.0</h2>
<ol>
<li>Pobieramy i instalujemy JavaFx SDK 2.0 wraz z JavaFx 2.0 Runtime<br />
<a href="http://www.oracle.com/technetwork/java/javafx/downloads/index.html">http://www.oracle.com/technetwork/java/javafx/downloads/index.html</a></li>
<li>Pobieramy i instalujemy  narzędzie Netbeans. Wersja Netbeans 7.1 Beta zawiera w sobie plugin do obsługi JavaFx 2.0. Jeśli chcemy używać starszej wersji Nebeans, musimy go sami zainstalować.<br />
<a href="http://dlc.sun.com.edgesuite.net/netbeans/7.1/beta/">http://dlc.sun.com.edgesuite.net/netbeans/7.1/beta/</a>
</li>
</ol>
<h2>Przykładowy program w JavaFX 2.0</h2>
<p>Aby porównać JavaFx 2.0 z jej poprzednimi wersjami, stworzymy prosty kalkulator, który w JavaFx 1.3 został już opublikowany w naszym blogu.<br />
Procedura zakładania nowego projektu nie zmieniła się.</p>
<ol>
<li>Tworzymy nowy projekt JavaFX Application:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2011/10/JavaFX2_proj.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2011/10/JavaFX2_proj.jpg" alt="" width="478" height="331" class="aligncenter size-full wp-image-1572" /></a></li>
<li>Uzupełniamy dane o projekcie i wybieramy Finish:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2011/10/JavaFX2_proj2.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2011/10/JavaFX2_proj2.jpg" alt="" width="506" height="334" class="aligncenter size-full wp-image-1573" /></a></li>
</ol>
<h2>Deklaracja nowego okna w JavaFX 2.0 oraz JavaFX 1.3</h2>
<ul>
<li>W JavaFX 1.3 deklaracja nowej sceny wyglądała następująco:
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Stage {<br />
&nbsp; &nbsp; title: &quot;JavaFX quick calculator!&quot;<br />
&nbsp; &nbsp; scene: Scene {<br />
&nbsp; &nbsp; &nbsp; &nbsp; width: 130<br />
&nbsp; &nbsp; &nbsp; &nbsp; height: 150<br />
&nbsp; &nbsp; &nbsp; &nbsp; content: [<br />
&nbsp; &nbsp; &nbsp; &nbsp; ] //Zawartość Sceny<br />
&nbsp; &nbsp; } <br />
}</div></td></tr></tbody></table></div>
</li>
<li>W nowej JavaFX 2.0 deklaracja ta wygląda zupełnie inaczej:
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public class Calculator extends Application { &nbsp; &nbsp;<br />
&nbsp; &nbsp; public static void main(String[] args) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; Application.launch(args);<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; public void start(Stage primaryStage) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; primaryStage.setTitle(&quot;Calculator&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp; Scene scene = new Scene(?zawartość?, 130, 150);<br />
&nbsp; &nbsp; &nbsp; &nbsp; primaryStage.setScene(scene);<br />
&nbsp; &nbsp; &nbsp; &nbsp; primaryStage.show();<br />
&nbsp; &nbsp; }<br />
}</div></td></tr></tbody></table></div>
</li>
</ul>
<p>A oto deklaracja przykładowych elementów projektu „Kalkulator”:</p>
<ul>
<li>JavaFX 1.3:
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TextBox{<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; layoutX:2;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; layoutY:2;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; height:20;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width:120;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: bind currResult.toString();<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; editable:false;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
<br />
Button{<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; layoutX:2;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; layoutY:25;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text:&quot;1&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width:20;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; height:20;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onMouseClicked:function (e:MouseEvent){<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(not funcDefined){<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;firstElem=firstElem*10+1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;currResult=firstElem;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else{<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;secondElem=secondElem*10+1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div></td></tr></tbody></table></div>
</li>
<li>JavaFX 2.0:
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TextField ekran = new TextField();<br />
&nbsp;ekran.setEditable(false);<br />
&nbsp;ekran.setPrefSize(120, 20);<br />
<br />
Button przycisk = new Button(&quot;0&quot;);<br />
przycisk.setPrefSize(30,30);<br />
przycisk.setOnAction(new EventHandler() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override public void handle(ActionEvent e) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(functionset){<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; secondnumber=secondnumber*10;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ekran.setText(secondnumber.toString());<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else{<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; firstnumber=firstnumber*10;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ekran.setText(firstnumber.toString());<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });</div></td></tr></tbody></table></div>
</li>
</ul>
<h2>Kalkulator</h2>
<p>Projekt Kalkulatora możemy pobrać <a href='http://blog.atena.pl/wp-content/uploads/2011/10/Calculator.zip'>tutaj</a>.</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2011/10/calc.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2011/10/calc.jpg" alt="" width="368" height="434" class="aligncenter size-full wp-image-1588" /></a></p>
<h2>Podsumowanie</h2>
<ul>
<li>JavaFX 2.0 nie wymaga od programistów zagłębiania wiedzy o nowym języku skryptowym, jak miało to miejsce w JavaFX 1.3. Programiści języka Java z powodzeniem mogą wykorzystać swoje umiejętności oraz narzędzia do tworzenia aplikacji w JavaFX 2.0.</li>
<li>Wszystkie aplikacje stworzone w JavaFX 2.0 zachowują się tak samo w różnych środowiskach.</li>
<li>Możliwość wykorzystania wszystkich istniejących bibliotek JAVA.</li>
<li>Istniejące aplikacje SWING mogą być w prosty sposób aktualizowane z użyciem JavaFX 2.0. </li>
<li>JavaFX jest instalowana wraz z Java Runtime Environment, co umożliwia uruchomienie aplikacji na prawie wszystkich komputerach.</li>
<li>JavaFX dostarcza wszystkie najważniejsze kontrolki UI oraz umożliwia dostosowanie ich wyglądu z wykorzystaniem CSS.</li>
</ul>
<h2>Źródła</h2>
<ul>
<li><a href="http://blog.atena.pl/wprawki-w-javafx">http://blog.atena.pl/wprawki-w-javafx </a>JavaFX 1.3</li>
<li><a href="http://download.oracle.com/javafx/index.html">http://download.oracle.com/javafx/index.html</a> Dokumentacja JavaFX 2.0
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/javafx-2-0/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JBoss + LDAP</title>
		<link>http://blog.atena.pl/jboss-ldap</link>
		<comments>http://blog.atena.pl/jboss-ldap#comments</comments>
		<pubDate>Thu, 06 Oct 2011 12:25:09 +0000</pubDate>
		<dc:creator>Michał Łaguna</dc:creator>
				<category><![CDATA[JBoss]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaEE]]></category>
		<category><![CDATA[autentykacja]]></category>
		<category><![CDATA[autoryzacja]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[uwierzytelnianie]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1535</guid>
		<description><![CDATA[Jak skonfigurować w JBossie uwierzytelnianie i autoryzację opartą o LDAP ? Na początek przykładowa aplikacja Na potrzeby testów stwórzmy sobie prościutką aplikację i umieśćmy ją na JBossie. Najprościej będzie użyć do tego celu mechanizmu archetypów Mavena: mvn archetype:generate wybierzmy webapp-jee5 wybierzmy wersję 1.0 wskażmy groupId – np. pl.atena wskażmy artifactId – np. ldap-integration wskażmy version [...]]]></description>
			<content:encoded><![CDATA[<p>Jak skonfigurować w JBossie uwierzytelnianie i autoryzację opartą o LDAP ?</p>
<p><span id="more-1535"></span></p>
<h2>Na początek przykładowa aplikacja</h2>
<p>Na potrzeby testów stwórzmy sobie prościutką aplikację i umieśćmy ją na JBossie.</p>
<p>Najprościej będzie użyć do tego celu mechanizmu archetypów Mavena:</p>
<pre><strong>mvn archetype:generate</strong>
wybierzmy webapp-jee5
wybierzmy wersję 1.0
wskażmy groupId – np. pl.atena
wskażmy artifactId – np. ldap-integration
wskażmy version – np. 1.0-SNAPSHOT
wskażmy pakiet – np. pl.atena.ldap</pre>
<p>Po zatwierdzeniu powinniśmy mieć gotowy do deployu projekt.</p>
<p>Wystarczy go zbudować</p>
<pre><strong>mvn clean package</strong></pre>
<p>i skopiować do katalogu <strong>JBOSS/server/default/deploy</strong></p>
<p>Po uruchomieniu serwera i wejściu na stronę <a href="http://localhost:8080/ldap-integration">http://localhost:8080/ldap-integration</a> powinniśmy zobaczyć „Hello World”.</p>
<h2>Konfiguracja modułu uwierzytelniania w JBossie</h2>
<p>Kolejnym krokiem będzie konfiguracja uwierzytelniania w JBossie. W tym celu edytujemy plik <strong>JBOSS/Server/default/login-config.xml</strong> i dodajemy w nim nową politykę bezpieczeństwa, którą nazwiemy ldap:</p>
<pre>&lt;application-policy name="ldap"&gt;
  &lt;authentication&gt;
    &lt;login-module code="<strong>org.jboss.security.auth.spi.LdapExtLoginModule</strong>" flag="required" &gt;
      &lt;module-option&gt;<strong>ldap://serwerLdap:389</strong>&lt;/module-option&gt;
      &lt;module-option&gt;<strong>ATENA\ldapUser</strong>&lt;/module-option&gt;
      &lt;module-option&gt;<strong>password</strong>&lt;/module-option&gt;

      &lt;module-option name="baseCtxDN"&gt;<strong>CN=Users,DC=companyName,DC=com</strong>&lt;/module-option&gt;
      &lt;module-option name="baseFilter"&gt;<strong>(sAMAccountName={0})</strong>&lt;/module-option&gt;

      &lt;module-option&gt;<strong>OU=Groups,DC=companyName,DC=com</strong>&lt;/module-option&gt;
      &lt;module-option name="matchOnUserDN"&gt;<strong>true</strong>&lt;/module-option&gt;
      &lt;module-option name="uidAttributeID"&gt;<strong>member</strong>&lt;/module-option&gt;
      &lt;module-option name="roleFilter"&gt;<strong>(member={1})</strong>&lt;/module-option&gt;
      &lt;module-option name="roleAttributeID"&gt;<strong>CN</strong>&lt;/module-option&gt;

      &lt;module-option name="roleRecursion"&gt;<strong>2</strong>&lt;/module-option&gt;
      &lt;module-option name="searchScope"&gt;<strong>SUBTREE_SCOPE</strong>&lt;/module-option&gt;

      &lt;module-option name="allowEmptyPasswords"&gt;<strong>false</strong>&lt;/module-option&gt;
    &lt;/login-module&gt;
  &lt;/authentication&gt;
&lt;/application-policy&gt;</pre>
<p><strong>Wyjaśnienie najważniejszych parametrów:</strong></p>
<ul>
<li>login-module      – wskazanie modułu uwierzytelniania – dla samego uwierzytelniania możemy      użyć LdapLoginModule; jeśli chcemy użyć również autoryzacji opartej o LDAP      musimy użyć LdapExtLoginModule</li>
<li>java.naming.provider.url      – namiary na kontroler domeny</li>
<li>bindDN      – nazwa użytkownika z uprawnieniami do wykonywania zapytań w LDAPie</li>
<li>bindCredential – hasło      użytkownika</li>
<li>baseCtxDN – ścieżka do      wyszukiwania użytkownika</li>
<li>baseFilter      – filtr służący do wyszukania uwierzytelnianego użytkownika</li>
<li>rolesCtxDN – ścieżka do      wyszukiwania roli</li>
<li>roleFilter      – filtr służący do wyszukania roli użytkownika</li>
<li>roleAttributeID      – wskazanie na miejsce w ścieżce gdzie będzie nazwa roli</li>
<li>roleRecursion      – głębokość wyszukiwania roli</li>
<li>searchScope      – zasięg wyszukiwania (OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE)</li>
<li>allowEmptyPasswords      – flaga wskazująca, czy puste hasła powinny być przekazywane do serwera      LDAPa (niektóre serwery LDAP traktują puste hasło jako zalogowanie      anonimowe)</li>
</ul>
<p><strong>Pełna lista parametrów dla modułu LdapExtLoginModeule dostępna jest pod adresem: </strong></p>
<p><a href="http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.2/html/Server_Configuration_Guide/Using_JBoss_Login_Modules-LdapExtLoginModule.html" target="_blank">http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.2/html/Server_Configuration_Guide/Using_JBoss_Login_Modules-LdapExtLoginModule.html</a></p>
<h2>Podpięcie uwierzytelniania do aplikacji</h2>
<p>Ostatnim krokiem jest podpięcie dodanej polityki do naszej aplikacji i zabezpieczenie dostępu do pewnych zasobów w aplikacji. W tym celu dodajemy w katalogu src/main/webapp/WEB-INF/ plik <strong>jboss-web.xml</strong> o następującej treści:</p>
<pre>&lt;jboss-web&gt;
  &lt;security-domain&gt;<strong>java:/jaas/ldap</strong>&lt;/security-domain&gt;
&lt;/jboss-web&gt;</pre>
<p>Następnie zabezpieczamy dostęp do aplikacji w pliku <strong>web.xml</strong>:</p>
<pre>&lt;web-app&gt;
  &lt;display-name&gt;<strong>Archetype Created Web Application</strong>&lt;/display-name&gt;
  &lt;security-constraint&gt;
    &lt;web-resource-collection&gt;
      &lt;web-resource-name&gt;<strong>LDAP Restricted Zone</strong>&lt;/web-resource-name&gt;
      &lt;url-pattern&gt;<strong>/*</strong>&lt;/url-pattern&gt;
    &lt;/web-resource-collection&gt;
    &lt;auth-constraint&gt;
      &lt;role-name&gt;<strong>administrator</strong>&lt;/role-name&gt;
    &lt;/auth-constraint&gt;
    &lt;/security-constraint&gt;
    &lt;login-config&gt;
      &lt;auth-method&gt;<strong>BASIC</strong>&lt;/auth-method&gt;
      &lt;realm-name&gt;<strong>LDAP Restricted Zone</strong>&lt;/realm-name&gt;
    &lt;/login-config&gt;
    &lt;security-role&gt;
      &lt;role-name&gt;<strong>administrator</strong>&lt;/role-name&gt;
    &lt;/security-role&gt;
&lt;/web-app&gt;</pre>
<p>Gdy ponownie wejdziemy na stronę naszej aplikacji (<a href="http://localhost:8080/ldap-integration">http://localhost:8080/ldap-integration</a>) powinniśmy zostać zapytani o login i hasło użytkownika. Po podaniu domenowego loginu i hasła powinniśmy ponownie zobaczyć nasze ‘Hello World’ – pod warunkiem, że jesteśmy w LDAPie przypisani do grupy <em>administrator</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/jboss-ldap/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wstęp do rozproszonej kontroli wersji na przykładzie Git’a</title>
		<link>http://blog.atena.pl/wstep-do-rozproszonej-kontroli-wersji-na-przykladzie-gita</link>
		<comments>http://blog.atena.pl/wstep-do-rozproszonej-kontroli-wersji-na-przykladzie-gita#comments</comments>
		<pubDate>Wed, 14 Sep 2011 06:16:51 +0000</pubDate>
		<dc:creator>Michał Łaguna</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Narzędzia]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[repozytorium rozproszone]]></category>
		<category><![CDATA[rozproszona kontrola wersji]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1481</guid>
		<description><![CDATA[W standardowych (centralnych) systemach wersjonowania mamy zazwyczaj jedno główne repozytorium kodu, z którego korzysta cały zespół. Praca w projekcie wiąże się z ciągłym pobieraniem i wgrywaniem zmian i w związku z tym wymaga stałego połączenia z jednym centralnym serwerem. Cała historia zmian trzymana jest w centralnym repozytorium, członkowie zespołu lokalnie posiadają jedynie kopię źródeł. Rozproszona [...]]]></description>
			<content:encoded><![CDATA[<p>W standardowych (centralnych) systemach wersjonowania mamy zazwyczaj jedno główne repozytorium kodu, z którego korzysta cały zespół. Praca w projekcie wiąże się z ciągłym pobieraniem i wgrywaniem zmian i w związku z tym wymaga stałego połączenia z jednym centralnym serwerem. Cała historia zmian trzymana jest w centralnym repozytorium, członkowie zespołu lokalnie posiadają jedynie kopię źródeł.</p>
<p>Rozproszona kontrola wersji jest zorganizowana w zupełnie inny sposób. Repozytoriów jest tyle ilu członków zespołu. Każdy z nich lokalnie posiada pełne źródła projektu wraz z historią zmian. <strong>Wszystkie repozytoria są równe – żadne z nich nie jest w żaden sposób wyróżnione.</strong> To, z którego repozytorium na przykład zbudujemy wersję jest sprawą czysto umowną.</p>
<p><span id="more-1481"></span>Rozpoczęcie pracy z projektem wiąże się ze stworzeniem nowej kopii projektu przez sklonowanie wybranego istniejącego repozytorium. Dalsza praca może odbywać się lokalnie. W wybranych momentach następuje scalanie zmian dokonywanych przez różnych członków zespołu.</p>
<h2>Co zyskujemy dzięki rozproszeniu?</h2>
<p>Przede wszystkim pracujemy lokalnie – tworzymy branche wtedy kiedy my ich potrzebujemy, nazywamy je tak jak chcemy (nie ma konfliktów nazw często spotykanych w repozytoriach centralnych), commitujemy zmiany kiedy uznamy jakąś część pracy za wykonaną. <strong>Pomimo pracy lokalnej jesteśmy cały czas pod kontrolą wersji</strong> – możemy zarządzać nawet małymi lokalnymi zmianami, które potencjalnie mogą zawierać błędy.</p>
<p><strong>Zarządzamy zmianami a nie wersjami</strong>. Wbrew pozorom to bardzo duża zmiana w podejściu do zarządzania kodem – zamiast zastanawiać się jak uaktualnić jedną wersję tak, żeby była taka sama jak inna &#8211; zarządzamy zmianami – mówimy więc ‘daj mi swój zestaw zmian’. Przy takim podejściu mergowanie zmian staje się codziennością w związku z czym musi być wydajne i bezproblemowe i takie właśnie jest. Dzięki temu pośrednio zyskujemy też silne wsparcie dla nieliniowego rozwoju projektu.</p>
<p>Kompletny projekt wraz z historią zmian istnieje w wielu miejscach. Podczas zakładania (klonowania) projektu dostajemy pełną kopię repozytorium (wraz z historią zmian). Dzięki temu nie mamy jednego newralgicznego punktu, ale te same źródła w wielu miejscach.</p>
<h2>Systemy rozproszonego zarządzania wersjami</h2>
<p>Na rynku istnieje kilka systemów <strong>DVCS (Distributed Version Control System)</strong>. Do głównych należą darmowe Mercurial, Bazaar, Git oraz komercyjny BitKeeper. Nie ma dużych różnic projektowych pomiędzy nimi (być może poza sposobem synchronizacji), są za to znaczące różnice w implementacji, które wpływają na wydajność i komfort pracy. Ciekawostką jest to, ze Bazaar może pracować zarówno jako repozytorium rozproszone jak i w modelu z centralnym repozytorium.</p>
<p>Ze względu na rosnącą popularność Git’a proponuję pouczyć się co to jest DVCS na jego przykładzie.</p>
<h2>Git</h2>
<p><strong>Git jest szybkim rozproszonym systemem kontroli wersji dostępnym na licencji open source.</strong> Został zaprojektowany i pierwotnie stworzony przez Linusa Torvaldsa na potrzeby zarządzania źródłami jądra Linuxa.</p>
<p>Wśród głównych cech Git’a autorzy wymieniają to, że jest systemem rozproszonym, wspiera nieliniowy development, jest wydajny w dużych projektach oraz zapewnia spójność repozytorium przez zastosowanie algorytmów szyfrujących (SHA1).</p>
<h2>Instalacja</h2>
<p>Większość systemów linuxowych ma już gita w swoich repozytoriach pakietów (git-core). Wersję zbudowaną lub źródła można pobrać ze strony projektu (http://git-scm.com/download). Instalacja jest prosta i nie powinna przysporzyć problemów.</p>
<p>Po zainstalowaniu Git jest gotowy do zarządzania naszym kodem.</p>
<p>Jedyne co powinniśmy ustawić, to swoją nazwę użytkownika i e-mail:</p>
<pre>git config --global user.name Michal Laguna
git config --global user.email michal.laguna@atena.pl</pre>
<h2>Utworzenie repozytorium</h2>
<p>Po założeniu katalogu z projektem wykonujemy polecenie <em>git init</em>. Spowoduje to utworzenie repozytorium – w katalogu z projektem powinien powstać katalog .git.</p>
<pre>$git init
Initialized empty Git repository in /home/atena/repo1/.git</pre>
<p>Za pomocą polecenia git status możemy sprawdzić aktualny stan naszego repozytorium. Powinniśmy dostać odpowiedź podobną do tej:</p>
<pre>$git status
# On branch master
nothing to commit (working directory clean)</pre>
<h2>Dodanie/zmiana plików</h2>
<p>Pliki dodajemy i zmieniamy w repozytorium za pomocą polecenia add:</p>
<pre>$git add.
$git status
# On branch master
# Changes to be commited:
…
# new file: test1.txt</pre>
<h2>Zatwierdzenie zmian</h2>
<p>Wprowadzone zmiany zatwierdzamy za pomocą polecenia commit (uwaga: commit zatwierdza zmiany tylko w lokalnym repozytorium):</p>
<pre>$git commit –m ‘Poprawa bledu Abcd1234’
1 files changed, 1 insertion(+), 0 deletion(-)
create mode 100644 test1.txt</pre>
<h2>Historia zmian</h2>
<p>W dowolnej chwili można podejrzeć historię zmian za pomocą polecenia log:</p>
<pre>$git log</pre>
<p>Możemy podejrzeć również listę różnic:</p>
<pre>$git log –p</pre>
<h2>Branchowanie i mergowanie</h2>
<p>Stworzenie brancha jest tak proste jak wykonanie instrukcji git branch [nazwa brancha]. Żeby przełączyć się na brancha wykonujemy polecenie git checkout [nazwa brancha].</p>
<pre>$git branch xyz123
$git checkout xyz123
Switched to branch ‘xyz123’</pre>
<p>W dowolnej chwili możemy sprawdzić w jakim branchu aktualnie się znajdujemy (ten oznaczony gwiazdką):</p>
<pre>$git branch
master
* xyz123</pre>
<p>Dokonajmy teraz zmiany w naszym branchu xyz123 i dodajmy zmianę do brancha:</p>
<pre>$git add –m ‘Zmiana w branchu’
$git commit</pre>
<p>Powyższe dwie instrukcje możemy też zastąpić pojedynczą:</p>
<pre>$git commit –a –m ‘Zmiana w branchu’</pre>
<p>Po przejściu z powrotem do brancha głównego widzimy, że nie ma w nim wprowadzonych zmian:</p>
<pre>$git checkout master
$git log</pre>
<p>Możemy teraz dociągnąć zmiany za pomocą polecenia merge:</p>
<pre>$git merge xyz123</pre>
<p>Na koniec możemy podejrzeć drzewko zmian w narzędziu gitk</p>
<pre>$gitk</pre>
<p>I usunąć gałąź xyz123</p>
<pre>$git branch –d xyz123</pre>
<h2>Tagowanie</h2>
<p>Założenie taga to wykonanie polecenia Tag:</p>
<pre>$git tag 0.1.15</pre>
<p>Lista tagów:</p>
<pre>$git tag -l</pre>
<p>Następnie możemy stworzyć brancha z dowolnego taga:</p>
<pre>$git branch stable 0.1.15</pre>
<h2>Praca w zespole</h2>
<p>Jak już wiemy w pracy z rozproszonym systemem kontroli wersji <strong>wszystkie repozytoria są równe</strong>, a wskazanie repozytorium, z którego na przykład budujemy wersję lub uruchamiany testy jest <strong>tylko kwestią umowy</strong>.</p>
<p>Załóżmy, że pracujemy w dwuosobowym zespole (user1, user2). User2 tworzy swoje lokalne repozytorium przez sklonowanie repozytorium należącego do user1:</p>
<pre>$git clone git-repo-user1 git-repo-user2
Cloning into git-repo-user2…
done.</pre>
<p>Następnie user2 edytuje lokalnie jakieś pliki umieszcza je w swoim repozytorium:</p>
<pre>cd git-repo-user2
git commit –a –m ‘Zmiany user2’</pre>
<p>Gdy skończy może powiadomić usera1 o możliwości zaciągnięcia zmian – wtedy user1 może dociągnąć zmiany z repozytorium usera2 za pomocą polecenia pull:</p>
<pre>$git pull /home/atena/git-repo-user2 master</pre>
<p>Polecenie pull powoduje pobranie zmian ze wskazanego repozytorium i zmergowanie ich z naszym kodem (fetch + merge). Wskazane jest zacommitowanie wszystkich lokalnych zmian przed wykonaniem operacji pull – pozwoli to na bezproblemowe przeprowadzenie merge’a.</p>
<p>Istnieje możliwość ściągnięcia zmian z innego repozytorium bez ich mergowania – służy do tego polecenie fetch:</p>
<pre>$git fetch /home/atena/git-repo-user2 master
$git log –p HEAD..FETCH_HEAD
$git merge FETCH_HEAD</pre>
<p>Dla ułatwienia pracy można nadać alias zdalnemu repozytorium, z którym pracujemy:</p>
<pre>$git remote add user2 /home/atena/git-repo-user2</pre>
<p>Z poziomu swojego repozytorium możemy też ‘wepchać’ zmiany do repozytorium zdalnego – praca z Gitem przypomina wtedy pracę z repozytorium centralnym. Służy do tego polecenie push:</p>
<pre>$git push user2 master</pre>
<p>Co ważne – Git domyślnie nie pozwoli na wepchnięcie zmian do zdalnego repozytorium jeśli wskazany branch został w nim zacheckoutowany. Dostaniemy wtedy taki komunikat:</p>
<pre>error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.</pre>
<p>Możemy wtedy zrobić dwie rzeczy – albo w zdalnym repozytorium przejść (checkout) na inny branch lub przekształcić zdalne repozytorium w repozytorium centralne (bare), czyli takie, które zawiera jedynie katalog .git i nie zawiera żadnych zacheckoutowanych plików</p>
<pre>git config --bool core.bare true</pre>
<h2>Rebase</h2>
<p>Niniejszy artykuł jest jedynie wprowadzeniem do zagadnienia rozproszonego kontrolowania źródeł, ale ponieważ za przykład wzięliśmy Git’a nie sposób nie wspomnieć o jeszcze jednej bardzo wartościowej i silnej funkcjonalności którą dostarcza – rebase.</p>
<p>Rebase to w uproszczeniu przesunięcie miejsca utworzenia brancha. Załóżmy, że mamy w projekcie branch główny oraz jakiś dodatkowy z funkcjonalnością przygotowywaną dla konkretnego klienta. Jeśli chcemy aby branch dedykowany dla klienta zawierał wszystkie zmiany wrzucane do brancha głównego musimy dokonywać merge’y.</p>
<p>Git daje nam możliwość wykonania operacji rebase, która spowoduje przesunięcie miejsca utworzenia brancha:</p>
<pre>$git checkout clientX_branch
$git rebase origin</pre>
<p>Po takiej operacji Git zapisze wszystkie commity od momentu utworzenia brancha jako patche w katalogu .git/rebase, zaktualizuje brancha tak, żeby wskazywał aktualną wersję w branchu głównym i na koniec zaaplikuje odłożone patche. Dzięki temu historia zmian będzie serią commitów bez merge’y.</p>
<h2>Podsumowanie</h2>
<p>Rozproszone systemy zarządzania wersjami moim zdaniem w pewnym sensie <strong>definiują na nowo podejście do zarządzania kodem źródłowym</strong>. Skupienie się na zmianach zamiast na wersjach rozwiązało bardzo wiele problemów spotykanych w pracy z SVN’em czy CVS’em &#8211; branchowanie i mergowanie staje się standardowym elementem prowadzenia developmentu, a dzięki rozproszeniu <strong>repozytorium towarzyszy nam od pierwszej linijki kodu</strong>.</p>
<p>Z drugiej strony rozproszone systemy repozytorium kodu nie są żadną nowością, a moim zdaniem wciąż nie zyskały bardzo dużej popularności w projektach komercyjnych. Wydaje mi się,  że z punktu widzenia firmy rozproszenie repozytorium nie jest czymś niezbędnym &#8211; najczęściej przecież i tak potrzebujemy repozytorium centralnego, z którego automatycznie budujemy aktualną wersję i na przykład puszczamy testy jednostkowe. Tworzenie oprogramowania w firmie jest zazwyczaj prowadzone w sposób bardziej usystematyzowany niż w projektach tworzonych przez otwartą społeczność. Zakłada się, że wszyscy deweloperzy wykonują przydzielone zadania i wyniki ich pracy będą musiały się znaleźć w wersji. Czasem może nawet nie chcemy, żeby szeregowy developer mógł pobrać projekt wraz z kilkuletnią historią jego rozwoju.<br />
Pewnym problemem może być też wsparcie systemu kontroli wersji przez IDE. SVN czy CVS jest wszechobecny &#8211; większość narzędzi do projektowania i wytwarzania aplikacji bez względu na język programowania czy modelowania ma albo natywną obsługę albo przynajmniej wtyczki do obsługi najpopularniejszych systemów kontroli wersji. Niestety żaden z rozproszonych systemów kontroli wersji nie należy jeszcze do tych najpopularniejszych.</p>
<p>Jeśli chodzi o Git’a to jest bez wątpienia bardzo silnym narzędziem. Na dzień dzisiejszy wydaje się być dopracowanym projektem gotowym do użycia w komercyjnym projekcie. Nie jest jednak jedynym DVCS’em – moim zdaniem przed rozpoczęciem projektu warto rozpoznać konkurencję pod kątem naszych konkretnych potrzeb (np. chociażby pluginów do wybranych IDE).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/wstep-do-rozproszonej-kontroli-wersji-na-przykladzie-gita/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wprowadzenie do Maven&#8217;a</title>
		<link>http://blog.atena.pl/wprowadzenie-do-mavena</link>
		<comments>http://blog.atena.pl/wprowadzenie-do-mavena#comments</comments>
		<pubDate>Tue, 30 Aug 2011 05:57:54 +0000</pubDate>
		<dc:creator>Michał Łaguna</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaEE]]></category>
		<category><![CDATA[Narzędzia]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[mvn]]></category>
		<category><![CDATA[zarządzanie zależnościami]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1420</guid>
		<description><![CDATA[Wielką zaletą języka Java jest jego elastyczność. Oznacza to między innymi, że nikt nie mówi nam gdzie mają być nasze źródła, do jakiego katalogu mają trafić binarki ani gdzie mamy mieć umieszczone pliki propertiesów czy biblioteki zewnętrzne. Poza drobnymi ograniczeniami specyficznymi dla pewnych rodzajów rozwiązań możemy zazwyczaj sami zdefiniować praktycznie całą strukturę projektu według własnych [...]]]></description>
			<content:encoded><![CDATA[<p>Wielką zaletą języka Java jest jego elastyczność. Oznacza to między innymi, że nikt nie mówi nam gdzie mają być nasze źródła, do jakiego katalogu mają trafić binarki ani gdzie mamy mieć umieszczone pliki propertiesów czy biblioteki zewnętrzne. Poza drobnymi ograniczeniami specyficznymi dla pewnych rodzajów rozwiązań możemy zazwyczaj sami zdefiniować praktycznie całą strukturę projektu według własnych potrzeb i upodobań. Do tego mamy jeszcze dowolność w wyborze sposobu budowania aplikacji &#8211; możemy zbudować projekt z poziomu IDE, z linii poleceń lub użyć dedykowanych narzędzi do budowania.</p>
<p><span id="more-1420"></span></p>
<h2>Gdzie ja mam wrzucić te pliki?</h2>
<p>Ta wielka zaleta potrafi jednak obrócić się przeciwko nam. Ponieważ to projektanci i programiści definiują strukturę projektu i sposób budowania aplikacji trudno jest znaleźć dwa takie same projekty. Każdy, kto pracował w kilku projektach javowych, szczególnie wytwarzanych w ramach różnych zespołów prawdopodobnie spotkał się z opisywaną sytuacją. Wydaje mi się, że taki brak „szablonu projektu” może być problematyczny szczególnie dla młodszych programistów, którzy &#8211; przechodząc z projektu do projektu &#8211; mogą czuć się zagubieni.</p>
<h2>Wsparcie – Maven</h2>
<p>Z pomocą przychodzi Maven, czyli narzędzie do zarządzania projektem Javowym. Osobiście uważam Mavena za jeden z najbardziej przełomowych &#8216;wynalazków&#8217; świata Javowego.</p>
<p><strong>Maven zrodził się z potrzeby zdefiniowania standardowej struktury projektu, standardowego sposobu budowania aplikacji oraz sposobu definiowania zależności pomiędzy modułami projektu.</strong> Dzięki tej standaryzacji przejście pomiędzy projektami opartymi o Mavena jest wręcz przezroczyste &#8211; możemy skupić się na biznesowych problemach zamiast zastanawiać się nad tym jak to wszystko zbudować i skąd wziąć oraz gdzie wrzucić kolejnego JARka.</p>
<p>Budowanie oprogramowania przy użyciu Mavena oparte jest o cele. Każde wołanie powinno zakończyć osiągnięciem konkretnego celu. Może być nim np. kompilacja (compile), zbudowanie paczki (package) czy przeprowadzenie testów jednostkowych (test). Dostępne cele są określane przez wtyczki rozszerzające funkcjonalność Mavena. Konkretne cele mogą wymagać wykonania wcześniej jakiegoś innego celu (np. package musi być poprzedzony compile).</p>
<p>Projekt mavenowy definiuje się poprzez stworzenie i utrzymywanie pliku <strong>pom.xml</strong> (POM &#8211; ang. Project Object Model). Pom.xml jest głównym miejscem pracy z projektem i zawiera wszystkie istotne elementy definiujące projekt, jego strukturę, sposób budowania i przede wszystkim zależności.</p>
<p>Mavena można pobrać ze strony projektu http://maven.apache.org/download.html &#8211; nie wymaga on tak naprawdę żadnej instalacji &#8211; po rozpakowaniu należy jedynie ustawić zmienne środowiskowe: M2_HOME (wskazanie na katalog, do którego rozpakowaliśmy mavena), M2 (wskazanie na katalog [M2_HOME]/bin) i dodać katalog bin do zmiennej PATH (wskazanie na [M2_HOME]/bin).</p>
<h2>Struktura projektu</h2>
<p>Typowy projekt mavenowy ma strukturę taką, jak na poniższym diagramie:</p>
<pre>atena-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- pl
    |           `-- atena
    |               `-- app
    |                   `-- AtenaApp.java
    |   `-- resources
    |       `--META-INF
    |          `--application.properties
    `-- test
        `-- java
            `-- pl
                `-- atena
                    `-- app
                        `-- AtenaAppTest.java</pre>
<p>Sam plik pom.xml może wyglądać tak jak w poniższym fragmencie kodu:</p>
<pre>&lt;project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;pl.atena&lt;/groupId&gt;
  &lt;artifactId&gt;atena-app&lt;/artifactId&gt;
  &lt;packaging&gt;jar&lt;/packaging&gt;
  &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
  &lt;name&gt;Maven Quick Start Archetype&lt;/name&gt;
  &lt;url&gt;http://maven.apache.org&lt;/url&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;3.8.1&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/project&gt;</pre>
<p>Jest to bardzo prosty podstawowy plik pom.xml. Poniżej krótki opis poszczególnych sekcji pom’a:</p>
<ul>
<li><strong>groupId </strong>- twórcę (pl.atena),</li>
<li><strong>artifactId </strong>- nazwę aplikacji (atena-app),</li>
<li><strong>packaging </strong>- sposób pakowania (jar, war, ear),</li>
<li><strong>version </strong>- wersję,</li>
<li><strong>name </strong>- nazwę wyświetlaną</li>
<li><strong>url </strong>- link do strony projektu</li>
<li><strong>dependecies </strong>– zależności od innych modułów</li>
</ul>
<h2>Zakładanie i definiowanie projektu</h2>
<p>Projekt możemy zdefiniować ręcznie poprzez utworzenie wymaganej struktury katalogów oraz stworzenie pliku pom.xml. Nie ma tutaj żadnej magii – tak przygotowany projekt jest w pełni poprawnym projektem mavenowym. Takie tworzenie nie jest jednak zbyt przyjemne.</p>
<p>Z pomocą przychodzi mechanizm archetypów (a ściślej mówiąc plugin archetype), czyli tzw. szablony projektów. Poprzez wywołanie poniższej linii stworzymy kompletną strukturę prostego projektu wraz z podstawowym plikiem pom.xml:</p>
<pre>mvn archetype:generate -DgroupId=pl.atena -DartifactId=atena-app
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false</pre>
<p>Powyższa linia oznacza: wywołaj cel ‘generate’ z pluginu ‘archetype’ i stwórz projekt pl.atena.atena-app na podstawie szablonu maven-archetype-quickstart. W wyniku pracy mavena powinniśmy otrzymać katalog z projektem i prosty pom.xml.</p>
<p>Istnieje bardzo dużo gotowych szablonów, dzięki czemu możemy na przykład przez wywołanie takiego prostego polecenia stworzyć kompilujący się i gotowy do deployu projekt aplikacji webowej zgodny z JEE6.</p>
<h2>Budowanie projektu</h2>
<p>Jak już wcześniej wspominałem budowanie projektu to wykonywanie określonych celi. Jeśli chcemy np. skompilować projekt wykonujemy polecenie mvn compile z poziomu katalogu głównego projektu (czyli tam gdzie jest umieszczony plik pom.xml).</p>
<p>Możemy wykonać kilka celi po kolei – np.: mvn clean package spowoduje wyczyszczenie wyników wcześniejszych buildów i spakowanie od nowa projektu (poprzedzone kompilacją, gdyż package wywołuje najpierw compile).</p>
<h2>Cykl życia projektu</h2>
<p>Maven definiuje coś co nazywa się cykle życia projektu. Jest to zestaw standardowych najważniejszych z punktu widzenia aplikacji, bardzo precyzyjnie zdefiniowanych i wykonywanych w określonej kolejności faz. Błąd na dowolnym etapie zatrzymuje wykonywanie kolejnych faz w cyklu. Maven definiuje trzy cykle życia: <strong>default</strong>, <strong>clean </strong>i <strong>site</strong>.</p>
<p>Fazy domyślnego (<strong>default</strong>) cyklu życia:</p>
<ul>
<li><strong>validate </strong>- sprawdza poprawność projektu;</li>
<li><strong>compile </strong>- kompiluje kod źródłowy;</li>
<li><strong>test </strong>- wykonuje testy jednostkowe;</li>
<li><strong>package </strong>- pakuje skompilowany kod w paczki dystrybucyjne (np. Jar, war);</li>
<li><strong>integration</strong>-test &#8211; deployuje paczkę w środowisku testów integracyjnych;</li>
<li><strong>verify </strong>- sprawdza poprawność paczki;</li>
<li><strong>install </strong>- umieszcza paczkę w lokalnym repozytorium aby mogła być używana przez inne moduły;</li>
<li><strong>deploy </strong>- umieszcza (publikuje) paczkę w zdalnym repozytorium.</li>
</ul>
<p>Cykl życia <strong>clean </strong>czyści wynik działania wcześniejszych buildów.</p>
<p>Cykl życia <strong>site </strong>generuje dokumentację projektu.</p>
<p>Powyżej opisane fazy są tak naprawdę mapowane na konkretne cele. Na przykład package w przypadku projektu typu jar wywoła jar:jar, a w przypadku projektu typu war war:war.</p>
<h2>Pluginy</h2>
<p>Funkcjonalność Mavena może być rozszerzana przez pluginy. Wywoływanie celów zdefiniowanych w pluginach odbywa się poprzez wywołanie polecenia mvn [plugin]:[goal], gdzie plugin to nazwa wtyczki, a goal to wywoływany cel.</p>
<p>Użyliśmy tej konstrukcji tworząc projekt z szablonu (mvn archetype:generate).</p>
<p>Samo dodanie plugina do projektu odbywa się poprzez dodanie odpowiedniej definicji w pliku pom.xml. Taka zależność może wyglądać jak poniżej:</p>
<pre>&lt;build&gt;
  &lt;plugins&gt;
    &lt;plugin&gt;
      &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
      &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
      &lt;version&gt;2.0.2&lt;/version&gt;
      &lt;configuration&gt;
        &lt;source&gt;1.5&lt;/source&gt;
        &lt;target&gt;1.5&lt;/target&gt;
      &lt;/configuration&gt;
    &lt;/plugin&gt;
  &lt;/plugins&gt;
&lt;/build&gt;</pre>
<h2>Zależności</h2>
<p>Zarządzanie zależnościami bywa trudne nawet w małym projekcie, a w projekcie dużym i złożonym bywa zadaniem bardzo wyczerpującym.</p>
<p>Prawdopodobnie każdy z nas niejednokrotnie wyszukiwał w google’u jakichś JARków i próbował je ściągać z przypadkowych stron. Ponadto pracując w projekcie złożonym z kilku modułów bardzo często napotykamy problem dostarczania coraz to nowszej wersji modułu do innego obszaru projektu. W tych problemach z pomocą ponownie przychodzi Maven. Zarządzanie zależnościami jest chyba tym z czego Maven tak naprawdę słynie najbardziej.</p>
<p>Dodanie zależności sprowadza się do dodanie elementu dependency w pliku pom.xml. W elemencie dependency wkazujemy dostawcę (groupId), nazwę modułu (artifactId), wersję (version) i zasięg (scope). Maven podczas budowania automatycznie pobierze z repozytorium moduł od którego zależność zdefiniowaliśmy (wcześniej może być konieczne zdefiniowanie dodatkowych repozytorium).</p>
<p>Przykładowa definicja zależności:</p>
<pre>&lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;3.8.1&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
    ……
  &lt;/dependencies&gt;</pre>
<h2>Zależności przechodnie</h2>
<p>Zależności przechodnie oszczędzają nam pracy związanej z odkrywaniem od czego jeszcze musimy zależeć w związku ze zdefiniowaniem zależności od jakiegoś modułu. Jeśli nasz moduł A zależy od modułu B, a moduł B zależy od kolejnych modułów to te końcowe zależności zostaną automatycznie dołączone do naszego projektu.</p>
<p>Istotnym elementem definiowania zależności jest określenie zasięgu (<strong>scope</strong>). Może mieć on jedną z poniższych wartości:</p>
<ul>
<li><strong>compile </strong>- domyślny zasięg – zależności o zasięgu kompilacji są dostępne we wszystkich fazach (kompilacji, uruchomienia) projektu i są propagowane do projektów zależących od mojego projektu.</li>
<li><strong>provided </strong>- zasięg zbliżony do compile z tą różnicą, że zakładamy dostępność tych bibliotek w runtime. Przykładem dla użycia provided może być Servlet API – potrzebujemy go do kompilacji, ale w runtime będzie udostępniony przez kontener.</li>
<li><strong>runtime </strong>- zasięg zakłada, że biblioteka nie jest potrzebna do kompilacji, ale tylko do uruchomienia (runtime i test).</li>
<li><strong>test </strong>- zasięg wskazuje, że biblioteka nie jest wymagana do normalnej pracy aplikacji i jest potrzebna jedynie w fazie testów.</li>
<li><strong>system </strong>- zasięg zbliżony do provided z tą różnicą, że jawnie wskazujemy jara zawierającego bibliotekę.</li>
<li><strong>import </strong><em>(dostęny od Mavena 2.0.9)</em> &#8211; zasięg dostępny jedynie dla zależności typu pom &#8211; wskazuje Mavenowi, że chcemy dołożyć do naszego projektu zależności zdefiniowane w innym projekcie.</li>
</ul>
<h2>Integracja z IDE</h2>
<p>Korzystanie z Mavena tylko z linii poleceń może być uciążliwe, ale oczywiście nie jest to konieczne. Istnieją oficjalne pluginy do Eclipse&#8217;a i Netbeans&#8217;a. Szczególnie polecanym pluginem do Eclipse&#8217;a jest m2eclipse &#8211; jest to najstarszy i najdojrzalszy plugin i działa bardzo poprawnie.</p>
<p>Więcej o pluginach do Eclipse&#8217;a można znaleźć na stronie http://maven.apache.org/eclipse-plugin.html, a o pluginach o Netbeans&#8217;a na http://maven.apache.org/netbeans-module.html. InteliJ wspiera mavena natywnie.</p>
<h2>Podsumowanie</h2>
<p>Powyższy artykuł jest tak naprawdę tylko wstępem, który mam nadzieję choć trochę przybliży Mavena i zachęci do zagłębienia się w temat. Maven daje wiele więcej – udostępnia mechanizmy dziedziczenia i agregacji pom’ów, pozwala na tworzenie własnych artefaktów, może być rozszerzany o wtyczki wspierające deployment komponentów na różnych serwerach aplikacyjnych &#8230; i wciąż się rozwija.</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">
<h2>Gdzie ja mam wrzucić te pliki?</h2>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/wprowadzenie-do-mavena/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Różnorodność mobilnych systemów operacyjnych &#8211; ograniczenie czy szansa?</title>
		<link>http://blog.atena.pl/roznorodnosc-mobilnych-systemow-operacyjnych-ograniczenie-czy-szansa</link>
		<comments>http://blog.atena.pl/roznorodnosc-mobilnych-systemow-operacyjnych-ograniczenie-czy-szansa#comments</comments>
		<pubDate>Wed, 22 Jun 2011 08:22:45 +0000</pubDate>
		<dc:creator>Zbigniew Wysocki</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Bez kategorii]]></category>
		<category><![CDATA[InfoShare]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1348</guid>
		<description><![CDATA[Rynek urządzeń mobilnych jest zdecydowanie jednym z najszybciej rozwijających się na świecie, a co za tym idzie &#8211; także zapotrzebowanie na aplikacje jest ogromne. A wraz ze wzrostem możliwości i dostępności tego rynku, również jego oczekiwania będą coraz większe. Mówiąc wprost, prędzej czy później firmy IT będą musiały rozpocząć prace nad tego typu aplikacjami, aby [...]]]></description>
			<content:encoded><![CDATA[<p>Rynek urządzeń mobilnych jest zdecydowanie jednym z najszybciej rozwijających się na świecie, a co za tym idzie &#8211; także zapotrzebowanie na aplikacje jest ogromne. A wraz ze wzrostem możliwości i dostępności tego rynku, również jego oczekiwania będą coraz większe. Mówiąc wprost, prędzej czy później firmy IT będą musiały rozpocząć prace nad tego typu aplikacjami, aby sprostać wymaganiom rynku. Jednak każdy, kto wytwarzał aplikacje mobilne lub zastanawiał się nad tym, zapewne zdaje sobie sprawę z trudności związanych z różnorodnością obecnych telefonów oraz tempem pojawiania się nowych modeli. Popularne od lat API Javy czy Symbiana także nie jest przyjazne dla programisty. Czy jednak tak jest ciągle? Co zmieniło się w ostatnich latach? Jak ten rynek będzie wyglądał za parę lat? Na jakie problemy można natrafić podczas prowadzenia projektu? <span id="more-1348"></span>Wybrałem się na wykład pod tytułem &#8222;Różnorodność mobilnych systemów operacyjnych &#8211; ograniczenie czy szansa&#8221; w ramach tegorocznej konferencji <a rel="nofollow" href="http://infoshare.pl/">InfoShare</a> z nadzieją, iż Łukasz Korzeniowski z firmy FancyFon S.A pomoże mi w znalezieniu odpowiedzi na te pytania.</p>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-"></a></h3>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Opisprezentacji"></a>Opis prezentacji</h3>
<p>Podczas prezentacji Łukasz Korzeniowski skupił się na porównaniu czasu pisania aplikacji na różne platformy telefonów komórkowych oraz podsumowaniu co zaskoczyło twórców i z czym mieli największe problemy. Przedstawił także obecne trendy i przyszłe prognozy popularności telefonów. Nie zostały poruszone szczegółowe różnice platform w oferowanych możliwościach. Wszystkie wnioski, jakie zostały przekazane przez prowadzącego, pochodzą z realnego projektu Pakk wykonanego na zlecenie węgierskiego klienta Vodafone. Ważne jest też, że do każdego typu telefonu został przydzielony programista z doświadczeniem w pracy z daną platformą.</p>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Obecnedane"></a>Obecne dane</h3>
<p>Oto, jak przedstawia się procentowy udział platformy na rynku urządzeń mobilnych za pierwszy kwartał 2011 roku:</p>
<table>
<tbody>
<tr>
<th> Platforma</th>
<th> 2011 Market Share</th>
</tr>
<tr>
<td>Android</td>
<td>39.5%</td>
</tr>
<tr>
<td>BlackBerry</td>
<td>14.9%</td>
</tr>
<tr>
<td>iOS</td>
<td>15.7%</td>
</tr>
<tr>
<td>Symbian</td>
<td>20.9%</td>
</tr>
<tr>
<td>WindowsMobile</td>
<td>5.5%</td>
</tr>
<tr>
<td>Others</td>
<td>3.5%</td>
</tr>
</tbody>
</table>
<p>Według danych od Vodafhone wśród czołowych czterdziestu modeli telefonów występują:</p>
<ul>
<li>Java:    42%</li>
</ul>
<ul>
<li>Symbian: 26%</li>
</ul>
<ul>
<li>Android: 32%</li>
</ul>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Podsumowanieplatform"></a>Podsumowanie platform</h3>
<h4><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-java"></a>Java</h4>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Zalety"></a>Zalety</h5>
<ul>
<li>Stosunkowo krótki czas wytworzenia</li>
</ul>
<ul>
<li>Powszechny język programowania</li>
</ul>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Problemy:"></a>Problemy:</h5>
<ul>
<li>API nie działające zgodnie ze specyfikacją</li>
<li>rozmiar aplikacji</li>
<li>zróżnicowanie wielkości ekranu</li>
<li>zróżnicowanie możliwości przeglądarki</li>
<li>różna reprezentacja obiektów (np. kontakt)</li>
<li>wysoki koszt testów</li>
<li>problem z konfiguracją APN (Nokia) oraz uprawnień aplikacji &#8211; negatywny wpływ na wrażenia użytkownika!!!</li>
</ul>
<h4><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Android"></a>Android</h4>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Zalety:"></a>Zalety:</h5>
<ul>
<li>wielozadaniowy system operacyjny &#8211; można więcej</li>
<li>duża swoboda aplikacji (szeroki dostęp do systemu)</li>
<li>popularny język programowania</li>
<li>szybkość tworzenia aplikacji</li>
<li>automatyczna dostępność aplikacji na tablety</li>
</ul>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-"></a></h5>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Problemy:"></a>Problemy:</h5>
<ul>
<li>różnice w zachowaniu API na różnych modelach telefonów (raczej incydentalne)</li>
<li>pewne nienaruszalne założenia (np. sposób instalacji aplikacji) &#8211; ograniczenie możliwości</li>
<li>nie najlepsza dokumentacja</li>
</ul>
<h4><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-"></a></h4>
<h4><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Symbian"></a>Symbian</h4>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Zalety:"></a>Zalety:</h5>
<ul>
<li>API pozwalające na dostęp do każdego elementu systemu</li>
<li>w nowych telefonach możliwość tworzenia aplikacji w Qt</li>
</ul>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Problemy:"></a>Problemy:</h5>
<ul>
<li>dużo wyższa pracochłonność  niż na innych platformach (bez użycia Qt)</li>
<li>archaiczny język i środowisko programistyczne</li>
<li>ukryte API</li>
<li>skomplikowany system podpisów</li>
<li>„sztuczki i kruczki&#8221; zarówno w systemie jak i w środowisku</li>
<li>zróżnicowanie między wersjami Symbiana</li>
<li>zróżnicowanie między urządzeniami</li>
</ul>
<h4><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-iPhone"></a>iPhone</h4>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Zalety:"></a>Zalety:</h5>
<ul>
<li>niewielka liczba urządzeń i wersji systemu</li>
<li>szybki development</li>
<li>„błyszczący&#8221; interfejs użytkownika</li>
<li>automatyczna dostępność aplikacji dla iPad</li>
</ul>
<h5><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Wady:"></a>Wady:</h5>
<ul>
<li>nietypowy język programowania</li>
<li>konieczność posiadania sprzętu Apple</li>
<li>ograniczone API do dostępu do elementów systemu (np. skrzynka SMS)</li>
</ul>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-"></a></h3>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Czasnapisaniaaplikacji"></a>Czas napisania aplikacji</h3>
<table>
<tbody>
<tr>
<th> Platforma</th>
<th> Czas</th>
</tr>
<tr>
<td>Java</td>
<td>półtora miesiąca</td>
</tr>
<tr>
<td>Symbian</td>
<td>ponad dwa i bez paru funkcjonalności</td>
</tr>
<tr>
<td>Android</td>
<td>miesiąc</td>
</tr>
<tr>
<td>iOS</td>
<td>trzy tygodnie</td>
</tr>
</tbody>
</table>
<h3><a name="Różnorodnośćmobilnychsystemówoperacyjnych-ograniczenieczyszansa-Wnioski"></a>Wnioski</h3>
<p>Ważne jest, aby podczas podpisywania umowy ograniczyć ilość telefonów docelowych na których zapewniamy poprawność naszej aplikacji. Mnogość modeli na rynku może znacząco wpłynąć na ryzyko przekroczenia budżetu i czasu naszego projektu. Należy testować aplikację na konkretnych telefonach, a nie tylko symulatorach, co również pozwoli skrócić czas wykrycia nieprawidłowości w działaniu aplikacji.<br />
W związku z popularyzacją smartphonów i osłabianiem się pozycji Symbiana na rynku, powinno się w miarę możliwości zrezygnować z supportu dla tej drugiej platformy. Po za tym sprawił on najwięcej problemów w projekcie i zajął najwięcej czasu. W przypadku iPhona powinno się zastanowić, na ile nasza aplikacja może być popularna na iStore, gdyż w przypadku napisania pierwszej koszty wejścia na ten rynek, są dość wysoki. Niestety niezbędny jest zakup: iPhone, iMac i licencji developerskiej pozwalającej na publikowanie aplikacji w iStore. Kolejną rzeczą, która wymaga zastanowienia , jest fakt, że w powyższym przedsięwzięciu nie używano praktycznie żadnego współdzielenia kodu między platformami. Rozwiązaniem tego problemu może być użycie jednego z frameworków:</p>
<ul>
<li>LWUIT -  <a rel="nofollow" href="http://lwuit.java.net/">http://lwuit.java.net/</a></li>
</ul>
<ul>
<li>OpenGL &#8211; <a rel="nofollow" href="http://www.khronos.org/opengles/">http://www.khronos.org/opengles/</a></li>
</ul>
<ul>
<li>PhoneGap (HTML5) &#8211; <a rel="nofollow" href="http://www.phonegap.com/home/">http://www.phonegap.com/home/</a></li>
</ul>
<p>Z powyższej listy do prostego interfejsu bez &#8222;fajerwerków&#8221; wybrałbym zdecydowanie PhoneGap. Dzięki użyciu HTML5 i javascript (powszechnie znanych technologi) jest on bardzo prosty w użyciu dla programisty. Zarazem zapewnia API pozwalające na tworzenie dowolnych aplikacji, można odwoływać się również do native API. Gdyby pojawiły się problemy, możemy liczyć na wsparcie rozwijającej się społeczności wokół tego projektu. Natomiast jeśli miałaby to być gra lub inna aplikacja wymagająca więcej od telefonu, warto rozważyć użycie OpenGL. Projekt ten jest wiodącym pod względem renderingu 3D. Więcej informacji o frameworkach można znaleźć na stronach podanych powyżej. Dodatkowe wiadomości można również zaczerpnąć z prezentacji Łukasz Korzeniowskiego dostępnej <a title="Prezentacja" rel="nofollow" href="http://www.slideshare.net/infosharepl/infoshare-2011-ukasz-korzeniowski-rnorodno-mobilnych-systemw-operacyjnych-ograniczenie-czy-szansa">tutaj</a>.</p>
<p>﻿</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/roznorodnosc-mobilnych-systemow-operacyjnych-ograniczenie-czy-szansa/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Badanie wydajności repozytorium plików JackRabbit</title>
		<link>http://blog.atena.pl/badanie-wydajnosci-repozytorium-plikow-jackrabbit</link>
		<comments>http://blog.atena.pl/badanie-wydajnosci-repozytorium-plikow-jackrabbit#comments</comments>
		<pubDate>Fri, 14 Jan 2011 13:16:26 +0000</pubDate>
		<dc:creator>Marcin Garniewski</dc:creator>
				<category><![CDATA[JMeter]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Narzędzia]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1160</guid>
		<description><![CDATA[Apache JackRabbit jest znaną i uznaną biblioteką implementującą standard JSR-170 czyli repozytorium treści. Potrafi przechowywać w hierarchiczny sposób z obsługą ustrukturyzowanych oraz nieustrukturyzowanych danych, z możliwością ich tekstowego przeszukiwania, zarządzania wersjami itp. Jednym z interfejsów dostępu do JackRabbit jest WebDAV. Celem tego artykułu jest pokazanie jak można przetestować wydajność podstawowych operacji zapisu i odczytu plików komunikując [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://jackrabbit.apache.org" target="_blank">Apache JackRabbit</a> jest znaną i uznaną biblioteką implementującą standard JSR-170 czyli repozytorium treści. Potrafi przechowywać w hierarchiczny sposób z obsługą ustrukturyzowanych oraz nieustrukturyzowanych danych, z możliwością ich tekstowego przeszukiwania, zarządzania wersjami itp. Jednym z interfejsów dostępu do JackRabbit jest WebDAV. Celem tego artykułu jest pokazanie jak można przetestować wydajność podstawowych operacji zapisu i odczytu plików komunikując się z repozytorium poprzez interfejs WebDAV. Wykorzystam do tego niezastąpiony Apache JMeter.</p>
<p><span id="more-1160"></span></p>
<p><strong>Metodologia testu</strong></p>
<p>Interfejs WebDAV oferuje szeroki zakres funkcjonalności. Na potrzeby testu wybrałem tylko kilku podstawowych metod: PUT (wysłanie pliku), GET (pobranie pliku), LIST (lista wszystkich plików w węźle) oraz DELETE (usunięcie pliku). Niestety, interfejs WebDAV jest rozszerzeniem standardu dlatego standardowe komponenty JMetera nie są w stanie wygenerować prawidłowych żądań. Dlatego utworzymy bibliotekę dostępu do wybranych metod WebDAV, a następnie będziemy wywoływać metody przy pomocy komponentu JMetera &#8222;Java Request&#8221;.</p>
<p><strong>Uruchomienie JackRabbit</strong></p>
<p>Zacznijmy od uruchomienia repozytorium. JackRabbit można uruchomić w różnych środowiskach i konfiguracjach. Wszystkie możliwości zaprezentowane są <a href="http://jackrabbit.apache.org/deployment-models.html" target="_blank">tutaj</a>. Na potrzeby naszego testu uruchomimy JackRabbit jako moduł WAR na serwerze JBoss 5.1.  W tym celu ściągamy stabilną wersję aplikacji jackrabbit-webapp-X.X.X.war ze strony  <a title="download" href="http://jackrabbit.apache.org/downloads.html" target="_blank">http://jackrabbit.apache.org/downloads.html</a>. Następnie za radą <a href="http://wiki.apache.org/jackrabbit/JackrabbitOnJBoss">FAQ Jackrabbita</a> musimy usunąć z niej biblioteki: WEB-INF\lib\xercesImpl-2.9.0.jar oraz WEB-INF\lib\xml-apis-1.3.04.jar. Wynika to z tego, że te biblioteki istnieją już w dystrybucji Jboss-a. Umieszczenie ich dodatkowo w aplikacji WAR prowadzi do konfliktu. Innym rozwiązaniem jest zmiana konfiguracji classloaderów w JBoss.</p>
<p>Po uruchomieniu jboss-a aplikacja JackRabbit jest dostępna na przykład pod adresem http:\\localhost:8080\jackrabbit. Domyślnie pod tym adresem dostępna jest strona z dokumentacją, opisem standardów, FAQ, tutorialami itp. Z innych ciekawych rzeczy mamy do dyspozycji browser, wyszukiwarkę treści oraz tzw: &#8222;Zasilacz treści&#8221; (ang. Populate).  Zasilenie polega na losowym wygenerowaniu i zapisaniu do repozytorium różnego rodzaju plików. Opcja przydatna przy przeprowadzaniu testów. My nie będziemy leniwi i sami zasilimy repozytorium własnymi danymi.</p>
<p><strong>Projekt biblioteki dostępu do JackRabbit za pomocą WebDav</strong></p>
<p>Api JackRabbita zawiera cały zestaw metod służących do wykonywania wszystkich dostępnych metod interfejsu WebDAV. Metody te są zawarte w pakiecie: “org.apache.jackrabbit.webdav.client.methods”. Przykładowy kod uruchomienia metody PUT może wyglądać następująco:</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">pl.atena.webdav</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.IOException</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.commons.httpclient.HostConfiguration</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.commons.httpclient.HttpClient</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.commons.httpclient.methods.ByteArrayRequestEntity</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.commons.httpclient.methods.RequestEntity</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.client.methods.PutMethod</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.log4j.Logger</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PutWebDav <span style="color: #000000; font-weight: bold;">extends</span> AbstractWebDav <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> Logger log <span style="color: #339933;">=</span> Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>PutWebDav.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> PutWebDav<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> PutWebDav<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> webDavUrl<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>webDavUrl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> putFile<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> fileName, <span style="color: #000000; font-weight: bold;">final</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> destName<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> bytes <span style="color: #339933;">=</span> readFile<span style="color: #009900;">&#40;</span>fileName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; putFile<span style="color: #009900;">&#40;</span>bytes, destName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> putFile<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> bytes, <span style="color: #000000; font-weight: bold;">final</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> destName<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; HttpClient client <span style="color: #339933;">=</span> initHttpClient<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; PutMethod method <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PutMethod<span style="color: #009900;">&#40;</span>getWebDavUrl<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> destName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; RequestEntity requestEntity <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ByteArrayRequestEntity<span style="color: #009900;">&#40;</span>bytes<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; method.<span style="color: #006633;">setRequestEntity</span><span style="color: #009900;">&#40;</span>requestEntity<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; HostConfiguration conf <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HostConfiguration<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responseCode <span style="color: #339933;">=</span> client.<span style="color: #006633;">executeMethod</span><span style="color: #009900;">&#40;</span>conf, method<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; errorCounter<span style="color: #339933;">--;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>responseCode <span style="color: #339933;">&gt;=</span> <span style="color: #cc66cc;">400</span> <span style="color: #339933;">&amp;&amp;</span> errorCounter <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aioexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">IOException</span></a> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Warto zwrócić uwagę na pętlę do{&#8230; }while. Służy ona do zmniejszenia ryzyka wystąpienia błędu jednoczesnej modyfikacji węzła. Sytuacja taka wystąpi, gdy równolegle dwóch lub więcej klientów wykonuje operację dodawania/usuwanie/modyfikacji pliku w tym samym węźle. Jest to spowodowane tym, że podczas tych operacji wykonywane są również modyfikacje na węźle, co przy równoległej pracy prowadzi do błędu HTTP 409 (Konflikt). W celu rozwiązania tego problemu operację wykonuję w pętli. Jeśli za pierwszym razem wystąpił błąd, próbuję wykonać ją ponownie. Liczba prób nie może przekroczyć dziesięciu, po tym metoda kończy działanie i zwraca kod błędu.<br />
Kod metody List:</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">pl.atena.webdav</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Collections</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.commons.httpclient.HttpClient</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.DavConstants</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.MultiStatus</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.MultiStatusResponse</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.client.methods.DavMethod</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jackrabbit.webdav.client.methods.PropFindMethod</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.log4j.Logger</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">pl.atena.webdav.utils.Utils</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
* Lista wszystkich plików w podanym węźle<br />
*/</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ListWebDav <span style="color: #000000; font-weight: bold;">extends</span> AbstractWebDav <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> Logger log <span style="color: #339933;">=</span> Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>ListWebDav.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ListWebDav<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ListWebDav<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> webDavUrl<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>webDavUrl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> listFiles<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> list <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ArrayList<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DavMethod pFind <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PropFindMethod<span style="color: #009900;">&#40;</span>getWebDavUrl<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,DavConstants.<span style="color: #006633;">PROPFIND_ALL_PROP</span>, DavConstants.<span style="color: #006633;">DEPTH_1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HttpClient client <span style="color: #339933;">=</span> initHttpClient<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responseCode <span style="color: #339933;">=</span> client.<span style="color: #006633;">executeMethod</span><span style="color: #009900;">&#40;</span>pFind<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MultiStatus multiStatus <span style="color: #339933;">=</span> pFind.<span style="color: #006633;">getResponseBodyAsMultiStatus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MultiStatusResponse<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> responses <span style="color: #339933;">=</span> multiStatus.<span style="color: #006633;">getResponses</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MultiStatusResponse currResponse<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> responses.<span style="color: #006633;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currResponse <span style="color: #339933;">=</span> responses<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>currResponse.<span style="color: #006633;">getHref</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">endsWith</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;.txt&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>Utils.<span style="color: #006633;">getFileName</span><span style="color: #009900;">&#40;</span>currResponse.<span style="color: #006633;">getHref</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Exception</span></a> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Acollections+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Collections</span></a>.<span style="color: #006633;">sort</span><span style="color: #009900;">&#40;</span>list<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> list<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>W podobny sposób zaimplementowane są pozostałe metody Get i Delete.</p>
<p><strong>Projekt biblioteki JMeter</strong></p>
<p>Aby wykonywać żądania WebDAV, wykorzystamy komponent Java Request. Pozwala on na wykonywanie metod napisanych w języku Java. Będziemy wykonywać metody powyższego Api. Aby było to możliwe, należy utworzyć dodatkowe klasy testu JMeter, które rozszerzają interfejs &#8222;org.apache.jmeter.protocol.java.sampler.JavaSamplerClient&#8221;. Dla każdej z metod tworzymy klasę JMetera. Zawiera ona następujące metody:</p>
<ul>
<li>getDefaultParameters &#8211; lista parametrów metody</li>
<li>runTest &#8211; ciało metody testującej</li>
<li>setupTest &#8211; przygotowanie testu (metoda wykonywana jako pierwsza)</li>
<li>teardownTest &#8211; zakończenie testu (metoda wykonywana jako ostatnia)</li>
</ul>
<p>W metodzie runTest implementujemy uruchomienie akcji WebDAV.</p>
<p>Przykładowy kod klasy testującej metodę PUT w JMeter:</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">pl.atena.webdav.jmeter</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.config.Arguments</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.protocol.java.sampler.JavaSamplerContext</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.samplers.SampleResult</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">pl.atena.webdav.PutWebDav</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
* Klasa JMeter-a potrzebna do uruchomienia metod interfejsu WebDAV<br />
*/</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PutWebDavJMeter <span style="color: #000000; font-weight: bold;">extends</span> AbstractJavaSamplerClient <span style="color: #000000; font-weight: bold;">implements</span> JMeterStatics <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Arguments getDefaultParameters<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Arguments arg <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Arguments<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arg.<span style="color: #006633;">addArgument</span><span style="color: #009900;">&#40;</span>FILE_NAME, <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arg.<span style="color: #006633;">addArgument</span><span style="color: #009900;">&#40;</span>DEST_NAME, <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arg.<span style="color: #006633;">addArgument</span><span style="color: #009900;">&#40;</span>WEB_DAV_URL, STATIC_WEB_DAV_URL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> arg<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> SampleResult runTest<span style="color: #009900;">&#40;</span>JavaSamplerContext arg0<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; SampleResult result <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SampleResult<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">sampleStart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; PutWebDav putWebDav <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PutWebDav<span style="color: #009900;">&#40;</span>arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>WEB_DAV_URL<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; putWebDav.<span style="color: #006633;">putFile</span><span style="color: #009900;">&#40;</span>arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>FILE_NAME<span style="color: #009900;">&#41;</span>, arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>DEST_NAME<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">sampleEnd</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">setSuccessful</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">setResponseCodeOK</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">setResponseMessage</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;&lt;response&gt;&quot;</span> <span style="color: #339933;">+</span> putWebDav.<span style="color: #006633;">getResponseCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;&lt;/response&gt;&lt;fileName&gt;&quot;</span> <span style="color: #339933;">+</span> arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>DEST_NAME<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;&lt;/fileName&gt;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">setSamplerData</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Put source &quot;</span> <span style="color: #339933;">+</span> arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>FILE_NAME<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot; as &quot;</span> <span style="color: #339933;">+</span> arg0.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>DEST_NAME<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color: #006633;">setSampleLabel</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PutWebDav&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> result<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>W metodzie getDefaultParameters umieszczamy listę parametrów, jakie mają być dostępne do ustawienia z poziomu JMetera. Widok na listę parametrów zdefiniowanych w powyższym teście:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img10.png"><img class="alignnone size-full wp-image-1211" title="img10" src="http://blog.atena.pl/wp-content/uploads/2010/12/img10.png" alt="" /></a></p>
<p>Analogicznie tworzymy klasy testowe dla pozostałych metody WebDAV.<br />
Po skompilowaniu należy umieścić klasy java w pliku jar i skopiować go to katalogu JMetera: “&lt;jmeter.home&gt;/lib/ext”. Po zrestartowaniu JMetera oraz wybraniu komponentu “Java Request” pojawią się nowe opcje:</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/12/img01.jpg"><img class="alignnone size-medium wp-image-1164" src="http://blog.atena.pl/wp-content/uploads/2010/12/img01-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p><strong>Skrypt testowy</strong></p>
<p>Widok na hierarchie skryptu testowego:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img02.png"><img class="alignnone size-full wp-image-1199" title="img02" src="http://blog.atena.pl/wp-content/uploads/2010/12/img02.png" alt="" width="246" height="329" /></a></p>
<p>Opis konfiguracji:<br />
Zmienne globalne &#8211; zmienne wykorzystywane w różnych komponentach:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img07.png"><img class="alignnone size-full wp-image-1195" title="img07" src="http://blog.atena.pl/wp-content/uploads/2010/12/img07.png" alt="" /></a></p>
<p>VAR_LICZBA_UZYTKOWNIKOW &#8211; liczba symulowanych równolegle pracujących użytkowników<br />
VAR_LICZBA_POWTORZEN &#8211; liczba powtórzeń testu<br />
VAR_LICZBA_KATALOGOW &#8211; liczba węzłów na których pracują użytkownicy<br />
VAR_WEB_DAV_URL &#8211; adres WebDav</p>
<p>Java Request Put<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img03.png"><img class="alignnone size-full wp-image-1200" title="img03" src="http://blog.atena.pl/wp-content/uploads/2010/12/img03.png" alt="" /></a></p>
<p>sourceFileName &#8211; lokalizacja pliku źródłowego (w tym przypadku plik tekstowy o wielkości 256Kb)<br />
destName &#8211; nazwa docelowa pliku w JackRabbit, funkcja ${__counter(false)} zwraca kolejną wartość, zaczynając od 1, parametr false oznacza, że licznik jest wspólny dla wszystkich użytkowników<br />
webDavURL &#8211; adres serwera WebDav<br />
Jako dziecko do tego komponentu dodany jest komponent &#8222;Regular Expression Extractor&#8221;. Wykorzystujemy go do odczytania nazwy, pod którą został zapisanego pliku w JackRabbit. Nazwę tę umieszczamy w odpowiedzi żądania w tagach &lt;fileName&gt;&#8230;&lt;/fileName&gt; (kod do obejrzenia w klasie PutWebDavJMeter).<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img04.png"><img class="alignnone size-full wp-image-1201" title="img04" src="http://blog.atena.pl/wp-content/uploads/2010/12/img04.png" alt="" /></a></p>
<p>Java Request &#8211; List<br />
Wylistowanie wszystkich plików z węzła podanego w parametrze webDavURL. Plik testowy został tak napisany, że zwraca nazwy plików w znacznikach &lt;name&gt;&#8230;&lt;/name&gt;. Wyrażenie regularne wyciąga listę nazw plików z odpowiedzi Java Request i umieszcza w zmiennej VAR_CONTENT_NAME_IN.<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img05.png"><img class="alignnone size-full wp-image-1202" title="img05" src="http://blog.atena.pl/wp-content/uploads/2010/12/img05.png" alt="" /></a></p>
<p>ForEach Controller &#8211; Get<br />
Odczytuje listę nazw plików ze zmiennej VAR_CONTENT_NAME_IN i iteruje po niej umieszczając konkretne nazwy plików w zmiennej VAR_CONTENT_NAME_OUT.</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/12/img11.png"><img class="alignnone size-full wp-image-1236" title="img06" src="http://blog.atena.pl/wp-content/uploads/2010/12/img06.png" alt="" /></a></p>
<p>Java Request Get<br />
Wywołuję metodę GET na pliku podanym w zmiennej destName:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img11.png"><img class="alignnone size-full wp-image-1213" title="img11" src="http://blog.atena.pl/wp-content/uploads/2010/12/img11.png" alt="" /></a></p>
<p><strong>Wykonanie testu JMeter</strong></p>
<p>Tak przygotowany test umożliwia nam manipulowanie liczbą użytkowników, liczbą węzłów, do których zapisujemy pliki oraz rozmiarem pliku.</p>
<p>Skrypt uruchamiamy, wybierając opcję z menu Uruchom-&gt;Start, a następnie pozostaje nam już tylko cieszyć się napływającymi wynikami:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/12/img09.png"><img class="alignnone size-full wp-image-1214" title="img09" src="http://blog.atena.pl/wp-content/uploads/2010/12/img09.png" alt="" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/badanie-wydajnosci-repozytorium-plikow-jackrabbit/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wstęp do Google Guice</title>
		<link>http://blog.atena.pl/wstep-do-google-guice</link>
		<comments>http://blog.atena.pl/wstep-do-google-guice#comments</comments>
		<pubDate>Thu, 26 Aug 2010 09:17:07 +0000</pubDate>
		<dc:creator>Adam Andrzejewski</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1014</guid>
		<description><![CDATA[Guice jest biblioteką od Google, której ideę stanowi możliwość zastąpienia różnego rodzaju fabryk obiektów, tworzenia obiektów za pomocą operatora new. Zapewnia ona ponadto mechanizmy zbliżone do dependency injection. Wiadomo, że najlepiej człowiek uczy się na przykładzie, więc omówię tę bibliotekę podpierając się odniesieniem do prostego projektu. Link do całej aplikacji dostępny jest na końcu artykułu. [...]]]></description>
			<content:encoded><![CDATA[<p>Guice jest biblioteką od Google, której ideę stanowi możliwość zastąpienia różnego rodzaju fabryk obiektów, tworzenia obiektów za pomocą operatora new. Zapewnia ona ponadto mechanizmy zbliżone do dependency injection.<br />
<span id="more-1014"></span><br />
Wiadomo, że najlepiej człowiek uczy się na przykładzie, więc omówię tę bibliotekę podpierając się odniesieniem do prostego projektu. Link do całej aplikacji dostępny jest na końcu artykułu.</p>
<p>Załóżmy, że mamy w naszej aplikacji jakieś zdarzenia które chcemy obsługiwać i wysyłać powiadomienia. Mamy więc abstrakcyjny byt Event, przydałby się manager zarządzania powiadomieniami i oczywiście mechanizmy obsługi zdarzeń &#8211; EventHandler.</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">pl.atena.guice.demo.api</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> getCaller<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> NotificationManager <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">void</span> sendMail<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> userName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> EventHandler <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> NotificationManager notificationManager<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> event<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> EventHandler<span style="color: #009900;">&#40;</span>NotificationManager notificationManager, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">notificationManager</span> <span style="color: #339933;">=</span> notificationManager<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">event</span> <span style="color: #339933;">=</span> event<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> handle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//do some event handling</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//send notification</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; notificationManager.<span style="color: #006633;">sendMail</span><span style="color: #009900;">&#40;</span>event.<span style="color: #006633;">getCaller</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span></div></td></tr></tbody></table></div>
<p>Do czego w takim razie jest nam tu potrzebne Guice? Przecież w czasie działania aplikacji jeżeli nasz kontener wspiera w jakiś wstrzykiwanie instancji, mógłby więc też wrzucić nam odpowiednie elementy i niczym nie musielibyśmy się martwić. No tak, ale co w sytuacji, kiedy nasz kontener tak po prostu tego nie potrafi? A jeżeli w ogóle nie mamy kontenera? Co z testami jednostkowymi, które chcemy uruchamiać bez niego? Do tego właśnie nadaje się Guice. Zamiast w aplikacji wykonywać rzeczy takie jak</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MainApp <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> event <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CreationEvent<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Creation Event caller&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NotificationManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultNotificationManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EventHandler handler <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> EventHandler<span style="color: #009900;">&#40;</span>manager, event<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; handler.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>a potem jeszcze &#8222;kombinować&#8221; przy testach</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//test obslugi eventow, nie chcemy tutaj testowac mailingu</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestEventHandling <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> event <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CreationEvent<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Creation Event caller&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NotificationManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FakeNotificationManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EventHandler handler <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> EventHandler<span style="color: #009900;">&#40;</span>manager, event<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handler.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #666666; font-style: italic;">//test mailingu, jakie to są eventy nas nie obchodzi</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestNotificationManager <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> event <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FakeEvent<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NotificationManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultNotificationManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EventHandler handler <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> EventHandler<span style="color: #009900;">&#40;</span>manager, event<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handler.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>możemy posłużyć się Guice, by to on zadbał o wszystkie konieczne elementy dla naszej aplikacji i testów. Czy nie lepiej zrobić coś takiego:</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MainApp <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Injector injector <span style="color: #339933;">=</span> Guice.<span style="color: #006633;">createInjector</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> DefaultEventHandlerModule<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EventHandler instance <span style="color: #339933;">=</span> injector.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>EventHandler.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; instance.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//....</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestEventHandling <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Injector injector <span style="color: #339933;">=</span> Guice.<span style="color: #006633;">createInjector</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> TestEventHandlerModule<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EventHandler instance <span style="color: #339933;">=</span> injector.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>EventHandler.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; instance.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//....</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestNotificationManager <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Injector injector <span style="color: #339933;">=</span> Guice.<span style="color: #006633;">createInjector</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> TestNotificationManagerModule<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EventHandler instance <span style="color: #339933;">=</span> injector.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>EventHandler.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; instance.<span style="color: #006633;">handle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Takie podejście upraszcza nam logikę testów i odcina je od faktycznej implementacji. Czy ktoś jest w stanie sobie wyobrazić sytuację w której handler będzie miał dziesięć różnych elementów? Wszystkie chcemy testować, a po jakimś czasie okazuje się, że dwa z nich sa niepotrzebne, a trzy nowe musimy dodać. Doprowadziłoby to do zmian wielu testów, nie mówiąc o zmianach w logice biznesowej. Utrzymywanie tego bytu stałoby się mozolne. A w większych aplikacjach takich bytów bywa przecież więcej. Guice pozwala uniknąć tych problemów, musimy zadbać tylko o parę rzeczy. Po pierwsze – obiekty powinny posiadać konstruktory bezargumentowe lub adnotowane przez @Inject.</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CreationEvent <span style="color: #000000; font-weight: bold;">implements</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a><span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> caller<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; @Inject<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> CreationEvent<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> caller<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">caller</span> <span style="color: #339933;">=</span> caller<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> getCaller<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> caller<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> &nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DefaultNotificationManager <span style="color: #000000; font-weight: bold;">implements</span> NotificationManager<span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> sendMail<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> userName<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// fancy mail sending logic</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">System</span></a>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sending mail from class &quot;</span> <span style="color: #339933;">+</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">getClass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot; to &quot;</span> <span style="color: #339933;">+</span> userName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Po drugie &#8211; musimy dla każdej interesującej nas kombinacji parametrów obiektu stworzyć moduł, który będzie wiedział jak utworzyć naszą instancję. Czyli dla kawałka kodu</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Injector injector <span style="color: #339933;">=</span> Guice.<span style="color: #006633;">createInjector</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> TestNotificationManagerModule<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
EventHandler instance <span style="color: #339933;">=</span> injector.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>EventHandler.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>potrzebujemy TestNotificationManagerModule. Każdy moduł powinien rozszerzać klasę AbstractModule oraz implementować metodę configure(), w której określamy jakie klasy chcemy posiadać w czasie runtime&#8217;u ukryte pod interfejsami</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestNotificationManagerModule <span style="color: #000000; font-weight: bold;">extends</span> AbstractModule <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bind<span style="color: #009900;">&#40;</span>NotificationManager.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>DefaultNotificationManager.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bind<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>FakeEvent.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>W przypadku klas które posiadają konstruktory z parametrami możemy wykorzystać nieco inne podejście &#8211; metody @Provides</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DefaultEventHandlerModule <span style="color: #000000; font-weight: bold;">extends</span> AbstractModule <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bind<span style="color: #009900;">&#40;</span>NotificationManager.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>DefaultNotificationManager.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; @Provides<br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> provideEvent<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CreationEvent event <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CreationEvent<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Creation Event Caller&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> event<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Metody takie zastępują wywołanie bind() &#8211; gdy moduł będzie potrzebował implementacji Event odszuka odpowiednią metodę z adnotacją @Provides i wywoła ją w celu pozyskania elementu.</p>
<p>W ten sposób możemy utworzyć dowolne kombinacje elementów podstawiając wymagane implementacje, zależnie od naszych potrzeb w danej chwili. Co więcej zmiana mechanizmów tworzenia wstrzykiwanego komponentu sprowadza się do zmiany modułów, które są zazwyczaj prostymi klasami, i nie musimy dokonywać dodatkowych modyfikacji w kodzie z logiką biznesową.</p>
<p>Cały projekt można pobrać z załączników żeby zobaczyć jak moduły załatwiają sprawę przydzielania odpowiednich implementacji do interfejsów zależnie od potrzeb.</p>
<p>Guice posiada kilka mechanizmów wstrzykiwań</p>
<ul>
<li>linked bindings &#8211; tak jak w podanym przykładzie</li>
<li>instance bindings &#8211;      możliwość przywiązania klasy do jej konkretnej instancji. Przydatne w      łączeniu z adnotowaniem parametrów (o tym niżej)</li>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">bind<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">annotatedWith</span><span style="color: #009900;">&#40;</span>Names.<span style="color: #006633;">named</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;JDBC URL&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;jdbc:mysql://localhost/pizza&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<li>@Provides methods &#8211; jak w przykładzie, wykorzystanie metod oznaczonych @Provides zamiast bind(). Przydatne przy większych obiektach które posiadają proste elementy w konstruktorach, oraz w sytuacji, kiedy chcemy je przed użyciem skonfigurować</li>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Provides<br />
<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aevent+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Event</span></a> provideEvent<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; CreationEvent event <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CreationEvent<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Creation Event Caller&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> event<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<li>klasy Provider &#8211; mechanizm      podobny do metod @Provides, jednak dla zdecydowanie większych i bardziej złożonych konstrukcji. Klasa taka powinna rozszerzać interfejs Provider&lt;T&gt; i posiadać metodę get() która zwraca wymagany element T. Klasy takie mogą jak najbardziej być adnotowane przez @Inject by uprościć sobie ich tworzenie, np</li>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DatabaseTransactionLogProvider <span style="color: #000000; font-weight: bold;">implements</span> Provider<span style="color: #339933;">&lt;</span>TransactionLog<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aconnection+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Connection</span></a> connection<span style="color: #339933;">;</span><br />
<br />
&nbsp; @Inject<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> DatabaseTransactionLogProvider<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aconnection+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Connection</span></a> connection<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">connection</span> <span style="color: #339933;">=</span> connection<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> TransactionLog get<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; DatabaseTransactionLog transactionLog <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DatabaseTransactionLog<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; transactionLog.<span style="color: #006633;">setConnection</span><span style="color: #009900;">&#40;</span>connection<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> transactionLog<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>i w module przywiązujemy interfejs nie do konkretnej klasy, ale do klasy Providera</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Override<br />
&nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; bind<span style="color: #009900;">&#40;</span>TransactionLog.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toProvider</span><span style="color: #009900;">&#40;</span>DatabaseTransactionLogProvider.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<li>untargeted bindings &#8211;  wiązania, które nie określają implementacji.</li>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">bind<span style="color: #009900;">&#40;</span>CreditCardProcessor.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span></div></td></tr></tbody></table></div>
<p>Przydatne, jeżeli posiadamy interfejsy adnotowane @ImplementedBy i @ProvidedBy</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@ImplementedBy<span style="color: #009900;">&#40;</span>PayPalCreditCardProcessor.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> CreditCardProcessor <span style="color: #009900;">&#123;</span><br />
&nbsp; ChargeResult charge<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> amount, CreditCard creditCard<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throws</span> UnreachableException<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
@ProvidedBy<span style="color: #009900;">&#40;</span>DatabaseTransactionLogProvider.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TransactionLog <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">void</span> logConnectException<span style="color: #009900;">&#40;</span>UnreachableException e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">void</span> logChargeResult<span style="color: #009900;">&#40;</span>ChargeResult result<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</ul>
<p>Adnotowanie parametrów służy rozróżnieniu wiązań &#8211; możemy przecież chcieć posiadać w ramach modułu różne implementacje zależnie od sytuacji.<br />
Więcej o adnotowaniu parametrów w <a href="http://code.google.com/docreader/#p=google-guice&amp;s=google-guice&amp;t=BindingAnnotations">dokumentacji</a></p>
<p>Zasoby i bibliografia:</p>
<ul>
<li><a href="http://code.google.com/docreader/#p=google-guice&amp;s=google-guice&amp;t=google-guice">strona projektu</a></li>
<li>przykład <a href='http://blog.atena.pl/wp-content/uploads/2010/08/GuiceDemo.zip'>GuiceDemo</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/wstep-do-google-guice/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PRAKTYCZNY ENVERS</title>
		<link>http://blog.atena.pl/praktyczny-envers</link>
		<comments>http://blog.atena.pl/praktyczny-envers#comments</comments>
		<pubDate>Fri, 20 Aug 2010 07:00:10 +0000</pubDate>
		<dc:creator>Mateusz Mrozewski</dc:creator>
				<category><![CDATA[Bez kategorii]]></category>
		<category><![CDATA[JBoss]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaEE]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=1028</guid>
		<description><![CDATA[Envers jest dodatkiem do Hibernate’a pozwalającym na automatyczne zapisywanie historii zmian encji (audytu). Envers używa pojęcia rewizji – co oznacza, że każda zmiana dowolnej (audytowalnej) encji tworzy nową rewizję. Nowy rekord jest zapisany do tabeli, a na podstawie starego zostaje utworzona rewizja i zapisana do dodatkowej tabeli wraz z poprzednimi wartościami. Konfiguracja W ramach podstawowej [...]]]></description>
			<content:encoded><![CDATA[<p>Envers jest dodatkiem do Hibernate’a pozwalającym na automatyczne zapisywanie historii zmian encji (audytu). Envers używa pojęcia rewizji – co oznacza, że każda zmiana dowolnej (audytowalnej) encji tworzy nową rewizję. Nowy rekord jest zapisany do tabeli, a na podstawie starego zostaje utworzona rewizja i zapisana do dodatkowej tabeli wraz z poprzednimi wartościami.</p>
<p><span id="more-1028"></span></p>
<p><strong>Konfiguracja</strong></p>
<p>W ramach podstawowej niezbędnej konfiguracji należy dodać następujące właściwości do pliku persistence.xml lub hibernate.cfg.xml:</p>
<p style="text-align: left">&lt;property name=&#8221;hibernate.ejb.event.post-insert&#8221; value=&#8221;org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener&#8221; /&gt;<br />
&lt;property name=&#8221;hibernate.ejb.event.post-update&#8221; value=&#8221;org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener&#8221; /&gt;<br />
&lt;property name=&#8221;hibernate.ejb.event.post-delete&#8221; value=&#8221;org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener&#8221; /&gt;<br />
&lt;property name=&#8221;hibernate.ejb.event.pre-collection-update&#8221; value=&#8221;org.hibernate.envers.event.AuditEventListener&#8221; /&gt;<br />
&lt;property name=&#8221;hibernate.ejb.event.pre-collection-remove&#8221; value=&#8221;org.hibernate.envers.event.AuditEventListener&#8221; /&gt;<br />
&lt;property name=&#8221;hibernate.ejb.event.post-collection-recreate&#8221; value=&#8221;org.hibernate.envers.event.AuditEventListener&#8221; /&gt;</p>
<p>Konfigurujemy w ten sposób listenery , które sprawdzają, czy zmieniły się jakieś audytowalne encje i czy należy zachować historię zmian tych encji.</p>
<p>Kolejnym krokiem jest już oznaczenie encji adnotacją @Audited. Jeśli adnotację umieścimy na poziomie klasy, wszystkie pola będą wersjonowane. Możemy również adnotację umieścić na poziomie pól klasy, aby wersjonować tylko wybrane.</p>
<p><strong>Przykład użycia</strong></p>
<p>Po umieszczeniu konfiguracji opisanej w kroku wyżej użycie Envers’a sprowadza się do dodania odpowiednich adnotacji.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Entity<br />
@Audited<br />
public class Item {<br />
&nbsp; &nbsp; @Id<br />
&nbsp; &nbsp; private int id;<br />
<br />
&nbsp; &nbsp; private String name;<br />
<br />
&nbsp; &nbsp; public int getId() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return id;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; public void setId(int id) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; this.id = id;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; public String getName() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return name;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; public void setName(String name) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;<br />
&nbsp; &nbsp; }<br />
}</div></td></tr></tbody></table></div>
<p>I to tak naprawdę wszystko z rzeczy specyficznych dla Envers. Użycie encji w innym zakresie jest tak standardowe, jak w przypadku JPA lub Hibernate i w zasadzie niczym się od nich nie różni.</p>
<p><strong>Przechowywanie rewizji</strong></p>
<p>Dla każdej adnotowanej encji zostanie utworzona dodatkowa tabela przechowująca audyt. Dla naszej encji z podanego przykładu powstanie podstawowa tabela:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CREATE TABLE ITEM<br />
(<br />
ID decimal(10) PRIMARY KEY NOT NULL,<br />
NAME varchar2(1020)<br />
);</div></td></tr></tbody></table></div>
<p>Oraz dodatkowa tabela do przechowywania audytu:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CREATE TABLE ITEM_AUD<br />
(<br />
ID decimal(10) NOT NULL,<br />
REV decimal(10) NOT NULL,<br />
REVTYPE decimal(3),<br />
NAME varchar2(1020),<br />
CONSTRAINT SYS_C006187 PRIMARY KEY (ID,REV)<br />
);</div></td></tr></tbody></table></div>
<p>Dodatkowo doszły nam następujące pola:</p>
<ul>
<li>REV – oznacza numer rewizji;</li>
<li>REVTYPE – typ zmiany; możliwe wartości: 0 – wstawienie rekordu, 1 – modyfikacja rekordu, 2 – usunięcie rekordu.</li>
</ul>
<p>Najnowszy rekord w tabeli audytu będzie miał wartości o jedną wersję wstecz względem wartości w aktualnej tabeli. Jeśli natomiast rekord zostanie usunięty, nie znajdziemy go już w tabeli podstawowej, a najświeższy wpis będzie miał wartości ustawione na &lt;null&gt; i typ rewizji 2.</p>
<p>Numery rewizji są wspólne dla wszystkich encji. Oznacza to, że jeśli najpierw zmienimy encję A, otrzyma ona rewizję 1, dopiero potem zmienimy encję B, która otrzyma rewizję 2 (oczywiście obie będą posiadały oddzielne tabele audytu).</p>
<p><strong>Encja rewizji i zapis dodatkowych danych</strong></p>
<p>Oprócz zapisywania historii zmian danej encji możemy dla każdej rewizji zapisać dodatkowe informacje. Służy do tego encja rewizji – jest to standardowa encja z dodatkową adnotacją oraz dodatkowymi polami, jakie chcemy zapisać. Przykładowo:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Entity<br />
@RevisionEntity(MyRevisionListener.class)<br />
public class MyRevisionEntity extends DefaultRevisionEntity {<br />
&nbsp; &nbsp; private static final long serialVersionUID = -78999006241889798L;<br />
&nbsp; &nbsp; private String username;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; public String getUsername() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return username;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; public void setUsername(String username) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; this.username = username;<br />
&nbsp; &nbsp; }<br />
}</div></td></tr></tbody></table></div>
<p>Klasa DefaultRevisionEntity jest dostarczana wraz z Envers i deklaruje dwa podstawowe pola: id oraz timestamp. Do tego możemy dołożyć dodatkowe informacje, które chcemy zapisać, np. nazwę użytkownika. Wykonuje się to w listenerze wskazanym przez adnotację @RevisionEntity:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public class MyRevisionListener implements RevisionListener {<br />
<br />
&nbsp; &nbsp; public void newRevision(Object revisionEntity) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; MyRevisionEntity entity = (MyRevisionEntity) revisionEntity;<br />
&nbsp; &nbsp; &nbsp; &nbsp; entity.setUsername(&quot;NAZWA UŻYTKOWNIKA&quot;);<br />
&nbsp; &nbsp; }<br />
<br />
}</div></td></tr></tbody></table></div>
<p>Dla przykładowej encji rewizji zostanie utworzona następująca tabela:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CREATE TABLE MYREVISIONENTITY<br />
(<br />
ID decimal(10) PRIMARY KEY NOT NULL,<br />
TIMESTAMP decimal(19) NOT NULL,<br />
USERNAME varchar2(1020)<br />
);</div></td></tr></tbody></table></div>
<p>Teraz przy utworzeniu nowej rewizji dowolnej audytowanej encji zostanie utworzony nowy wpis w tej tabeli z danymi uzupełnionymi według naszego listenera.</p>
<p><strong>Odpytywanie o rewizje</strong></p>
<p>Envers dostarcza klasy użytkowe pozwalające na odpytywanie o stan rewizji poszczególnych encji. Klasa AuditReaderFactory pozwala nam na pobranie instancji AuditReader w zależności od tego, czy operujemy na EntityManager z JPA czy też na Session z Hibernate.</p>
<p>AuditReader pozwala na budowanie zapytań implementujących interfejs AuditReader. Służy on do budowania zapytań w sposób podobny jak w przypadku Hibernate Criteria. Pytać możemy na dwa sposoby:</p>
<ul>
<li>o encję w konkretnej rewizji,</li>
<li>o rewizje, w których encje się zmieniły.</li>
</ul>
<p>Przykład zapytania o konkretną rewizję:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int revision = 1;<br />
AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(Item.class, revision);<br />
<br />
List items = query.addOrder(AuditEntity.property(&quot;name&quot;).desc())<br />
&nbsp; &nbsp; .setFirstResult(4)<br />
&nbsp; &nbsp; .setMaxResults(2)<br />
&nbsp; &nbsp; .getResultList();</div></td></tr></tbody></table></div>
<p>Przykład zapytania o rewizje, w których zmieniała się encja:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int revision = 1;<br />
Number revision = (Number) getAuditReader().createQuery()<br />
&nbsp; &nbsp; .forRevisionsOfEntity(Item.class, false, true)<br />
&nbsp; &nbsp; .setProjection(AuditEntity.revisionNumber().min())<br />
&nbsp; &nbsp; .add(AuditEntity.id().eq(entityId))<br />
&nbsp; &nbsp; .getSingleResult();</div></td></tr></tbody></table></div>
<p><strong>Wnioski</strong></p>
<p>Jak widać, Envers pozwala na łatwe wdrożenie historii zmian bez specjalnego nakładu pracy i praktycznie transparentnie dla istniejącego modelu. Warto też wspomnieć, że Envers stał się już częścią dystrybucji Hibernate’a (od wersji 3.5), co dodatkowo świadczy o jego użyteczności i jakości.</p>
<p><strong>Źródła</strong></p>
<p>Strona główna projektu: <a href="http://jboss.org/envers">http://jboss.org/envers</a><br />
Dokumentacja: <a href="http://docs.jboss.org/envers/docs/index.html">http://docs.jboss.org/envers/docs/index.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/praktyczny-envers/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>W walce o jakość kodu</title>
		<link>http://blog.atena.pl/dbalosc-o-jakosc-kodu</link>
		<comments>http://blog.atena.pl/dbalosc-o-jakosc-kodu#comments</comments>
		<pubDate>Thu, 17 Jun 2010 13:09:08 +0000</pubDate>
		<dc:creator>Adam Andrzejewski</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Narzędzia]]></category>
		<category><![CDATA[sonar]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=963</guid>
		<description><![CDATA[Wielu programistów, zwłaszcza początkujących, nie zwraca uwagi na jakość kodu, który tworzą. Czasami brak nam czasu lub wiedzy na wytworzenie kodu, który &#8211; poza tym że działa &#8211; jest czytelny, zrozumiały i wydajny. Jakość kodu to nie tylko sławne „do not repeat yourself” (swoją drogą często zapomniane&#8230;), ale także całe zestawy reguł dbające o prostotę [...]]]></description>
			<content:encoded><![CDATA[<p>Wielu programistów, zwłaszcza początkujących, nie zwraca uwagi na jakość kodu, który tworzą. Czasami brak nam czasu lub wiedzy na wytworzenie kodu, który &#8211; poza tym że działa &#8211; jest czytelny, zrozumiały i wydajny. Jakość kodu to nie tylko sławne „do not repeat yourself” (swoją drogą często zapomniane&#8230;), ale także całe zestawy reguł dbające o prostotę utrzymania, łatwość zrozumienia, wydajność itd. Na szczęście nie musimy znać ich wszystkich, bo istnieją narzędzia które mogą nas wspierać w pisaniu kodu wysokiej jakości. Jedno z nich chciałbym przedstawić w tym artykule – jest to Sonar.</p>
<p><span id="more-963"></span></p>
<p>Sonar to opensource’owy projekt, który wykorzystuje najpopularniejsze zewnętrzne narzędzia do sprawdzania jakości kodu – pmd, findbugs czy checkstyle. Wyniki prezentowane są na stronie WWW. Ponieważ najlepiej temat poznawać na przykładzie, zainstalujmy Sonara i sprawdźmy jak to wygląda w praktyce.</p>
<p>Przede wszystkim potrzebujemy Sonara – można pobrać go z <a href="http://sonar.codehaus.org/downloads/">http://sonar.codehaus.org/downloads/</a> . Na potrzeby tego artykułu pobrałem wersję 2.1.2.</p>
<p>Dostarczany jest jako paczka zip/tar,  po rozpakowaniu aplikacja jest gotowa do pracy. Żadne wyrafinowane mechanizmy instalacji czy konfiguracji nie są wymagane – wystarczy wejść do folderu Sonara i uruchomić</p>
<pre>bin\windows-x86-32\StartSonar.bat</pre>
<p>w przypadku systemu operacyjnego Windows lub wybrać odpowiedni skrypt dla swojej wersji OS (dostępna jest spora ilość skryptów na systemy Linux, UNIX czy Mac OS). Po bardziej zaawansowaną konfigurację odsyłam do <a href="http://docs.codehaus.org/display/SONAR/Install+Sonar#InstallSonar-Fullinstallationin5steps" target="_blank">dokumentacji</a></p>
<p>W wyniku działania powinniśmy dostać nowe okienko powłoki. Nie należy się martwić, jeżeli jest puste – zależnie od wersji Sonara którą pobraliśmy, czasami będziemy widzieć w nim log aplikacji, a w innych wersjach log domyślnie zapisywany jest do pliku. Aplikacja Sonar dostępna jest pod adresem <a href="http://localhost:9000/">http://localhost:9000/</a></p>
<p>Jeżeli wszystko poszło dobrze, powinniśmy otrzymać stronę główną Sonara</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/06/Sonar.jpeg"><img class="aligncenter size-large wp-image-970" title="Sonar" src="http://blog.atena.pl/wp-content/uploads/2010/06/Sonar-1024x532.jpg" alt="" width="1024" height="532" /></a></p>
<p>Po kliknięciu odnośnika ‘Configuration’ zostaniemy przeniesieni na stronę z listą profili jakościowych domyślnie zdefiniowanych w Sonarze. Oczywiście nic nie stoi na przeszkodzie, aby zdefiniować własny styl – każda reguła posiada dokładny opis, czego dotyczy. A reguł jest aż 706. Jest więc z czego wybierać, tworząc własne profile jakości. Ja pozostanę przy domyślnym „Sonar way” – zbiera najczęstsze błędy i naruszenia.</p>
<p>Jeżeli zechcecie zmienić domyślny profil dla testów, najpierw należy się zalogować jako ‘admin’, domyślne hasło to również ‘admin’.</p>
<p>Aby wykonać analizę projektu, należy wykonać z linii komend polecenie</p>
<pre>mvn sonar:sonar</pre>
<p>Jeżeli nie masz zainstalowanego Mavena to najwyższa pora, by to zrobić &#8211; <a href="http://maven.apache.org/download.html">http://maven.apache.org/download.html</a> Ponieważ nie jest to artykuł o Mavenie, pomijam opis instalacji i konfiguracji. Na stronie projektu są dostępne materiały dobrze opisujące te zagadnienia.</p>
<p>Prawdopodobnie po przeczytaniu powyższego akapitu pomyślałeś, że Sonar nie nadaje się do twoich projektów, bo nie korzystasz z Mavena. Nic bardziej mylnego. Sonar może przeanalizować każdy projekt w Javie. Wystarczy, że dodasz do niego plik pom.xml z następującą treścią</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;project xmlns=&quot;http ://maven.apache.org/POM/4.0.0&quot;<br />
&nbsp; &nbsp;xmlns:xsi=&quot;http ://www.w3.org/2001/XMLSchema-instance&quot;<br />
&nbsp; &nbsp;xsi:schemaLocation=&quot;http ://maven.apache.org/POM/4.0.0 http ://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;<br />
<br />
&nbsp; &nbsp;&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&nbsp; &nbsp;&lt;groupId&gt;pl.atena&lt;/groupId&gt;<br />
&nbsp; &nbsp;&lt;artifactId&gt;test2&lt;/artifactId&gt;<br />
&nbsp; &nbsp;&lt;name&gt;Test2&lt;/name&gt;<br />
&nbsp; &nbsp;&lt;version&gt;1.0&lt;/version&gt;<br />
<br />
&nbsp; &nbsp;&lt;build&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;sourceDirectory&gt;C:\projekt\zrodla&lt;/sourceDirectory&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;plugins&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;plugin&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;configuration&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;source&gt;1.5&lt;/source&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;target&gt;1.5&lt;/target&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;excludes&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;exclude&gt;**/*.*&lt;/exclude&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;/excludes&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/configuration&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;/plugin&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;/plugins&gt;<br />
&nbsp; &nbsp;&lt;/build&gt;<br />
&nbsp; &nbsp;&lt;properties&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;sonar.dynamicAnalysis&gt;false&lt;/sonar.dynamicAnalysis&gt;<br />
&nbsp; &nbsp;&lt;/properties&gt;<br />
&lt;/project&gt;</div></td></tr></tbody></table></div>
<p>W pliku definiujemy nazwę projektu, którego dotyczy analiza oraz ścieżkę do katalogu z plikami źródłowymi projektu. W katalogu, w którym jest nasz plik wywołujemy z listy poleceń</p>
<pre>mvn sonar:sonar</pre>
<p>W efekcie powinnien pojawić się taki trace:</p>
<pre>C:\Documents and Settings\adama\workspace\SonarTest\src&gt;mvn sonar:sonar
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] [sonar-core:internal]
[INFO]  Database dialect class org.sonar.api.database.dialect.Derby
[INFO]  -------------  Analyzing SonarTest
[INFO]  Selected quality profile : Sonar way, language=java
[INFO]  Configure maven plugins...
[INFO]  Sensor SquidSensor...
[INFO]  Java AST scan...
[INFO]  Java AST scan done: 265 ms
[INFO]  Squid extraction...
[INFO]  Squid extraction done: 906 ms
[INFO]  Sensor SquidSensor done: 1250 ms
[INFO]  Sensor JavaSourceImporter...
[INFO]  Sensor JavaSourceImporter done: 3188 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 625 ms
[INFO]  Execute maven plugin maven-pmd-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-pmd-plugin:2.4:pmd]
[INFO] ------------------------------------------------------------------------
[INFO] [pmd:pmd]
[WARNING] Unable to locate Source XRef to link to - DISABLED
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. b
uild is platform dependent!
[INFO]  Execute maven plugin maven-pmd-plugin done: 5265 ms
[INFO]  Sensor PmdSensor...
[INFO]  Sensor PmdSensor done: 3375 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 16 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 94 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 156 ms
[INFO]  Execute maven plugin maven-checkstyle-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-checkstyle-plugin:2.4:ch
eckstyle]
[INFO] ------------------------------------------------------------------------
[INFO] [checkstyle:checkstyle]
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. b
uild is platform dependent!
[WARNING] Unable to locate Source XRef to link to - DISABLED
[INFO]  Execute maven plugin maven-checkstyle-plugin done: 8984 ms
[INFO]  Sensor CheckstyleSensor...
[INFO]  Sensor CheckstyleSensor done: 172 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 94 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 15 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 453 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 5 seconds
[INFO] Finished at: Thu Jun 17 09:22:21 CEST 2010
[INFO] Final Memory: 22M/40M
[INFO] ------------------------------------------------------------------------</pre>
<p>Po odświeżeniu strony głównej Sonara powinny pojawić się informacje o przeanalizowanym projekcie<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/main.jpg"><img class="aligncenter size-large wp-image-969" title="main" src="http://blog.atena.pl/wp-content/uploads/2010/06/main-1024x101.jpg" alt="" width="1024" height="101" /></a><br />
Klikając w nazwę projektu zagłębiamy się w szczegóły:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/drill1.jpg"><img class="aligncenter size-large wp-image-964" title="drill1" src="http://blog.atena.pl/wp-content/uploads/2010/06/drill1-1024x389.jpg" alt="" width="1024" height="389" /></a><br />
Z tego miejsca możemy jeszcze głębiej zajrzeć, np. w konkretny typ błędów:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/drill2.jpg"><img class="aligncenter size-large wp-image-965" title="drill2" src="http://blog.atena.pl/wp-content/uploads/2010/06/drill2-1024x448.jpg" alt="" width="1024" height="448" /></a><br />
Wybierając konkretny błąd, możemy podejrzeć, w którym miejscu w kodzie wystąpiło naruszenie.</p>
<p>Po takiej analizie jak na dłoni widać gdzie i jakie naruszenia popełniliśmy.</p>
<p>Dodatkową istotną funkcjonalnością jest możliwość integracji bezpośrednio z IDE.<br />
W tej chwili Sonar posiada wtyczki do Eclipse i IntelliJ IDEA. W fazie budowy jest też wtyczka do NetBeans. W tym przykładzie skupię się na Eclipse.</p>
<p>Wtyczkę do Eclipse pobieramy z update site http://dist.sonar-ide.codehaus.org/eclipse/<br />
Po instalacji przechodzimy do Window -&gt; Preferences -&gt; Sonar. Możemy zdefiniować nową instancję Sonara, ale domyślnie powinniśmy mieć dodaną już lokalną wersję. Po kliknięciu przycisku  ‘Edit’ możemy sprawdzić czy połączenie z Sonarem działa.</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/06/eclipse_conn.jpg"><img class="aligncenter size-large wp-image-966" title="eclipse_conn" src="http://blog.atena.pl/wp-content/uploads/2010/06/eclipse_conn-1024x784.jpg" alt="" width="1024" height="784" /></a><br />
Następnie klikamy prawym na naszym projekcie, wybieramy ‘Properties i w zakładce Sonar upewniamy się, że jesteśmy podpięci do poprawnej instancji Sonara<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/verifyconn.jpg"><img class="aligncenter size-full wp-image-972" title="verifyconn" src="http://blog.atena.pl/wp-content/uploads/2010/06/verifyconn.jpg" alt="" width="622" height="533" /></a><br />
Jeżeli wszystko się zgadza, ponownie klikamy prawym na projekt, wybieramy Sonar -&gt; Associate Project with Sonar, a potem jeszcze prawy -&gt; Sonar -&gt; Refresh Violations.</p>
<p>Po tych zabiegach nasz kod zostanie zbadany przez Sonara i wszelkie naruszenia zostaną podświetlone oraz dodany stosowny komentarz:<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/sonareclipse.jpg"><img class="aligncenter size-full wp-image-971" title="sonareclipse" src="http://blog.atena.pl/wp-content/uploads/2010/06/sonareclipse.jpg" alt="" width="737" height="690" /></a></p>
<p>Niestety Eclipse pobiera tylko listę naruszeń z serwera Sonara, więc istnieje możliwość że otrzymamy zgłoszenia dotyczące linii kodu, które nie są błędne, a nawet nie istnieją lub są puste. Jeżeli chcemy otrzymać świeżą listę naruszeń, dokładnie odpowiadającą naszej wersji kodu musimy z linii poleceń wywołać
<pre>mvn sonar:sonar</pre>
<p> w katalogu z plikiem pom.xml naszego projektu.</p>
<p>A to jeszcze nie wszystko – przecież rozwój prawdziwych aplikacji to nie tylko development i budowa projektów w IDE. Często większe projekty wykorzystują środowiska Continues Integration do budowy i weryfikacji poprawności kodu. Jednym z takich narzędzi jest Hudson. Sonar wpasowuje się w trend CI dostarczając wtyczkę do Hudsona umożliwiającą weryfikację jakości kodu po każdej budowie projektu. Wtyczka do pobrania jest na stronie <a href="http://wiki.hudson-ci.org/display/HUDSON/Sonar+plugin">http://wiki.hudson-ci.org/display/HUDSON/Sonar+plugin</a>. Dokładne informacje o mechanizmach Hudsona dostępne są na <a href="http://wiki.hudson-ci.org/">stronie projektu</a>, ja skupię się tylko na konfiguracji połączenia z Sonarem.</p>
<p>Po uruchomieniu Hudsona przechodzimy do „Manage Hudson” -&gt; „Manage Plugins” -&gt; „Advanced”. Tam ładujemy pobrany plik z wtyczką Sonara i restartujemy Hudsona.<br />
Następnie przechodzimy do „Manage Hudson”-&gt;”Configure System” i na samym dole dokonujemy konfiguracji instancji Sonara – jeżeli wszystko instalowaliśmy z domyślnymi wartościami nasza konfiguracja ogranicza się jedynie do podania nazwy identyfikacyjnej daną instancję Sonara<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/hudsonconfig.jpg"><img class="aligncenter size-large wp-image-968" title="hudsonconfig" src="http://blog.atena.pl/wp-content/uploads/2010/06/hudsonconfig-1024x352.jpg" alt="" width="1024" height="352" /></a><br />
Po dokonaniu konfiguracji przechodzimy do utworzenia zadania kompilującego i wykonującego weryfikację jakościową. Wybieramy „New Job” -&gt; „Build a free-style software Project”. Dokonujemy standardowej konfiguracji zadania podając namiary na SCM  i metody budowania (maven, ant itp.) – po szczegóły odsyłam do dokumentacji.<br />
Dla nas najistotniejsza jest sekcja „Post-build Actions”. Zaznaczamy opcję „Sonar” i wypełniamy interesujące nas pola. Co ciekawe, z poziomu Hudsona nie potrzebujemy pliku pom.xml, możemy dodać odpowiednie parametry w definicji akcji<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/06/hudsonbuildconfig.jpg"><img class="aligncenter size-large wp-image-967" title="hudsonbuildconfig" src="http://blog.atena.pl/wp-content/uploads/2010/06/hudsonbuildconfig-1024x633.jpg" alt="" width="1024" height="633" /></a></p>
<p>Po zapisaniu i wykonaniu builda powinien pojawić się taki trace</p>
<pre>…
[SonarTest] $ D:\apache-maven-2.1.0\bin\mvn.bat -e -B -f sonar-pom.xml sonar:sonar
+ Error stacktraces are turned on.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] [sonar-core:internal]
[INFO]  Database dialect class org.sonar.api.database.dialect.Derby
[INFO]  -------------  Analyzing SonarTest
[INFO]  Selected quality profile : Sonar way, language=java
[INFO]  Configure maven plugins...
[INFO]  Sensor SquidSensor...
[INFO]  Java AST scan...
[INFO]  Java AST scan done: 312 ms
[INFO]  Squid extraction...
[INFO]  Squid extraction done: 344 ms
[INFO]  Sensor SquidSensor done: 719 ms
[INFO]  Sensor JavaSourceImporter...
[INFO]  Sensor JavaSourceImporter done: 78 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 47 ms
[INFO]  Execute maven plugin maven-pmd-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-pmd-plugin:2.4:pmd]
[INFO] ------------------------------------------------------------------------
[INFO] [pmd:pmd]
[WARNING] Unable to locate Source XRef to link to - DISABLED
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[INFO]  Execute maven plugin maven-pmd-plugin done: 5265 ms
[INFO]  Sensor PmdSensor...
[INFO]  Sensor PmdSensor done: 859 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 0 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 16 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 31 ms
[INFO]  Execute maven plugin maven-checkstyle-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-checkstyle-plugin:2.4:checkstyle]
[INFO] ------------------------------------------------------------------------
[INFO] [checkstyle:checkstyle]
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[WARNING] Unable to locate Source XRef to link to - DISABLED
[INFO]  Execute maven plugin maven-checkstyle-plugin done: 9219 ms
[INFO]  Sensor CheckstyleSensor...
[INFO]  Sensor CheckstyleSensor done: 187 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 157 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 15 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 219 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 27 seconds
[INFO] Finished at: Thu Jun 17 11:12:20 CEST 2010
[INFO] Final Memory: 22M/40M
[INFO] ------------------------------------------------------------------------
Finished: SUCCESS</pre>
<p>W tym momencie możemy przejść na stronę główną aplikacji Sonara żeby sprawdzić wyniki weryfikacji.</p>
<p>Łącząc razem te trzy narzędzia otrzymujemy prawdziwy kombajn do weryfikacji poprawności i jakości tworzonych aplikacji. Korzyści są ogromne:<br />
1.	developerzy tworząc kod danych modułów na bieżąco widzą naruszenia jakościowe<br />
2.	kod oddany do SCM jest pobierany przed Hudsona i regularnie raz na dobę uruchamiana jest procedura budowy całej aplikacji, która sprawdza, czy całość aplikacji się kompiluje i buduje, a następnie jest poddawana weryfikacji przez Sonara<br />
3.	weryfikacje jakości wywoływane przez Hudsona są zapisywane w bazie danych Sonara, a zatem możemy obserwować trendy w jakości kodu oraz korzystać ze wszystkich dobrodziejstw Sonara nie obciążając go nadmierną ilością weryfikacji wywoływanych przez developerów.</p>
<p>Podsumowując – Sonar jest kompleksowym narzędziem do weryfikacji jakości kodu. Może być wykorzystywany zarówno do szybkiej lokalnej weryfikacji jak i przy budowie bardziej złożonych aplikacji w systemach CI. Jest to narzędzie, które zdecydowanie warto posiadać i wykorzystywać by budować dobrej jakości aplikacje.</p>
<p>Źródła:<br />
- <a href="http://docs.codehaus.org/display/SONAR/Documentation ">http://docs.codehaus.org/display/SONAR/Documentation </a><br />
- <a href="http://wiki.hudson-ci.org/display/HUDSON/">http://wiki.hudson-ci.org/display/HUDSON/</a><br />
- <a href="http://maven.apache.org/">http://maven.apache.org</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/dbalosc-o-jakosc-kodu/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>JSR-303 &#8211; przepis na fasolkę. Bardzo dobrą poniekąd. Cz. 1</title>
		<link>http://blog.atena.pl/jsr-303-przepis-na-fasolke-bardzo-dobra-poniekad-cz-1</link>
		<comments>http://blog.atena.pl/jsr-303-przepis-na-fasolke-bardzo-dobra-poniekad-cz-1#comments</comments>
		<pubDate>Thu, 11 Feb 2010 09:21:27 +0000</pubDate>
		<dc:creator>Daniel Ramotowski</dc:creator>
				<category><![CDATA[JBoss]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaEE]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=858</guid>
		<description><![CDATA[Finalna wersja specyfikacji JSR-303: Bean Validation ukazała się światu pod koniec ubiegłego roku (2009). Jest to kolejny przysmak a’la carte z renomowanej kuchni Gavin’a King’a i spółki, który doczekał się formalnej specyfikacji. Zatem – delektujmy się przez chwilę… Dla osób niewtajemniczonych wyjaśniam, że mam na myśli produkt hibernate-validator, który jest protoplastą specyfikacji. Wraz z nią [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Finalna wersja specyfikacji JSR-303: Bean Validation ukazała się światu pod koniec ubiegłego roku (2009). Jest to kolejny przysmak a’la carte z renomowanej kuchni Gavin’a King’a i spółki, który doczekał się formalnej specyfikacji. Zatem – delektujmy się przez chwilę…</strong><br />
<span id="more-858"></span><br />
Dla osób niewtajemniczonych wyjaśniam, że mam na myśli produkt hibernate-validator, który jest protoplastą specyfikacji.<br />
Wraz z nią otrzymaliśmy jej implementację referencyjną w postaci produktu hibernate-validator w wersji 4.<br />
Świadomy tego, że bezapelacyjnie każdego ta historia urzekła przejdę do konkretów.<br />
Dlaczego w ogóle o tym piszę? istnieje co najmniej kilka powodów:</p>
<ol>
<li>Jest to nowy standard w ramach Javy.</li>
<li>Będzie wchodził w skład JEE 6.</li>
<li>Bardzo łatwo się go używa &#8211; również na platformie SAP NetWeaver. <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>Posiada nowe rozbudowane API oraz nowe możliwości rozszerzeń (np. tzw. &#8222;composite constraints&#8221;).</li>
<li>W sposób przezroczysty integruje się z już posiadanym kodem.</li>
</ol>
<p>Ponieważ jest to artykuł subiektywny, nie zamierzam w nim wymieniać wszystkich właściwości oraz różnic w specyfikacji JSR 303 w stosunku do starego hibernate-validator&#8217;a. Ze szczegółami można zawsze zapoznać się pobierając specyfikację ze stron <a href="http://jcp.org/en/jsr/detail?id=303">Java Community Process</a>.</p>
<p>Moim zdaniem bardzo istotna jest rozbudowa specyfikacji o możliwość definiowania mechanizmów walidacji za pomocą deskryptorów XML. Być może niektórzy czytelnicy posądzą mnie tutaj o herezję, ponieważ dziesiątki deskryptorów dostępnych w JEE to swoiste &#8222;małe piekiełko&#8221;. W przypadku walidatora jest to bardzo dobry pomysł o czym świadczą silne argumenty:</p>
<ol>
<li>Deskryptory pozwalają na zastosowanie walidacji w beanach dostarczanych w postaci bibliotek,</li>
<li>Definicje w deskryptorach uniezależniają walidowane komponenty od  API walidatora oraz własnych walidatorów w formie rozszerzeń.</li>
</ol>
<p>Poniżej przedstawiam przykład kodu z zastosowaniem adnotacji oraz odpowiednika z zastosowaniem deskryptora xml.</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// Person.java</span><br />
<span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">test.beans</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.constraints.NotNull</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Size</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.constraints.Past</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Date</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Valid</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Person <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// wymuszenie wartości różnej niż null</span><br />
&nbsp; &nbsp; @NotNull<span style="color: #009900;">&#40;</span>message<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Imię nie może być puste&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> name<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// wymuszenie wartości różnej niż null</span><br />
&nbsp; &nbsp; @NotNull<span style="color: #009900;">&#40;</span>message<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Nazwisko nie może być puste&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> surname<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// wymuszamy datę przeszłą w stosunku do czasu systemowego</span><br />
&nbsp; &nbsp; @Past<span style="color: #009900;">&#40;</span>message<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Należy podać datę przeszłą&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adate+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Date</span></a> birthDate<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// oczekiwanie, że w kolekcji będzie co najmniej jeden element</span><br />
&nbsp; &nbsp; @Size<span style="color: #009900;">&#40;</span>min<span style="color: #339933;">=</span><span style="color: #cc66cc;">1</span>,message<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Należy podać co najmniej jeden adres&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; @Valid <span style="color: #666666; font-style: italic;">// wskazanie aby implementacja wykonała również walidację adresów</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> List<span style="color: #339933;">&lt;</span>Address<span style="color: #339933;">&gt;</span> adrList<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#40;</span>...<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #339933;">----------------------------------------------------------</span><br />
<span style="color: #666666; font-style: italic;">// &nbsp;Address.java</span><br />
<span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">test.beans</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.constraints.NotNull</span><span style="color: #339933;">;</span><br />
<br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Address <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// wymuszenie wartości różnej niż null</span><br />
&nbsp; &nbsp; @NotNull<span style="color: #009900;">&#40;</span>message<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Miasto nie może być puste&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> city<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&#40;</span>...<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Stan analogiczny do powyższego kodu możemy uzyskać za pomocą następujących definicji w deskryptorze xml:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- sample-constraints.xml --&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint-mappings</span> </span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://jboss.org/xml/ns/javax/validation/mapping&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;default-package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test.beans<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/default-package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Person&quot;</span> <span style="color: #000066;">ignore-annotations</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;name&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint</span> <span style="color: #000066;">annotation</span>=<span style="color: #ff0000;">&quot;javax.validation.constraints.NotNull&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Imię nie może być puste<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/field<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;surname&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint</span> <span style="color: #000066;">annotation</span>=<span style="color: #ff0000;">&quot;javax.validation.constraints.NotNull&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Nazwisko nie może być puste<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/field<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;birthDate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint</span> <span style="color: #000066;">annotation</span>=<span style="color: #ff0000;">&quot;javax.validation.constraints.Past&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Należy podać datę przeszłą<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/field<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;adrList&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint</span> <span style="color: #000066;">annotation</span>=<span style="color: #ff0000;">&quot;javax.validation.constraints.Size&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Należy podać co najmniej jeden adres<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;element</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;min&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/element<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;valid</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/field<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Address&quot;</span> <span style="color: #000066;">ignore-annotations</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;city&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint</span> <span style="color: #000066;">annotation</span>=<span style="color: #ff0000;">&quot;javax.validation.constraints.NotNull&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Miasto nie może być puste<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/message<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/field<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint-mappings<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Nie jest trudno wywnioskować, że wszystkie ograniczenia zdefiniowane w kodzie źródłowym mają swoje odpowiedniki w deskryptorze. Aby powyższe przykłady uruchomić, konieczne jest jeszcze skonfigurowanie całego &#8222;silnika&#8221; walidacji.<br />
Konfigurację realizuje się przez zamieszczenie w katalogu META-INF pliku o nazwie validation.xml, który jest deskryptorem konfiguracji JSR-303.<br />
Oto przykład pliku:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;validation-config</span> </span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://jboss.org/xml/ns/javax/validation/configuration&quot;</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;default-provider<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.hibernate.validator.HibernateValidator<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/default-provider<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constraint-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>META-INF/sample-constraints.xml<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constraint-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/validation-config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>W powyższym pliku określono następujące właściwości silnika:</p>
<ol>
<li><strong>Default-provider</strong> wskazuje dostawcę implementacji JSR-303, którym jest oczywiście hibernate validator</li>
<li><strong>Constraint-mapping</strong> wskazuje na dodatkowy deskryptor xml z definicją ograniczeń, można zdefiniować wiele plików z definicją ograniczeń</li>
</ol>
<p>Na deser pozostał mi jeszcze prościutki przykład uruchomienia walidacji w kodzie z zastosowaniem poprzednich przykładów.<br />
Oto on:</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// ValidationTest.java</span><br />
<span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">test.beans</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.ConstraintViolation</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Validation</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.ValidatorFactory</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ValidationTest <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> argv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ValidationTest vt <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ValidationTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Person p <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Person<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; p.<span style="color: #006633;">name</span><span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;John&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; t.<span style="color: #006633;">validateBean</span><span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> validateBean<span style="color: #009900;">&#40;</span>Person p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ValidatorFactory vf <span style="color: #339933;">=</span> Validation.<span style="color: #006633;">buildDefaultValidatorFactory</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Set<span style="color: #339933;">&lt;</span>ConstraintViolation<span style="color: #339933;">&gt;</span> violationSet <span style="color: #339933;">=</span> vf.<span style="color: #006633;">getValidator</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">validate</span><span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span>ConstraintViolation cv <span style="color: #339933;">:</span> violationSet <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">System</span></a>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>cv.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp;<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Smacznej walidacji <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/jsr-303-przepis-na-fasolke-bardzo-dobra-poniekad-cz-1/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

