<?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>CodePlay &#187; Szoftverfejlesztés</title>
	<atom:link href="http://codeplay.hu/category/developer/feed/" rel="self" type="application/rss+xml" />
	<link>http://codeplay.hu</link>
	<description>Kitaláljuk, lefejlesztjük, telepítjük</description>
	<lastBuildDate>Wed, 21 Dec 2011 14:48:53 +0000</lastBuildDate>
	<language>hu</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>PHP fejlesztői környezet OSX-en</title>
		<link>http://codeplay.hu/developer/2011/10/osx-php/</link>
		<comments>http://codeplay.hu/developer/2011/10/osx-php/#comments</comments>
		<pubDate>Sun, 23 Oct 2011 11:13:36 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mcrypt]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[snow leopard]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=215</guid>
		<description><![CDATA[Ha jól emlékszem lassan három hónapja gyűröm a MacBook Pro-t, és próbálom elfelejteni az évek alatt beidegződött Windows-t több kevesebb bosszúság árán. Eljutottam addig a pontig, hogy már nem csak felhasználóként szeretném használni az OSX-et, hanem az új webtárhely oldalunkat a Tárhelypark-ot oldalt is szeretném ezen fejleszteni és tesztelni mielőtt éles üzembe kerül. Mivel egyelőre [...]]]></description>
			<content:encoded><![CDATA[<p>Ha jól emlékszem lassan három hónapja gyűröm a <a href="http://www.apple.com/hu/macbookpro/">MacBook Pro</a>-t, és próbálom elfelejteni az évek alatt beidegződött Windows-t több kevesebb bosszúság árán. Eljutottam addig a pontig, hogy már nem csak felhasználóként szeretném használni az <a href="http://www.apple.com/hu/macosx/">OSX</a>-et, hanem az új <a href="http://tarhelypark.hu">webtárhely</a> oldalunkat a <a href="http://tarhelypark.hu">Tárhelypark</a>-ot oldalt is szeretném ezen fejleszteni és tesztelni mielőtt éles üzembe kerül. Mivel egyelőre ezt <a href="http://wordpress.com/">WordPress</a>-el tervezzük, ezért szükségem van a Mac-en egy <a href="http://httpd.apache.org">Apache</a>/<a href="http://php.net">PHP</a>/<a href="http://www.mysql.com">MySQL</a> fejlesztői környezetre, amit most össze is rakok.</p>
<p><span id="more-215"></span></p>
<p>Állítólag a <a href="http://www.apple.com/hu/macbookpro/">Mac</a> már alap kiszerelésben is egy fejlesztői gép, ezért minden van rajta kezdve az <a href="http://httpd.apache.org">Apache</a>-tól a <a href="http://php.net">PHP</a>-n át a <a href="http://rubyonrails.org/">Ruby</a>-ig. Ez talán igaz is lehetne, ha nem derült volna ki azonnal, hogy azért egy kis tuningolás nem árt, mert egy alap <a href="http://wordpress.com/">WordPress</a> futtatásához hiányzik egy két dolog: a PHP telepítésből az mcrypt könyvtár, a <a href="http://www.mysql.com">MySQL</a> adatbázis kezelő, és némi Apache konfiguráció.</p>
<p>A konfiguráció amin dolgozom: Mac OS X 10.6.8 (10K549) &#8211; Snow Leopard</p>
<h2>OSX Apache konfiguráció</h2>
<p>Az OSX-ben már benne van az Apache, de nem fut, el kell indítani:</p>
<p><code>$ sudo apachectl start</code></p>
<p>leállítani vagy újraindítani így tudod:</p>
<p><code>$ sudo apachectl stop</code></p>
<p><code> </code></p>
<p><code>$ sudo apachectl restart</code></p>
<p>Ha fut a webszerver akkor a localhost-on már látnod is kell egy böngészőből:</p>
<p><code>http://localhost</code></p>
<h3>Apache Virtuális hosztok</h3>
<p>Én szeretem a virtuális hosztok használatát, mert így könnyebb megjegyezni az egyes alkalmazások elérését, és nem kell foglalkozni az elérési utakkal az URL-ben. Úgy terveztem, hogy a létrehozott oldalakat a saját Sites könyvtáramban fogom tárolni a /Users/user/Sites könyvtárban, mert ezt használja több program is alapértelmezésben.</p>
<p>Az Apache konfigurációs fájlban (/etc/apache2/httpd.conf) engedélyezni kell a virtuális hosztokat:</p>
<p><strong>/etc/apache2/httpd.conf</strong></p>
<p><code># Virtual hosts<br />
Include /private/etc/apache2/extra/httpd-vhosts.conf</code></p>
<p>A httpd.vhosts.conf konfigurációs fájlban felvettem a tarhelypark.local domain-hez tartozó hosztot.</p>
<p><strong>httpd-vhosts.conf</strong></p>
<p><code>ServerAdmin xyz@codeplay.hu<br />
DocumentRoot "/Users/kepes/Sites/tarhelypark-wp"<br />
ServerName tarhelypark.local<br />
ServerAlias *.tarhelypark.local<br />
ErrorLog "/private/var/log/apache2/tarhelypark.local-error_log"<br />
CustomLog "/private/var/log/apache2/tarhelypark.local-access_log" common</code></p>
<p><strong>Hosts fájl az OSX-en</strong></p>
<p>Ahhoz, hogy a virtuális hosztok működjelenk, még fel kell venni a megfelelő nevűt a /etc/hosts fájlba. A ServerName paraméterben megadott nevet kell hozzákapcsolni a localhost Ip címéhez.</p>
<p><code>$sudo nano /etc/hosts</code></p>
<p><code>127.0.0.1       localhost<br />
255.255.255.255 broadcasthost<br />
::1             localhost<br />
fe80::1%lo0     localhost<br />
127.0.0.1       tarhelypark.local<br />
127.0.0.1       myadmin.local<br />
127.0.0.1       blog.tarhelypark.local</code></p>
<p>Miután ezt felvettük, és az Apache újraindult, a böngészőből el lehet érni a szervert a tarhelypark.local beírásával.</p>
<h2>Symbolic link not allowed or link target not accessible</h2>
<p>Jól használhatók még a szimbolikus linkek is, amiket trükkös engedélyezni. Nem a fő konfigurációs fájlban kell beállítani a FollowSymlinks paramétert mert egy inkludált konfig fájl felülírja azt.</p>
<p><strong>/etc/apache2/users/username.conf</strong></p>
<p><code>Options Indexes MultiViews FollowSymlinks<br />
AllowOverride All<br />
Order allow,deny<br />
Allow from all<br />
AddType application/x-httpd-php .php<br />
AddType application/x-httpd-php-source .phps</code></p>
<p>Amiért még ilyen hibaüzenetet kaphatunk, az a könyvtár jogosultsága amire a szimbolikus link mutat. Ha a konfiguráció után még mindíg jelentkezik a probléma, akkor jól nézd át a jogokat és tulajdonosokat!</p>
<h2>PHP konfiguráció</h2>
<p>Eredetileg nincsen php.ini fájl, létre kell hozni a /etc könyvtárban</p>
<p><code>$ sudo cp /etc/php.ini.default /etc/php.ini</code></p>
<h2>PHP és mcrypt</h2>
<p>A PHP alap konfigurációból hiányzik az mcrypt könyvtár, ami számos programhoz, például a PHPMyAdmin-hez is szükséges. Ezt most pótolni fogjuk.</p>
<p>Először is nézzük meg milyen php verzió fut a gépen:</p>
<p><code>$ php -v</code></p>
<p><code>PHP 5.3.4 (cli) (built: Dec 15 2010 12:15:07)</code></p>
<p><code>Copyright (c) 1997-2010 The PHP Group</code></p>
<p><code> </code></p>
<p><code>Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies</code></p>
<p>Nálam a PHP 5.3.4. Ahhoz, hogy az mcrypt-et hozzá tudjuk kapcsolni a PHP-hez szükségünk van a következő három dologra:</p>
<ul>
<li><a href="http://developer.apple.com/technologies/mac/" target="_blank">Xcode 3</a>, amihez Apple Developer-é kell válnunk. Ez egy kicsit macerás, az xcode telepítve 9 Gb</li>
<li><a href="http://sourceforge.net/projects/mcrypt/files/Libmcrypt/" target="_blank">mcrypt könyvtár (libmcrypt)</a></li>
<li><a href="http://www.php.net/releases/" target="_blank">PHP forráskód</a>, a megfelelő verzióval</li>
</ul>
<p>Az xcode telepítése után csomagold ki a libmcrypt és php letöltéseket. A libmcrypt fordítása:</p>
<p><code>$ ./configure</code></p>
<p><code>$ make</code></p>
<p><code> </code></p>
<p><code>$ make install</code></p>
<p>A PHP-ből nincsen szükség a teljes csomag lefordítására, csak az mcrypt kiegészítő szükséges:</p>
<p><code>$ cd php-/ext/mcrypt/</code></p>
<p><code>$ sudo phpize</code></p>
<p><code>$ sudo ./configure</code></p>
<p><code>$ sudo make</code></p>
<p><code> </code></p>
<p><code>$ sudo make install</code></p>
<p>Ezek után létre kell jöjjön egy .so fájl a /usr/lib/php/extensions/no-debug-non-zts-20090626 könyvtárban.</p>
<p>Az <strong>/etc/php.ini</strong> fájlban szerepelnie kell a következő két sornak:</p>
<p><code>extension_dir=/usr/lib/php/extensions/no-debug-non-zts-20090626<br />
extension=mcrypt.so</code></p>
<p>Az Apache újraindításával a phpinfo-ban meg kell jelennie az mcrypt könyvtárban.</p>
<p><a href="http://codeplay.hu/wp-content/uploads/2011/09/php-mcrypt.png"><img class="aligncenter size-medium wp-image-222" title="PHP mcrypt" src="http://codeplay.hu/wp-content/uploads/2011/09/php-mcrypt-300x149.png" alt="" width="300" height="149" /></a></p>
<h2>MySQL</h2>
<p>A MySQL letöltés és telepítése egyszerű, ezt nem részletezem. Miután a telepítés befejeződött szükség van a my.cnf konfigurációs fájl létrehozására a /etc könyvtárban. Én a fejlesztéshez a legkisebb példa konfigurációt, a my-small.cnf fájlt választottam.</p>
<p><code>$ sudo cp /usr/local/mysql/support-files/my-small.cnf /etc/my.cnf</code></p>
<p>Alapértelmezés szerint a PHP rossz helyen keresi a sock fájlt, ezért meg kell változtatni a /etc/php.ini fájlban a mysql.default_socket bejegyzést:</p>
<p><code>mysql.default_socket = /tmp/mysql.sock</code></p>
<p><code>$ sudo /Library/StartupItems/MySQLCOM/MySQLCOM start</code></p>
<p>Érdemes belerakni a MySql-t a path -ba</p>
<p><code>$ nano ~/.profile<br />
export PATH=$PATH:/usr/local/mysql/bin</code></p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2011/10/osx-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Facebook alkalmazás &#8211; Küldj egy lapot</title>
		<link>http://codeplay.hu/news/2011/08/facebook-alkalmazas-kuldj-egy-lapot/</link>
		<comments>http://codeplay.hu/news/2011/08/facebook-alkalmazas-kuldj-egy-lapot/#comments</comments>
		<pubDate>Fri, 26 Aug 2011 09:10:15 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Hírek]]></category>
		<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[alkalmazás]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=202</guid>
		<description><![CDATA[Elindult az Allianz Biztosító megrendelésére készített Facebook alkalmazásunk a Küldj egy lapot. A játékban a felhasználók négy szituáció közül választhatnak, melybe ismerőseik arcát &#8220;behúzva&#8221; vicces képeket tudnak készíteni egy-egy képzeletbeli nyaralásról. A résztvevők között az Allianz egy darab két személyes Wellness hétvégét sorsol ki a játék végén. A fejlesztés során az ilyen jellegű játékokban megszokott [...]]]></description>
			<content:encoded><![CDATA[<p><p>Elindult az <a href="https://www.allianz.hu">Allianz Biztosító</a> megrendelésére készített <a href="http://codeplay.hu/facebook">Facebook alkalmazásunk</a> a <a href="http://www.kuldjegylapot.hu/">Küldj egy lapot</a>. A játékban a felhasználók négy szituáció közül választhatnak, melybe ismerőseik arcát &#8220;behúzva&#8221; vicces képeket tudnak készíteni egy-egy képzeletbeli nyaralásról. A résztvevők között az Allianz egy darab két személyes Wellness hétvégét sorsol ki a játék végén. A fejlesztés során az ilyen jellegű játékokban megszokott Flash animáció helyett <a href="http://jquery.com/">JQuery-t</a> használtunk, a szerver oldalon <a href="http://rubyonrails.org/">Ruby on Rails</a> dolgozik. A nagy látogatószám kiszolgálására képes szervert a <a href="http://tarhelypark.hu">Tárhelypark.hu</a> biztosítja.</p>
<p><span id="more-202"></span><br />
<a href="http://codeplay.hu/wp-content/uploads/2011/08/kuldjegylapot.jpg"><img src="http://codeplay.hu/wp-content/uploads/2011/08/kuldjegylapot-300x195.jpg" alt="Küldj egy lapot nyitó képernyő" title="Küldj egy lapot" width="300" height="195" class="aligncenter size-medium wp-image-207" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/news/2011/08/facebook-alkalmazas-kuldj-egy-lapot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook alkalmazás &#8211; Soproni nem nyertem</title>
		<link>http://codeplay.hu/news/2011/08/facebook-alkalmazas-soproni-nem-nyertem/</link>
		<comments>http://codeplay.hu/news/2011/08/facebook-alkalmazas-soproni-nem-nyertem/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 09:27:45 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Hírek]]></category>
		<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[alkalmazás]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=209</guid>
		<description><![CDATA[A Soproni és a Port.hu közös promóciója a rengeteg TV spottal megtámogatott &#8220;Nem nyertem&#8221; reklámhadjárat, melyben a Hol söröz oldalról indulva egy nem nyertes Soproni kuponnal bárki meghívhatja öt barátját egy sörözésre, az első kört a Soproni állja. A Facebook alkalmazás érdekessége, hogy több rendszert kötöttünk össze, melyben részt vett a Port.hu fejlesztőcsapata is. A [...]]]></description>
			<content:encoded><![CDATA[<p>A <a href="http://soproni.hu/">Soproni</a> és a <a href="http://port.hu/">Port.hu</a> közös promóciója a rengeteg <a href="http://soproni.hu/letoltesek.html">TV spottal megtámogatott</a> &#8220;Nem nyertem&#8221; reklámhadjárat, melyben a <a href="http://port.hu/pls/w/holsorozz.index2">Hol söröz</a> oldalról indulva egy nem nyertes Soproni kuponnal bárki meghívhatja öt barátját egy sörözésre, az első kört a Soproni állja. A Facebook alkalmazás érdekessége, hogy több rendszert kötöttünk össze, melyben részt vett a Port.hu fejlesztőcsapata is. A felhasználó a <a href="http://port.hu/">Port.hu</a>-ról vagy a <a href="http://port.hu/pls/w/holsorozz.index2">Hol söröz</a>-ről indulva jut el a Facebook alkalmazásig, ahol meghívhatja ismerőseit, összeállítva a meghívotti listát. Az ismerősök értesítést kapnak a meghívásról, majd bekerülnek a Port.hu rendszerébe is.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/news/2011/08/facebook-alkalmazas-soproni-nem-nyertem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook alkalmazás &#8211; Üzemanyagár tippelő</title>
		<link>http://codeplay.hu/news/2011/04/facebook-alkalmazas-uzemanyag/</link>
		<comments>http://codeplay.hu/news/2011/04/facebook-alkalmazas-uzemanyag/#comments</comments>
		<pubDate>Tue, 26 Apr 2011 09:14:00 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Hírek]]></category>
		<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[alkalmazás]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=195</guid>
		<description><![CDATA[A múlt héten került éles üzembe új Facebook alkalmazásunk a Genertel Biztosító megrendelésére. Az Üzemanyagár Figyelő játékban a felhasználók a következő heti benzin és dízel üzemanyagárat tippelhetik meg. A helyes tippelők között minden héten 50-50 liter üzemanyag kerül kisorsolásra, ami véleményem szerint elég jó nyereménynek számít a Facebook játékok között, tekintve, hogy egy folyamatos játékról [...]]]></description>
			<content:encoded><![CDATA[<p>A múlt héten került éles üzembe új <a href="http://codeplay.hu/facebook/">Facebook alkalmazásunk</a> a <a title="Genertel honlap" href="https://www.genertel.hu/">Genertel Biztosító</a> megrendelésére. Az <a title="Üzemanyagár figyelő alkalmazás" href="http://apps.facebook.com/uzemanyagar-figyelo/">Üzemanyagár Figyelő</a> játékban a felhasználók a következő heti benzin és dízel üzemanyagárat tippelhetik meg. A helyes tippelők között minden héten 50-50 liter üzemanyag kerül kisorsolásra, ami véleményem szerint elég jó nyereménynek számít a Facebook játékok között, tekintve, hogy egy folyamatos játékról beszélünk, nem pedig egy egyszeri sorsolásról. A játék érdekessége fejlesztési szempontból, hogy a nyertesek sorsolását is elvégzi az adminisztrátori felületről, ahonnan az aktuális árak is feltölthetők.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/news/2011/04/facebook-alkalmazas-uzemanyag/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails kezdetek</title>
		<link>http://codeplay.hu/developer/2011/01/ruby-on-rails/</link>
		<comments>http://codeplay.hu/developer/2011/01/ruby-on-rails/#comments</comments>
		<pubDate>Sun, 16 Jan 2011 17:30:34 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=127</guid>
		<description><![CDATA[Előző bejegyzésében Almi kifejtette, nem sok jót jósolunk a Java technológiának sajnos, így kénytelenek voltunk más fele is nyitni érdeklődésünket. Az iPhone és Android mobil fejlesztések mellett választanunk kell egy Web-es MVC keretrendszert, ami egyszerű, támogatott, és a fejlesztés menete ha lehet gyorsabb minta a Java-s technológiákkal. Én eddig a PHP/Zend Framework párost támogattam, mert [...]]]></description>
			<content:encoded><![CDATA[<p>Előző <a href="http://codeplay.hu/developer/2010/11/mi-lesz-veled-java/">bejegyzésében</a> Almi kifejtette, nem sok jót jósolunk a Java technológiának sajnos, így kénytelenek voltunk más fele is nyitni érdeklődésünket. Az iPhone és Android mobil fejlesztések mellett választanunk kell egy Web-es MVC keretrendszert, ami egyszerű, támogatott, és a fejlesztés menete ha lehet gyorsabb minta a Java-s technológiákkal. Én eddig a <a href="http://zendframework.com/">PHP/Zend Framework</a> párost támogattam, mert PHP-t már láttam előtte, de ennek alternatívája a <a href="http://rubyonrails.org/">Ruby On Rails</a>. Ma megpróbáltam egy minimális &#8220;Hello World&#8221; alkalmazást létrehozni Rails-ben, ennek buktatóit szedtem össze.</p>
<p><span id="more-127"></span></p>
<p>Minél egyszerűbben szerettem volna eljutni addig, hogy böngészőmben megjelenjen az első MVC-s weboldal, tényleg minimális igényekkel, csak azt akartam látni, menyire bonyolult a dolog, nem érdekelt maga a nyelv. Windows 7 alatt próbálkoztam, így egy icsit specifikus az írás, és valószínűleg a problémák is, de könnyen adaptálható más oprendzserre.</p>
<p>Tehát Felmentem a <a href="http://rubyonrails.org/">Ruby On Rails</a> oldalára, és kiválasztottam a <a href="http://rubyonrails.org/download">Letöltés menüpontot</a>, és letöltöttem az éppen aktuális 1.9.2-es verziót. Az oldalon meglehetősen jól nem csak az van leírva, hogy honnan töltsük le a dolgokat, hanem, hogy hogyan indítsuk el a Rails-t. Ez kicsit kevés a Hello World-höz, de jó kiindulás.</p>
<p>A letöltés után a Ruby /doc könyvtárában van egy pdf, ami alapján elkezdtem az első alkalmazás fejlesztését (334. oldal) de ez annyira régi, hogy nem bizonyult megfelelőnek. A parancsok megváltoztak azóta mióta ezt írták, és az 1.9.2 parancsosora másképp működik. Azért a nyelv elsajátítására még jó lehet majd később, elég részletesnek látszik.</p>
<p>A könyv után a <a href="http://guides.rubyonrails.org/getting_started.html">Getting Started</a> leírással próbálkoztam, ami már jóval naprakészebb információkat tartalmazott. Elsőként el kell érni a Ruby-t ami Windows alatt elég egyszerű, mert a telepítő a Start menübe telepít egy &#8221;Start Ruby Command Prompt&#8221; nevű ikont, de más oprendszerben is csak annyi a trükk, hogy a /bin könyvtár legyen a PATH-ben. Próba képpen érdemes lefuttatni a ruby parancsot magéban, ami megjeleníti a paranacs helpjét. Ha megy akkor a Rails telepítéséhez a következő parancs szükséges:</p>
<p><code>gem install rails</code></p>
<p>Érdemes tudni kis háttér információt a fenti parancshoz, mégpedig, hogy a Ruby alaprendszer mellé kis csomagokként telepíthetők kiegészítések, ezek a gem-ek. Ilyen kiegészítő például a Rails is, ami nem a Ruby nyelv része.</p>
<p>Mivel elvileg a keret adott a fejlesztéshez, létrehoztam a projekt könyvtáramat. Ez tetszőleges helyen lehet, és a D: meghajtóra tettem egy ruby_workspace könyvtárba, követve az eddig jól bevált Eclipse-es névkonvenciót. Amint megvan a könyvtár lépjünk is bele &#8211; itt lesznek majd a projektjeink &#8211; majd a <code>rails new helloworld</code> parancsal létrehoztam a helloworld projektet</p>
<p><code> mkdir ruby_workspace<br />
 cd ruby_workspace<br />
 rails new helloworld<br />
 </code></p>
<p>A Rails projekt futtatásához számos gem-et kell telepíteni majd, de ezt a Ruby megoldja, és egy leíróban tárolja minden projekthez, mire van szüksége. Ezek szintén nincsenek még letöltve, ezért letöltöm őket a következő paranccsal:</p>
<p><code>bundle install</code></p>
<p>Elvileg olyan stádiumba került a projekt, hogy akár futtatható lenne egy szerveren, ezért megpróbáltam elindítani:</p>
<p><code>rails server</code></p>
<h3>sqliste3.dll is missing from your computer</h3>
<p>A fenti hibaüzenet jelent meg egy kis ablakban, ami kicsit flusztráló, mert úgy éreztem mindent a Rails leírás szerint csináltam eddig. Kis Google és mindjárt megvan az eredmény, szükségem van az <a href="http://www.sqlite.org">SQLite adatbáziskezelőre</a>, mert az eléréséhez szükséges dolgokat a Ruby telepíti ugyan, de magát az adatbáziskezelőt nem. Gyorsan letöltöttem innen az <a href="http://www.sqlite.org/download.html">SQLite Letöltés oldaláról</a> a DLL verziót, és bemásoltam a Ruby /bin könyvtárába. Sok helyen írják, hogy másoljuk a System32-be de ez utoljára Windows 3.1 alatt volt megengedhető, ezért NE tegyük!</p>
<p>Újra megpróbáltam elindítani a szervert:</p>
<p><code>rails server</code></p>
<h3>bind(2) (Errno::EADDRINUSE)</h3>
<p>Megint egy kis idegesítő szálka a tervem közepén, miszerint 2 perc alatt megvan a Hello World. Nem jöttem rá miért, de valami a Windows 7 alatt rátelepedett a 3000-es portra, amit szegény Rails szerver próbál használni, és így nem tud. Megoldásként át kell rakni a szervert egyel nagyobb portra:</p>
<p><code>rails server -p 3001</code></p>
<p>Csodák csodája, elindult végre:</p>
<p><code> => Booting WEBrick<br />
 => Rails 3.0.3 application starting in development on http://0.0.0.0:3001<br />
 => Call with -d to detach<br />
 => Ctrl-C to shutdown server<br />
 [2011-01-16 13:40:39] INFO  WEBrick 1.3.1<br />
 [2011-01-16 13:40:39] INFO  ruby 1.9.2 (2010-12-25) [i386-mingw32]<br />
 [2011-01-16 13:40:39] INFO  WEBrick::HTTPServer#start: pid=9676 port=3001<br />
 [2011-01-16 13:41:03] INFO  going to shutdown ...<br />
 [2011-01-16 13:41:03] INFO  WEBrick::HTTPServer#start done.</code></p>
<div>A futó szerver tesztelhető a következő linken: <code>http://localhost:3001</code></div>
<h3>Hello Ruby MVC</h3>
<p>Eljutottam oda, hogy végre kiírhatom a böngészőbe az áhított üdvözlést. Először létre kell hozni hozzá egy Controller és egy View osztályt. Szerencsére a Rails generálni tudja ezeket:</p>
<p><code>rails generate controller home index</code></p>
<p>A paranccsal annyit mondtunk, hogy szükségünk van egy home nevű kontrollerre, aminek van egy index akciója. A parancs futása közben a képernyőn megjelenik milyen fájlokat hoz létre, érdemes egyesével átnézni őket tanulás végett, de ezzel most én nem foglalkozom. Gyorsan megmódosítom a /app/views/home/index.html.erb template fájlt, hogy benne legyen a &#8220;Hello Ruby&#8221; és kipróbálom az új kontrolleremet a következő linken: <code>http://localhost:3001/home/index</code></p>
<h3>routes.rb</h3>
<p>Még egy kívánságom van a Ruby isteneitől, hogy az index megjelenéséhez ne kelljen beírni a teljes útvonalat. Ehhez törölni kell a /public/index.html fájlt és konfigurálni kell a rendszert a /conf/routes.rb fájlban.</p>
<p><code>root :to => "home#index"</code></p></p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2011/01/ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mi lesz veled Java?</title>
		<link>http://codeplay.hu/developer/2010/11/mi-lesz-veled-java/</link>
		<comments>http://codeplay.hu/developer/2010/11/mi-lesz-veled-java/#comments</comments>
		<pubDate>Fri, 05 Nov 2010 10:39:35 +0000</pubDate>
		<dc:creator>almergabor</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[sun]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=116</guid>
		<description><![CDATA[Az utóbbi idők fontosabb Java történései: Oracle megvette a Sun-t, így a Java-t is James Gosling a Java szülőatyja otthagyta Sun-t (vagyis már az Oracle-t) Oracle perli a Google-t az Android-os Java miatt (hogy pontosan miért, az számomra elég zavaros) Apple bejelentette, hogy a Mac-es Java-t nem fejlesztik tovább És egyáltalán kevesebbet hallani a Java-ról [...]]]></description>
			<content:encoded><![CDATA[<p>Az utóbbi idők fontosabb Java történései:</p>
<ol>
<li>Oracle megvette a Sun-t, így a Java-t is</li>
<li>James Gosling a Java szülőatyja otthagyta Sun-t (vagyis már az Oracle-t)</li>
<li>Oracle perli a Google-t az Android-os Java miatt (hogy pontosan miért, az számomra elég zavaros)</li>
<li>Apple bejelentette, hogy a Mac-es Java-t nem fejlesztik tovább</li>
<li>És egyáltalán kevesebbet hallani a Java-ról</li>
</ol>
<p>Ezt a témát jártam körbe kicsit részletesebben.</p>
<p><span id="more-116"></span></p>
<p><strong>1.</strong> Ezzel talán az a gond, hogy az Oracle miután megvette a Bea-t, már akkor is gondban volt, hogy mit csináljon azokkal a termékeivel, amikből kettő lett neki, és ez helyzet csak romlott a Sun megvételével, ahol megint csak hasonló termékek voltak. Mintha maga az Oracle sem tudná, hogy például, akkor most Weblogic, vagy Glassfish, vagy IAS. (Na jó, az IAS, csak vicc volt <img src='http://codeplay.hu/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )</p>
<ul>
<li>Tavaly az Oracle fejlesztői konferencián az előadónak csak záporoztak a kérdések, hogy akkor most IAS-t kell-e használni, vagy Weblogic-ot. A vicc az egészben az volt, hogy pont azokban a napokban látott napvilágot az Sun felvásárlásának a híre, és valaki még a GlassFish-re is rákérdezett, persze az előadó csak az IAS és Weblogic témára tudott mit mondani, mégpedig, hogy Weblogic-ot érdemes használni, az IAS már csak egy ideig lesz támogatva.</li>
<li>A nagy cégekre általában azt mondják, hogy maga az ördög. Ez most sincs másként, mivel az Oracle, így már egy nagyon-nagyon nagy cég lett.</li>
<li>Az ilyen cégek lépéseit mindenki nagyon kritikusan figyeli. Legyen szó akár a Google-ről, az Apple-ről, vagy éppen az Oracle-ről.</li>
<li>Az Oracle adatbázis licenszekről tudjuk, hogy elég drágák, és nem lapul mindenkinek a fiókjában pár darab, így ha lehet, minden informatikai vezető kétszer is meggondolja, hogy kell-e neki Oracle, vagy használjon valami mást, mondjuk MySQL-t.</li>
<li>Mivel még korábban a Sun megvette a MySQL-t, ami így megint csak az Oracle kezében landolt, a lehetőségek tovább szűkültek, mivel  az Oracle ebből is jó kis pénzt szeretne behúzni.</li>
<li>Elég csak megnézni a jelenlegi MySQL árakat: <a href="http://mysql.com/products/">http://mysql.com/products/</a></li>
<li>Egy Clusteres MySQL kb. évi 2 millió forint.</li>
<li>Hogy az emberek mennyire ugranak mindenre amit az Oracle változtat, mutatja a napokban felkapott hír, miszerint a MySQL Classic Edition már nem tartalmazza az InnoDB storage engine-t: <a href="http://www.infoq.com/news/2010/11/MySQL-Classic-InnoDB">http://www.infoq.com/news/2010/11/MySQL-Classic-InnoDB</a></li>
<li>Már több helyen olvastam, hogy ha új projektet indítasz, akkor inkább PostgreSQL-t használj, vagy valamilyen NoSQL terméket.</li>
</ul>
<p><br class="spacer_" /></p>
<p><strong>2.</strong> Hogy James Gosling (http://en.wikipedia.org/wiki/James_Gosling) otthagyta az Oracle-t, inkább csak szimbolikus jelentőséggel bír, de mindenképpen érdekes dolog. A Java fejlesztők körében (persze csak akik egyáltalán tudtak róla), így nem lett sokkal népszerűbb az Oracle.</p>
<p><br class="spacer_" /></p>
<p><strong>3.</strong> A Google felhasznált valamilyen kódrészleteket a Java forrásából. Ezért perel az Oracle: <a href="http://www.infoq.com/news/2010/08/oracle_sues_google">http://www.infoq.com/news/2010/08/oracle_sues_google</a></p>
<p>Az ügy egyébként elég bonyolultnak tűnik, viszont egy érdekes felvetést olvastam valahol: az egész azért van, hogy a Google megvegye a Java-t az Oracle-től, mivel az nem tud vele mit kezdeni, a Google pedig az Android miatt picit felkavarná a Java körüli állóvizet. Nem tudom mennyi igaz belőle, mindenesetre érdekes.</p>
<p><br class="spacer_" /></p>
<p><strong>4. </strong>Mivel egyre több Java fejlesztő használ Mac-et, így sokaknak fájó az a bejelentés, hogy az új Mac OS X Lion operációs rendszerben, már nem lesz alapból megtalálható a Java. Mivel az Apple fejleszti a Mac-es Java-t, és gondolom az Oracle megint csak kicsit pénzéhesen sokat kért, amire Steve Jobs beintett.</p>
<p><br class="spacer_" /></p>
<p><strong>5.</strong> Egyre kevesebbet lehet hallani a Java-ról. Régebben, alig bírtam a Google Reader-em Java-s híreivel, manapság jó ha kéthetente van egy-egy érdekes hír. Mintha már mindenki mindent leírt volna amit tudott a Java-ról. Nincs miről írni, mert nem történik semmi Érdemes megnézni, hogy például az  O&#8217;Reilly kiadónál nincs előkészületben egyetlen Java-s könyv se: <a href="http://oreilly.com/java/index.html">http://oreilly.com/java/index.html</a></p>
<p>Ami még érdekes, hogy maga a Java nyelv és a körülötte lévő technológiák jóval bonyolultabbak, mint kellene.</p>
<p>Ha valaki manapság egy átlag Java-s web-es projektbe belecsöppen, akkor körülbelül a következő dolgokkal találkozhat, amikről tudnia kell:</p>
<ul>
<li>Java</li>
<li>Spring</li>
<li>Hibernate</li>
<li>Struts2</li>
<li>Maven</li>
</ul>
<p>Az előbb felsorolt technológiák mindegyikéről külön könyvek jelentek meg, mindegyik technológia megtanulása hónapokba telik.</p>
<p>Betanulási idő, és legtöbbször sajnos fejlesztési idő szempontjából a PHP, Python vagy akár a Ruby, még mindig sokkal jobb választásnak tűnik, mint a Java (leszámítva a nagyvállalati környezetet).</p>
<p>Bruce Tate könyve elég érdekesen írja le ezt az egész folyamatot, igaz ő a Ruby szempontjából közelíti meg a dolgot, de próbál objektív maradni: <a href="http://pragprog.com/titles/fr_j2r/from-java-to-ruby">http://pragprog.com/titles/fr_j2r/from-java-to-ruby</a></p>
<p>Azt mondja, hogy a feladatok nagy részére sokkal ésszerűbb mást használni, esetében Ruby-t, mind Java-t.</p>
<p><br class="spacer_" /></p>
<p>Most, hogy ezeket így leírtam, azon gondolkodom, hogy mindezt csak önigazolásként gyűjtöttem-e össze. Azért, mert nem látom a jövőmet a Java-ban.</p>
<p>Nem tudom.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2010/11/mi-lesz-veled-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android onItemClick probléma ListView és Button használatakor</title>
		<link>http://codeplay.hu/developer/2010/07/android-onitemclick-problema-listview-es-button-hasznalatakor/</link>
		<comments>http://codeplay.hu/developer/2010/07/android-onitemclick-problema-listview-es-button-hasznalatakor/#comments</comments>
		<pubDate>Tue, 27 Jul 2010 23:16:26 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Mobil]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=40</guid>
		<description><![CDATA[Népszerű és mindenképp használatra javasolt komponens Androidon a ListView. Gyakorlatilag a legtöbbet használt UI elem, bárhmely programot használunk, rendszeresen feltűnik különböző formákban. Lényege, hogy a képernyőn megjelenő elemeket egy listába rendezzük, és ezt a listát görgethetjük le-fel ha nem fér ki minden elem a képernyőre. Használata relative egyszerű, amíg nem akarunk egyedi megjelenést, például Button vagyCheckbox komponenseket [...]]]></description>
			<content:encoded><![CDATA[<p>Népszerű és mindenképp használatra javasolt komponens Androidon a <code>ListView</code>. Gyakorlatilag a legtöbbet használt UI elem, bárhmely programot használunk, rendszeresen feltűnik különböző formákban. Lényege, hogy a képernyőn megjelenő elemeket egy listába rendezzük, és ezt a listát görgethetjük le-fel ha nem fér ki minden elem a képernyőre. Használata relative egyszerű, amíg nem akarunk egyedi megjelenést, például <code>Button</code> vagy<code>Checkbox</code> komponenseket belerakni, mert ekkor azonnal beleütközünk a problémába, a <code>ListView onItemClick</code>event handler nem hívódik meg kattintáskor.</p>
<p><span id="more-40"></span>Az Internet tele van a problémával, de teljes egészében leírt megoldást ritkán találni. Általában utalások vannak rá, hogy tároljunk ID-t a Tag mezőben, vagy írjuk át az <code>Adapter</code>-t, de mik is ezek az utalások tulajdonképpen?</p>
<p>A feladat amit kitaláltam egy olyan <code>ListView</code> megjelenítés, ami a <code>SimpleAdaptert</code>-t használja adatforrásnak, így a layout betölthető XML-ből egyszrűen. A layout tartalmaz egy gombot, amit megnyomva az Activity onClick metódusa hívódik meg. A probléma itt következik: az <code>onClick</code> az <code>onItemClick</code>-el ellentétben nem kapja meg melyik soron kattintottunk. Valahonnan pedig illene tudni, hiszen nem minden soron ugyanazt szeretnénk végrehajtani.</p>
<p>Az ötelt a fent amlített netes leírások alapján adja magát, tároljuk le az onClick-et meghívó View Tag-jében (<code>View.setTag(Object o)</code>) a szükséges azonosítót, így az onClick-ben a paraméterként megkapott View-tól le tudjuk kérdezni.</p>
<p>Minden ListView a lista elemeit egy Adapter osztálytól kapja (<code>ListView.setAdapter()</code>) a <code>getView()</code> metóduson keresztül. Az adapter kis átírásával megoldható, hogy a lista elemeibe bekerüljön a az Id a megfelelő Tag property-be, amikor a ListView meghívja a <code>getView()</code>-t. Leszármaztattam hát a <code>SimpleAdaptert</code>-t:</p>
<pre class="brush: java">public class ClickableButtonListAdapter extends SimpleAdapter {	

	private static final String HASHMAP_ID = "_id";

	public ClickableButtonListAdapter(Context context,
			List&lt;? extends Map&lt;String, ?&gt;&gt; data, int resource, String[] from,
			int[] to) {
		super(context, data, resource, from, to);

	}

	@SuppressWarnings("unchecked")
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view = super.getView(position, convertView, parent);
		setViewTag(view, ((HashMap&lt;String,String&gt;) getItem(position)).get(HASHMAP_ID) );
		return view;
	}

	private void setViewTag(View view, Object tag) {
		view.setTag(tag);
		if (view instanceof ViewGroup) {
			for (int i=0; i &lt; ((ViewGroup) view).getChildCount(); i++) {
				setViewTag(((ViewGroup) view).getChildAt(i), tag);
			}
		}
	}
}
</pre>
<p>A példában a lista elemei HashMap-ek, így ebből szedem ki az Id-t. A <code>HahMap</code>-ben az Id mező az &#8220;_id&#8221; elemben van, így ezt keresem ki, és rakom a Tag-be. A <code>setViewTag()</code> rekurzív metódus végigmegy az összes megjelenítendő View elemen és beállítja a Tag-et, így bármelyikre definiálhatjuk majd az onClick-et, mindig megkapjuk a Tag-ben a kiválasztott sor Id-ját.</p>
<p>Az <code>Activity</code>-ben az <code>onClick()</code> igen egyszerű:</p>
<pre class="brush: java">public void onClick(View v) {
         Toast.makeText(this, "onClick id: " + v.getTag(), Toast.LENGTH_SHORT).show();
}</pre>
<p>Nem mondom, hogy szép megoldás, de használható. Jobban tetszene, ha az Android megfelelően támogatná az egyedi ListView létrehozását esetleg azzal, hogy az onItemClick meghívódna, és eldönthetném, hogy mit akarok kezdeni az eseménnyel.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2010/07/android-onitemclick-problema-listview-es-button-hasznalatakor/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Displaytag detail megjelenítés jQuery-vel</title>
		<link>http://codeplay.hu/developer/2010/07/displaytag-detail-megjelenites-jquery-vel/</link>
		<comments>http://codeplay.hu/developer/2010/07/displaytag-detail-megjelenites-jquery-vel/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 23:01:00 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=33</guid>
		<description><![CDATA[Projektjeinkben táblázatos megjelenítéshez általában a DisplayTag nevezetű tag könyvtárat használjuk, mert jól összefér a használt Struts2 és Spring keretrendszerekkel, és egyszerűen formázható, programozható. Szerettem volna azonban kicsit többet, mint amit tud, mégpedig ha részletes adatokat tudna megjeleníteni egy legördülő sorban jQuery segítségével. Ez arra jó, ha egy sorban nem szeretnénk minden adatot bezsúfolni, mert nem [...]]]></description>
			<content:encoded><![CDATA[<p>Projektjeinkben táblázatos megjelenítéshez általában a <a href="http://displaytag.sourceforge.net">DisplayTag</a> nevezetű tag könyvtárat használjuk, mert jól összefér a használt <a href="http://struts.apache.org/2.x/index.html">Struts2</a> és <a href="http://www.springsource.org">Spring</a> keretrendszerekkel, és egyszerűen formázható, programozható. Szerettem volna azonban kicsit többet, mint amit tud, mégpedig ha részletes adatokat tudna megjeleníteni egy legördülő sorban <a href="http://jquery.com">jQuery</a> segítségével. Ez arra jó, ha egy sorban nem szeretnénk minden adatot bezsúfolni, mert nem mindig érdekli a felhasználót, de azért néha szeretné megtekinteni a részletes adatokat.</p>
<p><span id="more-33"></span></p>
<p>Tegnap megvalósítottam az ötletet. A feladat egy olyan jQuery plugin létrehozása volt, amely úgy tudja a detail megjelenítést megoldani, hogy ne kelljen a displaytag forrásába belepiszkálni. Ez elsőre azért tűnt bonyolultnak, mert általában az ilyen megjelenítők úgy oldják meg a feladatot, hogy már eleve legenerálnak egy plusz, nem látható sort a táblázatba, ami akkor válik láthatóvá, ha megnyomjuk a részletek megjelenítésére szolgáló ikont. Végül sikerült egy olyan plugint létrehozni, ami nem csak a displaytag könyvtárral működik együtt, hanem egy tetszőleges táblázattal, így bármely olyan kész komponenssel használható, amibe nem tudunk vagy nem szeretnénk belehekkelni egy plusz TR-t.</p>
<p>Ha nem érdekel a leírás, innen letöltheted a plugint: <a href="http://codeplay.hu/wp-content/uploads/2010/09/jquery.displaytagdetail.zip">jquery.displaytagdetail.zip</a></p>
<h3>Displaytag felhasználásával</h3>
<p>Az alapot egy displaytag definíció szolgálja a JSP fájlban. Így néz ki általában:</p>
<pre class="brush:xml">&lt;display:table name="paginatedList" id="auditlogList" sort="external" requestURI="auditlogList.action"&gt;
  &lt;display:setProperty name="pagination.sort.param" value="paginatedList.sortCriterion" /&gt;
  &lt;display:setProperty name="pagination.sortdirection.param" value="paginatedList.sortDirectionName" /&gt;
  &lt;display:setProperty name="pagination.pagenumber.param" value="paginatedList.pageNumber" /&gt;
  &lt;display:column sortable="true" property="idAuditlog" title="id"/&gt;
  &lt;display:column sortable="true" property="creationTime" title="Időpont"/&gt;
  &lt;display:column sortable="true" property="priority" title="Prioritás"/&gt;
  &lt;display:column sortable="true" property="username" title="Felhasználó"/&gt;
&lt;/display:table&gt;
</pre>
<h3>HTML táblázat</h3>
<p>A fentebbi tag a következő HTML kódot generálja le, de ez előállítható akár PHP-ból is</p>
<pre class="brush: xml;">&lt;table id="auditlogList"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;User&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2010-07-02 13:27:07.0&lt;/td&gt;
&lt;td&gt;NORMAL&lt;/td&gt;
&lt;td&gt;root@valami-asdf.hu&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2010-07-02 14:04:28.0&lt;/td&gt;
&lt;td&gt;NORMAL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</pre>
<h3>jQuery plugin</h3>
<p>Létrehoztam a <strong>displaytagdetail</strong> plugin forrását, amit aztán Javascript-ként beillesztettem az oldal forrásába.</p>
<pre class="brush: js">jQuery.fn.displaytagdetail = function(button, detailClass, imgUp, imgDown, speed) {
		$(this).find(button).click( function() {
			tr = $(this).parents("tr");
			if (tr.next().hasClass(detailClass)) {
				tr.next().find("div").slideUp(function() {
					tr.next().remove();
				  });
				$(this).find("img:first").attr("src",imgDown);
			} else {
				tr.after("&lt;tr class='" + detailClass + "'&gt;&lt;td colspan=1000&gt;&lt;div style='display:none'&gt;" +
						$(this).next("div").html() +
						"&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;");
				tr.next().addClass(tr.attr("class"));
				$(this).find("img:first").attr("src",imgUp);
				tr.next().find("div").slideDown(speed);
			}
		});
	};
</pre>
<p>Paraméterként a következőket kell megadni:</p>
<ul>
<li>A detail gomb class neve (‘.’-el kezdőtik)</li>
<li>A detail div osztálya</li>
<li>Záró ikon</li>
<li>Nyitó ikon</li>
<li>Animáció sebessége</li>
</ul>
<p>Példa jQuery hívás:</p>
<pre class="brush: js">	&lt;script type="text/javascript"&gt;
		$(function() {
			$("#auditlogList").displaytagdetail(".detail_button","detail","images/arrow_up.png","images/arrow_down.png","slow");
		});
	&lt;/script&gt;
</pre>
<h3>Módosított displaytag a JSP-ben</h3>
<p>A tag-ben létrehoztam egy plusz oszlopot, ami tartalmazza a részleteket tartalmazó div-et és a lenyitó gombot</p>
<pre class="brush:xml" style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">&lt;display:table name="paginatedList" id="auditlogList" sort="external" requestURI="auditlogList.action"&gt;
  &lt;display:setProperty name="pagination.sort.param" value="paginatedList.sortCriterion" /&gt;
  &lt;display:setProperty name="pagination.sortdirection.param" value="paginatedList.sortDirectionName" /&gt;
  &lt;display:setProperty name="pagination.pagenumber.param" value="paginatedList.pageNumber" /&gt;
  &lt;display:column&gt;
    &lt;a&gt;&lt;img src="images/arrow_down.png"/&gt;&lt;/a&gt;
    &lt;div style="display:none"&gt;
      &lt;strong&gt;Komponens:&lt;/strong&gt;&lt;br/&gt;
      ${auditlogList.component}&lt;br/&gt;&lt;br/&gt;
      &lt;strong&gt;Log:&lt;/strong&gt;&lt;br/&gt;
      ${auditlogList.log}
    &lt;/div&gt;
  &lt;/display:column&gt;
  &lt;display:column sortable="true" property="idAuditlog" title="id"/&gt;
  &lt;display:column sortable="true" property="creationTime" title="Időpont"/&gt;
  &lt;display:column sortable="true" property="priority" title="Prioritás"/&gt;
  &lt;display:column sortable="true" property="username" title="Felhasználó"/&gt;
&lt;/display:table&gt;</pre>
<h3>Módosított HTML táblázat</h3>
<p>A részleteket tartalmazó generált táblázat így néz ki.</p>
<pre class="brush: xml">
<div id="_mcePaste">&lt;table id="auditlogList"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &lt;/th&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;User&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a&gt;&lt;img src="images/arrow_down.png" alt="" /&gt;&lt;/a&gt;
&lt;div style="display: none;"&gt;
&lt;strong&gt;Komponens:&lt;/strong&gt;
admin.UserBo.getUserByEmailForLogin
&lt;strong&gt;Log:&lt;/strong&gt;
java.lang.String=root
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2010-07-02 13:27:07.0&lt;/td&gt;
&lt;td&gt;NORMAL&lt;/td&gt;
&lt;td&gt;root&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a&gt;&lt;img src="images/arrow_down.png" alt="" /&gt;&lt;/a&gt;
&lt;div style="display: none;"&gt;
&lt;strong&gt;Komponens:&lt;/strong&gt;
admin.UserRequestBo.saveUserRequest
&lt;strong&gt;Log:&lt;/strong&gt;
Log entry
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2010-07-02 14:04:28.0&lt;/td&gt;
&lt;td&gt;NORMAL&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</div>
</pre>
<h3>Végül</h3>
<p>Ha mindent jól csináltunk, akkor a táblázatunkban lenyitható és bezárható egy sor a kis ikonnal.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2010/07/displaytag-detail-megjelenites-jquery-vel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android és adatbázis</title>
		<link>http://codeplay.hu/developer/2010/05/android-es-adatbazis/</link>
		<comments>http://codeplay.hu/developer/2010/05/android-es-adatbazis/#comments</comments>
		<pubDate>Sat, 22 May 2010 22:55:14 +0000</pubDate>
		<dc:creator>kepes</dc:creator>
				<category><![CDATA[Szoftverfejlesztés]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Mobil]]></category>

		<guid isPermaLink="false">http://codeplay.hu/?p=31</guid>
		<description><![CDATA[Előző bejegyzésekben már írtam a HTC Desire felhasználhatóságáról, tapasztalataimról, mint end-user. Mivel szoftverfejlesztőként is érdekelt a telefon és az Android, ezért amint megvolt a készülék, azonnal elkezdtem nézni az Android SDK-t. Elsőként szerettem volna egy egyszerű kis alkalmazást összerakni, amely tartalmaz beviteli mezőket, és egy listát, ahol a már felvitt elemek módosíthatók. A lista természetesen [...]]]></description>
			<content:encoded><![CDATA[<p>Előző bejegyzésekben már írtam a HTC Desire felhasználhatóságáról, tapasztalataimról, mint end-user. Mivel szoftverfejlesztőként is érdekelt a telefon és az Android, ezért amint megvolt a készülék, azonnal elkezdtem nézni az <a href="http://developer.android.com">Android SDK</a>-t. Elsőként szerettem volna egy egyszerű kis alkalmazást összerakni, amely tartalmaz beviteli mezőket, és egy listát, ahol a már felvitt elemek módosíthatók.<span id="more-31"></span></p>
<p>A lista természetesen legyen a tapifonokon már megszokott szépen gördíthető lista, a beviteli képernyő standard beviteli mezőkből álljon össze. Egy ilyen alkalmazás leírását a <a href="http://developer.android.com">Developer portál </a>elég jól leírja a <a href="http://developer.android.com/guide/index.html">Guideokban </a>erre nem térek most ki. Ami szerintem egy kicsit elbonyolított, és nem épp lényegre törő rész ebben az útmutatóban az az <a href="http://developer.android.com/guide/topics/data/data-storage.html">adatok tárolása</a>, ezen belül is az Androidba beépített <a href="http://www.sqlite.org">SQLite</a> adatbázis kezelő <a href="http://developer.android.com/guide/topics/data/data-storage.html#db">leírása</a>. Ezt egy külön részben tovább boncolgatja a <a href="http://developer.android.com/resources/tutorials/notepad/index.html">Notepad tutorial</a>, de itt sajnos már belekeverik a <a href="http://developer.android.com/guide/topics/providers/content-providers.html">Content Provider</a>-eket is, így nem kapunk kellő instrukciót, hogyan is kellene használni az adatbázist.</p>
<p>A neten található leírások általában azt a módszert erőltetik, hogy a <a href="http://developer.android.com/reference/android/database/Cursor.html">Cursor</a> objektumon végig iterálva, vagy azt felhasználva a <a href="http://developer.android.com/reference/android/widget/ListView.html">ListView </a>objektumhoz a <a href="http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html">SimpleCursorAdatpter</a> segítségével kezeljük mi az adatbázis kapcsolatot, a kurzort és az ezzel járó minden nyűgös dolgot. Ez nekem nem igazán tetszett, hiszen a Java világában már jópár éve létezik az <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> technika, amit általában egy J2EE alkalmazásban a <a href="http://www.hibernate.org/">Hibernate</a>-el szoktunk használni (vagy <a href="http://java.sun.com/developer/technicalArticles/J2EE/jpa/">JPA</a> kinek mi tetszik). Így nincs szükség az adatbázis kapcsolat közvetlen kezelésér, kurzorok bezárogatására, adatbázis kivételek kezelésére. Bánatomra a Hibernate és a JPA nem tűnik jó megoldásnak Android alatt, mert a Hibernate nem kezeli megfelelően az SQLite-ot, és különben is miért lövünk ágyúval verébre?</p>
<p>Így arra gondoltam, ORM technikát nem felejtem el, de az itt felmerülő igényeknek megfelelően alakítom ki. Amit meghatároztam igényként:</p>
<ul>
<li>Lightweight megoldás, lehetőleg J2EE technológiák nélkül</li>
<li>Az alkalmazás felületének és üzelti logikájának elkülönítése az adatbázistól</li>
<li>Az adatbázis POJO objektumokon keresztül reprezentált</li>
</ul>
<p>Nem tűnik nagy feladatnak, mégis sokat segít majd később. Elsőként kitaláltam egy alkalmazást. Mindig is szerettem a helyzetmeghatározással foglalkozni, tároljunk hát térkép pontokat adatbázisban.</p>
<p>A tábla szerkezete:</p>
<ul>
<li>id</li>
<li>név</li>
<li>szélesség</li>
<li>hosszúság</li>
<li>magasság</li>
</ul>
<p>Az adatbázis műveletekhez létrehoztam egy <a href="http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html">SQLiteOpenHelper </a>osztályt a <a href="http://developer.android.com/guide/topics/data/data-storage.html#db">developer portálon megfogalmazottak</a> szerint:</p>
<pre class="brush: java">public class DatabaseHelper extends SQLiteOpenHelper {

private static final String TAG = "DatabaseHelper";
private static final String DATABASE_NAME = "mydatabase.db";
private static final int DATABASE_VERSION = 1;

public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + MapPoint.TABLE_NAME + " (" +
MapPoint._ID + " integer primary key," +
MapPoint.NAME + " text," +
MapPoint.LATITUDE + " real," +
MapPoint.LONGTITUDE + " real," +
MapPoint.ALTITUDE + " integer);");
}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

Log.w(TAG, "Upgrading database from version " + oldVersion + " to "

+ newVersion + ", which will destroy all old data");

db.execSQL("DROP TABLE IF EXISTS mappoint");

onCreate(db);

}

}
</pre>
<p>Az osztályból látszik, hogy szükséges egy MapPoint nevű osztály. Az ORM-ben ez az osztály lesz a Model osztályom. Így néz ki:</p>
<pre class="brush: java">public class MapPoint implements BaseColumns {

 public static String NAME = "name";
 public static String LATITUDE = "latitude";
 public static String LONGTITUDE = "longtitude";
 public static String ALTITUDE = "altitude";

 public static String TABLE_NAME = "mappoint";

 public static final String DEFAULT_SORT_ORDER = "name";

 private Long _id;
 private String name;
 private Double latitude;
 private Double longtitude;
 private Integer altitude;

 public Long get_id() {
 return _id;
 }
 public void set_id(Long _id) {
 this._id = _id;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public Double getLatitude() {
 return latitude;
 }
 public void setLatitude(Double latitude) {
 this.latitude = latitude;
 }
 public Double getLongtitude() {
 return longtitude;
 }
 public void setLongtitude(Double longtitude) {
 this.longtitude = longtitude;
 }
 public Integer getAltitude() {
 return altitude;
 }
 public void setAltitude(Integer altitude) {
 this.altitude = altitude;
 }
}
</pre>
<p>A Model osztály az Adroidos <a href="http://developer.android.com/reference/android/provider/BaseColumns.html">BaseColumn</a>-ból származik, ami miatt egy _ID nevű mező van definiálva benne. Ez azért jó, mert ilyen mezője minden SQLite adatbázs táblának kell legyen, és így nem kell külön foglalkozni vele.<br />
 A Model osztályban nem biztos, hogy jó helyen vannak a statikus tulajdonságok, de egyelőre itt hagyom őket. Ezeket a Notepad tutorial a ContentProvider-be rakja, de nekünk ilyenünk nem lesz.</p>
<p>Végül a legfontosabb elem, a DAO osztály következik. Ez az osztály intézi el végül is az ORM-et, lekéri az adatbázisból a rekordokat, map-eli őket a Model osztályba, jelen esetben a MapPoint-be.</p>
<pre class="brush: java">public class MapPointDao {

 private DatabaseHelper databaseHelper;

 public MapPointDao(Context context) {
 this.databaseHelper = new DatabaseHelper(context);
 }

 public int deleteById(long id) {
 return -1;
 }

 public long insert(MapPoint mapPoint) {
 ContentValues values = new ContentValues();
 values.put(MapPoint.NAME, mapPoint.getName());
 values.put(MapPoint.LATITUDE, mapPoint.getLatitude());
 values.put(MapPoint.LONGTITUDE, mapPoint.getLongtitude());
 values.put(MapPoint.ALTITUDE, mapPoint.getAltitude());

 SQLiteDatabase db = databaseHelper.getWritableDatabase();        

 long rowId = db.insertOrThrow(MapPoint.TABLE_NAME, MapPoint.NAME, values);
 db.close();

 if (rowId &gt; 0) {
 return rowId;
 }

 throw new SQLException("Failed to insert row into ");
 }

 public List find(boolean distinct, String[]  columns,
 String  selection, String[]  selectionArgs, String  groupBy, String  having,
 String  orderBy, String  limit) {

 MapPoint mapP = new MapPoint();
 mapP.set_id(new Long(1));
 mapP.setAltitude(new Integer(2));
 mapP.setLongtitude(new Double(200));

 findByExample(mapP);

 if (TextUtils.isEmpty(orderBy)) {
 orderBy = MapPoint.DEFAULT_SORT_ORDER;
 }

 SQLiteDatabase db = databaseHelper.getReadableDatabase();
 Cursor c = db.query(distinct, MapPoint.TABLE_NAME, columns, selection, selectionArgs, groupBy, having,
 orderBy, limit);

 List list = new ArrayList();

 while (c.moveToNext()) {
 MapPoint mapPoint = new MapPoint();

 mapPoint.set_id(c.getLong(c.getColumnIndex(MapPoint._ID)));
 mapPoint.setName(c.getString(c.getColumnIndex(MapPoint.NAME)));
 mapPoint.setAltitude(c.getInt(c.getColumnIndex(MapPoint.ALTITUDE)));
 mapPoint.setLatitude(c.getDouble(c.getColumnIndex(MapPoint.LATITUDE)));
 mapPoint.setLongtitude(c.getDouble(c.getColumnIndex(MapPoint.LONGTITUDE)));

 list.add(mapPoint);
 }
 c.close();
 db.close(); 

 return list;
 }

 public List find(String  selection, String[]  selectionArgs) {
 return find(false,null,selection, selectionArgs, null, null, null, null);
 }

 public List findAll() {
 return find(null,null);
 }

 public int update(MapPoint mapPoint) {
 return -1;
 }

 public List&lt;Map&lt;String, String&gt;&gt; convertForAdapter(List&lt;MapPoint&gt; mapPointList) {
 List&lt;Map&lt;String, String&gt;&gt; list = new ArrayList&lt;Map&lt;String, String&gt;&gt;();
 for (int i=0; i&lt;mapPointList.size(); i++) {
 Map&lt;String, String&gt; map = new HashMap&lt;String, String&gt;();

 map.put(MapPoint._ID, String.valueOf(mapPointList.get(i).get_id()));
 map.put(MapPoint.NAME, mapPointList.get(i).getName());
 map.put(MapPoint.LATITUDE, String.valueOf(mapPointList.get(i).getLatitude()));
 map.put(MapPoint.LONGTITUDE, String.valueOf(mapPointList.get(i).getLongtitude()));
 map.put(MapPoint.ALTITUDE, String.valueOf(mapPointList.get(i).getAltitude()));
  list.add(map);
 }
 return list;
 }
}
</pre>
<p>A DAO osztály-t nem fejeztem be, csak a find() és insert() metódusokat programoztam le, a delete() és update() mindeninek házi feladat <img class="wp-smiley" src="http://codeplay.hu/wp-includes/images/smilies/icon_smile.gif" alt=":)" /> . Az igazság az, hogy már most rájöttem ez nem egészen lesz így jó, mert a DAO osztályt így minden adatbázis táblára létre kell hoznom, minden mezőt egyesével map-elni kell. Nem szeretem az ilyet.</p>
<p>A DAO minden lekérdező metódusa a Model osztályt, vagy az ebből generált lista objektumot adja vissza lekérdezésnél. A módosító metódusok általában azt adják vissza, mennyi rekord módosult, az insert() pedig az új rekord id-t.</p>
<p>Lényeges kiemelni a DAO osztály convertForAdapter() metódusát, ami a <a href="http://developer.android.com/reference/android/widget/SimpleAdapter.html">SimpleAdatpter </a>számára fog használható objektumstruktúrát előállítani. A find() által visszaadott List objektumból egy más struktúrájú listát állít elő, aminek az elemei már nem Model osztályok.</p>
<p>Végül lássuk, hogyan jelenik meg az Activity-ben a ListView. Az egész Activity-t nem másolom ide be, csak egyes részeit.</p>
<pre class="brush: java"> private ListView listMapPoints;

 private List mapPointList;
 private MapPointDao mapPointDao;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);

 this.listMapPoints = (ListView) findViewById(R.id.listMapPoints);

 mapPointDao = new MapPointDao(this);                

 refreshList();
 }

 private void refreshList() {
 mapPointList = mapPointDao.findAll();

 int[] i = { R.id.textName, R.id.textDesc };
 String[] s = { "name", "_id" };

 this.listMapPoints.setAdapter(
 new SimpleAdapter(this, mapPointDao.convertForAdapter(mapPointList),
 R.layout.pointlistitem,s,i));
 }
</pre>
<p>Először az onCreate()-ben kikeressük a ListView objektumot a layout fájlból, majd létrehozzuk a DAO-t. A refreshList() metódusban programoztam le az lista elemek lekérdezését, mert így a refresh esetleg máshonnan is meghívható. Például egy dialógus ablakot definiálhatunk, ami törölni tud lista elemeket, és a törlés után jó ha a lista frissül.</p>
<h3>Miért jó?</h3>
<ul>
<li>Szerintem elég lightweight lett, nem igényel külső lib-et</li>
<li>Az adatbázis kezelés a program egyetlen pontján van, nem kell az Activity-ben foglalkozni a kurzorral</li>
<li>POJO osztályok</li>
<li>Elkülönül az üzleti logika, a megjelenítés és a perzisztencia réteg (MVC)</li>
</ul>
<h3>Problémák</h3>
<p>Természetesen ezzel nem állítottam elő egy Hibernate funkcionalitású ORM-et. A fentebbi programban elférnének a következő kiegészítések:</p>
<ul>
<li>A DAO egyes metódusainak paraméterezése történhetne Model osztállyal, így szűrőket lehetne megadni. Például findByExample(Model model) vagy deleteByExample(Model model)</li>
<li>Jó lenne a DAO-t generikusra megírni, hogy ne kelljen mindig a mapeléseket megírni</li>
<li>A DatabaseHelper az adatbázis szkriptet betölthetné külső fájlból vagy resource-ból</li>
<li>A DAO-ban az adatbázis kapcsolatokat nem kellene mindig bezárni, egyszer kéne a konstruktorban létrehozni, és a nyitottat használni</li>
<li>Jó lenne megoldani a foreign key-ek kezelését a Model-ben és a DAO-ban, hogy ne kelljen többször bekérdezni, ha például egy lista több táblából épül fel.</li>
<li>Hibakezelés és logolás</li>
</ul>
<p>Tovább fogom fejleszteni kis alkalmazásomat, így a fentebbi problémákra megoldást fogok kidolgozni, amit hasonló módon publikálni fogok.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeplay.hu/developer/2010/05/android-es-adatbazis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

