<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4809200280367588708</id><updated>2011-11-23T18:34:18.434+01:00</updated><category term='activeldap'/><category term='tapestry 5'/><category term='firebug'/><category term='actor'/><category term='open source'/><category term='unix file permissions'/><category term='e17'/><category term='presentation'/><category term='shjs'/><category term='firefox'/><category term='spring3'/><category term='ldap'/><category term='unboundid'/><category term='ivy'/><category term='haskell'/><category term='xpath'/><category term='sun'/><category term='javassist'/><category term='xsplash'/><category term='apacheds'/><category term='xml'/><category term='_'/><category term='scala'/><category term='research'/><category term='java'/><category term='personal'/><category term='karmic koala'/><category term='openworldforum'/><category term='no-commons-logging'/><category term='syncrepl'/><category term='pom'/><category term='meeting'/><category term='autocomplete'/><category term='slf4j'/><category term='scaladays'/><category term='oracle'/><category term='rest'/><category term='comet'/><category term='annotation'/><category term='build'/><category term='groovy'/><category term='coq'/><category term='rfc4533'/><category term='project euler'/><category term='personal thought'/><category term='dsl'/><category term='easyant'/><category term='underscore'/><category term='ubuntu'/><category term='liftweb'/><category term='password'/><category term='xstream'/><title type='text'>Fanf's blog</title><subtitle type='html'>A blog about Scala, Java ecosystem and personal stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>53</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3192145527498208644</id><published>2011-11-17T17:45:00.000+01:00</published><updated>2011-11-17T17:45:00.985+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='password'/><category scheme='http://www.blogger.com/atom/ns#' term='autocomplete'/><category scheme='http://www.blogger.com/atom/ns#' term='firebug'/><title type='text'>Make firefox remember "autocomplete=off" password fields</title><content type='html'>Some site thinks that they better know than us what is security. For example, they want to prevent us to make firefox remember the login/password for them, and in the sametime, they don't allow to use a 30 char passphrase (because it does not contain a symbol, but six "!" is ok...).&lt;br /&gt;&lt;br /&gt;If, like me, you are finding that behaviour as irrespectuous of your browsing experience as, say pop-ups, there is a trick:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;install &lt;a href="https://addons.mozilla.org/fr/firefox/addon/firebug/"&gt;Firebug &lt;/a&gt;&lt;/li&gt;&lt;li&gt;on the page with the faulty password field, open Firebug.&lt;/li&gt;&lt;li&gt;use the blue mouse pointer in Firebug toolbar to select the password field&lt;/li&gt;&lt;li&gt;on the Firebug HTML tab, you should have a &amp;lt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;&lt;span class="nodeTag "&gt;input&lt;/span&gt;&lt;span class="nodeAttr editGroup "&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="nodeAttr editGroup "&gt; &lt;span class="nodeName editable "&gt;type&lt;/span&gt;="&lt;span class="nodeValue editable "&gt;password&lt;/span&gt;"&lt;/span&gt;&lt;span class="nodeAttr editGroup "&gt; &lt;/span&gt;&lt;span class="nodeAttr editGroup "&gt;&lt;span class="nodeName editable "&gt;autocomplete&lt;/span&gt;="&lt;span class="nodeValue editable "&gt;off&lt;/span&gt;"&lt;/span&gt;&lt;span class="nodeAttr editGroup "&gt;&lt;/span&gt;....&amp;gt; field selected&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;double-click on "off" to edit the value and change it to "on".&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;Now, enter you login/password as usual in the page form&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;when you hit "submit", Firefox should display the notification pop-up that allows to remember the login/password for that site.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;&amp;nbsp;Now, each time you are going to go on that page, firefox will autocomplete&amp;nbsp; the login/password as usual.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nodeLabelBox repTarget " role="treeitem"&gt;&lt;br /&gt;Hop it will help other !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3192145527498208644?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3192145527498208644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3192145527498208644' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3192145527498208644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3192145527498208644'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2011/11/make-firefox-remember-autocompleteoff.html' title='Make firefox remember &quot;autocomplete=off&quot; password fields'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-7082545921420332255</id><published>2011-02-06T00:37:00.000+01:00</published><updated>2011-02-06T00:37:35.078+01:00</updated><title type='text'>Installing ZeroMQ and Java bindings on Ubunu 10.10</title><content type='html'>For some times now, I'm following the slow evolution of &lt;a href="http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol"&gt;AMQP&lt;/a&gt; toward it's 1.0 release. In the trip, one traveler decided that the road was far too long, and complex, and choosed to take its independence: &lt;a href="http://www.zeromq.org/"&gt;ZeroMQ&lt;/a&gt; is living its own adventure for some times now. And their choices are intersting, really focused and sharp, so I needed to see what can be done with that message system, and a bit of Scala.&lt;br /&gt;&lt;br /&gt;So the first part was to install ZeroMQ and its &lt;a href="http://www.zeromq.org/bindings:java"&gt;Java binding&lt;/a&gt; into my computer, a Linux Ubuntu 10.10. It was quite easy, but as I didn't find a single post for the whole thing, I write that one as a memo, when in some days I will try to do it again and won't be able to remind the precise steps :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Step 1: install recent ZeroMQ libraries&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Before playing with some code, you need to install ZeroMQ libraries on your system. That library is on Ubuntu 10.10, but a more recent version seems to be needed for Java bindings. That's not a problem as some good will has made a &lt;a href="https://launchpad.net/%7Echris-lea/+archive/zeromq"&gt;PPA repository&lt;/a&gt; for them:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;% sudo add-apt-repository ppa:chris-lea/zeromq&lt;/pre&gt;&lt;pre&gt;% sudo aptitude install libzmq-dev&lt;/pre&gt;&lt;br /&gt;That should install libzmq-dev (header files needed for the Java bindings) and the libzmq0 package - the core messaging system itself.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Step 2: get ZeroMQ binding&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For that, you will have to clone &lt;a href="https://github.com/zeromq/jzmq/"&gt;the github repository&lt;/a&gt; of the project&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;% git clone https://github.com/zeromq/jzmq.git&lt;/pre&gt;&lt;br /&gt;And with that, you have a new jzmq directory with everything needed to build the Java bindings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Step 3: build and install jzmq package&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We are on a Debian based distribution, and ZeroMQ guys have the good taste to provide all what is needed to build a .deb for JZMQ, so let's just use the good work.&lt;br /&gt;In the former jzmq directory, just do:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;% ./autogen.sh&lt;/pre&gt;&lt;pre&gt;% dpkg-buildpackage -rfakeroot&lt;/pre&gt;&lt;br /&gt;And that's it. If all goes well, you should have a "jzmq_[some-version]_i386.deb" package on the parent directory of the one you are in. Just install it as usual:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;% dpkg -i jzmq_[some-version]_i386.deb&lt;/pre&gt;&lt;br /&gt;And now, you can use ZQM from you Java code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Some last notes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* don't forget to add the JNI library path in you JVM command line: use &lt;b&gt;-Djava.library.path=/usr/lib&lt;/b&gt;&lt;br /&gt;(/usr/lib should contains libjzmq.so, you can see it with &lt;b&gt;dpkg -L jzmq&lt;/b&gt;)&lt;br /&gt;If you the JAVA_HOME environment variable was correctly set when you buit the package,you may not have to add that parameter.&amp;nbsp;&lt;br /&gt;* libjzmq.jar is in &lt;b&gt;/usr/share/java/&lt;/b&gt;&lt;br /&gt;* you will find some Java examples &lt;a href="https://github.com/imatix/zguide/tree/master/examples/Java"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;That's it! Enjoy a world of easy message distribution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-7082545921420332255?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/7082545921420332255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=7082545921420332255' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7082545921420332255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7082545921420332255'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2011/02/installing-zeromq-and-java-bindings-on.html' title='Installing ZeroMQ and Java bindings on Ubunu 10.10'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-7468260263863186276</id><published>2011-01-31T10:45:00.000+01:00</published><updated>2011-01-31T10:45:11.411+01:00</updated><title type='text'>Martin Odersky au Paris Scala User Group le 31 janvier</title><content type='html'>&amp;nbsp;Après pas mal de temps en sommeil, je réveille ce blog pour faire suivre cette annonce: Martin Odersky, le papa de &lt;a href="http://scala-lang.org/"&gt;Scala&lt;/a&gt;, fera une présentation au &lt;a href="https://groups.google.com/group/paris-scala-user-group/about?hl=en&amp;amp;noredirect=true"&gt;Paris Scala User Group&lt;/a&gt;, ce lundi 31 janvier. Plus de détails sont disponibles &lt;a href="http://blog.xebia.fr/2011/01/21/martin-odersky-invite-du-psug/"&gt;ici&lt;/a&gt; et &lt;a href="https://groups.google.com/d/topic/paris-scala-user-group/ws2ozp-MTjU/discussion"&gt;ici&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;J'en profite pour relayer l'information du &lt;a href="http://www.scala-lang.org/node/8579"&gt;financement à hauteur de 2.3 Million d'Euros sur 5 ans de Scala par l'Europe&lt;/a&gt;, ce qui devrait permettre de lever les dernières incertitudes quant à la pérénité du langage.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-7468260263863186276?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/7468260263863186276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=7468260263863186276' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7468260263863186276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7468260263863186276'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2011/01/martin-odersky-au-paris-scala-user.html' title='Martin Odersky au Paris Scala User Group le 31 janvier'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2620727733587015471</id><published>2010-11-09T20:19:00.000+01:00</published><updated>2010-11-09T20:19:59.337+01:00</updated><title type='text'>Scala 2.8.1 is out!</title><content type='html'>After a far shorter development cycle than for 2.8.0, &lt;a href="http://www.scala-lang.org/node/8102"&gt;Scala 2.8.1&lt;/a&gt; reach us today.&lt;br /&gt;&lt;br /&gt;More than 100 bugs were corrected, some of them really old (&lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/36"&gt;#36&lt;/a&gt; !).&lt;br /&gt;&lt;br /&gt;The great thing with that release is that for the first time ever, it is fully binary compatible with the previous one, Scala 2.8.0. With that and the creation of &lt;a href="http://scalasolutions.com/"&gt;Scala Solution&lt;/a&gt; company, it seems to be really good insights toward Scala industrialization in the coming years.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2620727733587015471?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2620727733587015471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2620727733587015471' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2620727733587015471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2620727733587015471'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/11/scala-281-is-out.html' title='Scala 2.8.1 is out!'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-6791470209467298776</id><published>2010-07-27T17:03:00.000+02:00</published><updated>2010-07-27T17:03:41.916+02:00</updated><title type='text'>Set-up Eclipse workspace in RAM</title><content type='html'>I just published an article about how to set-up your Eclipse workspace in RAM to make I/O (almost) instantaneous. It was promised in the &lt;a href="http://blog.normation.com/2010/05/24/optimizing-eclipse-performances/"&gt;"Eclipse perfomance optimisation article&lt;/a&gt;", and now it's here: &lt;a href="http://blog.normation.com/2010/07/27/set-up-eclipse-workspace-in-ram/"&gt;http://blog.normation.com/2010/07/27/set-up-eclipse-workspace-in-ram/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And like last time, any information about Eclipse optimization is much appreciated !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-6791470209467298776?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/6791470209467298776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=6791470209467298776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6791470209467298776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6791470209467298776'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/07/set-up-eclipse-workspace-in-ram.html' title='Set-up Eclipse workspace in RAM'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2269305627368058659</id><published>2010-07-18T19:49:00.000+02:00</published><updated>2010-07-18T19:49:07.957+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apacheds'/><category scheme='http://www.blogger.com/atom/ns#' term='comet'/><category scheme='http://www.blogger.com/atom/ns#' term='liftweb'/><category scheme='http://www.blogger.com/atom/ns#' term='rfc4533'/><category scheme='http://www.blogger.com/atom/ns#' term='syncrepl'/><category scheme='http://www.blogger.com/atom/ns#' term='ldap'/><category scheme='http://www.blogger.com/atom/ns#' term='unboundid'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Java LDAP SDK for SyncRepl replication showcase</title><content type='html'>&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;I just published a post on my company blog about how to implement a SyncRepl client using two different Java LDAP SDK, Apache DS and UnboundID:&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;a href="http://blog.normation.com/2010/07/18/java-ldap-sdk-for-syncrepl-replication-showcase/"&gt;http://blog.normation.com/2010/07/18/java-ldap-sdk-for-syncrepl-replication-showcase/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;SyncRepl is a replication protocol for LDAP, normalized in RFC 4533. &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;The demonstration is done with a showcase web application that display in real time modification done in an LDAP server.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;The application, named Syweno, was developed in Scala, thanks to Liftweb and it's amazing Comet. It looks like:&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_9D3n-ZqzF48/TEMDGz0H8TI/AAAAAAAABHA/_VTGVmDEeAI/s1600/syweno-main.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="435" src="http://4.bp.blogspot.com/_9D3n-ZqzF48/TEMDGz0H8TI/AAAAAAAABHA/_VTGVmDEeAI/s640/syweno-main.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Of course, update are synchronized thank to SyncRepl, and are propagated to the web page in real time thanks to Comet updates.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The code source is available on github here: &lt;a href="http://github.com/fanf/syweno"&gt;http://github.com/fanf/syweno&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enjoy !&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2269305627368058659?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2269305627368058659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2269305627368058659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2269305627368058659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2269305627368058659'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/07/java-ldap-sdk-for-syncrepl-replication.html' title='Java LDAP SDK for SyncRepl replication showcase'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9D3n-ZqzF48/TEMDGz0H8TI/AAAAAAAABHA/_VTGVmDEeAI/s72-c/syweno-main.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3594780782801051597</id><published>2010-07-14T21:07:00.000+02:00</published><updated>2010-07-14T21:07:18.664+02:00</updated><title type='text'>Scala 2.8.0 is out</title><content type='html'>The most awaited Scala version of all time (ok, it's easy for now...) is out, at last !&lt;br /&gt;&lt;br /&gt;Congratulation to every body who contributed to make it happens, and long life to Scala post-2.8.0. After a brilliant childhood, perhaps it is time for the unruly teenager to quieten down a little and conquer the industrial world !&lt;br /&gt;&lt;br /&gt;The official link: &lt;br /&gt;&lt;a href="http://www.scala-lang.org/node/7009"&gt;http://www.scala-lang.org/node/7009&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3594780782801051597?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3594780782801051597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3594780782801051597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3594780782801051597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3594780782801051597'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/07/scala-280-is-out.html' title='Scala 2.8.0 is out'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3126328147216174469</id><published>2010-07-01T18:23:00.000+02:00</published><updated>2010-07-01T18:23:23.524+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='underscore'/><category scheme='http://www.blogger.com/atom/ns#' term='_'/><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala dreaded underscore @ PSUG</title><content type='html'>(orignal content from &lt;a href="http://blog.normation.com/2010/07/01/scala-dreaded-underscore-psug/"&gt;http://blog.normation.com/2010/07/01/scala-dreaded-underscore-psug&lt;/a&gt;&amp;nbsp; )&lt;br /&gt;&lt;br /&gt;On the evening of June 30th 2010, the &lt;a href="http://groups.google.com/group/paris-scala-user-group"&gt;Paris Scala User Group&lt;/a&gt; organized its second event.&lt;br /&gt;This time, there were two presentations:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;in the first one, Alexis Agahi, our kind user group leader, made a feedback after one year of scala experience. It’s &lt;a href="http://tinyurl.com/3xckpyf"&gt;available here&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;the second one was given by your servitor, and deals with each and every use case of underscores in the Scala language – I hope I didn’t miss any.&lt;br /&gt;It’s &lt;a href="http://www.slideshare.net/normation/scala-dreaded"&gt;available here&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;See you next time on PSUG!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3126328147216174469?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3126328147216174469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3126328147216174469' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3126328147216174469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3126328147216174469'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/07/scala-dreaded-underscore-psug.html' title='Scala dreaded underscore @ PSUG'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8447629002542452095</id><published>2010-05-24T13:24:00.000+02:00</published><updated>2010-05-24T13:24:10.723+02:00</updated><title type='text'>Optimizing Eclipse performances</title><content type='html'>I just published an article about Eclipse perfomance optimisation, especially with the Scala IDE plugin, here : &lt;a href="http://blog.normation.com/2010/05/24/optimizing-eclipse-performances/"&gt;http://blog.normation.com/2010/05/24/optimizing-eclipse-performances/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This article mostly talk about generalities and gives some reference links about JVM tunning. It also contains some eclipse.ini examples, and point to reference topic on that subject.&lt;br /&gt;&lt;br /&gt;A second, more involved article in which I will explain how to put your workspace into ram (and keep it synchronizes to disk, of course) will follow in a couple of days (ok, perhaps packed in weeks, depending of my work...).&lt;br /&gt;&lt;br /&gt;Of course, any information about Eclipse optimization is much appreciated !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8447629002542452095?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8447629002542452095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8447629002542452095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8447629002542452095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8447629002542452095'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/05/optimizing-eclipse-performances.html' title='Optimizing Eclipse performances'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-5538287055295035645</id><published>2010-05-18T16:24:00.002+02:00</published><updated>2010-05-18T16:36:04.144+02:00</updated><title type='text'>Maven2 bootstrap pom.xml for Scala with SLF4J and no-commons-logging</title><content type='html'>Following an &lt;a href="http://fanf42.blogspot.com/2009/11/maven2-bootstrap-pomxml-for-slf4j-and.html"&gt;older post&lt;/a&gt;, this is the pom I use as a starting point for Scala project which uses maven.&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;project xmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot; xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;br /&gt; xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&amp;gt;&lt;br /&gt; &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;org.test&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;test&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;version&amp;gt;0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;properties&amp;gt;&lt;br /&gt;  &amp;lt;!-- UTF-8 for everyone --&amp;gt;&lt;br /&gt;  &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;!-- Other general properties --&amp;gt;&lt;br /&gt;  &amp;lt;slf4j-version&amp;gt;1.6.0&amp;lt;/slf4j-version&amp;gt;&lt;br /&gt;  &amp;lt;logback-version&amp;gt;0.9.20&amp;lt;/logback-version&amp;gt;&lt;br /&gt;  &amp;lt;scala-version&amp;gt;2.8.0.RC2&amp;lt;/scala-version&amp;gt;&lt;br /&gt;  &amp;lt;scala-maven-plugin-version&amp;gt;2.13.1&amp;lt;/scala-maven-plugin-version&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;description&amp;gt;&lt;br /&gt;  Starting pom&lt;br /&gt; &amp;lt;/description&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;repositories&amp;gt;&lt;br /&gt;  &amp;lt;repository&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;scala-tools.org&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;name&amp;gt;Scala-tools Maven2 Repository&amp;lt;/name&amp;gt;&lt;br /&gt;   &amp;lt;url&amp;gt;http://scala-tools.org/repo-releases&amp;lt;/url&amp;gt;&lt;br /&gt;  &amp;lt;/repository&amp;gt;&lt;br /&gt;  &amp;lt;repository&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;scala-snapshots.org&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;name&amp;gt;Scala-tools Maven2 Repository snapshots&amp;lt;/name&amp;gt;&lt;br /&gt;   &amp;lt;url&amp;gt;http://scala-tools.org/repo-snapshots&amp;lt;/url&amp;gt;&lt;br /&gt;  &amp;lt;/repository&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;repository&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;no-commons-logging&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;name&amp;gt;No-commons-logging Maven Repository&amp;lt;/name&amp;gt;&lt;br /&gt;   &amp;lt;layout&amp;gt;default&amp;lt;/layout&amp;gt;&lt;br /&gt;   &amp;lt;url&amp;gt;http://no-commons-logging.zapto.org/mvn2&amp;lt;/url&amp;gt;&lt;br /&gt;   &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;&lt;br /&gt;  &amp;lt;/repository&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;pluginRepositories&amp;gt;&lt;br /&gt;  &amp;lt;pluginRepository&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;scala-tools.org&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;name&amp;gt;Scala-tools Maven2 Repository&amp;lt;/name&amp;gt;&lt;br /&gt;   &amp;lt;url&amp;gt;http://scala-tools.org/repo-releases&amp;lt;/url&amp;gt;&lt;br /&gt;   &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;&lt;br /&gt;  &amp;lt;/pluginRepository&amp;gt;&lt;br /&gt;  &amp;lt;pluginRepository&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;scala-snapshots.org&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;name&amp;gt;Scala-tools Maven2 Repository snapshots&amp;lt;/name&amp;gt;&lt;br /&gt;   &amp;lt;url&amp;gt;http://scala-tools.org/repo-snapshots&amp;lt;/url&amp;gt;&lt;br /&gt;  &amp;lt;/pluginRepository&amp;gt;&lt;br /&gt; &amp;lt;/pluginRepositories&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;build&amp;gt;&lt;br /&gt;  &amp;lt;sourceDirectory&amp;gt;src/main/scala&amp;lt;/sourceDirectory&amp;gt;&lt;br /&gt;  &amp;lt;testSourceDirectory&amp;gt;src/test/scala&amp;lt;/testSourceDirectory&amp;gt;&lt;br /&gt;  &amp;lt;plugins&amp;gt;&lt;br /&gt;   &amp;lt;plugin&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;org.scala-tools&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;maven-scala-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;${scala-maven-plugin-version}&amp;lt;/version&amp;gt; &lt;br /&gt;    &amp;lt;executions&amp;gt;&lt;br /&gt;     &amp;lt;execution&amp;gt;&lt;br /&gt;      &amp;lt;goals&amp;gt;&lt;br /&gt;       &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;&lt;br /&gt;       &amp;lt;goal&amp;gt;testCompile&amp;lt;/goal&amp;gt;&lt;br /&gt;      &amp;lt;/goals&amp;gt;&lt;br /&gt;     &amp;lt;/execution&amp;gt;&lt;br /&gt;    &amp;lt;/executions&amp;gt;&lt;br /&gt;    &amp;lt;configuration&amp;gt;&lt;br /&gt;     &amp;lt;args&amp;gt;&lt;br /&gt;      &amp;lt;arg&amp;gt;-target:jvm-1.5&amp;lt;/arg&amp;gt;&lt;br /&gt;      &amp;lt;arg&amp;gt;-make:transitivenocp&amp;lt;/arg&amp;gt;&lt;br /&gt;      &amp;lt;arg&amp;gt;-dependencyfile&amp;lt;/arg&amp;gt;&lt;br /&gt;      &amp;lt;arg&amp;gt;${project.build.directory}/.scala_dependencies&amp;lt;/arg&amp;gt;&lt;br /&gt;     &amp;lt;/args&amp;gt;&lt;br /&gt;     &amp;lt;jvmArgs&amp;gt;&lt;br /&gt;      &amp;lt;jvmArg&amp;gt;-client&amp;lt;/jvmArg&amp;gt;&lt;br /&gt;      &amp;lt;jvmArg&amp;gt;-Xmx1G&amp;lt;/jvmArg&amp;gt;&lt;br /&gt;     &amp;lt;/jvmArgs&amp;gt;&lt;br /&gt;    &amp;lt;/configuration&amp;gt;&lt;br /&gt;   &amp;lt;/plugin&amp;gt;&lt;br /&gt;   &amp;lt;plugin&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;2.1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;source&amp;gt;1.6&amp;lt;/source&amp;gt;&lt;br /&gt;    &amp;lt;/configuration&amp;gt;&lt;br /&gt;   &amp;lt;/plugin&amp;gt;&lt;br /&gt;   &lt;br /&gt;  &amp;lt;/plugins&amp;gt;&lt;br /&gt; &amp;lt;/build&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;dependencies&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;org.scala-lang&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;scala-library&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;${scala-version}&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;joda-time&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;joda-time&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;1.6&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;!--  test --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;4.7&amp;lt;/version&amp;gt;&lt;br /&gt;   &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!--&lt;br /&gt;   All the following is related to our will to NOT use Commong-logging&lt;br /&gt;  --&amp;gt;&lt;br /&gt;  &amp;lt;!-- use no-commons-logging --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;99.0-does-not-exist&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;!-- no-commons-logging-api, if you need it --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;commons-logging-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;99.0-does-not-exist&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;!-- the slf4j commons-logging replacement --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;${slf4j-version}&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;!-- the other slf4j jars --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;${slf4j-version}&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;!-- using slf4j native backend --&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;logback-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;${logback-version}&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;   &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;   &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;&lt;br /&gt;   &amp;lt;version&amp;gt;${logback-version}&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt; &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-5538287055295035645?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/5538287055295035645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=5538287055295035645' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5538287055295035645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5538287055295035645'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/05/maven2-bootstrap-pomxml-for-scala-with.html' title='Maven2 bootstrap pom.xml for Scala with SLF4J and no-commons-logging'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-6193587528566497096</id><published>2010-04-19T16:17:00.001+02:00</published><updated>2010-04-20T15:15:47.644+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scaladays'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Summary of my Scala Days 2010</title><content type='html'>&lt;span style="font-size: x-large;"&gt;A great reception...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;I had the immense luck to go to theFirst &lt;a href="http://days2010.scala-lang.org/"&gt;ScalaDays&lt;/a&gt; event organized by EPFL in Lausanne on 15/16 of April 2010.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;It was an immense luck, because theevent was simply fabulous. And so, to begin, I really want to thanks the Scalateam, and especially Antonio Cunei for their amazing work oforganization: the welcome with the little kit with the little goodies and T-Shirt was a nice introduction, the food was really good, theboat trip and dinner on first day evening a really top-level dinner. &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Safe for a volcanic eruption in Icelandwhich disrupted flights all around Europe and so impacted a lot of attendees, it could have been nearperfection. &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;... with great talks ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;And that is just for the organization: presentations were at the same level. Most of them were really good, and the choice between two sessions not always easy. Fortunately, presentation were recorded, and so should soon become available in line (I listed presentation I went to at the end). One little reproach: some of them would have deserve more time than allowed here, but that is near to nothing.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://akkasource.org/"&gt; Akka&lt;/a&gt; presentation was somehow special. Jonas Boner and the Akka team did an amazing work in nomore than a year, from “just an other actor implementation” to afull feature actor framework à la &lt;a href="http://en.wikipedia.org/wiki/Open_Telecom_Platform_%28OTP%29"&gt;Erlang OTP&lt;/a&gt;, with actor supervision and management, persistent datastructures, distribution, Software Transactional Memory (STM) integration, and all of that under thecommon umbrella of actor paradigm.&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;To me, Akka is more and more looking like theKiller App for Scala, a middle layer framework which will be more or less in all Scala applications in a near future, a little like Spring is for the Java world. It brings so much power with so littleboilerplate... So, if you don't know Akka, just go looking for itright now. &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;... and a bright future in sight for Scala&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;All along the event, there was afelling of “taking part of the starting point of something great”,perhaps a little like what were firsts Java one. Perhaps it was partly du to the fact that meeting about 155 Scala enthusiasts fromEurope, US, Japan, Australia and so on was a great moment - it was really good to finally put faces on mailing lists and IRC names (hello Miles,Josh, Timothy and all the others !). &lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;But I believe that it was more than just that. Today, I'm pretty confident that Scala is here to stay and growth.&lt;br /&gt;&lt;br /&gt;The most "symptomatic" announcement of that evolution of the language organization from the research sphere to a broader audience is the &lt;a href="http://twitter.com/#search?q=%23scaladays%20foundation"&gt;announcement that a Scala Foundation will be created&lt;/a&gt; to manage it.&amp;nbsp; &lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;So, that was a really wonderful event, and long life to Scala ! &lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Ho – and I get my “Programming inScala” dedicated by Martin, it's the little thing that is makingthat event even more special to me :)&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Presentations seen&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;So, that's the list of presentations Iattended, with a (really) brief description of them. Video of talks should me made available in a near future.&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;b&gt;April, 15&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: small;"&gt;15 morning - opening talk&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;A cool Opening Talk by Martin Odersky, focused on all the goodness brought by Scala 2.8, how it evolves from "just a little refactoring of Collection API" to a "3.0 without the name". Great. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;15, morning&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;PEGEX by Kota Mizushima&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;or how to have combinator parser which looks like regexp. Interesting project, but a I think a little young for now... Keep an eye on it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Scala Parallel collections by Aleksander Prokopec&lt;/b&gt;&lt;br /&gt;Presentation of parallel collections arriving in Scala 2.8.1... It seems that it will be really great stuff, with good integration in existing collection API.&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Developing the Scala bindings to the Fly Object Space by Channing Walton, Nigel Warren, Simon Kent&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;I miss a part of the beginning, but for what I saw,&amp;nbsp; Fly Object Space seems to be a powerful framework for distributed computing.&amp;nbsp;   &lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;b&gt;15, afternoon, part 1&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;CCSTM: A library based STM for Scala by Nathan Bronson, Hasaan Chafi, Kunle Olukotun&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;A talk about what&amp;nbsp; Software Transactional Memory (STM)  implementation can be achieve with Scala from an ideal STM, really nice stuff – STM seems to be a hot topic, it is cool that what is one of the most interesting feature of Clojure is winning interest in Scala.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Lightweight language support for type-based, concurrent event processing by Phillip Hadler&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Really nice technical presentation about how type information can leads to massive performance optimization in pattern matching. &lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Named and default argument in Scala by Luka Rytz&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;To me, this feature is one of the best of Scala 2.8. It was nice to see how the implementation was done.  &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;15, afternoon, part 2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Specialization in Scala by Iulian Dragos&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Specialization finally comes to Scala 2.8 ! For the first time, Scala has the opportunity to be able to do things faster than Java, namely automatically specializing method to native JVM type to remove unnecessary boxing/unboxing logic. Great stuff, even if it's just a beginning.  &lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Leaky Monads – an experiment with automatic resources management by Josh Suereth&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Or how to cleanly manage resources in Scala with a little bit of monad, but only when we need them.&lt;br /&gt;Great presentation by Josh, with a lot of “déjà vu” feeling for me – most of the problem he talk about and the solution he found was alike whose I encountered when I did my monadic resource management of LDAP connections.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Type-safe SQL embedded in Scala by Christoph Wulfz&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Cool stuff to make SQL a first class citizen in Scala, as XML is.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;April, 16 &lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;The next day seems to have again raise the level of the event. For me, it was a fabulous set ofpresentations. All were really top level one, and allsubjects were great - well, or at least, I was the perfect target for them :)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;16, morning keynotes&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;A really interesting keynote by KunleOlukotun, the man behind the heavily-multi-core Niagara processor. Heshows how to deeply embed polymorphic DSL in Scala, and it was kindof amazing. The Parallel and concurrent future seems to be bright inScala world. &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;16, morning&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;b&gt;Scala @ Linkedin : distributed computed with Norbert by Chris Conrad&lt;/b&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;Really cool to see what Linkedin did with Scala, and their scaling and distribution problem are really nice ones (in the way a hard maths theorem is nice to prove ;).&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Akka: Simpler scalabitity, fault-tolerance, concurrency &amp;amp; remoting throught actors by Jonas Boner, Victor Klang&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;As I already said, Akka is more and more looking like the killer app on Scala. Kudo to Jonas ans Akka team.  &lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Scala IDE for Eclipse : retrospect and prospect for 2.8 by Miles Sabin&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;After years of purgatory (for users ;), Scala Eclipse IDE seems to finally be interesting again, thanks to Miles and all the hard work. A really bad point for Eclipse foundation and its autism regarding JDT evolution.  &lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;16, afternoon, part 1&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;sbt: design and implementation by Mark Harrah  &lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;SBT, the build system that will save all of us from Maven – thanks Mark, and congrats for the work&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Scala Modules: a Scala DSL to ease OSGi development by Heiko Seeberger&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;A “small” library to make OSGi use more user-friendly, and a lotof interest toward it. Sometime, syntax and cleanness IS important (subliminal message to all Java coders who don't see the problems with Java boilerplate)&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Sneaking Scala into your organization by David Copeland&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Even if I don't have that problem – in my company of four people, all the two developers are Scala experts ;), the talk was really interesting and well thought. Hope that a lot of people will follow these advices :)&lt;/div&gt;&lt;br /&gt;&lt;b&gt;16, afternoon, part 2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;Their was no presentation in the last afternoon, but a workshop in which attendees were able to summarize their thought about Scala - what is missing, what has to be done, etc. Unfortunately, I had to leave before than the restitution was done, and missed it. So, for that, I'm like all of you: waiting for blog/video to know what happened !&lt;br /&gt;&lt;br /&gt;And that's all, until next year (in U.S ?) !&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-6193587528566497096?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/6193587528566497096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=6193587528566497096' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6193587528566497096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6193587528566497096'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/04/summary-of-my-scala-days-2010.html' title='Summary of my Scala Days 2010'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2319659587659090145</id><published>2010-04-14T14:47:00.000+02:00</published><updated>2010-04-14T14:47:29.840+02:00</updated><title type='text'>Scala Days tomorrow !</title><content type='html'>In a few hours, I'm going to take the TGV for Lausanne, to attend first &lt;a href="http://days2010.scala-lang.org/"&gt;Scala Days&lt;/a&gt; !&lt;br /&gt;&lt;br /&gt;There seems to be a lots of really &lt;a href="http://days2010.scala-lang.org/program"&gt;good conferences&lt;/a&gt;, and it will be the opportunity to finally met a lot of irc/mailing list names !&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2319659587659090145?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2319659587659090145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2319659587659090145' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2319659587659090145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2319659587659090145'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/04/scala-days-tomorrow.html' title='Scala Days tomorrow !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-5116804299102912652</id><published>2010-04-10T19:15:00.000+02:00</published><updated>2010-04-10T19:15:34.803+02:00</updated><title type='text'>Embed OpenDS in your application</title><content type='html'>I just created a github project that shows what one has to do to configure and start &lt;a href="https://www.opends.org/"&gt;OpenDS&lt;/a&gt; LDAP directory from a Java application, for example to run unit tests. &lt;br /&gt;&lt;br /&gt;Most of the code is a direct transcription of information found on OpenDS wiki[1].&lt;br /&gt;&lt;br /&gt;Along the commits, I tried to remove most of the unused configuration for the proposed goal, and I ended to replace the Berkeley DB backend by a memory one.&lt;br /&gt;&lt;br /&gt;The source code is here: &lt;a href="http://github.com/fanf/opends-simple-config"&gt;http://github.com/fanf/opends-simple-config&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Feel free to remove even more unused configuration, or propose things to make OpenDS start time even faster.&lt;br /&gt;&lt;br /&gt;Enjoy !&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="https://www.opends.org/wiki/page/CreatingAnOpenDSInstanceForEmbeddedUse"&gt;https://www.opends.org/wiki/page/CreatingAnOpenDSInstanceForEmbeddedUse&lt;/a&gt;&lt;br /&gt;&lt;a href="https://www.opends.org/wiki/page/ControllingOpenDSFromAnotherApplication"&gt;https://www.opends.org/wiki/page/ControllingOpenDSFromAnotherApplication&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-5116804299102912652?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/5116804299102912652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=5116804299102912652' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5116804299102912652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5116804299102912652'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/04/embed-opends-in-your-application.html' title='Embed OpenDS in your application'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-6080205403435749443</id><published>2010-03-17T23:43:00.000+01:00</published><updated>2010-03-17T23:43:48.327+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix file permissions'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Unix file permissions DSL</title><content type='html'>Scala native DSL capabilities are astonishing. I just created some Scala object to mimic Unix file permission representation and "chmod" interaction, and I'm rather pleased of the result&lt;br /&gt;&lt;br /&gt;Only user", "group" and "other" permission are managed - so no setuid, setgid or sticky bit.&lt;br /&gt;&lt;h3&gt;Perm objects&lt;/h3&gt;They are simple immutable permission objects with a nice toString and an octal representation:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val p:Perm = wx&lt;br /&gt;scala&gt; w.toString // "-wx"&lt;br /&gt;scala&gt; w.octal // 3&lt;br /&gt;&lt;/pre&gt;You can combine permission to obtain new permissions:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; w+r  // rw-&lt;br /&gt;scala&gt; rwx-w // r-w&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;FilePerms objects&lt;/h3&gt;They keep a group of three mutable permissions.You can create a new File permission object from octal values:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val perms = FilePerms(777)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Or from Perm object:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val perms = FilePerms(rw,rw,r)&lt;br /&gt;&lt;/pre&gt;Like Perm, they have nice string and octal representation:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val perms = FilePerms(777)&lt;br /&gt;scala&gt; perms.toString //rwxrwxrwx&lt;br /&gt;scala&gt; perms.octal // 777&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Missing values are initialized to "no permission":&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val perms = FilePerms(77) //rwxrwx---&lt;br /&gt;scala&gt; val perms = FilePerms(rw) //rw-------&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And of course, you can change permissions:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; val perms = FilePerms(77) //rwxrwx---&lt;br /&gt;scala&gt; perms.g-wx  // rwxr----&lt;br /&gt;scala&gt; perms.ugo+x // rwxr-x--x&lt;br /&gt;scala&gt; perms.a-wx  // r--r-----&lt;br /&gt;&lt;/pre&gt;The binding of theses objects with Java IO with the goal to actually set file permissions is let as an exercise for the reader ;)&lt;br /&gt;It's available on gist here: &lt;a href="http://gist.github.com/335791"&gt;http://gist.github.com/335791&lt;/a&gt;. To test it, simply copy the file content, fire a Scala REPL, start an object declaration, past the content of the file, close you object, import its content, and play:&lt;pre class="sh_scala"&gt;&lt;br /&gt;scala&gt; object p { [enter]&lt;br /&gt;  | [here, past the content of the file]&lt;br /&gt;  .....&lt;br /&gt;  | }&lt;br /&gt;defined module p&lt;br /&gt;&lt;br /&gt;scala&gt; import p._&lt;br /&gt;import p._&lt;br /&gt;&lt;br /&gt;scala&gt; FilePerms(644)&lt;br /&gt;res0: Option[p.FilePerms] = Some(rw-r--r--)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enjoy !&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;PS: if you have an idea about how to mimic chown, I would appreciate. For now, all I get is:&lt;pre&gt;&lt;br /&gt;chmod( ug(_)+rw, filePerms)&lt;br /&gt;&lt;/pre&gt;Not really nice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-6080205403435749443?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/6080205403435749443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=6080205403435749443' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6080205403435749443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6080205403435749443'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/03/scala-unix-file-permissions-dsl.html' title='Scala Unix file permissions DSL'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3056714887109082003</id><published>2010-01-27T17:48:00.002+01:00</published><updated>2010-01-27T17:51:06.797+01:00</updated><title type='text'>Scala 2.8 Beta 1 is out !</title><content type='html'>Today, the first official "Scala 2.8 Beta" was released. It was awaited, and for really good reasons !&lt;br /&gt;Just look at the announcement summary to see all the goodness available: &lt;a href="http://www.scala-lang.org/node/4587"&gt;http://www.scala-lang.org/node/4587&lt;/a&gt;&lt;a href="http://old.nabble.com/-scala--Scala-2.8.0-Beta-1-td27339970.html"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I would like to thanks all the people at EPFL and all other contributors around the world to provide us with such a good language and awesome libraries/tools for our daily work - both production ready thanks to Java existing ecosystem and Start-up friendly (ok, no argument here, I just like that language :)&lt;br /&gt;&lt;br /&gt;Downloads are available here:&lt;a href="http://www.scala-lang.org/downloads"&gt; http://www.scala-lang.org/downloads&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3056714887109082003?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3056714887109082003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3056714887109082003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3056714887109082003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3056714887109082003'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/01/scala-28-beta-1-is-out.html' title='Scala 2.8 Beta 1 is out !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-5442020061651053230</id><published>2010-01-20T09:36:00.005+01:00</published><updated>2010-01-20T14:57:53.272+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='actor'/><category scheme='http://www.blogger.com/atom/ns#' term='spring3'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala and Spring 3 JavaConfig</title><content type='html'>&lt;span style="font-size: x-large;"&gt;Scala, Spring 3, Actor, REST, IoC configuration by code...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;... and well, I should be able to put some other buzz words in that title, perhaps agile and Scrum ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I wanted to test &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/"&gt;Spring 3&lt;/a&gt; &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/new-in-3.html#new-java-configuration"&gt;"configuration via code"&lt;/a&gt; new feature, and especially how well it works with Scala.&lt;br /&gt;&lt;br /&gt;As a &lt;a href="http://tapestry.apache.org/tapestry5.1/tapestry-ioc/"&gt;Tapestry 5&lt;/a&gt; (former) user, I'm a great fan of IoC  configuration done in Java (or Scala). From a developer point of view, it's so much more easy and robust (especially refactoring prone) to have access to a real, type safe language in place of an ersatz like XML... and most of the time, it's also much less verbose.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;The application&lt;/span&gt;&lt;br /&gt;I needed a pretext and decided to build a trivial webapplication that allows to upload files to some URL, and post-processthem - a rather usual need in a web-application. That will allow to test Spring 3 new "REST"features, a bit of Expression Language, and put in a little Scala Actorto let the (long) processing be done asynchronously.&lt;br /&gt;I also used maven, and Slf4j with NoCommonsLogging to be able to use Slf4j with Spring. &lt;br /&gt;&lt;br /&gt;What exactly does the application:&lt;br /&gt;- wait uploads on a REST endpoint URL;&lt;br /&gt;- when an upload comes, save it into a temporary file;&lt;br /&gt;- signal the file's availability to a "file processor". That processing may take a looooooong time to process (for example, it's a big XML report, with a lot of parsing, input validation, graphs generation, etc), and so, the processing should be done in a side process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Results&lt;/span&gt;&lt;br /&gt;Everything comes along really well, and the result is available on &lt;a href="http://github.com/fanf/scala-spring3-upload/fast_forward"&gt;github&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To test it, you will need a JVM and Maven  (if you haven't done it yet and are not limited by production constrains, just go download the last 1.6 JVM (1.6.0_18), the performances improvements with the last two releases are impressive)&lt;br /&gt;&lt;pre style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;% git clone git://github.com/fanf/scala-spring3-upload.git&lt;/pre&gt;&lt;pre style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;% cd scala-spring3-upload&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;% mvn jetty:run&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;You should have a Jetty server up and running on localhost.&lt;br /&gt;Now, you can upload a file to &lt;b&gt;http://localhost:8080/upload&lt;/b&gt;, and see that the upload is processed and HTTP code returned, and then an asynchronous process is launched to process the file - well, actually it just waits 10 seconds and delete it.&lt;br /&gt;On Linux, you can use Curl to post files:&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;% curl -F FileToUploadName=@/path/to/the/file/to/upload http://localhost:8080/upload/&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Details about the project&lt;/span&gt;&lt;br /&gt;Here comes the different files and their purpose:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;src/main/webapp/WEB-INF/&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;It contains usual servlet configuration files, in XML :&lt;br /&gt;- &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;web.xml&lt;/span&gt; : standard Java servlet config file&lt;strike&gt;, nothing to see here.&lt;/strike&gt; with a reference to the annotation based context loader and the AppConfig.scala file.&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;strike&gt;- &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;upload-servlet.xml&lt;/span&gt;&lt;i&gt; &lt;/i&gt;: Spring servlet config file. It's this one that is Spring default enter point, and it contains an entry point to the Scala file used for bean configuration, and to the prope&lt;/strike&gt;&lt;br /&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;strike&gt;I just don't understand why this last file is needed. It's where you feel that JavaConfig was an afterthought in Spring... Couldn't have we a convention in place of that ? Something like "put your master configuration code in that package" ? All in all, it's small pain to have to write that file, but it also bring really little information.&amp;nbsp; &lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;br /&gt;UPDATE: as Chris Beams shows me, I should have RTFM more carefully. It's now possible (I do believed it wasn't in first RCs), and I updated the sources to have a full ScalaBased configuration. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;src/main/scala/org/test/upload&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;That package contains the code to receive file (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;UploadEndpoint.scala&lt;/span&gt;) and process them (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;FileProcessor.scala&lt;/span&gt;).&lt;br /&gt;As you can see, there is very little code, and most of it is self-explanatory. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;src/main/scala/&lt;/b&gt;&lt;b&gt;org/test/upload/config&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;That last package only contains the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AppConfig.scala&lt;/span&gt; file, the place where Spring IoC configuration is done.&lt;br /&gt;I really like the cleaness of that file, compared to what may have been the equivalent XML one.&lt;br /&gt;The default sleepTime value is especially cool, typically a things hard to do when you only have XML&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;This little project could be a good starting-point if you want to use Spring 3 with Scala, or Slf4j with Spring.&lt;br /&gt;I'm also rather impressed by how much little code is needed with Spring 3 to configured the REST endpoint.&lt;br /&gt;And building little asynchronous services thanks to actor is just too simple (OK, here it's a toy, but if you want serious business with actor, look at &lt;a href="http://akkasource.org/"&gt;AKKA&lt;/a&gt;). &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-5442020061651053230?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/5442020061651053230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=5442020061651053230' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5442020061651053230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5442020061651053230'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/01/scala-and-spring-3-javaconfig.html' title='Scala and Spring 3 JavaConfig'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2164238104592353844</id><published>2010-01-09T18:43:00.000+01:00</published><updated>2010-01-09T18:43:52.901+01:00</updated><title type='text'>Happy new year 2010</title><content type='html'>For me, year 2010 will be a big switch in my life... hopefully for the best !&lt;br /&gt;So, I wish you all the best things for this last year of the first third millennium's decade !&lt;br /&gt;&lt;br /&gt;Happy new year !&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2164238104592353844?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2164238104592353844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2164238104592353844' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2164238104592353844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2164238104592353844'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2010/01/happy-new-year-2010.html' title='Happy new year 2010'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-504352821641202707</id><published>2009-11-12T11:41:00.001+01:00</published><updated>2009-11-12T11:43:10.979+01:00</updated><title type='text'>Bootstrap GWT2 with maven, UiBinder and i18n</title><content type='html'>I'm setting up a boostrap project for GWT 2 witch would use maven 2, UiBinder and i18n.&lt;br /&gt;The idea is to centralize resources about UiBinder and test GWT 2, the result being used as a template project for real GWT 2 projects.&lt;br /&gt;&lt;br /&gt;I'm quite new to GWT (2 days old...), so it is also a learning project. If it could be of any use for you, don't hesitate to use it - or enhance it, or make comments :)&lt;br /&gt;&lt;br /&gt;For now, it's based on GWT 2.0.0-ms2, and some configuration may be specific to my environment (Linux&amp;amp;Firefox 3.5).&lt;br /&gt;&lt;br /&gt;It's available here: &lt;a href="http://github.com/fanf/gwt2-mvn-bootstrap"&gt;http://github.com/fanf/gwt2-mvn-bootstrap&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-504352821641202707?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/504352821641202707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=504352821641202707' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/504352821641202707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/504352821641202707'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/11/bootstrap-gwt2-with-maven-uibinder-and.html' title='Bootstrap GWT2 with maven, UiBinder and i18n'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-4554936995934834608</id><published>2009-11-10T14:44:00.003+01:00</published><updated>2009-11-10T14:51:32.335+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='slf4j'/><category scheme='http://www.blogger.com/atom/ns#' term='pom'/><category scheme='http://www.blogger.com/atom/ns#' term='no-commons-logging'/><title type='text'>Maven2 bootstrap pom.xml for SLF4J and no-commons-logging</title><content type='html'>Each time I start a new Java project with Maven 2, I need to write the same dependencies again and again: SLF4J and no commons-logging because it's evil (and SpringFramework seems to want to keep it), Joda Time by default, some properties, etc. &lt;br /&gt;&lt;br /&gt;So, that's the template pom.xml I use for the bootstrap, if it may help anybody here (it uses logback for logging, as it's more efficient than Log4j with SLF4J, but feel free to use what you want):&lt;br /&gt;&lt;br/&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;org.test&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;test&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;properties&amp;gt;&lt;br /&gt;    &amp;lt;!-- UTF-8 for everyone --&amp;gt;&lt;br /&gt;    &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;br /&gt;    &amp;lt;slf4j-version&amp;gt;1.5.8&amp;lt;/slf4j-version&amp;gt;&lt;br /&gt;    &amp;lt;logback-version&amp;gt;0.9.17&amp;lt;/logback-version&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;description&amp;gt;Template for project without Commons-logging&amp;lt;/description&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;repositories&amp;gt;&lt;br /&gt;    &amp;lt;repository&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;no-commons-logging&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;name&amp;gt;No-commons-logging Maven Repository&amp;lt;/name&amp;gt;&lt;br /&gt;      &amp;lt;layout&amp;gt;default&amp;lt;/layout&amp;gt;&lt;br /&gt;      &amp;lt;url&amp;gt;http://no-commons-logging.zapto.org/mvn2&amp;lt;/url&amp;gt;&lt;br /&gt;      &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;&lt;br /&gt;    &amp;lt;/repository&amp;gt;&lt;br /&gt;  &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;pluginRepositories&amp;gt;&lt;br /&gt;  &amp;lt;/pluginRepositories&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;    &amp;lt;plugins&amp;gt;&lt;br /&gt;    &amp;lt;/plugins&amp;gt;&lt;br /&gt;  &amp;lt;/build&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;joda-time&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;joda-time&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.6&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!--  test --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;4.7&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!--&lt;br /&gt;      All the following is related to our will to NOT use Commong-logging. Never. &lt;br /&gt;      And framework we depend on won't bring commons-loggin nether (I'm looking at&lt;br /&gt;      you, stringframework).&lt;br /&gt;    --&amp;gt;&lt;br /&gt;    &amp;lt;!-- use no-commons-logging --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;99.0-does-not-exist&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;!-- no-commons-logging-api, if you need it --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;commons-logging-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;99.0-does-not-exist&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;!-- slf4j commons-logging replacement --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${slf4j-version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;!-- other slf4j jars --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${slf4j-version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;!-- using slf4j native backend --&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${logback-version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${logback-version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-4554936995934834608?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/4554936995934834608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=4554936995934834608' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4554936995934834608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4554936995934834608'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/11/maven2-bootstrap-pomxml-for-slf4j-and.html' title='Maven2 bootstrap pom.xml for SLF4J and no-commons-logging'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3381805905529037513</id><published>2009-10-24T18:32:00.000+02:00</published><updated>2009-10-24T18:32:40.871+02:00</updated><title type='text'>Clone objects with arguments override in Scala 2.8: best practices ?</title><content type='html'>I'm actively looking for best practices and patterns about how to create clone objects in Scala, with the possibility to change some values of the cloned object along the way.&lt;br /&gt;&lt;br /&gt;I have the usual concern of the Java world on that topic: I would like to avoid Java "clone", I want to be able to use the pattern in a class hierarchy, I want to have the minimum amount of code (or at least, the simplest possible) to write in domain class to support my cloning API.&lt;br /&gt;And as I'm in Scala, I want to deal with both vars and vals, if possible in the same consistent way.&lt;br /&gt;&lt;br /&gt;Actually, I want to provide to my libraries consumer an effective way to do things like that (where *Child* extends *Parent* class):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;    val p = new Parent("some value")&lt;br /&gt;    // simple cloning&lt;br /&gt;    val p2 = p.copy&lt;br /&gt;    //clone, and change a val and a var along the way&lt;br /&gt;    val p3 = p.copy(p_val1 = "new value for val", p_var1 = "new value for var")&lt;br /&gt;&lt;br /&gt;    //and same things apply for children of Parent:&lt;br /&gt;    val c = new Child("some parent value", "some child value")&lt;br /&gt;    //override child val/var and/or parent val/var in the same fashion&lt;br /&gt;    val c1 = c.copy(p_val1 = "new value for val defined in Parent class",&lt;br /&gt;                    c_val1 = "new value for val defined in Child class",&lt;br /&gt;                    p_var1 = "new value for var defined in Parent class",&lt;br /&gt;                    c_var1 = "new value for var defined in Child class" )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As Scala 2.8 is advertised with "default and named arguments", such things should possible (well, hopefully easy too ;).I came with this solution:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;pre class="sh_scala"&gt;class A(val val_a:String)  {&lt;br /&gt;    var var_a = ""&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object A {&lt;br /&gt;    def merge[T](t:T)&lt;br /&gt;    (&lt;br /&gt;        var_a : String&lt;br /&gt;    ) : T = {&lt;br /&gt;        t match {&lt;br /&gt;            case x:A =&amp;gt; x.var_a = var_a&lt;br /&gt;            case _ =&amp;gt; error("")&lt;br /&gt;        }&lt;br /&gt;        t&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    def copy(source:A)&lt;br /&gt;    (&lt;br /&gt;        val_a : String = source.val_a, &lt;br /&gt;        var_a : String = source.var_a&lt;br /&gt;    ) : A = merge(new A(val_a))(var_a)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class B(override val val_a:String, val val_b : Int) extends A(val_a) {&lt;br /&gt;    var var_b = 0&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object B {&lt;br /&gt;    def merge[T](t:T)&lt;br /&gt;    (&lt;br /&gt;        var_a : String,&lt;br /&gt;        var_b : Int&lt;br /&gt;    ) : T = {&lt;br /&gt;        A.merge(t)(var_a) match {&lt;br /&gt;            case x:B =&amp;gt; x.var_b = var_b&lt;br /&gt;            case _ =&amp;gt; error("")&lt;br /&gt;        }&lt;br /&gt;        t&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    def copy(source:B)&lt;br /&gt;    (&lt;br /&gt;        val_a : String = source.val_a,&lt;br /&gt;        var_a : String = source.var_a,&lt;br /&gt;        val_b : Int = source.val_b,&lt;br /&gt;        var_b : Int = source.var_b&lt;br /&gt;    ) : B = merge(new B(val_a,val_b))(var_a,var_b)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class C(override val val_a : String) extends A(val_a)&lt;br /&gt;&lt;br /&gt;// ***************** &lt;br /&gt;// Example of use&lt;br /&gt;// ***************** &lt;br /&gt;&lt;br /&gt;object TestCloning {&lt;br /&gt;    &lt;br /&gt;    def main(args:Array[String]) {&lt;br /&gt;        val a1 = new A("la_init")&lt;br /&gt;        a1.var_a = "ra_init"&lt;br /&gt;            &lt;br /&gt;        val b1 = new B("lb_init",1)&lt;br /&gt;        b1.var_a = "rb_init"&lt;br /&gt;        b1.var_b = 10&lt;br /&gt;&lt;br /&gt;        //example with A&lt;br /&gt;&lt;br /&gt;        val a2 = A.copy(a1)()&lt;br /&gt;        assert(!(a1 eq a2))&lt;br /&gt;        assert(a2.var_a == a1.var_a)&lt;br /&gt;        assert(a2.val_a == a1.val_a)&lt;br /&gt;        &lt;br /&gt;        val a3 = A.copy(a1)(val_a = "la_mod")&lt;br /&gt;        assert(a3.var_a == a1.var_a)&lt;br /&gt;        assert(a3.val_a == "la_mod")&lt;br /&gt;        &lt;br /&gt;        val a4 = A.copy(a1)(val_a = "la_mod", var_a = "ra_mod")&lt;br /&gt;        assert(a4.val_a == "la_mod")&lt;br /&gt;        assert(a4.var_a == "ra_mod")&lt;br /&gt;&lt;br /&gt;        val a5 = A.copy(new C("foo"))()&lt;br /&gt;        assert(a5.var_a == "")&lt;br /&gt;        assert(a5.val_a == "foo")&lt;br /&gt;&lt;br /&gt;        val a6 = A.copy(b1)()&lt;br /&gt;        assert(a6.val_a == "lb_init")&lt;br /&gt;        assert(a6.var_a == "rb_init")&lt;br /&gt;        &lt;br /&gt;        //with B&lt;br /&gt;            &lt;br /&gt;        val b2 = B.copy(b1)()&lt;br /&gt;        assert(b2.val_a == "lb_init")&lt;br /&gt;        assert(b2.var_a == "rb_init")&lt;br /&gt;        assert(b2.val_b == 1)&lt;br /&gt;        assert(b2.var_b == 10)&lt;br /&gt;            &lt;br /&gt;        val b3 = B.copy(b1)(var_b = 5, val_a = "lb_mod")&lt;br /&gt;        assert(b3.val_a == "lb_mod")&lt;br /&gt;        assert(b3.var_a == "rb_init")&lt;br /&gt;        assert(b3.val_b == 1)&lt;br /&gt;        assert(b3.var_b == 5)&lt;br /&gt;            &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That solution seems to work, and allows to do the kind of use case I wanted to build.&lt;br /&gt;But it seems not satisfactory at all for (at least) these reasons:&lt;br /&gt;1/ - the trailing "()" in real clone without override is mandatory and doesn't look right;&lt;br /&gt;2/ - it seems to be a lot of tedious code to write in each class, and so seems to be really error prone;&lt;br /&gt;3/ - I'm not at ease with the merge method, but I can't say why exactly;&lt;br /&gt;4/ - I don't like to much the factory approach.&lt;br /&gt;&lt;br /&gt;1/ could be easily addressed if in place of only a copy(source:X)(.....) we define a couple of method :&lt;br /&gt;&lt;pre class="sh_scala"&gt;    def copyWith(source:A)( ... ) : A = merge(...)(...)&lt;br /&gt;    def copy(source:A) = copyWith(source)()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;3/ and 4/ are just feelings, and so could be shut up for now.&lt;br /&gt;&lt;br /&gt;But 2/ is a real concern, and I would like to find a way to externalize more code in traits, so that domain classes have only simple, short code to write to provide a clone API.&lt;br /&gt;&amp;nbsp; &lt;br /&gt;So Scalazy, what are your best practices about the cloning topic in Scala ?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3381805905529037513?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3381805905529037513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3381805905529037513' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3381805905529037513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3381805905529037513'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/10/clone-objects-with-arguments-override.html' title='Clone objects with arguments override in Scala 2.8: best practices ?'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-732988195960910991</id><published>2009-10-12T21:42:00.004+02:00</published><updated>2009-10-14T22:31:20.979+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='activeldap'/><category scheme='http://www.blogger.com/atom/ns#' term='ldap'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>ActiveLDAP in Scala : LDAP on the JVM, in a shell !</title><content type='html'>&lt;i&gt;Update: typos only&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Until a really recent time, LDAP in the JVM, trougth JNDI API, was a nightmare of usability. Just connecting to an LDAP directory with a simple login/pass was worth a dozen lines of really unatural code (and &lt;a href="http://java.sun.com/products/jndi/tutorial/ldap/connect/create.html"&gt;I'm almost not exagering&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Hopefully, the situation is evolving, and there is several projects willing to provide a better LDAP SDK on the JVM. &lt;br /&gt;&lt;br /&gt;Among them, there is &lt;a href="http://www.unboundid.com/products/ldapsdk/"&gt;UnboundId's one&lt;/a&gt;. I started to play with it, and it's quite delighting to be able to use a good API to do your work !&lt;br /&gt;&lt;br /&gt;So it gives me an idea : how this SDK could be pimped thanks to Scala to be used in command lines, in a ruby &lt;a href="http://ruby-activeldap.rubyforge.org/doc/"&gt;ActiveLDAP&lt;/a&gt; fashion ?&lt;br /&gt;&lt;br /&gt;And things are coming along really well. It's just a start, but this is an example of a Scala REPL session with my version of Scala ActiveLDAP :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;scala&amp;gt; import test.activeldap._&lt;br /&gt;import test.activeldap._&lt;br /&gt;&lt;br /&gt;scala&amp;gt; import LdapFilter._&lt;br /&gt;import LdapFilter._&lt;br /&gt;&lt;br /&gt;scala&amp;gt; val p = new SimpleAuthLCP(baseDn = "dc=example,dc=org",authDn = &lt;br /&gt;"cn=admin", authPw = "secret pass")&lt;br /&gt;p: test.activeldap.SimpleAuthLCP = [cn=admin@localhost:389 (base: &lt;br /&gt;dc=example,dc=org) by password authentication]&lt;br /&gt;&lt;br /&gt;scala&amp;gt; val users = new MetaActiveEntry(prefix = "ou=people",&amp;nbsp; &lt;br /&gt;rdn = "uid" , classes = Set("top","person","organizationalPerson","inetOrgPerson"), &lt;br /&gt;provider = p )&lt;br /&gt;users: test.activeldap.MetaActiveEntry = test.activeldap.MetaActiveEntry@c85a33&lt;br /&gt;&lt;br /&gt;scala&amp;gt; val user = users.find()(0)&lt;br /&gt;user: test.activeldap.ActiveEntry = uid=42,ou=people,dc=example,dc=org&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user.details&lt;br /&gt;res28: java.lang.String = Entry(dn='uid=42,ou=people,dc=example,dc=org', &lt;br /&gt;attributes={Attribute(name=objectClass, values={'inetOrgPerson', &lt;br /&gt;'organizationalPerson', 'person', 'top'}), &lt;br /&gt;Attribute(name=sn, values={'Bar'}), Attribute(name=cn, values={'Foo'}), &lt;br /&gt;Attribute(name=mail, values={'foo@bar.com'}), Attribute(name=uid, values={'42'})})&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user("uid") = "43"&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user.save&lt;br /&gt;&lt;br /&gt;scala&amp;gt; users.find()&lt;br /&gt;res31: Seq[test.activeldap.ActiveEntry] = ArrayBuffer(uid=42,ou=people,dc=example,dc=org,&lt;br /&gt;uid=43,ou=people,dc=example,dc=org)&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user("mail") = Seq("foo@bar.com","foo_bar@bar.com")&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user.save&lt;br /&gt;&lt;br /&gt;scala&amp;gt; users.find(EQ("uid","43"))(0).details&lt;br /&gt;res34: java.lang.String = Entry(dn='uid=43,ou=people,dc=example,dc=org', &lt;br /&gt;attributes={Attribute(name=objectClass, values={'inetOrgPerson', &lt;br /&gt;'organizationalPerson', 'person', 'top'}), Attribute(name=sn, values={'Bar'}),&lt;br /&gt;Attribute(name=cn, values={'Foo'}), Attribute(name=mail, values={'foo@bar.com', &lt;br /&gt;'foo_bar@bar.com'}), Attribute(name=uid, values={'43'})})&lt;br /&gt;&lt;br /&gt;scala&amp;gt; user.delete&lt;br /&gt;&lt;br /&gt;scala&amp;gt; users.find(EQ("uid","43"))&lt;br /&gt;res36: Seq[test.activeldap.ActiveEntry] = ArrayBuffer()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;scala&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There is a really nice feature brought by Scala 2.8 for this kind of API: named and default parameters. I&amp;nbsp; used it in the previous sessions to define the connection: host and port were not provided (default to localhost:389),&amp;nbsp; but you can specify them if you need :&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&amp;nbsp;scala&amp;gt; val p = new SimpleAuthLCP(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | authDn = "cn=manager",&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | authPw = "secret password",&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | host = "an.other.host.com",&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | port = "1389",&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | baseDn = "dc=company,dc=com"&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's just a begining, and there is a lot of other nice features from Ruby ActiveLDAP that could be added...&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-732988195960910991?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/732988195960910991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=732988195960910991' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/732988195960910991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/732988195960910991'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/10/activeldap-in-scala-ldap-on-jvm-in.html' title='ActiveLDAP in Scala : LDAP on the JVM, in a shell !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3996520124893062490</id><published>2009-10-01T18:24:00.003+02:00</published><updated>2009-10-01T18:34:39.121+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='openworldforum'/><category scheme='http://www.blogger.com/atom/ns#' term='meeting'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Alternative languages for the JVM @ OpenWorldForum Paris</title><content type='html'>Today, a was kindly invited by &lt;a href="http://blogs.sun.com/alexismp/"&gt;Alexis Moussine - Pouchkine&lt;/a&gt; to be the Scala advocate in a roundtable about alternative languages on the JVM, during a session &lt;b style="font-weight: normal;"&gt;about the &lt;a href="http://openworldforum.org/program/floss-java"&gt;Futur of Java&lt;/a&gt; &lt;/b&gt;in &lt;a href="http://openworldforum.org/"&gt;Open World Forum&lt;/a&gt; meeting in Paris.&lt;br /&gt;&lt;br /&gt;The sessions was brief (3 parts of about 30 minutes), and in my feeling a bit outside the main topic of OpenWorldForum which was more about open source at a strategic an politic level, but (surprisingly for me) our room was quite crowd, with interested people. &lt;br /&gt;&lt;br /&gt;Alexis gave the first presentation about the state of Java and OpenJDK, and final presentation,&amp;nbsp; about forthcoming JavaEE 6. As always, I really liked to hear and see Alexis make the show, his presentations were really good, and he defenitly deserve his "JavaEE and Glashfish Evangelist" title. &lt;br /&gt;&lt;br /&gt;The roundtable begun with a presentation from &lt;a href="http://blogs.nuxeo.com/sections/blogs/fermigier"&gt;Stéphane Fermigier&lt;/a&gt; of the way accomplished by Java and the JVM as a platform for other language since it's first release back in 1996.&lt;br /&gt;Afterwards, &lt;a href="http://glaforge.free.fr/weblog/"&gt;&lt;b style="font-weight: normal;"&gt;Guillaume Laforge&lt;/b&gt;&lt;/a&gt; (of course for Groovy) and I (for Scala) talked about our prefered language, the "welcomeness" of the JVM plateform, the always funny debate about dynamically and statically typed languages, and the fact that we seem to be going to a world of "polyglotism", where multiple languages would cooperate on top of a highly industrialized, robust and efficient VM, and be selected for their adequacy to the task to accomplish - all that things mixed up with attendees questions.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;And then, even if we went past the given 30 minutes (well, actually, even went past the 40 minutes...) it was already time to stop.&lt;br /&gt;&lt;br /&gt;It was a really pleasant meeting, and I'm really happy to see that Groovy is now a first class citizen in the Java world, that Scala is beyond the status of new intriguing thing and becomes to be evaluated in different places, and that we can say "functional programming" elsewhere than in an University or some strange startup without being looked as a dangerous, non business compliant hacker.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3996520124893062490?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3996520124893062490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3996520124893062490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3996520124893062490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3996520124893062490'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/10/alternative-languages-for-jvm.html' title='Alternative languages for the JVM @ OpenWorldForum Paris'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8319022019334598529</id><published>2009-09-20T16:40:00.000+02:00</published><updated>2009-09-20T16:40:41.742+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='e17'/><category scheme='http://www.blogger.com/atom/ns#' term='karmic koala'/><category scheme='http://www.blogger.com/atom/ns#' term='xsplash'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Faster log in in Ubuntu 9.10 "Karmic Koala" and e17</title><content type='html'>I'm a long time user of &lt;a href="http://www.enlightenment.org/"&gt;Enlightenment 17&lt;/a&gt;, or e17. I mean, a really long time user, since I used it since the end of 2004 or so. If I kept it for so a long time dispite of all its rough edges, it's because I love a lot of things in e17, like the default windows and mouse focusing behaviour, the possibility to have a lot of cool and usefull desktop effects with a real open source driver that doesn't support 3D acceleration.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But what I like above all the the speed of the the environement. In e17, everything seems to be quick and responsive - well almost everything, Firefox and OpenOffice are what they are ;)&lt;br /&gt;For example, the login process in e17 takes a couple of second. I mean, really a couple: I validate my user/password in GDM, and hop, my desktop environement is fully-loaded and usable.&lt;br /&gt;&lt;br /&gt;OK, so why I'm talking about that ? Lastly, I tried the new &lt;a href="http://www.ubuntu.com/testing/karmic/alpha5"&gt;Ubuntu Karmic Koala Alpha 5&lt;/a&gt;. Before anything else, I do know what alpha means, and I'm not saying anything against Ubuntu, things are expected to enhance until end of october. &lt;br /&gt;Among a loads of other things, Karmic Koala introduces a new transition screen when X is loading, in order to smoothen a little transitions : &lt;a href="https://launchpad.net/xsplash"&gt;XSplash&lt;/a&gt;. The problem is that XSplash doesn't seem to be aware of the speed of e17, and when you login, it loops for quite a long time (perhaps 20 seconds ?) before letting the desktop be shown.&lt;br /&gt;&lt;br /&gt;So, the solution is simply to disable XSplash for the login, and let e17 loads within its 2 seconds:&lt;br /&gt;in the file &lt;b&gt;/etc/gdm/PreSession/Default&lt;/b&gt; comments the things related to XSplash, or if "Default" file only contains XSplash related things, disable it like that (of course, be aware that as Ubuntu is only in alpha phase, this file may be use for other things that Xsplash in the future, and you can break other things with that) :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;mv /etc/gdm/PreSession/Default /etc/gdm/PreSession/Default.disabled&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;That's all ! Now, you can enjoy the lightning login speed of e17 on Ubuntu Karmic Koala.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8319022019334598529?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8319022019334598529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8319022019334598529' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8319022019334598529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8319022019334598529'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/09/faster-log-in-in-ubuntu-910-karmic.html' title='Faster log in in Ubuntu 9.10 &quot;Karmic Koala&quot; and e17'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-5685294940855084225</id><published>2009-08-14T13:39:00.001+02:00</published><updated>2009-08-14T13:42:50.521+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='xpath'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Why simple XML processing is so painful in Java ?</title><content type='html'>&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Note: this article is of little interest to learn Scala XML apis, there is far better coverage of them elsewhere in the web, like &lt;a href="http://www.ibm.com/developerworks/library/x-scalaxml/"&gt;here&lt;/a&gt; and &lt;a href="http://burak.emir.googlepages.com/scalaxbook.docbk.html"&gt;in details here&lt;/a&gt;. It's more like a rant against Java, which makes things painful where it should shine...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nowadays, XML is more or less everywhere, especially when there is data to dispatch between applications, protocols, program languages and other technologies - and no, Json is not (yet ?) as &lt;span onclick="dr4sdgryt(event)"&gt;ubiquitous&lt;/span&gt; as XML for that.&lt;br /&gt;&lt;br /&gt;And still nowadays, parsing simple XML documents in Java is a pain.&lt;br /&gt;&lt;br /&gt;Well, actually, I don't speak about complex, normalized documents with defined, huge XSD schemas (perhaps in this situation, you can afford to invest time in &lt;a href="https://jaxp.dev.java.net/"&gt;Jaxb&lt;/a&gt; or &lt;a href="http://jibx.sourceforge.net/"&gt;Jibx&lt;/a&gt; to do it the right way), nor simpler scenario, but where you want to have a real XML/Object mapping - &lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; is a kind here, and really does a good job.&lt;br /&gt;&lt;br /&gt;I'm talking about kind of XML documents which are more like a database dump, that may be long and with rather deep tree structures, and where you just want to cherry pick some values - of course, in different parts of the tree.  You know, when you just want to test ideas, and you have to implement a quick, working thing to see if the overall architecture works &lt;a href="#footnote_1"&gt;[1]&lt;/a&gt;, and you really don't want to build a full POJO tree to change or erase it the next hour. &lt;br /&gt;&lt;br /&gt;That's a kind of place where Java XPath API (&lt;a href="https://jaxp.dev.java.net"&gt;jaxp&lt;/a&gt;) should shine. But it doesn't. I'm not saying that it's difficult, nor that it doesn't actually work, but that it's painful and you end up with lines and lines and lines of burden (cast, expression compilation, redefinition of higher function than the ones provided by API to do common things, etc) in code that should just expose your intention at first sight.&lt;br /&gt;&lt;br /&gt;Well, lets take a super simple example.&lt;br /&gt;&lt;br /&gt;Lets say that I have this kind of XML data :&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" ?&amp;gt;&lt;br /&gt;&amp;lt;request&amp;gt;&lt;br /&gt;  &amp;lt;id&amp;gt;463516&amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;timestamp&amp;gt;1250240149028&amp;lt;/timestamp&amp;gt;&lt;br /&gt;  &amp;lt;information&amp;gt;&lt;br /&gt;    &amp;lt;person&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;463&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;firstname&amp;gt;Alex&amp;lt;/firstname&amp;gt;&lt;br /&gt;      &amp;lt;lastname&amp;gt;Bar&amp;lt;/lastname&amp;gt;&lt;br /&gt;      &amp;lt;age&amp;gt;34&amp;lt;/age&amp;gt;&lt;br /&gt;      &amp;lt;gender&amp;gt;male&amp;lt;/gender&amp;gt;&lt;br /&gt;      &amp;lt;address&amp;gt;&lt;br /&gt;        &amp;lt;street&amp;gt;136 W 9th St&amp;lt;/street&amp;gt;&lt;br /&gt;        &amp;lt;city&amp;gt;Casper&amp;lt;/city&amp;gt;&lt;br /&gt;        &amp;lt;country&amp;gt;United States&amp;lt;/country&amp;gt;&lt;br /&gt;      &amp;lt;/address&amp;gt;&lt;br /&gt;    &amp;lt;/person&amp;gt;&lt;br /&gt;  &amp;lt;/information&amp;gt;&lt;br /&gt;&amp;lt;/request&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And I only want to take the timestamp, add the city in a male or female list depending of the gender, and if age &gt; 18, increment the count off adults. &lt;br /&gt;&lt;br /&gt;I have a data container that looks like&lt;a href="#footnote_2"&gt;[2]&lt;/a&gt;:&lt;br /&gt;&lt;pre class="sh_java"&gt;&lt;br /&gt;public class Data {&lt;br /&gt; public static final String MALE = "male";&lt;br /&gt; public static final String FEMALE = "female";&lt;br /&gt; &lt;br /&gt; private final Long timestamp;&lt;br /&gt;&lt;br /&gt; private final Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; stats;&lt;br /&gt;&lt;br /&gt; private int adults;&lt;br /&gt; &lt;br /&gt; public Data(Long timestamp) {&lt;br /&gt;  this.timestamp = timestamp;&lt;br /&gt;  this.stats = new HashMap&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt;();&lt;br /&gt;  this.stats.put(MALE, new ArrayList&amp;lt;String&amp;gt;());&lt;br /&gt;  this.stats.put(FEMALE, new ArrayList&amp;lt;String&amp;gt;());&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public void addMale(String city) { this.stats.get(MALE).add(city); }&lt;br /&gt; public void addFemale(String city) { this.stats.get(FEMALE).add(city); }&lt;br /&gt; public Long getTimestamp() { return timestamp; }&lt;br /&gt; public void incAdults() { this.adults = this.adults + 1; }&lt;br /&gt; &lt;br /&gt; @Override&lt;br /&gt; public String toString() {&lt;br /&gt;  StringBuilder sb = new StringBuilder();&lt;br /&gt;  sb.append("time: ").append(this.timestamp).append("\n");&lt;br /&gt;  sb.append("female: ");&lt;br /&gt;  for(String s : stats.get(FEMALE)) {&lt;br /&gt;   sb.append(s).append("; ");&lt;br /&gt;  }&lt;br /&gt;  sb.append("\n");&lt;br /&gt;  sb.append("male: ");&lt;br /&gt;  for(String s : stats.get(MALE)) {&lt;br /&gt;   sb.append(s).append("; ");&lt;br /&gt;  }&lt;br /&gt;  sb.append("\n");&lt;br /&gt;  sb.append("adults: ").append(adults);&lt;br /&gt;  return sb.toString();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;OK, I now this the simplest Java class I came with to implements this logic:&lt;br /&gt;&lt;pre class="sh_java"&gt;&lt;br /&gt;/*&lt;br /&gt; * So, you need a lots of imports,&lt;br /&gt; * and you must have jaxp-api&lt;br /&gt; * somewhere in you path&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;import javax.xml.parsers.DocumentBuilder;&lt;br /&gt;import javax.xml.parsers.DocumentBuilderFactory;&lt;br /&gt;import javax.xml.xpath.XPath;&lt;br /&gt;import javax.xml.xpath.XPathConstants;&lt;br /&gt;import javax.xml.xpath.XPathExpression;&lt;br /&gt;import javax.xml.xpath.XPathFactory;&lt;br /&gt;&lt;br /&gt;import org.w3c.dom.Document;&lt;br /&gt;import org.w3c.dom.NodeList;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class ParseData {&lt;br /&gt; &lt;br /&gt; /*&lt;br /&gt;  * the "throws Exception" is here to try to remove a &lt;br /&gt;  * lot of burden, but of course, don't do that at home !&lt;br /&gt;  */&lt;br /&gt; public static void main(String[] args) throws Exception {&lt;br /&gt;&lt;br /&gt;  DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();&lt;br /&gt;  domFactory.setNamespaceAware(true); &lt;br /&gt;  DocumentBuilder builder = domFactory.newDocumentBuilder();&lt;br /&gt;  Document doc = builder.parse("data.xml");&lt;br /&gt;  XPath xpath = XPathFactory.newInstance().newXPath();&lt;br /&gt;  &lt;br /&gt;  // now, I start to actually do something interesting&lt;br /&gt;  Data data = new Data(Long.parseLong(&lt;br /&gt;    s(xpath, doc, "//request/timestamp/text()")));&lt;br /&gt;&lt;br /&gt;  XPathExpression xe = xpath.compile("//request/information/person");&lt;br /&gt;  NodeList nodes = (NodeList)xe.evaluate(doc,XPathConstants.NODESET);&lt;br /&gt;  &lt;br /&gt;  for(int i = 0; i &lt; nodes.getLength() ; i++) {&lt;br /&gt;   String gender = s(xpath, nodes.item(i), "//gender/text()");&lt;br /&gt;   String city = s(xpath, nodes.item(i), "//address/city/text()");&lt;br /&gt;   &lt;br /&gt;   if(Data.MALE.equals(gender.toLowerCase())) {&lt;br /&gt;    data.addMale(city);&lt;br /&gt;   } else if (Data.FEMALE.equals(gender.toLowerCase())) {&lt;br /&gt;    data.addFemale(city);&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   if(Integer.parseInt(s(xpath, nodes.item(i), "//age/text()")) &gt;= 18) {&lt;br /&gt;    data.incAdults();&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  System.out.println(data);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /*&lt;br /&gt;  * Why do I have to do that ? Even it it's two lines, &lt;br /&gt;  * I just let you imagine the look of the&lt;br /&gt;  * main loop without this function...&lt;br /&gt;         * But why the Xpath API doesn't have the four of five&lt;br /&gt;  * functions alike defined for each XPathConstants types ? &lt;br /&gt;  * Before actually begin to use the API, I have to redefine it...&lt;br /&gt;  */&lt;br /&gt; public static String s(XPath xpath, Object root, String expr) throws Exception {&lt;br /&gt;  XPathExpression xe = xpath.compile(expr);&lt;br /&gt;  return (String)xe.evaluate(root, XPathConstants.STRING);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, there is a lots of type cast, and I quickly loose what I'm looking for, even in a so simple class with so little cases and data to retrieve.&lt;br /&gt;&lt;br /&gt;So, at the end, what did I do ? Just use the Scala XML library. Same logic, in a scala class: &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;&lt;br /&gt;import scala.xml.XML&lt;br /&gt;&lt;br /&gt;object ScalaParseData {&lt;br /&gt;&lt;br /&gt; def main(args:Array[String]) {&lt;br /&gt;&lt;br /&gt;  val doc = XML.load("data.xml")&lt;br /&gt;  &lt;br /&gt;  val data = new Data((doc\\"request"\"timestamp" text).toLong)&lt;br /&gt;  &lt;br /&gt;  for(person &lt;- (doc\\"request"\"information"\"person")) {&lt;br /&gt;   val city = person\"address"\"city" text&lt;br /&gt;   &lt;br /&gt;   (person\"gender" text).toLowerCase match {&lt;br /&gt;    case Data.MALE =&gt; data.addMale(city)&lt;br /&gt;    case Data.FEMALE =&gt; data.addFemale(city)&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   if((person\"age" text).toInt &gt;= 18) data.incAdults&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  println(data)&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In both case, the same output is printed in stdout:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;time: 1250240149028&lt;br /&gt;female: &lt;br /&gt;male: Casper; &lt;br /&gt;adults: 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Even if you never look at Scala, you understand what is the global logic, what piece of data are looked for. Nothing to add :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="footnote_1"&gt;[1]&lt;/a&gt;: ok, the question here is: is Java the right language for that ? Well, it seems that the answer, for whose who still had doubts, is &lt;span style="font-weight:bold;"&gt;DEFINITLY NOT&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a name="footnote_2"&gt;[2]&lt;/a&gt; OK, even the data container is complex, and Java really miss Tuples structure to prototype efficiently. In such a process, you just don't want to spend time writing POJOs and POJOs and POJOs that are only, meaningless container for two string lists and a long, even if you IDE does 90%of the job. If you are interested by more efficient data structure for Java, you should go and look for &lt;a href="http://functionaljava.org/"&gt;Functional Java&lt;/a&gt;, that's a really cool project - and at least, you will have tuples (named "products" here), function class (to not have to define again and again that &lt;code&gt;Filter&amp;lt;E&amp;gt; { boolean filter(E element); }&lt;/code&gt; class)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-5685294940855084225?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/5685294940855084225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=5685294940855084225' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5685294940855084225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/5685294940855084225'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/08/why-simple-xml-processing-is-so-painful.html' title='Why simple XML processing is so painful in Java ?'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-560901380711200035</id><published>2009-06-07T19:32:00.003+02:00</published><updated>2009-06-07T19:52:08.935+02:00</updated><title type='text'>A Tour Of Scala @ OSSGTP - Paris OSS user group</title><content type='html'>&lt;span class="clickable" onclick="'dr4sdgryt(event,"&gt;Thursday (4 june 2009), I gave a presentation about the &lt;a href="http://scala-lang.org/"&gt;Scala programming language&lt;/a&gt; to the &lt;a href="http://www.ossgtp.org/xwiki/bin/"&gt;OSSGTP&lt;/a&gt; &lt;/span&gt;&lt;span class="clickable" onclick="'dr4sdgryt(event,"&gt;group&lt;/span&gt;&lt;span class="clickable" onclick="'dr4sdgryt(event,"&gt; (Open Source Software - Get Together in Paris).&lt;br /&gt;&lt;br /&gt;This presentation is available under Creative Common BY-NC-SA, so you are free to &lt;a href="http://www.slideshare.net/fanf42/a-tour-of-scala/download"&gt;download the source&lt;/a&gt;,  use it,  enhanced it and redistribute it !&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_1544991"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/fanf42/a-tour-of-scala?type=presentation" title="A Tour Of Scala"&gt;A Tour Of Scala&lt;/a&gt;&lt;object style="margin: 0px;" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=atourofscala-090607123113-phpapp01&amp;amp;stripped_title=a-tour-of-scala"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=atourofscala-090607123113-phpapp01&amp;amp;stripped_title=a-tour-of-scala" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;Keynote presentations&lt;/a&gt; from &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/fanf42"&gt;fanf42&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS: let me know if you see any errors, or if you use it, it will make me happy&lt;br /&gt;PPS: I took inspiration from "Programming in Scala" book by Martin Odersky, Lex Spoon and Bill Venners, "&lt;a href="http://www.slideshare.net/jboner/pragmatic-real-world-scala-45-min-presentation?type=powerpoint"&gt;Pragmatic Real World Scala&lt;/a&gt;" by Jonas Boner, "&lt;a href="http://www.slideshare.net/Odersky/fosdem-2009-1013261"&gt;A Scalable Language&lt;/a&gt;" by Martin Odersky and "&lt;a href="http://www.parleys.com/display/PARLEYS/Home#slide=1;talk=27131945;title=The%20Feel%20Of%20Scala"&gt;The feel of Scala&lt;/a&gt;" by Bill Venners - thanks for their great presentations and books !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-560901380711200035?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/560901380711200035/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=560901380711200035' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/560901380711200035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/560901380711200035'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/06/tour-of-scala-ossgtp-paris-oss-user.html' title='A Tour Of Scala @ OSSGTP - Paris OSS user group'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-7467478135896925869</id><published>2009-05-28T13:46:00.005+02:00</published><updated>2009-05-28T14:06:41.315+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>100 problems solved on Project Euler</title><content type='html'>Today, I just finished my 100th problem on &lt;a href="http://projecteuler.net/"&gt;Project Euleur&lt;/a&gt;, using Scala - of course.&lt;br /&gt;&lt;br /&gt;Project Euler is a really good way to learn a language on small problems, to see its different sides and idiomatic constructs, and be confronted on performance/algorithm optimization choices - that teaches you to feel when something migth make you gain an order or two of execution time / memory consumption, and when you are working for peanuts.&lt;br /&gt;&lt;br /&gt;OK, you won't see how the language solves big architectural design and maintenance problems, but you will learn if the language fits your mind, and if you are able to get things done with it. And definitly, Scala shines on such problems, and completly fits my mind.&lt;br /&gt;&lt;br /&gt;So, it was a really good learning experience. Now, I need to test it on bigger problem, to see how it goes on the long run, and I have some ideas for that...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-7467478135896925869?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/7467478135896925869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=7467478135896925869' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7467478135896925869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7467478135896925869'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/05/100-problems-solved-on-project-euler.html' title='100 problems solved on Project Euler'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-7100190609286613244</id><published>2009-04-21T09:35:00.006+02:00</published><updated>2009-04-21T11:58:16.349+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sun'/><category scheme='http://www.blogger.com/atom/ns#' term='personal thought'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>So, Sun is no more - Oracle is one of the big three</title><content type='html'>At the beginning, I though I wouldn't write about it. After all, all the Internet is talking about it, and I'm just a little developer, with my little biased view of the world through my small experience. But the thing may be so impacting for my daily life, and well Sun was such an uncommon adventure of a company, I wanted to mark the day. The following is just my thoughts on that big thing, take them as no more than that.&lt;br /&gt;&lt;br /&gt;So, yesterday Oracle announced to the world that they &lt;a href="http://www.sun.com/third-party/global/oracle/index.jsp"&gt;bought Sun&lt;/a&gt; for something like $7,4 Billions.&lt;br /&gt;My first feeling was (is) "better being Oracle than IBM". All in all, it may even be good. But wow, what a concentration ! Now, the "business software solution" industry is shared among 3 bigs (MS/IBM/Oracle), and that's all. And Oracle owns the database market, both opensource and proprietary.&lt;br /&gt;&lt;br /&gt;So, more in details, I thing that there is 3 domains of Sun that will be push foward by Oracle:&lt;br /&gt;- MySQL ;&lt;br /&gt;- the Java platform ;&lt;br /&gt;- Hardware, Solaris and related knowledge.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Hardware and Solaris &lt;/span&gt;&lt;br /&gt;The hardware and Solaris part are, I think, the domains with the clearer future : they will become the preferred platform for hight performance, highly tuned, very very  expensive SGBD server and Business app server.&lt;br /&gt;For me, that's the main point why Oracle is better than IBM : Oracle WANT these missing layers in their integrated stack, and IBM would have killed Sparc and Solaris, their old rivals. So, be prepared for Sparc/Solaris/Oracle SGBD killer servers, with Sun^W Oracle storage solutions, to make run your Sparc/Solaris/Weblogic business application servers.&lt;br /&gt;Moreover, we could see some really cool and great things happen in the filesytem domain: just think that ZSF, btrfs and OCFS(2) fathers are now in the same company...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;MySQL&lt;/span&gt;&lt;br /&gt;I don't fear anything for MySQL. Oracle bought InnoDB not so long time ago, they already thought to buy them at the same moment Sun did. MySQL could become their "low level" offer, and all the big customer will be encourage to switch to Oracle DB with wors like "you know, we own both system, but clearly you, you need our most expensive one, the one that works best".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Java language and the Java platform&lt;/span&gt;&lt;br /&gt;Oracle have a lot of business application build on Java, and now they own the platform. They also have two JVMs.&lt;br /&gt;Oh, and they make money with the techno, something Sun never succeeded to do.&lt;br /&gt;&lt;br /&gt;So clearly, Java was a BIG motivation for the operation, and Oracle will want to promote at the maximum its platform against opponents. And a better platform whould lead to better softwares, no ? :)&lt;br /&gt;&lt;br /&gt;The real question is about policies. What will happen to JCP ?  In the current model, the guerilla beside Sun and IBM was famous, things could become even worst now... Will Oracle try to follow MS way in the management of its software platform evolution to avoid it ?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Less clear points&lt;/span&gt;&lt;br /&gt;My real interrogation are around Sun existing application, and Oracle behavior toward OpenSource.&lt;br /&gt;&lt;br /&gt;Netbeans may be a winner here, even if Oracle seem to have taken interests onto Eclipse. But what will happen to Glassfish ? The v3 is amazing, it's still a reference implementation of JEE, but there's Weblogic... So, Glassfish has the low level / test solution, and Weblo for "real things" ?&lt;br /&gt;&lt;br /&gt;Even more frighting, what will happen to Sun's (really good) Identity and Access Management solution (OpenDS, OpenSSO, Identity Manager, etc) ? Oracle was a frontal concurrent here, I don't see them keep both offers...&lt;br /&gt;&lt;br /&gt;And what will happen to the Sun clear move toward open source ? Oracle is not reluctant to OSS (I mean, at least not more than IBM), and  they contributed some really nice stuff in the last years (btrfs for example). But they are not exactly an open source company, to say the least.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;So, what next for us ?&lt;/span&gt;&lt;br /&gt;So, my best hope is that Oracle will free a lot of technical/low level stuff, like filesystem, a JVM, etc. That kind of stuff has little added value (in dollars) for them, and they might attracts a lot of geek / small companies to work on and make them better. On the other hand, Oracle keep their higher level, more business oriented, and far more profitable middlewares as incomes sources.&lt;br /&gt;&lt;br /&gt;To conclude, there is one thing that I'm sure of: "It's tough making predictions, especially about the future", as would say Yogi Berra. Or Neils Bohr. Or Mark Twain. Or was it Robert Storm Petersen ? Well, at least, what is done is done, and let's see what will happen !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-7100190609286613244?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/7100190609286613244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=7100190609286613244' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7100190609286613244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/7100190609286613244'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/04/so-sun-is-no-more-oracle-is-one-of-big.html' title='So, Sun is no more - Oracle is one of the big three'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-1569934686493369186</id><published>2009-03-25T18:20:00.003+01:00</published><updated>2009-04-09T12:57:12.420+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='xstream'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tapestry 5 - Scala : view article in HTML, JSON or XML</title><content type='html'>&lt;h2&gt;We must have the REST in our blog, it will attract a lot of investors&lt;/h2&gt;&lt;br /&gt;The last time we saw how to &lt;a href="http://fanf42.blogspot.com/2009/01/t5-scala-layout-and-basic-crud.html"&gt;make basic CRUD functionalities for the blog&lt;/a&gt;. That was quite a long time, because I started to encounter some &lt;a href="http://fanf42.blogspot.com/2009/02/tapestry-5-scala-start-of-delusion.html"&gt;rough&lt;/a&gt; &lt;a href="http://fanf42.blogspot.com/2009/03/java-annotation-scala-object-and.html"&gt;edges&lt;/a&gt; that make Scala and T5 don't go together as smoothly as expected. Nevertheless, all problems were worked around.&lt;br /&gt;&lt;br /&gt;This article is about how simply one can customized the output format of her URL in a RESTful way (&lt;a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm"&gt;see that for more details about REST&lt;/a&gt;, but whatever says this too academic article, we all well know that "REST" means "pretty shiny URLs" and "being 2.0, not like whose outdated web service" ;). &lt;br /&gt;&lt;br /&gt;So, basically, what we will provide is two different ways of viewing an article:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A standard, HTML view with this kind of URLs: http://localhost:8080/blog/article/view/1 &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9D3n-ZqzF48/SZhxHI43FRI/AAAAAAAAAq8/2g_fdyZb-g0/s1600-h/blog_view_article.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_9D3n-ZqzF48/SZhxHI43FRI/AAAAAAAAAq8/2g_fdyZb-g0/s320/blog_view_article.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5303112928687756562" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;An XML or JSON output, with this kind of URLs: http://localhost:8080/blog/article/view:xml/1 or blog/article/view:json/1&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;article title=&amp;quot;First article&amp;quot; id=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;published&amp;gt;true&amp;lt;/published&amp;gt;&lt;br /&gt;    &amp;lt;content&amp;gt;Content for the first article&amp;lt;/content&amp;gt;&lt;br /&gt;    &amp;lt;creationDate&amp;gt;2009-03-24 16:16:31.865 CET&amp;lt;/creationDate&amp;gt;&lt;br /&gt;&amp;lt;/article&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{"article": {&lt;br /&gt;  "@published": "true",&lt;br /&gt;  "@title": "First article",&lt;br /&gt;  "@id": "1",&lt;br /&gt;  "content": "Content for the first article",&lt;br /&gt;  "creationDate": "2009-03-24 16:16:31.865 CET"&lt;br /&gt;}}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;The "view article" page&lt;/h2&gt;&lt;br /&gt;The first step here is to build a page that will show an article based on it's id. &lt;br /&gt;We want that an URL like: http://localhost:8080/blog/article/view/1&lt;br /&gt;Return the page: &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9D3n-ZqzF48/SckKKZfd6pI/AAAAAAAAArU/QmNq4jIypjY/s1600-h/view_article.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 138px;" src="http://2.bp.blogspot.com/_9D3n-ZqzF48/SckKKZfd6pI/AAAAAAAAArU/QmNq4jIypjY/s320/view_article.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5316792008845421202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For that, we add a ViewArticle class and ViewArticle template in the package "org.example.blog.pages.article".&lt;br /&gt;&lt;br /&gt;The template is trivial, we simply display meaningful information of a backed article object:&lt;br /&gt;&lt;em&gt;org.example.blog.pages.article.ViewArticle.tml&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;t:layout xmlns:t=&amp;quot;http://tapestry.apache.org/schema/tapestry_5_0_0.xsd&amp;quot;&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;h2&amp;gt;${article.title}&amp;lt;/h2&amp;gt;&lt;br /&gt; &amp;lt;h4&amp;gt;by ${authorname}, on ${article.creationDate}&amp;lt;/h4&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;div&amp;gt;&lt;br /&gt;  ${article.content}&lt;br /&gt; &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/t:layout&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And that's all. &lt;br /&gt;&lt;br /&gt;The Scala class is not much more complicated:&lt;br /&gt;&lt;em&gt;org.example.blog.pages.article.ViewArticle.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;class ViewArticle {&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  var articleDao : ReadDao[Article,String] = _&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  var conf : BlogConfiguration = _&lt;br /&gt;  &lt;br /&gt;  @Property&lt;br /&gt;  var article : Article = _&lt;br /&gt;  &lt;br /&gt;  var id : String = _&lt;br /&gt;  &lt;br /&gt;  def onActivate(id:String) { this.id = id }&lt;br /&gt;  &lt;br /&gt;  def getAuthorName() = this.conf.getAuthor.getLogin&lt;br /&gt;  &lt;br /&gt;  def setupRender {&lt;br /&gt;    this.article = this.get(id)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private def get(id:String) = &lt;br /&gt;    if(null == id ) NoneArticle&lt;br /&gt;    else this.articleDao.get(id).getOrElse(NoneArticle)&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We see that I use two services, the Article DAO that allows to retrieve article from their store, and the blog's configuration that is used to display to author name: the article object it accessible from the template because of the @Property annotation (this T5 annotation is in fact the same as the Scala @BeanProperty one, it generates the pair of getter/setter for the attribute), &lt;code&gt;getAuthorName()&lt;/code&gt; is called in the template by &lt;code&gt;${authorname}&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;The logic of the page is almost inexistent: when the page is activated (what means an HTTP request is handled by that page), we store the "id" parameter (in our example, it's "1") for when the page is rendered. &lt;a href="http://tapestry.apache.org/tapestry5/guide/pagenav.html"&gt;There is more about Tapestry 5 page activation and parameters here&lt;/a&gt;.&lt;br /&gt;When the page is rendered, we ask the article DAO to retrieve the article with the given ID. If none is found, or if the given id was null (no parameter was found in the URL), we used a special "NoneArticle" object for the rendering. This object is a placeholder that stands for "null" for article type, and is defined as follow:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.data.Article.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;object NoneArticle extends Article(None) {&lt;br /&gt;  creationDate = new Date(0L);&lt;br /&gt;  title = "No such article"&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And with that, the HTML view is over. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Marshalling article&lt;/h2&gt;&lt;br /&gt;Here we deal with the transformation of article object into XML or Json, and how we make a service for that task available in our blog.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;XStream, the swiss-knife of serialization&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Well, in fact I will confess something: I did almost nothing to make the other two output renderings works, it's basically only the mapping of an &lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; output to some Tapestry 5 event handlers. &lt;br /&gt;&lt;br /&gt;If you don't already know XStream, stop reading here, and just go and look for &lt;a href="http://xstream.codehaus.org/tutorial.html"&gt;its 2 minutes tutorial&lt;/a&gt; - it's actually a two minutes thing to read and shows how powerful Xstream is.&lt;br /&gt; &lt;br /&gt;For the lazy clicker, there's a summary: XStream is an amazing XML and JSON marshalling and unmarshalling library for Java. It's fast, it's powerful, it's broadly used with all the good that that carries, and its learning curve is counted in seconds.&lt;br /&gt; &lt;br /&gt;Basically, without any configuration, you can use it like that:&lt;br /&gt;&lt;pre class="sh_java"&gt;&lt;br /&gt;Person joe = new Person("Joe", "Walnes");&lt;br /&gt;XStream xstream = new XStream();&lt;br /&gt;String xml = xstream.toXML(joe);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And it will output something like that:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;org.foo.domain.person&amp;gt;&lt;br /&gt;  &amp;lt;firstname&amp;gt;Joe&amp;lt;/firstname&amp;gt;&lt;br /&gt;  &amp;lt;lastname&amp;gt;Walnes&amp;lt;/lastname&amp;gt;&lt;br /&gt;&amp;lt;/org.foo.domain.person&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With one more config line for the Xstream object:&lt;br /&gt;&lt;pre class="sh_java"&gt;xstream.alias("person", Person.class);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You get a prettier output:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;person&amp;gt;&lt;br /&gt;  &amp;lt;firstname&amp;gt;Joe&amp;lt;/firstname&amp;gt;&lt;br /&gt;  &amp;lt;lastname&amp;gt;Walnes&amp;lt;/lastname&amp;gt;&lt;br /&gt;&amp;lt;/person&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Doesn't it look simple? And if I say that it also works for JSON output, and also in the reverse way (from JSON/XML to Object), that output customization is almost infinite, you're likely to fall in love with this little, cute library.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Marshalling services for our blog&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;In the pages, we only need a simple service that transform object to a String representation. As always, we define an interface for that service:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.Marshaller.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;trait Marshaller { &lt;br /&gt;   def to(o:Any) : String&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, we are going to build two implementation for that service, one for XML output and one other for the JSON output. The two of them will extend a common Xstream based Marshaller:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.impl.XstreamMarshaller.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;class XstreamMarshaller(val xstream:XStream) extends Marshaller  {&lt;br /&gt;  override def to(o : Any) = this.xstream.toXML(o)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class XmlXstreamMarshaller() extends XstreamMarshaller(new XStream(new DomDriver()))&lt;br /&gt;&lt;br /&gt;class JsonXstreamMarshaller() extends XstreamMarshaller(new XStream(new JsonHierarchicalStreamDriver()))&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There is only one step remaining to enable the service in our blog: binding interface and implementation in the Tapestry module definition:&lt;br /&gt;&lt;em&gt;org.example.blog.services.AppModule.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;object AppModule {&lt;br /&gt;  //bind is a conventionnal method name for binding interface and implementation when no special configuration is needed&lt;br /&gt;  def bind(binder : ServiceBinder) {&lt;br /&gt;    binder.bind[Marshaller](classOf[Marshaller],classOf[impl.XmlXstreamMarshaller]) withId "xmlMarshaller"&lt;br /&gt;    binder.bind[Marshaller](classOf[Marshaller],classOf[impl.JsonXstreamMarshaller]) withId "jsonMarshaller"&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we assign a name (an Id) to each marshaller. That's because we now have two implementations for a given interface declared in the IoC registry. Tapestry 5 will not be able to know automatically what we really want to use when we will require a service injection for that interface, and so we will have to precise the name of the actual service we really want.&lt;br /&gt;&lt;br /&gt;An now, let's use these marshallers to render JSONinfied and XMLified articles. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Binding URL to marshaller output&lt;/h2&gt;&lt;br /&gt;This second part aims to produce the correct output based on the URL.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;T5 event handling system&lt;/h3&gt;&lt;br /&gt;Again, I did nothing special to bind URL and XML/JSON output since I used the standard Tapestry 5 event system: Url with ":" after a component or page name are interpreted as "component:eventname/eventparams".&lt;br /&gt;&lt;br /&gt;For example, &lt;code&gt;http://localhost:8080/blog/article/view:xml/1&lt;/code&gt; means: throws the "xml" event on page "article", with the "1" parameter. &lt;br /&gt;&lt;br /&gt;For our use case, the only thing to do is to handle "Xml" and "Json" events in the Scala back end of the "Article/View" page. Like most of the time in Tapestry 5, these event handlers are based on convention, and here the convention is to use "onEVENT" for the method name, where "EVENT" is the name of the event to handle. &lt;br /&gt;&lt;br /&gt;The modified ViewArticle class looks like:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.pages.article.ViewArticle.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;class ViewArticle {&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  var articleDao : ReadDao[Article,String] = _&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  var conf : BlogConfiguration = _&lt;br /&gt;  &lt;br /&gt;  @Inject @Service("xmlMarshaller")&lt;br /&gt;  var xmlMarshaller : Marshaller = _&lt;br /&gt;  &lt;br /&gt;  @Inject @Service("jsonMarshaller")&lt;br /&gt;  var jsonMarshaller : Marshaller = _&lt;br /&gt;&lt;br /&gt;  @Property&lt;br /&gt;  var article : Article = _&lt;br /&gt;  &lt;br /&gt;  var id : String = _&lt;br /&gt;  &lt;br /&gt;  def onActivate(id:String) { this.id = id }&lt;br /&gt;  &lt;br /&gt;  def getAuthorName() = this.conf.getAuthor.getLogin&lt;br /&gt;  &lt;br /&gt;  def setupRender {&lt;br /&gt;    this.article = this.get(id)&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  def onXml = new TextStreamResponse("text/xml",this.xmlMarshaller.to(NoneArticle))&lt;br /&gt;  def onJson = new TextStreamResponse("text/plain",this.jsonMarshaller.to(NoneArticle))&lt;br /&gt;  &lt;br /&gt;  def onXml(id:String) = {&lt;br /&gt;    new TextStreamResponse("text/xml",this.xmlMarshaller.to(this.get(id)))&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def onJson(id:String) = {&lt;br /&gt;    new TextStreamResponse("text/plain",this.jsonMarshaller.to(this.get(id)))&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private def get(id:String) = &lt;br /&gt;    if(null == id ) NoneArticle&lt;br /&gt;    else this.articleDao.get(id).getOrElse(NoneArticle)&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Compared to the first version, we just injected two marshallers and used them in event handlers. I set-up specific handlers for the case when no parameter is given in the URL. &lt;br /&gt;&lt;br /&gt;Note that we solved the injection ambiguity problem on "Marshaller" injection by naming the service we really want to be injected thanks to the "@Service("name")" annotation after the @Inject one. &lt;br /&gt;&lt;br /&gt;The only other remarkable thing is the &lt;code&gt;TextStreamResponse&lt;/code&gt; object, that allows to return arbitrary text output for rendering. It's an implementation of the  &lt;code&gt;StreamResponse&lt;/code&gt; interface, that allows to return arbitrary content - yes, returning a PDF for a given URL is a matter of returning the correct StreamResponse in a handler method. Simple, no ?&lt;br /&gt;&lt;br /&gt;With that, we have a first promising result. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;http://localhost:8080/blog/article/view:xml/1&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;org.example.blog.data.Article&amp;gt;&lt;br /&gt;  &amp;lt;published&amp;gt;true&amp;lt;/published&amp;gt;&lt;br /&gt;  &amp;lt;comments class=&amp;quot;scala.Nil$&amp;quot;/&amp;gt;&lt;br /&gt;  &amp;lt;content&amp;gt;Content for the first article&amp;lt;/content&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt;First article&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;creationDate&amp;gt;2009-03-25 14:19:41.940 CET&amp;lt;/creationDate&amp;gt;&lt;br /&gt;  &amp;lt;id class=&amp;quot;scala.Some&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;x class=&amp;quot;string&amp;quot;&amp;gt;1&amp;lt;/x&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;&amp;lt;/org.example.blog.data.Article&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And &lt;code&gt;http://localhost:8080/blog/article/view:json/1&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;{"org.example.blog.data.Article": {&lt;br /&gt;  "published": true,&lt;br /&gt;  "comments": {&lt;br /&gt;    "@class": "scala.Nil$"&lt;br /&gt;  },&lt;br /&gt;  "content": "Content for the first article",&lt;br /&gt;  "title": "First article",&lt;br /&gt;  "creationDate": "2009-03-25 14:19:41.940 CET",&lt;br /&gt;  "id": {&lt;br /&gt;    "@class": "scala.Some",&lt;br /&gt;    "x": {&lt;br /&gt;      "@class": "string",&lt;br /&gt;      "$": "1"&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And non existing article or no parameter, like in &lt;code&gt;http://localhost:8080/blog/article/view:xml/foobar&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;org.example.blog.data.NoneArticle_-&amp;gt;&lt;br /&gt;  &amp;lt;published&amp;gt;false&amp;lt;/published&amp;gt;&lt;br /&gt;  &amp;lt;comments class=&amp;quot;scala.Nil$&amp;quot;/&amp;gt;&lt;br /&gt;  &amp;lt;content/&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt;No such article&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;creationDate&amp;gt;1970-01-01 01:00:00.0 CET&amp;lt;/creationDate&amp;gt;&lt;br /&gt;  &amp;lt;id class=&amp;quot;scala.None$&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;/org.example.blog.data.NoneArticle_-&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's not too bad for a couple of line of code, but output should be nicer.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Configuring output&lt;/h3&gt;&lt;br /&gt;Actually, we don't want to show the qualified class name in the output, nor we need the comments here, and it will be cool to have "id" and "title" as attributes of the "article" node.&lt;br /&gt;&lt;br /&gt;For that, we will customized Xstream marshaller. &lt;br /&gt;&lt;br /&gt;The first step is to change the marshaller implementation registration in AppModule to a more configurable one:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.AppModule.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;  def bind(binder : ServiceBinder) {&lt;br /&gt;    //remove marshaller from here&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def buildXmlMarshaller(): Marshaller = {&lt;br /&gt;    val m = new XmlXstreamMarshaller&lt;br /&gt;    ConfigureArticle4Xstream.configure(m.xstream)&lt;br /&gt;    m&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def buildJsonMarshaller(): Marshaller = {&lt;br /&gt;    val m = new JsonXstreamMarshaller&lt;br /&gt;    ConfigureArticle4Xstream.configure(m.xstream)&lt;br /&gt;    m&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These new definition also build two marshallers, named "XmlMarshaller" and "JsonMarshaller", but with that way we are able to configure the Xstream instance of each implementation. &lt;br /&gt;Since our case is really simple, the two configurations are the same, and look like that:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.impl.XstreamMarshaller.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;object ConfigureArticle4Xstream {&lt;br /&gt;  def configure(x:XStream) {&lt;br /&gt;    import org.example.blog.data.{Article,NoneArticle}&lt;br /&gt;    //output "article" in place of org.example.blog.data.Article&lt;br /&gt;    x.alias("article",classOf[Article])&lt;br /&gt;    &lt;br /&gt;    //title and id will be output as attributes of article...&lt;br /&gt;    x.useAttributeFor(classOf[Article],"title")&lt;br /&gt;    x.useAttributeFor(classOf[Article],"id")&lt;br /&gt;&lt;br /&gt;    //...and since Id is not a simple string, we have to provide a converter to make it works&lt;br /&gt;    x.registerLocalConverter(classOf[Article],"id",new ArticleIdConverter())&lt;br /&gt;    &lt;br /&gt;    //we don't want to display comments&lt;br /&gt;    x.omitField(classOf[Article],"comments")&lt;br /&gt;    &lt;br /&gt;    //special config for NoneArticle&lt;br /&gt;    x.alias("article",NoneArticle.getClass)&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Each line provides the commented explanation.&lt;br /&gt;The id converter simply output the id if available, or "none":&lt;br /&gt;&lt;em&gt;org.example.blog.services.impl.XstreamMarshaller.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;class ArticleIdConverter extends SingleValueConverter {&lt;br /&gt;  def fromString(s:String) = if("none" == s) None else Some(s)&lt;br /&gt;  def toString(a:Object) = a match { &lt;br /&gt;    case None =&gt; "none" &lt;br /&gt;    case Some(x) =&gt; x.toString &lt;br /&gt;    case _ =&gt; error("Not supported type: " + a.getClass.getName)&lt;br /&gt;  }&lt;br /&gt;  def canConvert(c:Class[_]) = {&lt;br /&gt;    if(c == classOf[scala.Option[_]]) true&lt;br /&gt;    else false&lt;br /&gt;  }  &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With this configuration, outputs are much nicer:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;http://localhost:8080/blog/article/view:xml/1&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&amp;lt;article title=&amp;quot;First article&amp;quot; id=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;published&amp;gt;true&amp;lt;/published&amp;gt;&lt;br /&gt;  &amp;lt;content&amp;gt;Content for the first article&amp;lt;/content&amp;gt;&lt;br /&gt;  &amp;lt;creationDate&amp;gt;2009-03-25 15:09:20.476 CET&amp;lt;/creationDate&amp;gt;&lt;br /&gt;&amp;lt;/article&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And &lt;code&gt;http://localhost:8080/blog/article/view:json/1&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;{"article": {&lt;br /&gt;  "@title": "First article",&lt;br /&gt;  "@id": "1",&lt;br /&gt;  "published": true,&lt;br /&gt;  "content": "Content for the first article",&lt;br /&gt;  "creationDate": "2009-03-25 15:09:20.476 CET"&lt;br /&gt;}}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And non existing article or no parameter, like in &lt;code&gt;http://localhost:8080/blog/article/view:xml/foobar&lt;/code&gt; leads to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;{"article": {&lt;br /&gt;  "@title": "No such article",&lt;br /&gt;  "@id": "none",&lt;br /&gt;  "published": false,&lt;br /&gt;  "content": "",&lt;br /&gt;  "creationDate": "1970-01-01 01:00:00.0 CET"&lt;br /&gt;}}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, we can say too our chief that he can go and look for investor, our blog has the REST (well, almost ;).&lt;br /&gt;And that's all for today !&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Next time&lt;/h2&gt;&lt;br /&gt;We reach a rather satisfying result with really few lines of code, but I have to say that our implementation is bad. &lt;br /&gt;&lt;br /&gt;The main reason for that is that there is a bunch of coupling and code duplication at the moment:&lt;br /&gt;- from the page designer point of vue, it's crappy to have to inject several marshallers, and choose the correct one for each event;&lt;br /&gt;- moreover, addind a new output (for example, plain text) would mean modifying *all* pages that use marshallers;&lt;br /&gt;- with the actual configuration, each time that we want to customize an output for a given object, we have to actually modify the code of XstreamMarshaller core implementation, or in the core module definition ! &lt;br /&gt;&lt;br /&gt;So the next time, we will see how we can improve these points. And again, it will be easy, thanks to Tapestry IoC provided features.&lt;br /&gt;&lt;br /&gt;As always, the real full code is available at Github at this tag : &lt;br /&gt;&lt;a href="http://github.com/fanf/scala-t5-blog/tree/article4_20090325"&gt;http://github.com/fanf/scala-t5-blog/tree/article4_20090325&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-1569934686493369186?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/1569934686493369186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=1569934686493369186' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/1569934686493369186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/1569934686493369186'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/02/tapestry-5-scala-view-article-in-html.html' title='Tapestry 5 - Scala : view article in HTML, JSON or XML'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9D3n-ZqzF48/SZhxHI43FRI/AAAAAAAAAq8/2g_fdyZb-g0/s72-c/blog_view_article.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3685339236438393369</id><published>2009-03-16T10:18:00.006+01:00</published><updated>2009-03-16T16:26:04.614+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='annotation'/><category scheme='http://www.blogger.com/atom/ns#' term='javassist'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Java annotation, scala object and javassist don't get along well</title><content type='html'>[&lt;i&gt;Update: in the next paragraph, "showstopper" is clearly too strong - put it in my bad english level. The title is perhaps better, I wanted to say that things didn't came along as well as I hoped initially. In no case I wanted to sound over-pessimistic. Actually, the workaround is rather simple : I can use a direct call to the look-up service of T5 IOC each time I need a named service in place of the direct injection of that service.&lt;/i&gt;]&lt;br /&gt;&lt;br /&gt;In my quest of using Tapestry 5 with a Scala back-end, I believe I fall on a showstopper. I seems that &lt;a href="http://www.jboss.org/javassist"&gt;Javassist&lt;/a&gt; doesn't see annotation on method parameter in Scala object, although the annotation (being marked with Runtime retention) is seen with the Java reflexion API.&lt;br /&gt;&lt;br /&gt;I tested with both Scala 2.7.3 and 2.8.0-nigtly, and both Javassist 3.9.0.GA and 3.10 - the behaviour is consistent in all combinations. &lt;br /&gt;&lt;br /&gt;In fact, what seems to happens is that when one defines a Scala object "Foo.scala", scalac generates two classes : "Foo.class" that is a kind of singleton facade and initializer, and "Foo$.class" that is the actual class. &lt;br /&gt;&lt;br /&gt;When the java reflexion API is used, I think that scala delegates the call in the rigth way. The problem seems to be that Javassist directly read the bytecode of "Foo.class", and doesn't see the annotation - it seems to be only on the method in "Foo$.class".&lt;br /&gt;&lt;br /&gt;You can you see this behaviour like that:&lt;br /&gt;&lt;br /&gt;Make a simple Java annotation, and compile it, something like &lt;a href="http://svn.apache.org/viewvc/tapestry/tapestry5/tags/releases/5.0.18/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java?view=markup"&gt;@InjectService in Tapestry5-annotation package&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_java"&gt;&lt;br /&gt;@Target({PARAMETER, FIELD})&lt;br /&gt;@Retention(RUNTIME)&lt;br /&gt;@Documented&lt;br /&gt;public @interface InjectService&lt;br /&gt;{&lt;br /&gt;    String value();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create a scala class that make use of that annotation and test it visibility thanks to Java reflexion API and Javassist :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;import org.apache.tapestry5.ioc.annotations.InjectService&lt;br /&gt;import javassist._&lt;br /&gt;import javassist.runtime._&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;object ObjectTestAnnotation {&lt;br /&gt;  def methodWithParamAnnot(@InjectService("service id") s:String) = s&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ClassTestAnnotation {&lt;br /&gt;  def methodWithParamAnnot(@InjectService("service id") s:String) = s  &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object Main {&lt;br /&gt;&lt;br /&gt;  def main(args: Array[String]) { &lt;br /&gt;    /*&lt;br /&gt;     * Using Java reflexion API&lt;br /&gt;     */&lt;br /&gt;    val methodWithParamAnnot = ObjectTestAnnotation.&lt;br /&gt;      getClass.getMethod("methodWithParamAnnot", classOf[String])&lt;br /&gt;    val annotations = methodWithParamAnnot.getParameterAnnotations&lt;br /&gt;    println("* with java reflexion API, on ObjectTestAnnotation")&lt;br /&gt;    annotations.foreach(_.foreach( x =&gt; println(x)))&lt;br /&gt;    // print:&lt;br /&gt;    // * with java reflexion API, on ObjectTestAnnotation&lt;br /&gt;    // @org.apache.tapestry5.ioc.annotations.InjectService(value=service id)&lt;br /&gt;&lt;br /&gt;    val methodWithParamAnnot1 = classOf[ClassTestAnnotation].&lt;br /&gt;      getMethod("methodWithParamAnnot", classOf[String])&lt;br /&gt;    val annotations1 = methodWithParamAnnot1.getParameterAnnotations&lt;br /&gt;    println("* with java reflexion API, on ClassTestAnnotation")&lt;br /&gt;    annotations1.foreach(_.foreach( x =&gt; println(x)))&lt;br /&gt;    // print:&lt;br /&gt;    // * with java reflexion API, on ClassTestAnnotation&lt;br /&gt;    // @org.apache.tapestry5.ioc.annotations.InjectService(value=service id)&lt;br /&gt;&lt;br /&gt;    /*&lt;br /&gt;     * Using Javassist&lt;br /&gt;     */&lt;br /&gt;    val cp = ClassPool.getDefault()&lt;br /&gt;    val ctString = cp.get("java.lang.String")&lt;br /&gt;    val methodWithParamAnnot2  = cp.get("test.ObjectTestAnnotation")&lt;br /&gt;      .getDeclaredMethod("methodWithParamAnnot",Array(ctString))&lt;br /&gt;    val annotations2 =  methodWithParamAnnot2.getParameterAnnotations&lt;br /&gt;    println("* with javassist, on ObjectTestAnnotation")&lt;br /&gt;    annotations2.foreach(_.foreach( x =&gt; println(x)))&lt;br /&gt;&lt;br /&gt;    // print (AND THAT'S BAD, the annotation is not seen !)&lt;br /&gt;    &lt;br /&gt;    // * with javassist, on ObjectTestAnnotation&lt;br /&gt;      &lt;br /&gt;    val methodWithParamAnnot2_bis  = cp.get("test.ObjectTestAnnotation$")&lt;br /&gt;      .getDeclaredMethod("methodWithParamAnnot",Array(ctString))&lt;br /&gt;    val annotations2_bis =  methodWithParamAnnot2_bis.getParameterAnnotations&lt;br /&gt;    println("* with javassist, on ObjectTestAnnotation$")&lt;br /&gt;    annotations2_bis.foreach(_.foreach( x =&gt; println(x)))&lt;br /&gt;    // print:&lt;br /&gt;    // * with javassist, on ObjectTestAnnotation$&lt;br /&gt;    // @org.apache.tapestry5.ioc.annotations.InjectService(value="service id")&lt;br /&gt;    &lt;br /&gt;  &lt;br /&gt;    val methodWithParamAnnot3  = cp.get("test.ClassTestAnnotation")&lt;br /&gt;      .getDeclaredMethod("methodWithParamAnnot",Array(ctString))&lt;br /&gt;    val annotations3 =  methodWithParamAnnot3.getParameterAnnotations&lt;br /&gt;    println("* with javassist, on ClassTestAnnotation")&lt;br /&gt;    annotations3.foreach(_.foreach( x =&gt; println(x)))&lt;br /&gt;    // print:&lt;br /&gt;    // * with javassist, on ClassTestAnnotation&lt;br /&gt;    // @org.apache.tapestry5.ioc.annotations.InjectService(value="service id")&lt;br /&gt;    &lt;br /&gt;    println("done")&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;  } &lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cry ! Because, of course, Tapestry 5 uses these annotations in such a way that a bug here make the whole thing unusable - the core of T5-IOC container relies on them. &lt;br /&gt;I would have to see if I can use a class in place of the object...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3685339236438393369?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3685339236438393369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3685339236438393369' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3685339236438393369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3685339236438393369'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/03/java-annotation-scala-object-and.html' title='Java annotation, scala object and javassist don&apos;t get along well'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-252765418681522279</id><published>2009-03-03T10:51:00.003+01:00</published><updated>2009-03-03T11:00:06.580+01:00</updated><title type='text'>Small UTF-8 URL</title><content type='html'>I just found this site thanks to reddit : http://www.reddit.com/r/programming/comments/81ld2/tinyarrows_what_do_you_think_site_we_made_to/&lt;br /&gt;&lt;br /&gt;The goal is to build tiny URL from long ones, something as old as the Internet. The difference is that the URL can be build with UTF-8, what gives you funny opportunities :)&lt;br /&gt;&lt;br /&gt;So now, you can access my blog with these URL :&lt;br /&gt;&lt;br /&gt;&lt;a href="http://➡.ws/φ"&gt;http://➡.ws/φ&lt;/a&gt;&lt;br /&gt;&lt;a href="http://➡.ws/φ42"&gt;http://➡.ws/φ42&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ok, that's something a little useless, but it's cool and funny :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-252765418681522279?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/252765418681522279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=252765418681522279' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/252765418681522279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/252765418681522279'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/03/small-utf-8-url.html' title='Small UTF-8 URL'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2568278546357938975</id><published>2009-02-15T21:01:00.007+01:00</published><updated>2009-02-15T22:31:18.647+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='personal'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='research'/><category scheme='http://www.blogger.com/atom/ns#' term='coq'/><title type='text'>Personal thougth: Scala, Haskell, Coq and so little time !</title><content type='html'>There is a lot of really cool stuff going on the world in computer science and more precisely in formal proof, the last I found being: &lt;a href="http://arxiv.org/abs/cs/0605058"&gt;this article about "A Monadic, Functional Implementation of Real Numbers"&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Haskell is continuously gaining attention, Scala and Clojure bring new dimensions to the JVM, this later (hopefully) evolving towards better support for functional paradigm and perhaps more verification support. &lt;br /&gt;&lt;br /&gt;I'm lucky enough to have already worked in formal proof with the &lt;a href="http://compcert.inria.fr/doc/index.html"&gt;CompCert team&lt;/a&gt; when I graduated... but it was 5 years in the past. &lt;br /&gt;&lt;br /&gt;In the meantime, I worked in the "real life business", and now I'm sure this don't feat to me. Well, at least I worked in the security domain, and discovered that their is some really hight level work done in this domain in France: two years ago, Gemalto proved a never reached level of certification for the JavaCard plateform:&lt;br /&gt;&lt;a href="http://www.gemalto.com/php/pr_view.php?id=239"&gt;http://www.gemalto.com/php/pr_view.php?id=239&lt;/a&gt; . And they did it with Coq, what a coincidence :)&lt;br /&gt;&lt;br /&gt;Well, I really want to spend a lot of more time in all these fields. So much things to do, so little time to spend in them...&lt;br /&gt;&lt;br /&gt;EDIT: I forgot all the cool things around parallelism, Pi-Calculus, or actors (I believe there is something great that is on the way with &lt;a href="http://erikengbrecht.blogspot.com/"&gt;Scala actors&lt;/a&gt; ;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2568278546357938975?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2568278546357938975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2568278546357938975' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2568278546357938975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2568278546357938975'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/02/personal-thougth-scala-haskell-coq-and.html' title='Personal thougth: Scala, Haskell, Coq and so little time !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8415243917107996803</id><published>2009-02-12T11:48:00.003+01:00</published><updated>2009-02-12T14:16:40.889+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tapestry 5 - Scala : start of delusion</title><content type='html'>I didn't write anything for a long time on my Tapestry 5 / Scala experiment. Things are starting to go wrong. &lt;br /&gt;&lt;br /&gt;From one part, I found what may have been a bug in Scala ( https://lampsvn.epfl.ch/trac/scala/ticket/1695 ) and that delayed me lot in the use of T5 IoC binder. &lt;br /&gt;&lt;br /&gt;For the other part, T5 IoC does not seems to support parameterized types at more than one level, and so I can't use parameterized class in contributions. &lt;br /&gt;&lt;br /&gt;For example, I can't contribute Tuple, or (and that's quite a big limitation) class because in Scala, you can't use the unparameterized "Class" argument, it must be "Class[Something]", and here lies the hell of generics...&lt;br /&gt;&lt;br /&gt;So for now, I'm beginning to thing that T5 and Scala don't feet so well together, or at least that I have some nuts to scratch and some "best practices" to find before going further in the test.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;EDIT: as proposed by Ricky Clarkson, for the class problem, just use Class[_]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8415243917107996803?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8415243917107996803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8415243917107996803' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8415243917107996803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8415243917107996803'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/02/tapestry-5-scala-start-of-delusion.html' title='Tapestry 5 - Scala : start of delusion'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-4909988773846496483</id><published>2009-01-26T11:44:00.003+01:00</published><updated>2009-01-27T09:53:21.370+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='ivy'/><category scheme='http://www.blogger.com/atom/ns#' term='easyant'/><title type='text'>Ivy 2.0 released</title><content type='html'>The java library dependency management system Ivy finally reached the 2.0.0 released, and that's a &lt;strong&gt;great&lt;/strong&gt; new. &lt;br /&gt;&lt;br /&gt;The release note is here:&lt;br /&gt;&lt;a href="http://ant.apache.org/ivy/history/2.0.0/release-notes.html"&gt;http://ant.apache.org/ivy/history/2.0.0/release-notes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(for the lazy clicker, here is the announcement part of the release note:)&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;Jan 20, 2009 - The Ivy project is pleased to announce its 2.0.0 release.&lt;br /&gt;This is the first non-beta release of Ivy under Apache.&lt;br /&gt;&lt;br /&gt;Ivy is a tool for managing (recording, tracking, resolving and&lt;br /&gt;reporting) project dependencies, characterized by flexibility,&lt;br /&gt;configurability, and tight integration with Apache Ant.&lt;br /&gt;&lt;br /&gt;Key features of the 2.0.0 release are&lt;br /&gt;* enhanced Maven2 compatibility, with several bug fixes and more&lt;br /&gt;  pom features covered&lt;br /&gt;* improved cache management, including dynamic revision caching&lt;br /&gt;  with fine grain TTL&lt;br /&gt;* improved concurrency support with cache locking and atomic publish&lt;br /&gt;* namespace aware validation, allowing to use validation with&lt;br /&gt;  extra attributes&lt;br /&gt;* new 'packager' resolver added&lt;br /&gt;* better and more homogeneous relative paths handling&lt;br /&gt;* better support for local builds&lt;br /&gt;* numerous bug fixes as documented in Jira and in the release notes&lt;br /&gt;&lt;br /&gt;We encourage all users of Ivy to update to this new version.&lt;br /&gt;&lt;br /&gt;Issues should be reported to:&lt;br /&gt;https://issues.apache.org/jira/browse/IVY&lt;br /&gt;&lt;br /&gt;Download the 2.0.0 release at:&lt;br /&gt;http://ant.apache.org/ivy/download.cgi&lt;br /&gt;&lt;br /&gt;More information can be found on the Ivy website:&lt;br /&gt;http://ant.apache.org/ivy/&lt;br /&gt;&lt;br /&gt;Regards,&lt;br /&gt;Maarten Coene&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note: I'm in now way implied in the Ivy dev-team, I just love their tool and wanted to thanks them for it. &lt;br /&gt;&lt;br /&gt;Ivy seems to be loved by new "build system" make. &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;, the Groovy buildr, is based on Ivy.&lt;br /&gt;I will also signal the on-going work around an "maven-style build system with a stack of convention" build on top of Ivy and Ant, &lt;a href="http://easyant.org"&gt;easy-ant&lt;/a&gt; (and there is an irc chan on freenode: #easyant). The project is work-in-progress, but a lot has already been done, and I believe it will be a great solution for all of us that are pissed-off by Maven, or just can't move from Ant but want to normalized (or "base on conventions") their build scripts, and integrate Ivy. &lt;br /&gt;&lt;br /&gt;Note 2: I'm neither  implied in easy-ant dev ;)&lt;br /&gt;&lt;br /&gt;So, it seems that Maven is not the final winner in Java build system land, and that's good (no monopole, concurrency for the best...) !&lt;br /&gt;&lt;br /&gt;Update: I simply forgot to link to &lt;a href="http://xhab.blogspot.com/2009/01/apache-ivy-20-final-is-out.html"&gt;Xavier Henin blog post about Ivy 2.0.0 release&lt;/a&gt;. Shame on me :/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-4909988773846496483?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/4909988773846496483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=4909988773846496483' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4909988773846496483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4909988773846496483'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/ivy-20-released.html' title='Ivy 2.0 released'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-263968159155294498</id><published>2009-01-19T07:01:00.017+01:00</published><updated>2009-04-09T13:02:01.886+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tapestry 5 - Scala : a layout and basic CRUD for the blog</title><content type='html'>After setting up &lt;a href="http://fanf42.blogspot.com/2009/01/tapestry-5-with-scala-get-code.html"&gt;a hello world application in Scala and Tapestry&lt;/a&gt;, and testing how &lt;a href="http://fanf42.blogspot.com/2009/01/t5-scala-first-injection-and-property.html"&gt;Tapestry IoC / property access works in this environment&lt;/a&gt;, it's time to actually do something.&lt;br /&gt;&lt;br /&gt;So, this article will explain how I set up the basic fonctionnalities for our blog:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;build a "Layout" component, so that the development will hurt our eyes a little less;&lt;/li&gt;&lt;li&gt;add an Article object, and the standards pages to use it:&lt;ul&gt;&lt;/li&gt;&lt;li&gt;the "home page" page will show all the published articles;&lt;/li&gt;&lt;li&gt;a "create" page will allow to add new article;&lt;/li&gt;&lt;li&gt;a "view" page will show only one article and its comments&lt;/li&gt;&lt;li&gt;a "manage" page will allows to view a list of all the article with some actions, like publish, delete, edit.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;h2&gt;Index&lt;/h2&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#layout"&gt;Setting up a layout&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#crud"&gt;Create, Retrieve, Update, Detele articles&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#article"&gt;The "Article" domain object&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#dao"&gt;Data access object&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#abstract_dao"&gt;Generic DAO API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#inmemory_dao"&gt;In memory Article DAO&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#dao_injection"&gt;Enable Article DAO service thanks to T5 IoC&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href="#presentation"&gt;Putting the parts together : the presentation layer&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#homepage"&gt;The Home page&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#create_page"&gt;Create new articles&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#manage_page"&gt;Manage all articles&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href="#final"&gt;Final words&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#source"&gt;Source code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="layout"&gt;&lt;h1&gt;Setting up a layout&lt;/h1&gt;&lt;/a&gt;&lt;br /&gt;Using "layout" is a common pattern to apply the same design for all the site. In tapestry, no need to use an external template engine like sitemesh, you can simply build a "layout component" that you will use on all page that have to be decorated. &lt;br /&gt;&lt;br /&gt;This pattern is so common that Tapestry 5 &lt;a href=http://tapestry.apache.org/tapestry5/guide/layout.html""&gt;has a documentation page on how to do it with T5&lt;/a&gt;, so you just have to follow it : the harder part is to design the layout, or if, like me, you are a dumb in design, find a cool CSS/HTML template on internet (thank you &lt;a href="http://www.free-css-templates.com/"&gt;Free CSS Templates&lt;/a&gt; for the one I chose. &lt;br /&gt;&lt;br /&gt;As it's the first time that we will build a Tapestry 5 component, I will details a little what we need. In Tapestry 5, component are simple POJOs. They go under the ${t5-root}/components package, and are coupled with a Template (.tml) file.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;create the ${root}/components/Layout.tml and ${root}/components/Layout.java couple of files for our component;&lt;/li&gt;&lt;li&gt;add the needed CSS/images in the webapp directory.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The code for the layout is here:&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;@IncludeStylesheet(Array("context:css/red/style.css"))&lt;br /&gt;class Layout {&lt;br /&gt;&lt;br /&gt;  @Inject @Property&lt;br /&gt;  var conf : BlogConfiguration = _&lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The interesting part is the @IncludeStyleSheet annotation, that say to T5 ti add it the given CSS into the header of the pages where this component is used, what is handy for a layout component. &lt;br /&gt;&lt;br /&gt;We can see that in Scala, we can't simply use the &lt;pre&gt;@IncludeStylesheet({"context:css/red/style.css"})&lt;/pre&gt; notation, and have to explicitly build a new array - hopefully, it's trivial in Scala. &lt;br /&gt;&lt;br /&gt;The template part of the component is bigger, since it's there that goes all the common HTML declaration. &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot; xmlns:t=&amp;quot;http://tapestry.apache.org/schema/tapestry_5_0_0.xsd&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt; &amp;lt;title&amp;gt;${conf.blogTitle}&amp;lt;/title&amp;gt;&lt;br /&gt; &amp;lt;meta http-equiv=&amp;quot;Content-Language&amp;quot; content=&amp;quot;English&amp;quot; /&amp;gt;&lt;br /&gt; &amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;div id=&amp;quot;wrap&amp;quot;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;&lt;br /&gt;   &amp;lt;h1&amp;gt;&amp;lt;a t:type=&amp;quot;pagelink&amp;quot; t:page=&amp;quot;index&amp;quot;&amp;gt;${conf.blogTitle}&amp;lt;/a&amp;gt;&amp;lt;/h1&amp;gt;&lt;br /&gt;   &amp;lt;h2&amp;gt;${conf.blogDescription}&amp;lt;/h2&amp;gt;&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt; &lt;br /&gt;  &amp;lt;div id=&amp;quot;menu&amp;quot;&amp;gt;&lt;br /&gt;   &amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;a t:type=&amp;quot;pagelink&amp;quot; t:page=&amp;quot;index&amp;quot;&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;[...]&lt;br /&gt;   &amp;lt;/ul&amp;gt;&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;br /&gt;   &amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt; &lt;br /&gt;    &lt;br /&gt;    &amp;lt;t:body /&amp;gt;&lt;br /&gt;   &lt;br /&gt;   &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;br /&gt;   &amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt; &lt;br /&gt;   &lt;br /&gt;    &amp;lt;h2&amp;gt;Archives&amp;lt;/h2&amp;gt;&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;[... here will go the archives ...]&lt;br /&gt;    &amp;lt;/ul&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;h2&amp;gt;Tags :&amp;lt;/h2&amp;gt;&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;[... here will go tags link ...]&lt;br /&gt;    &amp;lt;/ul&amp;gt;&lt;br /&gt;    &lt;br /&gt;   &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;br /&gt;   &amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;div id=&amp;quot;bottom&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;  &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;&lt;br /&gt;   Designed by &amp;lt;a href=&amp;quot;http://www.free-css-templates.com/&amp;quot;&amp;gt;Free CSS Templates&amp;lt;/a&amp;gt;&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt; &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The important part it the &lt;b&gt;&amp;lt;t:body /&amp;gt;&lt;/b&gt; tag, that says "here will go what will be find between the &amp;lt;t:layout&amp;gt; and &amp;lt;/t:layout&amp;gt; tags. So, in the page where we want to use this layout, we will use template code like:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;t:layout xmlns:t=&amp;quot;http://tapestry.apache.org/schema/tapestry_5_0_0.xsd&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;h2&amp;gt;New article&amp;lt;/h2&amp;gt;&lt;br /&gt;  [....]&lt;br /&gt;&lt;br /&gt;&amp;lt;/t:layout&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And now, our blog is prettier:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9D3n-ZqzF48/SXNUj3zJ5hI/AAAAAAAAAqc/Ar455BepQ54/s1600-h/blog_layout.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 233px;" src="http://2.bp.blogspot.com/_9D3n-ZqzF48/SXNUj3zJ5hI/AAAAAAAAAqc/Ar455BepQ54/s320/blog_layout.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5292666962341127698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;br /&gt;Note: I equally use &amp;lt;htmlTag t:type="T5_component"...&amp;gt; and &amp;lt;t:="T5_component"&amp;gt; notation to include T5 component in templates. The first one is better for designer, as template preview is correct, the second one is a little shorter. They are equivalent, and I should homogeneously use one or the other...&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="crud"&gt;&lt;h1&gt;Article's CRUD&lt;/h1&gt;&lt;/a&gt;&lt;br /&gt;All this blog application is a pretext for that very part, so let's take a look at it. Reminder: "CRUD" stands for "Create, Retrieve, Update, Delete", and is a well know acronym that is used for simple application, with very little domain logic, and which are almost a front-end for datas, persisted in some layer (MySQL comes to mind, but CouchDB is a better buzz word today ;) &lt;br /&gt;&lt;br /&gt;To sum-up, we have Article objects, a DAO to persist them, and a couple of pages to enable human I/O. &lt;br /&gt;&lt;br /&gt;&lt;a name="article"&gt;&lt;h2&gt;The "Article" domain object&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;An article is an object with an id, a title, a content, a list of comments and a creation date. &lt;br /&gt;&lt;br /&gt;The "id" is unique identifier for an article among all the blog's article. Most of the time, it will be used to identity a particular article in the persistence layer or in URL. &lt;br /&gt;I take the choice to let the persistance layer assigned the id, because we really are in a CRUD application, and no business logic can provide a realiable unique identifier. That means that a not yet persisted article has no id. In the same time, I want to enforce the fact that Id are imutable datas, that given a Article object, the id won't ever change. &lt;br /&gt;&lt;br /&gt;In java, this kind of requirement can't easily be done in an other way than usgin "null". In Scala as in many other language, we have an &lt;b&gt;Option&lt;/b&gt; type that has two kind of value:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the "None" value, which means "there is no data here";&lt;/li&gt;&lt;li&gt;the "Some[TypeOfData]" value, which means "there is a data here, and that is it's value".&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I use this type for the article "Id", and the "Id" is a constructor param value of article, so that:&lt;ul&gt;&lt;li&gt;article id is immutable: an living object can't have it's id change;&lt;/li&gt;&lt;li&gt;an article with "None" id has never been saved ;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;the persistence layer will assign IDs and return article with there definitive ID&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Given that, that's the code for the Article object:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.data.Article.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;class Article(val id:Option[String]) {&lt;br /&gt;  /*&lt;br /&gt;   * "none" is not allowed for article ID&lt;br /&gt;   */&lt;br /&gt;  assert( id.forall( (s:String)=&gt; !(s.toLowerCase == "none" ))) &lt;br /&gt;  &lt;br /&gt;  @BeanProperty var creationDate = new Date()&lt;br /&gt;  &lt;br /&gt;  @BeanProperty var title = ""&lt;br /&gt;  &lt;br /&gt;  @BeanProperty var content = ""&lt;br /&gt;  &lt;br /&gt;  @BeanProperty var comments = List[Comment]()&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;  @BeanProperty var published = false&lt;br /&gt;  &lt;br /&gt;  def getId = id&lt;br /&gt;  &lt;br /&gt;  /*&lt;br /&gt;   * String translation of the ID. Of course, it &lt;br /&gt;   * requires that id can't be the "None" String, &lt;br /&gt;   * and that's why we add the "assert" requirement&lt;br /&gt;   */&lt;br /&gt;  def getDisplayId = this.id.getOrElse("None") &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object Article {&lt;br /&gt;  &lt;br /&gt;  /*&lt;br /&gt;   * Create a copy Article from a source one, &lt;br /&gt;   * setting the ID to a new value.&lt;br /&gt;   */&lt;br /&gt;  def apply(id:String, source:Article) : Article = {&lt;br /&gt;    val a = new Article(Some(id))&lt;br /&gt;    a.title = source.title&lt;br /&gt;    a.content = source.content&lt;br /&gt;    a.comments = source.comments&lt;br /&gt;    a.creationDate = source.creationDate&lt;br /&gt;    a.published = source.published&lt;br /&gt;    a&lt;br /&gt;  } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Apart from the Article constructor and "Id" type explained before, there is three other notable things in this class:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A &lt;b&gt;getDisplayId&lt;/b&gt; that is a simple method to give the article Id to other layer, especially the presentation layer. I chose to map "Some(id)" to the given id string, and the  "None" type to the "None" string, what implies that I should never accept the "None" id;&lt;/li&gt;&lt;li&gt;since I can't accept "None" string as id, I added a requirement through an assertion (and no, performances don't matter, it's a tool blog application ;)&lt;/li&gt;&lt;li&gt;finally, there is a strange "object" definition after my class with the same name as it, that needs its own paragraph&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;"objects" are the Scala way to define static methods and contents, and it's why I used the "object" key word in the AppModule.&lt;br /&gt;When paired with a class, it is called a companion object for the class. They have some special rights, in  particular regarding visibilyity, that goes beyond this article. &lt;br /&gt;&lt;br /&gt;I used this one to create a "copy" method that allows to create an article with a given id, different from the source - remember, I want to have immutable ids for an Article for all is life in memory.&lt;br /&gt;&lt;br /&gt;The question is "why do I called this method &lt;b&gt;apply&lt;/b&gt;, what is a name that carry almost zero information ?". Simply because it's a Scala magic word, that can be zapped when used ! Just writing &lt;b&gt;"Article(id, article)"&lt;/b&gt; will call Article.apply(...). If you remember the "Array" in the @IncludeStyleSheet for the layout... That was the same principle. Array is the companion object of the Array class, and "Array("...","...")" secretly call the "apply" method of Array that take a list of String as parameter. &lt;br /&gt;&lt;br /&gt;And we are done with Articles. &lt;br /&gt;&lt;br /&gt;&lt;a name="dao"&gt;&lt;h2&gt;DAO&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A DAOs ("Data Access Objects") are objects responsible for accessing and persisting (or delegate persistence of) other objects. They are the heart of CRUD application.&lt;br /&gt;&lt;br /&gt;The first paragraph explain our generic DAO API, the second will show a naive, in memory implementation of the generic DAO for article, and a third one will explain how to use it with Tapestry IoC.&lt;br /&gt;&lt;br /&gt;&lt;a name="abstract_dao"&gt;&lt;h3&gt;Generic DAO API&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;We will define DAO by their API, the set of method exposed by these service objects. In Java, API means "Interfaces", in Scala they means "Traits". In our example, they are the same things. We will define a real implementation &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.DAO.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * A read-only dao&lt;br /&gt; * @param T is the type of entities handled by this DAO&lt;br /&gt; * @param K is the type of the key that is used to identify entities.&lt;br /&gt; */&lt;br /&gt;trait ReadDao[T, K &lt;: Serializable] {&lt;br /&gt;  &lt;br /&gt;  /*&lt;br /&gt;   * Retrieve an entity from its key. If no&lt;br /&gt;   * entities are known for the given key, None is returned.&lt;br /&gt;   * @param K the unique id of the entity to fetch&lt;br /&gt;   * @return None if no entity match that key,&lt;br /&gt;   *         Some[entity] else&lt;br /&gt;   */&lt;br /&gt;  def get(id:K) : Option[T]&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Retrieve all the entities known by that DAO.&lt;br /&gt;   * Be carefull, that may be a huge number.&lt;br /&gt;   * @return the list of all entities for that DAO&lt;br /&gt;   */&lt;br /&gt;  def getAll() : List[T]&lt;br /&gt; &lt;br /&gt;  /**&lt;br /&gt;   * Find all the entities that match the given requirement&lt;br /&gt;   * @param T =&gt; Boolean : the function to apply to find if&lt;br /&gt;   *        an entity should be included in the returned list.&lt;br /&gt;   *        (on a "true" return) or excluded (on a "false" return)&lt;br /&gt;   * @return the list of enetities matching the filter.&lt;br /&gt;   */&lt;br /&gt;  def find(filter: T =&gt; Boolean) : List[T]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * A write-only dao&lt;br /&gt; * @param T is the type of entities handled by this DAO&lt;br /&gt; * @param K is the type of the key that is used to identify entities.&lt;br /&gt; */&lt;br /&gt;trait WriteDao[T, K &lt;: Serializable] {&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Persist the given entity: create a new one if&lt;br /&gt;   * the entity wasn't know in that DAO (entity&lt;br /&gt;   * key was None), or update an existing entity &lt;br /&gt;   * (it's key was Some[K]).&lt;br /&gt;   * @param T the entity to persist&lt;br /&gt;   * @return the key of the persisted entity if the process &lt;br /&gt;   *         succeded, or None the the peristence failed.&lt;br /&gt;   */&lt;br /&gt;  def save(entity:T) : Option[K]&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Delete the article matching this id. &lt;br /&gt;   * If no article match this id, does nothing.&lt;br /&gt;   * Return true is the deletion is successful&lt;br /&gt;   */&lt;br /&gt;  def delete(id:K) : Boolean&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * A read-write DAO, that combine read and write DAO traits.&lt;br /&gt; */&lt;br /&gt;trait ReadWriteDao[T, K &lt;: Serializable] extends ReadDao[T,K] with WriteDao[T,K]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Comments speak for themselves here, and "Option" is well-known now.&lt;br /&gt;The only surprises are the "&lt;:" which means that the K type has to be Serializable, and more notably for a Java guy, the "find" method: it takes a method as parameter !&lt;br /&gt;The signature of the filter method is "I take an entity of type T as parameter, and return a Boolean". &lt;br /&gt;&lt;br /&gt;For example, if we take an Article DAO, we may use this to find all the article whose title begin with "The" like that:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;val articles = dao.find( (a:Article) =&gt; a.title.startsWith("The") == true )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's all. It means "the method find takes as parameter a method that take an article as parameter, and return the result of the evaluation of "a.title.startsWith("The") == true". &lt;br /&gt;&lt;br /&gt;It can even be simpler, because Scala allows to use "_" as a place-holder for parameter when there is no ambiguities, like here (in our case, find can't take anything but a method which has the "Article =&gt; Boolean" signature):&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;val articles = dao.find( _.title.startsWith("The") == true )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you don't see why "closure" are so useful, look how simple that declaration is compared to the burden to declare a filter interface and used it, even with anonymous class in place of real instances...&lt;br /&gt;&lt;br /&gt;&lt;a name="inmemory_dao"&gt;&lt;h3&gt;In memory Article DAO&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now that we have our generic DAO API, we are ready to implement a version for Articles. This first DAO will be a really simple one, where articles are persisted in memory (in a Map). &lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.impl.dao.InmemoryDao.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;import org.example.blog.data.Article&lt;br /&gt;import scala.collection.mutable&lt;br /&gt;&lt;br /&gt;import org.example.blog.services.ReadWriteDao&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * A simple, naive implementation of the Article DAO.&lt;br /&gt; * In particular, this implementation is&lt;br /&gt; * NOT AT ALL THREADSAFE&lt;br /&gt; */&lt;br /&gt;class InmemoryArticleDao extends ReadWriteDao[Article, String] {&lt;br /&gt;  &lt;br /&gt;  private val memory : mutable.Map[String, Article] = new mutable.HashMap()&lt;br /&gt;  private var id = 0&lt;br /&gt;  private def newId = { id = id + 1 ; id }&lt;br /&gt;  &lt;br /&gt;  def get(id:String) = this.memory.get(id)&lt;br /&gt;&lt;br /&gt;  def getAll() = this.memory.values.toList&lt;br /&gt; &lt;br /&gt;  def find(filter: Article =&gt; Boolean) = &lt;br /&gt;    (for { &lt;br /&gt;      a &lt;- this.memory.values&lt;br /&gt;      if(filter(a))&lt;br /&gt;    } yield a).toList&lt;br /&gt;&lt;br /&gt;  def save(article:Article) = {&lt;br /&gt;    val a = article.id match {&lt;br /&gt;      case None =&gt; &lt;br /&gt;        val i = this.newId&lt;br /&gt;        Article(i.toString,article)&lt;br /&gt;      case Some(id) =&gt; article&lt;br /&gt;    }&lt;br /&gt;    assert(a.id.isDefined)&lt;br /&gt;    this.memory.put(a.id.get,a)&lt;br /&gt;    //check if article is in map for the id, return id if OK&lt;br /&gt;    this.memory.get(a.id.get).map( _.id.get)&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  def delete(id:String) = !( (this.memory - id).isDefinedAt(id) )&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can see that the "extends ReadWriteDao[Article, String]" is really like Java with generics. &lt;br /&gt;&lt;br /&gt;The implementation is a basic mapping between our DAO API and the Map used as a back-end. Article Ids are generated by an incrementing number, but there's no lock against thread concurrency. Say that for now, it's really a tool example, and all in all, our blog can have only one author (reminds the configuration object of the previous post).&lt;br /&gt;&lt;br /&gt;The save method is the most complex, because we have to process the update and the create case, based on the fact that id is None or Some(value). &lt;br /&gt;We also see the use of the Article companion object "apply", that allows to copy the given article to a new one, but with it's freshly created id. &lt;br /&gt;&lt;br /&gt;The filter method the Scala for comprehension loop that automatically concatenates yielded elements, but it could have been done with an even more imperative "for" loop too:&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;def find(filter: Article =&gt; Boolean) = {&lt;br /&gt;    var articles = List[Article]()&lt;br /&gt;    for(a &lt;- this.memory.values) {&lt;br /&gt;      if(filter(a)) articles = a :: articles &lt;br /&gt;    }&lt;br /&gt;    articles&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I believe that the first method is better, because the two are almost as inefficient, and the latter use a mutable variable.&lt;br /&gt;&lt;br /&gt;That's all for the implementation of our DAO !&lt;br /&gt;&lt;br /&gt;&lt;a name="dao_injection"&gt;&lt;h3&gt;Enable Article DAO service thanks to T5 IoC&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now that we have a DAO API, and a DAO implementation for Article, we want to let our application know that when we use a DAO on articles, what we really want is to use the "In Memory Article DAO". &lt;br /&gt;&lt;br /&gt;As for the Configuration service on the previous post, we just have to add a "build" method into the AppModule object to bind the ReadWrite[String,Article] DAO to its implementation:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;  def buildArticleDao = new InmemoryArticleDao()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hum. Yeah, there is nothing to do but that, but as we are Professional, we can't let our bosses think that our job is so simple, so let's add some boilerplate to make the code seems harder, more complex:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;  def buildArticleDao = {&lt;br /&gt;    val a1 = new Article(None)&lt;br /&gt;    a1.title = "First article"&lt;br /&gt;    a1.content = "Content for the first article"&lt;br /&gt;    a1.published = true&lt;br /&gt;    &lt;br /&gt;    val a2 = new Article(None)&lt;br /&gt;    a2.title = "Second article"&lt;br /&gt;    a2.content = "Content for the second article"&lt;br /&gt;    &lt;br /&gt;    val m = new InmemoryArticleDao()&lt;br /&gt;    m.save(a1)&lt;br /&gt;    m.save(a2)&lt;br /&gt;    m&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OK, that's better ! Actually, I just initialized the DAO with two articles (one published, not the other one), but it's far more impressive like that ;)&lt;br /&gt;&lt;br /&gt;&lt;a name="presentation"&gt;&lt;h2&gt;Putting the parts together : the presentation layer&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now that we (finally !) have all the services to create and retrieve articles set-up, we can switch to the only part in which customers have some interests, the presentation layer (that's because code screenshots look bad on powerpoint). &lt;br /&gt;&lt;br /&gt;&lt;a name="homepage"&gt;&lt;h2&gt;The Index page&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;The first page that will use our new services is the home page. On this page, we just want to display all published articles.&lt;br /&gt;&lt;br /&gt;For that, we will use the &lt;b&gt;Loop&lt;/b&gt; component:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.pages.Index.tml&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;div t:type="loop" t:source="articles" t:value="article" class="article"&amp;gt;&lt;br /&gt;  &amp;lt;h2&amp;gt;&amp;lt;a t:type="pagelink" t:page="article/view" t:context="article.displayid"&amp;gt;&lt;br /&gt;   ${article.title}&lt;br /&gt;  &amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;div&amp;gt;${article.content}&amp;lt;/div&amp;gt;&lt;br /&gt; &amp;lt;/div&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/t:layout&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We see in this template that we link to the "article/view" page, in which we will display the article with its comments. But as it's for an other day, for now we just create a org.example.blog.page.article.ViewArticle.{scala,tml} couple so that Tapestry 5 don't stop on a broken link (it validate that all lins are correct at start time), and we will take care of them the next time.&lt;br /&gt;&lt;br /&gt;We also see that we need a "source" from where articles are taken, and a "value" to hold the current article of the loop. Of course, these objects are provided by the Scala part of the couple:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.pages.Index.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;class Index {&lt;br /&gt;  &lt;br /&gt;  @Inject&lt;br /&gt;  var readArticleDao : ReadDao[Article, String] = _&lt;br /&gt;  &lt;br /&gt;  @Cached&lt;br /&gt;  def getArticles = readArticleDao.find( _.published == true ).toArray&lt;br /&gt;  &lt;br /&gt;  @Property&lt;br /&gt;  var article : Article = _&lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code stands for itself : we inject a read-only DAO for article - we don't need more, and even if actually we get the in memory read write implementation, this code only care for the read part ; we have a "getArticles" method that retrieve all publish articles from the DAO (remember: closures are great), and we have an Article "@Property" annotated to receive the current article from the loop.&lt;br /&gt;&lt;br /&gt;As we have initialized the DAO with two articles (one published among them), as soon as we start the application, we can see the first, published article on the home page:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9D3n-ZqzF48/SXOiKYnj91I/AAAAAAAAAqk/o1mLGWuJPhA/s1600-h/blog_index_first_article.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 238px;" src="http://2.bp.blogspot.com/_9D3n-ZqzF48/SXOiKYnj91I/AAAAAAAAAqk/o1mLGWuJPhA/s320/blog_index_first_article.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5292752286381242194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Isn't that great ?&lt;br /&gt;&lt;br /&gt;&lt;a name="create_page"&gt;&lt;h2&gt;Create new articles&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now that we can see our article, we may want to add some new ones - well, it's aim to be a blog, and what the point if I can't talk about how cute is my ickle hamster ?&lt;br /&gt;&lt;br /&gt;For that, let's build the "create article" page. &lt;br /&gt;Let's begin with the template. In this first version, I won't rely on the magc BeanEditForm, and we need to be able to set a title, a content, and choose to publish or not the article:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;&lt;br /&gt;&amp;lt;t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"&amp;gt;&lt;br /&gt; &amp;lt;h2&amp;gt;Create a new article&amp;lt;/h2&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;t:form t:id="NewArticleForm" class="new-article"&amp;gt;&lt;br /&gt;    &lt;br /&gt;  &amp;lt;p&amp;gt;&lt;br /&gt;   &amp;lt;t:label for="publish" /&amp;gt;&amp;amp;nbsp;&amp;lt;t:checkbox t:id="publish" t:value="article.published" /&amp;gt;&lt;br /&gt;  &amp;lt;/p&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;p&amp;gt;&lt;br /&gt;   &amp;lt;t:label for="title"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;   &amp;lt;t:textfield class="large" t:id="title" value="article.title" validate="required"/&amp;gt;&lt;br /&gt;  &amp;lt;/p&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;p&amp;gt;&lt;br /&gt;   &amp;lt;t:label for="content" /&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;   &amp;lt;t:textarea class="large" t:id="content" value="article.content" /&amp;gt;&lt;br /&gt;  &amp;lt;/p&amp;gt;&lt;br /&gt;  &amp;lt;t:submit /&amp;gt;&lt;br /&gt; &amp;lt;/t:form&amp;gt;&lt;br /&gt;&amp;lt;/t:layout&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This template is a little boring, but it's the first time we see a constructed form and it's different input. The title is required, and the form will be refused as long as it is no provided. There is other predifined validator, like min/man, regexp... And... well, there's nothing more to say : all input has a value parameter that is the link to the server-side java^W Scala object that will handle it, and there is a submit button. And that's all.&lt;br /&gt;&lt;br /&gt;That looks like that:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9D3n-ZqzF48/SXTwODCSoJI/AAAAAAAAAqs/yGgMWhYGq9E/s1600-h/blog_create_article.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 237px;" src="http://1.bp.blogspot.com/_9D3n-ZqzF48/SXTwODCSoJI/AAAAAAAAAqs/yGgMWhYGq9E/s320/blog_create_article.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5293119586190925970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ok, so how do we handle that on the server side ?&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.page.article.CreateArticle.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;import org.apache.tapestry5.annotations.{Property,Persist,InjectPage}&lt;br /&gt;import org.apache.tapestry5.ioc.annotations.Inject&lt;br /&gt;&lt;br /&gt;import org.example.blog.data.Article&lt;br /&gt;import org.example.blog.services.WriteDao&lt;br /&gt; &lt;br /&gt;import java.text.DateFormat&lt;br /&gt;&lt;br /&gt;class CreateArticle {&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  var articleDao : WriteDao[Article,String] = _&lt;br /&gt;  &lt;br /&gt;  @Persist @Property&lt;br /&gt;  var article : Article = _&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;  @InjectPage&lt;br /&gt;  var redirectPage : ManageArticle = _&lt;br /&gt;  &lt;br /&gt;  def setupRender {&lt;br /&gt;    if(null == this.article) {&lt;br /&gt;      this.article = new Article(None)&lt;br /&gt;    } &lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  def onSuccessFromNewArticleForm = {&lt;br /&gt;    articleDao.save(article) match {&lt;br /&gt;      case None =&gt; error("Dao error ! Please retry.")&lt;br /&gt;      case _ =&gt; this.article = null ; redirectPage&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This time we need the "Write" part of the DAO (and a again, no need for the other, so I injected the minimal aspect), and an Article that will back the the new article.&lt;br /&gt;&lt;br /&gt;The article is annotated @Persist, so that it will be stored in session. We need that because the form has to be validated, and perhaps show again: we don't want to loose what was written in this case. &lt;br /&gt;&lt;br /&gt;The setupRender method is a conventional name that matches a &lt;a href="http://tapestry.apache.org/tapestry5/guide/rendering.html"&gt;component rendering phase&lt;/a&gt;. We will take advantage of this method to initialized a new Article, if needed. &lt;br /&gt;&lt;br /&gt;The onSuccessFromNewArticleForm is again a conventional method name to handle a component event. On that case, the event is "success", and we await it from the "articleForm" component... which is our form's "t:id". So, you get it, when the form succeed, we go into that method, in which we try to save the Article. If the DAO failed in its job, we raise an error, and else we redirect into the ManageArticle page. There is a lot of way to redirect to a page in T5: you can use URL, page class, the string page name, or the InjectPage annotated page. This method is handy when you need to init some value in the page before redirecting to it. Well, here it's just because it's cool ;).&lt;br /&gt;&lt;br /&gt;And now, we are redirected to the "manate" page.&lt;br /&gt;&lt;br /&gt;&lt;a name="manage_page"&gt;&lt;h2&gt;Manage all articles&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The goal of this page is to give the author the possibility to view the list of all existing articles. Moreover, we want to be able to go there detail page, to publish or unpublish, edit and delete them.&lt;br /&gt;&lt;br /&gt;In this case, the perfect component is &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-core/ref/org/apache/tapestry5/corelib/components/Grid.html"&gt;the grid component&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This component allows to display a list of beans, one column by property, and allows to add, remove, reorder columns.&lt;br /&gt;&lt;br /&gt;The template looks like that:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;h2&amp;gt;List, modify, publish article&amp;lt;/h2&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;t:grid source="articles" row="article"&lt;br /&gt;   reorder="title" exclude="content" add="comments,publish,edit,delete"&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;t:parameter name="titleCell"&amp;gt;&lt;br /&gt;   &amp;lt;t:pagelink t:page="article/view" t:context="article.displayid"&amp;gt;&lt;br /&gt;    ${article.title}&lt;br /&gt;   &amp;lt;/t:pagelink&amp;gt;&lt;br /&gt;  &amp;lt;/t:parameter&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;t:parameter name="publishCell"&amp;gt;&lt;br /&gt;   &amp;lt;t:actionlink t:id="changePublication" t:context="article.displayid"&amp;gt;&lt;br /&gt;    ${changePublication}&lt;br /&gt;   &amp;lt;/t:actionlink&amp;gt;&lt;br /&gt;  &amp;lt;/t:parameter&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;t:parameter name="commentsCell"&amp;gt;&lt;br /&gt;   ${article.comments.size()}&lt;br /&gt;  &amp;lt;/t:parameter&amp;gt;&lt;br /&gt; &lt;br /&gt;  &amp;lt;t:parameter name="editCell"&amp;gt;&lt;br /&gt;   &amp;lt;t:pagelink t:page="article/edit" t:context="article.displayid"&amp;gt;&lt;br /&gt;    edit&lt;br /&gt;   &amp;lt;/t:pagelink&amp;gt;&lt;br /&gt;  &amp;lt;/t:parameter&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;t:parameter name="deleteCell"&amp;gt;&lt;br /&gt;   &amp;lt;t:actionlink t:id="delete" t:context="article.displayid"&amp;gt;&lt;br /&gt;    delete&lt;br /&gt;   &amp;lt;/t:actionlink&amp;gt;&lt;br /&gt;  &amp;lt;/t:parameter&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/t:grid&amp;gt;&lt;br /&gt;&amp;lt;/t:layout&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What looks in real like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9D3n-ZqzF48/SXTy8hpq-GI/AAAAAAAAAq0/LdAe3kan7Zk/s1600-h/blog_manage_articles.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 239px;" src="http://3.bp.blogspot.com/_9D3n-ZqzF48/SXTy8hpq-GI/AAAAAAAAAq0/LdAe3kan7Zk/s320/blog_manage_articles.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5293122583706400866" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is some interesting things in this template:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;we have a source of bean, and the current Article is handle in the "row" parameter;&lt;/li&gt;&lt;li&gt;the "t:parameter" is special invocation that allows to bind a block of template code to component parameter. In our case, each t:parameter is used to replace the content of a column cell;&lt;/li&gt;&lt;li&gt;the pagelink component has already been seen several times, but here can see how easy it is to map page to URL: it's simply the list of directories from the "pages" package to the page object. We also see how we can pass a some context (variable) into the targeted page;&lt;/li&gt;&lt;li&gt;lastly, the "t:actionlink" is a component that allows to fire an event on the server side;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So, how we handle all that on the server side ?&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.pages.article.ManageArticle.scala&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;class ManageArticle {&lt;br /&gt;  &lt;br /&gt;  @Inject&lt;br /&gt;  var rwDao : ReadWriteDao[Article, String] = _&lt;br /&gt;  &lt;br /&gt;  @Property&lt;br /&gt;  var article : Article = _&lt;br /&gt;  &lt;br /&gt;  def getArticles = this.rwDao.getAll.sort( _.creationDate.getTime &gt; _.creationDate.getTime ).toArray&lt;br /&gt;  &lt;br /&gt;  def getChangePublication = if(article.published) "Un-published" else "Published"&lt;br /&gt;  &lt;br /&gt;  def onActionFromChangePublication(id:String) {&lt;br /&gt;    val a = this.rwDao.get(id).getOrElse(error("No such article, id: " + id) )&lt;br /&gt;    a.published = !a.published&lt;br /&gt;    this.rwDao.save(a)&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  def onActionFromDelete(id:String) {&lt;br /&gt;    if(!this.rwDao.delete(id)) {&lt;br /&gt;      error("Can not delete this article")&lt;br /&gt;    }&lt;br /&gt;  }  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code is fairly simple and clear:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;we need the ReadWriteDao, so we inject it;&lt;/li&gt;&lt;li&gt;we need an article to keep the current row, so we add an @Property annotated Article;&lt;/li&gt;&lt;li&gt;the source of all bean is provided by the "getArticles()" method, that simply retrieve all the articles from DAO (and sort them by date);&lt;/li&gt;&lt;li&gt;the "getChangePublication()" return the good text given the status of the article;&lt;/li&gt;&lt;li&gt;the "onActionFromChangePublication" method handle the event from the actionLink with "t:id" changePublication. The method await a parameter which is given by the context of action link (and is the article id). We react at this event by changing the status of the matching article, and save it back into the DAO;&lt;/li&gt;&lt;li&gt;finally, the "onActionFromDelete" handle the event from the "delete" link, and react to it by deleting the article from the DAO.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Note that all event handler that does not return anything redirect to the calling page.&lt;br /&gt;&lt;br /&gt;&lt;a name="final"&gt;&lt;h1&gt;Final words&lt;/h1&gt;&lt;/a&gt;&lt;br /&gt;&lt;a name="conclusion"&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And that's done ! The goal perimeter is reached, we can see, add, manage articles in a not too ugly blog. &lt;br /&gt;&lt;br /&gt;Now, a lot of things remained:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Articles are not really persisted, and are lost on server shutdown. What abot saving them into a database, or even better into a more "text oriented" storage, has XML files, or something like a Java Content Repository (or a CouchDB ?)&lt;/li&gt;&lt;li&gt;Where are the comments ?&lt;/li&gt;&lt;li&gt;And the article details ? And all the formating of articles is lost in rendering ! That's awful ! Perhaps we need a smarter rendering component... and so we may used it at several place around the site (Index, article details...)&lt;/li&gt;&lt;li&gt;And what about a better text editor, that allows some kind of rich UI ? Personally, I really like &lt;a href="http://attacklab.net/showdown/"&gt;showdown editor&lt;/a&gt;&lt;/li&gt;&lt;li&gt;And tags, hu ? We are building the tomorrow blog plateform for web 3.0 and don't even have tags ? That can't be serious !&lt;/li&gt;&lt;li&gt;oups, somebody just pointed that for now, there is no way to protect the manager area from the simple user... No authentication, no authorizations...&lt;li&gt;&lt;li&gt;I also said that I will attempt to use &lt;a href="http://easyant.org/"&gt;easy-ant&lt;/a&gt; as build tool, in place of maven&lt;/li&gt;&lt;li&gt;and the list is almost infinite !&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So, there is still some room to a little more experiment with T5 and Scala !&lt;br /&gt;&lt;br /&gt;&lt;a name="source"&gt;&lt;h2&gt;Source code&lt;/h2&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As always, the source code is available on the GitHub repository of the project. &lt;br /&gt;&lt;br /&gt;To download and test the code for that articles, simply executes these commands:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;% git clone git://github.com/fanf/scala-t5-blog.git&lt;br /&gt;% cd scala-t5-blog&lt;br /&gt;% git checkout -b test article3_20090119&lt;br /&gt;% mvn jetty:run&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Enjoy, and see you next time !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-263968159155294498?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/263968159155294498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=263968159155294498' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/263968159155294498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/263968159155294498'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/t5-scala-layout-and-basic-crud.html' title='Tapestry 5 - Scala : a layout and basic CRUD for the blog'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9D3n-ZqzF48/SXNUj3zJ5hI/AAAAAAAAAqc/Ar455BepQ54/s72-c/blog_layout.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2779369361537036887</id><published>2009-01-11T10:37:00.013+01:00</published><updated>2009-01-11T16:24:04.145+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>T5 - Scala : first injection and property access</title><content type='html'>The last time, we set-up the Tapestry 5 quickstart application to run with Scala in place of Java. Now, it's time to add our first service and data, to see what are the common idiom we will have to follow to make them work together. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Target scope of this iteration&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;We want to add only two features:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Two domain objects:&lt;/li&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;the author for our blog,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;a configuration object, which will be a container for blog's parameters (title, author, etc)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;a service to access this configuration, injected where needed&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;After the domain object will be added, I will mmodify the Index page to use them.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;User, configuration and service, first attempt&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;User and configuration objects&lt;/h4&gt;&lt;br /&gt;So, we want an user with a non-modifiable login, a name/surname, and an email. For now, the configuration will only have the main author (an user), and a title for the blog. &lt;br /&gt;They will go in the same file as they are both related to configuration data:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.data.BlogConfiguration&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;package org.example.blog.data&lt;br /&gt;&lt;br /&gt;class BlogConfiguration(val author : User) {&lt;br /&gt;  var blogTitle = "%s's blog".format(author.login)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class User(val login : String) {  &lt;br /&gt;  var commonname = ""&lt;br /&gt;  var surname = ""&lt;br /&gt;  var email = ""&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And that's it. For the user, commonname, surname, and email are "var", so we will be able to get them with &lt;em&gt;user.email&lt;/em&gt;, and set them with &lt;em&gt;user.email = "newValue"&lt;/em&gt;. &lt;br /&gt;We can note that the type of this properties is inferred by Scala to String. Remember, Scala is statically typed, but that doesn't imply &lt;br /&gt;&lt;br /&gt;login (for user) and author (for configuration) are constructor's parameter. As they are tagged "val", they will be read-only, and viewable from other class. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Configuration service&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;Now, we have to build a service for configuration so that we will be able to inject it where we need it. &lt;br /&gt;&lt;br /&gt;Thank's to &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-ioc/"&gt;Tapestry 5 powerful and super-easy IoC feature&lt;/a&gt;, it's a matter of adding some lines in our application module:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.services.AppModule&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;  def buildBlogConfiguration = {&lt;br /&gt;    val author = new User("jondoe")&lt;br /&gt;    author.commonname = "Jon"&lt;br /&gt;    author.surname = "Doe"&lt;br /&gt;    author.email = "jondoe@foo.bar"&lt;br /&gt;    &lt;br /&gt;    new BlogConfiguration(author)&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And it's all what we need. Now, let's use this service in our Index page to display some info about the user !&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Index modification&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Index.scala&lt;/h4&gt;&lt;br /&gt;The index page modification is really trivial. That's the code for the Scala part:&lt;br /&gt;&lt;em&gt;org.example.blog.pages.Index&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;class Index {&lt;br /&gt;  &lt;br /&gt;  @Inject @Property&lt;br /&gt;  var conf : BlogConfiguration = _&lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We want to access our BlogConfiguration service, so we just declare a variable with the wanted type. The really important thing here is to &lt;b&gt;initialized it with "_"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Without that (for example, if you initialized the var with null), you will get silly error about read-only variable not modifiable.&lt;br /&gt;&lt;br /&gt;As we want T5 to inject the real BlogConfiguration service, we annotated the var with @Inject, and as we want to access it from the template and I'm lazy, we also used the @Property annotation, that save us from writing the getter for "conf".&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Index.tml&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;The template part isn't much more thrilling. We want to use the blog title in the page's title, display information about the author, and even update them. That's the full template code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;&amp;lt;html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Tapestry 5 - Scala blog&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;  &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;h1&amp;gt;${conf.blogTitle}&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;p&amp;gt;Author info:&amp;lt;/p&amp;gt;&lt;br /&gt;    &amp;lt;t:beandisplay t:object="conf.author" /&amp;gt;&lt;br /&gt;    &amp;lt;p&amp;gt;Update author info:&amp;lt;/p&amp;gt;&lt;br /&gt;    &amp;lt;t:beaneditform t:object="conf.author" /&amp;gt;&lt;br /&gt;  &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"&lt;b&gt;${}&lt;/b&gt;" is the T5 syntax to say "look into my class, take the blogTitle object in conf object". &lt;br /&gt;"&lt;b&gt;beandisplay&lt;/b&gt;" is a component that simply display all the properties of an object, and "&lt;b&gt;beaneditform&lt;/b&gt;" is a magic component that fully build a create/update form for the given object.&lt;br /&gt;&lt;br /&gt;And now, we test our blog... And that's not at all what we want.&lt;br /&gt;&lt;br /&gt;T5 shows us a really insightful error message:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9D3n-ZqzF48/SWnrK5puvrI/AAAAAAAAAqM/va3fvMCZ1bc/s1600-h/t5_error_scala_prop_unavailables.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 132px;" src="http://1.bp.blogspot.com/_9D3n-ZqzF48/SWnrK5puvrI/AAAAAAAAAqM/va3fvMCZ1bc/s320/t5_error_scala_prop_unavailables.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5290017809830428338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Clearly, Tapestry does not understand that our "conf" object has a "blogTitle" property.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;User, configuration and service, second attempt&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;What happened is that T5 relies on &lt;a href="http://en.wikipedia.org/wiki/JavaBean"&gt;Java Bean conventions&lt;/a&gt; to see what properties of an object are available. And Scala does not follow that convention with the auto-generated accessors. As we see in at the begining, Scala use the directly the property name as getter and setter.&lt;br /&gt;&lt;br /&gt;So, we have to add traditional JavaBean getter/setter to our &lt;em&gt;User&lt;/em&gt; and &lt;em&gt;BlogConfiguration&lt;/em&gt; classes, or use the &lt;em&gt;scala.reflect.BeanProperty&lt;/em&gt; where possible. This annotation is the Scala equivalent to T5's Property annotation and generate the getter/setter pair for us :&lt;br /&gt;&lt;br /&gt;&lt;em&gt;org.example.blog.data.BlogConfiguration&lt;/em&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;package org.example.blog.data&lt;br /&gt;&lt;br /&gt;import scala.reflect.BeanProperty&lt;br /&gt;&lt;br /&gt;class BlogConfiguration(val author:User) {&lt;br /&gt;&lt;br /&gt;  @BeanProperty&lt;br /&gt;  var blogTitle = "%s's blog".format(author.login)&lt;br /&gt;  &lt;br /&gt;  def getAuthor = author&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class User(val login : String) {  &lt;br /&gt;  @BeanProperty&lt;br /&gt;  var commonname = ""&lt;br /&gt;&lt;br /&gt;  @BeanProperty&lt;br /&gt;  var surname = ""&lt;br /&gt;&lt;br /&gt;  @BeanProperty&lt;br /&gt;  var email = ""&lt;br /&gt;&lt;br /&gt;  def getLogin = login&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sadly, the updated classes look a little more bloated, but now, it works as expected.&lt;br /&gt;If you go to "http://localhost:8080/blog/", you should see :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9D3n-ZqzF48/SWnxBZLiiyI/AAAAAAAAAqU/WHFnkq-1q20/s1600-h/t5_author_display_update.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 146px;" src="http://3.bp.blogspot.com/_9D3n-ZqzF48/SWnxBZLiiyI/AAAAAAAAAqU/WHFnkq-1q20/s320/t5_author_display_update.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5290024243564808994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Of course, if you modify User info and click on "create/update", the user info are really updated in the BlogConfiguration.&lt;br /&gt;&lt;br /&gt;And that's over for the time being.&lt;br /&gt;&lt;br /&gt;Edit: oups, the code is available here: &lt;a href="http://github.com/fanf/scala-t5-blog/tree/article2_20090111"&gt;http://github.com/fanf/scala-t5-blog/tree/article2_20090111&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To get the code and run it:&lt;br /&gt;&lt;pre class="sh_xml"&gt;&lt;br /&gt;% git clone git://github.com/fanf/scala-t5-blog.git&lt;br /&gt;% cd scala-t5-blog&lt;br /&gt;% git checkout -b test article2_20090111&lt;br /&gt;% mvn jetty:run &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And go to http://localhost:8080/blog/&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;For now, Tapestry 5 and Scala work together, as soon as you know that "_" is to be used as init placeholder for Injected var, and that T5 use Java Bean convention for getter/setter.&lt;br /&gt;&lt;br /&gt;The problem is that we don't really see what Scala brings in place of Java, so why switching ?&lt;br /&gt;&lt;br /&gt;We can see it the other way: as everything works at least as well as with Java, I think I will continue this experiment a little bit more : I'm using eclipse with Scala plugin and OK, it's not as good as Java plugin, but it's ok, RunJettyRun has no problem to launch the application, &lt;a href=http://tapestry.apache.org/tapestry5/guide/reload.html""&gt;T5 live class reloading works fine&lt;/a&gt;, etc. &lt;br /&gt;&lt;br /&gt;Moreover, I suspect that as soon as I will come down a little in the application layer, some benefits will emerge - just think to real DAO that take a closure as filter, without having to deal with Java anonymous classes, generic mess, and all that stuff...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2779369361537036887?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2779369361537036887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2779369361537036887' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2779369361537036887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2779369361537036887'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/t5-scala-first-injection-and-property.html' title='T5 - Scala : first injection and property access'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9D3n-ZqzF48/SWnrK5puvrI/AAAAAAAAAqM/va3fvMCZ1bc/s72-c/t5_error_scala_prop_unavailables.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2897125009258980853</id><published>2009-01-07T21:28:00.004+01:00</published><updated>2009-01-08T07:39:28.105+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tapestry 5 with Scala - Get the code !</title><content type='html'>&lt;h3&gt;A Scala / Tapestry 5 blog&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;In the next days/weeks, I will try to see a little more precisely how Tapestry 5 and Scala get together. I chose to start with a little blog application (how imaginative I am ;)&lt;br /&gt;&lt;br /&gt;If your are interested to see how it works, I've set-up a github repository to keep a trace of the evolution.&lt;br /&gt;&lt;br /&gt;So, the repository is here: &lt;a href="http://github.com/fanf/scala-t5-blog/"&gt;http://github.com/fanf/scala-t5-blog/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step one : an hello world application&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;The first step is to have the equivalent of the &lt;a href="http://tapestry.apache.org/tapestry5/quickstart/"&gt;Tapestry 5 quickstart application&lt;/a&gt;, but with a Scala back end. That suppose:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;to change Java class to scala one;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;to add the correct dependencies and plugins (I used the &lt;a href="http://scala-tools.org/mvnsites/maven-scala-plugin/index.html"&gt;scala-maven-plugin&lt;/a&gt;) for Maven, so that it will be able to compile Scala files.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I also renamed the standard directory structure for source classes from src/main/java to src/main/scala.&lt;br /&gt;&lt;br /&gt;And that's it ! &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Test it yourself&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;So, if you want to see and test a Tapestry "hello world" application with Scala in place of Java, simply:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;install &lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; if you don't have it already&lt;/li&gt;&lt;br /&gt;&lt;li&gt;get the source with the command: &lt;br /&gt;&lt;pre&gt;% git clone git://github.com/fanf/scala-t5-blog.git&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Go to the &lt;em&gt;scala-t5-blog&lt;/em&gt; directory, and switch to the tag for the "hello world" application with the command:&lt;br /&gt;&lt;pre&gt;% git checkout -b test helloworld-scala-t5 &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You're done ! You can compile and run it with the standard "mvn jetty:run" command, or make a war to use it with your prefered web application with "mvn package"&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;That's it for this first step, next I will try to make a more beautiful, perhaps configurable skin for the blog. &lt;br /&gt;&lt;br /&gt;Enjoy !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2897125009258980853?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2897125009258980853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2897125009258980853' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2897125009258980853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2897125009258980853'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/tapestry-5-with-scala-get-code.html' title='Tapestry 5 with Scala - Get the code !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8573917830821347851</id><published>2009-01-04T20:56:00.007+01:00</published><updated>2009-01-05T20:37:23.640+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tapestry 5 with Scala</title><content type='html'>I just tested to use Scala for the code used in components for Tapestry 5. For now, all seems to work great ! &lt;br /&gt;&lt;br /&gt;I just created a default project with the quick-start archetype, changed Index.java and AppModule.java to Index.scala and AppModule.scala respectively, added some render-phase handler in Index, add a filter in AppModule, and all worked fine...&lt;br /&gt;&lt;br /&gt;Expect one crucial thing: T5 requires that properties annotated @Persist are &lt;span style="font-weight:bold;"&gt;not&lt;/span&gt; initialized with a default value. &lt;br /&gt;&lt;br /&gt;This is due to the fact that T5 components / pages are pooled, and so are instantiated prior to their used, and after use are cleaned and send back to the pool. &lt;br /&gt;The problem is the clean stage: T5 as to know what is a "clean" value for the one managed by the framework - @Persist-ed one the first. That's hard to know for statefull object... as for example a collection of phone numbers, or some credential: T5 can not know effectively if a statefull object state changed, so it can only let it as it is, or nullify it. Nullify it expose you to NPE (because as a developer, you thought the initialization was done on class instantiation), and you don't want to see this kind of information to be badly cleaned and so, maybe leaked elsewhere, when the class in pool is used again.&lt;br /&gt;&lt;br /&gt;OK, so it's a good thing that T5 does not let you fire on your foot, and throws an exception if you try to set a default value to such a managed property. &lt;br /&gt;Except... that Scala &lt;span style="font-weight:bold;"&gt;requires&lt;/span&gt; that variable or values have a default value. So for now, I can't use persisted field for components, what is quite a limit :/&lt;br /&gt;&lt;br /&gt;I'm going to continue the experiment, to if Scala and Tapestry 5 can be used together, or if I will have to use Scala only for deeper layers of my application (and well, perhaps at last, I will have to try Groovy for the upper layer...)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE: there seems to be some problem with the IOC, so that will be hard...&lt;br /&gt;Symptoms are that the field is read-only, I will have to look more carefully at the difference between Scala var and Java properties...&lt;br /&gt;&lt;br /&gt;EDIT: Thanks a lot too &lt;a href="http://www.blogger.com/profile/02835376424060382389"&gt;James Iry&lt;/a&gt; who pointed to me that the variable initialization should be done with "_" : that's the solution. So just use "Persist var name:String = _", and it works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8573917830821347851?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8573917830821347851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8573917830821347851' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8573917830821347851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8573917830821347851'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/tapestry-5-with-scala.html' title='Tapestry 5 with Scala'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-6451434719849698872</id><published>2009-01-03T16:40:00.006+01:00</published><updated>2009-01-03T19:39:22.547+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>ProjectEuler#84 : monopoly game in Scala</title><content type='html'>In the last weeks, I slowed down my completion rate of Project Euler's problems a lot. But yesterday, looking for something to do for the last days of Christmas's holidays, I found the &lt;a href="http://projecteuler.net/index.php?section=problems&amp;amp;id=84"&gt;#84 problem&lt;/a&gt; which seemed quite fun: the goal is to find what are the 3 most visited squares in the game if we played with 4 sided dices in place of the common 6 sided ones.&lt;br /&gt;&lt;br /&gt;It's interesting, because it's a probabilistic problem, and I'm lame in proba. So, as the problem does not require too much precision (at contrary to &lt;a href="http://projecteuler.net/index.php?section=problems&amp;amp;id=213"&gt;problem #213&lt;/a&gt;...), I could solve it in a &lt;a href="http://en.wikipedia.org/wiki/Monte_Carlo_methods"&gt;monte-carlo way&lt;/a&gt;. This is the kind of proba solving method that suits me the best, because no proba are used...&lt;br /&gt;&lt;br /&gt;As always, it was really simple to express the solution I imagine in Scala, and that's the result.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Be careful ! If you play at Project Euler, the following contains a solution that you may prefer to find by yourself !&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * This is the companion object of our Monopoly class, it's the&lt;br /&gt; * place where we put all the common and side stuff, &lt;br /&gt; * the board definition and our Random number generator&lt;br /&gt; * definition, for example. &lt;br /&gt; */&lt;br /&gt;object Monopoly {&lt;br /&gt;  /*&lt;br /&gt;   * The monopoly board &lt;br /&gt;   * (yes, we could have just use the square numbers,&lt;br /&gt;   * but I found that clearer at the begining, and the overhead is&lt;br /&gt;   * really small)&lt;br /&gt;   */&lt;br /&gt;  val board = Array(&lt;br /&gt;    "GO"  , "A1", "CC1", "A2" , "T1", "R1", "B1" , "CH1", "B2", "B3", &lt;br /&gt;    "JAIL", "C1", "U1" , "C2" , "C3", "R2", "D1" , "CC2", "D2", "D3",&lt;br /&gt;    "FP"  , "E1", "CH2", "E2" , "E3", "R3", "F1" , "F2" , "U2", "F3",&lt;br /&gt;    "G2J" , "G1", "G2" , "CC3", "G3", "R4", "CH3", "H1" , "T2", "H2"   &lt;br /&gt;  )&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Match a case name to it's number&lt;br /&gt;   */&lt;br /&gt;  val reverseBoard = {&lt;br /&gt;    var m = Map[String,Int]()&lt;br /&gt;    for(i &lt;- 0 until board.size) m = m.+((board(i) , i))&lt;br /&gt;    m&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  abstract class Random {&lt;br /&gt;    def next : Int&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * A simple homothetie from int's range to a new one range,&lt;br /&gt;   * used to transform Random to dice roll&lt;br /&gt;   */&lt;br /&gt;  def randomInRange(start:Int,end:Int, random: Random) : Int = {&lt;br /&gt;    //that was funny to set up, there was some intersting&lt;br /&gt;    //overflow and int division to take care of ;)&lt;br /&gt;    val i = start +&lt;br /&gt;      ((random.next.toFloat - Int.MinValue) * (end+1 - start) / &lt;br /&gt;         (Int.MaxValue.toFloat - Int.MinValue) ).toInt &lt;br /&gt;    if(i &gt; end) end else if(i&lt;start) start else i //rouding error&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Utility methods that sends three square back &lt;br /&gt;   */&lt;br /&gt;  def goBack3(square:String) : String = {&lt;br /&gt;    val i =  reverseBoard(square)&lt;br /&gt;    if(i&gt;2)board(i-3) else board(board.size+i-4)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Utility method that given a square, &lt;br /&gt;   * return the next Railway Company square&lt;br /&gt;   */&lt;br /&gt;  def gotoNextR(square:String) : String = {&lt;br /&gt;    val i =  reverseBoard(square)&lt;br /&gt;    if(i&gt;5 &amp;&amp; i &lt;= 15) "R2"&lt;br /&gt;    else if(i&gt;15 &amp;&amp; i &lt;= 25) "R3"&lt;br /&gt;    else if(i&gt;25 &amp;&amp; i &lt;= 35) "R4"&lt;br /&gt;    else "R1"&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Utility method that given a square, &lt;br /&gt;   * return the next Utility company square&lt;br /&gt;   */&lt;br /&gt;  def gotoNextU(square:String) : String = {&lt;br /&gt;    val i =  reverseBoard(square)&lt;br /&gt;    if(i &gt; 12 &amp;&amp; i &lt;= 28) "U2"&lt;br /&gt;    else "U1"&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /*&lt;br /&gt;   * Represent a stack of cards, used for Communty cards and&lt;br /&gt;   * Chance. &lt;br /&gt;   * We cycle throught an array to convey the idea that cards&lt;br /&gt;   * are put back on the stack after use. &lt;br /&gt;   * &lt;br /&gt;   * Each "card" is a function that is awaiting for the real&lt;br /&gt;   * square name to return the resulting square move. Most of&lt;br /&gt;   * the card does nothing for us, so the function is identity&lt;br /&gt;   * (return the square itself)&lt;br /&gt;   */&lt;br /&gt;  class CardStack(random: Random, private val size:Int) {&lt;br /&gt;    protected val cards = new Array[String=&gt;String](size)&lt;br /&gt;    for(i &lt;- 0 until size) cards(i) =  (square:String) =&gt; square&lt;br /&gt;    private var index = 0&lt;br /&gt;    private def rand = random&lt;br /&gt;&lt;br /&gt;    def next(square:String) : String = {&lt;br /&gt;      index = (index+1)%size&lt;br /&gt;      cards(index)(square)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * The class that represents the chance card heap.&lt;br /&gt;   * Fairly random card distribution, &lt;br /&gt;   * see http://xkcd.com/221/ for more details&lt;br /&gt;   */&lt;br /&gt;  class CH(random: Random) extends CardStack(random,16) {&lt;br /&gt;    cards(1) = gotoNextR _&lt;br /&gt;    cards(2) = goBack3 _&lt;br /&gt;    cards(4) = _ =&gt; "GO"&lt;br /&gt;    cards(5) = _ =&gt; "R1"&lt;br /&gt;    cards(7) = _ =&gt; "C1"&lt;br /&gt;    cards(9) = _ =&gt; "H2"&lt;br /&gt;    cards(10) = gotoNextR _&lt;br /&gt;    cards(12) = _ =&gt; "JAIL"&lt;br /&gt;    cards(14) = gotoNextU _&lt;br /&gt;    cards(15) = _ =&gt; "E3"&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * The class that represent the community chest card heap. &lt;br /&gt;   * Fairly random card distribution, &lt;br /&gt;   * see http://xkcd.com/221/ for more details (again)&lt;br /&gt;   */&lt;br /&gt;  class CC(random: Random) extends CardStack(random,16) {&lt;br /&gt;    cards(4)  = _ =&gt; "GO"&lt;br /&gt;    cards(10) = _ =&gt; "JAIL"&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * A class that represents a pair of dices &lt;br /&gt;   * with a given number of faces&lt;br /&gt;   * &lt;br /&gt;   * The only intersting thing to do with&lt;br /&gt;   * is of course to roll them &lt;br /&gt;   * (with cards, dices and money involved, I can't &lt;br /&gt;   * understand where The Monopoly failed to be attractive).&lt;br /&gt;   */&lt;br /&gt;  class Dices(faces:Int,random: Random) {&lt;br /&gt;    def roll = (&lt;br /&gt;      randomInRange(1,faces,random),&lt;br /&gt;      randomInRange(1,faces,random)&lt;br /&gt;    )&lt;br /&gt;  }&lt;br /&gt;}  &lt;br /&gt;  &lt;br /&gt;/*&lt;br /&gt; * That's the actuall Monopoly representation. &lt;br /&gt; * In our simplification of the Game, a&lt;br /&gt; * Monopoly has a pair of dices, a Community Chest&lt;br /&gt; * and a Chance heap of cards, a log of the number&lt;br /&gt; * of consecutive doubles, and a marker for the &lt;br /&gt; * current position of the player (notice that as&lt;br /&gt; * there is only one player, the game should be&lt;br /&gt; * even less attractive than the real Mo,opoly...)&lt;br /&gt; * &lt;br /&gt; * Nonetheless, we want to play to our game, so&lt;br /&gt; * we have a "turn" method that roll the dices and&lt;br /&gt; * move the player thanks to a "next square" method&lt;br /&gt; * processor. &lt;br /&gt; * &lt;br /&gt; * And that's all, our monopoly really looks like &lt;br /&gt; * the real !&lt;br /&gt; */  &lt;br /&gt;class Monopoly(faces:Int,random: Monopoly.Random) {&lt;br /&gt;  import Monopoly.{CC,CH,Dices}&lt;br /&gt;  import Monopoly.{board=&gt;B,reverseBoard=&gt;RB}&lt;br /&gt;  &lt;br /&gt;  val dices = new Dices(faces,random)&lt;br /&gt;  val cc = new CC(random)&lt;br /&gt;  val ch = new CH(random)&lt;br /&gt;  var doubles = 0&lt;br /&gt;  var currentPosition = 0&lt;br /&gt;&lt;br /&gt;  private def next(square:String) : String = {&lt;br /&gt;    val s = square match {&lt;br /&gt;      case "CC1" =&gt; cc.next(square)&lt;br /&gt;      case "CC2" =&gt; cc.next(square)&lt;br /&gt;      case "CC3" =&gt; cc.next(square)&lt;br /&gt;      case "CH1" =&gt; ch.next(square)&lt;br /&gt;      case "CH2" =&gt; ch.next(square)&lt;br /&gt;      case "CH3" =&gt; ch.next(square)&lt;br /&gt;      case "G2J" =&gt; "JAIL"&lt;br /&gt;      case  _    =&gt; square&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if(s == square) s&lt;br /&gt;    else next(s)&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  /*&lt;br /&gt;   * A turn starts at one square and end on another,&lt;br /&gt;   * perhaps passing on several other squares&lt;br /&gt;   */&lt;br /&gt;  def turn() : String = {&lt;br /&gt;    val d = dices.roll&lt;br /&gt;    &lt;br /&gt;    var newSquare = next(&lt;br /&gt;      B((currentPosition+d._1+d._2)%B.size ))&lt;br /&gt;    &lt;br /&gt;    //3 consecutive double send to Jail&lt;br /&gt;    if(d._1 == d._2) {&lt;br /&gt;      doubles = doubles+1&lt;br /&gt;      if (doubles &gt;= 3) {&lt;br /&gt;        doubles = 0&lt;br /&gt;        newSquare = "JAIL"&lt;br /&gt;      }&lt;br /&gt;    } else doubles = 0&lt;br /&gt;    &lt;br /&gt;    currentPosition = RB(newSquare)      &lt;br /&gt;    newSquare&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;  &lt;br /&gt;/*&lt;br /&gt; * Now that we can have a Monopoly, &lt;br /&gt; * we game play a party ! &lt;br /&gt; * In Scala, party are called "application", &lt;br /&gt; * but it's because software developper are&lt;br /&gt; * known to be dull people. &lt;br /&gt; */  &lt;br /&gt;object Problem85 extends Application {&lt;br /&gt;  import Monopoly.{reverseBoard=&gt;RB}&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * We want to observe the evolution of&lt;br /&gt;   * the game, so we define a Logger&lt;br /&gt;   * (I'm sooooo unsurprising)&lt;br /&gt;   */&lt;br /&gt;  abstract class Logger {&lt;br /&gt;    def register(square:String)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * A looger that just output to console,&lt;br /&gt;   * used at the begining, to see the player&lt;br /&gt;   * evolves...&lt;br /&gt;   */&lt;br /&gt;  trait ConsoleLogger extends Logger {&lt;br /&gt;    override def register(s:String) = println(s)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * ... and was quickly replaced by a logger that&lt;br /&gt;   * just keep everything in a map, not that&lt;br /&gt;   * it was boring... Well, actually, it was.&lt;br /&gt;   */&lt;br /&gt;  trait MapLogger extends Logger {&lt;br /&gt;    var map = new HashMap[String,Int]()&lt;br /&gt;    override def register(s:String) { &lt;br /&gt;      /*&lt;br /&gt;       * ** Note to Java developpers **&lt;br /&gt;       * look how it's easy to say &lt;br /&gt;       * "I want to retrieve a key value&lt;br /&gt;       * from my map, but if the key does &lt;br /&gt;       * not exists, defined it with the &lt;br /&gt;       * given default value" in Scala. &lt;br /&gt;       * Just think to the number of if, and&lt;br /&gt;       * brackets and the like in Java...&lt;br /&gt;       */&lt;br /&gt;      map(s) = map.getOrElse(s,0) + 1&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Aaaaaahhhhhhh ! At last, there is our Game !&lt;br /&gt;   * It's defined with a random generator, the number&lt;br /&gt;   * of face we want our dices to have (remember, &lt;br /&gt;   * that's actually the point of the problem...), and&lt;br /&gt;   * a limit number.&lt;br /&gt;   * &lt;br /&gt;   * The limit number is the number of turn that our &lt;br /&gt;   * game will play before stoping (and we, look to&lt;br /&gt;   * the results). As we are in a Monte Carlo similution,&lt;br /&gt;   * this number will have to be HUGE. Say ONE MILLION !&lt;br /&gt;   * Ok, that's ridiculously small, but thanks to the&lt;br /&gt;   * kindness of project Euler team, the number converge &lt;br /&gt;   * quickly, and my PC is not as fast as clusters used&lt;br /&gt;   * for real Monte Carlo simulation, &lt;br /&gt;   * so it will have to do ;)&lt;br /&gt;   */&lt;br /&gt;  abstract class Game(&lt;br /&gt;    faces:Int, &lt;br /&gt;    random: Monopoly.Random, &lt;br /&gt;    limit:Int) extends Logger {&lt;br /&gt;    &lt;br /&gt;    val monopoly = new Monopoly(faces,random)&lt;br /&gt;    var square = ""&lt;br /&gt;    var turn = 0&lt;br /&gt;    &lt;br /&gt;    def start = {&lt;br /&gt;      while(turn &lt; limit) {&lt;br /&gt;        this.register(monopoly.turn())&lt;br /&gt;        turn = turn + 1&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Oups, don't forget to actually get a random&lt;br /&gt;   * generator. As explained for the Game, we don't&lt;br /&gt;   * need something too sophisticated for this&lt;br /&gt;   * simple example. We may have taken &lt;br /&gt;   * http://www.honeylocust.com/RngPack/ for a&lt;br /&gt;   * better pseudo-random generator (for example).&lt;br /&gt;   */&lt;br /&gt;  class JavaSimpleRandom extends Monopoly.Random {&lt;br /&gt;    val r = new scala.util.Random()&lt;br /&gt;    override def next = r.nextInt&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /* ============================= */&lt;br /&gt;  /*        Actual test            */&lt;br /&gt;  /* ============================= */&lt;br /&gt;  &lt;br /&gt;  val r = new JavaSimpleRandom()&lt;br /&gt;  val rounds = 1000000&lt;br /&gt;  val test = new Game(4,r,rounds) with MapLogger&lt;br /&gt;&lt;br /&gt;  print("begins... ")&lt;br /&gt;  test.start&lt;br /&gt;  println("results:")&lt;br /&gt;  val a = test.map.toList.sort( &lt;br /&gt;    ( x:(String,Int), y:(String,Int) ) =&gt; x._2 &gt; y._2)&lt;br /&gt;  for(i &lt;- 0 until 5) {&lt;br /&gt;    println("%5s (%02d): %s".&lt;br /&gt;      format(&lt;br /&gt;        a(i)._1,&lt;br /&gt;        RB(a(i)._1), &lt;br /&gt;        a(i)._2.toFloat/rounds)&lt;br /&gt;    )&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Voilà !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-6451434719849698872?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/6451434719849698872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=6451434719849698872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6451434719849698872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6451434719849698872'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2009/01/projecteuler84-monopoly-game-in-scala.html' title='ProjectEuler#84 : monopoly game in Scala'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8578907131695088437</id><published>2008-12-31T17:30:00.002+01:00</published><updated>2009-01-01T14:49:10.453+01:00</updated><title type='text'>Happy new year 2009</title><content type='html'>So, we are in 2009. As always, it's a good time to sum up the past year, and plan for the future. Of course, it's not the only moment for that, it's just that it seems to be in the ambient mood ;)&lt;br /&gt;&lt;br /&gt;So, what next ? A little report about top things on 2008, and some previsions ? General topics or more personal ones ? Tech or not ?&lt;br /&gt;&lt;br /&gt;Well, at least I will list some topic that were important to me, and we will see if a emerging design emerges ;)&lt;br /&gt;&lt;br /&gt;- I met really interesting people in 2008, and I would like to especially thank you &lt;a href="http://blog.asyd.net/2008/12/au-revoir-linagora/"&gt;Bruno for the time spent with us&lt;/a&gt;, I hope to work again with you. I would also thanks my team for the good time spent on developing software this year. Other cool people are lurking on #tapestry there were really surrealist and funny moments.  And there is all the others I'm forgetting, but thanks for all the good time.&lt;br /&gt;&lt;br /&gt;- I miss perhaps one of the best opportunities that I will ever have in 2008. I will have to be less timorous this year, more self confident.&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=221903"&gt;Java-the-language died in 2008&lt;/a&gt;, and perhaps it's a cool new. I only hope that it won't stop the JVM evolution. Moreover, Sun is not in its best wealth to say the least...  I can't imagine my future on a MS platform, that's clear (even if F# and C# 4.0 are becoming thrilling). So, perhaps it's time to look more carefully at Android...&lt;br /&gt;&lt;br /&gt;- A little think for my Grand-mother who died a 3 weeks ago...&lt;br /&gt;&lt;br /&gt;- That's 4 years that I'm Paris, and almost as long that I work on Linagora. That's a long, long time. I will have to do real software developpement in 2009, that's for sure.&lt;br /&gt;&lt;br /&gt;- I'm playing with Scala for almost 18 months now, but only for kid work. Perhaps  it is time to start real projects with it now...&lt;br /&gt;&lt;br /&gt;- I'm developing with &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry 5&lt;/a&gt; for almost 2 years now, it's really a wonderful framework. Thank you Howard for that piece of architecture, it's a great work !&lt;br /&gt;&lt;br /&gt;Oh, wait, perhaps there's an emerging design here ;)&lt;br /&gt;&lt;br /&gt;So, what next for 2009 ? That will have to be a year of major evolution, both on a personal and a professional point of vue. Perhaps it's time to go outside of France, perhaps it's time to come back on the south. Let's see how it can be done.&lt;br /&gt;&lt;br /&gt;So, let's go for 2009, let's take the opportunies this year !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8578907131695088437?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8578907131695088437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8578907131695088437' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8578907131695088437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8578907131695088437'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/12/happy-new-year-2009.html' title='Happy new year 2009'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8501758424403741861</id><published>2008-12-12T09:30:00.003+01:00</published><updated>2008-12-12T10:28:40.744+01:00</updated><title type='text'>Tapestry 5 Final is out !</title><content type='html'>At least !&lt;br /&gt;&lt;br /&gt;After almost two years of public alpha/beta releases, &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;Tapestry 5&lt;/a&gt; final is out !&lt;br /&gt;&lt;br /&gt;The vote for the 5.0.18 &lt;a href="http://markmail.org/message/hfigeeglqisjjjap"&gt;release succeeded this night&lt;/a&gt;, so perhaps not all the resources are already up to date, but it should be updated soon.&lt;br /&gt;&lt;br /&gt;So now, spread the words !&lt;br /&gt;&lt;br /&gt;The next BIG task for the community is to write a great and powerful third par component library, something like &lt;a href="http://gwt-ext.com/demo/"&gt;GWT-EXT&lt;/a&gt;. &lt;a href="http://www.chenillekit.org/"&gt;Chenillekit&lt;/a&gt; seems to be the best candidate today, even if it's in no way as polish and broad as gwt-ext.&lt;br /&gt;&lt;br /&gt;So, Tapestry 5 community, join our force to make T5 really attractive !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8501758424403741861?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8501758424403741861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8501758424403741861' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8501758424403741861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8501758424403741861'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/12/tapestry-5-final-is-out.html' title='Tapestry 5 Final is out !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-8916364321050734909</id><published>2008-11-24T10:21:00.003+01:00</published><updated>2008-11-24T10:59:01.480+01:00</updated><title type='text'>Tapestry final coming soon !</title><content type='html'>On the tech side, it's a good time for me !&lt;br /&gt;&lt;br /&gt;Soon after the release of Scala 2.7.2, it's Tapestry 5 time to reach &lt;a href="http://tapestryjava.blogspot.com/2008/11/ready-for-5017.html"&gt;an RC status&lt;/a&gt; (OK, I didn't blog about the RC1, some personal stuff were more important at this time).&lt;br /&gt;&lt;br /&gt;Moreover, Tapestry 5 is gaining a kind of hype in Europe, or at least in France : the new &lt;a href="http://france.meteofrance.com/france"&gt;official French weather&lt;/a&gt; site is coded with T5, and it's a big one (about 800,000 visitors in a day), and I just learn that &lt;a href="http://fr.wikipedia.org/wiki/Unedic"&gt;Unedic&lt;/a&gt;[1], the French civil service for the unemployed, which a BIG civil service (as most of them in France ;), chose Tapestry 5 as there new default "ligth" web framework.&lt;br /&gt;&lt;br /&gt;I'm quite happy of my choice for T5, almost 2 years ago :)&lt;br /&gt;&lt;pre wrap=""&gt;[1] sorry for the English readers, I didn't find an English description about Unedic :/&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-8916364321050734909?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/8916364321050734909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=8916364321050734909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8916364321050734909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/8916364321050734909'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/11/tapestry-final-coming-soon.html' title='Tapestry final coming soon !'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-942187332615918733</id><published>2008-11-22T17:30:00.002+01:00</published><updated>2008-11-22T17:34:02.147+01:00</updated><title type='text'>Windows refound if when you buy a computer</title><content type='html'>&lt;div style="margin: 0px auto 10px; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9D3n-ZqzF48/SSgzoXVuYyI/AAAAAAAAAo4/F91lTbEJlnw/s1600-h/Acer_Windows_rembours%C3%A9.jpg"&gt;&lt;img src="http://2.bp.blogspot.com/_9D3n-ZqzF48/SSgzoXVuYyI/AAAAAAAAAo4/F91lTbEJlnw/s320/Acer_Windows_rembours%C3%A9.jpg" alt="" border="0" /&gt;&lt;/a&gt; &lt;/div&gt;&lt;div style="clear: both; text-align: left;"&gt;It's the first time I ever see that in the description of a new computer. It's saying : "ask a vendor if you don't want Windows Vista with your new computer, the refound is 50€". The computer was an Acer of about 500€, it was in a big electronic french brand, and that's reaaly cool.&lt;br /&gt;&lt;br /&gt;Minds are evolving...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-942187332615918733?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/942187332615918733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=942187332615918733' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/942187332615918733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/942187332615918733'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/11/windows-refound-if-when-you-buy.html' title='Windows refound if when you buy a computer'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9D3n-ZqzF48/SSgzoXVuYyI/AAAAAAAAAo4/F91lTbEJlnw/s72-c/Acer_Windows_rembours%C3%A9.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-4660819917363237016</id><published>2008-11-10T09:19:00.004+01:00</published><updated>2008-11-10T09:33:21.046+01:00</updated><title type='text'>Scala 2.7.2 is out</title><content type='html'>Here we are, &lt;a href="http://www.scala-lang.org/node/348"&gt;Scala 2.7.2 was released on november, the 10&lt;/a&gt;.&lt;br /&gt;And it's a great news !&lt;br /&gt;&lt;br /&gt;You may wonder why a minor release seems to be so important ?&lt;br /&gt;&lt;br /&gt;C'm'on, it's a palindromic release number, it's so fantastic !&lt;br /&gt;&lt;br /&gt;Well, more seriously, it's because this released is the one that will be cover by the coming book &lt;a href="http://www.artima.com/shop/programming_in_scala"&gt;"Programming in Scala"&lt;/a&gt;, and so, this release mark a kind of shift in the Scala language development : Until now, the language was evolving quite quickly, what was great in term of enhancement, but bring some recurring problems, and seems to frighten a lot "the enterprise developers" (or at least there bosses).&lt;br /&gt;&lt;br /&gt;With this release, seconded by a great book, the Scala language reach a new level of maturity, and perhaps will gain more visibility outside the rather small (but growing !) circle of first time enthusiastic who use it today.&lt;br /&gt;&lt;br /&gt;So, it's a great news for Scala users, and a great time to go and discover Scala !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-4660819917363237016?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/4660819917363237016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=4660819917363237016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4660819917363237016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4660819917363237016'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/11/scala-272-is-out.html' title='Scala 2.7.2 is out'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-2599163908980340905</id><published>2008-11-04T10:21:00.013+01:00</published><updated>2009-01-03T16:49:48.369+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shjs'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>ProjectEuler#42, aka Scala shines as a scripting language</title><content type='html'>I'm still playing with project Euler, and I'm going to love Scala more and more.&lt;br /&gt;Yesterday, I solved the #42 problem, on which we need to parse a text file, and make some simple transformations and filtering on the results (it's why I choose this title, because it's generally the kind of things you expect to do in a scripting language, and well, I'm really&lt;br /&gt;impressive, and I read this morning the post  &lt;a href="http://www.codecommit.com/blog/scala/scala-as-a-scripting-language"&gt;"Scala as a scripting language?"&lt;/a&gt;, and I say "ho, it's exactly what I felt when I did pb#42 yesterday, let's blog on it, it's fashion :)&lt;br /&gt;&lt;br /&gt;So, this problem is a simple Project Euler one (at least, there is no math on it), but just stop and think to what may look the Java's solution. Yes, you will have to deal with Files, input stream, and the like, filtering data, sorting things, and even if it's quite simple, it's always a little too heavy compared to what it may be.&lt;br /&gt;&lt;br /&gt;So, there is the full solution in Scala, in a mixed imperative and functional style, as produced in the first sketch version (OK, I'm lying, in the first sketch, I didn't include comments and variables names looked more to 'lsv' and the like, these transformations are blog add-ons).&lt;br /&gt;&lt;br /&gt;I'm sure there is a lot of optimizations available, but the important think is that Scala let you program as you think, whitout to much noise and boilerplate...&lt;br /&gt;&lt;br /&gt;So let's go for the code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_scala"&gt;&lt;br /&gt;package ex26_50&lt;br /&gt;import scala.io.Source &lt;br /&gt;/*&lt;br /&gt;Problem#42&lt;br /&gt;The nth term of the sequence of triangle numbers &lt;br /&gt;is given by, tn = n(n+1);&lt;br /&gt;so the first ten triangle numbers are: &lt;br /&gt;1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...&lt;br /&gt;&lt;br /&gt;By converting each letter in a word to a number corresponding to its&lt;br /&gt;alphabetical position and adding these values we form a word value.&lt;br /&gt;For example, the word value for SKY is 19 + 11 + 25 = 55 = t10.&lt;br /&gt;&lt;br /&gt;If the word value is a triangle number then we shall &lt;br /&gt;call the word a triangle word.&lt;br /&gt;&lt;br /&gt;Using words.txt (right click and 'Save Link/Target As...'), &lt;br /&gt;a 16K text file containing nearly two-thousand common English &lt;br /&gt;words, how many are triangle words? &lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;object Problem42 extends Application {&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * iterate over all the lines of a file and&lt;br /&gt; * split each one on ',', remove surronding ",&lt;br /&gt; * and put the result in a list&lt;br /&gt; */&lt;br /&gt;def parseWords(file:String): List[String] = {&lt;br /&gt;   for {&lt;br /&gt;     line &lt;- Source.fromFile(file).getLines.toList&lt;br /&gt;     s &lt;- line.split(",")&lt;br /&gt;     if(!s.isEmpty)&lt;br /&gt;   } yield s.replaceAll("\"","") &lt;br /&gt;}  &lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Simple mapping function that associate&lt;br /&gt; * each char to it's value (position in the alphabet, begin to 1)&lt;br /&gt; * and a word to the sum of its char value&lt;br /&gt; */&lt;br /&gt;  def wordValue(s:String) : Int = { &lt;br /&gt;    var sum = 0 &lt;br /&gt;    for(c &lt;- s) {&lt;br /&gt;      // iterate over the chars of the string&lt;br /&gt;      val cval = c.toInt&lt;br /&gt;      if(cval &gt;= 64 &amp;amp;&amp;amp; cval &lt;= 90) {  &lt;br /&gt;        // 64 = ascii val for 'A', 90 = ascii val for 'Z'&lt;br /&gt;        sum = sum + cval - 64 &lt;br /&gt;      } else {&lt;br /&gt;        error("Unauthorized char: " + c.toString) &lt;br /&gt;      } &lt;br /&gt;    }&lt;br /&gt;    sum&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * That's the definition of the list number on witch we will work:&lt;br /&gt; * - parse the file to a list of word&lt;br /&gt; * - transform each word to it's word value &lt;br /&gt; * - sort the resulting, so that we can know the&lt;br /&gt; *      upper bound of our triangle value to caluculate            &lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;  val list_wordValues = &lt;br /&gt;    parseWords("src/words.txt").map(wordValue(_)).sort(_ &gt; _)&lt;br /&gt;&lt;br /&gt;//we also see that in Scala, Format syntax is actually usable&lt;br /&gt;  println("Max value in %s words: %s (min: %s)".format(&lt;br /&gt;      list_wordValues.size, &lt;br /&gt;      list_wordValues.head, &lt;br /&gt;      list_wordValues.reverse.head))&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Given the upper bound,&lt;br /&gt;   * generate the set of triangle number&lt;br /&gt;   */&lt;br /&gt;  val set_triangles = {&lt;br /&gt;    var set = Set[Int]()&lt;br /&gt;    var n = 1&lt;br /&gt;    var i = 1&lt;br /&gt;    while (n &lt; max ) {&lt;br /&gt;      n = (i * (i+1))/2&lt;br /&gt;      i = i + 1&lt;br /&gt;      set = set.+(n)&lt;br /&gt;    }&lt;br /&gt;    set&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /*&lt;br /&gt;   * That's all, we just have to filter the list of words to&lt;br /&gt;   * only keep whose which are in the set of triangles value,&lt;br /&gt;   * and take the size of the resulting list.&lt;br /&gt;   */ &lt;br /&gt;  val nb = list_wordValues.filter( (i:Int) =&gt; &lt;br /&gt;             set_triangles.contains(i)).size&lt;br /&gt;&lt;br /&gt;  println("Found %s triangles words !".format(nb))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I love scala :)&lt;br /&gt;&lt;br /&gt;PS: It's the full working solution, appart from the leading "_", sorry for the formatting, it seems that blogger is not the most friendly for code formatting. If somebody has some hint on that subject, I will be glad to heard them (ok, perhaps I should have a look on the plugins)&lt;br /&gt;&lt;br /&gt;EDIT: I found a way to highlight code thanks to &lt;a href="http://shjs.sourceforge.net/"&gt;SHJS&lt;/a&gt;. Thanks to the author for this plugin that wasn't to hard to make it work with blogger, and which the only Javascript highlighter that supports Scala :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-2599163908980340905?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/2599163908980340905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=2599163908980340905' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2599163908980340905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/2599163908980340905'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/11/projecteuler42-aka-scala-shines-as.html' title='ProjectEuler#42, aka Scala shines as a scripting language'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-28526714499361493</id><published>2008-10-22T08:57:00.011+02:00</published><updated>2008-10-27T16:58:37.354+01:00</updated><title type='text'>On static vs. dynamic type systems in programming languages</title><content type='html'>I'm a "static typed languages" guy. Whose who know me see what I mean :)&lt;br /&gt;&lt;br /&gt;The Rail's boys would say it's because I'm frightened by the field of possibilities, the freedom of dynamic languages&lt;span style="font-size:78%;"&gt; &lt;a href="http://www.blogger.com/post-edit.g?blogID=4809200280367588708&amp;amp;postID=28526714499361493#1"&gt;[1]&lt;/a&gt;&lt;/span&gt;.  I believe that it's more certainly because I came to software development through OCaml, a really good static typed language, and not like a vast majority of developer through languages from the C family (Java the worst among them &lt;span style="font-size:78%;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=4809200280367588708&amp;amp;postID=28526714499361493#2"&gt;[2])&lt;/a&gt;&lt;/span&gt;, which really missed the point of most of the advantages of static typing (yes, one days I will write about how enlightening was my experience with the &lt;a href="http://logical.saclay.inria.fr/coq/?q=node/8"&gt;Coq&lt;/a&gt; Proof assistant, and why things like &lt;a href="http://research.microsoft.com/%7Esimonpj/papers/boxy/"&gt;FPH&lt;/a&gt; are beautiful)&lt;br /&gt;&lt;br /&gt;So, because I'm dealing with Javascript, Pearl, Ruby and Python fan boys quite often (Lisper and Smaltalker are somewhat rarer ;), I would highlight this really good article about static and dynamic type systems, and the fallacies that most programmers believe about statically typed language : &lt;a href="http://www.pphsg.org/cdsmith/types.html"&gt;http://www.pphsg.org/cdsmith/types.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Synopsis:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;/h3&gt;&lt;blockquote&gt;&lt;h3&gt;Fallacies About Static and Dynamic Types&lt;/h3&gt;     &lt;p&gt;     Many programmers approach the question of whether they prefer static or dynamic types     by comparing some languages they know that use both techniques.  This is a reasonable     approach to most questions of preference.  The problem, in this case, is that most     programmers have limited experience, and haven't tried a lot of languages.  For context,     here, six or seven doesn't count as "a lot."  On top of that, it requires more than a     cursory glance to really see the benefit of these two very different styles of     programming.  Two interesting consequences of this are:    &lt;/p&gt;     &lt;ul&gt;&lt;li&gt;Many programmers have used very poor statically typed languages.&lt;/li&gt;&lt;li&gt;Many programmers have used dynamically typed languages very poorly.&lt;/li&gt;&lt;/ul&gt;     &lt;p&gt;     This section, then, brings up some of the consequences of this limited experience: things     many people assume about static or dynamic typing that just ain't so.    &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;And as I clearly fit in the category of "programmers [who] have used dynamically typed languages very poorly", I have to find the same article about fallacies on dynamic type language.&lt;br /&gt;I would really enjoy stuff about run-time optimization, contract on dynamic language, meta-programing &lt;span style="font-size:78%;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=4809200280367588708&amp;amp;postID=28526714499361493#3"&gt;[3]&lt;/a&gt;&lt;/span&gt; and such things.&lt;br /&gt;&lt;br /&gt;&lt;a name="1"&gt;[1]&lt;/a&gt; actually, when I see something like Jquery, I understand that Javascript is somewhat amazing. I will have to look harder on it.&lt;br /&gt;&lt;a name="2"&gt;[2]&lt;/a&gt; when you reach something like &lt;a href="http://apocalisp.wordpress.com/2008/10/23/heterogeneous-lists-and-the-limits-of-the-java-type-system/"&gt;that&lt;/a&gt; to get a real static type check for something like an heterogeneous list, then you know that something goes wrong.&lt;br /&gt;&lt;a name="3"&gt;[3]&lt;/a&gt; it's something that is possible in static typed language,as for example with &lt;a href="http://brion.inria.fr/gallium/index.php/Camlp4"&gt;OCamlP4&lt;/a&gt;, but I believe meta-programing in Lisp (for example) is more powerful, and the concept of meta-programing is more spread in dynamic typed language. It may be one of the fallacies ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-28526714499361493?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/28526714499361493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=28526714499361493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/28526714499361493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/28526714499361493'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/10/on-static-vs-dynamic-type-systems-in.html' title='On static vs. dynamic type systems in programming languages'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-6638925982498065740</id><published>2008-10-09T09:35:00.011+02:00</published><updated>2008-10-18T15:46:08.299+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='tapestry 5'/><category scheme='http://www.blogger.com/atom/ns#' term='meeting'/><title type='text'>Metting Tapestry father - Howard Lewis Ship in Paris</title><content type='html'>Thuesday the 7 october, I met Howard Lewis Ship, the father of Tapestry 5 Java web framework in Paris.&lt;br /&gt;He was here for a &lt;a href="http://tapestryjava.blogspot.com/2008/08/tapestry-europe-tour.html"&gt;3 weeks trip in Europe&lt;/a&gt;, far from its home, Portland, USA.&lt;br /&gt;&lt;br /&gt;There were Howard, his wife Suzan, and almost all my developers team, so 5 people from Linagora, all of them T5 addicts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Evening part I : bar and T5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Imminent release of 5.0 final....&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The evening began with a beer (or two...) in a bar near Linagora, and the discussion almost immediately started on Tapestry 5. Howard wanted to know how we came to T5, so I explained that I'm following its development since 5.0.1 and &lt;a href="http://raibledesigns.com/rd/entry/choosing_a_jvm_web_framework1#comment-1188917451000"&gt;that I didn't chose at all by luck T5.&lt;/a&gt; Now, every developer in my team use T5, and quite like it.&lt;br /&gt;&lt;br /&gt;We chatted about the iminent release of T5.0 final (YES !), the beauty of the framework thanks to the IoC framework, its scalabity, not only in performance, but in all thinkable meaning of the term : scalabitly in component from technical ones to business ones, scalabilty of the T5 user target from the business oriented people to the the technical nerd, etc.&lt;br /&gt;&lt;br /&gt;We also discussed the missing points, around the documentation and some little things (what bring me to a&lt;a href="http://markmail.org/search/?q=list%3Aorg.apache.tapestry.users+what+is+you#query:list%3Aorg.apache.tapestry.users%20what%20is%20you+page:1+mid:tsbsgttn574i2vlw+state:results"&gt; ml post on the subject&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;... and Tapestry 5.1 project&lt;/span&gt;...&lt;br /&gt;&lt;br /&gt;The discussion followed on the 5.1 release, it's short, time-based and not functionnality-based release cycle, every 3 to max 5 month.&lt;br /&gt;&lt;br /&gt;I think this is a really good new, because it was one of the most recurrent &lt;span style="cursor: pointer;" onclick="'dr4sdgryt(event,"&gt;criticism against Tapestry : its really really long release cycle, along with the compatibility issue between them.&lt;/span&gt; Even if Howard came back several times on the last point (it's even explained in the &lt;a href="http://tapestry.apache.org/tapestry5/"&gt;T5 home page, at the bottom)&lt;/a&gt;, upgrades would be even smoother if there is less time between them. Moreover, from a customer point of view, it's always best to have his product based on a stable release. I mean, a release tagged stable, because T5 is already one of the most stable soft I used, but the "alpha" or "beta" status is something quite frightening for a customer...&lt;br /&gt;&lt;br /&gt;Afterwards, Howard gives us the possibility to argue for our "most wanted feature".&lt;br /&gt;This is our wish-list, along with what Howard expects :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Portlets&lt;/li&gt;&lt;/ul&gt;That would be a great feature, because the component approach to the web really goes together with the portlet world. Howard thinks that it should be rather simple to make T5 portlet aware, because most of the needed abstractions are already here. And it's one of the things that should go in T5.1, so, we may be dreaming to cool webadmin interface with T5 in a portail in a near futur&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Webflow&lt;/li&gt;&lt;/ul&gt;That's another point that came back several time in the mailing list, and that is already in the T5.1 scope. &lt;a href="http://markmail.org/search/?q=list%3Aorg.apache.tapestry.users+Tapestry+5+Integration+with+Spring+Web+Flow+2#query:list%3Aorg.apache.tapestry.users%20Tapestry%205%20Integration%20with%20Spring%20Web%20Flow%202+page:1+mid:2i6ijlqmmfbfkmpd+state:results"&gt;Howard seems to be in discussion&lt;/a&gt; with Keith Donald to integrate Spring Web 2 and Tapestry 5 together.&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Plus, this is a really good feature to ship, especially directed to the IT managers. It's the kind of tool that make them think they can actually develop using boxes and arrows&lt;/span&gt;. I'm not completely sure I want Spring web flow integration into T5, but I definitely want a conversation persistence scope, along with a clean way to manage "wizards". So, if it has to come with Spring Web Flow integration, so be it...&lt;br /&gt;&lt;ul&gt;&lt;li&gt;skinning / themes&lt;/li&gt;&lt;/ul&gt;Howards was quite enthousiastic about the &lt;a href="https://issues.apache.org/jira/browse/TAP5-237"&gt;skinning and theming&lt;/a&gt; possibilities he envisions for 5.1.  It would be a kind of sitemesh, for free, thanks to a T5 component.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;OSGi&lt;/li&gt;&lt;/ul&gt;We chatted a little about OSGi. Several people on the ml already tried to integrate T5 and OSGi together, with &lt;a href="http://markmail.org/search/?q=list%3Aorg.apache.tapestry.users+OSGi#query:list%3Aorg.apache.tapestry.users%20OSGi+page:1+mid:o2lqqb7igyq6hrd4+state:results"&gt;more or less success&lt;/a&gt;. For now, I'm not quite sure of OSGi, I think it lacks a lot of all the plumbery that T5 so nicely hide to developpers... Perhaps Spring Dynamic Modules is the way to go, but for now, I think its use cases should remain in the proof of concept level.&lt;br /&gt;&lt;br /&gt;That was the main points, but we also talked about other framework as Terracotta, and ideas as ""CRUD should be free" (I would just add "as long as it is a side module, and not in the core". That's not really a problem with T5 and it's pluggable architecture, but for example, all the CRUD stuff is of no use in InterLDAP).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;...in an evolving Java ecosystem&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The last discussions in the bar where less focused on Tapestry, and more on the Java ecosystem. Java 7 came in the discussion, and I was happy to discover that Howard seems to share most of my view on the subject. He agree that the JVM need optimizations (faster, more plugable, more versatile, etc), but that Java the language should not evolve anymore...&lt;br /&gt;We talked about Scala and Groovy, his preference going to the second one (obviously, mine is in the first :), but he really likes the lazy evaluation possibilities that Scala bring.&lt;br /&gt;&lt;br /&gt;Here, there is something that I don't understand... For a functional developer, all Tapestry architecture is built around functional concept, I see map/fold and pattern matching every where in Tapestry :)&lt;br /&gt;&lt;br /&gt;Jean-Louis, one of my co-worker, talked about his "&lt;a href="http://easyant.abrm.info/trac"&gt;easy ant&lt;/a&gt;" project - take the best of Ant and Maven dependency management thanks to Ivy. A to-be-followed project.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Evening part II : "La Casita" restaurant&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the end of the evening, we moved to &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;q=la+casita,+9+rue+de+Washington+75008+Paris&amp;amp;jsv=132e&amp;amp;sll=37.0625,-95.677068&amp;amp;sspn=38.365962,96.679688&amp;amp;ie=UTF8&amp;amp;latlng=48872206,2301486,13580886255140101092&amp;amp;ei=Wk34SK35MJPKoAP2kvjHDg&amp;amp;sig2=P1MoXQtkwGJSM-nAVnxg8A&amp;amp;cd=1"&gt;"La Casita", a french restaurant near Les Champs Elysées&lt;/a&gt;. It's a typical France South-West cooking restaurant, with Champagne, Foie Gras, snails, duck, wine, cheese... And to my great pleasure, Suzan and Howard seemed to enjoy it !&lt;br /&gt;So much for our French a priori and cliché about American taste :)&lt;br /&gt;&lt;br /&gt;There, we talked less about Tapestry, and more on general subjects. We chatted about the difference on open source in USA (more pragmatic, due to cost efficiency) and in France (more philosophical and political).&lt;br /&gt;We also had an input around the use of IRC, and the complementarity this communication channel can have with the traditionnal mailing list (folks, come in the Tapestry irc chan : #tapestry on freenode).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;See you next time !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Along the night, I tested the &lt;a href="http://xkcd.com/323/"&gt;Ballmer Peak&lt;/a&gt; applied to English spoken skills, and went at least as far in the curve as Millenium developpers...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For me, it was a really really great evening, Howard and Suzan are really nice people.&lt;br /&gt;Moreover, Howard is one of the best architect I know in the Java world, it was a great pleasure to meet him. Suzy is realy nice, the next time I will have to invite my girlfriend too :)&lt;br /&gt;&lt;br /&gt;So, thank you Howard and Suzy for this meeting, and see next time (in Portland ?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-6638925982498065740?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/6638925982498065740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=6638925982498065740' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6638925982498065740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/6638925982498065740'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/10/metting-tapestry-father-howard-lewis.html' title='Metting Tapestry father - Howard Lewis Ship in Paris'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-811550517816807776</id><published>2008-09-30T23:15:00.006+02:00</published><updated>2008-10-03T09:55:39.875+02:00</updated><title type='text'>Java Bar Camp Mardi 30 septembre</title><content type='html'>J'ai participé hiers soir à mon premier "&lt;a href="http://barcamp.org/JavaCampParis"&gt;Java Bar Camp&lt;/a&gt;" à Paris, dans les locaux de &lt;a href="http://www.octo.com/"&gt;Octo Technologie&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Avant d'aller plus loin, je tiens à remercier les organisateurs, mis à part le retard sur l'arrivée des participants, tout le reste a été très bien géré, bravo !&lt;br /&gt;&lt;br /&gt;Premières impressions : ce n'est pas du tout ce à quoi je m'attendais. Je m'attendais à un rassemblement de geek &amp;amp; développeurs barbus, alors que l'assemblée était beaucoup plus hétéroclite, avec une forte coloration consultant/chef de projet.&lt;br /&gt;Les thèmes s'en sont fortement ressenti : méthodes de développement, build et tests étaient à l'honneur.&lt;br /&gt;&lt;br /&gt;Mais revenons sur le déroulement de la soirée :&lt;br /&gt;- 18h30 / 19h30 arrivée des participants (un peu de retard, Julien Dubois (M. Spring en France) absent (il est papa :), toutes mes félicitations )&lt;br /&gt;- 19h30 :&lt;br /&gt;* tour de salle : chacun décline nom/prénom, et 3 tags, des sujets qu'il souhaite évoquer - dans un bar camp, tout le monde est acteur ;&lt;br /&gt;* après le tour de salle, chacun est libre d'aller inscrire sur un post-it le sujet dont il souhaite parler parmi les tags;&lt;br /&gt;* 8 sujets sont choisis parmi les post-it, organisés en 2 sessions (donc réparti dans 4 salles)&lt;br /&gt;- 19h45/20h35 : première session : TDD/Test ; Licenses OSS ; Spring vs JEE ; ? ;&lt;br /&gt;- 20h40/21h30 : seconde session : usine logicielle (build, maven...) ; scrum en vrai ; ? ; ?&lt;br /&gt;- ensuite, buffet et discussion libres.&lt;br /&gt;&lt;br /&gt;J'ai choisi en première session JEE5 vs Spring (à regret), et en seconde session "Scrum en vrai".&lt;br /&gt;&lt;br /&gt;Je ne vais pas m'éterniser sur la première session, orienté "débat", et il fut relativement stérile et consensuel. Rien n'émerge clairement, sauf que "certain client ne veulent que des normes, et JEE s'impose", "Sans Spring, Java en entreprise serait sûrement mort, bouffi par sa complexité". Bref, rien de nouveau. Le point de vu de Julien aurait sûrement mis un peu de couleurs.&lt;br /&gt;&lt;br /&gt;La seconde session m'a beaucoup plus plû. J'y ai rencontré Eric Mignot de &lt;a href="http://www.pyxis-tech.com/"&gt;Pyxis&lt;/a&gt;, un "évangéliste Scrum", intégriste (dans le bon sens ), qui m'a permis de voir le chemin qu'il reste à parcourir dans sa mise en place dans les projets auxquels je participe, mais aussi de prendre consience du chemin déjà parcouru.&lt;br /&gt;&lt;br /&gt;Après avoir revu les bases de scrum (organisation, objets), nous avons abordé les problèmes contractuel, la gestion de l'architecture, la gestion humaine des équipe.&lt;br /&gt;&lt;br /&gt;Le mot qui revient le plus souvent est "engagement" : un projet Scrum ne peut pas fonctionner si toutes les personnes y prennant part son convaincu par la méthode, en particulier si le scrum master n'a pas un soutient indéfible de sa direction, et si le product owner n'a pas le pouvoir décisionnaire sur les paiement/le budjet et sur le périmètre fonctionnel.&lt;br /&gt;&lt;br /&gt;La fin de la soirée étaient agréable, les groupes se formant et se séparant au gré des discussions, souvent pationnée.&lt;br /&gt;&lt;br /&gt;En résumé : une expérience intéressante, un fin de soirée nettement plus intéressante que le début, et je reste sur ma fin en terme de développement pur - ce n'est pas dans ce genre de soirée que je parlerais de Scala ou de language fonctionnels :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-811550517816807776?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/811550517816807776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=811550517816807776' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/811550517816807776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/811550517816807776'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/java-bar-camp-mardi-30-septembre.html' title='Java Bar Camp Mardi 30 septembre'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-1989328597035817202</id><published>2008-09-30T10:34:00.003+02:00</published><updated>2008-09-30T11:01:55.843+02:00</updated><title type='text'>Project Euler - Scala</title><content type='html'>I discovered &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt;, a website that purpose a lots of Mathematical problems that can be solved with programming.  The website provides a check of you solution, and a forum to discuss it but only after you give the rigth answer.&lt;br /&gt;&lt;br /&gt;Scala really shine in this kind of game. Well, I think that any functionnal language, and perhaps Ocaml even better that other (thanks to it's amazing vm),  are really well fitted for this kind of small, algoritm instensive tasks.&lt;br /&gt;&lt;br /&gt;The first problems are really simple, and brute force works well, but quickly it is not enonght, and the game become really interesting : it force myself to remind old memories of school, and I'm afraid at the size of the hole in them - I mean, I should have followed some advandced Maths courses in classe préparatoires, and it's almost if I have to discover again all the concept and properties and theorems...  A good reason to do all the Project Euler problem till the last one !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-1989328597035817202?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/1989328597035817202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=1989328597035817202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/1989328597035817202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/1989328597035817202'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/project-euler-scala.html' title='Project Euler - Scala'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-525465606484637711</id><published>2008-09-30T09:48:00.005+02:00</published><updated>2008-09-30T10:20:47.120+02:00</updated><title type='text'>Amazing Mythical Man Month</title><content type='html'>Fred Brooks was rigtht. Well, I know I will not have a Nobel for this fantastic discovery, but each time I refer to the &lt;a href="http://en.wikipedia.org/wiki/The_Mythical_Man-Month"&gt;TMMM&lt;/a&gt;, I'm really impressed by the insight of the man.&lt;br /&gt;&lt;br /&gt;Ok, so, to be more specific : TMMM has 33 years. He is older than me. And Fred Brooks already depected most of the Agile programming method (&lt;span style="cursor: pointer;" onclick="'dr4sdgryt(event,"&gt;history is constantly repeating itself).&lt;br /&gt;&lt;br /&gt;But perhaps what impresse me the most is that he forecasted 33 years ago what is happening with Open Source software and the JVM ecosystem today : we will build better and cheaper programms only if common, higth-quality tools and library are broadly available.&lt;br /&gt;&lt;br /&gt;It's (almost, but if we look from a hight level, it's not too bad) what is happeing in the JVM (do not read Java) world, and tools like IVY and Maven, &lt;/span&gt;Superpackages (ah, not yet)&lt;span style="cursor: pointer;" onclick="'dr4sdgryt(event,"&gt; only make it happens quicker.&lt;br /&gt;&lt;br /&gt;The future will be intersting, if Sun does not break everything (I hope it's too late for that now).&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-525465606484637711?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/525465606484637711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=525465606484637711' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/525465606484637711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/525465606484637711'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/amazing-mythical-man-month.html' title='Amazing Mythical Man Month'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3600767087697768543</id><published>2008-09-29T09:22:00.000+02:00</published><updated>2008-09-29T09:59:37.089+02:00</updated><title type='text'>About me</title><content type='html'>OK, since I broke the rule I decreed in the first post, at least I should let some information about me.&lt;br /&gt;&lt;br /&gt;I'm François Armand, I'm French (Paris) and work in software development for an open-source company, &lt;a href="http://linagora.com/"&gt;Linagora&lt;/a&gt;. My daily work is mostly with Java, with all the drowback it brings - and some quite good surprises from time to time, especially about the wealth and diversity of its ecosystem (but this point is more about the JVM's ecosystem than Java-the-language).&lt;br /&gt;&lt;br /&gt;I'm rather new in computer related stuff, since my first programms where done when I reach the master cycle (don't now exactly how French's 'Grandes Écoles" translate in other cultures - for whom who migth be curious, I'm from "&lt;a href="http://www.ensiie.fr/"&gt;ENSIIE&lt;/a&gt;"). It was in september 2001.&lt;br /&gt;&lt;br /&gt;I keep from that period a deep interest for functionnal programming, and especially a real good memory in my 2004 research project (the one for the end of school's master cycle), when I was allowed to take part of the INRIA's &lt;a href="http://compcert.inria.fr/"&gt;CompCert (Certified Compiler)&lt;/a&gt; project and had a deeper look into Ocaml and &lt;a href="http://coq.inria.fr/"&gt;COQ&lt;/a&gt; (a great program prover - well, not exactly, see by youserlves).  I will thanks for that Sandrine Blazy and all the people I met in this time (Xavier Leroy, Yves Bertot and others).&lt;br /&gt;&lt;br /&gt;The following is more boring. I met the "real world, with real programs and stuff that matter", say Java and Web development.  Hum. Well, all is not dark in this side of the world, because I work in company deeply involved with open source software, and I take part of some really good projects, as for example the &lt;a href="http://federid.org/"&gt;FederId&lt;/a&gt; project, in which I was the developer of &lt;a href="http://interldap.org/"&gt;InterLDAP-WUI&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;All in all, I'm not a real common Java developer, and it's perhaps why I'm looking toward Scala, or Tapestry 5.&lt;br /&gt;&lt;br /&gt;OK, that all for now, just a last sentence to link my &lt;a href="http://www.linkedin.com/in/francoisarmand"&gt;linkedin profil&lt;/a&gt; (I'm also on viadeo, and I believe that the two are rather out of date).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3600767087697768543?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3600767087697768543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3600767087697768543' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3600767087697768543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3600767087697768543'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/about-me.html' title='About me'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-63349087852795993</id><published>2008-09-29T09:13:00.000+02:00</published><updated>2008-09-29T09:21:51.270+02:00</updated><title type='text'>Tapestry 5, Scala</title><content type='html'>Since the first time I played with &lt;a href="http://tapestry.apache.org/tapestry5"&gt;Tapestry 5&lt;/a&gt; about 18 months ago, I know it would be great, and the more I use it, the more I see how well thought it is. But again, the more I see the limitation of Java-the-language.&lt;br /&gt;&lt;br /&gt;I really need to test again Tapestry 5 with &lt;a href="http://scala-lang.org"&gt;Scala&lt;/a&gt; as a back-end - Yeah, Scala is the other hot-thing I follow since about the same time, and at that moment Scala/T5 was working fine. But hence Scala evolved a lot, and T5 relies deeply on Javassist and byte code manipulation, I fear that I may encounter some bad surprises, especially in real-life application.&lt;br /&gt;&lt;br /&gt;One more item in my to-do list :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-63349087852795993?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/63349087852795993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=63349087852795993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/63349087852795993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/63349087852795993'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/tapestry-5-scala.html' title='Tapestry 5, Scala'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-3919527462685871184</id><published>2008-09-23T13:39:00.000+02:00</published><updated>2008-09-29T09:13:22.561+02:00</updated><title type='text'>Java 7, aka the Rubicon</title><content type='html'>I'm looking forward to write something about Java 7, and why it makes me feeling more and more uneasy. To summarize my thinking, I believe that Java, the language, can not continue to evolve without a clean deletion of old, not alway smart or still relevant design choice of java 1 to 5, but that the JVM have a great deal to play as the new open runtime environment.&lt;br /&gt;&lt;br /&gt;Hope I will find some time to develop it a little, at least it's writing somewhere.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-3919527462685871184?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/3919527462685871184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=3919527462685871184' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3919527462685871184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/3919527462685871184'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/java-7-aka-rubicon.html' title='Java 7, aka the Rubicon'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4809200280367588708.post-4775268764320326084</id><published>2008-09-16T09:51:00.000+02:00</published><updated>2008-09-16T09:55:43.717+02:00</updated><title type='text'>Hard to get OpenId</title><content type='html'>The so called standard authentication standard, with all its hole and drawbacks, is becoming a required tools... So, I have to open a blog to get an OpenID (google already has so many infos about me... Of course I trusted them, they are so nice...).&lt;br /&gt;&lt;br /&gt;Don't expect real post here :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4809200280367588708-4775268764320326084?l=fanf42.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fanf42.blogspot.com/feeds/4775268764320326084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4809200280367588708&amp;postID=4775268764320326084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4775268764320326084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4809200280367588708/posts/default/4775268764320326084'/><link rel='alternate' type='text/html' href='http://fanf42.blogspot.com/2008/09/hard-to-get-openid.html' title='Hard to get OpenId'/><author><name>Fanf</name><uri>http://www.blogger.com/profile/10948445494945956846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-O3Ulor55abs/TrsPRt-KiqI/AAAAAAAABLA/ndOiPuvyCXU/s220/francois.jpg'/></author><thr:total>0</thr:total></entry></feed>
