<?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>j2ee.pl - związani z javą &#187; Inne</title>
	<atom:link href="http://j2ee.pl/category/inne/feed/" rel="self" type="application/rss+xml" />
	<link>http://j2ee.pl</link>
	<description>związani z Javą</description>
	<lastBuildDate>Mon, 24 Aug 2009 11:45:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Wrażenia po COOLuarach</title>
		<link>http://j2ee.pl/2009/01/26/wrazenia-po-cooluarach/</link>
		<comments>http://j2ee.pl/2009/01/26/wrazenia-po-cooluarach/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 12:56:56 +0000</pubDate>
		<dc:creator>Błażej Bucko</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[Wydarzenia]]></category>
		<category><![CDATA[cooluary]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=532</guid>
		<description><![CDATA[
No i COOLuary się skończyły. Nieobecni niech żałują, bo naprawdę warto było się pojawić i posłuchać, a czasami nawet się wypowiedzieć. Na ich potrzeby przygotowałem ten krótki opis słowno-muzyczny z dodanymi tu i ówdzie zdjęciami&#8230; :)

 Cała impreza zaczęła się od krótkiego wykładu Grzegorza Dudy na temat samej konferencji, spraw organizacyjnych i sponsorów. Potem odbyła [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dworld.pl/cooluary/"><img class="alignleft" style="float: left;margin: 20px;" src="http://j2ee.pl/wp-content/uploads/2008/12/cooluary_logo.png" alt="COOLuary logo" /></a><br />
No i COOLuary się skończyły. Nieobecni niech żałują, bo naprawdę warto było się pojawić i posłuchać, a czasami nawet się wypowiedzieć. Na ich potrzeby przygotowałem ten krótki opis słowno-muzyczny z dodanymi tu i ówdzie zdjęciami&#8230; :)</p>
<p><span id="more-532"></span><br />
<a href="http://j2ee.pl/wp-content/uploads/2009/01/img_3670.jpg"><img class="size-thumbnail wp-image-544" style="border: 1px solid black;" title="Szaleństwo żółtych karteczek" src="http://j2ee.pl/wp-content/uploads/2009/01/img_3670-150x150.jpg" alt="Szaleństwo żółtych karteczek" width="150" height="150" align="left" /></a> Cała impreza zaczęła się od krótkiego wykładu Grzegorza Dudy na temat samej konferencji, spraw organizacyjnych i sponsorów. Potem odbyła się burza mózgów dotycząca zagadnień poszczególnych sesji, kilka osób próbowało szybko opanować bilokację i po krótkim szaleństwie żółtych karteczek przekładanych w pośpiechu po całej planszy całość w końcu ruszyła.</p>
<p>Pierwsza sesja w której uczestniczyłem dotyczyła <a href="http://en.wikipedia.org/wiki/Domain-driven_design">DDD</a> i anemicznego modelu. Dyskusja była ciekawa, dyskutanci bardzo profesjonalni, jednak brakowało (przynajmniej mi) krótkiego wstępu dotyczącego samego DDD.</p>
<p>Druga sesja dotyczyła przyszłości Springa w kontekście ostatnich zmian licencyjnych, braku postępów w rozwoju nowych funkcjonalności i planach wprowadzenia opłat za szeroko pojęty support. Wydaje mi się, że wszyscy zgodnie twierdzili, że zagranie nie do końca było fair, ale należy poczekać co dadzą opłaty. Temat zebrał przy jednym stoliku większość uczestników konferencji, a mniejszość zajmowała się sprawami refaktoringu.</p>
<p>Po obiedzie, zaskakująco smacznym nota bene, przysiadłem się do stolika gdzie toczyła się dyskusja na temat Scali. Niestety od pewnego momentu mój mizerny poziom wiedzy dot. języków funkcyjnych, zmusił mnie do rozpoczęcia wewnętrznych rozważań na tematy zmiany stolika :)</p>
<p><a href="http://j2ee.pl/wp-content/uploads/2009/01/img_3666.jpg"><img class="size-thumbnail" style="border: 1px solid black;" title="Otwarta dyskusja o Javie :)" src="http://j2ee.pl/wp-content/uploads/2009/01/img_3666-150x150.jpg" alt="Otwarta dyskusja o Javie :)" width="150" height="150" align="right" /></a></p>
<p>Czwarta sesja dotyczyła aspektów i AOP. Przyznaję się bez bicia, że wybrałem ją z braku innych ciekawych tematów, ale i tak dowiedziałem się kilku interesujących rzeczy dotyczących nie tylko aspektów, ale też adnotacji i zasad poprawnego programowania.</p>
<p>Ostatnia sesja to długa rozmowa o OSGi, rozpoczęta od trochę długiego wstępu, który na szczęście przerwano w odpowiednim momencie :) Potem dyskusja potoczyła się w arcyciekawym (przynajmniej dla mnie) kierunku virtualizacji, JVM&#8217;a i Xen&#8217;a. Niestety została przerwana losowaniem nagród. Nieskromnie pochwale się, że wygrałem książkę i udało mi się zdobyć jednego RefCardz&#8217;a, niestety nie do końca tego którego chciałem :)</p>
<p>Podsumowując: wielkie brawa dla Grześka (i jego żony) za zorganizowanie UNkonferencji i mam nadzieje, ze edycja druga odbędzie się jeszcze w tym roku :)</p>
<p>PS. W trakcie wszystkich dyskusji krążył po sali dyktafon, więc nieobecni będą mieli szanse posłuchać o czym rozmawialiśmy (nie wiem jaka będzie jakość dźwięku).</p>
<p>PS2. Więcej zdjęć można znależć <a href="http://picasaweb.google.pl/grzegorz.duda/COOLuaryV1">tutaj</a></p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2009/01/26/wrazenia-po-cooluarach/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Apache JAMES &#8211; agent specjalny ds. korespondencji</title>
		<link>http://j2ee.pl/2008/09/01/apache-james-agent-specjalny-ds-korespondencji/</link>
		<comments>http://j2ee.pl/2008/09/01/apache-james-agent-specjalny-ds-korespondencji/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 20:01:50 +0000</pubDate>
		<dc:creator>Michał Mally</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[james]]></category>
		<category><![CDATA[pop3]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=295</guid>
		<description><![CDATA[Wielu z nas marzyło w dzieciństwie, a może nadal marzy, by skonfigurować własny serwer pocztowy. Z marzeniami niestety tak bywa, że jeśli postanowią się już spełnić, to wybiorą do tego najmniej odpowiednią ze wszystkich chwilę. Nie inaczej było w moim przypadku. Sklecony metodami chałupniczymi z części wszelakich serwer po wieloletniej wzorowej służbie odszedł zasłużenie, ale [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;"><img style="float: left; margin: 5px;" src="http://j2ee.pl/wp-content/uploads/2008/08/mi5logo.gif" alt="MI-5" />Wielu z nas marzyło w <em>dzieciństwie</em>, a może nadal marzy, by skonfigurować własny serwer pocztowy. Z marzeniami niestety tak bywa, że jeśli postanowią się już spełnić, to wybiorą do tego najmniej odpowiednią ze wszystkich chwilę. Nie inaczej było w moim przypadku. Sklecony metodami chałupniczymi z części wszelakich serwer po wieloletniej wzorowej służbie odszedł zasłużenie, ale niespodziewanie do komputerowego <em>nieba</em>. Moje dawno nieaktualne już marzenie o konfiguracji serwera pocztowego wydawało się stawać rzeczywistością.</p>
<p style="text-align: justify;">Kiedy wyschły pierwsze łzy na mojej twarzy i minęła pierwsza żałoba, postawiony zostałem przed koniecznością utworzenia w sposób całkowicie błyskawiczny nowej instancji serwera. Z wszystkich usług zależało mi najbardziej na serwisach <strong>SMTP</strong> oraz <strong>POP3</strong>. Rozpoczęła się walka z czasem. Miałem zaledwie kilka dni zanim listy już wysłane na adresy w mojej domenie rozpoczną swoją powrotną wędrówkę na adres nadawcy. Przejrzałem posiadany przeze mnie <em>tabor</em> sprzętowy i z przykrością stwierdziłem, że jedyna dostępna w tym momencie maszyna mogąca służyć moim celom to stary, wysłużony i rozpadający się laptop <em>Asusa</em> z <em>Windowsem XP</em> na swoim pokładzie. Jedyne co łączyło go z serwerem z prawdziwego zdarzenia to fakt, że zmieściłby się on w szafie serwerowej. Zresztą jak w każdej innej meblościance ;)</p>
<p><span id="more-295"></span></p>
<h2>Działajmy!</h2>
<p style="text-align: justify;">Potrzebowałem łatwego w konfiguracji, darmowego, możliwego do zainstalowania na <em>Windowsie</em> oraz nie koniecznie naszpikowanego funkcjonalnością rozwiązania. W kontekście serwerów pocztowych obiła mi się o uszy fraza <a href="http://james.apache.org/">Apache JAMES</a>. Wiedziałem, że jest to projekt napisany w całości w <em>Javie</em> oraz obsługujący protokoły <strong>SMTP</strong> oraz <strong>POP3</strong>. Dodatkowo z literki <strong>J</strong> na początku wnioskowałem, że krzywa nauczania właśnie dla mnie przyjmie wyjątkowo miłe kształty. Postanowiłem więc wypróbować na <em>żywym</em> organizmie wspomniane funkcjonalności <em>agenta</em> oraz zobaczyć co więcej oferuje.</p>
<h2>Instalacyjka</h2>
<p style="text-align: justify;">Jeśli spodziewacie się wielostronnego, skomplikowanego oraz napisanego ciężkim technicznym językiem opisu instalacji to oczekujcie srogiego zawiedzenia. Przy wybraniu ścieżki dla osób nieprzejawiających skłonności sadomasochistycznych należy ściągnąć jedną z dostępnych binarnych paczek na <a href="http://james.apache.org/download.cgi">stronie domowej Apache JAMES</a> oraz rozpakować ją w dowolnie nam pasującym miejscu naszego systemu. W momencie pisania tego artykułu <em>najlepsza</em> wersja szczyciła się numerkiem <strong>2.3.1</strong>.</p>
<p style="text-align: justify;">Należy tutaj podkreślić, że <strong>JAMES</strong> ma budowę modularną pozwalającą na uruchomienie jedynie tych funkcjonalności, które wydają się być dla nas interesujące. Zatem paczka o której mowa zawiera tak naprawdę mikrokontener <strong>Avalon Phoenix</strong> (na próżno zda się szukanie jakiś o nim informacji w <em>guglach</em>, a przyczyny tego faktu postaram się przybliżyć w dalszej części) wraz z dołączonym <strong>Apache JAMES</strong>em. Zatem uruchamiać tak naprawdę będziemy mikrokontener, a nie bezpośrednio aplikację serwera pocztowego.</p>
<p style="text-align: justify;">Niesie to za sobą kolejne implikacje. Znajomość <em>Javy</em> nie jest wymagana, a osoby ją znające nie będą w żaden sposób faworyzowane, aż do momentu w którym nie zdecydują się one na własnoręczne rozszerzenie serwera o specyficzne dla swoich potrzeb funkcjonalności. Rozszerzeń tego typu <strong>Apache JAMES</strong>a można dokonywać poprzez tworzenie tak zwanych <em>mailetów</em> (służy do tego <strong>Mailet API</strong>),  ale ta możliwość nie pozostaje w obszarze zainteresowań tego artykułu.</p>
<h2>Mój pierwszy raz</h2>
<p style="text-align: justify;">Przed przystąpieniem do konfiguracji aplikację można, a nawet należy uruchomić. Dokonamy tego w zależności od systemu operacyjnego wykonując <em>run.bat</em> lub <em>run.sh</em>. Jak udało mi się sprawdzić aplikacja równie bezproblemowo działa zarówno na <em>Windowsach</em> jak i <em>Linuxach</em>.</p>
<p style="text-align: justify;">Wynikiem pierwszego uruchomienia powinien być <em>log</em> na konsoli podobny do poniżej zaprezentowanego.</p>
<pre style="background: #eee; font-size: 0.675; border: 1px dashed black; padding: 5px; font-family: monospace;">Using PHOENIX_HOME:   C:\james-2.3.1
Using PHOENIX_TMPDIR: C:\james-2.3.1\temp
Using JAVA_HOME:      C:\Program Files\Java\jdk1.6.0_03\

Phoenix 4.2

James Mail Server 2.3.1
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service started plain:119
FetchMail Disabled</pre>
<p style="text-align: justify;">W tak zwanym międzyczasie w katalogu <strong>apps/james</strong> pojawiły się pliki i foldery, które będą nam przydatne podczas konfiguracji serwera.</p>
<h2>Konfiguracja</h2>
<p style="text-align: justify;">Ktoś kto miał do czynienia w przeszłości z innymi rozwiązaniami pocztowymi takimi jak <a href="sendmail.org/">Sendmail</a>, <a href="http://exim.org/">Exim</a> czy <a href="http://postfix.org/">Postfix</a> może powiedzieć, że ich konfiguracja jest prosta jedynie <em>post factum</em> ponieważ przegrzebał się przez <em>tony</em> dokumentacji i ma już to na szczęście za sobą. Będę się starał pokazać, że w przypadku <strong>Apache JAMES</strong>a jest nieco inaczej.</p>
<p style="text-align: justify;">Nie opiszę tutaj wszystkich możliwych opcji, ale na przykładzie serwera, który miałem okazję konfigurować postaram się pokazać jak osiągnąć:</p>
<ul>
<li>serwer <strong>SMTP</strong> z autentykacji użytkowników</li>
<li>serwer <strong>POP3</strong> z obsługą szyfrowania i autentykacji</li>
</ul>
<h3>Sposób konfiguracji serwera</h3>
<p style="text-align: justify;">Do podstawowej konfiguracji serwera będzie nam potrzebny zwykły edytor plików tekstowych. Warto byłoby, aby nie był to jednak <em>Microsoft Notepad</em>, ale program, który w minimalnym choć stopniu wspiera edycję <em>XML</em>a. Ja osobiście bardziej z przyzwyczajenia niż dlatego, że jest to rzeczywiście najbardziej odpowiednie narzędzie do tego celu wykorzystałem <a href="http://eclipse.org/">Eclipse</a>&#8216;a.</p>
<p style="text-align: justify;">Aby zmiany, które wprowadzimy do konfiguracji zostały weszły w życie będziemy musieli serwer zatrzymać, a następnie ponownie uruchomić.</p>
<h3>Podstawowa konfiguracja</h3>
<p style="text-align: justify;">Zlokalizujemy teraz plik konfiguracyjny <strong>apps/james/SAR-INF/config.xml</strong>. Nie należy się przejmować jego objętością, ponieważ większą jego cześć stanowią komentarze, które powinny nasze zadanie uczynić jeszcze łatwiejszym.</p>
<p style="text-align: justify;">Rozpoczniemy od zmiany podstawowych własności serwera.</p>
<pre class="prettyprint">&lt;config&gt;
	&lt;James&gt;
		&lt;!-- adres e-mail z którego będą wysyłane (przede wszystkim) informacje o niedostarczonej poczcie --&gt;
		&lt;postmaster&gt;postmaster@bike-diary.org&lt;/postmaster&gt;
		&lt;!-- zezwalamy na dostarczanie maili jedynie na explicite wylistowane przez nas serwery --&gt;
		&lt;!-- nie zezwalamy na wysyłanie listów przy użyciu adresów IP --&gt;
		&lt;!-- wszystkie maila wysłane na adresy w domenie bike-diary.org będą traktowane jako maile do lokalnego dostarczenia --&gt;
		&lt;servernames autodetect="false" autodetectIP="false"&gt;
			&lt;servername&gt;bike-diary.org&lt;/servername&gt;
		&lt;/servernames&gt;
		(...)
	&lt;/James&gt;
	&lt;spoolmanager&gt;
		&lt;processor name="transport"&gt;
			(...)
			&lt;!-- wyłączamy sprawdzanie z jakich adresów IP łączą się nasi użytkownicy --&gt;
			&lt;!-- zamiast tego zastosujemy autentykację SMTP --&gt;
			&lt;!--
				&lt;mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor"&gt;
				&lt;processor&gt; relay-denied &lt;/processor&gt;
				&lt;notice&gt;550 - Requested action not taken: relaying denied&lt;/notice&gt;
				&lt;/mailet&gt;
			--&gt;
			(...)
			&lt;mailet match="All" class="RemoteDelivery"&gt;
				&lt;!-- wymagane przez niektóre serwery SMTP, aby dostarczenie wiadomości mogło się powieść --&gt;
				&lt;mail.smtp.localhost&gt;
					bike-diary.org
				&lt;/mail.smtp.localhost&gt;
			&lt;/mailet&gt;
		&lt;/processor&gt;
	&lt;/spoolmanager&gt;
	(...)
	&lt;remotemanager enabled="true"&gt;
		(...)
		&lt;!-- przy zdalnej konfiguracji serwera będziemy korzystali z szyfrowania --&gt;
		&lt;useTLS&gt;true&lt;/useTLS&gt;
		&lt;handler&gt;
			(...)
			&lt;administrator_accounts&gt;
				&lt;!-- hasło składające się z 8 gwiazdek jest nie do złamania ;) --&gt;
				&lt;account login="root" password="*********" /&gt;
			&lt;/administrator_accounts&gt;
			(...)
		&lt;/handler&gt;
	&lt;/remotemanager&gt;
	&lt;pop3server enabled="true"&gt;
		&lt;!-- wybieramy port 995, ponieważ będziemy chcieli szyfrować połączenia --&gt;
		&lt;port&gt;995&lt;/port&gt;
		&lt;useTLS&gt;true&lt;/useTLS&gt;
		(...)
	&lt;/pop3server&gt;
	&lt;smtpserver enabled="true"&gt;
		(...)
		&lt;handler&gt;
			(...)
			&lt;!-- nie chcemy z naszego serwera zrobić przystani dla spamerów --&gt;
			&lt;authRequired&gt;true&lt;/authRequired&gt;
			(...)
		&lt;/handler&gt;
	&lt;/smtpserver&gt;
	(...)
	&lt;sockets&gt;
		&lt;server-sockets&gt;
			(...)
			&lt;!-- ponieważ chcemy używać szyfrowania musimy odkomentować poniższy fragment --&gt;
			&lt;factory name="ssl"
				class="org.apache.avalon.cornerstone.blocks.sockets.TLSServerSocketFactory"&gt;
				&lt;ssl-factory&gt;
					&lt;keystore&gt;
						&lt;file&gt;conf/keystore&lt;/file&gt;
						&lt;!-- zmień domyślne hasło --&gt;
						&lt;password&gt;secret&lt;/password&gt;
						&lt;!-- zmień domyślne hasło --&gt;
						&lt;key-password&gt;keysecret&lt;/key-password&gt;
						&lt;type&gt;JKS&lt;/type&gt;
						&lt;protocol&gt;TLS&lt;/protocol&gt;
						&lt;algorithm&gt;SunX509&lt;/algorithm&gt;
						&lt;authenticate-client&gt;false&lt;/authenticate-client&gt;
					&lt;/keystore&gt;
				&lt;/ssl-factory&gt;
			&lt;/factory&gt;
		&lt;/server-sockets&gt;
		(...)
	&lt;/sockets&gt;
&lt;/config&gt;</pre>
<p style="text-align: justify;">Powyższy listing przedstawia wprowadzone przeze mnie zmiany do domyślnej konfiguracji serwera wraz z dołączonymi komentarzami wyjaśniającymi powód powstania modyfikacji. Umieszczenie tutaj całej zawartości pliku konfiguracyjnego nie miałoby swojego uzasadnionego sensu, a jedynie znacząco zaciemniłoby prezentowany przeze mnie przykład. Należy jednak zauważyć, że w prawdziwym środowisku produkcyjnym bardziej świadomy swoich potrzeb użytkownik wprowadziłby znacznie większą ilość usprawnień.</p>
<h3>Przygotowywanie wsparcia dla szyfrowania</h3>
<p style="text-align: justify;">Nim przystąpimy do ponownego uruchomienia serwera konieczne będzie jeszcze wygenerowanie składowiska kluczy (ang. <em>keystore</em>) oraz umieszczenie dostarczonej wraz z <strong>Sun JDK</strong> paczki dostawców usług kryptograficznych w odpowiedniej lokalizacji.</p>
<p style="text-align: justify;">Dla powyższego przykładu <em>keystore</em> możemy utworzyć przy pomocy dostarczonego wraz z <strong>Sun JDK</strong> narzędzia <em>keytool</em>.</p>
<pre class="prettyprint">keytool -genkey -keypass keysecret -keystore keystore -storepass secret</pre>
<p style="text-align: justify;">Powyższe polecenie należy wykonać w folderze <strong>apps/james/conf</strong>. Więcej informacji na temat generowania kluczy można uzyskać  <a href="http://java.sun.com/docs/books/tutorial/security/toolsign/step3.html">tutaj</a>.</p>
<p style="text-align: justify;">Przed przystąpieniem do ponownego uruchomienia serwera musimy jeszcze odnaleźć plik <strong>sunjce_provider.jar</strong> znajdujący się wewnątrz instalacji <strong>Sun JDK</strong>. Wspomniany plik należy przekopiować do folderu <strong>lib</strong> katalogu instalacyjnego <strong>Apache JAMES</strong>a.</p>
<div style="text-align: justify; border: 1px dashed black; background: #f77; padding: 5px;">Nie wykonanie powyższego kroku (lub jego niewłaściwe wykonanie) ze względu na <em>specyficzne</em> rozwiązanie zaimplementowane w <strong>Apache JAMES</strong>ie doprowadzi niechybnie do spowodowanie lokalnego <a href="http://pl.wikipedia.org/wiki/DoS">DOS</a>a. W mojej osobistej ocenie jest to ewidentny błąd programistów, czy też architektów tego serwera pocztowego. Miejmy nadzieję, że zostanie on  w niedalekiej przyszłości poprawiony :)</div>
<h3>Ponowne uruchomienie serwera</h3>
<p style="text-align: justify;">Oczywiście jeżeli mamy otwartą konsole w której jest uruchomiony właśnie serwer aplikacji, to do jego zatrzymania moglibyśmy użyć nieśmiertelnego <em>Ctrl-C</em> ;) My natomiast nauczymy się tą czynność wykonywać w bardziej prawidłowy sposób i przy okazji poznamy kolejny komponent <strong>Apache JAMES</strong>a, jakim jest <strong>RemoteManager</strong>.</p>
<p style="text-align: justify;">Wspomniany przed chwilą <strong>RemoteManager</strong> domyślnie uruchamiany jest na <em>4555</em> porcie i komunikuje się ze <em>światem zewnętrznym</em> przy pomocy protokołu <em>telnet</em>. Służy on do ogólnie pojętego zarządzania serwerem pocztowym w tym między innymi pozwala na dodawanie, modyfikowanie oraz usuwanie kont użytkowników.</p>
<p style="text-align: justify;">Z poziomu <em>Windowsa</em> w celach połączenia się z <strong>RemoteManager</strong>em możemy wykorzystać <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">PuTTY</a>.</p>
<p style="text-align: justify;">Zalogujmy się zatem wybierając typ połączenia <em>telnet</em>, odpowiedniego hosta oraz port <em>4555</em>. Naszym oczom powinna ukazać się zachęta do wprowadzenia danych uwierzytelniających (należy zerknąć do pliku konfiguracyjnego w celu upewnienia się jakie dane powinny zostać tutaj wprowadzone). Niestety z przykrością stwierdzam, że wprowadzane przez nas hasło będzie widoczne na ekranie komputera. Należy zatem zachować szczególną ostrożność by krytyczne dane nie zostały przechwycone przez osoby do tego niepowołane. W wyniku udanego logowania oraz wpisania komendy <em>HELP</em> powinniśmy zobaczyć ekran podobny do poniżej zaprezentowanego zawierający wszystkie aktualnie dostępne polecenia obsługi.</p>
<pre style="background: #eee; font-size: 0.675; border: 1px dashed black; padding: 5px; font-family: monospace;">Currently implemented commands:
help                                    display this help
listusers                               display existing accounts
countusers                              display the number of existing accounts
adduser [username] [password]           add a new user
verify [username]                       verify if specified user exist
deluser [username]                      delete existing user
setpassword [username] [password]       sets a user's password
setalias [user] [alias]                 locally forwards all email for 'user' to 'alias'
showalias [username]                    shows a user's current email alias
unsetalias [user]                       unsets an alias for 'user'
setforwarding [username] [emailaddress] forwards a user's email to another email address
showforwarding [username]               shows a user's current email forwarding
unsetforwarding [username]              removes a forward
user [repositoryname]                   change to another user repository
shutdown                                kills the current JVM (convenient when James is run as a daemon)
quit                                    close connection</pre>
<p style="text-align: justify;">Analizując powyższą listę można w łatwy sposób uzyskać informację na temat dostępnych opcji. Nas w tym momencie będzie interesowała opcja <em>shutdown</em> powodująca <em>grzeczne</em> zakończenie pracy przez serwer. Po udanym zatrzymaniu oraz ponownym uruchomieniu mikrokontenera powinniśmy już na konsoli ujrzeć, że nowe ustawienia weszły w życie (możemy to na przykład sprawdzić weryfikując numery portów na których uruchomiły się poszczególne usługi). Jeżeli coś sugeruje, że serwer nie uruchomił się prawidłowo warto spojrzeć na konsolę oraz zerknąć do folderu z logami <strong>apps/james/logs</strong>.</p>
<p style="text-align: justify;">Od tej pory po każdorazowej zmianie ustawień serwera polegającej na modyfikacji pliku konfiguracyjnego będziemy musieli wykonać ponowne uruchomienie serwera w sposób jaki został powyżej opisany.</p>
<h2>Podstawowe testy usługi</h2>
<p style="text-align: justify;">W celu skutecznego przetestowania usług należy przy pomocy <strong>RemoteManager</strong>a dodać użytkownika testowego (bądź <em>rzeczywsitego</em>). Następnie zgodnie z wprowadzonymi w pliku konfiguracyjnym serwera parametrami można dodać nowe konto pocztowe w swoim ulubionym kliencie poczty. Szczególną uwagę zwrócić należy na ustawienia protokołu <em>SMTP</em> oraz <em>POP3</em>.</p>
<p style="text-align: justify;">Na koniec w ramach przetestowania podstawowej funkcjonalności serwera można wysłać ze swojego innego konta pocztowego na serwerze zewnętrznym wiadomość na testowy adres i <em>vice versa</em>. Jeżeli obie wiadomości zostaną pomyślnie dostarczone będzie to oznaczało, że podstawowa funkcjonalność serwera działa. Hurra!</p>
<p style="text-align: justify;">W przypadku wystąpienia błędów warto przejrzeć pliki logów w poszukiwaniu wartościowych wskazówek oraz sprawdzić ponownie konfigurację serwera.</p>
<h2>Czego więcej można się spodziewać?</h2>
<p style="text-align: justify;">Przeglądając plik konfiguracyjny można łatwo zorientować się jakie inne nieopisane przeze mnie w tym artykule funkcjonalności posiada <strong>Apache JAMES</strong>. Za ciekawostkę z pewnością można uznać moduł <strong>IMAP</strong> (będący w momencie pisanie przeze mnie tego tekstu w fazie eksperymentalnej). Bardziej zainteresowanych czytelników z czystym sumieniem mogę odesłać do oficjalnej dokumentacji <strong>Apache JAMES</strong>a.</p>
<h2>Komu serwer, komu – bo idę do domu.</h2>
<p style="text-align: justify;">Literka <strong>E</strong> w nazwie serwera ma oznaczać, że ma on służyć do rozwiązań <em>biznesowych</em>. Czy rzeczywiście tak jest? Trudno jest mi to jednoznacznie ocenić. Z pewnością sprawdza się wspaniale w zastosowaniach <em>domowych</em> oraz w fazie deweloperskiej rozwoju aplikacji korzystających z serwera pocztowego. Nie lada zaletą jest także jego rozszerzalność, która umożliwia nam w łatwy sposób dodawanie nowych specyficznych funkcjonalności. Zatem każdy musi sobie sam odpowiedzieć, czy <strong>Apache JAMES</strong> jest rozwiązaniem spełniającym oczekiwania. W moim mniemaniu jest on z pewnością produktem, który zasługuje na swoją szansę.</p>
<h2>Wątpliwości architektoniczne</h2>
<p style="text-align: justify;">Serwer <strong>Apache JAMES</strong> jest wciąż mniej lub bardziej dynamicznie rozwijany. Tym bardziej wątpliwości może budzić fakt, że korzysta on z mikrokontenera <strong>Apache Avalon</strong>, który już dawna temu przestał być wspierany. Na stronie domowej serwera pocztowego można jednak znaleźć informacje, że wspomniane rozwiązanie nie przysparza żadnych większych problemów. Mimo to autorzy planują przenieść swój produkt na inne, wspierane środowisko. Kiedy to będzie miało miejsce? Tego nie wiadomo.</p>
<h2>Lineczki</h2>
<ul>
<li><a href="http://james.apache.org/">Strona domowa Apache JAMES</a></li>
<li><a href="http://java.sun.com/docs/books/tutorial/security/toolsign/step3.html">Generating keys</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/09/01/apache-james-agent-specjalny-ds-korespondencji/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JBoss jBPM!?</title>
		<link>http://j2ee.pl/2008/08/29/jboss-jbpm/</link>
		<comments>http://j2ee.pl/2008/08/29/jboss-jbpm/#comments</comments>
		<pubDate>Fri, 29 Aug 2008 07:41:02 +0000</pubDate>
		<dc:creator>Kamil Krasnodębski</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[WebServices]]></category>
		<category><![CDATA[JBoss]]></category>
		<category><![CDATA[jBPM]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=274</guid>
		<description><![CDATA[Słowem wprowadzenia jBPM (Business Process Management) jest platformą przeznaczoną do modelowania procesów biznesowych .
Specyfiką procesów biznesowych jest oczekiwanie. Większość systemów komputerowych jest budowana aby coś było wykonane natychmiast, jednak jest to niemożliwe gdy z procesem jest związana aktywność kilku ludzi. Proces modelowany za pomocą jBPM opiera się o stany w których system oczekuje na wykonanie [...]]]></description>
			<content:encoded><![CDATA[<div class="mceTemp"><img class="alignleft" title="jBPM_logo" src="http://www.jboss.org/file-access/default/members/jbossjbpm/images/jbpm_logo.png" alt="jBPM" width="287" height="137" />Słowem wprowadzenia jBPM (Business Process Management) jest platformą przeznaczoną do modelowania procesów biznesowych .</div>
<div class="mceTemp">Specyfiką procesów biznesowych jest oczekiwanie. Większość systemów komputerowych jest budowana aby coś było wykonane natychmiast, jednak jest to niemożliwe gdy z procesem jest związana aktywność kilku ludzi. Proces modelowany za pomocą jBPM opiera się o stany w których system oczekuje na wykonanie pracy przez człowieka. </p>
<p><span id="more-274"></span></div>
<h2 class="mceTemp">Wprowadzenie.</h2>
<p class="mceTemp">Na jBPM składają się:</p>
<div class="mceTemp">
<ul>
<li><strong>jPDL</strong>-grafowy język programowania oparty o xml,</li>
<li><strong>GPD </strong>- graficzny edytor (wtyczka do Eclipse),  który pozwala na szybkie i w miarę intuicyjne utworzenie modelu procesu w języku jPDL,</li>
<li><strong>PVM </strong>- Proces Virtual Machine za pomocą którego jPDL ożywa.</li>
</ul>
</div>
<p class="mceTemp">Siłą jBPM jest właśnie jPDL który łączy pracę analityka i programisty w jednym pliku. Analityk najpierw modeluje proces (np.  sprzedaż produktu) wyszczególniając na grafie kierunkowym wszystkie istotne kroki danego procesu. Etap ten jest podobny do modelowania diagramu przepływu lub przypadków użycia znanych z UML czyli przyjazny dla analityka. Następnie programista po otrzymaniu takiego pliku zaczyna podpinać do poszczególnych węzłów grafu różne akcje i zadania (np. wywołanie zdalnego systemu, zapis do bazy danych). Użyłem słowa podpinać gdyż programista przy pomocy GPD wskazuje po prostu klasy które mają być użyte do obsługi.  Kolejną miłą właściwością jBMP jest persystencja  oparta o Hibernate co pozwala na umieszczenie tabel jBPM&#8217;a zarówno obok tabel naszej aplikacji jak i w całkowicie oddzielnej bazie danych. W bazie danych zapisywane są definicje procesów, instancje procesów oraz dane zgromadzone w zadaniach (task).</p>
<h2 class="mceTemp">Jak to się robi.</h2>
<p class="mceTemp">Początek jest banalnie prosty wpisujemy  http://www.jboss.org/jbossjbpm/  pojawia nam się strona z wielkim przyciskiem DOWNLOAD  i idąc tym tropem ściągamy sobie jPDL Suite. Tak zdobytą paczkę rozpakować należy w dowolnym miejscu i przejść do katalogu &#8220;designer&#8221; z tego miejsca odpalamy anta który zainstaluje nam eclipse.  Można też po prostu ściągnąć sobie eclipse i rozpakować go do katalogu ./designer/eclipse.</p>
<p class="mceTemp">Po uruchomieniu eclipse tworzymy nowy projekt JBoss jBPM/Process Project. Dajemy mu nazwę i klikamy &#8216;Finish&#8217;. Naszym oczom ukazuje się przykładowy projekt wraz z  jednym handlerem i JUnit testem.  Najważniejszą częścią tego przykładu jest plik<em> procesdefinition.xml</em> który zawiera  graf kierunkowy determinujący przebieg procesu, jest napisany w języku jPDL.</p>
<p class="mceTemp">Bloki procesu (grafu) dzielą się na kilka grup. Dokładny opis wszystkich bloków był by bardzo obszerny więc przedstawię tylko podstawowe.</p>
<p class="mceTemp"><strong>States </strong>służą do określenia kolejnych kroków procesu istotnych z punktu biznesowego i  wykonywanych automatycznie(bez ingerencji użytkownika) np. odpytanie o dane jakiegoś zewnętrznego systemu.</p>
<div class="mceTemp">
<p><strong>Nodes </strong>są podobne do States jednak są wyposażone w pole odpowiadające za wykonanie konkretnej akcji.</div>
<p class="mceTemp"><strong>Tasks Node</strong> jest specyficznym stanem gdyż jest przeznaczony do umieszczania w nim zadań do wykonania dla człowieka. Proces przechodzi dalej w chwili zakończenia zadania przez człowieka np. następnego dnia. W czasie obsługi danego zadania w dowolnym momencie można zapisać jego aktualny stan.</p>
<p class="mceTemp"><strong>Fork i Join</strong> służące do rozdzielenia procesu na kilka równolegle wykonywanych ścieżek. Istotną rzeczą jest że fork i join zawsze pracują w parach i wszystkie ścieżki wychodzące z jednego forka muszą skończyć się w jednym joinie. Proces oczekuje na bloku Join do zakończenia wszystkich ścieżek.</p>
<p class="mceTemp"><strong>Transition </strong>jest to połączenie pomiędzy blokami procesu określające kierunek przejścia. Z bloku może wyjść dowolna liczba połączeń. Jeśli podczas wyjścia z bloku nie jest podana nazwa połączenia proces przechodzi po pierwszym (kolejność w xml).</p>
<p class="mceTemp">Każdy blok ma możliwość podpięcia klasy obsługującej wyjątki, oraz dowolną liczbę klas obsługujących akcje, wykonywanych gdy nastąpi zdarzenie do których są przyporządkowane(np. node enter, node leave). Akcje mogą być również przyporządkowane do Transitions.</p>
<div class="mceTemp">
<p>Proces (graf) zaczyna się od bloku Start State i kończy na bloku End State.</p>
<p><a href="http://j2ee.pl/wp-content/uploads/2008/08/simple.png"><img class="alignnone size-medium wp-image-275" title="simple" src="http://j2ee.pl/wp-content/uploads/2008/08/simple-214x300.png" alt="" width="214" height="300" /></a></div>
<div class="mceTemp">
<p>Na powyższym rysunku widać prosty przykładowy proces.  Widok źródła wygląda następująco:</p></div>
<div class="mceTemp">
<pre class="prettyprint">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="simple"&gt;
	&lt;start-state name="start"&gt;
		&lt;transition name="to_state" to="first"&gt;
			&lt;action name="action"
				class="com.sample.action.MessageActionHandler"&gt;
				&lt;message&gt;Going to the first state!&lt;/message&gt;
			&lt;/action&gt;
		&lt;/transition&gt;
	&lt;/start-state&gt;
	&lt;state name="first"&gt;
		&lt;transition name="to_end" to="end"&gt;
			&lt;action name="action"
				class="com.sample.action.MessageActionHandler"&gt;
				&lt;message&gt;About to finish!&lt;/message&gt;
			&lt;/action&gt;
		&lt;/transition&gt;
	&lt;/state&gt;
	&lt;end-state name="end"&gt;&lt;/end-state&gt;
&lt;/process-definition&gt;</pre>
</div>
<div class="mceTemp">W widoku xml widzimy że do transition są przyporządkowane akcje wraz z parametrem do nich przekazywanym. Kod klasy obsługującej wygląda następująco:</div>
<div class="mceTemp">
<pre class="prettyprint">public class MessageActionHandler implements ActionHandler {

	String message; 

	public void execute(ExecutionContext context) throws Exception {
		context.getContextInstance().setVariable("message", message);
	}
}</pre>
</div>
<p class="mceTemp">Jak widać w powyższym kodzie pole message  nie posiada metod get i set jego wartość jest bezpośrednio wstrzykiwana z definicji procesu. Interfejs ActionHandlera posiada tylko jedną metodę do której jako parametr przychodzi ExecutionContext zawierający definicję procesu i jego instancje(wszystkie).</p>
<p class="mceTemp">W momencie wykonania kompletnej implementacji wszystkich zdarzeń oraz podpięciu interfejsu użytkownika, mieli byśmy piękną trzy etapową obsługę czegoś. Gdyby była to aplikacja wykonana tradycyjnie każda zmiana wymagała by w mniejszym lub większym stopniu dostosowania istniejących elementów. Lecz gdy mamy do czynienia z grafem możemy po postu w dowolnym miejscu dodać kolejny element. Jak widać na rysunku poniżej.</p>
<p class="mceTemp"><a href="http://j2ee.pl/wp-content/uploads/2008/08/complex.png"><img class="alignnone size-medium wp-image-279" title="complex" src="http://j2ee.pl/wp-content/uploads/2008/08/complex.png" alt="" width="562" height="213" /></a></p>
<p class="mceTemp"><!--[if gte mso 9]><xml> </xml>< ![endif]--><!--[if gte mso 9]><xml> Normal   0         21         false   false   false      PL   X-NONE   X-NONE </xml>< ![endif]--><!--[if gte mso 9]><xml> </xml>< ![endif]--><!--  --><!--[if gte mso 10]> <mce :style>< !   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:Standardowy; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-priority:99; 	mso-style-qformat:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:11.0pt; 	font-family:"Calibri","sans-serif"; 	mso-ascii-font-family:Calibri; 	mso-ascii-theme-font:minor-latin; 	mso-fareast-font-family:"Times New Roman"; 	mso-fareast-theme-font:minor-fareast; 	mso-hansi-font-family:Calibri; 	mso-hansi-theme-font:minor-latin; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-theme-font:minor-bidi;} --> <!--[endif]--></mce></p>
<p>Wbrew pozorom takie rozszerzanie aplikacji zdarza się dość często szczególnie jak mamy do czynienia z procesami decyzyjnymi oraz organizacją pracy w rozwijających się przedsiębiorstwach.</p>
<h2>Podsumowanie.</h2>
<p>JBPM to platforma do modelowania procesów biznesowych oparta o grafowy język jPDL. Nadaje się świetnie do tworzenia systemów które mają na celu przydzielać zadania do wykonania dla poszczególnych osób w złożonym środowisku procedur i przepisów.</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/08/29/jboss-jbpm/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Widgety &#8211; część druga: WidSets</title>
		<link>http://j2ee.pl/2008/08/21/widgety-czesc-druga-widsets/</link>
		<comments>http://j2ee.pl/2008/08/21/widgety-czesc-druga-widsets/#comments</comments>
		<pubDate>Thu, 21 Aug 2008 14:28:10 +0000</pubDate>
		<dc:creator>Maciej Żywioł</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[WebServices]]></category>
		<category><![CDATA[widget]]></category>
		<category><![CDATA[widsets]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=246</guid>
		<description><![CDATA[Universal Widget API, o którym opowiadałem poprzednio, jest dość wszechstronny i faktycznie działa na wielu platformach, jednak jego zawarta w nazwie uniwersalność ma pewne ograniczenia. Najpoważniejszym z nich jest brak kompatybilności z urządzeniami mobilnymi – działają tylko pod iPhone’em, a Opera Mobile dla &#8220;normalnych&#8221; telefonów jeszcze z nimi nie współpracuje.
Dla chcących pisać widgety na bardziej [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://j2ee.pl/wp-content/uploads/2008/08/widsets1.gif"><img class="alignnone size-medium wp-image-254" title="widsets1" src="http://j2ee.pl/wp-content/uploads/2008/08/widsets1.gif" alt="" width="109" height="36" align="left" /></a>Universal Widget API, o którym opowiadałem poprzednio, jest dość wszechstronny i faktycznie działa na wielu platformach, jednak jego zawarta w nazwie uniwersalność ma pewne ograniczenia. Najpoważniejszym z nich jest brak kompatybilności z urządzeniami mobilnymi – działają tylko pod iPhone’em, a Opera Mobile dla &#8220;normalnych&#8221; telefonów jeszcze z nimi nie współpracuje.</p>
<p>Dla chcących pisać widgety na bardziej pospolite telefony komórkowe jest nadzieja w postaci platformy <a href="https://www.widsets.com/index.html" target="_blank"><strong>WidSets</strong></a>, uruchomionej i wdrożonej przez koncern Nokia, jednak nie tylko na telefony tej firmy przeznaczona.<span id="more-246"></span></p>
<h2>Użytkowanie</h2>
<p>Platforma WidSets współpracuje <a href="https://www.widsets.com/info/compatibility.html" target="_blank">z ponad trzema setkami modeli</a> telefonów komórkowych i opiera się o aplikację, którą w telefonie należy sobie zainstalować. Aplikacja ta łączy się z naszym kontem, założonym w internetowym serwisie WidSets, pobiera dane o wybranych przez nas widgetach i wyświetla je na ekranie naszego telefonu.</p>
<p>Oczywiście, najpierw trzeba sobie w serwisie założyć owo konto. Zanim to jednak zrobimy, serwis WidSets udostępnia nam bardzo ciekawie pomyślaną <a href="https://www.widsets.com/getstarted.html" target="_blank">demonstrację</a> swoich możliwości &#8211; na specjalnej stronie mamy dostępną całą bibliotekę widgetów do wyboru, oraz emulator telefonu komórkowego, na którym możemy podpatrzeć, jak aplikacja będzie wyglądać i działać.</p>
<p>Gdy już zdecydujemy się na <a href="https://www.widsets.com/register.html" target="_blank">rejestrację</a>, będziemy przez jej proces poprowadzeni jak za rączkę &#8211; serwis najpierw pyta o typowe dane rejestracyjne, a następnie pomaga nam pobrać i zainstalować aplikację w telefonie. Trzeba przyznać, że to także jest świetnie rozwiązane &#8211; dostępne są trzy drogi, do wyboru w zależności od stopnia zaawansowania użytkownika, w różnym stopniu absorbujące jego uwagę:</p>
<ul>
<li><strong>Dummies</strong> podają numer telefonu, na który przychodzi sms z linkiem, pod którym znajduje się aplikacja do zainstalowania,</li>
<li><strong>Techies</strong> przepisują podany na stronie URL do przeglądarki w komórce,</li>
<li>a <strong>Geeks</strong> pobierają plik JAD, który ręcznie przenoszą i odpalają w telefonie, instalując tym samym aplikację.</li>
</ul>
<p>Ja wybrałem to środkowe rozwiązanie, co pozwoliło nie czuć mi się ani jak oporny (dummy), ani jak geek.</p>
<p>Po zainstalowaniu w telefonie, aplikacja łączy się z kontem w serwisie i można przejść do konfiguracji, która polega głównie na wybraniu z biblioteki interesujących nas widgetów. <a href="https://www.widsets.com/library.html" target="_blank">Biblioteka</a> jest dość obszerna i zawiera mnóstwo programów przydatnych bardziej (wiadomości, pogoda, organizatory czasu, skrzynki e-mailowe&#8230;) lub mniej (gry i inne czasoumilacze). Bardzo fajne jest to, że swoje widgety można wybierać nie tylko za pośrednictwem telefonu, ale też w komputerze, logując się w serwisie &#8211; nawet, gdy nasz telefon nie jest z nim połączony, my możemy zobaczyć i skonfigurować nasz pulpit (<em>dashboard</em>), a nawet &#8211; odpalić emulator komórki, w którym możemy przetestować jego działanie.</p>
<p>Testowałem działanie WidSetsów na mojej Nokii E50 i wszystko działa bardzo dobrze. Dodatkowe ułatwienie, podejrzewam, mogą mieć posiadacze telefonów z wbudowanym WiFi (np. Nokia E51), którzy nie muszą się łączyć z internetem za pośrednictwem swojej sieci komórkowej.</p>
<h2>Tworzenie</h2>
<p>Jak większość serwisów widgetowych (NetVibes, Opera, Apple&#8230;), także WidSets udostępniają możliwość tworzenia własnych widgetów. Przede wszystkim w serwisie dostępna jest opcja szybkiego generowania widgeta. Ma on, oczywiście, ograniczone możliwości &#8211; można w nim stworzyć właściwie tylko czytnik kanałów RSS lub podobnych i najwyżej wybrać skórkę, która nam będzie odpowiadać &#8211; ale niektórym to w zupełności wystarcza (coś podobnego, ale dla widgetów &#8220;desktopowych&#8221;, oferuje serwis <a href="http://www.wstaw.to/wstawTo/1,88931,5166677.html" target="_blank">wstaw.to</a>).</p>
<p>Dla użytkowników bardziej wymagających i tych z zacięciem programistycznym, WidSets oferują cały <a href="http://wiki.forum.nokia.com/index.php/WidSets_SDK" target="_blank">Software Developer&#8217;s Kit</a> do tworzenia bardziej zaawansowanych programów. Taki wdget składa się z dwóch plików: XML-owego deskryptora (plik <em>widget.xml</em>) oraz z kodu aplikacji (plik <em>*.he</em>). Dodatkowo mogą się na niego składać pliki zasobów, np. obrazki w formacje jpg lub png.</p>
<p>Plik <a href="http://wiki.forum.nokia.com/index.php/Developing_your_first_WidSets_widget#Create_the_widget.xml" target="_blank"><strong>widget.xml</strong></a> zawiera informacje o naszym widgecie: w sekcji &lt;info&gt; znajdują się informacje o widgecie, np:</p>
<pre class="prettyprint"> &lt;info&gt;
   &lt;name&gt;Flag Selector&lt;/name&gt;
   &lt;version&gt;1.0&lt;/version&gt;
   &lt;author&gt;Developer&lt;/author&gt;
   &lt;shortdescription&gt;Displaying some flags&lt;/shortdescription&gt;
 &lt;/info&gt;</pre>
<p>Następnie w sekcji &lt;parameters&gt; opisane są opcje i parametry widgeta &#8211; analogicznie do taga &lt;widget:preferences&gt; w UWA:</p>
<pre class="prettyprint"> &lt;parameters&gt;
   &lt;parameter type="string"
                name="widgetname"
                description="Name of widget"
                help="This is the name of the widget"
                editable="false"
                sendtomobile="true"
                visible="true"&gt;
     &lt;value&gt;
       Flag Selector
     &lt;/value&gt;
   &lt;/parameter&gt;
 &lt;/parameters&gt;</pre>
<p>Następnie, w sekcji &lt;resources&gt; wymienione są dodatkowe źródła danych, np. style, z których aplikacja będzie korzystać (składniowo podobne do CSS), np:</p>
<pre class="prettyprint">&lt;stylesheet&gt;
   bkg {
     background: vgradient white silver;
   }

   frame {
     background: solid silver;
   }

   flag {
     align: hcenter vcenter;
     border: 2 2 2 2;
     border-type: rectangle red;
   }

   nametext {
     align: hcenter vcenter;
     color-1: green;
     font-1: medium bold;
     background: vgradient silver white;
   }

   greetingtext {
     align: hcenter vcenter;
     color-1: blue;
     font-1: medium bold;
     background: vgradient white green;
   }

   about {
     align: hcenter vcenter;
     color-1: blue;
     font-1: large bold;
     background: solid orange;
   }
 &lt;/stylesheet&gt;</pre>
<p>albo pliki zasobów, np. graficznych:</p>
<pre class="prettyprint"> &lt;img scale=”true” src="finland.png"/&gt;
 &lt;img scale=”true” src="uk.png"/&gt;
 &lt;img scale=”true” src="eu.png"/&gt;
 &lt;img src="bkg.png"/&gt;</pre>
<p>Wreszcie &#8211; podany tam jest plik (tylko jeden) z kodem źródłowym widgeta:</p>
<pre class="prettyprint"> &lt;code src=”flagselector.he”/&gt;</pre>
<p>W ostatniej sekcji deskryptora, &lt;layout&gt;, wymienione i opisane są widoki widgeta, których zasadami wyświetlania zajmuje się skrypt aplikacji. Elementy graficzne podobne są do komponentów Swingowych:</p>
<pre class="prettyprint"> &lt;layout minimizedheight="60px"&gt;
   &lt;view id="miniView"&gt;
     &lt;img src="minimized.png"/&gt;
   &lt;/view&gt;
   &lt;view class="bkg" id="mainView"&gt;
     &lt;script id="flag" top="10%" right="80%" bottom="60%" left="20%"/&gt;
     &lt;script id="name" top="65%" right="100%" bottom="80%" left="0%"/&gt;
     &lt;script id="greeting" top="80%" right="100%" bottom="100%" left="0%"/&gt;
   &lt;/view&gt;
 &lt;/layout&gt;</pre>
<p>Gdy już deskryptor mamy napisany, pora zasiąść do kodu właściwego. Piszę się go w języku skryptowym WSL, czyli <a href="http://wiki.forum.nokia.com/index.php/WidSets_Scripting_Language" target="_blank"><strong>WidSets Scripting Language</strong></a>. Jest on podobny w składni do Javy, choć mocno ograniczony. Cały kod widgeta opiera się na klasie, w której musimy zdefiniować metody startWidget() oraz openWidget() &#8211; od nich rozpoczyna działanie nasza aplikacja. Przepływ programu polega na odpowiednim odnoszeniu się do zdefiniowanych w deskryptorze, w sekcji &lt;layout&gt;, widoków i elementów. Mamy też możliwość sięgania po zdefiniowane tam zasoby i parametry, a także możemy definiować akcje klawiszy telefonu komórkowego.</p>
<p>Bardzo istotnym elementem API są usługi pobierania treści &#8211; nasz widget może być czymś więcej, niż lokalną aplikacją, działającą na lokalnych danych (jak gra bądź kalkulator). Możliwe jest sięganie do danych z różnych usług webowych. Dostępne są cztery rodzaje usług:</p>
<ul>
<li><a href="http://wiki.forum.nokia.com/index.php/Syndication_service" target="_blank"><strong>Syndication</strong></a> do pobierania treści z kanałów RSS, Atom czy RDF,</li>
<li><a href="http://wiki.forum.nokia.com/index.php/Webfeed_service" target="_blank"><strong>Webfeed</strong></a> do pobierania niestandardowych treści,</li>
<li><a href="http://wiki.forum.nokia.com/index.php/Image_service" target="_blank"><strong>Image</strong></a> do pobierania grafiki, oraz</li>
<li><a href="http://wiki.forum.nokia.com/index.php/HTTP_service" target="_blank"><strong>HTTP</strong></a> do wykonywania żądań HTTP GET i HTTP POST.</li>
</ul>
<p>Dzięki temu, oraz dodatkowym usługom (np. <a href="http://wiki.forum.nokia.com/index.php/HTTP_authentication" target="_blank">autentykacji</a>) można stworzyć widgeta, który będzie sięgał do różnych źródeł internetowych, pobierał i kompilował interesujące nas dane, a następnie wyświetlał w przystępnej formie na ekranie naszego telefonu.</p>
<h2>Użytkowanie tego, co się stworzyło</h2>
<p>Gdy już skrypt i deskryptor mamy napisane, możemy przejść do kompilacji, testowania, a wreszcie &#8211; umieszczenia na swoim pulpicie. Kompilator jest dołączony do SDK w postaci programu devkit, uruchamianego z linii komend. Na początek musimy zalogować się na swoje konto w serwisie WidSets:</p>
<pre class="prettyprint">devkit login [LOGIN] [HASŁO]</pre>
<p>a następnie wydajemy jedną komendę:</p>
<pre class="prettyprint">devkit run [ŚCIEŻKA_DO_WIDGETA]</pre>
<p>a program naszego widgeta skompiluje, spakuje do ZIPa, wyśle do serwisu i uruchomi emulator komórki, w którym możemy widgeta przetestwować od razu. Ponieważ widget jest od razu wrzucany na nasz WidSetsowy pulpit, możemy go także od razu przetestować w prawdziwym telefonie.</p>
<p>Kompilator devkit posiada jeszcze mnóstwo dodatkowych opcji, ale nie będę się w nie tutaj zagłębiał. Dość powiedzieć, że daje on całkiem pokaźne możliwości.</p>
<p>Po pozytywnym przetestowaniu nasz widget możemy dodać do biblioteki publicznej, aby inni też mogli go sobie pobrać i z niego korzystać, ale nie jest to oczywiście konieczne.</p>
<h2>Podsumowanie</h2>
<p>WidSets jest naprawdę ciekawą technologią, pozwalającą na tworzenie małych, prostych a użytecznych aplikacji, do których można mieć dostęp wszędzie za pośrednictwem telefonu komórkowego. Mogą mieć zarówno charakter lokalny (czyli przetwarzać dane, wprowadzane bezpośrednio do telefonu albo korzystać z jego zasobów &#8211; istnieje np. możliwość pobierania danych z aparatu fotograficznego w telefonie), jak i zdalny, gdy aplikacja sięga po zasoby lub informacje z Internetu, by je obrobić i wyświetlić.</p>
<h2>Źródła</h2>
<ul>
<li><a href="http://wiki.forum.nokia.com/index.php/Category:WidSets" target="_blank">WidSets Wiki</a>
<ul>
<li><a href="http://wiki.forum.nokia.com/index.php/Developing_your_first_WidSets_widget" target="_blank">Pierwsza aplikacja</a> (stąd brałem fragmenty kodu do przykładów w artykule)</li>
<li><a href="http://wiki.forum.nokia.com/index.php/WidSets_Scripting_Language" target="_blank">WSL w skrócie</a></li>
<li><a href="http://wiki.forum.nokia.com/index.php/WidSets_SDK" target="_blank">Opis WidSets SDK</a></li>
</ul>
</li>
<li><a href="http://www.forum.nokia.com/document/WidSets_APIdocs/" target="_blank">WidSets API &#8211; dokumentacja</a> a&#8217;la Javadoc</li>
<li><a href="http://www.forum.nokia.com/main/resources/tools_and_sdks/widsets/" target="_blank">WidSets SDK </a>- pobieranie</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/08/21/widgety-czesc-druga-widsets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Widgety &#8211; część pierwsza: Universal Widget API</title>
		<link>http://j2ee.pl/2008/08/18/widgety-czesc-pierwsza-universal-widget-api/</link>
		<comments>http://j2ee.pl/2008/08/18/widgety-czesc-pierwsza-universal-widget-api/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 13:36:54 +0000</pubDate>
		<dc:creator>Maciej Żywioł</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[WebServices]]></category>
		<category><![CDATA[universal widget api]]></category>
		<category><![CDATA[uwa]]></category>
		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=222</guid>
		<description><![CDATA[
Widgety – małe aplikacje użytkowe lub rozrywkowe, po polsku zwane często gadżetami – można spotkać coraz częściej, zarówno w sieci – na widgetach oparte są serwisy stron startowych (personalized homepages), jak NetVibes czy iGoogle – jak i poza nią, w aplikacjach desktopowych (panel gadgetów w Windows Vista albo Apple Dashboard pod Mac OSem), a nawet [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://j2ee.pl/wp-content/uploads/2008/08/netvibes2.png"><img class="alignnone size-medium wp-image-242" title="netvibes2" src="http://j2ee.pl/wp-content/uploads/2008/08/netvibes2.png" alt="" width="174" height="40" align="left"/></a></p>
<p>Widgety – małe aplikacje użytkowe lub rozrywkowe, po polsku zwane często gadżetami – można spotkać coraz częściej, zarówno w sieci – na widgetach oparte są serwisy stron startowych (<em>personalized homepages</em>), jak <a href="http://www.netvibes.com/" target="_blank">NetVibes</a> czy <a href="http://www.google.com/ig" target="_blank">iGoogle</a> – jak i poza nią, w aplikacjach desktopowych (panel gadgetów w Windows Vista albo <a href="http://www.apple.com/pl/downloads/dashboard/" target="_blank">Apple Dashboard</a> pod Mac OSem), a nawet w telefonie komórkowym. Każdy z wymienionych serwisów widgetów istniał jednak osobno – iGoogle, NetVibes, Apple czy Opera (która <a href="http://widgets.opera.com/general/faq/#widgets-run" target="_blank">od wersji 9</a> także wspiera widgety) miały swoje technologie i swoje zbiory gadżetów do pobrania i wykorzystania. Niektóre z nich udostępniały te technologie wszystkim, pragnącym samemu napisać jakąś małą aplikację, tym samym powiększając bibliotekę danego serwisu, ale cały czas taki twórczy użytkownik ograniczony był tylko do jednej platformy.<br />
Dlatego też NetVibes – pionier w dziedzinie owych stron startowych – postanowił przerobić swój MiniAPI 0.3, w którym wcześniej można było pisać moduły do zamieszczania w ich serwisie, na nowy API, który został zaprezentowany w wersji 1.0 pod nazwą <a href="http://dev.netvibes.com/" target="_blank">Universal Widget API</a>.<span id="more-222"></span></p>
<h2>Z czym to się je?</h2>
<p>Pierwszą i najważniejszą zaletą Universal Widget API (w skrócie UWA) jest – jak sama nazwa wskazuje – jego <a href="http://dev.netvibes.com/doc/universal_widget_api" target="_blank">uniwersalność</a>. W tej chwili napisane w nim widgety można zamieścić nie tylko na stronie NetVibes, ale także z powodzeniem zaimportować na stronach iGoogle czy Live.com, umieścić na pasku gadżetów Visty czy MAC OSa, według twórców działają też na iPhone oraz pod Operą desktopową (Opera na urządzenia mobilne jeszcze <a href="http://widgets.opera.com/general/faq/#widgets-usemobile" target="_blank">nie jest na nie gotowa</a>), ale tych ostatnich nie udało mi się uruchomić (nie jestem użytkownikiem Opery, a jej mechanizm importowania widgetów stanowi dla mnie barierę nie do przeskoczenia), a zapowiadanych jest jeszcze więcej platform (m.in. Facebook czy wspomniana Opera Mobile). Dodatkowo taki gadżet można umieścić w ramce (<em>iframe</em>) na dowolnej stronie, np. na blogu.<br />
Napisany pod UWA widget stanowi kombinację HTMLa (rzecz jasna z CSSem), JavaScripta i AJAXa &#8211; te technologie wystarczą do napisania całego, działającego widgeta. Dodatkowo możliwości widgeta można znacznie rozszerzyć, podpinając go pod zewnętrzny skrypt PHP czy JSP albo pod WebService oparty na dowolnej technologii.<br />
Dość prostym przykładem jest czytnik RSS – w UWA można go zawrzeć w pojedynczym pliku XHTML:</p>
<pre class="prettyprint">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xmlns:widget="http://www.netvibes.com/ns/"&gt;
&lt;head&gt;
  &lt;title&gt;RSS Reader&lt;/title&gt;

  &lt;link rel="stylesheet" type="text/css" href="http://www.netvibes.com/themes/uwa/style.css" /&gt;
  &lt;script type="text/javascript" src="http://www.netvibes.com/js/UWA/load.js.php?env=Standalone"&gt;&lt;/script&gt;

  &lt;widget:preferences&gt;
    &lt;preference name="url" type="text" label="URL" defaultValue="http://j2ee.pl/feed/" /&gt;
    &lt;preference name="limit" type="range" label="Number of items to display" defaultValue="10" step="1" min="1" max="25" /&gt;
  &lt;/widget:preferences&gt;
  &lt;script type="text/javascript"&gt;
    var RSSReader = {}

    RSSReader.feed = false;
    RSSReader.display = function(feed) {
      if(feed) RSSReader.feed = feed;
      var feedList = widget.createElement('ul');
      feedList.className = 'nv-feedList';
      var j = 0;
      for(var i=0; i &lt; RSSReader.feed.items.length; i++) {
        if(j &gt;= widget.getValue('limit')) break;
        var item = RSSReader.feed.items[i];
        var li = widget.createElement('li');
        var a = widget.createElement('a');
        a.href = item.link;
        a.target = '_blank';
        var displayTitle = item.title;
        if(search != '') {
          displayTitle = String.highlight(displayTitle, search);
        }
        a.innerHTML = displayTitle;
        var title = item.content.stripTags().truncate(255);
        a.desc = title;
        a.onmouseover = function() {
          UWA.Utils.setTooltip(this, this.desc, 250);
        }
        li.appendChild(a);
        var display = true;
        if(display) { feedList.appendChild(li); j++;
      }
    }
    widget.setBody(feedList);
  }
  widget.onLoad = function() {
    widget.log('RSSReader.onLoad');
    UWA.Data.getFeed(widget.getValue('url'), RSSReader.display);
  }
  widget.onRefresh = widget.onLoad;
&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;p&gt;Loading ...&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<h2>Przepis na gadżet</h2>
<p>Rdzeniem napisanego w UWA widgeta jest pojedynczy, statyczny plik XHTML, zawierający w nagłówku odniesienie do przestrzeni nazw NetVibes:</p>
<pre class="prettyprint"> xmlns:widget=“http://www.netvibes.com/ns/”</pre>
<p>Następnie w nagłówku strony należy umieścić w tagu <strong>preferences</strong> opcje widgeta – takie, które będą dostępne dla użytkownika po kliknięciu odpowiedniego linka na stronie (w zależności od platformy link ten może wyglądać inaczej):</p>
<pre class="prettyprint"> &lt;widget:preferences&gt;
  &lt;preference name="url" type="text" label="URL" defaultValue=" http://j2ee.pl/feed/" /&gt;
  &lt;preference name="limit" type="range" label="Number of items to display" defaultValue="7" step="1" min="1" max="10" /&gt;
 &lt;/widget:preferences&gt;</pre>
<p>Oczywiście, posiadanie właściwości nie jest niezbędne – można napisać widget bez żadnych opcji dostępnych dla użytkownika. Wtedy po prostu pozostawia się tag pusty:</p>
<pre class="prettyprint"> &lt;widget:preferences/&gt;</pre>
<p>Aktualnie UWA udostępnia kilka typów opcji, opartych na rodzajach pól w HTML-owych formularzach: <strong>text</strong>, <strong>password</strong>, <strong>boolean</strong> (odpowiednik <strong>checkbox</strong>), <strong>list </strong>(odpowiednik <strong>select</strong>), <strong>range </strong>(coś jak <strong>list</strong>, tylko z automatycznie generowanymi wartościami liczbowymi) i <strong>hidden</strong>. Trwają pracę nad obsłużeniem pól typu <strong>textarea</strong>. Wartości owych właściwości mogą zostać wykorzystane we właściwym javascriptowym kodzie widgeta w dalszej części strony za pomocą metody <strong>getValue </strong>obiektu <strong>widget</strong>.</p>
<h2>Danie główne &#8211; obiekty widget i UWA</h2>
<p>Kod javascriptowy kręci się wokół obiektu <strong>widget</strong>, którego metody analogiczne do zdarzeń (<strong>onLoad</strong>, <strong>onRefresh </strong>i inne) zawierają lub wywołują właściwy kod programu. Najczęściej – jeśli widget nie jest tylko lokalną aplikacją (np. grą), tylko sięga do zewnętrznych źródeł danych – kod ten zawiera jedną z dostarczanych przez UWA AJAXowych metod pobierania danych. W przykładzie, w metodzie <strong>onLoad </strong>można to znaleźć w linijce:</p>
<pre class="prettyprint"> UWA.Data.getFeed(widget.getValue('url'), RSSReader.display);</pre>
<p>Obiekt <strong>UWA.Data </strong>dostarcza kilka podobnych metod do wyboru. <strong>UWA.Data.getText() </strong>zwraca odpowiedź w formacie plain text, <strong>getXml() </strong>– w formacie XML, <strong>getJson() </strong>– w formacie danych <a href="http://www.json.org/" target="_blank">JSON</a>, <strong>getFeed()</strong> jest formą tego ostatniego, z tym, że JSONowa odpowiedź dodatkowo jest kompatybilna ze wszystkimi formatami źródeł danych – RSS, Atom i inne. Wszystkie metody pobierają dwa argumenty – adres źródła danych oraz nazwę funkcji, do której ma zostać przesłana odpowiedź (w przykładzie naszego czytnika RSS jest to metoda <strong>RSSReader.display()</strong>). Dodatkowo obiekt <strong>UWA.Data </strong>posiada metodę <strong>request()</strong>, która pobiera argumenty w postaci adresu oraz obiektu, przechowującego szczegóły żądania. Tak naprawdę wszystkie wymienione wcześniej metody (<strong>getText</strong>, <strong>getFeed </strong>itp.) są odpowiednio przeładowaną metodą <strong>request</strong>. Metody tej w czystej postaci używa się przy bardziej zaawansowanych potrzebach.<br />
Same źródła natomiast mogą być zupełnie dowolne – pod adresem, przekazywanym do metody, może znajdować się (jak w naszym przykładzie) kanał RSS, ale może to być dowolna inna zawartość (np. skrypt PHP, ASP czy JSP) generująca odpowiedź w odpowiednim formacie. Może to być, jak już wspomniałem, skrypt specjalnie na potrzeby tego widgeta napisany.<br />
Wracając do naszego przykładu &#8211; skoro już metoda <strong>getFeed </strong>zwróciła nam JSONowy obiekt z podanego adresu, przyjrzyjmy się metodzie, do której odpowiedź z serwera jest przekazywana. Metoda display przetwarza zawartość zwróconego obiektu <strong>feed </strong>i na jego podstawie buduje ciało strony. Używane są do tego metody obiektu <strong>widget </strong>takie, jak <strong>createElement</strong>, tworząca element HTMLowy podanego jako argument typu (np. <strong>widget.createElement(’a’) </strong>stworzy odnośnik) oraz metod obiektów reprezentujących owe elementy (<strong>addContent</strong>, <strong>setHTML</strong>, <strong>setStyle</strong>…). W ten sposób tworzona jest struktura DOM dokumentu, która, gdy już będzie gotowa, ładowana jest do ciała strony metodą <strong>widget.setBody</strong>, zastępując aktualną jego zawartość (dlatego jedyną zawartością znacznika <strong>&lt;body&gt; </strong>jest tymczasowy tekst „Loading…”, który znika po tym, jak metoda display przetworzy odpowiedź na żądanie).</p>
<h2>Deser – skrypty wykonywane po stronie serwera</h2>
<p>Jak już wspomniałem, widget może sięgać do źródeł danych specjalnie dla niego utworzonych, np. skryptów PHP. Jako przykład podam widgeta, pobierającego dane nie z jednego, a z wielu kanałów Atom (w tym przypadku – blogów z serwisu Blogger, których adresy przechowywane są w pliku myfeed.txt) i informujący o tym, kiedy każdy z nich był ostatnio aktualizowany.</p>
<p>Poniżej cytuję sam kod JavaScript z pliku XHTML widgeta. Nie korzysta on z żadnych ustawień (preferences) widgeta, więc obudowanie go odpowiednim kodem XHTML, wzorowanym choćby na powyższym przykładzie czytnika RSS, nie będzie trudne:</p>
<pre class="prettyprint">&lt;script type="text/javascript"&gt;
var xmlHttp = false;
var blogNote = false;
var MyFeed = {
  feed : false,
  feedArray : false,
  oneFeed : false,
  processFeed : function(feed) {
    widget.log(feed);
  }
}

MyFeed.parseFeeds = function(feed) {
  if(feed) MyFeed.feed = feed;
  widget.log(feed);
  var feedList = widget.createElement('ul');
  feedList.className = 'nv-feedList';
  feedArray = new Array();
  for(var i=0;i&lt;MyFeed.feed.list.length;i++) {
    var li = widget.createElement('li');
    var titleTxt = widget.createElement('a');
    titleTxt.className = 'myFeed_blogTitle';
    titleTxt.href = MyFeed.feed.list[i].url;
    titleTxt.target = '_blank';
    titleTxt.innerHTML = MyFeed.feed.list[i].title;
    li.appendChild(titleTxt);
    li.appendChild(widget.createElement('br'));
    var dateTxt = widget.createElement('span');
    dateTxt.className = 'myFeed_when';
    dateTxt.innerHTML = MyFeed.getWhen(MyFeed.feed.list[i].entry_when);
    li.appendChild(dateTxt);
    li.appendChild(widget.createElement('br'));
    var articleTxt = widget.createElement('a');
    articleTxt.className = 'myFeed_title';
    articleTxt.href = MyFeed.feed.list[i].url;
    articleTxt.target = '_blank';
    articleTxt.innerHTML = MyFeed.feed.list[i].entry_title;
    li.appendChild(articleTxt);
    li.appendChild(widget.createElement('br'));
    var categoriesTxt = widget.createElement('span');
    categoriesTxt.className = 'myFeed_categories';
    for(var j=0;j&lt;MyFeed.feed.list[i].entry_cats.length;j++) {
      var categoryTxt = widget.createElement('span');
      categoryTxt.className = 'myFeed_category';
      categoryTxt.innerHTML = MyFeed.feed.list[i].entry_cats[j];
      categoriesTxt.appendChild(categoryTxt);
      if(j+1 == MyFeed.feed.list[i].entry_cats.length) {
        break;
      }
      categoriesTxt.innerHTML += ', ';
    }
    li.appendChild(categoriesTxt);
    feedList.appendChild(li);
  }
  widget.setBody(feedList);
}

MyFeed.getWhen = function(datestr) {
  var then = parseInt(datestr);
  var now = Date.parse(Date());
  var whentxt = "";
  var when = now - then;
  if(when &lt; 3600000) {
    whentxt = ""+Math.floor(when/60000)+" minut temu";
  } else if (when &lt; 86400000) {
    whentxt = ""+Math.floor(when/3600000)+" godzin temu";
  } else {
    whentxt = ""+Math.floor(when/86400000)+" dni temu";
  }
  return whentxt;
}

widget.onLoad = function() {
  var url = 'myfeed.php';
  UWA.Data.getJson(url, MyFeed.parseFeeds);
}
&lt;/script&gt;</pre>
<p>Widget ten wysyła zapytanie do specjalnie utworzonego skryptu PHP, który sam pobiera dane z kanałów i na ich podstawie generuje odpowiedź w formacie JSON, którą odsyła do aplikacji. Następnie metoda parseFeeds ze zwróconego JSONa (w specjalnie utworzonym formacie, nie tym zwracanym przez metodę getFeed – oto dowód, że w formacie JSON można przesyłać naprawdę dowolne dane, nie tylko te kompatybilne z uniwersalnym formatem kanałów RSS i podobnych).</p>
<p>Oto zawartość pliku <strong>myfeed.php</strong>:</p>
<pre class="prettyprint">&lt;?php
error_reporting(E_ALL);
header ("Content-type: text/plain");

if(!file_exists("myfeed.txt"))
  echo "";
else {
  $file = fopen("myfeed.txt","r");
  echo " { \"list\" : ";
  $ec=0;
  while(!feof($file)) {
    if($ec == 0)
      echo " [ ";
    else
      echo " , ";
    $ec++;

    $url = chop(fgets($file));
    $xmlDoc = new DOMDocument();
    $xmlDoc-&gt;load($url);

    //get elements from "&lt;feed&gt;"
    $feed=$xmlDoc-&gt;getElementsByTagName('feed')-&gt;item(0);
    $feed_title = $feed-&gt;getElementsByTagName('title')-&gt;item(0)-&gt;nodeValue;
    $feed_url = $url;
    $feed_author = $feed-&gt;getElementsByTagName('author')-&gt;item(0)-&gt;firstChild-&gt;nodeValue;

    //get and output first "&lt;item&gt;" element
    $feed_entry=$xmlDoc-&gt;getElementsByTagName('entry')-&gt;item(0);
    $feed_entry_when = strtotime($feed_entry-&gt;getElementsByTagName('published')-&gt;item(0)-&gt;nodeValue)*1000;
    $feed_entry_cats = $feed_entry-&gt;getElementsByTagName('category');
    $feed_entry_categories = array();

    //get post categories
    for($i=0; $i&lt;$feed_entry_cats-&gt;length; $i++) {
      $feed_entry_categories[] = $feed_entry_cats-&gt;item($i)-&gt;attributes-&gt;getNamedItem('term')-&gt;nodeValue;
    }
    $feed_entry_title = $feed_entry-&gt;getElementsByTagName('title')-&gt;item(0)-&gt;nodeValue;

    echo " { \n";
    echo "\"title\" : \"" . str_replace("\"","\\\"",$feed_title) . "\" , \n";
    echo "\"author\" : \"" . $feed_author . "\" , \n";
    echo "\"url\" : \"" . $feed_url . "\" , \n";
    echo "\"entry_when\" : \"" . $feed_entry_when . "\" , \n";
    echo "\"entry_title\" : \"" . str_replace("\"","\\\"",$feed_entry_title) . "\" , \n";
    echo "\"entry_cats\" : ";
    for($i=0; $i&lt;count($feed_entry_categories); $i++) {
      if($i==0)
        echo " [ ";
      else
         echo " , ";
      echo "\"" . $feed_entry_categories[$i] . "\"";
    }
    echo " ] \n";
    echo " } \n";
  }
  echo " ] }";
}
fclose($file);
?&gt;</pre>
<p>Plik <strong>myfeed.txt</strong>, z którego powyższ skrypt czyta adresy kanałów Atom zawiera po prostu kilka adresów kanałów z kilku zaprzyjaźnionych blogów w serwisie Blogger.com.</p>
<h2>Przydatność do spożycia</h2>
<p>UWA jest wynalazkiem bardzo nowym, wciąż jeszcze rozwijanym i nie w pełni kompatybilnym z wszystkimi tymi platformami, którymi przechwalają się twórcy. Nie mniej jednak wyraźnie widać jego zalety i możliwości. Nie miałem możliwości przetestować jego działania pod Vistą czy MAC OSem ani na iPhone, a testy pod Operą zakończone były porażką, ale w głównych zastosowaniach – na stronach NetVibes, iGoogle czy w ramce iframe na dowolnej innej stronie – sprawdzają się bardzo dobrze. Myślę, że gdy zostanie dopracowane i przeniesione na jeszcze większą liczbę platform (telefony i urządzenia mobilne inne niż iPhone), Universal Widget API może cieszyć się zasłużonym zainteresowaniem, a programy w nim napisane mogą być w równym stopniu proste, jak przydatne.</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/08/18/widgety-czesc-pierwsza-universal-widget-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tomcat &#8211; Clustering i Loadbalancing</title>
		<link>http://j2ee.pl/2008/08/18/tomcat-clustering-i-loadbalancing/</link>
		<comments>http://j2ee.pl/2008/08/18/tomcat-clustering-i-loadbalancing/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 09:14:33 +0000</pubDate>
		<dc:creator>Błażej Bucko</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[tomcat]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=176</guid>
		<description><![CDATA[
Współczesne aplikacje internetowe są coraz bardziej skomplikowane i wymagaja coraz mocniejszych serwerów. Jednocześnie liczba użytkowników zwiększa się praktycznie z każdą minutą, co powoduje ze serwery muszą być jeszcze wydajniejsze. Można tej sytuacji zaradzić dokupując procesory, pamięci, zwiększając przepustowość kart sieciowych, jednakże w pewnym momencie trafimy na mur, którego już się w ten sposób obejść nie [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://tomcat.apache.org/images/tomcat.gif" alt="Tomcat" align="left" /><br />
Współczesne aplikacje internetowe są coraz bardziej skomplikowane i wymagaja coraz mocniejszych serwerów. Jednocześnie liczba użytkowników zwiększa się praktycznie z każdą minutą, co powoduje ze serwery muszą być jeszcze wydajniejsze. Można tej sytuacji zaradzić dokupując procesory, pamięci, zwiększając przepustowość kart sieciowych, jednakże w pewnym momencie trafimy na mur, którego już się w ten sposób obejść nie da. Możemy go jednakże przeskoczyć łącząc kilka komputerów w klaster, a następnie rozdzielając zapytania tak, aby wszystkie serwery były równo obciążone. Ta metoda jest również konieczna w przypadku, gdy awaria serwera jest niedopuszczalna i musimy zapewnić ciągły dostęp do aplikacji.</p>
<p><span id="more-176"></span></p>
<h2>Tomcat</h2>
<p>W trakcie normalnego działania klastra sesje są replikowane między wszystkimi komputerami przy użyciu jednej z następujących metod:</p>
<ol>
<li>Replikacja poprzez współdzielony sieciowy system plików (PersistanceManager + FileStore)</li>
<li>Replikacja do bazy danych (PersistanceManager + JDBCStore)</li>
<li>Replikacja w pamięci (SimpleTcpCluster)</li>
</ol>
<p>Jeżeli jeden z Tomcatów ulegnie awarii jest usuwany z klastra a powiązane z nim zapytania są automatycznie przekierowywane przez loadbalancera. Sesje powiązane z uszkodzonym serwerem mogą zostac w zależności od konfiguracji wygaszone lub nie.</p>
<p>Przynależność do klastra jest określana przy pomocy pakietów UDP wysyłanych przez wszystkie Tomcaty, ze skonfigurowanym tym samym adresem multicastowym oraz portem. Replikacja sesji odbywa się przy użyciu pakietów TCP.</p>
<p>Zawór replikacji (ReplicationValve) służy do określenia kiedy zapytanie zostało zakończone i klaster może rozpocząć replikację.</p>
<p>Element w pliku server.xml konfiguruje domyślnie klaster z następującymi parametrami:</p>
<ul>
<li>Membership z adresem multicastowym 228.0.0.4 i portem udp 8012</li>
<li>Potwierdzenie wysyłane co sekundę, usunięcie z listy po 30 sekundach bez odpowiedzi od danego Tomcata</li>
<li>Odbiorca wiadomości SocketReplicationListener na domyślnym adresie IP oraz pierwszym wolnym portem z zakresu 8015 &#8211; 8019</li>
<li>Replikacja oparta o ReplicationTransmitter w trybie fastasyncqueue</li>
<li>Dodane ClusterSessionListener oraz ReplicationValve.</li>
</ul>
<p>Wystarczy to do podstawowego skonfigurowania klastra, np. na maszynie developerskiej, jednakże w środowisku produkcyjnym zaleca się modyfikację ilości wątków obsługujących replikację i tryb replikacji.</p>
<h3>Tipsy:</h3>
<ul>
<li>Dokumentacja dotycząca klastrowania znajduje się tutaj: <a href="http://tomcat.apache.org/tomcat-5.5-doc/cluster-howto.html">Tomcat 5.5</a>, <a href="http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html">Tomcat 6.0</a></li>
<li>Obiekty które są zapisywane w sesji muszą implementować java.io.Serializable (np. dto w kreatorach springowych)</li>
<li>Na serwerach należy włączyć obsługę multicastu (np. pod Linuxem: ifconfig eth0 multicast)</li>
<li>W web.xml powinien znajdować się element &lt;distributable /&gt;, który powoduje, że dana aplikacja jest zdolna do działania w środowisku rozproszonym, czyli np. w klastrze.</li>
<li>Najważniejszym elementem jeżeli chodzi o wydajność replikacji jest parametr replicationMode, konfigurowalny w elemencie &lt;Sender …/&gt;</li>
</ul>
<h2>Apache i mod_jk</h2>
<p>Mod_jk to moduł do apache’a obsługujący komunikację z Tomcatem.  Worker to instancja Tomcata na której uruchomione są servlety i do której przekierowywane są zapytania. Mod_jk jest konfigurowany, tak jak inne moduły, w pliku apache.conf lub httpd.conf. W niektórych dystrybucjach (np. debian) pliki konfiguracyjne modułów znajdują się w podkatalogu mods-enabled i są includowane w głownym pliku konfiguracyjnym.</p>
<h3>Konfiguracja mod_jk</h3>
<p>Moduł ładowany jest przy pomocy dyrektywy:</p>
<pre class="prettyprint">LoadModule jk_module ${sciezkaDoKataloguZModulami}/mod_jk.so</pre>
<p>Następnie musimy dodać plik z workerami:</p>
<pre class="prettyprint">JkWorkersFile /etc/apache/workers.properties</pre>
<p>Oczywiście plik workers.properties znajdować się może w dowolnym miejscu widocznym przez Apache’a.</p>
<p>Dodatkowo, należy też skonfigurować punkt montowania, czyli scieżkę od której przetwarzaniem zapytań zajmować będzie się Tomcat.</p>
<pre class="prettyprint">JkMount /* tomcat1</pre>
<p>Ta dyrektywa sprawia, że wszystkie zapytania które odbierze Apache będą przekserowane do Wolkera o nazwie tomcat1. JkMount może się powtarzać i umieścić ją można zarówno w globalnej konfiguracji, VirtualHost jak i w Location (tylko nazwa workera, ścieżka będzie z Location) .<br />
Zamiast montowania każdego punktu z osobna można użyć pliku uriworkermap.properties przy pomocy dyrektywy JkMountFile wskazującej na plik z mapowaniem.</p>
<h3>Konfiguracja workera</h3>
<p>Workery znajdują się przeważnie w pliku workers.properties. W pliku powinna znaleźć się dyrektywa worker.list oraz definicja co najmniej jednego workera. Worker.list to lista oddzielonych przecinkami workerów, które będą udostępnione mod_jk. Workera definiuję się w następujący sposób:</p>
<pre class="prettyprint">worker.nazwaWorkera.type=
worker.nazwaWorkera.host=
worker.nazwaWorkera.port=</pre>
<p>Typ to najczęściej ajp13, który zastąpił starszy ajp12 i udostępnił między innymi kompresje danych i obsługę SSL’a.</p>
<h3>Konfiguracja loadbalancera</h3>
<p>Loadbalancer to specyficzny typ workera który nie komunikuje się z Tomcatem, tylko zajmuję się zarządzaniem pozostałymi „prawdziwymi” workerami, czyli min. rozdziela zadania na poszczególne instancje Tomcata używając algorytmu Round Robin z wagami. Sprawdza też które Tomcaty z listy nie odpowiadają i nie wysyła do nich zapytań.</p>
<p>Konfiguracja definiuję się w nastepujący sposób:</p>
<pre class="prettyprint">worker.nazwaWorkeraLB.balance_workers=</pre>
<p>Dodatkowo można skonfigurować sticky session, czyli czy loadbalancer powinien przekierowywać zapytania z istniejącym sessionId do obsługującego je wcześniej Tomcata. Domyślnie ta funkcjonalność jest włączona.</p>
<p>Workerom można przyporządkować rózne wagi (worker.nazwaWorkera.lbfactor) a w loadbalancerze zmienić metodę wyboru workera do którego przekazane zostaną zapytania (worker.nazwaWorkeraLB.method). Do wyboru są następujące metody:<br />
•<strong>R</strong>[equest] – kryterium jest obłożenie zapytaniami. Domyślne ustawienie.<br />
•<strong>S</strong>[ession] – kryterium jest obłożenie sesjami. Zalecane w przypadku ograniczonych zasobów do obsługi sesji.<br />
•<strong>B</strong>[usyness] – kryterium jest aktualne obciążenie serwera. Zalecane w przypadku długich sesji, np. w aplikacjach udostępniających pliki.<br />
•<strong>T</strong>[raffic] – kryterium jest ilość ruchu na łączu między Apachem a Tomcatem. Zalecane w przypadku ograniczonej łączności między klasterm a Apachem.</p>
<h3>Linki:</h3>
<ul>
<li><a href="http://tomcat.apache.org/connectors-doc/reference/apache.html">Pozostałe dyrektywy</a></li>
<li><a href="http://tomcat.apache.org/connectors-doc/reference/uriworkermap.html">Konfiguracja pliku mapowań</a></li>
<li><a href="http://tomcat.apache.org/connectors-doc/generic_howto/workers.html">Dokumentacja workerów</a></li>
</ul>
<h2>Przykłady</h2>
<h3>Apache -&gt; mod_jk  -&gt; 1 tomcat</h3>
<p>Najprostszy przykład. Zapytania są przekierowywane do jednego tomcata.</p>
<h4>Konfiguracja Apache 1:</h4>
<p><em> workers.properties:</em></p>
<pre class="prettyprint">worker.list=tomcat1

worker.tomcat1.type=ajp13
worker.tomcat1.host=10.1.1.2
worker.tomcat1.port=8009</pre>
<h4>Konfiguracja Tomcat1:</h4>
<p><em>server.xml, sekcja Service:</em></p>
<pre class="prettyprint">&lt;Connector port="8009"  protocol="AJP/1.3" /&gt;</pre>
<h3>Apache -&gt; mod_jk  -&gt; 2 tomcaty w klastrze</h3>
<p>Najbardziej użyteczna według mnie konfiguracja, bez użycia balansowania DNS&#8217;owego lub sprzętowego. Balansowaniem zajmuje się mod_jk.</p>
<h4>Konfiguracja Apache 1:</h4>
<p><em>workers.properties:</em></p>
<pre class="prettyprint">worker.list=cluster

worker.tomcat1.type=ajp13
worker.tomcat1.host=10.1.1.2
worker.tomcat1.port=8009

worker.tomcat2.type=ajp13
worker.tomcat2.host=10.1.1.3
worker.tomcat2.port=8009

worker.cluster.type=lb
worker.cluster.balance_workers=tomcat1, tomcat2</pre>
<h4>Konfiguracja Tomcat’ów:</h4>
<p><em>server.xml, sekcja Service:</em></p>
<pre class="prettyprint">&lt;Connector port="8009"  protocol="AJP/1.3" /&gt;</pre>
<p><em>server.xml,  sekcja Host:</em></p>
<pre class="prettyprint">&lt;Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"/&gt;</pre>
<p>Dodatkowo, do  należy dopisać jvmRoute=”${nazwaHosta}”, gdzie ${nazwaHosta} to odpowiednio tomcat1 i tomcat2</p>
<h3>Apache -&gt; mod_jk  -&gt; 1 tomcat jako loadbalancer -&gt; 2 tomcaty w klastrze</h3>
<p>Metoda ta używa aplikacji “balancer” uruchomionej na Tomcat’ie, który nie jest w klastrze. Zaletą tego rozwiązania jest możliwość dowolnego skonfigurowania balancingu. Wadą jest konieczność napisania klasy zajmującej się wyborem najlepszego Tomcata. Rozwiązanie to używa pliku workers.properties z przykładu pierwszego, konfiguracji klastra z przykładu drugiego oraz dodatkowego Tomcata, na którym działa aplikacja balancer. workers.properties przekierowuje zapytania na Tomcata pełniącego rolę LoadBalancera.</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/08/18/tomcat-clustering-i-loadbalancing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Oswajanie Kerberosa, czyli dwunasta praca Heraklesa</title>
		<link>http://j2ee.pl/2007/12/04/oswajanie-kerberosa-czyli-dwunasta-praca-heraklesa/</link>
		<comments>http://j2ee.pl/2007/12/04/oswajanie-kerberosa-czyli-dwunasta-praca-heraklesa/#comments</comments>
		<pubDate>Tue, 04 Dec 2007 19:25:01 +0000</pubDate>
		<dc:creator>Marcin Nowrot</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[kerberos]]></category>
		<category><![CDATA[weblogic]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/12/04/oswajanie-kerberosa-czyli-dwunasta-praca-heraklesa/</guid>
		<description><![CDATA[Czy zastanawialiście się kiedykolwiek, ile razy dziennie przechodzimy proces logowania się do różnych systemów i aplikacji WWW? Według statystyk, liczba ta idzie w dziesiątki dziennie, a stratę czasu na logowanie się i obsługę zapomnianych haseł liczy się w godzinach. Jest to szczególnie istotne, jeśli dotyczy aplikacji, z których korzystamy w pracy.
Czy istnieje sposób aby tego [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><a title="Herakles wyprowadzający Cerbera z Hadesu (waza grecka, V w. p.n.e.)" href="http://j2ee.pl/wp-content/uploads/2007/12/image001.png"><img src="http://j2ee.pl/wp-content/uploads/2007/12/image001.png" alt="Herakles wyprowadzający Cerbera z Hadesu (waza grecka, V w. p.n.e.)" align="left" /></a>Czy zastanawialiście się kiedykolwiek, ile razy dziennie przechodzimy proces logowania się do różnych systemów i aplikacji WWW? Według statystyk, liczba ta idzie w dziesiątki dziennie, a stratę czasu na logowanie się i obsługę zapomnianych haseł liczy się w godzinach. Jest to szczególnie istotne, jeśli dotyczy aplikacji, z których korzystamy w pracy.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Czy istnieje sposób aby tego uniknąć (na przykład automatycznie logując się do aplikacji przy użyciu danych wprowadzonych podczas autoryzacji w domenie Windows)? Jak najbardziej tak – aczkolwiek nie jest to zadaniem trywialnym. Niniejszy artykuł opisuje proces integracji serwera BEA WebLogic z systemem Kerberos, jednakże jego celem nie jest wyjaśnienie wszystkich aspektów tego procesu (wyjaśnienie na tym poziomie szczegółowości mogłoby z powodzeniem wypełnić książkę). Celem tego artykułu jest raczej przeprowadzenie operatora domeny Active Directory przez proces integracji w najbardziej typowych warunkach.</p>
<p><span id="more-105"></span></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Środowisko testowe</span></strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Środowisko testowe składać się będzie z trzech komputerów (p. <span>Rys. <span>1</span><!--[if gte mso 9]><xml> <w :data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003100380034003400340032003600350030000000</w> </xml>< ![endif]--></span>):</p>
<p class="MsoNormal" style="margin-left: 71.4pt; text-align: justify; text-indent: -18pt"><!--[if !supportLists]--><span>1.<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span><!--[endif]--><span class="HTML-wstpniesformatowanyZnak">zeus</span>: pracujący pod Windows 2003 kontroler domeny <span class="HTML-wstpniesformatowanyZnak">olympus.net</span> (ang. <em>Domain Controller</em>, DC), z uruchomionym Centrum Dystrybucji Kluczy (ang. <em>Key Distribution Center</em>, KDC) systemu Kerberos. (<strong>Uwaga:</strong> proces integracji różni się w zależności od wersji systemu Windows, pod kontrolą której pracują DC i KDC. Niniejszy artykuł opisuje proces integracji w oparciu o system Windows 2003).</p>
<p class="MsoNormal" style="margin-left: 71.4pt; text-align: justify; text-indent: -18pt"><!--[if !supportLists]--><span>2.<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span><!--[endif]--><span class="HTML-wstpniesformatowanyZnak">athena</span>: serwer aplikacji BEA Weblogic 9.2. Na potrzeby tego artykułu zakładamy, że systemem operacyjnym na serwerze <code><span style="font-size: 10pt">athena</span></code> jest system UNIX-owy</p>
<p class="MsoNormal" style="margin-left: 71.4pt; text-align: justify; text-indent: -18pt"><!--[if !supportLists]--><span>3.<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span><!--[endif]--><span class="HTML-wstpniesformatowanyZnak">apollo</span>: stacja robocza klienta, który jest zalogowany w domenie i chce uzyskać dostęp do aplikacji zainstalowanej na serwerze <span class="HTML-wstpniesformatowanyZnak">athena</span>.</p>
<p class="MsoNormal" style="text-align: center; page-break-after: avoid" align="center"><!--[if gte vml 1]><v :shapetype  id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t"  path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v :stroke joinstyle="miter" /> </v><v :formulas> <v :f eqn="if lineDrawn pixelLineWidth 0" /> <v :f eqn="sum @0 1 0" /> <v :f eqn="sum 0 0 @1" /> <v :f eqn="prod @2 1 2" /> <v :f eqn="prod @3 21600 pixelWidth" /> <v :f eqn="prod @3 21600 pixelHeight" /> <v :f eqn="sum @0 0 1" /> <v :f eqn="prod @6 1 2" /> <v :f eqn="prod @7 21600 pixelWidth" /> <v :f eqn="sum @8 21600 0" /> <v :f eqn="prod @7 21600 pixelHeight" /> <v :f eqn="sum @10 21600 0" /> </v> <v :path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /> <o :lock v:ext="edit" aspectratio="t" /> <v :shape id="_x0000_i1025" type="#_x0000_t75" style='width:234pt;  height:220.5pt' o:ole=""> <v :imagedata src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image001.emz" mce_src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image001.emz"   o:title="" /> </v>< ![endif]--><!--[if !vml]--><img src="http://j2ee.pl/wp-content/uploads/2007/12/image003.jpg" alt="" width="452" height="427" align="middle" /><!--[endif]--><!--[if gte mso 9]><xml> <o :OLEObject Type="Embed" ProgID="Visio.Drawing.11" ShapeID="_x0000_i1025"   DrawAspect="Content" ObjectID="_1258197932"> </o> </xml>< ![endif]--></p>
<p class="MsoCaption" style="text-align: center" align="center"><a title="_Ref184442650" name="_Ref184442650"></a><strong>Rys. <span><span>1</span></span>. Środowisko testowe i proces logowania się do aplikacji WWW zintegrowanej z systemem Kerberos (1 – Użytkownik zalogowany do stacji <span style="font-family: 'Courier New';">apollo.olympus.net </span>próbuje uzyskać dostęp do części chronionej aplikacji WWW. 2 – przeglądarka użytkownika wysyła żądanie do serwera aplikacji WWW</strong><strong><span style="font-family: 'Courier New';"> </span><span style="font-family: 'Courier New';">athena.olympus.net</span>, i odbiera odpowiedź HTTP401, rozpoczynającą proces logowania się do aplikacji za pośrednictwem systemu Kerberos. 3 – Komputer <span style="font-family: 'Courier New';">apollo.olympus.net</span> łączy się z KDC (<span style="font-family: 'Courier New';">zeus.olympus.net</span>) i wysyła żądanie przyznania ticketa. 4 – po pozytywnej identyfikacji użytkownika i hosta w domenie, serwer KDC odsyła ticket do komputera <span style="font-family: 'Courier New';">apollo.olympus.net</span>. 5 – ticket zostaje przekazany komputerowi <span style="font-family: 'Courier New';">athena.olympus.net</span>. Po poprawnym przetworzeniu ticketu, proces identyfikacji użytkownika kończy się sukcesem. 6 – serwer<span style="font-family: 'Courier New';"> athena.olympus.net</span> łączy się z LDAP Active Directory, celem pobrania grup AD (traktowanych jako role użytkownika). Po pobraniu grup kończy się proces autoryzacji użytkownika w aplikacji WWW)</strong><!--[if supportFields]><span style="mso-bookmark: _Ref184442650" mce_style="mso-bookmark: _Ref184442650"></span><span style="mso-element:field-begin" mce_style="mso-element:field-begin"></span><span style="mso-bookmark:_Ref184442650" mce_style="mso-bookmark:_Ref184442650"><span style="mso-spacerun:yes" mce_style="mso-spacerun:yes"> </span>SEQ Rys. \* ARABIC <span style="mso-element:field-separator" mce_style="mso-element:field-separator"></span></span>< ![endif]--><!--[if supportFields]><span style="mso-bookmark:_Ref184442650" mce_style="mso-bookmark:_Ref184442650"></span><span style="mso-element:field-end" mce_style="mso-element:field-end"></span>< ![endif]--> <span style="font-size: 14pt; font-weight: normal"></span></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Konfiguracja w KDC</span></strong></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><span> </span>Proces integracji serwera Weblogic z domeną Windows należy rozpocząć od utworzenia w kontrolerze domeny <span style="font-family: 'Courier New';">zeus.olympus.net</span> konta dla serwera aplikacji. Konto to musi spełniać kilka określonych warunków (p. tabela 1)</p>
<p class="MsoNormal" style="text-align: justify">
<table class="MsoTableGrid" style="border: medium none; border-collapse: collapse; height: 224px;" border="1" cellspacing="0" cellpadding="0" width="470">
<tbody>
<tr>
<td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 153.5pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify" align="center"><strong>Typ pola</strong></p>
</td>
<td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify"><strong>Wartość</strong></p>
</td>
<td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify"><strong>Uwagi</strong></p>
</td>
</tr>
<tr>
<td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 153.5pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">First name</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">athena.olympus.net</span></code></p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Nazwa konta identyczna z nazwą   hosta (oczywiście w domenie musi istnieć serwer DNS i ReverseDNS   odwzorowujący dla hosta <code><span style="font-size: 10pt">athena.olympus.net</span></code></p>
</td>
</tr>
<tr>
<td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 153.5pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Login</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">athena.olympus.net</span></code></p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Login taki sam jak nazwa hosta.</p>
</td>
</tr>
<tr>
<td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 153.5pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Hasło</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">longlongpassword</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Hasło będzie wykorzystane<span> </span>dalej, do generowania pliku zawierającego   klucz szyfrowania</p>
</td>
</tr>
<tr>
<td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 153.5pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Algorytm szyfrowania hasła</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">DES</p>
</td>
<td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 153.55pt" width="205" valign="top">
<p class="MsoNormal" style="text-align: justify">Po włączeniu szyfrowania DES na   koncie należy zresetować hasło konta, podając nowe hasło 100% zgodne ze   star</p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt" align="left"><strong>Tabela 1. Konto w Active Directory przeznaczone dla serwera aplikacji</strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Integracja z systemem Kerberos wymaga zarejestrowania w KDC usług, z którymi będziemy się integrować. Dokonujemy tego poprzez ustalenie tzw. <em>Service Principal Names</em>,<em> </em>SPN, na podstawie których identyfikowane sa usługi, dla których system Kerberos wystawia tickety. Aby zarejestrować SPN dla serwera Weblogic, w linii komend serwera KDC (<code><span style="font-size: 10pt">zeus.olympus.net</span></code>) wpisujemy:</p>
<p class="MsoNormal" style="text-align: justify">
<pre style="text-align: justify"><code><span style="font-family: Courier;">setspn -a HOST/athena.olympus.net@OLYMPUS.NET athena.olympus.net</span></code>
<code></code><code><span style="font-family: Courier;">setspn -a HTTP/athena.olympus.net@OLYMPUS.NET athena.olympus.net</span></code></pre>
<p class="MsoNormal" style="text-align: justify">gdzie <code><span style="font-size: 10pt">athena.olympus.net</span></code> to nazwa konta użytkownika (zarejestrowanego w kontrolerze domeny) z którego uruchamiany jest serwer aplikacji na komputerze <code><span style="font-size: 10pt">athena.olympus.net@OLYMPUS.NET</span></code></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Aby sprawdzić poprawność wygenerowanych SPNs należy na serwerze KDC wpisać następującą komendę:</p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">setspn –L athena.olympus.net</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify">po wpisaniu powyższej komendy, powinny zostać wyświetlone SPNs skojarzone z kontem Active Directory <code><span style="font-size: 10pt">athena.olympus.net</span></code></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Następnym krokiem jest utworzenie tzw. pliku keytab zawierającego klucz służący do szyfrowania i deszyfrowania ticketów wydawanych przez system Kerberos dla serwera <code><span style="font-size: 10pt">athena:</span></code></p>
<p class="MsoNormal" style="text-align: justify"><span> </span></p>
<pre style="text-align: justify"><span lang="EN-US">ktpass -princ HTTP/athena.olympus.net@OLYMPUS.NET
-mapuser athena.olympus.net
-crypto DES-CBC-MD5
-ptype KRB5_NT_PRINCIPAL
-mapop set +desonly
-pass longlongpassword
-out c:\temp\athena.http.keytab</span></pre>
<pre style="text-align: justify"><span lang="EN-US">ktpass -princ HOST/athena.olympus.net@OLYMPUS.NET
-mapuser athena.olympus.net
-crypto DES-CBC-MD5
-ptype KRB5_NT_PRINCIPAL
-mapop set +desonly
-pass longlongpassword
-out c:\temp\athena.host.keytab</span></pre>
<p class="MsoNormal" style="text-align: justify"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Podczas tworzenia pliku keytab należy podać SPN, dla którego tworzony jest plik keytab, algorytm szyfrowania ticketów oraz hasło użytkownika wymienionego w parametrze mapuser. Obydwa pliki keytab (zapisane na dysku w miejscu wyspecyfikowanym w parametrze <code><span style="font-size: 10pt">out</span></code>) przekazujemy następnie administratorowi serwera <code><span style="font-size: 10pt">athena.</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Konfiguracja serwera athena</span></strong></p>
<p class="MsoNormal" style="text-align: justify"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Pierwszym krokiem konfiguracji serwera <span style="font-family: 'Courier New';">athena.olympus.net</span> jest skonfigurowanie klienta systemu Kerberos, czyli przekazanie mu danych domeny OLYMPUS.NET. Dokonujemy tego poprzez wykonanie następującego wpisu w plikach <code><span style="font-size: 10pt">/etc/krb5/kdc.conf oraz /etc/krb5/krb5.conf</span></code></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><code><span style="font-size: 10pt"> </span></code></p>
<p align="center">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 460.6pt" width="614" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">[kdcdefaults]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>kdc_ports = 88,750</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">[realms]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>OLYMPUS.NET = {</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>profile = /etc/krb5/krb5.conf</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>database_name = /var/krb5/principal</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>admin_keytab = /etc/krb5/kadm5.keytab</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>acl_file = /etc/krb5/kadm5.acl</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>kadmind_port = 749</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>max_life = 8h 0m 0s</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>max_renewable_life = 7d 0h 0m 0s</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span></span></code><code><span style="font-size: 10pt">default_principal_flags   = +preauth</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>}</span></code></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt" align="center"><strong>Tabela 2. Przykładowa treść pliku kdc.conf</strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Najważniejszym ustawieniem jest tutaj podanie ścieżki do pliku krb5.conf oraz włączenie preautentykacji dla wszystkich principali.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Kolejnym krokiem konfiguracyjnym jest utworzenie/edycja pliku krb5.conf, który powinien zawierać informacje o kontrolerze/kontrolerach domeny, algorytmie szyfrowania ticketów, ustawieniach klienta Kerberosa oraz samej domenie AD.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 460.6pt" width="614" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">[libdefaults]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>default_realm =   OLYMPUS.NET</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>default_tkt_enctypes =   des-cbc-md5</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>default_tgs_enctypes =   des-cbc-md5</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>ticket_lifetime = 600</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">[realms]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>OLYMPUS.NET = {</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>kdc = 10.1.1.1:88</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>kdc =   10.1.1.2:88</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>kdc =   10.1.1.3:88</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>kdc =   10.1.1.4:88</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>admin_server =   10.1.1.1</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span><span> </span><span> </span>default_domain=OLYMPUS.NET</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>}</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">[domain_realm]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>.olympus.net = OLYMPUS.NET</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">[appdefaults]</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>autologin = true</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>forward = true</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>encrypt = true</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt"><span> </span>forwardable= true</span></code></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: center; text-indent: 35.4pt" align="center"><strong>Tabela 3. Przykładowa treść pliku krb5.conf, konfigurująca więcej niż jeden serwer KDC</strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify"><span> </span><span> </span>Po utworzeniu/edycji dwóch powyższych plików, należy pobrać od administratora KDC dwa pliki keytab, które zostały utworzone podczas przygotowywania KDC do integracji z serwerem aplikacji.</p>
<p class="MsoNormal" style="text-align: justify"><span> </span>Po otrzymaniu obu plików keytab należy je scalić za pomocą narzędzia ktutil, wydając następujące komendy:</p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">ktutil</span></code> – uruchamia narzędzie ktutil</p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">rkt athena.http.keytab</span></code> – wczytuje keytab HTTP</p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">rkt athena.host.keytab</span></code> – wczytuje keytab HOST</p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">wkt athena.keytab</span></code> – zapisuje scalony plik keytab</p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">q</span></code> – zamyka narzędzie ktutil</p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><span> </span>Po wykonaniu scalenia, należy sprawdzić poprawność konfiguracji wydając polecenie</p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">kinit –k –t /&lt;ścieżka&gt;/athena.keytab</span></code></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify">Jeżeli nie otrzymamy komunikatu o błędzie, konfiguracja hostów zakończyła się sukcesem i możemy przejść do konfiguracji serwera BEA WebLogic.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Konfiguracja serwera aplikacji</span></strong></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Aby rozpocząć konfiguracje, należy przygotować plik konfiguracji logowania w domenie JAAS dla serwera aplikacji, <code><span style="font-size: 10pt">krb5.login.config</span></code>. Powinien on zawierać m.in. dane niezbędne serwerowi aplikacji do zlokalizowania pliku <code><span style="font-size: 10pt">athena.keytab</span></code>. Przykładową treść takiego pliku przedstawia tabela 4.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p align="center">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 460.6pt" width="614" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">com.sun.security.jgss.initiate   {</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>com.sun.security.auth.module.Krb5LoginModule required</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>principal="HTTP/athena.olympus.net@OLYMPUS.NET"   useKeyTab=true</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>keyTab="/etc/athena.keytab"   storeKey=true;</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">};</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">com.sun.security.jgss.accept   {</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>com.sun.security.auth.module.Krb5LoginModule   required</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>principal="HTTP/athena.olympus.net@OLYMPUS.NET"   useKeyTab=true</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"><span> </span>keyTab="/etc/athena.keytab"   storeKey=true;</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US"> </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">};</span></code></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong>Tabela 4. Przykładowa treść pliku krb5.login.config</strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong> </strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Plik <code><span style="font-size: 10pt">krb5.login.config</span></code> powinien zostać utworzony w obrębie domeny serwera WebLogic. W dalszej części artykułu przyjmujemy, że został on utworzony w katalogu głównym domeny, oznaczanym jako $DOMAIN_HOME.</p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify"><span> </span>Po utworzeniu konfiguracji logowania domeny JAAS, należy uzupełnić zestaw parametrów rozruchowych serwera WebLogic o parametry specyficzne dla integracji z serwerem Kerberos. Listę parametrów zawiera tabela 5.</p>
<p class="MsoNormal" style="text-align: justify">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 460.6pt" width="614" valign="top">
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Djava.security.krb5.realm=OLYMPUS.NET </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Djava.security.krb5.kdc=10.1.1.1 </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Djava.security.auth.login.config= ${DOMAIN_HOME}/krb5.login.config </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Djavax.security.auth.useSubjectCredsOnly=false </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">-Dweblogic.security.enableNegotiate=true </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt">-Dweblogic.security.identityAssertionTTL=-1</span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Dsun.security.krb5.debug=true   <span> </span></span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-DDebugSecurityAdjudicator=true </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Dweblogic.debug.DebugSecurityAtn=true </span></code></p>
<p class="MsoNormal" style="text-align: justify"><code><span style="font-size: 10pt" lang="EN-US">-Dweblogic.debug.DebugSecurityAtz=true </span></code><span style="font-size: 10pt; font-family: 'Courier New';"></span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><strong>Tabela 5. Lista dodatkowych parametrów rozruchowych serwera BEA WebLogic</strong></p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Na liście parametrów znajdują się między innymi nazwa domeny, adres KDC, położenie pliku konfiguracji logowania. Parametr <code><span style="font-size: 10pt">weblogic.security.identityAssertionTTL</span></code> określa czas (w sekundach) ważności pojedynczego ustalenia tożsamości logującego się do usługi. Standardowo ma on wartość 300, ustawienie na -1 oznacza, że od razu po zalogowaniu dane ustalenie tożsamości jest nieważne i proces logowania powinien się rozpocząć od nowa przy każdej następnej próbie uzyskania dostępu do aplikacji przez danego użytkownika. Ostatnie cztery parametry włączają tryb DEBUG logowania mechanizmów dokonujących identyfikacji i autoryzacji w WebLogic. Ustawienie ich na true powoduje duży przyrost logów, dlatego po fazie testów integracji najlepiej przestawić je na false. Logi autentykatorów znajdują się w katalogu DOMAIN_HOME/servers/&lt;nazwa_serwera_weblogic&gt;.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><span style="font-size: 10pt">Po dodaniu parametrów rozruchowych należy uruchomić domenę i zalogować się do konsoli zarządzania serwerem. Po zalogowaniu się, należy przejść do Security Realms/&lt;nazwa_domeny_JAAS&gt; i wejść na zakładkę Providers. </span></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify; page-break-after: avoid" align="center"><!--[if gte vml 1]><v :shape  id="_x0000_i1026" type="#_x0000_t75" style='width:453pt;height:213.75pt'> <v :imagedata src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image003.png" mce_src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image003.png"   o:title="" /> </v>< ![endif]--><!--[if !vml]--><a title="Konfiguracja autentykatorów serwera WebLogic zintegrowanego z domeną Active Directory." href="http://j2ee.pl/wp-content/uploads/2007/12/image005.png"></a></p>
<p style="text-align: center"><a title="Konfiguracja autentykatorów serwera WebLogic zintegrowanego z domeną Active Directory." href="http://j2ee.pl/wp-content/uploads/2007/12/image005.png"><img src="http://j2ee.pl/wp-content/uploads/2007/12/image005.thumbnail.png" alt="Konfiguracja autentykatorów serwera WebLogic zintegrowanego z domeną Active Directory." /></a></p>
<p class="MsoCaption" style="text-align: center" align="center"><a title="_Ref184318028" name="_Ref184318028"></a><strong>Rys. <span><span>2</span></span>. Konfiguracja autentykatorów serwera WebLogic zintegrowanego z domeną Active Directory.</strong></p>
<p class="MsoCaption" style="text-align: center" align="center">
<p class="MsoCaption" style="text-align: center" align="center">
<p class="MsoNormal">
<p class="MsoNormal"><span> </span>Na zakładce Providers należy skonfigurować dwa autentykatory. Pierwszym z nich jest <code><span style="font-size: 10pt">NegotiateIdentityAsserter</span></code>, który powinien znaleźć się na szczycie stosu autentykatorów serwera WebLogic. Jego konfiguracja jest trywialna – w zdecydowanej większości przypadków wystarczy go tylko dodać do stosu.</p>
<p class="MsoNormal"><span> </span>Kolejnym autentykatorem, który należy skonfigurować w celu zintegrowania serwera WebLogic z domeną Active Directory jest <code><span style="font-size: 10pt">ActiveDirectoryAuthenticator</span></code>.</p>
<p class="MsoNormal">
<p class="MsoNormal" style="page-break-after: avoid"><!--[if gte vml 1]><v :shape  id="_x0000_i1027" type="#_x0000_t75" style='width:453pt;height:207pt'> <v :imagedata src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image005.png" mce_src="file:///C:\DOCUME~1\mano\USTAWI~1\Temp\msohtml1\01\clip_image005.png"   o:title="" /> </v>< ![endif]--><!--[if !vml]--><a title="Konfigurowanie ActiveDirectoryAuthenticator" href="http://j2ee.pl/wp-content/uploads/2007/12/image007.png"></a></p>
<p style="text-align: center"><a title="Konfigurowanie ActiveDirectoryAuthenticator" href="http://j2ee.pl/wp-content/uploads/2007/12/image007.png"><img src="http://j2ee.pl/wp-content/uploads/2007/12/image007.thumbnail.png" alt="Konfigurowanie ActiveDirectoryAuthenticator" /></a></p>
<p><!--[endif]--></p>
<p class="MsoCaption" style="text-align: center" align="center"><a title="_Ref184318033" name="_Ref184318033"></a><strong>Rys. <span><span>3</span></span>. Konfigurowanie ActiveDirectoryAuthenticator</strong></p>
<p class="MsoCaption" style="text-align: center" align="center">
<p class="MsoCaption" style="text-align: center" align="center">
<p class="MsoNormal">
<p class="MsoNormal" style="text-indent: 18pt">Podczas jego konfigurowania (na zakładce „Provider Specific” p. <span>Rys. <span>3</span><!--[if gte mso 9]><xml> <w :data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003100380034003300310038003000330033000000</w> </xml>< ![endif]--></span>), należy wprowadzić informacje o domenie AD, między innymi:</p>
<p class="MsoListBullet"><!--[if !supportLists]--><span style="font-family: Symbol;"><span>·<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span></span><!--[endif]-->adres IP Kontrolera Domeny</p>
<p class="MsoListBullet"><!--[if !supportLists]--><span style="font-family: Symbol;"><span>·<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span></span><!--[endif]-->port, na którym działa usługa LDAP AD zawierająca dane domeny</p>
<p class="MsoListBullet"><!--[if !supportLists]--><span style="font-family: Symbol;"><span>·<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span></span><!--[endif]-->gałąź użytkowników w drzewie LDAP AD</p>
<p class="MsoListBullet"><!--[if !supportLists]--><span style="font-family: Symbol;"><span>·<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span></span><!--[endif]-->gałąź grup w drzewie LDAP AD</p>
<p class="MsoListBullet"><!--[if !supportLists]--><span style="font-size: 10pt; font-family: Symbol;"><span>·<span style="font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; font-family: 'Times New Roman';"> </span></span></span><!--[endif]-->nazwę i hasło użytkownika zarejestrowanego w domenie, z uprawnień którego korzysta system podczas logowania się do LDAP AD. W naszym przykładzie, użytkownikiem takim będzie <code><span style="font-size: 10pt">athena.olympus.net</span></code></p>
<p class="MsoListBullet"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoListBullet" style="margin-left: 0cm; text-indent: 18pt"><span style="font-size: 10pt">Następnie należy przygotować naszą aplikację WWW do integracji z Kerberosem. Dokonujemy tego, zmieniając wpis dotyczący konfiguracji logowania w pliku web.xml aplikacji na:</span></p>
<p class="MsoListBullet" style="margin-left: 0cm; text-indent: 18pt"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt">&lt;login-config&gt;</span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt" lang="EN-US; text-indent: 34pt">&lt;auth-method&gt;CLIENT-CERT&lt;/auth-method&gt;</span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt">&lt;/login-config&gt;</span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal"><code><span style="font-size: 10pt"> </span></code></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Konfiguracja przeglądarki klienta</span></strong></p>
<p class="MsoNormal">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Zakładamy, że klient zalogowany na stacji <code><span style="font-size: 10pt">apollo.olympus.net</span></code> będzie uzyskiwał dostęp do aplikacji za pomocą przeglądarki MS Internet Explorer 7.0. Aby skonfigurować tą przeglądarkę do łączenia się<span> </span>z naszą aplikacją, należy dodać komputer <code><span style="font-size: 10pt">athena.olympus.net</span></code> do strefy „Lokalny intranet”. Dokonujemy tego poprzez wybranie z menu głównego przeglądarki pozycji „Narzędzia &gt; Opcje internetowe”. Następnie, na zakładce „Zabezpieczenia” wybieramy pozycję „Lokalny intranet” i naciskamy przycisk „Witryny”. Upewniamy się, że opcje „Uwzględnij wszystkie lokalne witryny (sieć intranet), które nie należą do innych stref” oraz „Uwzględnij wszystkie witryny, które nie używają serwerów proxy” są zaznaczone. Później klikamy w przycisk „Zaawansowane” i dodajemy adres <code><span style="font-size: 10pt">athena.olympus.net</span></code> do listy witryn traktowanych jako lokalny intranet.</p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Następnie, na zakładce „Zabezpieczenia”, klikamy w przycisk „Poziom niestandardowy” i w sekcji „Uwierzytelnianie użytkownika” wybieramy opcję „Zaloguj automatycznie tylko w strefie intranetu”.</p>
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify">
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">
<p class="MsoNormal" style="text-align: justify"><strong><span style="font-size: 14pt">Podsumowanie</span></strong></p>
<p class="MsoNormal" style="text-align: justify; text-indent: 35.4pt">Czas na przetestowanie nowego sposobu logowania do aplikacji WWW. Aby tego dokonać, logujemy się na stację <code><span style="font-size: 10pt">apollo.olympus.net</span></code> i podajemy w przeglądarce adres sięgający do strefy chronionej naszej aplikacji. Jeżeli zamiast prawidłowego ekranu aplikacji zobaczymy ekran z błędem protokołu HTTP, przechodzimy do fazy debugowania właśnie wykonanej integracji. Ale to już temat na zupełnie inny artykuł.<span> </span></p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/12/04/oswajanie-kerberosa-czyli-dwunasta-praca-heraklesa/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Hudson jako przykład implementacji koncepcji Automated Continuous Integration</title>
		<link>http://j2ee.pl/2007/12/01/hudson-jako-przyklad-implementacji-koncepcji-automated-continuous-integration/</link>
		<comments>http://j2ee.pl/2007/12/01/hudson-jako-przyklad-implementacji-koncepcji-automated-continuous-integration/#comments</comments>
		<pubDate>Sat, 01 Dec 2007 04:33:53 +0000</pubDate>
		<dc:creator>Michał Mally</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[Jakość]]></category>
		<category><![CDATA[ci]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[emma]]></category>
		<category><![CDATA[hudson]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/12/01/hudson-jako-przyklad-implementacji-koncepcji-automated-continuous-integration/</guid>
		<description><![CDATA[
Szczypta teorii
W żadnej poważnej publikacji nie może oczywiście zabraknąć części czysto teoretycznej! Pomimo faktu, że ta publikacja do tak zaszczytnego grona nie pretenduje, to z przykrością stwierdzam, że i tutaj teoretyczny wstęp znaleźć się niestety musi. Osoby niezainteresowane proszone są o przesunięcie paska przewijania odrobinę niżej.
Z roku na rok wdrażane systemy informatyczne stają się funkcjonalnie [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://j2ee.pl/wp-content/uploads/2007/12/hudson.png" title="Hudson"><img src="http://j2ee.pl/wp-content/uploads/2007/12/hudson.thumbnail.png" alt="Hudson" /></a></p>
<h3>Szczypta teorii</h3>
<p>W żadnej poważnej publikacji nie może oczywiście zabraknąć części czysto teoretycznej! Pomimo faktu, że ta publikacja do tak zaszczytnego grona nie pretenduje, to z przykrością stwierdzam, że i tutaj teoretyczny wstęp znaleźć się niestety musi. Osoby niezainteresowane proszone są o przesunięcie paska przewijania odrobinę niżej.</p>
<p>Z roku na rok wdrażane systemy informatyczne stają się funkcjonalnie bardziej złożone, terminy ich oddania krótsze, a stawiane im wymagania jakościowe surowsze. Sprostanie ciągle rosnącym oczekiwaniom klientów biznesowych wymaga od firm rynku IT stosowania coraz większej ilości narzędzi formalizujących i automatyzujących proces wytwarzania aplikacji.</p>
<p><span id="more-102"></span></p>
<p>Już w tym momencie do grona narzędzi uważanych za niezbędne w cyklu wytwarzania oprogramowania zalicza się, i to  z coraz większą stanowczością, aplikacje wspomagające proces <em>ciągłej integracji</em> (ang. <strong>Continuous Integration</strong>).</p>
<p>Uważam, że koncepcja <strong>Continuous Integration</strong> (<em>dalej</em>: <strong>CI</strong>) jest szczególnym przypadkiem wzorca projektowego i jako taka obecna była w informatyce w niesformalizowanej formie już od dawna. Jednak jej znacząca popularyzacja miała miejsce dopiero w okresie upowszechnienia się metodyki <strong>Extreme Programming</strong>. Z pewnością ogromny wpływ na taki stan rzeczy miały publikacje <strong>Martina Fowler</strong>&#8216;a oraz <strong>Kenta Beck</strong>&#8216;a, które nadały <strong>CI</strong> realne kształty i obudziły dyskusję na ten temat w światku informatycznym. Przedstawiona idea odbiła się dużym echem i w wielu projektach zaczęto wdrażać przedstawioną koncepcję.</p>
<p>Główna myśl stojącą za <strong>CI</strong> to wymuszenie zbudowania całego projektu w wyniku każdej najmniejszej nawet zmiany. Proces budowania powinien obejmować między innymi kompilację kodu źródłowego, sprawdzenie jego jakości przy wykorzystaniu różnych kryteriów (np. <a href="http://checkstyle.sourceforge.net/">checkstyle</a>&#8216;a),  wykonanie testów jednostkowych (np. <a href="http://www.junit.org/">JUnit</a>) oraz weryfikacja stopnia w jaki pokrywają one kod źródłowy (np. <a href="http://emma.sourceforge.net/">Emma</a>), wytworzenie artefaktów (w tym np. pliki <em>war</em>, dokumentacja). Wszystkie te działania koordynowane mogą być oczywiście przy pomocy <a href="http://ant.apache.org/">Apache Ant</a>, <a href="http://maven.apache.org/">Apache Maven</a>, czy też innego narzędzia przeznaczonego do budowania, chociaż dwa wymienione jako pierwsze wydają się być w tym momencie bezkonkurencyjne.</p>
<p>Widać więc zatem, że <strong>CI</strong> nie stara się wymyślać koła na nowo, a jedynie stanowi kolejną warstwę abstrakcji ponad  szeroko już wykorzystywanymi narzędziami.</p>
<h4>Zalety i wady</h4>
<p>Podstawowe zalety <strong>CI</strong> wymieniane na większości stron internetowych związanych z tematyką, to:</p>
<ul>
<li>możliwość dokładnego określenia która z wprowadzonych zmian spowodowała dezintegrację rozwijanego systemu poprzez określenie w którym momencie któryś z testów jednostkowych przestał poprawnie przechodzić</li>
<li>problemy związane z integracją są wykrywane i naprawiane na bieżąco</li>
<li>natychmiastowa informacja na temat <em>popsutego</em> kodu</li>
<li>natychmiastowe wykonywanie testów jednostkowych</li>
<li>dostępność najnowszej wersji zbudowanej aplikacji bez konieczności jej ręcznego budowania</li>
<li>możliwość śledzenia w czasie wartości różnych wskaźników opisujących różne parametry wytwarzanej aplikacji (np. stopień pokrycia kodu testami jednostkowymi)</li>
<li>programiści zmobilizowani są do tworzenia lepszych rozwiązań; są bardziej świadomi, że każda wprowadzana przez nich zmiana może zostać poddana obiektywnej ocenie</li>
</ul>
<p>Obok w/w zalet istnieją zapewne inne pomniejsze, które każdy z nas na swój sposób może w <strong>CI</strong> odnaleźć. Jakie są zatem minusy wdrożenia <em>procesu ciągłej integracji</em>? O wadach <strong>CI</strong> Internet dosyć <em>głośno milczy</em> i mnie również trudno jest znaleźć przynajmniej kilka wad, które mogłyby mieć generalny i warty wspominania charakter. Nie oznacza to jednak, że <strong>CI</strong> nie może nam przysporzyć dodatkowych problemów. Analizę potencjalnych minusów należy jednak przeprowadzić indywidualnie przy okazji wyboru konkretnego modelu realizacji <strong>CI</strong>. W większości jednak projektów używanie <strong>CI</strong> będzie sprawiać mniejsze problemy, niż te, które mogłyby wystąpić w wyniku jego nieużywania.</p>
<h4>Manual vs. Automated</h4>
<h5>Manual Continuous Integration</h5>
<p>Najprostszym możliwym sposobem wdrożenia <strong>CI</strong> w projekcie jest przerzucenie odpowiedzialności za jego stosowanie na programistów. Najprostszym i zarazem chyba najgorszym z możliwych. Mogłoby to polegać na zobowiązaniu osób związanych z procesem wytwarzania aplikacji do każdorazowego wykonywania serii żmudnych i mechanicznych czynności po każdej pojedynczej zmianie wprowadzonej do repozytorium. Niestety takie podejście ma bardzo wiele wad i wydaje się, że może się jedynie sprawdzać w bardzo małych projektach.</p>
<p>Podstawowe problemy związane z <em>manualnym</em> stosowaniem <strong>CI</strong>, które jestem w stanie w tym momencie wymienić, to:</p>
<ul>
<li>developerzy muszą poświęcić dodatkowy czas na procedury związane z <strong>CI</strong></li>
<li>występuje możliwość niedbałego podejścia developerów do stosowania <strong>CI</strong></li>
<li>obniżenie kreatywności developerów poprzez wykonywanie żmudnych i powtarzalnych procedur</li>
<li>niedeterministyczne opóźnienia w publikacji artefaktów związane z koniecznością manualnego wykonania wszystkich procedur</li>
</ul>
<p>Wymienione powyżej problemy, to jedynie niektóre z którymi możemy mieć do czynienia przy <em>ręcznym</em> stosowaniu koncepcji <strong>CI</strong>. Przedstawiona lista stanowi jednak dla mnie wystarczający powód, by <strong>CI</strong> w miarę możliwości starać się stosować jedynie w zautomatyzowanej formie. Tym bardziej, że proces przeprowadzania <em>ciągłej integracji</em> wytwarzanego projektu można bez większych przeszkód opisać w prostej sformalizowanej postaci. Umożliwi to jego automatyczne wykonywanie w wyniku konkretnego zdarzenia zachodzącego w naszym systemie (w klasycznej i najczęściej stosowanej postaci będzie to wprowadzenie przez developera zmian do kodu źródłowego projektu).</p>
<h5>Automated Continuous Integration</h5>
<p>Na szczęście, by wyrwać nas z marazmu związanego z <em>ręcznym</em> stosowaniem <strong>CI</strong>, przychodzą nam wyspecjalizowane narzędzia automatyzujące ten proces. Jeżeli nasze zakłopotanie nie mija, to tylko dlatego, że wybór odpowiedniego narzędzia, ze względu na ich mnogość, nie jest wcale prosty. Dostępnych jest przynajmniej kilkadziesiąt produktów tego rodzaju. Wybieranie aplikacji spełniającej nasze oczekiwania (w sposób możliwie najbardziej kompletny) powinno obejmować rozważenie licencji produktu, zastanowienie się nad czynnościami, które będziemy chcieli włączyć do procesu <strong>CI</strong> oraz z jakimi narzędziami chcielibyśmy, aby wybrana implementacja <em>ACI</em> współpracowała. Poza tym, co zostało wymienione,  powinniśmy kierować się jak zawsze zdroworozsądkowymi kryteriami &#8211; podobnie jak przy doborze innych narzędzi.</p>
<p>W miarę kompletną listę narzędzi do automatyzacji procesu <em>ciągłej integracji</em> można znaleźć <a href="http://en.wikipedia.org/wiki/Continuous_Integration">tutaj</a>.</p>
<h3>Gram praktyki</h3>
<p>Kiedy już poznaliśmy teoretyczne podstawy <strong>CI</strong> najwyższy czas, aby przejść do jego praktycznego wykorzystania. Zaczniemy od określenia szczegółowych wymagań dotyczących modelu procesu <em>ciągłej integracji</em>, który chcielibyśmy zaimplementować w naszym przykładowym projekcie. By tego jednak dokonać wcześniej postaram się opisać w kilku słowach środowisko wytwórcze powiązane z naszym przykładowym projektem nazwanym przeze mnie <em>Validator</em>.</p>
<p>Elementy środowiska wytwórczego dla projektu <em>Validator</em>:</p>
<ul>
<li>Wiodący język programowania: <strong>Java</strong></li>
<li>Repozytorium: <strong>Subversion</strong></li>
<li>Narzędzie automatyzujące proces budowania: <strong>Apache Ant</strong></li>
<li>Silnik testów jednostkowych: <strong>JUnit</strong></li>
<li>Narzędzie do weryfikacji pokrycia kodu: <strong>Emma</strong></li>
</ul>
<p>A teraz cele, które chcielibyśmy osiągnąć dzięki zastosowaniu <strong>Automated Continuous Integration</strong>. Każde wprowadzenie zmiany do repozytorium powinno skutkować:</p>
<ul>
<li>kompilacją kodu źródłowego</li>
<li>wykonaniem wszystkich testów jednostkowych (wraz z utrwaleniem rezultatów)</li>
<li>obliczeniem stopnia pokrycia kodu testami na poziomie klas, metod oraz linii (wraz z utrwaleniem rezultatów)</li>
<li>sprawdzeniem jakości kodu przy użyciu <em>checkstyle</em> (wraz z utrwaleniem rezultatów)</li>
<li>zbudowaniem biblioteki w postaci pliku <em>jar</em> oraz udostępnieniu go do pobrania</li>
<li>wysłaniem pod wskazany adres informacji w postaci maila o niepowodzeniu na jakimkolwiek etapie procesu</li>
</ul>
<p>Jak łatwo można zauważyć jest to bardzo prosty przykład procesu <em>ciągłej integracji</em> &#8211; można wręcz rzec, że <em>szkoleniowy</em>. W przypadku prawdziwych projektów prawdopodobnie będziemy mieli do czynienia z wielokrotnie bardziej złożonymi mechanizmami. Nie należy się jednak tym przerażać, gdyż w większości sytuacji dodatkowa praca, jaką należy wykonać jest związana, nie z samym narzędziem <strong>ACI</strong>, ale z narzędziem służącym do budowy aplikacji (np. <strong>Apache Ant</strong>).</p>
<h4>Hudson</h4>
<p>Wpisując w <strong>Google</strong> <em>hudson</em> można by pomyśleć, że <strong>Hudson</strong>, to rzeka. Nic bardziej mylnego ;) <strong>Hudson</strong> nie jest może najbardziej popularnym narzędziem <strong>ACI</strong>, ale z pewnością jest projektem, który bardzo dynamicznie się w ostatnim czasie rozwija i posiada podatną na rozszerzalność architekturę. Istnieje wiele <em>wtyczek</em> rozszerzających funkcjonalność <strong>Hudson</strong>&#8216;a o dodatkowe możliwości, a i tak ciągle pojawiają się nowe, a już istniejące są rozwijane. Widać, że projekt <em>żyje</em> &#8211; wróży mu to dobrą przyszłość. <strong>Hudson</strong> ma także jeszcze jedną niezaprzeczalną zaletę – osobiście bardzo lubię go używać i nie ukrywam, że mam nadzieję, że ten artykuł w jakiś, chociaż nieznaczny,  sposób wpłynie na jego szybszą popularyzację.</p>
<h5>Instalacja</h5>
<p>Instalacja <strong>Hudson</strong>&#8216;a jest wyjątkowo prosta. Wystarczy posiadać kontener <em>servlet</em>&#8216;ów – może to być na przykład <strong>Apache Tomcat</strong>. W przypadku <strong>Tomcat</strong>&#8216;a wystarczy jedynie przekopiować ściągnięty ze strony producenta plik <em>hudson.war</em> do katalogu <em>webapps</em>. Następnie uruchamiamy <strong>Tomcat</strong>&#8216;a i to już wszystko! Przy standardowej konfiguracji <strong>Hudson</strong> powinien być dostępny pod adresem <a href="http://localhost:8080/hudson">http://localhost:8080/hudson</a>.</p>
<p>Konfiguracja <strong>Hudson</strong>&#8216;a odbywa się poprzez <em>Manage Hudson/System Configuration</em> dostępne z głównej stronie. Minimalne ustawienia, jakie należy wprowadzić, to między innymi:</p>
<ul>
<li>lokalizacja instalacji <strong>JDK</strong></li>
<li>lokalizacja instalacji <strong>Ant</strong>/<strong>Maven</strong></li>
<li>konfiguracja serwera <em>SMTP</em> z którego będzie korzystał <strong>Hudson</strong></li>
</ul>
<p>Dodatkowo, aby umożliwić spełnienie wymagań, które sobie wcześniej postawiliśmy konieczne jest jeszcze ściągnięcie ze <a href="http://hudson.gotdns.com/wiki/display/HUDSON/Plugins">strony</a> odpowiednich wtyczek i ich zainstalowanie:</p>
<ul>
<li><strong>Emma</strong> &#8211; posłuży nam do śledzenia postępu pokrycia kodu testami (pomiędzy kolejnymi <em>build</em>&#8216;ami)</li>
<li><strong>Violations</strong> &#8211; posłuży nam do obrazowania zastrzeżeń, jakie <em>checkstyle</em> ma w stosunku do naszego kodu</li>
</ul>
<p>Instalacji <em>plugin</em>&#8216;ów należy dokonać poprzez opcję <em>Manage Hudson/Manage Plugins</em>. Po zainstalowaniu <em>wtyczek</em> należy zrestartować serwer aplikacji. W tym momencie powinniśmy posiadać już <strong>Hudson</strong>&#8216;a w postaci pozwalającej nam na osiągnięcie wyżej wskazanych celów. Teraz czeka nas jeszcze trochę pracy poza <strong>ACI</strong> związanej z czynnościami, które należy wykonać nawet, jeżeliby projekt nie korzystał z dobrodziejstw <strong>CI</strong>.</p>
<h4>Skrypt budujący</h4>
<p>Poniżej pozwoliłem sobie zamieścić używany w projekcie skrypt budujący <strong>Apache Ant</strong>. Jak łatwo można zauważyć jest to zwykły skrypt budujący i nic nie wskazuje na to, że był on przygotowany w celu późniejszej współpracy z <strong>Hudson</strong>&#8216;em. Nie posiada on także żadnych <em>magicznych</em> powiązań z systemem <strong>ACI</strong>. Nic zatem nie stoi na przeszkodzie by wywołać go bezpośrednio za pomocą <strong>Ant</strong>&#8216;a. Kompletne źródła projektu <em>Validator</em> można ściągnąć <a href="http://j2ee.pl/wp-content/uploads/2007/12/validator.zip">stąd</a>.</p>
<pre class="prettyprint">&lt;?xml version="1.0"?&gt;
&lt;project name="Validator" default="build_jar"&gt;

  &lt;property name="main.source.dir" location="src" /&gt;
  &lt;property name="test.source.dir" location="test" /&gt;
  &lt;property name="lib.dir" location="lib" /&gt;
  &lt;property name="build.dir" location="build" /&gt;
  &lt;property name="dist.dir" location="${build.dir}/dist" /&gt;
  &lt;property name="main.source.build.dir" location="${build.dir}/classes/source" /&gt;
  &lt;property name="main.source.debug.dir" location="${build.dir}/classes/source_debug" /&gt;
  &lt;property name="main.source.instrumented.dir" location="${build.dir}/classes/source_instrumented" /&gt;
  &lt;property name="test.source.build.dir" location="${build.dir}/classes/test" /&gt;
  &lt;property name="test.result.dir" location="${build.dir}/test" /&gt;
  &lt;property name="violations.result.dir" location="${build.dir}/violations" /&gt;
  &lt;property name="coverage.result.dir" location="${build.dir}/coverage" /&gt;
  &lt;property name="code.coverage.metadata.file" location="${coverage.result.dir}/coverage.em" /&gt;
  &lt;property name="code.coverage.xml.file" location="${coverage.result.dir}/coverage.xml" /&gt;
  &lt;property name="code.coverage.html.file" location="${coverage.result.dir}/coverage.html" /&gt;
  &lt;property name="checkstyle.result.file" location="${violations.result.dir}/checkstyle.xml" /&gt;
  &lt;property name="main.jar.file" value="validator.jar" /&gt;

  &lt;taskdef name="emma" classname="com.vladium.emma.emmaTask"&gt;
    &lt;classpath&gt;
      &lt;fileset dir="${lib.dir}"&gt;
        &lt;include name="emma_ant.jar" /&gt;
        &lt;include name="emma.jar" /&gt;
      &lt;/fileset&gt;
    &lt;/classpath&gt;
  &lt;/taskdef&gt;

  &lt;taskdef resource="checkstyletask.properties" classpath="${lib.dir}/checkstyle-all-4.3.jar" /&gt;

  &lt;path id="test.build.classpath"&gt;
    &lt;pathelement location="${main.source.build.dir}" /&gt;
    &lt;fileset dir="${lib.dir}"&gt;
      &lt;include name="junit.jar" /&gt;
    &lt;/fileset&gt;
  &lt;/path&gt;

  &lt;path id="test.runtime.classpath"&gt;
    &lt;pathelement location="${main.source.instrumented.dir}/classes" /&gt;
    &lt;pathelement location="${test.source.build.dir}" /&gt;
    &lt;fileset dir="${lib.dir}"&gt;
      &lt;include name="junit.jar" /&gt;
      &lt;include name="emma.jar" /&gt;
    &lt;/fileset&gt;
  &lt;/path&gt;

  &lt;target name="clean"&gt;
    &lt;delete dir="${build.dir}" /&gt;
  &lt;/target&gt;

  &lt;target name="compile_main"&gt;
    &lt;mkdir dir="${main.source.build.dir}" /&gt;
    &lt;javac srcdir="${main.source.dir}" destdir="${main.source.build.dir}" /&gt;
  &lt;/target&gt;

  &lt;target name="compile_main_debug"&gt;
    &lt;mkdir dir="${main.source.debug.dir}" /&gt;
    &lt;javac srcdir="${main.source.dir}" destdir="${main.source.debug.dir}" debug="true" /&gt;
  &lt;/target&gt;

  &lt;target name="compile_test"&gt;
    &lt;mkdir dir="${test.source.build.dir}" /&gt;
    &lt;javac srcdir="${test.source.dir}" destdir="${test.source.build.dir}"&gt;
      &lt;classpath refid="test.build.classpath" /&gt;
    &lt;/javac&gt;
  &lt;/target&gt;

  &lt;target name="run_test" depends="compile_main,compile_main_debug,compile_test"&gt;
    &lt;mkdir dir="${test.result.dir}" /&gt;
    &lt;delete dir="${main.source.instrumented.dir}" /&gt;
    &lt;mkdir dir="${main.source.instrumented.dir}" /&gt;
    &lt;emma&gt;
      &lt;instr outdir="${main.source.instrumented.dir}" mode="fullcopy" merge="false" metadatafile="${code.coverage.metadata.file}"&gt;
        &lt;instrpath&gt;
          &lt;pathelement location="${main.source.debug.dir}" /&gt;
        &lt;/instrpath&gt;
      &lt;/instr&gt;
    &lt;/emma&gt;
    &lt;junit fork="yes"&gt;
      &lt;formatter type="xml" /&gt;
      &lt;classpath refid="test.runtime.classpath" /&gt;
      &lt;sysproperty key="emma.coverage.out.file" value="${code.coverage.metadata.file}" /&gt;
      &lt;sysproperty key="emma.coverage.out.merge" value="true" /&gt;
      &lt;batchtest todir="${test.result.dir}"&gt;
        &lt;fileset dir="${test.source.dir}" /&gt;
      &lt;/batchtest&gt;
    &lt;/junit&gt;
    &lt;emma&gt;
      &lt;report sourcepath="${main.source.dir}"&gt;
        &lt;infileset file="${code.coverage.metadata.file}" /&gt;
        &lt;xml outfile="${code.coverage.xml.file}" /&gt;
        &lt;html outfile="${code.coverage.html.file}" /&gt;
      &lt;/report&gt;
    &lt;/emma&gt;
  &lt;/target&gt;

  &lt;target name="violations"&gt;
    &lt;mkdir dir="${violations.result.dir}" /&gt;
    &lt;checkstyle config="${lib.dir}/sun_checks_eclipse.xml"&gt;
      &lt;fileset dir="${main.source.dir}" includes="**/*.java" /&gt;
      &lt;formatter type="xml" toFile="${checkstyle.result.file}" /&gt;
    &lt;/checkstyle&gt;
  &lt;/target&gt;

  &lt;target name="build_jar" depends="run_test,violations"&gt;
    &lt;mkdir dir="${dist.dir}" /&gt;
    &lt;jar basedir="${main.source.build.dir}" destfile="${dist.dir}/${main.jar.file}" /&gt;
  &lt;/target&gt;

&lt;/project&gt;</pre>
<p>Z punktu widzenia <strong>Hudson</strong>&#8216;a i konfiguracji, której musimy dokonać istotne będą jedynie wymienione poniżej elementy:</p>
<ul>
<li>położenie pliku <em>validator.jar</em> będącego efektem końcowym procesu budowania, który chcemy udostępnić jako artefakt</li>
<li>położenie pliku XML zawierającego wyniki wykonania testów jednostkowych</li>
<li>położenie pliku XML zawierającego informacje na temat pokrycia kodu testami jednostkowymi</li>
</ul>
<h4>Tworzenie nowego zadania <strong>Hudson</strong>&#8216;a</h4>
<p>Powoli zbliżamy się do meritum. Mając już gotowy projekt wraz z działającym skryptem budującym nie pozostało nam już wiele do zrobienia, by objąć go procesem <em>ciągłej integracji</em>. Właściwie dzieli nas od finału już tylko jeden krok, którym będzie utworzenie nowego zadania w <strong>Hudson</strong>&#8216;ie.</p>
<p>Dokonanie tego nie będzie na szczęście niczym skomplikowanym:</p>
<ol>
<li>z głównego panelu sterowania <strong>Hudson</strong> wybieramy opcję <em>New Job</em></li>
<li>określamy nazwę dla tworzonego zadania</li>
<li>wybieramy <em>free-style</em> jako rodzaj projektu i przechodzimy do następnego ekranu, gdzie wpiszemy pozostałe szczegóły</li>
<li>wybieramy system kontroli wersji z którego będzie korzystał <strong>Hudson</strong> (w naszym przypadku będzie to <strong>Subversion</strong>)</li>
<li>jako warunek wywołania procesu integracji (<em>Build Triggers</em>) wybieramy cykliczne odpytywanie repozytorium (<em>Poll SCM</em>)</li>
<li>w harmonogramie wpisujemy łańcuch znaków zgodny z formatem <strong>crond</strong> (np. <em>*/2 * * * *</em> &#8211; odpytywanie co 2 minuty)</li>
<li>następnie definiujemy, co właściwie będzie oznaczać dla <strong>Hudson</strong>&#8216;a zbudowanie aplikacji – w naszym przypadku chcemy, aby było to wywołanie przy pomocy <strong>Ant</strong>&#8216;a domyślnego celu zdefiniowanego w skrypcie budowania (zaznaczamy <em>Invoke Ant</em>)</li>
<li>przyszedł czas na określenie czynności, które zostaną wykonane po zakończeniu budowania aplikacji &#8211; zgodnie z wcześniejszymi ustaleniami będzie interesowało nas:
<ol>
<li>zachowanie artefaktów (<em>validator.jar</em>) z procesu budowania (<em>Archive the artifacts</em>)</li>
<li>opublikowanie wyników testów jednostkowych (<em>Publish JUnit test result report</em>)</li>
<li>opublikowanie wyników pokrycia kodu testami (<em>Record Emma coverage report</em>)</li>
<li>opublikowanie wyników sprawdzenia jakości kodu przy użyciu <em>checkstyle</em>&#8216;a (<em>Report violations</em>)</li>
<li>wysłanie informacji o integracji, która się nie powiodła (<em>E-mail Notification</em>)</li>
</ol>
</li>
</ol>
<p>Tym razem to już naprawdę wszystko! Po zatwierdzeniu konfiguracji (jeżeli wszystko zrobiłeś dobrze ;)), to możesz się już cieszyć działającym procesem <em>ciągłej integracji</em>.</p>
<p>Od tej pory możesz zacząć regularną pracę zapominając zupełnie o istnieniu <strong>Hudson</strong>&#8216;a i sięgać do niego jedynie wtedy kiedy uznasz to za przydatne. A sytuacji takich może być co najmniej kilka:</p>
<ul>
<li>chęć uzyskania zbudowanej wersji aplikacji z konkretnego <em>build</em>&#8216;a</li>
<li>analiza zmienności w czasie różnych parametrów opisujących aplikację w celu określenia trendów (np. procentowe pokrycie testami kodu źródłowego)</li>
<li>zatwierdzenie zmian w repozytorium, które spowodują niebudowanie się aplikacji spowoduje wysłanie maila na wskazany adres</li>
</ul>
<h3>Podsumowanie</h3>
<p>Rozważany przez nas przykład był raczej przykładem trywialnym. Z tego też powodu może się wydawać, że <strong>Hudson</strong> nie pełni w nim znaczącej roli. Muszę się zgodzić z tą opinią – czym jednak system staje się większy i bardziej skomplikowany, tym <strong>ACI</strong> staje się bardziej niezbędny.</p>
<p>Miałem przyjemność pracować nad ogromnym systemem z wieloma podprojektami (repozytorium wielkości około 3GB), gdzie <strong>Hudson</strong> stanowił bardzo ważne ogniwo w procesie wytwarzania. Wydaje się więc, że jeżeli był w stanie poradzić sobie w takich warunkach, to dla większości standardowych zastosowań powinien być odpowiedni. Osobiście używam <strong>Hudson</strong>&#8216;a, gdyż pozostając bardzo intuicyjny oraz łatwy w konfiguracji dostarcza możliwości na zupełnie wystarczającym dla mnie poziomie zaawansowania.</p>
<p>Mam nadzieję, że mimo ograniczonych środków przekazu udało mi się przekonać Cię do wypróbowania <strong>Hudson</strong>&#8216;a na własnej <em>skórze</em>. Świadom jestem niestety, że artykuł ten to zaledwie czubek góry lodowej zarówno jeżeli chodzi o <strong>CI</strong>, jak i o samego<strong>Hudson</strong>&#8216;a.</p>
<h3>Bibliografia</h3>
<ol>
<li><a href="http://en.wikipedia.org/wiki/Continuous_Integration">http://en.wikipedia.org/wiki/Continuous_Integration</a></li>
<li><a href="http://www.extremeprogramming.org/">http://www.extremeprogramming.org/</a></li>
<li><a href="http://hudson.gotdns.com/wiki/display/HUDSON/Home">http://hudson.gotdns.com/wiki/display/HUDSON/Home</a></li>
<li><a href="http://martinfowler.com/">http://martinfowler.com/</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/12/01/hudson-jako-przyklad-implementacji-koncepcji-automated-continuous-integration/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Studia informatyczne OnLine</title>
		<link>http://j2ee.pl/2007/02/06/studia-informatyczne-online/</link>
		<comments>http://j2ee.pl/2007/02/06/studia-informatyczne-online/#comments</comments>
		<pubDate>Tue, 06 Feb 2007 09:17:03 +0000</pubDate>
		<dc:creator>Michał Porzożyński</dc:creator>
				<category><![CDATA[Inne]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/02/06/studia-informatyczne-online/</guid>
		<description><![CDATA[Wczotaj na blogu Jacka Laskowskiego znalazłem link do projektu prowadzonego przez kilka polskich uczelni, a mającego na celu prowadzenie studiów informatycznych przez Internet.  Serwis e-learningowy Studia Informatczne zawiera kilkadziesiąt kursów z zakresu szeroko pojętego IT. Na mnie, ze względu na zainteresowania, największe wrażenie zrobił przedmiot Zaawansowane aplikacje Internetowe, w którym poruszane są takie zagadnienia [...]]]></description>
			<content:encoded><![CDATA[<p>Wczotaj na blogu <a href="http://jlaskowski.blogspot.com/">Jacka Laskowskiego</a> znalazłem link do projektu prowadzonego przez kilka polskich uczelni, a mającego na celu prowadzenie studiów informatycznych przez Internet.  <a href="http://wazniak.mimuw.edu.pl/index.php?title=Strona_g%C5%82%C3%B3wna" target="_blank">Serwis e-learningowy Studia Informatczne</a> zawiera kilkadziesiąt kursów z zakresu szeroko pojętego IT. Na mnie, ze względu na zainteresowania, największe wrażenie zrobił przedmiot <em>Zaawansowane aplikacje Internetowe</em>, w którym poruszane są takie zagadnienia jak XML, CORBA, EJB (3.0), ORM, Web Services (do których zawsze chciałem siąść, ale nigdy nie miałem czasu), AJAX, Spring, wzorce projektowe J2EE (około 20 różnych) i inne. Inne kursy też zapowiadają się bardzo obiecująco: <em>zaawansowane projektowanie obiektowe</em>, <em>inżynieria oprogramowania</em> czy <em>zaawansowane systemy baz danych</em>. Co bardzo istotne treść wykładów często traktuje o najnowszych technologiach. Sam sposób prezentacji też nie zostawia wiele do życzenia. Świetny flash (z eleganckim czytaniem tekstu przez prowadzących), pdf, wiki.</p>
<p>Jestem pod dużym wrażeniem. Gratuluje pomysłu i realizacji !</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/02/06/studia-informatyczne-online/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
