<?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; JavaEE</title>
	<atom:link href="http://blog.atena.pl/category/java_ee/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>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>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>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>JavaFX jako GUI do JBoss Seam? Nie ma problemu!</title>
		<link>http://blog.atena.pl/javafx-jako-gui-do-jboss-seam-nie-ma-problemu</link>
		<comments>http://blog.atena.pl/javafx-jako-gui-do-jboss-seam-nie-ma-problemu#comments</comments>
		<pubDate>Wed, 18 Aug 2010 08:20:33 +0000</pubDate>
		<dc:creator>Adam Andrzejewski</dc:creator>
				<category><![CDATA[Interfejs]]></category>
		<category><![CDATA[JavaEE]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=996</guid>
		<description><![CDATA[Jakiś czas temu napisałem artykuł opisujący wstępne założenia JavyFX. Wtedy też obiecałem, że gdy uda mi się uruchomić aplikację FXową na serwerze aplikacyjnym, podzielę się doświadczeniem. Właśnie nadszedł ten czas. Często można spotkać opinie, że JavaFX nie ma przyszłości, bo nie posiada żadnego wsparcia dla komunikacji z elementami biznesowymi. Kiedyś być może było to prawdą, [...]]]></description>
			<content:encoded><![CDATA[<p>Jakiś czas temu napisałem artykuł opisujący <a href="http://blog.atena.pl/wprawki-w-javafx">wstępne założenia JavyFX</a>. Wtedy też obiecałem, że gdy uda mi się uruchomić aplikację FXową na serwerze aplikacyjnym, podzielę się doświadczeniem. Właśnie nadszedł ten czas.</p>
<p><span id="more-996"></span></p>
<p>Często można spotkać opinie, że JavaFX nie ma przyszłości, bo nie posiada żadnego wsparcia dla komunikacji z elementami biznesowymi. Kiedyś być może było to prawdą, dziś naprzeciw takim oczekiwaniom wychodzi Flamingo. Jest to framework, który może stać się czymś w rodzaju „kleju” łączącego teoretycznie różne technologie, m.in. JavyFX i Seama.</p>
<p>Aby nie pozostawiać słów bez pokrycia, przygotuję projekt, który zaprezentuje możliwości Flamingo. Pokaże on jak łączyć JavaFX z Seamem. Na koniec wszystko wrzucimy na serwer aplikacji i uruchomimy z poziomu przeglądarki.</p>
<p>Zacznijmy od klasycznego projektu Seama. Wykorzystam tu Eclipse 3.5.2, Seama 2.2, JBossa 5.1 oraz JBoss Tools dla Eclipse, żeby szybko wygenerować działającą aplikację. Jeżeli jeszcze ich nie masz, czas się zaopatrzyć w te niezbędne narzędzia.</p>
<p>W Eclipse wybieramy New &#8211; &gt; Other -&gt; Seam -&gt; Seam Web Project</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/08/newseamapp.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/newseamapp.jpg" alt="" title="newseamapp" width="497" height="497" class="aligncenter size-full wp-image-997" /></a></p>
<p>Wypełniamy pola formularza:</p>
<ul>
<li>nazwa projektu: SeamApp</li>
<li>Target runtime: JBoss 5.1 Runtime</li>
<li>Dynamic Web Module Vesion: 2.5</li>
<li>Target Server: JBoss 5.1 Runtime Server</li>
<li>Configuration: Dynamic web project with JBoss Seam 2.2.0</li>
</ul>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/08/seamwiz1.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/seamwiz1.jpg" alt="" title="seamwiz1" width="480" height="576" class="aligncenter size-full wp-image-998" /></a></p>
<p>Najprawdopodobniej nazwy docelowego runtime’u i serwera będą inne &#8211; w zależności od tego co sobie skonfigurujemy. Najważniejsze, by wybrać JBoss 5.1 (Seam 2.2. teoretycznie działa też na wcześniejszych wersjach).</p>
<p>Przez kilka kolejnych ekranów konfiguratora możemy przeskoczyć z domyślnymi ustawieniami. Dotrzemy ostatecznie do ekranu z wyborem bazy danych i sposobu deploymentu aplikacji. Ponieważ przykłady mają być proste, wybieramy pakowanie do war i bazę HSQLową – lub dowolną inną, nie będziemy korzystać tutaj z tego elementu.<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/08/seamwiz2.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/seamwiz2.jpg" alt="" title="seamwiz2" width="479" height="575" class="aligncenter size-full wp-image-999" /></a></p>
<p>Możemy zmienić jeszcze domyślne pakiety, ale nie jest to konieczne.</p>
<p>Wygenerowana aplikacja jest gotowa do użycia i deploymentu – zawiera wszystkie niezbędne elementy do uruchomienia, przykładowe strony oraz klasę Authenticator służącą do autentykacji użytkownika w systemie. Dla pewności możemy uruchomić aplikację by upewnić się, że wszystko poszło ok.</p>
<p>Aby móc podpiąć się do aplikacji za pomocą JavaFX, musimy dodać do niej kilka niezbędnych elementów. Są to biblioteki Flamingo (linki do wszystkich materiałów znajdują się na końcu artykułu):</p>
<ul>
<li>amf-serializer.jar</li>
<li>flamingo-service.jar</li>
<li>flamingo-services-common.jar</li>
<li>hessian.jar</li>
<li>scannotation.jar</li>
</ul>
<p>Umieszczamy je bezpośrednio w katalogu lib aplikacji. W skład Flamingo wchodzi jeszcze parę bibliotek, ale do podstawowego przykładu wystarczą te. Aby móc wywoływać komponenty Seam musimy jeszcze dodać do pliku web.xml wpis definiujący servlet, który będzie odpowiadał za komunikację JavaFX z Seamem</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">&lt;servlet&gt;<br />
&nbsp; &nbsp; &lt;servlet-name&gt;Hessian Remote Servlet&lt;/servlet-name&gt;<br />
&nbsp; &nbsp; &lt;servlet-class&gt;com.exadel.flamingo.service.seam.HessianToSeamServlet&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;servlet-mapping&gt;<br />
&nbsp; &nbsp; &lt;servlet-name&gt;Hessian Remote Servlet&lt;/servlet-name&gt;<br />
&nbsp; &nbsp; &lt;url-pattern&gt;/flamingo/hessian/*&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;</div></td></tr></tbody></table></div>
<p>Teraz już możemy dostać się do dowolnego komponentu Seam w naszej aplikacji za pomocą Flamingo. Przykładowa aplikacja posiada tylko jeden komponent (autentykator), więc wykorzystajmy go, aby nie komplikować całości. Do klasy Authenticator.java dodajmy metodę</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 /></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> <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> hello<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> name<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> <span style="color: #0000ff;">&quot;Hello &quot;</span> <span style="color: #339933;">+</span> name <span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;!&quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pozostanie ona naszą metodą, którą będziemy wywoływać z poziomu aplikacji FX-owej.</p>
<p>Czas na stworzenie klienta tej jakże wyrafinowanej metody. <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>W Eclipse tworzymy nowy projekt, w którym znajdą się zarówno klasy Java jak i JavaFX. Polecam by zainstalować sobie wytczkę  <a href="http://exadel.org/javafxplugin">Exadel JavaFX Eclipse plugin</a>. Ułatwia ona nieco tworzenie projektów FX-owych w Eclipse. Do tej części wymagane jest też posiadanie JavaFX 1.3 SDK. Jeżeli jeszcze go nie masz – czas zainstalować.</p>
<p>Wybieramy New -&gt; Other -&gt; JavaFX -&gt; JavaFX Project<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/08/newfxapp.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/newfxapp.jpg" alt="" title="newfxapp" width="497" height="496" class="aligncenter size-full wp-image-1000" /></a></p>
<p>Na kolejnych ekranach wizarda wybieramy nazwę projektu (FxClient), wersję SDK JavyFX, oraz JDK do wykorzystania w projekcie. Po &#8222;doklikaniu&#8221; do końca wizarda zostanie utworzony projekt ze wszystkimi niezbędnymi bibliotekami do pisania uruchamiania aplikacji FXowej.</p>
<p>Aby móc skorzystać z mechanizmów Seamowych, musimy dodać jeszcze trzy biblioteki. Tworzymy katalog lib i wrzucamy do niego:</p>
<ul>
<li>jboss-seam.jar (z instalacji seama)</li>
<li>jboss-seam-remoting.jar (jw.)</li>
<li>hessian.jar (ta sama wersja co w aplikacji Seamowej)</li>
</ul>
<p>Teraz musimy dodać interfejs, który będzie bramką do naszej usługi seamowej. W idealnym świecie pewnie byłby on zawarty w dostarczonym z zewnątrz jarze z API, ale upraszczamy wszystko jak możemy.</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 /></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.client.seam.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> HelloWorld <span style="color: #009900;">&#123;</span><br />
&nbsp; &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> hello<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> name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Potrzebna będzie też fabryka tej usługi, dodajmy więc i ją:</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 /></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.client.java</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.net.MalformedURLException</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.caucho.hessian.client.HessianProxyFactory</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">pl.atena.client.seam.api.HelloWorld</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> HelloWorldClient <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> HelloWorldClient CLIENT<span style="color: #339933;">;</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> _url<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> HelloWorld _service<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> HelloWorldClient<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> url<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; _url <span style="color: #339933;">=</span> url<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: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> setServerUrl<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> url<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CLIENT <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HelloWorldClient<span style="color: #009900;">&#40;</span>url<span style="color: #009900;">&#41;</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;">private</span> HelloWorld getService<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;">if</span> <span style="color: #009900;">&#40;</span>_service <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &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; &nbsp; &nbsp; HessianProxyFactory factory <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HessianProxyFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//(1)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _service <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>HelloWorld<span style="color: #009900;">&#41;</span> factory.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>HelloWorld.<span style="color: #000000; font-weight: bold;">class</span>, _url<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//(2)</span><br />
&nbsp; &nbsp; &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%3Amalformedurlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">MalformedURLException</span></a> ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &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>ex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</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><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> _service<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> <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> hello<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> s<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> getService<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">hello</span><span style="color: #009900;">&#40;</span>s<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Krótki komentarz do powyższego:</p>
<p>(1)   – Tworzymy nową instancję fabryki połączeń. Komunikacja za pomocą JavaFX i Seam odbywa się po protokole Hessian.</p>
<p>(2)   – Pobieramy instancję usługi HelloWorld na podstawie adresu URL zasobu. Parametr ten ustawimy już bezpośrednio w skrypcie FX i tam opiszę jego wygląd.</p>
<p>Pozostał nam jeszcze skrypt FX który skorzysta z usługi Seamowej. Utwórzmy go zatem:</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 />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<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;">/*<br />
<br />
*MainFrame.fx<br />
<br />
*<br />
<br />
*Created on sie 12, 2010, 08:09:02 AM<br />
<br />
*/</span><br />
<span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">pl.atena.client.fx</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.stage.Stage</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.Scene</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.text.Text</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.text.Font</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.layout.HBox</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.paint.Color</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.text.TextOrigin</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.ext.swing.SwingButton</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.layout.VBox</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javafx.scene.control.TextBox</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">pl.atena.client.java.HelloWorldClient</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">class</span> Hello<span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//(1)</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> var name<span style="color: #339933;">:</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: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> var str<span style="color: #339933;">:</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: #339933;">;</span> &nbsp; &nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<br />
var helloModel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Hello<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
HelloWorldClient.<span style="color: #006633;">setServerUrl</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;http://localhost:8080/SeamApp/flamingo/hessian/authenticator&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//(2)</span><br />
<br />
var helloText<span style="color: #339933;">:</span> TextBox <span style="color: #339933;">=</span> TextBox <span style="color: #009900;">&#123;</span> <br />
&nbsp; &nbsp; text<span style="color: #339933;">:</span> bind helloModel.<span style="color: #006633;">name</span> with inverse <span style="color: #666666; font-style: italic;">//(3)</span><br />
&nbsp; &nbsp; columns<span style="color: #339933;">:</span> <span style="color: #cc66cc;">7</span><br />
&nbsp; &nbsp; selectOnFocus<span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">true</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
var helloLabel <span style="color: #339933;">=</span> Text<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; y<span style="color: #339933;">:</span><span style="color: #cc66cc;">8</span><br />
&nbsp; &nbsp; font<span style="color: #339933;">:</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Afont+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Font</span></a> <span style="color: #009900;">&#123;</span> name<span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;sansserif&quot;</span>, size<span style="color: #339933;">:</span> <span style="color: #cc66cc;">12</span> <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; fill<span style="color: #339933;">:</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Acolor+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Color</span></a>.<span style="color: #006633;">BLACK</span><br />
&nbsp; &nbsp; content<span style="color: #339933;">:</span> bind <span style="color: #0000ff;">&quot;Server says: {helloModel.str}&quot;</span><br />
&nbsp; &nbsp; textOrigin<span style="color: #339933;">:</span> TextOrigin.<span style="color: #006633;">TOP</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
var helloButton <span style="color: #339933;">=</span> SwingButton &nbsp;<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; text<span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;Say Hello!&quot;</span><br />
&nbsp; &nbsp; action<span style="color: #339933;">:</span> function<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; helloModel.<span style="color: #006633;">str</span> <span style="color: #339933;">=</span> HelloWorldClient.<span style="color: #006633;">CLIENT</span>.<span style="color: #006633;">hello</span><span style="color: #009900;">&#40;</span>helloModel.<span style="color: #006633;">name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #666666; font-style: italic;">//(4)</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
Stage <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//(5)</span><br />
&nbsp; &nbsp; title<span style="color: #339933;">:</span> <span style="color: #0000ff;">&quot;Helloworld Sample&quot;</span><br />
&nbsp; &nbsp; width<span style="color: #339933;">:</span> <span style="color: #cc66cc;">200</span><br />
&nbsp; &nbsp; height<span style="color: #339933;">:</span> <span style="color: #cc66cc;">150</span><br />
&nbsp; &nbsp; scene<span style="color: #339933;">:</span> Scene <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; content<span style="color: #339933;">:</span> VBox <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; translateX<span style="color: #339933;">:</span> <span style="color: #cc66cc;">5</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; translateY<span style="color: #339933;">:</span> <span style="color: #cc66cc;">5</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spacing<span style="color: #339933;">:</span> <span style="color: #cc66cc;">10</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content<span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HBox <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content<span style="color: #339933;">:</span> helloText<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spacing<span style="color: #339933;">:</span> <span style="color: #cc66cc;">10</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HBox <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content<span style="color: #339933;">:</span> helloButton<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spacing<span style="color: #339933;">:</span> <span style="color: #cc66cc;">10</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HBox <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content<span style="color: #339933;">:</span> helloLabel<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spacing<span style="color: #339933;">:</span> <span style="color: #cc66cc;">10</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;">&#93;</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>(1)    – Tworzymy miniklasę, w której będziemy trzymać imię do powitania, oraz odpowiedź z komponentu Seam.<br />
(2)    – Ustawiamy adres do komponentu Seam do którego chcemy się odwołać. Generalnie powinien mieć on postać http://adres_serwera/kontekst_aplikacji/flamingo/hessian/nazwa_komponentu_seam, przy czym /flamingo/hessian to ścieżka dla servletu Flamingo którą wpisaliśmy w web.xml aplikacji seamowej.<br />
(3)    – Wiążemy zawartość pola tekstowego z jedną ze zmiennych naszej miniklasy.<br />
(4)    – Podpinamy wywołanie usługi pod kliknięcie na przycisk.<br />
(5)    – Tworzymy scenę, na której umieszczone zostaną nasze elementy graficzne.</p>
<p>W tym momencie (jeżeli mamy uruchomioną aplikację seamową oczywiście) możemy już uruchomić aplikację FXową i sprawdzić czy wszystko się udało.<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/08/run.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/run.jpg" alt="" title="run" width="200" height="147" class="aligncenter size-full wp-image-1001" /></a><br />
Jak widać, udało nam się wywołać komponent Seam z aplikacji desktopowej.</p>
<p>Czas podnieść sobie nieco poprzeczkę, i zrobić to samo z aplikacji webowej.</p>
<p>Tu też przydatny jest plugin do eclipse, gdyż może on za nas załatwić mozolną walkę z kompilacją do pliku jar wraz z wymaganymi bibliotekami (javafxpackager z linii poleceń też może to zrobić, ale wówczas trzeba się trochę napisać…).</p>
<p>Aby przygotować plik jar odpowiedni do wykorzystania na serwerze aplikacji wystarczy kliknąć na naszym skrypcie prawym przyciskiem myszy i wybierać Run as -&gt; JavaFX Application (applet)<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/08/runasapplet.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/runasapplet.jpg" alt="" title="runasapplet" width="983" height="630" class="aligncenter size-full wp-image-1002" /></a><br />
W folderze dist projektu zostaną utworzone następujące elementy</p>
<ul>
<li>plik jar ze skompilowanym skryptem FX</li>
<li>pliki jnlp, umożliwiające uruchamianie aplikacji przez Java Web Start</li>
<li>strona html, w treści której umieszczony został aplet ze skryptem FX</li>
</ul>
<p>Wszystko to przenosimy do katalogu WebContent naszej aplikacji Seamowej, zmieniamy nazwę wygenerowanego przez kompilator pliku html na index.html i robimy redeploy całej aplikacji. Teraz pod domyślnym adresem aplikacji seamowej powinniśmy otrzymać działający skrypt JavyFX<br />
<a href="http://blog.atena.pl/wp-content/uploads/2010/08/inbrowser.jpg"><img src="http://blog.atena.pl/wp-content/uploads/2010/08/inbrowser.jpg" alt="" title="inbrowser" width="421" height="297" class="aligncenter size-full wp-image-1003" /></a><br />
Prawda, że to proste?</p>
<p>Na koniec jeszcze jedna ciekawostka. Jeżeli zmodyfikujemy plik index.html i dodamy do definicji apletu parametr draggable, będziemy mogli dosłownie wyciągnąć aplet na pulpit (trzymając klawisz alt oraz lewy przycisk myszy) i korzystać z niego nawet po zamknięciu przeglądarki.</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;<br />
&lt;title&gt;MainFrame&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;h1&gt;MainFrame&lt;/h1&gt;<br />
&lt;script src=&quot;http://dl.javafx.com/1.3/dtfx.js&quot;&gt;&lt;/script&gt;<br />
&lt;script&gt;<br />
&nbsp; &nbsp; javafx(<br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; archive: &quot;MainFrame.jar&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; draggable: true,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width: 400,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; height: 400,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code: &quot;pl.atena.client.fx.MainFrame&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; extPackages: &quot;javafx.ext.swing&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: &quot;MainFrame&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; );<br />
&lt;/script&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</div></td></tr></tbody></table></div>
<p>Podsumowując, Flamingo pozwala nam łatwo zintegrować aplikację FXową z aplikacją Seamową. Dzięki niemu możemy korzystać z komponentów Seama zarówno w aplikacji desktopowej, jak i wykorzystać JavaFX do stworzenia interfejsu użytkownika bezpośrednio w aplikacji seamowej. Aplikację przygotowaną w ten sposób bez problemu można umieścić na serwerze, a także udostępnić wersję desktopową przez jnlp. JavaFX nie zabrania wykorzystania innych elementów na stronie, może współistnieć z innymi elementami i bibliotekami. Czas więc zakasać rękawy i stworzyć prawdziwe RIA.</p>
<p>Zasoby i bibliografia</p>
<ul>
<li><a href="http://exadel.org/flamingo">Framework Flamingo</a></li>
<li><a href="http://exadel.org/javafxplugin">Exadel JavaFX Eclipse Plugin</a></li>
<li><a href="http://mkblog.exadel.com/2010/07/enterprise-javafx-with-seam-and-flamingo-complete-edition/">Maxa Blog</a> (wiele pomocnych artykułów na temat łączenia Seama z JavaFX, również bardziej zaawansowanych – polecam!)</li>
<li><a href='http://blog.atena.pl/wp-content/uploads/2010/08/jars.zip'>wymagane pliki jar frameworku flamingo</a>
<li><a href='http://blog.atena.pl/wp-content/uploads/2010/08/FxClient.zip'>FxClient</a></li>
<li><a href='http://blog.atena.pl/wp-content/uploads/2010/08/SeamApp.zip'>Seam App wersja final (z dodanym apletem klienta)</a></li>
<li><a href="http://javafx.com/downloads/all.jsp">JavaFX SDK</a> jeżeli mamy już JDK 1.6.20</li>
<li><a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk-javafx-jsp-142924.html">JDK + JavaFX SDK</a> jeżeli nie mamy jeszcze JDK w wersji 1.6.20</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/javafx-jako-gui-do-jboss-seam-nie-ma-problemu/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OSGi bez irytacji</title>
		<link>http://blog.atena.pl/osgi-bez-irytacji</link>
		<comments>http://blog.atena.pl/osgi-bez-irytacji#comments</comments>
		<pubDate>Tue, 09 Mar 2010 11:26:26 +0000</pubDate>
		<dc:creator>Adam Andrzejewski</dc:creator>
				<category><![CDATA[JavaEE]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=923</guid>
		<description><![CDATA[Niedawno, tworząc pluginy do JIRA, natknąłem się na dość irytujący problem, który objawiał się dziwnymi komunikatami o niemożności zaimportowania niektórych pakietów. Ponieważ pluginami tymi są moduły OSGi, postanowiłem nieco zgłębić to zagadnienie. Na początek słowo wstępu o tym, czym jest OSGi.  Open Services Gateway Initiative -  bo tak należy rozwinąć ten skrót &#8211; to nic [...]]]></description>
			<content:encoded><![CDATA[<p>Niedawno, tworząc pluginy do JIRA, natknąłem się na dość irytujący problem, który objawiał się dziwnymi komunikatami o niemożności zaimportowania niektórych pakietów. Ponieważ pluginami tymi są moduły OSGi, postanowiłem nieco zgłębić to zagadnienie.</p>
<p><span id="more-923"></span>Na początek słowo wstępu o tym, czym jest OSGi.  Open Services Gateway Initiative -  bo tak należy rozwinąć ten skrót &#8211; to nic innego jak system dynamicznych modułów dla Java. Definiuje architekturę modułowych aplikacji, które mogą być uruchamiane w kontenerach wspierających OSGi. Do tychże zaliczyć możemy</p>
<ul>
<li><a href="http://www.eclipse.org/equinox" target="_blank">Equinox</a></li>
<li><a href="http://cwiki.apache.org/FELIX/index.html">Apache Felix</a></li>
<li><a href="http://www.knopflerfish.org/" target="_blank">knopflerfish</a></li>
</ul>
<p>Po co dodatkowy kontener? Co daje modularność? Pytania są jak najbardziej słuszne. Jeżeli idzie o kontenery, to są one tworzone specjalnie po to, by umożliwić zarządzanie aplikacjami modularnymi w sposób najwygodniejszy z możliwych &#8211; podmienianie modułów, ich dołączanie i odłączanie bez konieczności restartu całego serwera.  Umożliwiają zarządzanie zależnościami między modułami i pozwalają budować aplikacje najróżniejszych typów &#8211; od mobilnych do RIA.</p>
<p>Coraz większa popularność OSGi z pewnością ma też coś wspólnego ze wsparciem tego modelu przez Eclipse IDE. Środowisko to posiada wbudowane wizardy do tworzenia modułów OSGi, jak i własny kontener do ich testowania i debugowania.</p>
<p>Utwórzmy prosty moduł OSGi  (zwany Bundle) właśnie w środowisku Eclipse (Europa). Aby to zrobić, wybieramy New-&gt;Project-&gt;Plug-in Development -&gt; Plug-in Project. Dostaniemy do wypełnienia wizard, który utworzy dla nas przykładowy projekt.</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/03/createproject.jpg"><img class="aligncenter size-full wp-image-928" title="createproject" src="http://blog.atena.pl/wp-content/uploads/2010/03/createproject.jpg" alt="" width="504" height="500" /></a></p>
<p>Nazwa: TestBundle</p>
<p>Target Platform: OSGi framework -&gt; standard</p>
<p>Klikamy <strong>Next, Next.</strong> Jako szablon wybieramy <strong>Hello OSGi Bundle</strong> i klikamy next do końca kreatora.</p>
<p>Po zakończeniu powinniśmy dostać projekt z klasą Activator, plikiem MANIFEST.FM oraz build.properties.</p>
<p><a href="http://blog.atena.pl/wp-content/uploads/2010/03/testbundle.jpg"><img class="aligncenter size-large wp-image-929" title="testbundle" src="http://blog.atena.pl/wp-content/uploads/2010/03/testbundle-1024x400.jpg" alt="" width="1024" height="400" /></a></p>
<p>Przyjrzyjmy się wszystkim tym plikom.</p>
<p><strong>Activator</strong></p>
<pre>public class Activator implements BundleActivator {

 /*
 * (non-Javadoc)
 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
 */
 public void start(BundleContext context) throws Exception {
 System.out.println("Hello World!!");
 }

 /*
 * (non-Javadoc)
 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
 */
 public void stop(BundleContext context) throws Exception {
 System.out.println("Goodbye World!!");
 }

}
</pre>
<p>Activator to klasa implementująca BundleActivator &#8211; interfejs, który wskazuje, jak nasz moduł ma być startowany i zatrzymywany. W metodach start/stop wykonywane są operacje dostarczające danych do dalszej pracy i sprzątające przy zamknięciu (nawiązanie połączenia z bazą, zakończenie połączenia)</p>
<p><strong>MANIFEST.FM</strong></p>
<p>Na pierwszy rzut oka, plik MANIFEST to nic nadzwyczajnego, jest on zaszyty w niemal każdej bibliotece JAR. Dla mnie miał on jednak szczególne znaczenie, gdyż był przyczyną owych nieszczęsnych komunikatów o nieprawidłowych pakietach. Wygenerowany plik ma następującą treść</p>
<pre>Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: TestBundle Plug-in
Bundle-SymbolicName: TestBundle
Bundle-Version: 1.0.0
Bundle-Activator: testbundle.Activator
Import-Package: org.osgi.framework;version="1.3.0"
</pre>
<p>Pierwsze, co powinno rzucić się nam w oczy, to dyrektywa Bundle-Activator. Wymieniona jest tam nasza klasa Activator.  Sugeruje to,  że plik MANIFEST, może odgrywać dużo większą rolę niż się wydaje. Prześledźmy więc kolejno wszystkie dyrektywy</p>
<ul>
<li>Bundle-ManifestVersion: 2 &#8211; informuje o tym, z jakiej wersji specyfikacji OSGi korzysta ten bundle. 2 oznacza kompatybilność z release 4 specyfikacji, 1 z wcześniejszymi wersjami</li>
<li>Bundle-Name: &#8211; nazwa bundle w formie czytelnej dla człowieka</li>
<li>Bundle-SymbolicName &#8211; nazwa bundle, pod którą będzie widziany z innych modułów</li>
<li>Bundle-Version: wersja tego bundle (w kontenerach może jednocześnie działać kilka wersji tego samego bundle&#8217;a).</li>
<li>Bundle-Activator: klasa aktywatora bundle&#8217;a, czyli z jakiej klasy należy skorzystać przy uruchamianiu i zatrzymywaniu modułu</li>
<li>Import-Package:  tu definiujemy jakie pakiety chcemy zaimportować do naszego bundle&#8217;a. Możliwe jest importowanie pakietów z innych modułów, a więc ich wzajemne wiązanie i wykorzystywanie funkcjonalności</li>
</ul>
<p>W powyższym zestawieniu brak jednak dyrektywy najbardziej istotnej z punktu widzenia mojego problemu. A mianowicie:</p>
<ul>
<li>Export-Package: tu określamy jakie pakiety z naszego bundle&#8217;a chcemy wyeksportować. <strong>Tylko wyeksportowane pakiety mogą być importowane przez inne moduły.</strong></li>
</ul>
<p>Plik manifestu może posiadać jeszcze parę innych ważnych dyrektyw. Są to</p>
<ul>
<li>Private-Package: tu wymienione są pakiety, których nie chcemy udostępnić. Początkowo wydaje się to nie potrzebne, ale przecież może zaistnieć sytuacja, w której będziemy chcieli wyeksportować klasy pakietu pl.atena.* ale nie pakietu pl.atena.secret.*.  Header ten nie mieści się jednak w oficjalnej specyfikacji, wykorzystywany jest przez narzędzie BND do budowania bundle&#8217;a. Może to być różnie interpretowane w różnych kontenerach</li>
<li>Bundle-Classpath: tu możemy określić, gdzie w naszej bibliotece znajdują się inne wykorzystywane biblioteki. Domyślnie specyfikacja zakłada, że wszelkie dodatkowe pliki jar są w korzeniu bundle&#8217;a.</li>
<li>Ignore-Package: tu wymienione są pakiety ignorowane w trakcie budowania za pomocą narzędzia BND. Podobnie jak Private-Package nie jest to oficjalny nagłówek.</li>
</ul>
<p><strong>build.properties</strong></p>
<p>Plik ten określa tylko ścieżki do wykorzystania w trakcie budowania modułu.</p>
<p>Aplikacje modularne robią coraz większą furorę, więc przyszłość OSGi wydaje się jasna i pewna. Niewykluczone, że jeszcze nie raz przyjdzie mi spotkać się z nimi. Z pewnością podzielę się wtedy swoimi doświadczeniami w ich tworzeniu.</p>
<p><strong>Źródła:</strong></p>
<ul>
<li><a href="http://blog.springsource.com/2008/02/18/creating-osgi-bundles/">Creating OSGi Bundles</a></li>
<li><a href="http://www.osgi.org/Release4/HomePage/">OSGi Alliance</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/osgi-bez-irytacji/feed</wfw:commentRss>
		<slash:comments>0</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>
		<item>
		<title>Hibernate i efektywne sekwencje</title>
		<link>http://blog.atena.pl/hibernate-i-efektywne-sekwencje</link>
		<comments>http://blog.atena.pl/hibernate-i-efektywne-sekwencje#comments</comments>
		<pubDate>Tue, 15 Dec 2009 11:23:33 +0000</pubDate>
		<dc:creator>Daniel Ramotowski</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaEE]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=832</guid>
		<description><![CDATA[Do napisania kilku słów na temat optymalizacji używania generatorów w Hibernate 3 natchnął mnie kolega z pracy Krzysiek &#8211; prawdziwy specjalista Oracle i tropiciel motocyklistów w białych pantoflach (użyłem określenia &#8222;tropiciel&#8221;, w celu podkreślenia swobodnego charakteru tej publikacji i zwiększenia percepcji treści merytorycznych wśród czytelników; ma to oczywiście związek z pewnym zabawnym wydarzeniem ale nie [...]]]></description>
			<content:encoded><![CDATA[<p>Do napisania kilku słów na temat optymalizacji używania generatorów w Hibernate 3 natchnął mnie kolega z pracy Krzysiek &#8211; prawdziwy specjalista Oracle i tropiciel motocyklistów w białych pantoflach <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  (użyłem określenia &#8222;tropiciel&#8221;, w celu podkreślenia swobodnego charakteru tej publikacji i zwiększenia percepcji treści merytorycznych wśród czytelników; ma to oczywiście związek z pewnym zabawnym wydarzeniem ale nie o tym będzie tutaj mowa).</p>
<p><span id="more-832"></span></p>
<p>Kiedyś pracowaliśmy z Krzyśkiem przy tym samym projekcie, który intensywnie wykorzystywał JPA w implementacji Hibernate 3 oraz bazę danych Oracle.<br />
Kolega zwrócił właśnie uwagę na mało wydajny sposób w jaki Hibernate wstawia rekordy do bazy danych:</p>
<ul>
<li>wykonuje polecenie select, które pobiera identyfikator z sekwencji,</li>
<li>wstawia właściwy rekord z pobranym wcześniej identyfikatorem.</li>
</ul>
<p>Krzysiek był na tyle szybki, że zaraz po tym przedstawił propozycję rozwiązania problemu: zastosowanie strategii generowania identyfikatorów  <strong>org.hibernate.id.SequenceIdentityGenerator</strong>.</p>
<p>Co to jest i jak wpływa na wydajność?</p>
<p>Jest to specyficzna dla Hibernate implementacja obsługi sekwencji bazodanowych, która wykorzystuje funkcjonalność sterowników JDBC zgodnych ze specyfikacja 3.0 (charakterystyczna funkcja getGeneratedKeys). Dzięki jej zastosowaniu Hibernate jest w stanie wstawić rekord do bazy danych w połączeniu z wygenerowaniem identyfikatora i tym samym wykonać 50% operacji mniej <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Ograniczeniem zastosowania tego typu sekwencji jest wsparcie wspomnianej już specyfikacji JDBC 3.0 ze strony używanego sterownika.</p>
<p>Aby cieszyć się w pełni wydajnym wstawianiem danych, należy zadeklarować generator używając adnotacji <em>@GenericGenerator</em>. Stanowi ona rozszerzenie Hibernate i nie wchodzi w skład specyfikacji JPA. Adnotację możemy zastosować na pakiecie (w package-info.java), klasie lub atrybucie klasy.</p>
<p>Przykładowa deklaracja generatora może wyglądać następująco:</p>
<pre>package pl.atena;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;

@Entity
@Table(name="TBL_TEST")
public class Test {

    @Id
    @GeneratedValue(generator="jdbc3_generator")
    @org.hibernate.annotations.GenericGenerator(
        name="jdbc3_generator",
        strategy="org.hibernate.id.SequenceIdentityGenerator"
    )
    @Column(name="ID")
    protected Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}</pre>
<p>Jeżeli zależy nam na kodzie, który ma być przenośny miedzy kilkoma bazami danych, generator zoptymalizowaną pod kątem JDBC 3.0 należy umieścić w kodzie klasy (nie na poziomie pakietu). Tak skonstruowany kod w łatwy sposób nadpiszemy za pomocą pliku orm.xml np. przywracając domyślny mechanizm generowania sekwencji .</p>
<p>Przykład:</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;entity class="pl.atena.Test" metadata-complete="false"&gt;
    &lt;attributes&gt;
        &lt;id name="id"&gt;
	    &lt;generated-value strategy="AUTO" /&gt;
	&lt;/id&gt;
    &lt;/attributes&gt;
&lt;/entity&gt;</pre>
<p>Przedstawione informację są kwintesencją całego rozwiązania. Zachęcam osoby ciekawskie do zrobienia testów wydajności, ja tymczasem życząc wszystkim Wesołych Świąt oddaję się tropieniu tematów do kolejnych publikacji.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/hibernate-i-efektywne-sekwencje/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zasoby na Websphere 7 &#8211; aktualizacja właściwości</title>
		<link>http://blog.atena.pl/zasoby-na-websphere-7-aktualizacja-wlasciwosci</link>
		<comments>http://blog.atena.pl/zasoby-na-websphere-7-aktualizacja-wlasciwosci#comments</comments>
		<pubDate>Tue, 17 Nov 2009 13:43:47 +0000</pubDate>
		<dc:creator>Daniel Ramotowski</dc:creator>
				<category><![CDATA[JavaEE]]></category>
		<category><![CDATA[Websphere]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=789</guid>
		<description><![CDATA[Wedle powszechnie utartej opinii im więcej zasobów, tym lepiej. Poza tym od przybytku głowa nie boli, więc zająłem się tworzeniem zasobów na serwerze aplikacji IBM Websphere 7 (źródła danych aplikacji JEE i takie tam inne) . Oczywiście w ferworze twórczości wybrałem bardziej skomplikowaną ścieżkę, używając narzędzia wsadmin, które jest dostarczane z serwerem. Gdy już ochłonąłem, [...]]]></description>
			<content:encoded><![CDATA[<p>Wedle powszechnie utartej opinii im więcej zasobów, tym lepiej. Poza tym od przybytku głowa nie boli, więc zająłem się tworzeniem zasobów na serwerze aplikacji IBM Websphere 7 (źródła danych aplikacji JEE i takie tam inne) . Oczywiście w ferworze twórczości wybrałem bardziej skomplikowaną ścieżkę, używając narzędzia <strong>wsadmin</strong>, które jest dostarczane z serwerem.</p>
<p><span id="more-789"></span></p>
<p>Gdy już ochłonąłem, zacząłem zastanawiać się, jak można modyfikować takie zasoby. Przy użyciu konsoli zarządzania serwerem sprawa jest prosta.<br />
Inaczej rzecz się ma w przypadku modyfikowania właściwości z poziomu skryptów wykonywanych przez wsadmin (Jacl lub Jython).<br />
Większość przykładów tworzenia zasobów pokazuje, jak tworzyć nowe właściwości lub je &#8222;nadpisywać&#8221; przez dodanie nowej z taką samą nazwą, jak istniejąca. Nie jest to dobrym rozwiązaniem, ponieważ konsola administracyjna Websphere gubi się, odczytując właściwości zasobu, w którym istnieje kilka wpisów definiujących ten sam element.</p>
<p>Przykład <span style="color: #ff0000;"><strong>nieprawidłowego</strong></span> modyfikowania zasobów (dodawane są nowe wpisy o identycznych nazwach):</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">1. &nbsp;newURLPropertyValue = [<br />
2. &nbsp; &nbsp; &nbsp;['URL', 'oracleRACXARecoveryDelay'],<br />
3.     &nbsp;['value', 'jdbc:oracle:thin:@localhost:1521:XE']<br />
4. &nbsp;]<br />
5. &nbsp;dataSourceId = AdminConfig.getid(&quot;/DataSource:TestDataSource/&quot;);<br />
6. &nbsp;propertySetId = AdminConfig.showAttribute(dataSourceId,&quot;propertySet&quot;)<br />
7. &nbsp;AdminConfig.create('J2EEResourceProperty', propertySetId , newURLPropertyValue )</div></td></tr></tbody></table></div>
<p>Poniższy przykład pokazuje, jak <span style="color: #3366ff;"><strong>prawidłowo </strong></span>modyfikować wartość właściwości URL</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">1. &nbsp;urlPropertyStr = &quot;/DataSource:TestDataSource/J2EEResourcePropertySet:/J2EEResourceProperty:URL/&quot;<br />
2. &nbsp;urlPropertyId = AdminConfig.getid(urlPropertyStr);<br />
3. &nbsp;AdminConfig.modify('J2EEResourceProperty', urlPropertyId, newURLPropertyValue)</div></td></tr></tbody></table></div>
<p>Czy pomogło ?</p>
<p>Daniel Ramotowski</p>
<p>PS</p>
<p>Mam nadzieję, że nie zaszkodziło. <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>DR</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/zasoby-na-websphere-7-aktualizacja-wlasciwosci/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dobieramy się do JNDI</title>
		<link>http://blog.atena.pl/dobieramy-sie-do-jndi</link>
		<comments>http://blog.atena.pl/dobieramy-sie-do-jndi#comments</comments>
		<pubDate>Fri, 18 Sep 2009 13:00:10 +0000</pubDate>
		<dc:creator>Daniel Ramotowski</dc:creator>
				<category><![CDATA[JavaEE]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=665</guid>
		<description><![CDATA[Dość często w celach testowych muszę wywołać komponent EJB po interfejsie zdalnym i zawsze w takim momencie brakuje mi kompendium informacji na temat ustawiania właściwości kontekstu, specyficznych dla dostawcy serwera aplikacji. To powód, dla którego piszę ten post, a Ty go zapewne czytasz . Nie wdając się w dalsze dyskusje, poniżej charakteryzuję ustawianie właściwości kontekstu JNDI [...]]]></description>
			<content:encoded><![CDATA[<p>Dość często w celach testowych muszę wywołać komponent EJB po interfejsie zdalnym i zawsze w takim momencie brakuje mi kompendium informacji na temat ustawiania właściwości kontekstu, specyficznych dla dostawcy serwera aplikacji.<br />
To powód, dla którego piszę ten post, a Ty go zapewne czytasz <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p><span id="more-665"></span></p>
<p>Nie wdając się w dalsze dyskusje, poniżej charakteryzuję ustawianie właściwości kontekstu JNDI na różnych serwerach aplikacji.<br />
Zakładam przy tym, że każdy z serwerów jest zainstalowany pod dobrze znanym adresem <strong>&#8222;localhost&#8221;</strong> oraz, że usługi są  skonfigurowane na portach domyślnych.</p>
<table border="1" cellspacing="0" cellpadding="1">
<thead>
<tr>
<td>Serwer / właściwość</td>
<th>Context.INITIAL_CONTEXT_FACTORY</th>
<th>Context.PROVIDER_URL</th>
<th>Context.URL_PKG_PREFIXES</th>
</tr>
</thead>
<tbody>
<tr>
<th align="left">SAP NetWeaver 7.1</th>
<td align="left">com.sap.engine.services.jndi.InitialContextFactoryImpl</td>
<td align="left">p4://localhost:50004</td>
<td align="left">com.sap.engine.services</td>
</tr>
<tr>
<th align="left">IBM Websphere 7</th>
<td align="left">com.ibm.websphere.naming.WsnInitialContextFactory</td>
<td align="left">corbaloc:iiop:localhost:2809</td>
<td align="left">com.ibm.ws.naming</td>
</tr>
<tr>
<th>JBoss 4.x, 5.x</th>
<td>org.jnp.interfaces.NamingContextFactory</td>
<td>jnp://localhost:1099</td>
<td>org.jboss.naming:org.jnp.interfaces</td>
</tr>
</tbody>
</table>
<p>Właściwości te możemy przekazać jako mapę podczas tworzenia kontekstu JNDI.<br />
Możemy je również zdefiniować w pliku o nazwie jndi.properties:</p>
<p><strong>Postać pliku dla SAP NetWeaver 7.1</strong></p>
<pre>java.naming.factory.initial=com.sap.engine.services.jndi.InitialContextFactoryImpl
java.naming.provider.url=p4://localhost:50004
java.naming.factory.url.pkgs=com.sap.engine.services</pre>
<p><strong>Postać pliku dla IBM Websphere Application Server 7</strong></p>
<pre>java.naming.factory.initial=com.ibm.websphere.naming.WsnInitialContextFactory
java.naming.provider.url=corbaloc:iiop:localhost:2809
java.naming.factory.url.pkgs=com.ibm.ws.naming</pre>
<p><strong>Postać pliku dla JBoss</strong></p>
<pre>java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces</pre>
<p>Aby w pełni cieszyć się możliwościami wywołań zdalnych komponentów, przydadzą się nam jeszcze biblioteki z implementacją JNDI.</p>
<ul>
<li>Jeżeli używamy SAP NetWeaver Develiper Studio, na ścieżce klas potrzebna nam będzie biblioteka <strong>com.sap.engine.clientapis_2.0.0.090709123112.jar</strong>, którą znajdziemy w katalogu <strong>plugins</strong>.</li>
<li>W przypadku IBM Websphere Application Server 7 będziemy potrzebowali bibliotek <strong>com.ibm.ws.ejb.thinclient_7.0.0.jar</strong> oraz <strong>com.ibm.ws.orb_7.0.0.jar</strong>, które znajdziemy w katalogu <strong>AppServer\runtimes</strong>.</li>
<li>W przypadku serwera JBoss 4.2.X będzie potrzebna biblioteka <strong>jbossall-client.jar</strong>,którą znajdziemy w katalogu <strong>client</strong>.</li>
<li>W przypadku serwera JBoss 5.X będą potrzebne właściwie wszystkie biblioteki z katalogu <strong>client</strong>.</li>
</ul>
<p>Miłej zabawy!!! <img src='http://blog.atena.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>PS. Jako ciekawostkę dodam, że wywołując zdalne metody komponentów EJB zainstalowanych na IBM Websphere warto zapoznać się z narzędziem <strong><a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rejb_3stubscmd.html">createEJBStubs</a></strong>.<br />
Jest ono dostarczane razem z serwerem aplikacji Websphere.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/dobieramy-sie-do-jndi/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JRuby, Script Engine i Java</title>
		<link>http://blog.atena.pl/jruby-script-engine-i-java</link>
		<comments>http://blog.atena.pl/jruby-script-engine-i-java#comments</comments>
		<pubDate>Wed, 13 May 2009 08:39:21 +0000</pubDate>
		<dc:creator>Adam Andrzejewski</dc:creator>
				<category><![CDATA[JavaEE]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JRuby]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.atena.pl/?p=312</guid>
		<description><![CDATA[JRuby, „w 100% czysta implementacja Javy na bazie języka Ruby&#8221;, jak określają go twórcy, dostarcza zalety obydwu tych języków. W artykule tym skupię się jednak tylko na jednym ciekawym aspekcie JRubiego, czyli wykorzystania go bezpośrednio w aplikacjach stricte javowych poprzez Script Engine. Często programiści zostawiają w tworzonych aplikacjach różnego rodzaju furtki, by w razie awarii, [...]]]></description>
			<content:encoded><![CDATA[<p>JRuby, „w 100% czysta implementacja Javy na bazie języka Ruby&#8221;, jak określają go twórcy, dostarcza zalety obydwu tych języków. W artykule tym skupię się jednak tylko na jednym ciekawym aspekcie JRubiego, czyli wykorzystania go bezpośrednio w aplikacjach stricte javowych poprzez Script Engine.</p>
<p><span id="more-312"></span></p>
<p>Często programiści zostawiają w tworzonych aplikacjach różnego rodzaju furtki, by w razie awarii, jakiegoś nietypowego zachowania, mogli dojść do przyczyn. Czasem też dane w programie ewoluują, i okazuje się, że brakuje nam informacji by wykonać daną operację, np. stworzyć zaległy raport czy fakturę.</p>
<p>Java dostarcza środków do sprawnej realizacji tego typu zadań &#8211; silnik skryptowy. Dzięki niemu, możemy bez ingerencji w kod aplikacji czy magicznych sztuczek na poziomie interfejsu dostać się do interesujących nas danych i zmodyfikować je. I to wszystko bez potrzeby restartowania serwera czy przebudowywania kodu zależnie od problemu. Wystarczy umieścić w aplikacji Script Engine i interfejs do jego obsługi. Istnieje cały projekt zajmujący się dostarczaniem bibliotek do obsługi języków skryptowych w Javie &#8211; zainteresowanym polecam stronę <a href="http://scripting.dev.java.net/">https://scripting.dev.java.net/</a></p>
<p>Java dostarcza dwa rodzaje API do obsługi skryptów. Są to:</p>
<ul>
<li>JSR 223 Scripting API</li>
<li> Bean Scripting Framework (BSF) API</li>
</ul>
<p>Java 1.6 standardowo dostarcza engine do obsługi javaskryptu, jeżeli chcemy wykorzystywać JSR 223 do JRubiego, musimy dodać odpowiednie biblioteki do naszej aplikacji:</p>
<ul class="unIndentedList">
<li> jruby-bin-1.0.tar.gz &#8211; do pobrania z <a href="http://jruby.codehaus.org/">jruby.codehouse.org</a></li>
<li> jsr223-engines.tar.gz &#8211; do pobrania z <a href="http://scripting.dev.java.net/">scripting.dev.java.net</a></li>
</ul>
<p>Przyjrzyjmy się jak działa Script Engine na przykładzie*</p>
<pre><strong><span style="color: #a45b62;">import</span></strong> javax.script.*;</pre>
<pre><strong><span style="color: #a45b62;">public class</span></strong> EvalScript {</pre>
<pre>    <span style="color: #a45b62;"><strong>public static void</strong></span> main(String[] args) <span style="color: #a45b62;"><strong>throws</strong></span> Exception {</pre>
<pre style="padding-left: 60px;">ScriptEngineManager factory = <span style="color: #a45b62;"><strong>new</strong></span> ScriptEngineManager()</pre>
<pre style="padding-left: 60px;"><span style="color: #008000;">// Create a JRuby engine.</span><strong>
</strong>ScriptEngine engine = factory.getEngineByName(<strong><span style="color: #0000ff;">"jruby"</span></strong>);</pre>
<pre style="padding-left: 30px;">    <span style="color: #008000;">// Evaluate JRuby code from string.</span><span style="color: #a45b62;"><strong>
    try</strong></span> {
        engine.eval(<strong><span style="color: #0000ff;">"puts('Hello')"</span></strong>);<strong>
</strong>    } <span style="color: #a45b62;"><strong>catch </strong></span>(ScriptException exception) {
        exception.printStackTrace();
    }</pre>
<pre>    }
}</pre>
<p>Powyższa klasa tworzy engine JRuby i próbuje wykonać skrypt napisany w tym języku. Ten prosty przykład wypisuje tylko powitanie, jednak poprzez jego parametryzację możemy w łatwy sposób uzyskać obsługę skomplikowanych skryptów.</p>
<p>Poza ewaluacją skryptu Script Engine pozwala nam na wywoływanie konkretnych metod zdefiniowanych w skrypcie, w zależności od potrzeb.</p>
<p>//klasa Javy **</p>
<pre><span style="color: #a45b62;"><strong>public class</strong></span> RunMethods {</pre>
<pre style="padding-left: 30px;"><span style="color: #a45b62;"><strong>public static void main</strong></span>(String[] args) <span style="color: #a45b62;"><strong>throws</strong></span> ScriptException, FileNotFoundException {</pre>
<pre style="padding-left: 30px;">     ScriptEngineManager factory = <span style="color: #a45b62;"><strong>new</strong></span> ScriptEngineManager();</pre>
<pre>         <span style="color: #008000;">// Create a JRuby engine.</span></pre>
<pre>        <strong> </strong>ScriptEngine engine = factory.getEngineByName(<span style="color: #0000ff;"><strong>"jruby"</strong></span>);</pre>
<pre>         /<span style="color: #008000;">/process a ruby file</span></pre>
<pre>         engine.eval<strong>(</strong>new BufferedReader(<span style="color: #a45b62;"><strong>new</strong></span> FileReader(<strong><span style="color: #0000ff;">"myruby.rb"</span></strong>))<strong>);</strong></pre>
<pre>         <span style="color: #008000;">//call a method defined in the ruby source</span></pre>
<pre>        <strong> </strong>engine.put(<strong><span style="color: #0000ff;">"number</span></strong>", 6); //[1]</pre>
<pre>         long fact = (Long) engine.eval(<strong><span style="color: #0000ff;">"fact($number)"</span></strong>); //[2]</pre>
<pre>         System.out.println(<strong><span style="color: #0000ff;">"fact: "</span></strong> + fact);</pre>
<pre style="padding-left: 60px;">engine.eval(<span style="color: #0000ff;"><strong>"$myglobalvar = fact($number)"</strong></span>); //[3]

long myglob = (Long) engine.getBindings(ScriptContext.ENGINE_SCOPE).get(<strong><span style="color: #0000ff;">"myglobalvar"</span></strong>);//[4]</pre>
<pre>         System.out.println(<strong><span style="color: #0000ff;">"myglob: "</span></strong> + myglob);</pre>
<pre>    }
}</pre>
<p>// myruby.rb **</p>
<pre>def fact(n)</pre>
<pre> if n==0</pre>
<pre>    return 1</pre>
<pre> else</pre>
<pre>    return n*fact(n-1)</pre>
<pre> end</pre>
<pre>end</pre>
<p>Klasa wczytuje plik myruby.rb, który definiuje metodę fact obliczającą silnię dla podanego parametru. Po ewaluacji, engine pozwala nam ustawić lokalne zmienne [1] i wykorzystać je do wywołania metody zdefiniowanej w pliku [2]. Dodatkowo zmienne możemy ustawiać wywołując kolejne ewaluacje [3]. Engine.getBindings pozwala nam odczytać ustawione w skrypcie zmienne [4].</p>
<p>Wszystko fajnie, ale co z modyfikowaniem danych i obiektów Javy? Tu wkraczamy bardziej w samą składnię JRubiego niż istotę Script Engine jednak pozwolę sobie na prosty przykład</p>
<p>//example1.rb***</p>
<pre>   require 'java'      #[1]</pre>
<pre>   import java.lang.System #[2]</pre>
<pre>   frame = javax.swing.JFrame.new("Window") #[3]</pre>
<pre>   label = javax.swing.JLabel.new("The Time" + System::currentTimeMillis) #[4]</pre>
<pre>   frame.getContentPane.add(label) #[5]</pre>
<pre>   frame.setDefaultCloseOperation(javax.swing.JFrame::EXIT_ON_CLOSE)</pre>
<pre>   frame.pack</pre>
<pre>   frame.setVisible(true)</pre>
<p>Wczytując i wykonując powyższy skrypt powinniśmy dostać okienko pokazujące nam informację o aktualnym czasie. Linia [1] jest najistotniejsza w powyższym pliku. To ona pozwala nam na dostęp do standardowych klas Javy. Od tego momentu możemy używać klas Javy poprzez podanie pełnych ścieżek i nazw klas. Aby nie podawać ciągle pakietu klasy możemy użyć słowa import [2]. Linia [3] tworzy nam nowego JFrame&#8217;a, [4] JLabel z informacją o czasie. Operator :: używany jest do dostępu do statycznych metod i pól klasy. Do niestatecznych metod dostęp uzyskujemy przez standardową kropkę [5]. Aby uniknąć wielu importów klas, można importować całe pakiety dyrektywą<strong> include_package</strong> a klasy z poza projektu dostępne są po dodaniu pliku jar do skryptu (dyrektywa <strong>require</strong>)<strong>. </strong>Tym sposobem, możemy w skrypcie dodać brakujące dane, stworzyć potrzebny obiekt i usunąć zbędne dane (np generowanie zaległej faktury po zmianie oferowanych produktów).</p>
<p>Załóżmy, że mamy działającą aplikację na serwerze, z zaimplementowanym Script Engine w postaci formularza z polem tekstowym, który służy do wpisania skryptu. Submit formularza wywołuje metodę ewaluującą wpisany tekst.</p>
<p>Naszą nietypową sytuacją jest konieczność wykonania operacji na fakturze, jej wydrukowanie i usunięcie</p>
<p>// skrypt wpisany do pola tekstowego</p>
<p style="padding-left: 30px;"><strong> </strong></p>
<pre style="padding-left: 30px;">require 'java'</pre>
<pre>    import pl.atena.MyInvoice</pre>
<pre>    import pl.atena.InvoiceRepository</pre>
<pre>    root =  InvoiceRepository.instance</pre>
<pre>    invoice = MyInvoice.new</pre>
<pre>    # manipulate invoice data</pre>
<pre>    root.getInvoices.add(invoice)</pre>
<pre>    root.printInvoice(invoice)</pre>
<pre>    root.removeInvoice(invoice)</pre>
<p><strong> </strong></p>
<p><strong> </strong>//funkcja obsługująca submit formularza</p>
<pre><strong><span style="color: #a45b62;">public void</span></strong> doSubmit(String script) {</pre>
<pre>      <span style="color: #a45b62;"><strong>try</strong></span> {</pre>
<pre>        ScriptEngine engine = factory.getEngineByName(<strong><span style="color: #0000ff;">"jruby"</span></strong>)<strong>;</strong></pre>
<pre>        engine.eval(script)<strong>;</strong></pre>
<pre>      } <span style="color: #a45b62;"><strong>catch</strong></span> (ScriptException exception) {</pre>
<pre>        exception.printStackTrace();</pre>
<pre>      }</pre>
<p>}</p>
<p><strong> </strong>// klasa obsługi faktur</p>
<p><span style="color: #a45b6f;"><strong>class</strong> </span>InvoiceRepository {</p>
<p style="padding-left: 30px;">InvoiceRepository getInstance() {&#8230;}</p>
<p style="padding-left: 30px;">List&lt;Invoice&gt; getInvoices() {&#8230;.}</p>
<p style="padding-left: 30px;"><strong><span style="color: #a45b6f;">void</span></strong> printInvoice(Invoice invoice) {&#8230;.}</p>
<p style="padding-left: 30px;"><strong><span style="color: #a45b6f;">boolean</span></strong> removeInvoice(Invoice invoice {&#8230;}</p>
<p>}</p>
<p>Sytuacji wyjątkowych może być całe mnóstwo, a wszystkie je możemy obsłużyć w analogiczny sposób &#8211; bez konieczności modyfikacji nawet kawałka kodu naszej aplikacji. Jeżeli dodamy do tego, że aplikacja nie dostarcza bezpośrednio GUI do obsługi funkcji removeInvoice, ujawnia się nam prawdziwa potęga Script Engine.</p>
<p><strong> </strong></p>
<p>JRuby pozwala na dużo więcej, wszystkich zainteresowanych odsyłam na stronę projektu http://jruby.codehouse.org</p>
<p>Materiały źródłowe:</p>
<p>* <a href="http://java.sun.com/developer/technicalArticles/scripting/jruby/">http://java.sun.com/developer/technicalArticles/scripting/jruby/</a></p>
<p>** <a href="http://www.ics.muni.cz/%7Emakub/ruby/">http://www.ics.muni.cz/~makub/ruby/</a></p>
<p>*** <a href="http://wiki.jruby.org/wiki/Calling_Java_from_JRuby">http://wiki.jruby.org/wiki/Calling_Java_from_JRuby</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.atena.pl/jruby-script-engine-i-java/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

