<?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>Xis' blog &#187; Programowanie</title>
	<atom:link href="http://xis.schowek.net/category/programowanie/feed/" rel="self" type="application/rss+xml" />
	<link>http://xis.schowek.net</link>
	<description>Mój wirtualny schowek</description>
	<lastBuildDate>Thu, 10 Mar 2011 18:41:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Szybkie losowanie rekordów w SQL &#8211; jeszcze jeden sposób</title>
		<link>http://xis.schowek.net/2011/03/10/szybkie-losowanie-rekordow-w-sql-jeszcze-jeden-sposob/</link>
		<comments>http://xis.schowek.net/2011/03/10/szybkie-losowanie-rekordow-w-sql-jeszcze-jeden-sposob/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 18:24:44 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=386</guid>
		<description><![CDATA[Jeśli masz tabelę, w której znajduje się wiele rekordów i stajesz przed potrzebą wyświetlenie kilku losowych rekordów &#8211; na ogół masz problem związany z wydajnym sposobem realizacji zapytania. Są różne sposoby na rozwiązanie tego problemu. Najprostszy jest oczywiście ORDER BY RAND(), jednak słynie on z tego, że jest straszliwie powolny, zwłaszcza na dużych tabelach. Inne [...]]]></description>
			<content:encoded><![CDATA[<p>Jeśli masz tabelę, w której znajduje się wiele rekordów i stajesz przed potrzebą wyświetlenie kilku losowych rekordów &#8211; na ogół masz problem związany z wydajnym sposobem realizacji zapytania.<br />
Są różne sposoby na rozwiązanie tego problemu. Najprostszy jest oczywiście <code>ORDER BY RAND()</code>, jednak słynie on z tego, że jest straszliwie powolny, zwłaszcza na dużych tabelach.<br />
Inne rozwiązanie to załadowanie listy kluczy podstawowych tabeli do tablicy w pamięci i losowanie po stronie programu. Wykonujemy wprawdzie dwa zapytania zamiast jednego, jednak jest to metoda dużo bardziej wydajna w niektórych przypadkach.<br />
Wymyśliłem dziś inny sposób, dzięki któremu nie musimy skanować całej tabeli w celu wyświetlenia losowych rekordów. Rozwiązanie to jest bardzo proste w realizacji.</p>
<p>Wystarczy, że do tabeli, z której chcemy pobierać rekordy dodamy kolumnę np. <code>random_num</code>, najlepiej wesprzeć ją indeksem.  W kolumnie tej zapisywać będziemy losową liczbę z jakiegoś zakresu (np. 1 do 1000) podczas każdego zapisania obiektu.</p>
<p>Gdy mamy już tabelę wypełnioną  rekordami z losowymi wartościami  w kolumnie <code>random_num</code> (wartość ta oczywiście będzie się powtarzać w przypadku, gdy tabela ma &gt; 1000 rekordów, ale to nie szkodzi), wystarczy wykonać dwa zapytania:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> count<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> cnt <span style="color: #993333; font-weight: bold;">FROM</span> tabela</pre></div></div>

<p>&#8230; by zliczyć ilość rekordów.  Wynik zapytania załadujmy do zmiennej <code>cnt</code>. W zmiennej <code>limit</code> natomiast zapamiętajmy ilość rekordów, jakie chcemy pobrać. Następnie:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> tabela <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> random_num OFFSET :offset <span style="color: #993333; font-weight: bold;">LIMIT</span> :<span style="color: #993333; font-weight: bold;">LIMIT</span></pre></div></div>

<p>Pod parametr <code>:offset</code> podstawiamy losową wartość (losowaną po stronie programu) z zakresu 1 do <code>cnt</code> &#8211; ilość rekordów, jakie chcemy pobrać, a pod <code>:limit</code> &#8211; wartość zmiennej <code>limit</code>.</p>
<p>Wadą tego rozwiązania jest jego &#8222;statyczność&#8221;, tzn dla każdego wylosowanego offsetu wynik zapytania będzie się powtarzał jeśli offest będzie się powtarzał. Jeśli jednak zawartość Twojej tabeli zmienia się dość często nie jest to problemem. Innym sposobem obejścia tego stanu rzeczy jest wykonywanie co jakiś czas &#8222;reindeksacji&#8221; kolumny <code>random_num</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2011/03/10/szybkie-losowanie-rekordow-w-sql-jeszcze-jeden-sposob/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>NGINX z Symfony pod Windows</title>
		<link>http://xis.schowek.net/2009/08/24/nginx-z-symfony-pod-windows/</link>
		<comments>http://xis.schowek.net/2009/08/24/nginx-z-symfony-pod-windows/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 17:05:46 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[wamp]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=358</guid>
		<description><![CDATA[NGINX to szybki i lekki serwer HTTP, który mimo faktu, że zajmuje jedynie ok. 2 MB dysku, posiada sporo mozliwości konfiguracyjnych, takich jak virtual-hosts, czy url-rewriting. Dzięki FastCGI pozwala na obsługę skryptów PHP, ale i innych języków. Pod windowsem, w domowej deweloperce króluje zestaw WAMP, w skład którego whodzi Windows, Apache, MySQL i PHP. Postanowiłem [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://nginx.net/">NGINX</a> to szybki i lekki serwer <a href="http://pl.wikipedia.org/wiki/Hypertext_Transfer_Protocol">HTTP</a>, który mimo faktu, że zajmuje jedynie ok. 2 MB dysku, posiada sporo mozliwości konfiguracyjnych, takich jak <em>virtual-hosts</em>, czy <em>url-rewriting</em>. Dzięki <a href="http://pl.wikipedia.org/wiki/FastCGI">FastCGI</a> pozwala na obsługę skryptów <a href="http://php.net">PHP</a>, ale i innych języków.<br />
Pod windowsem, w domowej <em>deweloperce</em> króluje zestaw <a href="http://pl.wikipedia.org/wiki/WAMP">WAMP</a>, w skład którego whodzi Windows, <a href="http://pl.wikipedia.org/wiki/Apache_(serwer)">Apache</a>, <a href="http://pl.wikipedia.org/wiki/MySQL">MySQL</a> i <a href="http://pl.wikipedia.org/wiki/PHP">PHP</a>. Postanowiłem wykonać coś, co możnaby określić <em>WNMP</em>, czyli starego, ciężkiego Apacza zamienić na jego nowszy i lżejszy odpowiednik.<br />
Całość jednak ma mi pozwalać kontynuwać prace nad kilkoma projektami, które tworzę z użyciem frameworka <a href="http://www.symfony-project.org/">Symfony</a>.</p>
<p>Jak uruchomić serwer NGINX ze wsparciem dla projektów Symfony pod Windows?</p>
<p>Ściągamy <a href="http://nginx.net">najnowszą wersję serwera NGINX</a> &#8211; od niedawna istnieje wersja natywna, a nie <a href="http://www.cygwin.com/">cygwinowa</a>, jakie były <a href="http://www.kevinworthington.com/nginx-for-windows/">niedawno popularne</a>. Natywna wersja powinnna być dużo szybsza od poprzedniczki. Serwer instalujemy w np. <strong>c:/dev/tools/nginx</strong>.</p>
<p>Zakładam, że system zarządzania bazą danych MySQL, framework Symfony, oraz sam PHP jest już zainstalowany na Twoim komputerze. Zakładam też, że zarówno MySQL, jak i PHP przygotowane są do współpracy z Symfony. Jeśli nie &#8211; w sieci jest <a href="http://www.poetryofprogramming.com/pl/symfony/install-symfony-framework-xp-vista-wamp/">mnóstwo opisów jak to zrobić</a>.</p>
<p>Aby łatwo było uruchamiać i zatrzymywać serwer NGINX, musimy utworzyć następujące skrypty i zapisać je w katalogu NGINXa:</p>
<p><strong>start-nginx.bat</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">@</span><span style="color: #7a0874; font-weight: bold;">echo</span> off
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">NGINX_HOME</span>=c:<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>tools<span style="color: #000000; font-weight: bold;">/</span>nginx
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">PHP_HOME</span>=c:<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>tools<span style="color: #000000; font-weight: bold;">/</span>php
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">FASTCGI_ADDR</span>=127.0.0.1
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">FASTCGI_PORT</span>=<span style="color: #000000;">9000</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Startujemy nginx&quot;</span>
start <span style="color: #000000; font-weight: bold;">%</span>NGINX_HOME<span style="color: #000000; font-weight: bold;">%/</span>nginx.exe
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Startujemy php-cgi&quot;</span>
start <span style="color: #000000; font-weight: bold;">/</span>B <span style="color: #000000; font-weight: bold;">%</span>PHP_HOME<span style="color: #000000; font-weight: bold;">%/</span>php-cgi.exe <span style="color: #660033;">-b</span> <span style="color: #000000; font-weight: bold;">%</span>FASTCGI_ADDR<span style="color: #000000; font-weight: bold;">%</span>:<span style="color: #000000; font-weight: bold;">%</span>FASTCGI_PORT<span style="color: #000000; font-weight: bold;">%</span> <span style="color: #660033;">-c</span> <span style="color: #000000; font-weight: bold;">%</span>PHP_HOME<span style="color: #000000; font-weight: bold;">%/</span>php.ini
<span style="color: #7a0874; font-weight: bold;">exit</span></pre></div></div>

<p><strong>stop-nginx.bat</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">@</span><span style="color: #7a0874; font-weight: bold;">echo</span> off
taskkill <span style="color: #000000; font-weight: bold;">/</span>f <span style="color: #000000; font-weight: bold;">/</span>IM nginx.exe
taskkill <span style="color: #000000; font-weight: bold;">/</span>f <span style="color: #000000; font-weight: bold;">/</span>IM php-cgi.exe
<span style="color: #7a0874; font-weight: bold;">exit</span></pre></div></div>

<p>Teraz wystarczy tylko skonfigurować NGINX tak, by </p>
<ul>
<li>pozwalał na wykonywanie skryptów PHP za pomocą fastCGI</li>
<li>pozwalał na uruchamianie skryptów napisanych we frameworku Symfony</li>
</ul>
<p>Edytujemy skrypt konfiguracyjny NGINXa (<strong>conf/nginx.conf</strong>):</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">worker_processes  <span style="color: #cc66cc;">1</span><span style="color: #00AA00;">;</span>
&nbsp;
events <span style="color: #00AA00;">&#123;</span>
    worker_connections  <span style="color: #cc66cc;">64</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
&nbsp;
http <span style="color: #00AA00;">&#123;</span>
    include       mime.types<span style="color: #00AA00;">;</span>
    default_type  application/octet-stream<span style="color: #00AA00;">;</span>
&nbsp;
    client_header_timeout   10m<span style="color: #00AA00;">;</span>
    client_body_timeout     10m<span style="color: #00AA00;">;</span>
    send_timeout            10m<span style="color: #00AA00;">;</span>
&nbsp;
    connection_pool_size            <span style="color: #cc66cc;">256</span><span style="color: #00AA00;">;</span>
    client_header_buffer_size       1k<span style="color: #00AA00;">;</span>
    large_client_header_buffers     <span style="color: #cc66cc;">4</span> 2k<span style="color: #00AA00;">;</span>
    request_pool_size               4k<span style="color: #00AA00;">;</span>
&nbsp;
    gzip on<span style="color: #00AA00;">;</span>
    gzip_min_length <span style="color: #cc66cc;">1100</span><span style="color: #00AA00;">;</span>
    gzip_buffers    <span style="color: #cc66cc;">4</span> 8k<span style="color: #00AA00;">;</span>
    gzip_types      <span style="color: #993333;">text</span>/plain<span style="color: #00AA00;">;</span>
&nbsp;
    output_buffers  <span style="color: #cc66cc;">1</span> 32k<span style="color: #00AA00;">;</span>
    postpone_output <span style="color: #cc66cc;">1460</span><span style="color: #00AA00;">;</span>
&nbsp;
    sendfile        on<span style="color: #00AA00;">;</span>
    tcp_nopush      on<span style="color: #00AA00;">;</span>
    tcp_nodelay     on<span style="color: #00AA00;">;</span>
&nbsp;
    keepalive_timeout       <span style="color: #cc66cc;">75</span> <span style="color: #cc66cc;">20</span><span style="color: #00AA00;">;</span>
    ignore_invalid_headers  on<span style="color: #00AA00;">;</span>
&nbsp;
server <span style="color: #00AA00;">&#123;</span>
    set  $docroot     c<span style="color: #00AA00;">:</span>/dev/php/symfony/myproject<span style="color: #00AA00;">;</span>
    root $docroot/web<span style="color: #00AA00;">;</span>
    index  index.php<span style="color: #00AA00;">;</span>
&nbsp;
    listen       <span style="color: #cc66cc;">80</span><span style="color: #00AA00;">;</span>
    server_name  localhost<span style="color: #00AA00;">;</span>
&nbsp;
    log_format main
                <span style="color: #ff0000;">'$remote_addr - $remote_user [$time_local] '</span>
                <span style="color: #ff0000;">'&quot;$request&quot; $status $bytes_sent '</span>
                <span style="color: #ff0000;">'&quot;$http_referer&quot; &quot;$http_user_agent&quot; '</span>
                <span style="color: #ff0000;">'&quot;$gzip_ratio&quot;'</span><span style="color: #00AA00;">;</span> 
    access_log  $docroot/log/myproject<span style="color: #6666ff;">.access</span><span style="color: #6666ff;">.log</span>  main<span style="color: #00AA00;">;</span>
&nbsp;
    charset utf-<span style="color: #cc66cc;">8</span><span style="color: #00AA00;">;</span>
&nbsp;
    location / <span style="color: #00AA00;">&#123;</span>
        if <span style="color: #00AA00;">&#40;</span>-f $request_filename<span style="color: #00AA00;">&#41;</span> <span style="color: #00AA00;">&#123;</span>
            expires max<span style="color: #00AA00;">;</span>
            break<span style="color: #00AA00;">;</span>
        <span style="color: #00AA00;">&#125;</span>
        rewrite <span style="color: #00AA00;">^</span><span style="color: #00AA00;">&#40;</span>.<span style="color: #00AA00;">*</span><span style="color: #00AA00;">&#41;</span>/index<span style="color: #6666ff;">.php</span> last<span style="color: #00AA00;">;</span>
    <span style="color: #00AA00;">&#125;</span>
&nbsp;
    location /sf/ <span style="color: #00AA00;">&#123;</span>
          root c<span style="color: #00AA00;">:</span>/dev/tools/php/data/symfony-1.2.7/data/web<span style="color: #00AA00;">;</span>
    <span style="color: #00AA00;">&#125;</span>            
&nbsp;
    location ~ \.php<span style="color: #00AA00;">&#40;</span>$|/<span style="color: #00AA00;">&#41;</span> <span style="color: #00AA00;">&#123;</span>
        set $the_uri $uri<span style="color: #00AA00;">;</span>
        if <span style="color: #00AA00;">&#40;</span>$the_uri ~ <span style="color: #ff0000;">&quot;^(.+)/$&quot;</span><span style="color: #00AA00;">&#41;</span> <span style="color: #00AA00;">&#123;</span>
            set $the_uri    $<span style="color: #cc66cc;">1</span><span style="color: #00AA00;">;</span>
        <span style="color: #00AA00;">&#125;</span>
&nbsp;
        set  $script     $the_uri<span style="color: #00AA00;">;</span>
        set  $path_info  <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #00AA00;">;</span>
&nbsp;
        if <span style="color: #00AA00;">&#40;</span>$uri ~ <span style="color: #ff0000;">&quot;^(.+<span style="color: #000099; font-weight: bold;">\.</span>php)(/.+)&quot;</span><span style="color: #00AA00;">&#41;</span> <span style="color: #00AA00;">&#123;</span>
            set  $script     $<span style="color: #cc66cc;">1</span><span style="color: #00AA00;">;</span>
            set  $path_info  $<span style="color: #cc66cc;">2</span><span style="color: #00AA00;">;</span>
        <span style="color: #00AA00;">&#125;</span>
&nbsp;
        fastcgi_index   index.php<span style="color: #00AA00;">;</span>
        fastcgi_pass   127.0.0.1<span style="color: #00AA00;">:</span><span style="color: #cc66cc;">9000</span><span style="color: #00AA00;">;</span>
        include fastcgi_params<span style="color: #00AA00;">;</span>
&nbsp;
        fastcgi_param  SCRIPT_FILENAME  $docroot/web$script<span style="color: #00AA00;">;</span>
        fastcgi_param  SCRIPT_NAME      $script<span style="color: #00AA00;">;</span>
        fastcgi_param  PATH_INFO        $path_info<span style="color: #00AA00;">;</span> 
        fastcgi_param  SERVER_NAME      $host<span style="color: #00AA00;">;</span>
    <span style="color: #00AA00;">&#125;</span>
&nbsp;
    location ~ /\<span style="color: #6666ff;">.ht</span> <span style="color: #00AA00;">&#123;</span>
        deny  all<span style="color: #00AA00;">;</span>
    <span style="color: #00AA00;">&#125;</span>
  <span style="color: #00AA00;">&#125;</span>    
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Pliczek konfiguracyjny NGINX&#8217;a jest dość czytelny i łatwo go zrozumieć (łatwo go też rozbudować i zoptymalizować jeśli np. używamy virtual-hostów). Na uwagę zasługuje jednak fakt, że przed przekazaniem argumentów do FastCGI musimy nieco &#8222;rozpracować&#8221; żądanie i wydobyć z niego zmienne $script i $path_info, ewentualnie usuwając zakańczający je znak slash (zmienna $the_uri). Warto też odnotować, że NGINX wspiera znane z Apacza aliasy &#8211; widoczna tu sekcja <strong>location /sf/</strong>.<br />
Zauważ, że port 9000 wspomniany jest także w skrypcie startującym NGINX &#8211; możesz wybrać dowolny inny większy niż 1024 (niższe wymagają roli administratora i są zarezerwowane dla tzw. <em>well-known-services</em>).</p>
<p>Gotowe, teraz możemy uruchamiać NGINX poleceniem <strong>start-nginx.bat</strong> (z katalogu NGINXa) i zatrzymywać poprzez <strong>stop-nginx.bat</strong>.<br />
Nasz projekt powinien być dostępny pod adresem <a href="http://localhost/">http://localhost/</a> &#8211; czy to zakończonym slashem, czy tez nie.</p>
<p>Oczywiście nie jest to konfiguracja idealna &#8211; wspiera tylko jeden projekt (<strong>myproject</strong>), ale daje dobre podstawy do zbudowania konfiguracji dla wielu projektów i osobnych virtual-hostów dla każdego z nich. Warto wiedzieć, że konfiguracja NGINXa wspiera dyrektywę <strong>include</strong>, dzięki której możliwe jest importowanie konfiguracji z zewnętrznych plików konfiguracyjnych (np. po jednym dla każdego virtual-hosta) np. z sekcjami <strong>server</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/08/24/nginx-z-symfony-pod-windows/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Uszczelnianie aplikacji z Grails i JSecurity &#8211; ciąg dalszy</title>
		<link>http://xis.schowek.net/2009/03/22/uszczelnianie-aplikacji-z-grails-i-jsecurity-ciag-dalszy/</link>
		<comments>http://xis.schowek.net/2009/03/22/uszczelnianie-aplikacji-z-grails-i-jsecurity-ciag-dalszy/#comments</comments>
		<pubDate>Sun, 22 Mar 2009 11:12:18 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[jsecurity]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=329</guid>
		<description><![CDATA[Po ostatnim prostym zabezpieczeniu aplikacji Grailsowej z użyciem wtyczki JSecurity pozostał pewien niedosyt. Nasz przykład &#8211; i owszem &#8211; skutecznie zabezpieczył dostęp osób niezalogowanych, ale nie pokazał prawdziwej potęgi JSecurity &#8211; możliwości autoryzacji, czyli sprawdzania praw dostępu do określonych zasobów. Wyglądało to trochę tak, jakbyśmy wytaczali armatę po to by zabić muchę, dlatego teraz spróbujemy [...]]]></description>
			<content:encoded><![CDATA[<p>Po ostatnim <a href="http://xis.schowek.net/2009/03/15/proste-uwierzytelnianie-w-grails-z-jsecurity/">prostym zabezpieczeniu aplikacji Grailsowej</a> z użyciem wtyczki JSecurity pozostał pewien niedosyt. Nasz przykład &#8211; i owszem &#8211; skutecznie zabezpieczył dostęp osób niezalogowanych, ale nie pokazał prawdziwej potęgi JSecurity &#8211; możliwości autoryzacji, czyli sprawdzania praw dostępu do określonych zasobów. Wyglądało to trochę tak, jakbyśmy wytaczali armatę po to by zabić muchę, dlatego teraz spróbujemy tą armatą zapolować na grubszego zwierza ;) wciąż jednak pozostając przy założeniu, że ma być prosto i  estetycznie na ile to możliwe.<br />
Przyjmijmy zatem, że nasza aplikacja ma:</p>
<ul>
<li>dopuszczać tylko zalogowanych użytkowników (tak, jak poprzednio),</li>
<li>pozwalać na oglądanie zasobów wszystkim zalogowanym użytkownikom (posiadającym rolę &#8222;users&#8221;),</li>
<li>pozwalać na edycję/usuwanie/tworzenie nowych zasobów tylko użytkownikom posiadającym rolę &#8222;admin&#8221; (pozostali użytkownicy dostają informację o braku dostępu)</li>
</ul>
<p>Jak widzisz, wykorzystamy szkielet poprzedniej aplikacji. Zauważ też, że wprowadzamy pojęcie <em>roli</em>, czym jest rola?<br />
Zgodnie z infomacją na stronie wtyczki, to</p>
<blockquote><p>a job or a set of responsibilities that a person can have</p></blockquote>
<p>, czyli zbiór odpowiedzialności, które posiada dany użytkownik w systemie. System, oczywiście, musi takiemu użytkownikowi udostępnić możliwość wykonania czynności wchodzących w skład takich odpowiedzialności. Upraszczając &#8211; posiadanie danej roli pozwala na dostęp do zasobów systemu, do których dostęp bez niej jest zabroniony.<br />
Założeniem naszej aplikacji jest, aby każdy zalogowany użytkownik mógł oglądać dane, jednak modyfikacja jakichkolwiek informacji wiąże się z obowiązkiem posiadania roli admina.</p>
<p>Zaczynajmy.</p>
<p><strong>1.</strong> Dodajemy nowe klasy dziedzinowe</p>
<p>Musimy zdefiniować nowe klasy dziedzinowe, które pozwolą nam utrwalać informacje o rolach i powiązaniach ich z użytkownikami.</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Role <span style="color: #66cc66;">&#123;</span>
    <span style="color: #aaaadd; font-weight: bold;">String</span> name
<span style="color: #66cc66;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> UserRoleRef <span style="color: #66cc66;">&#123;</span>
    User user
    Role role
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Dzięki takim klasom dziedzinowym (i klasie <strong>User</strong> z poprzedniego wpisu) możliwa będzie realizacja referencji <em>wiele-do-wielu</em> &#8211; jeden użytkownik może mieć wiele ról w systemie, a jedna rola może być w posiadaniu wielu użytkowników.</p>
<p>Możemy teraz zapisać wstępnie uprawnienia dostępu do naszego systemu, np. tak:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">// użytkownicy</span>
<span style="color: #000000; font-weight: bold;">def</span> jasiu <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #66cc66;">&#40;</span>username: <span style="color: #ff0000;">&quot;jasiu&quot;</span>, password: <span style="color: #000000; font-weight: bold;">new</span> Sha1Hash<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;sekret&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toHex</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #000000; font-weight: bold;">def</span> admin <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #66cc66;">&#40;</span>username: <span style="color: #ff0000;">&quot;admin&quot;</span>, password: <span style="color: #000000; font-weight: bold;">new</span> Sha1Hash<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;admin&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toHex</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// role</span>
<span style="color: #000000; font-weight: bold;">def</span> usersRole <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;users&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #000000; font-weight: bold;">def</span> adminRole <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;admin&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// powiązania user-role</span>
<span style="color: #000000; font-weight: bold;">new</span> UserRoleRef<span style="color: #66cc66;">&#40;</span>user: jasiu, role: usersRole<span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #000000; font-weight: bold;">new</span> UserRoleRef<span style="color: #66cc66;">&#40;</span>user: admin, role: adminRole<span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p><strong>2.</strong> Uaktualniamy filtr</p>
<p>Role i powiązania z użytkownikami mamy już zdefiniowane i zapisane w bazie danych, jednak wciąż nie wiemy po co nam one. Samo posiadanie praw &#8222;admina&#8221; nic nie daje, jeśli nie wiemy, co one dają. Uaktualniamy nasz plik <strong>SecurityFilters.groovy</strong> tak:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> SecurityFilters <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">def</span> filters <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        auth<span style="color: #66cc66;">&#40;</span>controller: <span style="color: #ff0000;">&quot;*&quot;</span>, action: <span style="color: #ff0000;">&quot;*&quot;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            before <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
                accessControl <span style="color: #66cc66;">&#123;</span> <span style="color: #000000; font-weight: bold;">true</span> <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        manageRecord<span style="color: #66cc66;">&#40;</span>controller: <span style="color: #ff0000;">&quot;*&quot;</span>, action: <span style="color: #ff0000;">&quot;(create|edit|save|update|delete)&quot;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            before <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
                accessControl <span style="color: #66cc66;">&#123;</span>
                    role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;admins&quot;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        showRecord<span style="color: #66cc66;">&#40;</span>controller: <span style="color: #ff0000;">&quot;*&quot;</span>, action: <span style="color: #ff0000;">&quot;show&quot;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            before <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
                accessControl <span style="color: #66cc66;">&#123;</span>
                    role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;admins&quot;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">||</span> role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;users&quot;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Jak widać, mamy zdefiniowane dwie reguły dostępu do dowolnego kontrolera (gwiazdka), ale z wyszczególnionymi akcjami. Akcja <strong>show</strong> wymaga posiadania roli &#8222;users&#8221;, albo &#8222;admins&#8221; (czyli dowolnej, na chwilę obecną), a akcje pozwalające na modyfikacje informacji &#8211; roli &#8222;admins&#8221;.</p>
<p><strong>3.</strong> Rozszerzamy funkcjonalność <strong>MyRealm</strong></p>
<p>Czas na fragment kodu, który będzie odpowiadał za sprawdzanie, czy dany użytkownik posiada daną rolę. Wzbogacamy naszą klasę <strong>MyRealm</strong> w dwie dodatkowe (poza <strong>authenticate()</strong>) metody:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">def</span> hasRole<span style="color: #66cc66;">&#40;</span>principal, roleName<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">def</span> criteria <span style="color: #66cc66;">=</span> UserRoleRef.<span style="color: #006600;">createCriteria</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">def</span> roles <span style="color: #66cc66;">=</span> criteria.<span style="color: #006600;">list</span> <span style="color: #66cc66;">&#123;</span>
            role <span style="color: #66cc66;">&#123;</span>
                eq<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'name'</span>, roleName<span style="color: #66cc66;">&#41;</span>
            <span style="color: #66cc66;">&#125;</span>
            user <span style="color: #66cc66;">&#123;</span>
                eq<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'username'</span>, principal<span style="color: #66cc66;">&#41;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> roles.<span style="color: #663399;">size</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> hasAllRoles<span style="color: #66cc66;">&#40;</span>principal, roles<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">def</span> criteria <span style="color: #66cc66;">=</span> UserRoleRef.<span style="color: #006600;">createCriteria</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">def</span> r <span style="color: #66cc66;">=</span> criteria.<span style="color: #006600;">list</span> <span style="color: #66cc66;">&#123;</span>
            role <span style="color: #66cc66;">&#123;</span>
                <span style="color: #ff0000;">'in'</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'name'</span>, roles<span style="color: #66cc66;">&#41;</span>
            <span style="color: #66cc66;">&#125;</span>
            user <span style="color: #66cc66;">&#123;</span>
                eq<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'username'</span>, principal<span style="color: #66cc66;">&#41;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> r.<span style="color: #663399;">size</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">==</span> roles.<span style="color: #663399;">size</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Obie są dość proste &#8211; pierwsza sprawdza istnienie referencji użytkownik-rola dla zadanych parametrów, druga metoda robi to samo, ale ze zbiorem ról zadanych jako parametr.</p>
<p><strong>4.</strong> Dodajemy widok informujący o braku dostępu</p>
<p>Założenia mamy takie, żeby użytkownik bez dostępu do konkretnego zasobu został o tym poinformowany komunikatem. W tym celu wprowadzamy drobne usprawnienie do naszego kontrolera <strong>AuthController</strong>. Wprowadzamy domknięcie unauthorized, które będzie wykonane za każdym razem, gdy użytkownik spróbuje wykonać akcję, do której nie ma dostępu.</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">def</span> unauthorized <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>&#8230; oraz plik widoku dla takiej akcji (<strong>views/auth/unauthorized.gsp</strong>):</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ page <span style="color: #000066;">contentType</span>=<span style="color: #ff0000;">&quot;text/html;charset=UTF-8&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;Content-Type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Brak dostępu<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Dostęp zabroniony<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p><strong>5.</strong> Uaktualnianie menu</p>
<p>Nasze zabezpieczanie właściwie się zakończyło, jednak warto jeszcze zadbać o dodatkową rzecz. Jeśli pracujemy na widokach wygenerowanych przez Grails (np. za pomocą komendy <strong>grails generate-all &lt;klasa_dziedzinowa&gt;</strong>), to każdy z widoków wyposażony jest w przyciski/odnośniki kierujące do stron pozwalających na modyfikację/dodawanie/usuwanie rekordów, np. takich:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;nav&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;menuButton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;home&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;${createLinkTo(dir:'')}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Home<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;menuButton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>New Book<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Teoretycznie nic się nie stanie, jeśli tak to zostawimy, bo nawet kliknięcie na link <strong>New Book</strong> nie spowoduje wygenerowania formularza tworzenia nowej książki, tylko skieruje nas do strony z informacją o braku dostępu. Jednak&#8230; czego oczy nie widzą, tego sercu nie żal :) więc warto ukryć przed użytkownikiem te pozycje menu, które nie są mu potrzebne. Wykorzystamy więc znacznik <strong>jsec:hasRole</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;nav&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;menuButton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;home&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;${createLinkTo(dir:'')}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Home<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsec:hasRole</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;admins&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;menuButton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;g:link</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;create&quot;</span> <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;create&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>New Book<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/g:link<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsec:hasRole<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Od tej pory odnośnik <strong>New Book</strong> pokaże się tylko użytkownikom posiadającym rolę &#8222;admins&#8221;. Takie modyfikacje możemy wprowadzić we wszystkich widokach naszej aplikacji.</p>
<p>I to właściwie wszystko jeśli chodzi o kontrolę ról za pomocą JSecurity w Grails.</p>
<p>Dość ciekawą rzeczą, która warta jest poznania, ale nie opisałem jej tutaj (miało być prosto, więc nie chciałem dodatkowo komplikować) jest kontrola <em>uprawnień</em> za pomocą JSecurity. Wtyczka dla Grails pozwala na kontrolę uprawnień nie tylko na poziomie kontroler/akcja, ale też np. dostępu do plików, albo innych zasobów systemowych.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/03/22/uszczelnianie-aplikacji-z-grails-i-jsecurity-ciag-dalszy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Proste uwierzytelnianie w Grails z JSecurity</title>
		<link>http://xis.schowek.net/2009/03/15/proste-uwierzytelnianie-w-grails-z-jsecurity/</link>
		<comments>http://xis.schowek.net/2009/03/15/proste-uwierzytelnianie-w-grails-z-jsecurity/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 18:03:24 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[jsecurity]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=308</guid>
		<description><![CDATA[Pisałem ostatnio aplikację webową, która wymagała bardzo prostego uwierzytelniania. Grails &#8211; jak się okazuje &#8211; ma wtyczkę JSecurity, dzięki której można realizować proste uwierzytelnianie, ale i bardziej skomplikowane operacje autoryzacji. Wtyczka JSecurity dla Grails jest wyposażona w fajny QuickStart, który to już po instalacji pozwala na całkiem kompleksowe zabezpieczenie aplikacji. Mi jednak potrzebny był ekstremalnie [...]]]></description>
			<content:encoded><![CDATA[<p>Pisałem ostatnio aplikację webową, która wymagała bardzo prostego uwierzytelniania. Grails &#8211; jak się okazuje &#8211; <a href="http://www.grails.org/JSecurity+Plugin">ma wtyczkę JSecurity</a>, dzięki której można realizować proste uwierzytelnianie, ale i bardziej skomplikowane operacje autoryzacji. Wtyczka <a href="http://jsecurity.org">JSecurity</a> dla Grails jest wyposażona w fajny <a href="grails install-plugin jsecurity">QuickStart</a>, który to już po instalacji pozwala na całkiem kompleksowe zabezpieczenie aplikacji. Mi jednak potrzebny był ekstremalnie prosty mechanizm, na szczęście wtyczka zaoferowała coś w sam raz. </p>
<p>Poniższy wpis jest oparty właśnie na wspomnianym wyżej QuickStarcie, jednak został uproszczony i ograniczony jedynie do mechanizmu <s>autentykacji</s> <a href="http://pl.wikipedia.org/wiki/Uwierzytelnianie">uwierzytelnienia</a>, nie zaś <a href="http://pl.wikipedia.org/wiki/Autoryzacja_(informatyka)">autoryzacji</a> (kontroli dostępu do zasobów) użytkowników.</p>
<p>Dostęp do aplikacji z JSecurity jest realizowany za pomocą <em>przestrzeni</em> (<em>ang. realms</em>), można skonstruować mechanizm <s>autentykacji</s> uwierzytelnienia (i autoryzacji) na różne sposoby, np. za pomocą <a href="http://pl.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol">katalogów LDAP</a>, loginów systemowych, usług sieciowych itd. My wykorzystamy najbardziej tradycyjny mechanizm: sprawdzania użytkowników zapisanych w bazie danych. JSecurity realizuje mechanizm weryfikacji dostępu do poszczególnych zasobów systemu za pomocą przynależności użytkowników do ról, jednak mój przykład będzie znacznie prostszy &#8211; wystarczy, że użytkownik będzie istniał w bazie danych, a już będzie miał dostęp do zasobów systemu.</p>
<p>Oto jak wzbogacić naszą aplikację o wymaganie <s>autentykacji</s> uwierzytelniania  użytkowników, kompletnie nie zajmując się kwestiami autoryzacji dostępu do zasobów (wszyscy zalogowani użytkownicy mają dostęp):</p>
<p><strong>1</strong>. Instalujemy wtyczkę</p>
<p><strong>grails install-plugin jsecurity</strong></p>
<p><strong>2</strong>. Tworzymy klasę dziedzinową użytkownika:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> User <span style="color: #66cc66;">&#123;</span>
    <span style="color: #aaaadd; font-weight: bold;">String</span> username
    <span style="color: #aaaadd; font-weight: bold;">String</span> password
&nbsp;
    <span style="color: #000000; font-weight: bold;">static</span> mapping <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        table <span style="color: #ff0000;">&quot;users&quot;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #aaaadd; font-weight: bold;">String</span> toString<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        username
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Używam tutaj <a href="http://www.grails.org/GORM+-+Mapping+DSL">mapowania</a> na inną niż domyślna nazwę tabeli (domyślnie byłaby &#8222;user&#8221;, a ja dałem &#8222;users&#8221;) &#8211; taką kiedyś mi wpojono konwencję, by tabele miały nazwy w liczbie mnogiej. Z kolei metoda <strong>toString() </strong>przyda się nam nieco później.</p>
<p>Sama tabelka nie wystarczy, trzeba jeszcze użytkownika zapisać w bazie. Możemy to zrobić używając poniższego fragmentu kodu:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #66cc66;">&#40;</span>username: <span style="color: #ff0000;">&quot;jasiu&quot;</span>, password: <span style="color: #000000; font-weight: bold;">new</span> Sha1Hash<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;sekret&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toHex</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Jak widzisz, hasło jest kodowane za pomocą <a href="http://pl.wikipedia.org/wiki/SHA-1">algorytmu Sha1</a> (kodowanie to wspierane jest przez JSecurity), nie obędzie się więc bez:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> org.<span style="color: #006600;">jsecurity</span>.<span style="color: #006600;">crypto</span>.<span style="color: #006600;">hash</span>.<span style="color: #006600;">Sha1Hash</span></pre></div></div>

<p><strong>3</strong>.  Dodajemy do katalogu <strong>grails-app/conf/</strong> pliczek <strong>SecurityFilters.groovy</strong> o zawartości:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> SecurityFilters <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">def</span> filters <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        auth<span style="color: #66cc66;">&#40;</span>controller: <span style="color: #ff0000;">&quot;*&quot;</span>, action: <span style="color: #ff0000;">&quot;*&quot;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            before <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
                accessControl <span style="color: #66cc66;">&#123;</span> <span style="color: #000000; font-weight: bold;">true</span> <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Ten filtr spowoduje, że wszystkie żądania (gwiazdki oznaczają dowolny kontroler, i dowolną akcję) zostaną poddane działaniu naszego filtra, a ten, przed wykonaniem żądania, wymusi na nim sprawdzenie praw dostępu.</p>
<p><strong>4</strong>. W katalogu <strong>realms/</strong> tworzymy klasę <strong>MyDbRealm</strong>,  o postaci:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.AccountException</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.IncorrectCredentialsException</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.UnknownAccountException</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.SimpleAccount</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> MyDbRealm <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">static</span> authTokenClass <span style="color: #66cc66;">=</span> org.<span style="color: #006600;">jsecurity</span>.<span style="color: #006600;">authc</span>.<span style="color: #006600;">UsernamePasswordToken</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> authenticate<span style="color: #66cc66;">&#40;</span>authToken<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">def</span> username <span style="color: #66cc66;">=</span> authToken.<span style="color: #006600;">username</span><span style="color: #66cc66;">;</span>
        <span style="color: #000000; font-weight: bold;">def</span> user <span style="color: #66cc66;">=</span> User.<span style="color: #006600;">findByUsername</span><span style="color: #66cc66;">&#40;</span>username<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">!</span>user<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> UnknownAccountException<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Użytkownik ${username} nie istnieje w bazie danych&quot;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">def</span> account <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleAccount<span style="color: #66cc66;">&#40;</span>username, user.<span style="color: #006600;">password</span>, <span style="color: #ff0000;">&quot;MyDbRealm&quot;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">!</span>credentialMatcher.<span style="color: #006600;">doCredentialsMatch</span><span style="color: #66cc66;">&#40;</span>authToken, account<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            log.<span style="color: #006600;">info</span> <span style="color: #ff0000;">'Nieprawidłowe hasło dla użytkownika ${user.username}'</span>
            <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> IncorrectCredentialsException<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Nieprawidłowe hasło dla użytkownika ${user.username}&quot;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> user<span style="color: #66cc66;">;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p><strong>5</strong>. Tworzymy kontroler naszego mechanizmu uwierzytelniania <strong>AuthController</strong> (zapisujemy go oczywiście w katalogu <strong>controllers/</strong> naszej aplikacji):</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.AuthenticationException</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.authc.UsernamePasswordToken</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">org.jsecurity.SecurityUtils</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> AuthController <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">def</span> jsecSecurityManager
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> index <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span> redirect<span style="color: #66cc66;">&#40;</span>action: <span style="color: #ff0000;">'login'</span>, params: params<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> login <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #66cc66;">&#91;</span> username: params.<span style="color: #006600;">username</span>, targetUri: params.<span style="color: #006600;">targetUri</span> <span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> signIn <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">def</span> authToken <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> UsernamePasswordToken<span style="color: #66cc66;">&#40;</span>params.<span style="color: #006600;">username</span>, params.<span style="color: #006600;">password</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">try</span><span style="color: #66cc66;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006600;">jsecSecurityManager</span>.<span style="color: #006600;">login</span><span style="color: #66cc66;">&#40;</span>authToken<span style="color: #66cc66;">&#41;</span>
            <span style="color: #000000; font-weight: bold;">def</span> targetUri <span style="color: #66cc66;">=</span> params.<span style="color: #006600;">targetUri</span> <span style="color: #66cc66;">?</span>: <span style="color: #ff0000;">&quot;/&quot;</span>
            redirect<span style="color: #66cc66;">&#40;</span>uri: targetUri<span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #66cc66;">&#40;</span><span style="color: #aaaadd; font-weight: bold;">AuthenticationException</span> ex<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
            log.<span style="color: #006600;">info</span> <span style="color: #ff0000;">&quot;Błąd logowania użytkownika: '${params.username}'.&quot;</span>
            flash.<span style="color: #006600;">message</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;Logowanie nieudane&quot;</span>
&nbsp;
            <span style="color: #000000; font-weight: bold;">def</span> m <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span> username: params.<span style="color: #006600;">username</span> <span style="color: #66cc66;">&#93;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>params.<span style="color: #006600;">targetUri</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                m<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'targetUri'</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">=</span> params.<span style="color: #006600;">targetUri</span>
            <span style="color: #66cc66;">&#125;</span>
&nbsp;
            redirect<span style="color: #66cc66;">&#40;</span>action: <span style="color: #ff0000;">'login'</span>, params: m<span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">def</span> signOut <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
        SecurityUtils.<span style="color: #006600;">subject</span><span style="color: #66cc66;">?</span>.<span style="color: #006600;">logout</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
        redirect<span style="color: #66cc66;">&#40;</span>uri: <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p><strong>6</strong>. Tworzymy okienko logowania (<strong>views/auth/login.gs</strong>p):</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;Content-Type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;main&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Login<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;g:if</span> <span style="color: #000066;">test</span>=<span style="color: #ff0000;">&quot;${flash.message}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;message&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>${flash.message}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/g:if<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;g:form</span> <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;signIn&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;hidden&quot;</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;targetUri&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${targetUri}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;table<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tbody<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Username:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;username&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${username}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Password:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;password&quot;</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;password&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;td<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;submit&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;Zaloguj&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/td<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/tr<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/tbody<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/table<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/g:form<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p><strong>7</strong>. Modyfikujemy nasz główny <i>layout</i> tak, by pokazał czy i jako kto jesteśmy zalogowani:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsec:isLoggedIn<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Witaj <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsec:principal</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>! (<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;g:link</span> <span style="color: #000066;">controller</span>=<span style="color: #ff0000;">&quot;auth&quot;</span> <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;signOut&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Wyloguj<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/g:link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>)<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsec:isLoggedIn<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>I tu właśnie przydała nam się metoda <strong>toString()</strong> klasy <strong>User</strong>, albowiem znacznik <strong>jsec:principial</strong> zwróci nam właśnie wartość obiektu, który przedstawia zalogowanego aktualnie użytkownika (to, co zwróciła metoda <strong>authenticate()</strong> klasy <strong>MyDbRealm</strong>), a ten reprezentowany jest właśnie przez <strong>toString()</strong>.<br />
Tag <strong>jsec:isLoggedIn</strong> wraz z zawartością umieszczamy np. nad użyciem znacznika  <strong>g:layoutBody</strong>. Dla chcących potestować inne tagi dostarczane przez wtyczkę polecam <a href="http://www.grails.org/JSecurity+Plugin+-+Quick+Start#GSP%20tags">lekturę ich listy</a>.</p>
<p>Gotowe, aplikacja zabezpieczona, a my możemy spać spokojnie :)</p>
<p>I na koniec, dwa linki, jako uzupełnienie tematu zabezpieczania aplikacji Grails z JSecurity: </p>
<ul>
<li><a href="http://tramuntanal.wikidot.com/jsecurityplugin">http://tramuntanal.wikidot.com/jsecurityplugin</a></li>
<li><a href="http://asrijaffar.blogspot.com/2008/08/grails-jsecurity-plugin.html">http://asrijaffar.blogspot.com/2008/08/grails-jsecurity-plugin.html</a></li>
<ul>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/03/15/proste-uwierzytelnianie-w-grails-z-jsecurity/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Upiększanie JTable</title>
		<link>http://xis.schowek.net/2009/03/11/upiekszanie-jtable/</link>
		<comments>http://xis.schowek.net/2009/03/11/upiekszanie-jtable/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 11:15:32 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jtable]]></category>
		<category><![CDATA[swing]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=289</guid>
		<description><![CDATA[Przy okazji moich zabaw ze Swingiem &#8211; krótko o tym jak ulepszyć JTable. Mamy sobie JTable taką: A będziemy chcieli taką: Wzbogacimy więc naszą tabelkę o bardzo ładne oznaczenie numerów wierszy, oraz kolorowanie co drugiego rekordu. Zabieg pierwszy: kolorowanie co drugiego wiersza Aby używać warunkowego kolorowania wierszy, musimy wskazać naszej tabelce, by wykorzystała obiekt klasy [...]]]></description>
			<content:encoded><![CDATA[<p>Przy okazji moich zabaw ze Swingiem &#8211; krótko o tym jak ulepszyć <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JTable.html">JTable</a>.</p>
<p>Mamy sobie JTable taką:</p>
<p><img class="aligncenter size-full wp-image-290" title="przed" src="http://xis.schowek.net/wp-content/uploads/2009/03/przed.png" alt="przed" width="491" height="308" /></p>
<p>A będziemy chcieli taką:</p>
<p><img class="aligncenter size-full wp-image-294" title="po1" src="http://xis.schowek.net/wp-content/uploads/2009/03/po1.png" alt="po1" width="554" height="393" /></p>
<p>Wzbogacimy więc naszą tabelkę o bardzo ładne oznaczenie numerów wierszy, oraz kolorowanie co drugiego rekordu.</p>
<p><strong>Zabieg pierwszy: kolorowanie co drugiego wiersza</strong></p>
<p>Aby używać warunkowego kolorowania wierszy, musimy wskazać naszej tabelce, by wykorzystała obiekt klasy pochodnej od <a href="http://java.sun.com/javase/6/docs/api/javax/swing/table/DefaultTableCellRenderer.html">DefaultTableCellRenderer</a>, np. takiej:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> ColorCellRenderer <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">DefaultTableCellRenderer</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Component</span> getTableCellRendererComponent<span style="color: #009900;">&#40;</span> <span style="color: #003399;">JTable</span> table, <span style="color: #003399;">Object</span> val, <span style="color: #000066; font-weight: bold;">boolean</span> selected, <span style="color: #000066; font-weight: bold;">boolean</span> focused, <span style="color: #000066; font-weight: bold;">int</span> row, <span style="color: #000066; font-weight: bold;">int</span> col <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">Component</span> comp <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">getTableCellRendererComponent</span><span style="color: #009900;">&#40;</span> table, val, selected, focused, row, col <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> selected <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span> row <span style="color: #339933;">%</span> <span style="color: #cc66cc;">2</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                comp.<span style="color: #006633;">setBackground</span><span style="color: #009900;">&#40;</span> color <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
            <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                comp.<span style="color: #006633;">setBackground</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> comp<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><strong>Zabieg drugi: numeracja wierszy</strong></p>
<p>Na forum Suna znalazłem b. stary, ale nadal ciekawy <a href="http://forums.sun.com/thread.jspa?messageID=3746961#3746961">przykład rozwiązania tego problemu</a>. Budujemy klasę <strong>LineNumberTable</strong>, która dziedziczy po JTable:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> LineNumberTable <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">JTable</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">JTable</span> mainTable<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> LineNumberTable<span style="color: #009900;">&#40;</span> <span style="color: #003399;">JTable</span> table <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        mainTable <span style="color: #339933;">=</span> table<span style="color: #339933;">;</span>
        setAutoCreateColumnsFromModel<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setModel<span style="color: #009900;">&#40;</span> mainTable.<span style="color: #006633;">getModel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setSelectionModel<span style="color: #009900;">&#40;</span> mainTable.<span style="color: #006633;">getSelectionModel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setAutoscrolls<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        addColumn<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">TableColumn</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        getColumnModel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getColumn</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setCellRenderer</span><span style="color: #009900;">&#40;</span> mainTable.<span style="color: #006633;">getTableHeader</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getDefaultRenderer</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        getColumnModel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getColumn</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setPreferredWidth</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">30</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setPreferredScrollableViewportSize<span style="color: #009900;">&#40;</span> getPreferredSize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> isCellEditable<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">int</span> row, <span style="color: #000066; font-weight: bold;">int</span> column <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> getValueAt<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">int</span> row, <span style="color: #000066; font-weight: bold;">int</span> column <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Integer</span><span style="color: #009900;">&#40;</span> row <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">int</span> getRowHeight<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">int</span> row <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> mainTable.<span style="color: #006633;">getRowHeight</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>OK, teraz wystarczy wykorzystać utworzone klasy w naszej JTable:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> MyPanel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        initComponents<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// wskazujemy nowy renderer, dla obiektów wszystkich typów naszej tabelki</span>
        jTable1.<span style="color: #006633;">setDefaultRenderer</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">Object</span>.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #000000; font-weight: bold;">new</span> ColorCellRenderer<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// scrollPane, którym mamy osadzoną tabelę dekorujemy oznaczeniem numerów wierszy</span>
        jScrollPane1.<span style="color: #006633;">setRowHeaderView</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> LineNumberTable<span style="color: #009900;">&#40;</span> jTable1 <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Gotowe. Prawda, że ładniej?</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/03/11/upiekszanie-jtable/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>NetBeans i ujednolicanie JDialog</title>
		<link>http://xis.schowek.net/2009/03/08/netbeans-i-ujednolicanie-jdialog/</link>
		<comments>http://xis.schowek.net/2009/03/08/netbeans-i-ujednolicanie-jdialog/#comments</comments>
		<pubDate>Sun, 08 Mar 2009 11:29:14 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jdialog]]></category>
		<category><![CDATA[netbeans]]></category>
		<category><![CDATA[swing]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=242</guid>
		<description><![CDATA[Miałem niedawno okazję dłużej popracować nad projektami Javy w NetBeans 6.5 (wcześniej poważniej NetBeans używałem tylko do Grails). Środowisko to nie było dotychczas moim ulubionym, głównie ze względu na wydajność, co do której można mieć spore zastrzerzenia, jednak zauważyłem, że ma ono również mnóstwo zalet. Pierwszą jaką dostrzegłem jest to, że projekty generowane przez to [...]]]></description>
			<content:encoded><![CDATA[<p>Miałem niedawno okazję dłużej popracować nad projektami Javy w <a href="http://www.netbeans.org/">NetBeans 6.5</a> (wcześniej poważniej NetBeans używałem tylko do <a href="http://www.grails.org/">Grails</a>). Środowisko to nie było dotychczas moim ulubionym, głównie ze względu na wydajność, co do której można mieć spore zastrzerzenia, jednak zauważyłem, że ma ono również mnóstwo zalet. Pierwszą jaką dostrzegłem jest to, że projekty generowane przez to <em>IDE</em> są naprawdę ładnie utworzone, wykorzystują standardowe narzędzia Javy, takie jak np. <a href="http://www.ant.apache.org/">Ant</a> i nie uzależniają użytkownika od używania &#8222;jedynego i właściwego&#8221; IDE. NetBeans może zauroczyć również stopniem dopracowania swoich elementów &#8211; jak już coś wspiera, to wspiera naprawdę dobrze. Przykładem tu może być sposób, w jaki można za pomocą tego środowiska utworzyć i zarządzać aplkacjami wykorzystującymi <em>Web Services</em> w aplikacji &#8211; zarówno klientem, jak i usługą wykorzystującącymi <em>API</em> <a href="http://en.wikipedia.org/wiki/JAX-WS">JAX-WS</a>. Kolejny (lecz na pewno nie ostatni) plus należy się NetBeans za właściwie bezkonkurencyjny <em>edytor wizualny</em> aplikacji wykorzystujących <a href="http://pl.wikipedia.org/wiki/Swing_(Java)">Swing</a>.</p>
<p>I o Swingu właśnie będzie ten wpis (nieco przydługi, ostrzegam).</p>
<p>Nie do końca podoba mi się domyślna filozofia <em>okien dialogowych</em> w Javie. Np. rozmiar &#8211; niby można zmieniać rozmiar &#8222;świeżo&#8221; utworzonego okienka dialogowego rozciągając je, ale menadżery okien nie pozwalają na jego maksymalizację (brakuje bowiem przycisku maksymalizacji). Wiem, że takie jest założenie okienek dialogowych, ale wyczuwam tu pewną niekonsekwencję. Ponadto &#8222;goły&#8221; <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JDialog.html">JDialog</a> jest praktycznie pozbawiony funkcjonalności, np. brakuje mu domyślnych zachowań takich jak potwierdzanie i anulowanie, reakcję na przycisk <em>Escape</em> i <em>Enter</em> &#8211; te braki sprawiają, że każda implementacja okienka dialogowego musi być poprzedzona żmudnym wykonywaniem tych banalnych czynności.</p>
<p>Postanowiłem więc wykonać coś na wzór <em>bazy</em> dla okna dialogowego, która to baza będzie wyposażona we wszystkie cechy, które wg mnie posiadać powinna każda implementacja JDialog. W takiej bazie będę umieszczał różne komponenty &#8211; w zależności od tego, jakiego dialogu potrzebuję.</p>
<p><img class="size-full wp-image-243" style="margin: 0; margin-left: -25px;" title="szkic" src="http://xis.schowek.net/wp-content/uploads/2009/03/szkic.png" alt="szkic" width="689" height="440" /></p>
<p>Chcę uzyskać bazę dla dialogu, w której będę umieszczał przeróżne panele &#8211; począwszy od prostych, informacyjnych (wtedy taki dialog przypominałby funkconalnością <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JOptionPane.html">JOptionPane</a>), skończywszy na całkiem zaawansowanych funkcjonalnie formularzach edycji wykorzystujących panele, które przygotuję sobie osobno (dzięki temu będę mógł wykorzystać panele także w innych sytuacjach). Wszystkie jednak dialogi cechować się mają wspólnymi właściwościami: dialog można zatwierdzić (<em>submit</em>), albo odrzucić (<em>cancel</em>). Wciśnięcie <em>Escape</em> na aktywnym oknie powoduje jego zamknięcie (funkcjonalność identyczna do wciśnięcia przycisku <em>Anuluj</em>), a <em>Enter</em> &#8211; zatwierdzenie (kliknięcie <em>OK</em>).</p>
<p>W tym celu zbudowałem JDialog w NetBeans wybierając z menu projektu <strong>New</strong>-&gt;<strong>JDialog Form</strong> i nazwałem go <strong>DialogBase</strong>. W edytorze wizualnym umieściłem dwa przyciski (nazwałem je <strong>jBtnOK</strong> i <strong>jBtnCancel</strong>), oraz jeden <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JPanel.html">JPane</a>l (<strong>jPanelMain</strong>), z ustawionym layoutem <a href="http://java.sun.com/javase/6/docs/api/java/awt/BorderLayout.html">BorderLayout</a> &#8211; w tym panelu będę umieszczał przeróżne panele &#8222;implementacyjne&#8221; &#8211; w zależności od przeznaczenia mojego dialogu.</p>
<p>Na początek, domyślny konstruktor i obsługa własności <strong>panel</strong> (czyli obiekt panelu, który umieszczamy w oknie):</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">JPanel</span> panel<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> DialogBase<span style="color: #009900;">&#40;</span><span style="color: #003399;">JPanel</span> panel<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">null</span>, <span style="color: #000066; font-weight: bold;">true</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setLocationRelativeTo<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        setPanel<span style="color: #009900;">&#40;</span>panel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> setPanel<span style="color: #009900;">&#40;</span><span style="color: #003399;">JPanel</span> panel<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">panel</span> <span style="color: #339933;">=</span> panel<span style="color: #339933;">;</span>
        jPanelMain.<span style="color: #006633;">removeAll</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        jPanelMain.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span> panel, <span style="color: #003399;">BorderLayout</span>.<span style="color: #006633;">CENTER</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        panel.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">true</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399;">Dimension</span> d <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Dimension</span><span style="color: #009900;">&#40;</span>panel.<span style="color: #006633;">getPreferredSize</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">setSize</span><span style="color: #009900;">&#40;</span> d.<span style="color: #006633;">width</span>, d.<span style="color: #006633;">height</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">70</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">JPanel</span> getPanel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> panel<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Metoda <strong>setPanel()</strong> ustawia własność <strong>panel</strong> oraz zajmuje się osadzeniem go w oknie dialogu i ustawieniem odpowiedniego rozmiaru okna (wysokość zwiększam o wielkość przycisków na dole okna).</p>
<p>Aby wiedzieć w jaki sposób moje okno dialogowe zostało zamknięte, wyposażam je we własność <strong>exitStatus</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> DLG_EXIT_CANCEL <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> DLG_EXIT_OK <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> exitStatus <span style="color: #339933;">=</span> DLG_EXIT_CANCEL<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// getter i setter</span></pre></div></div>

<p>Domyślne zamknięcie okna poskutkuje zapamiętaniem statusu &#8222;Cancel&#8221;.</p>
<p>Czas na obsługę klawisza <em>Escape</em> i <em>Enter</em>. Posiłkując się <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip72.html?page=1">ciekawym na ten temat artykułem</a>, wzbogaciłem mój <strong>DialogBase</strong> o następujący kod:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">JRootPane</span> createRootPane<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">JRootPane</span> theRootPane <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">JRootPane</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #003399;">KeyStroke</span> escStroke <span style="color: #339933;">=</span> <span style="color: #003399;">KeyStroke</span>.<span style="color: #006633;">getKeyStroke</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">KeyEvent</span>.<span style="color: #006633;">VK_ESCAPE</span>, <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        theRootPane.<span style="color: #006633;">registerKeyboardAction</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ActionListener</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> actionPerformed<span style="color: #009900;">&#40;</span> <span style="color: #003399;">ActionEvent</span> actionEvent <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                doCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>, escStroke, <span style="color: #003399;">JComponent</span>.<span style="color: #006633;">WHEN_IN_FOCUSED_WINDOW</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #003399;">KeyStroke</span> entStroke <span style="color: #339933;">=</span> <span style="color: #003399;">KeyStroke</span>.<span style="color: #006633;">getKeyStroke</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">KeyEvent</span>.<span style="color: #006633;">VK_ENTER</span>, <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        theRootPane.<span style="color: #006633;">registerKeyboardAction</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ActionListener</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> actionPerformed<span style="color: #009900;">&#40;</span> <span style="color: #003399;">ActionEvent</span> actionEvent <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                doSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>, entStroke, <span style="color: #003399;">JComponent</span>.<span style="color: #006633;">WHEN_IN_FOCUSED_WINDOW</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> theRootPane<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Jak widzisz, wykorzystuję tu tajemnicze metody <strong>doSubmit()</strong> i <strong>doCancel()</strong>. Co to za metody?</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> doSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> onSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            setExitStatus<span style="color: #009900;">&#40;</span> DLG_EXIT_OK <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            dispose<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> doCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> onCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            setExitStatus<span style="color: #009900;">&#40;</span> DLG_EXIT_CANCEL <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            dispose<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">boolean</span> onSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">boolean</span> onCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Obie metody działają dość podobnie: jeśli metoda <strong>onSubmit()</strong> (lub analogicznie <strong>onCancel()</strong>) zwróci <strong>true</strong>, ustawiamy odpowiedni <strong>exitStatus</strong> i zamykamy okno. Zarówno <strong>doSubmit()</strong> jak i <strong>doCancel()</strong> wiążę też za pomocą zdarzenia <a href="http://java.sun.com/javase/6/docs/api/java/awt/event/ActionEvent.html">ActionEvent</a> z przyciskami (wystarczy dwukrotnie kliknąć na przycisku w edytorze wizualnym i wyedytować wygenerowaną przez NetBeans pustą metodę):</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> jBtnCancelActionPerformed<span style="color: #009900;">&#40;</span>java.<span style="color: #006633;">awt</span>.<span style="color: #006633;">event</span>.<span style="color: #003399;">ActionEvent</span> evt<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        doCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> jBtnOKActionPerformed<span style="color: #009900;">&#40;</span>java.<span style="color: #006633;">awt</span>.<span style="color: #006633;">event</span>.<span style="color: #003399;">ActionEvent</span> evt<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        doSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>OK, ale po co nam te trywialne metody <strong>onSubmit()</strong> i <strong>onCancel()</strong>? Wykorzystamy je np. do walidacji w przyszłych implementacjach naszych okien dialogowych (jeśli zdecydujemy się na ich przesłonięcie, jeśli nie &#8211; niczego złego nie zrobią ;) ).</p>
<p>Wygląda na to, że nasza baza jest gotowa. Użyjmy jej więc na jakimś przykładzie &#8211; np. formularzu logowania.</p>
<p>W NetBeans, tworzymy nowy <strong>JPanel Form</strong>, nazywamy go <strong>PanelLogin</strong> i dodajemy odpowiednie elementy interfejsu użytkownika (jak na załączonym wyżej szkicu), oczywiście to ten panel będziemy osadzać w bazie dialogu, więc nie dodajemy już przycisków <em>OK</em> i <em>Anuluj</em>, bo nie musimy. Element <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JTextField.html">JTextField</a>, zawierający nazwę użytkownika nazywamy <strong>jTxtUsername</strong>, a <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JPasswordField.html">JPasswordField</a> (z hasłem) &#8211; <strong>jTxtPassword</strong>.<br />
Dodajemy dwie publiczne metody do pobrania wprowadzonych nazwy użytkownika i hasła:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getUsername<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> jTxtUsername.<span style="color: #006633;">getText</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>jTxtPassword.<span style="color: #006633;">getPassword</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>A teraz nasz dialog logowania.<br />
W NetBeans tworzę nową <span style="text-decoration: underline;">klasę Javy</span> (<strong>New</strong>-&gt;<strong>Java Class</strong>), a nie dialog(!) i nazywam ją <strong>DialogLogin</strong>. Nasza nowa klasa musi dziedziczyć po <strong>DialogBase</strong>. Ponadto, nasz dialog powinien zwracać obiekt użytkownika (jakiejś klasy np. <strong>User</strong>, której szczegóły nie są tu istotne) jeśli logowanie się powiedzie. W tym celu powołujemy własność <strong>returnValue</strong> (wraz z getterem i setterem). Przy okazji dodaję też licznik prób logowania &#8211; proste umożliwienie trzykrotnej pomyłki przy logowaniu.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DialogLogin <span style="color: #000000; font-weight: bold;">extends</span> DialogBase <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> User returnValue<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> tries <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> DialogLogin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> PanelLogin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Czas na obsługę logiki biznesowej naszego dialogu. Anulowanie dialogu zostawiamy bez zmian &#8211; po prostu zamykamy okno. Jednak musimy zaimplementować obsługę zatwierdzania formularza. W tym celu przesłaniamy naszą metodę <strong>onSubmit()</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">boolean</span> onSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        PanelLogin thePanel <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> PanelLogin <span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">getPanel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        User u <span style="color: #339933;">=</span> App.<span style="color: #006633;">login</span><span style="color: #009900;">&#40;</span> thePanel.<span style="color: #006633;">getUsername</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, thePanel.<span style="color: #006633;">getPassword</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> u <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">JOptionPane</span>.<span style="color: #006633;">showMessageDialog</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">this</span>, <span style="color: #0000ff;">&quot;Nie udało się zalogować&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>tries<span style="color: #339933;">&lt;=</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        returnValue <span style="color: #339933;">=</span> u<span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Jeśli <strong>App.login()</strong> (przyjmijmy, że ta metoda odpowiada za autoryzację aplikacji) zwróci <strong>null</strong>, to znaczy, ze nie zalogowaliśmy się do aplikacji &#8211; dialog nie zamknie się, ale pokaże nam info o nieprawidłowych parametrach logowania (i tak do momentu aż wartość <strong>tries</strong> osiągnie wartość mniejszą lub równą zeru). Jeśli użytkownik jest prawidłowy, dialog zamknie się ustawiwszy uprzednio własność <strong>returnValue</strong>.</p>
<p>Powinno działać. Sprawdźmy:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">UIManager</span>.<span style="color: #006633;">setLookAndFeel</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">UIManager</span>.<span style="color: #006633;">getSystemLookAndFeelClassName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">catch</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">Exception</span> ex <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>
&nbsp;
        DlgLogin dlg <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DlgLogin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        dlg.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">true</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Logowanie zakończone: &quot;</span><span style="color: #339933;">+</span>dlg.<span style="color: #006633;">getExitStatus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> dlg.<span style="color: #006633;">getExitStatus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> DialogBase.<span style="color: #006633;">DLG_EXIT_OK</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> dlg.<span style="color: #006633;">getReturnValue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;W porządku, użytkownik prawidłowy&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
            <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Brak dostępu!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Anulowano!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Voila!</p>
<p><em>We wpisie użyłem ikon <a href="http://kde-look.org/content/show.php/Free+Business+Icons?content=77050  ">Free Business Icons</a> opublikowanych na licencji <a href="http://creativecommons.org/licenses/by/3.0/deed.pl  ">Creative Commons</a> oraz <a href="http://www.famfamfam.com/lab/icons/silk/">Silk</a> na licencji <a href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html">LGPL</a>.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/03/08/netbeans-i-ujednolicanie-jdialog/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Grails &#8211; DataTable z filtrem i pagerem</title>
		<link>http://xis.schowek.net/2009/02/01/grails-datatable-z-filtrem-i-pagerem/</link>
		<comments>http://xis.schowek.net/2009/02/01/grails-datatable-z-filtrem-i-pagerem/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 12:00:19 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[datatable]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[yui]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=221</guid>
		<description><![CDATA[Mojej przygody z Grails ciąg dalszy. Zauważyłem, że framework ten posiada bardzo wiele fajnych wtyczek. Jedną z nich jest grails-ui, który korzystając z dobrodziejstw Yahoo! User Interface Library pozwala na wstawianie ciekawych komponentów na stronę za pomocą zaledwie jednego znacznika GSP. Jednym z takich komponentów jest DataTable, bazujący na yui:dataTable, pozwalający np. na pobieranie danych [...]]]></description>
			<content:encoded><![CDATA[<p>Mojej przygody z Grails ciąg dalszy. Zauważyłem, że framework ten posiada bardzo wiele <a href="http://grails.org/Plugins">fajnych wtyczek</a>. Jedną z nich jest <a href="http://grails.org/GrailsUI+Plugin">grails-ui</a>, który korzystając z dobrodziejstw <a href="http://developer.yahoo.com/yui/">Yahoo! User Interface Library</a> pozwala na wstawianie ciekawych komponentów na stronę za pomocą zaledwie jednego znacznika <a href="http://grails.org/GSP+Tag+Reference">GSP</a>. Jednym z takich komponentów jest <a href="http://weblog.dangertree.net/2008/11/02/using-grailsui-datatable-tag/">DataTable</a>, bazujący na <a href="http://developer.yahoo.com/yui/datatable/">yui:dataTable</a>, pozwalający np. na pobieranie danych za pomocą <a href="http://pl.wikipedia.org/wiki/AJAX">żądań asynchronicznych AJAX</a> w formacie <a href="http://json.org/">JSON</a> (lub <a href="http://pl.wikipedia.org/wiki/XML">XML</a>, wedle życzenia), dzielenie wyników na podstrony (<em>pager</em>), mechanizm skórek itd. Znacznik GSP <strong>gui:dataTable </strong> posiada wiele opcjonalnych atrybutów, którymi można skonfigurować naszą tabelę z danymi (ilość maksymalna wierszy na jednej podstronie, format danych, kolumny itd.). Mam jednak wrażenie, że autor wtyczki nie pomyślał o możliwości dołączenia do naszej tabeli filtrowania wyników. Owszem, w Sieci można znaleźć <a href="http://developer.yahoo.com/yui/examples/datatable/">przykłady filtrowania dla &#8216;gołego&#8217; yui:dataTable</a>, ale większość z nich, albo nie wspiera cięcia na podstrony, albo filtruje wyniki dopiero po stronie klienta (a z serwera pobiera pełną listę danych). Dla mnie to niestety za mało.</p>
<p>Oto przykład na to, jak korzystając ze znacznika GSP <strong>gui:dataTable </strong> zaimplementować dataTable, który daje się połączyć z prostym filtrem wyników.</p>
<p>Do przedstawienia przykładu wykorzystam dane dostępne na stronie z <a href="http://developer.yahoo.com/yui/examples/datatable/dt_xhrjson.html">przykładami użycia dataTable</a> w YUI.  Załóżmy więc, że mam bazę danych restauracji (pizzerii).</p>
<p><img class="aligncenter size-full wp-image-233" title="d12" src="http://xis.schowek.net/wp-content/uploads/2009/02/d12.jpg" alt="d12" width="640" height="422" /></p>
<p>Użyję więc klasy dziedzinowej (ang. <em>domain class</em>) <strong>Restaurant</strong> o postaci:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Restaurant <span style="color: #66cc66;">&#123;</span>
    <span style="color: #aaaadd; font-weight: bold;">String</span> title
    <span style="color: #aaaadd; font-weight: bold;">String</span> address
    <span style="color: #aaaadd; font-weight: bold;">String</span> city
    <span style="color: #aaaadd; font-weight: bold;">String</span> state
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Listę tę chcę mieć dostępną pod adresem <a href="http://localhost:8080/PagedDatatable/restaurant/list">http://localhost:8080/PagedDatatable/restaurant/list</a>, czyli potrzebny mi będzie kontroler <strong>RestaurantController</strong>, a w nim metoda <strong>list</strong>. W metodzie tej, kontroler nie ma zbyt wiele roboty &#8211; po prostu serwuje statyczną stronę, toteż jej postać jest taka:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">def</span> list <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Niezbyt skomplikowane, prawda? :) Pusta metoda sprawi, że kontroler od razu zabierze się za renderowanie wyniku, strony GSP, która wygląda tak:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;g:javascript</span> <span style="color: #000066;">library</span>=<span style="color: #ff0000;">&quot;yui&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;gui:resources</span> <span style="color: #000066;">components</span>=<span style="color: #ff0000;">&quot;['dataTable']&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;Content-Type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;main&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Restaurant List<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;yui-skin-sam&quot;</span> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">&quot;width: 600px;&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;label</span> <span style="color: #000066;">for</span>=<span style="color: #ff0000;">&quot;fltr[title]&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Title:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/label<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;fltr[title]&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;label</span> <span style="color: #000066;">for</span>=<span style="color: #ff0000;">&quot;fltr[city]&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>City:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/label<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;fltr[city]&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;button</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;filterButton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Filter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/button<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;br</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;gui:dataTable</span></span>
<span style="color: #009900;">        <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;myDataTable&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">controller</span>=<span style="color: #ff0000;">&quot;restaurant&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;listAsJSON&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">rowsPerPage</span>=<span style="color: #ff0000;">&quot;15&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">sortedBy</span>=<span style="color: #ff0000;">&quot;title&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">columnDefs</span>=<span style="color: #ff0000;">&quot;[</span>
<span style="color: #009900;">        [key:'title', label:'Title'],</span>
<span style="color: #009900;">        [key:'address', label: 'Address'],</span>
<span style="color: #009900;">        [key:'city', label: 'City'],</span>
<span style="color: #009900;">        [key:'state', label: 'State']</span>
<span style="color: #009900;">        ]&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      YAHOO.util.Event.onDOMReady(function () {
&nbsp;
        updateFilter  = function () {
          GRAILSUI.myDataTable.customQueryString =
            &quot;title=&quot;+YAHOO.util.Dom.get(&quot;fltr[title]&quot;).value+&quot;<span style="color: #ddbb00;">&amp;&quot;+</span>
<span style="color: #ddbb00;">            &quot;city=&quot;+YAHOO.util.Dom.get(&quot;fltr[city]&quot;).value;</span>
&nbsp;
          var state = GRAILSUI.myDataTable.getState();
          // gui:dataTable odwołuje się do własności sorting obiektu state,
          // podczas gdy yui oferuje jedynie własność sortedBy (czyżby bug?)
          // kopiujemy własność, by uniknąć błędu
          state.sorting = state.sortedBy;
          // reset pagera, zawsze po filtrowaniu wracamy do pierwszej strony
          state.pagination.recordOffset = 0;
          query = GRAILSUI.myDataTable.buildQueryString(state);
&nbsp;
          GRAILSUI.myDataTable.getDataSource().sendRequest(query,{
            success : GRAILSUI.myDataTable.onDataReturnReplaceRows,
            failure : GRAILSUI.myDataTable.onDataReturnReplaceRows,
            scope   : GRAILSUI.myDataTable,
            argument: state
          });
        };
&nbsp;
        YAHOO.util.Event.on('filterButton','click',function (e) {
          updateFilter();
        });
      });
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Na początku strony, deklarujemy użycie wtyczki YUI! oraz komponentu dataTable &#8211; w ten sposób Grails zadba o to, by nasza strona została wyposażona w linki do odpowiednich skryptów i arkuszy stylów. W znaczniku  używam opcjonalnego atrybutu <strong>id</strong>, jest to spowodowane faktem, że będę się odwoływał do naszej tabeli i muszę wiedzieć jak. Gdybym nie użył id, dostałbym tabelę z unikalnym, losowym identyfikatorem. Nasza tabela wywołuje asynchronicznie metodę <strong>listAsJSON</strong> kontrolera <strong>RestaurantController</strong> (o niej za chwilę). Ważne jest, żeby w zdarzeniu <strong>onDOMReady</strong> powiązać kliknięcie w przycisk <strong>Filter</strong> z funkcją <strong>updateFilter()</strong>, w której konstruujemy parametry żądania i wstawiamy je do własności <strong>customQueryString</strong> naszej tabeli. Następnie obchodzimy jeden bug(?) <strong>gui:dataTable</strong>, resetujemy pager (na wypadek, gdybyśmy załadowali wynik z mniejszą ilością podstron niż obecna) i przeładowujemy naszą tabelę.</p>
<p>Gotowe :)</p>
<p>Na koniec tylko metoda <strong>listAsJSON</strong> naszego kontrolera:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">def</span> listAsJSON <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">def</span> pagingConfig <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span>
            <span style="color: #663399;">max</span>: params.<span style="color: #663399;">max</span> <span style="color: #66cc66;">?</span>: <span style="color: #cc66cc;">15</span>,
            offset: params.<span style="color: #006600;">offset</span> <span style="color: #66cc66;">?</span>: <span style="color: #cc66cc;">0</span>,
            <span style="color: #663399;">sort</span>: params.<span style="color: #663399;">sort</span> <span style="color: #66cc66;">?</span>: <span style="color: #ff0000;">'title'</span>,
            order: params.<span style="color: #006600;">order</span> <span style="color: #66cc66;">?</span>: <span style="color: #ff0000;">'asc'</span>
        <span style="color: #66cc66;">&#93;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">def</span> resultFilter <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
            or <span style="color: #66cc66;">&#123;</span>
                <span style="color: #b1b100;">if</span><span style="color: #66cc66;">&#40;</span>params.<span style="color: #006600;">title</span> <span style="color: #66cc66;">&amp;&amp;</span> params.<span style="color: #006600;">title</span> <span style="color: #66cc66;">!=</span> <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
                    like<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;title&quot;</span>, <span style="color: #ff0000;">&quot;${params.title}%&quot;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#125;</span>
                <span style="color: #b1b100;">if</span><span style="color: #66cc66;">&#40;</span>params.<span style="color: #006600;">city</span> <span style="color: #66cc66;">&amp;&amp;</span> params.<span style="color: #006600;">city</span> <span style="color: #66cc66;">!=</span> <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
                    like<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;city&quot;</span>, <span style="color: #ff0000;">&quot;${params.city}%&quot;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">def</span> c <span style="color: #66cc66;">=</span> Restaurant.<span style="color: #006600;">createCriteria</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">def</span> list <span style="color: #66cc66;">=</span> c.<span style="color: #006600;">list</span><span style="color: #66cc66;">&#40;</span>pagingConfig, resultFilter<span style="color: #66cc66;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">def</span> totalRec <span style="color: #66cc66;">=</span> list.<span style="color: #006600;">totalCount</span>
&nbsp;
        response.<span style="color: #006600;">setHeader</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Cache-Control&quot;</span>, <span style="color: #ff0000;">&quot;no-store&quot;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">def</span> data <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span>
            totalRecords: totalRec,
            results: list
        <span style="color: #66cc66;">&#93;</span>
        render data <span style="color: #000000; font-weight: bold;">as</span> JSON
    <span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Korzystamy tu z dobrodziejstw dwóch ciekawych możliwości oferowanych przez Grails. Pierwszą z nich są <strong>Criteria</strong>, pozwalające na budowanie filtrów naszego zapytania (za pomocą domknięć mechanizm ten staje się jeszcze atrakcyjniejszy niż jego pierwowzór pochodzący z Hibernate). Każda klasa dziedzinowa posiada możliwość stworzenia obiektu klasy Criteria za pomocą metody <strong>createCriteria()</strong>. Drugą ciekawostką jest <em>konwerter</em> JSON, ładowany za pomocą importu:</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> grails.<span style="color: #006600;">converters</span>.<span style="color: #006600;">JSON</span></pre></div></div>

<p>Konwerter ten, w locie, zamieni naszą mapę wyników na format JSON, zrozumiały dla naszej tabeli.</p>
<p><img class="aligncenter size-full wp-image-234" title="d22" src="http://xis.schowek.net/wp-content/uploads/2009/02/d22.jpg" alt="d22" width="609" height="420" /></p>
<p>Gotowe. Miłego filtrowania :)</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/02/01/grails-datatable-z-filtrem-i-pagerem/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Zen Cart w zgodzie z WAMP</title>
		<link>http://xis.schowek.net/2009/01/06/zen-cart-w-zgodzie-z-wamp/</link>
		<comments>http://xis.schowek.net/2009/01/06/zen-cart-w-zgodzie-z-wamp/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 21:24:05 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Do zapamiętania]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wamp]]></category>
		<category><![CDATA[zen cart]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=174</guid>
		<description><![CDATA[Ostatnio miałem okazję wykonać kilka modyfikacji dla platformy sklepowej Zen Cart zainstalowanej na serwerze mojego klienta. Zen Cart to platforma sklepowa oparta o darmowy osCommerce. Istnieje dla niego dość sporo rozszerzeń i wtyczek, ale moje zlecenie było tak specyficzne, że niestety nie obyło się bez potrzeby modyfikacji kodu sklepu (czego, mówiąc szczerze, bardzo starałem się [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio miałem okazję wykonać kilka modyfikacji dla platformy sklepowej <a href="http://www.zencart.pl/">Zen Cart</a> zainstalowanej na serwerze mojego klienta. Zen Cart to platforma sklepowa oparta o darmowy <a href="http://pl.wikipedia.org/wiki/OsCommerce">osCommerce</a>. Istnieje dla niego dość sporo rozszerzeń i wtyczek, ale moje zlecenie było tak specyficzne, że niestety nie obyło się bez potrzeby modyfikacji kodu sklepu (czego, mówiąc szczerze, bardzo starałem się uniknąć).</p>
<p>Wersja produkcyjna sklepu działa pod kontrolą systemu <a href="http://pl.wikipedia.org/wiki/Unix">UNIX</a>&#8216;owego, a specyfika zlecenia polegała na tym, że musiałem dokonać kilku poważnych poprawek &#8211; co najważniejsze &#8211; działając na różnych platformach (czasem musiałem pracować na domowym Linuksie, czasem na Windows).</p>
<p>Przygotowanie środowiska roboczego pod Linuksem zajęło mi naprawdę niewiele czasu; szybko napisałem skrypty automatycznie pobierające bazę danych i synchronizujące pliki kodu z wersją produkcyjną. Gorzej, gdy zacząłem potrzebować możliwości modyfikacji kodu sklepu spod Windows. Muszę przyznać, że był to mój debiut w pisaniu czegokolwiek w php na tym systemie, ale w końcu postanowiłem dać mu szansę. Jako środowiska programistycznego użyłem <a href="http://www.aptana.com/">Aptana Studio</a> (choć mam wrażenie, że wystarczyłby sam <a href="http://www.eclipse.org/">Eclipse</a> z <a href="http://www.eclipse.org/pdt/">PDT</a>), a całość zamierzałem postawić na &#8211; znanym mi ze słyszenia &#8211; <a href="http://pl.wikipedia.org/wiki/WAMP">WAMP</a>ie. Instalacja WAMP odbyła się bardzo sprawnie, pierwsze <em>Hello World</em> &#8211; również bez niespodzianek. Problem jednak zaczął się po instalacji &#8211; a jakże &#8211; Zen Carta.</p>
<p>Pobrałem zrzut bazy danych i pliki z kodem sklepu i zainstalowałem je w WAMP wykorzystując do tego możliwość tworzenia aliasów.  Okazało się jednak, że instalacja ta nie działa, WAMP serwuje mi tylko komunikaty błędów, albo jakieś krzaki zamiast polskich znaków. Oto lista czynności, które musiałem wykonać, aby zacząć normalnie pracować nad zmianami dla klienta:</p>
<p><strong>Problem 1</strong> &#8211; <a href="http://www.apache.org/">Apache</a> częstuje mnie błędem <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_Error">500</a> (Internal Server Error) przy jakimkolwiek odwołaniu.</p>
<p>Problem ten spowodowany był wyłączoną domyślnie obsługą <a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html">modułu rewrite</a> przez WAMPowego Apacza. Pomogła zwykła edycja <strong>httpd.conf</strong> i odkomentowanie linijki:</p>
<pre>LoadModule rewrite_module modules/mod_rewrite.so</pre>
<p>(oczywiście po tym procesie należy wyedytować odpowiednio plik <strong>.htacces</strong> &#8211; zgodnie z potrzebami i ścieżkami)</p>
<p><strong>Problem 2</strong> &#8211; Kodowanie polskich znaków bazy danych</p>
<p>Zen Cart niespecjalnie zwraca uwagę na różne możliwości kodowania znaków diakrytycznych bazy danych &#8211; na serwerze produkcyjnym była jakaś domyślna konfiguracja i taką też wgrałem u siebie. Niestety, okazało się, że WAMPowe domyślne ustawienie kodowania UTF8 pozwala na wczytanie bazy bez problemów (wpisy są dobrze widoczne z poziomu <a href="http://www.phpmyadmin.net/home_page/index.php">PhpMyAdmina</a>), jednak sam sklep wyświetla znaki zapytania zamiast polskich literek.  Tu nie obyło się bez modyfikacji kodu Zen Carta i tak  w pliku <strong>/includes/init_includes/init_database.php</strong> dodałem na końcu pliku linijki:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> HTTP_SERVER <span style="color: #339933;">==</span> <span style="color: #0000ff;">'http://localhost'</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #000088;">$db</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Execute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SET NAMES 'latin2'  COLLATE 'latin2_general_ci'&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>i wreszcie zobaczyłem polskie znaki na moim <em>localhost</em>. Powyższy <em>ifcheck</em> wstawiłem po to, by system działał z innymi znakami tylko na konfiguracji roboczej &#8211; w wersji produkcyjnej niech zostanie bez zmian. Później i tak usunę te linijki, toteż opatrzyłem je łatwymi do odnalezienia komentarzami. Dodam, że Zen Cart jest tak napisany, że połączenie z bazą danych odbywa się w jeszcze kilku innych miejscach,  należy więc mieć na względzie potencjalną potrzebę dodania powyższych linijek do innych plików, zawierających linijkę:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$db</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>connect<span style="color: #009900;">&#40;</span> DB_SERVER<span style="color: #339933;">,</span> DB_SERVER_USERNAME<span style="color: #339933;">,</span> DB_SERVER_PASSWORD<span style="color: #339933;">,</span> DB_DATABASE<span style="color: #339933;">,</span> USE_PCONNECT<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><strong>Problem 3</strong> &#8211; Puste listy produktów</p>
<p>Kiedy już zażegnałem problemy &#8216;techniczne&#8217;, okazało się, że sklep działa, ale listy produktów są w nim puste. Nie dostawałem komunikatów błędów, ale mimo to strona główna zawierała jedynie boczne <em>sideboksy</em>, a w środku nic. Okazało się, że problemem tutaj był fakt, że domyślna konfiguracja php w WAMP ma wyłączoną opcję<strong> Short Tags</strong>, co powoduje, że wszelkie<em> template&#8217;y</em> zawierające znacznik otwarcia kodu php <strong>&lt;?</strong> zamiast <strong>&lt;?php</strong> nie były interpretowane przez parser php. Włączenie powyższej opcji w pliku <strong>php.ini</strong> spowodowało prawidłowe wyświetlanie produktów.</p>
<p>Po tych poprawkach i restarcie wszystkich usług WAMPa mogłem wreszcie zacząć prace nad sklepem. Wydaje mi się jednak, że &#8211; gdybym chciał oprzeć na takiej konfiguracji wersję produkcyją sklepu &#8211; musiałbym się jeszcze sporo natrudzić, by uznać to rozwiązanie za stabilne.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/01/06/zen-cart-w-zgodzie-z-wamp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java Server Faces i parametry GET</title>
		<link>http://xis.schowek.net/2008/11/08/java-server-faces-i-parametry-get/</link>
		<comments>http://xis.schowek.net/2008/11/08/java-server-faces-i-parametry-get/#comments</comments>
		<pubDate>Sat, 08 Nov 2008 16:22:09 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[EJB]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Java Server Faces]]></category>
		<category><![CDATA[JSF]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=50</guid>
		<description><![CDATA[Java Server Faces to całkiem ciekawy framework dla Javy. O jego zaletach dużo by pisać, toteż odsyłam w tym temacie do odpowiednich wpisów w Sieci. JSF ma jednak jedną wadę; dość słabo wspiera przesyłanie parametrów za pomocą metody GET protokołu HTTP. Oto krótki poradnik jak używać parametrów przekazanych za pomocą metody GET do strony obsługiwanej [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://java.sun.com/javaee/javaserverfaces/">Java Server Faces</a> to całkiem ciekawy framework dla Javy. O jego zaletach dużo by pisać, toteż odsyłam w tym temacie do odpowiednich wpisów w Sieci. JSF ma jednak jedną wadę; dość słabo wspiera przesyłanie parametrów za pomocą metody <a href="http://en.wikipedia.org/wiki/HTTP">GET protokołu HTTP</a>. Oto krótki poradnik jak używać parametrów przekazanych za pomocą metody GET do strony obsługiwanej przez Java Server Faces.</p>
<p>Załóżmy, że mamy listę pracowników, z poziomu której możemy podejrzeć konkretnego zatrudnionego. Do obsługi naszej miniaplikacji wykorzystamy zatem dwie  strony <code>employee_list.jsp</code> i <code>employee.jsp</code>. Przyjmijmy także, że chcielibyśmy, aby dostęp do szczegółów dot. pracownika możliwy był po wprowadzeniu adresu np. <a href="http://localhost:8080/company/employee.jsf?e=10">http://localhost:8080/company/employee.jsf?e=10</a>.  Naszą aplikację zasili ziarno zarządzane (<em>managed bean</em>) <code>CompanyController</code>, którą wyposażamy we własność <code>selectedEmployeeId</code> i własność <code>selectedEmployee</code> zawierającą obiekt wskazanego pracownika:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">net.schowek.jsf.ui</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CompanyController
<span style="color: #009900;">&#123;</span>
    @EJB
    CompanyServiceLocal companyService<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> DataModel   empDataModel<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Long</span>        selectedEmployeeId<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> Employee    selectedEmployee<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> DataModel getAllEmployees<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        empDataModel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ListDataModel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        empDataModel.<span style="color: #006633;">setWrappedData</span><span style="color: #009900;">&#40;</span> companyService.<span style="color: #006633;">findAll</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> empDataModel<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Employee getSelectedEmployee<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>selectedEmployee <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            selectedEmployee <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Employee<span style="color: #009900;">&#41;</span> companyService.<span style="color: #006633;">findById</span><span style="color: #009900;">&#40;</span> selectedEmployeeId <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> selectedEmployee<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setSelectedEmployee<span style="color: #009900;">&#40;</span> Employee selectedEmployee <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">selectedEmployee</span> <span style="color: #339933;">=</span> selectedEmployee<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Long</span> getSelectedEmployeeId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> selectedEmployeeId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setSelectedEmployeeId<span style="color: #009900;">&#40;</span> <span style="color: #003399;">Long</span> selectedEmployeeId <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">selectedEmployeeId</span> <span style="color: #339933;">=</span> selectedEmployeeId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Wygląda to więc dość standardowo, tylko posługujemy sie tą tajemniczą własnością <code>selectedEmployeeId</code>. I skąd nasz <code>CompanyController</code> ma wiedzieć, że w tejże własności ma znaleźć się parametr przekazany w metodzie GET pod zmienną &#8216;<code>e</code>&#8216;?</p>
<p>Zdefiniujemy to pliku <code>faces-config.xml</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>managed-bean<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-name<span style="color: #ddbb00;">&amp;gt;</span>company<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-name<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-class<span style="color: #ddbb00;">&amp;gt;</span>net.schowek.jsf.ui.CompanyController<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-class<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-scope<span style="color: #ddbb00;">&amp;gt;</span>request<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-scope<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-property<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>property-name<span style="color: #ddbb00;">&amp;gt;</span>selectedEmployeeId<span style="color: #ddbb00;">&amp;lt;</span>/property-name<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>value<span style="color: #ddbb00;">&amp;gt;</span>#{param.e}<span style="color: #ddbb00;">&amp;lt;</span>/value<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>/managed-property<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>Oraz nasze pliczki stron:</p>
<p>Lista pracowników:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>!-- employee_list.jsp --<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>f:view<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>h:form<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>h:datatable var=&quot;employee&quot; value=&quot;#{company.allEmployees}&quot;<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>h:column<span style="color: #ddbb00;">&amp;gt;</span>
                <span style="color: #ddbb00;">&amp;lt;</span>h:outputtext value=&quot;#{employee.id}&quot; /<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>/h:column<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>h:column<span style="color: #ddbb00;">&amp;gt;</span>
                <span style="color: #ddbb00;">&amp;lt;</span>h:outputtext value=&quot;#{employee.name}&quot; /<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>/h:column<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>h:column<span style="color: #ddbb00;">&amp;gt;</span>
                <span style="color: #ddbb00;">&amp;lt;</span>h:outputlink value=&quot;employee.jsf&quot;<span style="color: #ddbb00;">&amp;gt;</span>
                    <span style="color: #ddbb00;">&amp;lt;</span>f:verbatim<span style="color: #ddbb00;">&amp;gt;</span>Szczegóły<span style="color: #ddbb00;">&amp;lt;</span>/f:verbatim<span style="color: #ddbb00;">&amp;gt;</span>
                    <span style="color: #ddbb00;">&amp;lt;</span>f:param value=&quot;#{employee.id}&quot; name=&quot;e&quot; /<span style="color: #ddbb00;">&amp;gt;</span>
                <span style="color: #ddbb00;">&amp;lt;</span>/h:outputlink<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>/h:column<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>/h:datatable<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>/h:form<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/f:view<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>&#8230;, karta pracownika&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>!-- employee.jsp --<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>f:view<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>h:form<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>h2<span style="color: #ddbb00;">&amp;gt;</span>Szczegóły pracownika #<span style="color: #ddbb00;">&amp;lt;</span>h:outputText value=&quot;#company.selectedEmployee.id&quot;/<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>/h2<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>div<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>span<span style="color: #ddbb00;">&amp;gt;</span>Imię i nazwisko:<span style="color: #ddbb00;">&amp;lt;</span>/span<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>span<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>h:outputText value=&quot;#company.selectedEmployee.name&quot;/<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>/span<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>/div<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>div<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>span<span style="color: #ddbb00;">&amp;gt;</span>Stanowisko:<span style="color: #ddbb00;">&amp;lt;</span>/span<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>span<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>h:outputText value=&quot;#company.selectedEmployee.position&quot;/<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>/span<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>/div<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>div<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>span<span style="color: #ddbb00;">&amp;gt;</span>Dodatkowe informacje:<span style="color: #ddbb00;">&amp;lt;</span>/span<span style="color: #ddbb00;">&amp;gt;</span>
            <span style="color: #ddbb00;">&amp;lt;</span>div<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>h:outputText value=&quot;#company.selectedEmployee.comments&quot;/<span style="color: #ddbb00;">&amp;gt;&amp;lt;</span>/div<span style="color: #ddbb00;">&amp;gt;</span>
        <span style="color: #ddbb00;">&amp;lt;</span>/div<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>/h:form<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/f:view<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>Takie rozwiązanie ma jednak dość poważną wadę, bowiem wspiera jedynie ziarna zarządzane, których zasięg (<em>scope</em>) dotyczy żądania. Własności ziaren zarządzanych deklarowanych w pliku <code>faces-config.xml</code> muszą mieć czas życia co najmniej taki jak czas życia samego ziarna, toteż <code>#{param}</code>, który żyje tylko wraz z żądaniem ogranicza zasięg całego ziarna. Często jednak zdarza się, że potrzebujemy ziarna żyjącego przez całą sesję, wtedy nie możemy skorzystać z własności deklarowanej w <code>faces-config.xml</code>. Możemy jednak, zamiast oczekiwać wstrzyknięcia wartości naszej własności przez JSF, sami pobrać wartość parametru żądania.</p>
<p>W tym celu usuwamy z pliku <code>faces-config.xml</code> deklarację parametru pozostawiając:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>managed-bean<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-name<span style="color: #ddbb00;">&amp;gt;</span>company<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-name<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-class<span style="color: #ddbb00;">&amp;gt;</span>net.schowek.jsf.ui.CompanyController<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-class<span style="color: #ddbb00;">&amp;gt;</span>
    <span style="color: #ddbb00;">&amp;lt;</span>managed-bean-scope<span style="color: #ddbb00;">&amp;gt;</span>request<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean-scope<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/managed-bean<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>Modyfikujemy tez nasze ziarno usuwając własność <code>selectedEmployeeId</code> wraz z <em>getterem</em> i <em>setterem</em> i zmieniając metodę <code>getSelectedEmployee()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> Employee getSelectedEmployee<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  Map<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>String, String<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> reqParams <span style="color: #339933;">=</span> FacesContext.<span style="color: #006633;">getCurrentInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getExternalContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getRequestParameterMap</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #003399;">String</span> eId <span style="color: #339933;">=</span> reqParams.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;e&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #003399;">Long</span> selectedEmployeeId <span style="color: #339933;">=</span> <span style="color: #003399;">Long</span>.<span style="color: #006633;">parseLong</span><span style="color: #009900;">&#40;</span> eId <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>selectedEmployee <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    selectedEmployee <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Employee<span style="color: #009900;">&#41;</span> companyService.<span style="color: #006633;">findById</span><span style="color: #009900;">&#40;</span> selectedEmployeeId <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000000; font-weight: bold;">return</span> selectedEmployee<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Od tej pory ziarno o czasie życia sesji również potrafi obsługiwać parametry GET, a my możemy dodawać do zakładek odnośniki do kart konkretnych pracowników :)</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2008/11/08/java-server-faces-i-parametry-get/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Bałagan w mrowisku</title>
		<link>http://xis.schowek.net/2008/11/04/balagan-w-mrowisku/</link>
		<comments>http://xis.schowek.net/2008/11/04/balagan-w-mrowisku/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 08:54:24 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/2008/11/04/balagan-w-mrowisku/</guid>
		<description><![CDATA[Dość długo nic nie pisałem, szczerze mówiąc zastanawiałem się, czy nie przestać całkowicie (jak się okazuje, strasznie trudno pisać o tym, co możnaby w tym czasie robić ;) ), ale postanowiłem coś jednak naskrobać i dalej prowadzić ten swój zapiśnik. Nie będę chyba jednak publikował wpisów zbyt często, bo postanowiłem już całkowicie sprowadzić tego bloga [...]]]></description>
			<content:encoded><![CDATA[<p>Dość długo nic nie pisałem, szczerze mówiąc zastanawiałem się, czy nie przestać całkowicie (jak się okazuje, strasznie trudno pisać o tym, co możnaby w tym czasie robić ;) ), ale postanowiłem coś jednak naskrobać i dalej prowadzić ten swój zapiśnik. Nie będę chyba jednak publikował wpisów zbyt często, bo postanowiłem już całkowicie sprowadzić tego bloga do roli swego rodzaju notatnika zawierającego po prostu rzeczy do zapamiętania.</p>
<p>Dziś o pewnym narzędziu, z którym życie programisty <a href="http://pl.wikipedia.org/wiki/Java">Java</a> staje się łatwiejsze &#8211; <a href="http://ant.apache.org/">Ant</a>.</p>
<p>Ant to &#8211; jak pewnie każdy <em>Javowiec</em> wie &#8211; doskonałe narzędzie upraszczające nie tylko proces budowania projektów, ale pomagające zautomatyzować każdą rutynową operację. Wachlarz instrukcji, które potrafi on wykonać jest ogromny i stale się powiększa.</p>
<p>Ostatnio miałem okazję budować projekt, który zależał od kilku innych podprojektów, których z kolei wynikami były różne typy archiwów (<a href="http://pl.wikipedia.org/wiki/JAR_(format_pliku)">JAR</a>/<a href="http://en.wikipedia.org/wiki/WAR_file">WAR</a>). Całość (projekt główny) była pakietem <a href="http://en.wikipedia.org/wiki/Web_module#Modules">EAR</a> zawierającym wspomniane wcześniej archiwa. Z poziomu mojego ulubionego <a href="http://www.eclipse.org/">Eclipse</a> można oczywiście wyklikać eksport owych składników do projektu docelowego, ale wykonywanie tego przy każdej próbie sprawdzenia efektów swojej pracy było dość uciążliwe. Na szczęście Eclipse jest doskonale zintegrowany z Antem, toteż przygotowanie pliku budującego dla moich projektów trwało dosłownie chwilę. Ant dysponuje również instrukcją &#8216;ant&#8217; pozwalającą na wykonanie innego pliku budującego z poziomu pliku głównego. To idealne rozwiązanie dla mojej sytuacji z podprojektami.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>property name=&quot;ejbjar.dir&quot; value=&quot;${basedir}/../MyEJBModule&quot;/<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>property name=&quot;webmodule.dir&quot; value=&quot;${basedir}/../MyWEBModule&quot;/<span style="color: #ddbb00;">&amp;gt;</span>        
<span style="color: #ddbb00;">&amp;lt;</span>target name=&quot;preparecomponents&quot;<span style="color: #ddbb00;">&amp;gt;</span>
  <span style="color: #ddbb00;">&amp;lt;</span>ant antfile=&quot;build.xml&quot; dir=&quot;${ejbjar.dir}&quot;/<span style="color: #ddbb00;">&amp;gt;</span>
  <span style="color: #ddbb00;">&amp;lt;</span>ant antfile=&quot;build.xml&quot; dir=&quot;${webmodule.dir}&quot;/<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/target<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>Pojawił się jednak pewien problem, otóż tak wykonywane skrypty Ant&#8217;a posiadały dość dziwne własności (<em>properties</em>). Okazało się, że dziedziczą one po projekcie głównym i tak najczęściej używane przeze mnie własności jak np. <em>project.distname</em>, czy <em>basedir</em> miały wartości zdefiniowane w projekcie głównym, a nie te, których definicja występowała u nich samych, co oczywiście powodowało błędy przy budowaniu i ogólną porażkę. Rozwiązaniem może tu być zmiana nazw własności na unikalne dla każdego z projektów, ale to oczywiście nie jest najelegantsze rozwiązanie, pomijając już jego sensowność.</p>
<p>Na szczęście Ant zabezpiecza nas przed tym dodając atrybut <em>inheritall</em>, pozwalający na zbudowanie zupełnie nowego środowiska dla każdego poszczególnego skryptu wykonywanego z poziomu skryptu głównego.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #ddbb00;">&amp;lt;</span>target name=&quot;preparecomponents&quot;<span style="color: #ddbb00;">&amp;gt;</span>
  <span style="color: #ddbb00;">&amp;lt;</span>ant antfile=&quot;build.xml&quot; dir=&quot;${ejbjar.dir}&quot; inheritall=&quot;false&quot;/<span style="color: #ddbb00;">&amp;gt;</span>
  <span style="color: #ddbb00;">&amp;lt;</span>ant antfile=&quot;build.xml&quot; dir=&quot;${webmodule.dir}&quot; inheritall=&quot;false&quot;/<span style="color: #ddbb00;">&amp;gt;</span>
<span style="color: #ddbb00;">&amp;lt;</span>/target<span style="color: #ddbb00;">&amp;gt;</span></pre></div></div>

<p>W ten sposób każdy z komponentów zostanie zbudowany tak, jakbyśmy wykonali osobno każdy ze skryptów budowania. Warto zanotować, że w elemencie <em>ant</em> można zagnieżdżać elementy <em>property</em> i przekazywać je do wykonywanego skryptu, zatem komunikacja skryptu głównego z komponentami jest również możliwa.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2008/11/04/balagan-w-mrowisku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

