<?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</title>
	<atom:link href="http://xis.schowek.net/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.3.2</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> <span style="color: #993333; font-weight: bold;">COUNT</span><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    $1<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     $1<span style="color: #00AA00;">;</span>
            set  $path_info  $2<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>Zrób sobie przerwę</title>
		<link>http://xis.schowek.net/2009/02/22/zrob-sobie-przerwe/</link>
		<comments>http://xis.schowek.net/2009/02/22/zrob-sobie-przerwe/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 17:15:18 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Ogólnie]]></category>
		<category><![CDATA[narzędzia]]></category>
		<category><![CDATA[odpoczynek]]></category>
		<category><![CDATA[praca]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=239</guid>
		<description><![CDATA[Dość intensywnie ostatnio pracuję (dużo pracy, a do tego taka ilość ciekawych rzeczy dookoła, że nie sposób nie poświęcić na ich badanie wieczora lub dwóch), do pracy tej używam rzecz jasna komputera. Odbiło się to niestety negatywnie na moim samopoczuciu, możnaby rzec, ze dopadło mnie coś na wzór RSI, tyle że dotyczyło wzroku i bólów [...]]]></description>
			<content:encoded><![CDATA[<p>Dość intensywnie ostatnio pracuję (dużo pracy, a do tego taka ilość ciekawych rzeczy dookoła, że nie sposób nie poświęcić na ich badanie wieczora lub dwóch), do pracy tej używam rzecz jasna komputera. Odbiło się to niestety negatywnie na moim samopoczuciu, możnaby rzec, ze dopadło mnie coś na wzór <a href="http://pl.wikipedia.org/wiki/RSI_(choroby)">RSI</a>, tyle że dotyczyło wzroku i bólów głowy. Już tak mam, że kiedy &#8222;wkręcę&#8221; się w jakąś czynność, coś mnie zainteresuje, potrafię pracować bez przerw i kompletnie nie kontroluję tego ile czasu zajmuje mi praca. Skupiam się wtedy na wykonywanej czynności maksymalnie, zapominając o świecie poza nią. Postanowiłem więc coś w tej sprawie zrobić i &#8211; oprócz zdroworozsądkowego odstawienia na jakiś czas komputera &#8211; znaleźć narzędzie, które pozwoli mi nieco zadbać o swoje zdrowie w pracy z nim. Znalazłem dwa programy, ktore umożliwiają kontrolę nad przerwami.</p>
<p>Pierwszy z nich to <a href="http://themech.net/eyesrelax/">EyesRelax</a>. Programik ten umożliwia ustawienie odstępu czasowego między przerwami i &#8211; uruchomiony w tle &#8211; odlicza nam czas na do odpoczynku, gdy ten nadejdzie, EyesRelax zasłania ekran komputera białym tłem. Ciekawą jego funkcją jest <em>Parent Mode</em>, która pozwala na całkowite zablokowanie komputera na czas przerwy (odblokowanie może nastąpić dopiero po podaniu hasła). Programik ekstremalnie prosty, ale spełniający dokładnie swoje zadanie. Niestety jednak, nie do końca, bowiem jedna jego wada spowodowała, że zacząłem rozglądać się za innym rozwiązaniem. EyesRelax ma jakiś błąd, która sprawia, że białe plansze nie zawsze zasłaniają pulpit, często samoczynnie wędrują sobie w tło i &#8211; jeśli używa się zmaksymalizowanego okna jakiegoś programu &#8211; użytkownik nie ma pojęcia, że właśnie w tej chwili powinien zrobić przerwę. Ja niestety potrzebuję narzędzia, które &#8211; nawet brutalnie &#8211; wyrwie mnie z <em>amoku</em> programowania i każe odpocząć :) Dlatego zacząłem szukać dalej.</p>
<p>Znalazłem <a href="http://workrave.org/welcome/">WorkRave</a>. To narzędzie bardzo pozytywnie zaskoczyło mnie ilością możliwości konfiguracji, oraz samą koncepcją walki z RSI. Program ten oferuje trzy sposoby zabezpieczenia przed przepracowaniem &#8211; i wszystkie można stosować naraz:</p>
<ul>
<li>Mikroprzerwy &#8211; krótkie odpoczynki pozwalające &#8222;odetchnąć&#8221;, przede wszytskim oczom i szyi,</li>
<li>Odpoczynki &#8211; dłuższe przerwy na np. spacer, śniadanie, ćwiczenia, albo po prostu zrobienie sobie herbaty,</li>
<li>Kontrola całkowitego czasu pracy &#8211; skutecznie powstrzymuje przed niechcianymi nadgodzinami.</li>
</ul>
<p>Poza samym odliczaniem czasu, WorkRave mile zaskakuje możliwością dodania wstępnych &#8222;ostrzeżeń&#8221; o tym, że zbliża się przerwa, a także biblioteką porad dotyczących ćwiczeń (<a href="http://pl.wikipedia.org/wiki/Akomodacja_oka">akomodacji oczu</a>, mięśni szyi, rąk itd.) które możemy robić w trakcie odpoczynku &#8211; ilość proponowanych ćwiczeń jest całkiem spora, a same ich opisy dość szczegółowe (z obrazkami ;) ). Ponadto warto zauważyć, że program można przełączać w różne tryby pracy (Normalny, Cichy i Zawieszony), dzięki czemu nie jest on nachalny np. gdy oglądamy na komputerze film. Narzędzie to posiada też opcję pracy w sieci, ale nie udało mi się jej jeszcze przetestować.</p>
<p>Gorąco zachęcam do używania takich <em>kontrolerów czasu pracy</em>, niech najlepszym dowodem ich skuteczności będzie fakt, że skończyły się moje problemy z oczami i bólami głowy, ba &#8211; kiedy dokładnie stosuję się do zaleceń WorkRave, dzień w pracy mija mi tak, że wracam do domu w ogóle nie będąc zmęczonym!</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/02/22/zrob-sobie-przerwe/feed/</wfw:commentRss>
		<slash:comments>2</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>Grails i kompozytowe klucze w Hibernate</title>
		<link>http://xis.schowek.net/2009/01/24/grails-i-kompozytowe-klucze-w-hibernate/</link>
		<comments>http://xis.schowek.net/2009/01/24/grails-i-kompozytowe-klucze-w-hibernate/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 16:30:06 +0000</pubDate>
		<dc:creator>xis</dc:creator>
				<category><![CDATA[Do zapamiętania]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://xis.schowek.net/?p=202</guid>
		<description><![CDATA[Grails to bardzo ciekawy framework przygotowany dla języka Groovy. Od razu zdobył moją sympatię za to, że &#8211; nie tylko nazwą &#8211; przypomina architekturę Ruby on Rails, czy też Symfony dla PHP, realizując najważniejsze polityki nowoczesnych frameworków: Convention Over Configuration i Do Not Repeat Yourself. Zawsze ubolewałem (i w sumie nadal ubolewam) nad brakiem takiego [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://grails.org/">Grails</a> to bardzo ciekawy framework przygotowany dla języka <a href="http://groovy.codehaus.org/">Groovy</a>. Od razu zdobył moją sympatię za to, że &#8211; nie tylko nazwą &#8211; przypomina architekturę <a href="http://rubyonrails.org/">Ruby on Rails</a>, czy też <a href="http://www.symfony-project.org/">Symfony</a> dla <a href="http://php.net">PHP</a>, realizując najważniejsze polityki nowoczesnych frameworków: <a href="http://en.wikipedia.org/wiki/Convention_over_Configuration">Convention Over Configuration</a> i <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">Do Not Repeat Yourself</a>. Zawsze ubolewałem (i w sumie nadal ubolewam) nad brakiem takiego rozwiązania dla &#8216;czystej&#8217; Javy (może Ty znasz jakiś przykład?), dlatego tym chętniej zainteresowałem się tajnikami Grails.</p>
<p>Przyznam, że raczej sceptycznie reaguję na różne &#8216;liberalne&#8217; języki programowania, np. fakt, że jakąś operację można wykonać używając różnych konstrukcji języka (bo wg mnie zaciemnia to nieco obraz samego kodu i utrudnia jego pielęgnację), albo dynamiczcne typowanie (zawsze przeklinałem PHP za tę &#8216;przypadłość&#8217;), jednak dałem Groovy&#8217;emu szansę, za jego główną zaletę: pełną kompatybilność z Javą &#8211; Groovy jest de facto wykonywany przez maszynę wirtualną Javy, więc kompatybilność ta jest oczywista.</p>
<p>Umówmy się &#8211; należę do tych bardziej konserwatywnych programistów wierzących w &#8216;twardą&#8217; składnię, a w Groovy nie umiem (jeszcze) nic poza &#8222;Hello World&#8221;, toteż bardzo zależało mi na frameworku, w którym będę mógł wykorzystać już istniejące ziarenka Javy.  Samego Groovy&#8217;ego też chętnie zgłębię, ale najpierw chcę zobaczyć co mogę zrobić z Grailsami wykorzystując istniejący już kod Javy.</p>
<p>Grails &#8211; jak RoR, czy Symfony &#8211; posiada własny mechanizm <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">mapowania obiektowo-relacyjnego</a> (gdzieś tam głęboko napędzany przez <a href="http://www.hibernate.org/">Hibernate</a>), zwany <a href="http://grails.org/GORM">GORM</a>, pozwalający na mapowanie klas Groovy&#8217;ego z bazą danych. Ja jednak, przez założenie, chcę mapować ziarna encji Hibernate napisane w Javie. Grails pozwala na to bez problemów, kilka prostych czynności i już możemy wykorzystać przygotowane wcześniej encje w Grails.</p>
<p>No, może nie całkiem bez problemów.</p>
<p>Aby zmapować klasy encji wystarczy, zgodnie z <a href="http://grails.org/Hibernate+Integration">opisem na stronie Grails</a>, wyedytować plik <strong>DataSource.groovy</strong>, dodać mapowanie w <strong>hibernate.cfg.xml</strong> i wreszcie skopiować swoje klasy javy do katalogu <strong>src/java</strong>. Po wykonaniu tych czynności możemy już wygenerować na podstawie encji nowy kontroler i widok, wklepując w konsoli:</p>
<pre>grails generate-all pelna.nazwa.naszej.Klasy</pre>
<p>Grails wygeneruje dla nas wszystkie niezbędne klasy kontrolerów (w języku Groovy, rzecz jasna), elementy widoku (strony GSP), słowem mamy już cały <a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>.  Problem jednak pojawia się w przypadku, gdy nasza encja wyposażona jest w klucz złożony, a schemat naszej bazy danych &#8211; jak w moim przypadku &#8211;  nie może zostać zmodyfikowany, bo jest wykorzystywany przez inne programy.</p>
<p>Grails teoretycznie pozwoli na mapowanie takich encji, wygeneruje też dla nich kontrolery i pliki widoków, jednak nie bedą one działały. Rozważmy poniższy przypadek.</p>
<p>Mamy encję Produkt (mapowaną  na tabelę &#8222;PRODUKTY&#8221;), encję Cennik (mapowaną na tabelę &#8222;CENNIKI&#8221;) i encję Cena (tabela &#8222;CENY&#8221;) .  <a href="http://www.netbeans.org/">NetBeans</a>, na podstawie istniejącego schematu bazy danych, wygenerował mi takie klasy (po drobnej korekcie nazw własności):</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">net.schowek.grailsapp</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// importy</span>
&nbsp;
@<span style="color: #003399;">Entity</span>
@Table<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;PRODUKTY&quot;</span><span style="color: #009900;">&#41;</span>
@NamedQueries<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>@NamedQuery<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;Produkt.findAll&quot;</span>, query <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT p FROM Produkt p&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Produkt <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Serializable</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</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;">long</span> serialVersionUID <span style="color: #339933;">=</span> 1L<span style="color: #339933;">;</span>
&nbsp;
    @Id
    @Basic<span style="color: #009900;">&#40;</span>optional <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;pr_id&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
    @Basic<span style="color: #009900;">&#40;</span>optional <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;pr_nazwa&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> nazwa<span style="color: #339933;">;</span>
&nbsp;
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;pr_opis&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> opis<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Produkt<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Produkt<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> prId<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;">id</span> <span style="color: #339933;">=</span> prId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// gettery i settery</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<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> getNazwa<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>


<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">net.schowek.grailsapp</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// importy</span>
&nbsp;
@<span style="color: #003399;">Entity</span>
@Table<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;CENNIKI&quot;</span><span style="color: #009900;">&#41;</span>
@NamedQueries<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>@NamedQuery<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;Cennik.findAll&quot;</span>, query <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT c FROM Cennik c&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Cennik <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Serializable</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</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;">long</span> serialVersionUID <span style="color: #339933;">=</span> 1L<span style="color: #339933;">;</span>
&nbsp;
    @Id
    @Basic<span style="color: #009900;">&#40;</span>optional <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;cn_id&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;cn_nazwa&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> nazwa<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Cennik<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Cennik<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> cnId<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;">id</span> <span style="color: #339933;">=</span> cnId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// gettery i settery</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<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> getNazwa<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>


<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">net.schowek.grailsapp</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// importy</span>
&nbsp;
@<span style="color: #003399;">Entity</span>
@Table<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;CENY&quot;</span><span style="color: #009900;">&#41;</span>
@NamedQueries<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>@NamedQuery<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;Cena.findAll&quot;</span>, query <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT c FROM Cena c&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Cena <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Serializable</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</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;">long</span> serialVersionUID <span style="color: #339933;">=</span> 1L<span style="color: #339933;">;</span>
&nbsp;
    @EmbeddedId
    <span style="color: #000000; font-weight: bold;">private</span> CenaPK id<span style="color: #339933;">;</span>
&nbsp;
    @JoinColumn<span style="color: #009900;">&#40;</span> name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ce_pr_id&quot;</span>, referencedColumnName <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;pr_id&quot;</span>, insertable <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span>, updatable <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span>  <span style="color: #009900;">&#41;</span>
    @ManyToOne
    <span style="color: #000000; font-weight: bold;">private</span> Produkt produkt<span style="color: #339933;">;</span>
&nbsp;
    @JoinColumn<span style="color: #009900;">&#40;</span> name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ce_cn_id&quot;</span>, referencedColumnName <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;cn_id&quot;</span>, insertable <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span>, updatable <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span>  <span style="color: #009900;">&#41;</span>
    @ManyToOne
    <span style="color: #000000; font-weight: bold;">private</span> Cennik cennik<span style="color: #339933;">;</span>
&nbsp;
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ce_cena&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">BigDecimal</span> cena<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Cena<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> Cena<span style="color: #009900;">&#40;</span>CenaPK cenaPK<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;">id</span> <span style="color: #339933;">=</span> cenaPK<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// gettery i settery</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<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> getId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</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>I wreszcie klasa określająca nasz klucz złożony:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">net.schowek.grailsapp</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// importy</span>
&nbsp;
@Embeddable
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CenaPK <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Serializable</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    @Basic<span style="color: #009900;">&#40;</span>optional <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ce_pr_id&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> cePrId<span style="color: #339933;">;</span>
&nbsp;
    @Basic<span style="color: #009900;">&#40;</span>optional <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
    @Column<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ce_cn_id&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> ceCnId<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> CenaPK<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> CenaPK<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> cePrId, <span style="color: #000066; font-weight: bold;">int</span> ceCnId<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;">cePrId</span> <span style="color: #339933;">=</span> cePrId<span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">ceCnId</span> <span style="color: #339933;">=</span> ceCnId<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;">int</span> getCePrId<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> cePrId<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> setCePrId<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> cePrId<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;">cePrId</span> <span style="color: #339933;">=</span> cePrId<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;">int</span> getCeCnId<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> ceCnId<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> setCeCnId<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> ceCnId<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;">ceCnId</span> <span style="color: #339933;">=</span> ceCnId<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;">String</span> toString<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: #0000ff;">&quot;net.schowek.grailsapp.CenaPK[cePrId=&quot;</span> <span style="color: #339933;">+</span> cePrId <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;, ceCnId=&quot;</span> <span style="color: #339933;">+</span> ceCnId <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;]&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Tak przygotowanesą podstawą wygenerowanej aplikacji.  Po uruchomieniu aplikacji za pomocą komendy grails run-app mogę już eksplorować zasoby cen i produktów. Problem jednak zaczyna się, gdy chcę przejrzeć listę cen. Już na liście (http://localhost:8080/GrailsApp/cena/list) widać, że odnośniki do rekordów cen nie przypominają standardowych odnośników do rekordów tabel o prostych kluczach. Przykładowy link do ceny wyglądał tak:</p>
<p><a href="http://localhost:8080/GrailsAppl/cena/show/net.schowek.grailsapp.CenaPK%5BcePrId%3D63%2C+ceCnId%3D2%5D">http://localhost:8080/GrailsAppl/cena/show/net.schowek.grailsapp.CenaPK%5BcePrId%3D63%2C+ceCnId%3D2%5D</a></p>
<p>a strona, którą można pod nim zobaczyć wygląda tak:</p>
<p><img class="aligncenter size-full wp-image-211" title="err" src="http://xis.schowek.net/wp-content/uploads/2009/01/err.jpg" alt="err" width="770" height="407" /><br />
Jak widać, Grails w miejsce <strong>id</strong>, podstawia wartość obiektu klasy <strong>CenaPK</strong>, a ten reprezentowany jest przez swoją metodę <strong>toString()</strong>.  Po odwołaniu się do serwera i zapytaniu o cenę o podanym kluczu, serwer &#8211; co oczywiste &#8211; częstuje nas wyjątkiem.</p>
<p>Oto prosty sposób, w jaki można temu zaradzić (zakładając, że klucz złożony składa się z pól typu numerycznego).</p>
<p>Przede wszystkim, zmieniłem kod klasy <strong>CenaPK</strong> na taki (zmieniłem <strong>toString() </strong>i dodałem jeden konstruktor):</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: #003399;">String</span> KEY_SEPARATOR<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;_&quot;</span><span style="color: #339933;">;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<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> cePrId<span style="color: #339933;">+</span>KEY_SEPARATOR<span style="color: #339933;">+</span>ceCnId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> CenaPK<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> k<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> keys <span style="color: #339933;">=</span> k.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span> KEY_SEPARATOR <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">cePrId</span> <span style="color: #339933;">=</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">parseInt</span><span style="color: #009900;">&#40;</span>keys<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</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;">ceCnId</span> <span style="color: #339933;">=</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">parseInt</span><span style="color: #009900;">&#40;</span>keys<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Jak widzisz, połączyłem w jeden string dwa klucze oddzielone od siebie separatorem. Oznacza to, że ponowne wygenerowanie widoków komendą:</p>
<pre>grails generate-views net.schowek.grailsapp.Cena</pre>
<p>poskutkuje nową listą cen, zawierającą odnośniki do rekordów podobne do tych:</p>
<p><a href="http://localhost:8080/GrailsAppl/cena/show/63_2">http://localhost:8080/GrailsAppl/cena/show/63_2</a></p>
<p>Aby wszystko grało, musiałem jeszcze przerobić kontroler cen (plik <strong>CenaController.groovy</strong> w katalogu <strong>controllers/</strong>) i zmienić wszystkie linie ładujące pojedynczy rekord ceny z</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">def</span> cenaInstance <span style="color: #66cc66;">=</span> Cena.<span style="color: #663399;">get</span><span style="color: #66cc66;">&#40;</span> params.<span style="color: #006600;">id</span> <span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>na</p>

<div class="wp_syntax"><div class="code"><pre class="groovy" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">def</span> cenaInstance <span style="color: #66cc66;">=</span> Cena.<span style="color: #663399;">get</span><span style="color: #66cc66;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> CenaPK<span style="color: #66cc66;">&#40;</span>params.<span style="color: #006600;">id</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Od tej pory mogłem się już cieszyć działającą aplikacją obsługującą klucze złożone.</p>
<p>Aha, separatorem klucza może być w zasadzie dowolny znak, jednak są tu wyjątki &#8211; np. nie zadziała na pewno <em>slash</em>, ponieważ jest on interpretowany przez <strong>UrlMappera</strong> grails. Warto zatem sprawdzić co zadziała, a co nie.</p>
]]></content:encoded>
			<wfw:commentRss>http://xis.schowek.net/2009/01/24/grails-i-kompozytowe-klucze-w-hibernate/feed/</wfw:commentRss>
		<slash:comments>0</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>
	</channel>
</rss>

