<?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-8738651469871299069</id><updated>2011-07-31T10:56:33.561+02:00</updated><category term='ruby'/><category term='xml'/><category term='hibernate'/><category term='tools'/><category term='java'/><category term='english'/><category term='security'/><category term='jenkins'/><category term='scm'/><category term='maven'/><category term='gwt'/><category term='hosting'/><category term='hudson'/><category term='command'/><category term='french'/><category term='ruby on rails'/><category term='agile'/><category term='build'/><category term='wicket'/><category term='groovy'/><category term='jetty'/><category term='spring'/><category term='ORM'/><category term='findbugs'/><category term='weblogic'/><category term='cakephp'/><category term='windows'/><category term='eclipse'/><category term='testing'/><category term='j2ee'/><category term='subversion'/><category term='database'/><category term='deploy'/><title type='text'>Side Spin, Gael's blog</title><subtitle type='html'>Tips, thoughts on software engineering in general.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-4766832532178222830</id><published>2011-05-25T14:22:00.021+02:00</published><updated>2011-05-26T00:42:29.326+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='deploy'/><category scheme='http://www.blogger.com/atom/ns#' term='jetty'/><category scheme='http://www.blogger.com/atom/ns#' term='jenkins'/><title type='text'>Hot deploy in Jetty a war file built by Jenkins</title><content type='html'>We use &lt;a href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt; to build our application as a war file and we wanted to deploy it in a &lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt; server to provide a manual testing environment.&lt;div&gt;So, we installed Jetty on our Ubuntu machine using &lt;span class="Apple-style-span"&gt;'sudo apt-get jetty libjetty-extra'&lt;/span&gt;&lt;br /&gt;&lt;div&gt;By default, when you copy a war file to Jetty &lt;span class="Apple-style-span"&gt;webapps&lt;/span&gt; directory, nothing happens because Jetty scans this directory only at startup. So, we could stop/start Jetty daemon but it requires granting some privileges to the user running Jenkins and also we may want to deploy more than one application without stoppîng the ones that are already running.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another solution is to use Jetty's &lt;a href="http://docs.codehaus.org/display/JETTY/ContextDeployer"&gt;ContextDeployer&lt;/a&gt; hot deploy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This means editing &lt;span class="Apple-style-span"&gt;/etc/jetty/jetty.xml&lt;/span&gt; and setting the &lt;span class="Apple-style-span"&gt;scanInterval&lt;/span&gt; of &lt;span class="Apple-style-span"&gt;ContextDeployer&lt;/span&gt; to lowest possible value: 1 second and then restart Jetty.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&amp;lt;Call name="addLifeCycle"&amp;gt;&lt;br /&gt;&amp;lt;Arg&amp;gt;&lt;br /&gt;&amp;lt;New class="org.mortbay.jetty.deployer.ContextDeployer"&amp;gt;&lt;br /&gt;&amp;lt;Set name="contexts"&amp;gt;&amp;lt;Ref id="Contexts"/&amp;gt;&amp;lt;/Set&amp;gt;&lt;br /&gt;&amp;lt;Set name="configurationDir"&amp;gt;&amp;lt;SystemProperty name="jetty.home" default="."/&amp;gt;/contexts&amp;lt;/Set&amp;gt;&lt;br /&gt;&amp;lt;Set name="scanInterval"&amp;gt;1&amp;lt;/Set&amp;gt;&lt;br /&gt;&amp;lt;/New&amp;gt;&lt;br /&gt;&amp;lt;/Arg&amp;gt;&lt;br /&gt;&amp;lt;/Call&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;Now we must create a context file for our war file in /etc/jetty/contexts directory. Let's call it myapp.xml and let's point it to the location of the war file from last successful build in Jenkins.&lt;/div&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&amp;lt;?xml version="1.0"  encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"&amp;gt;&lt;br /&gt;&amp;lt;Configure class="org.mortbay.jetty.webapp.WebAppContext"&amp;gt;&lt;br /&gt; &amp;lt;Set name="contextPath"&amp;gt;/myapp&amp;lt;/Set&amp;gt;&lt;br /&gt; &amp;lt;Set name="war"&amp;gt;/var/lib/jenkins/jobs/MyProject/lastSuccessful/archive/trunk/myapp/target/myapp-0.0.1-SNAPSHOT.war&amp;lt;/Set&amp;gt;&lt;br /&gt;&amp;lt;/Configure&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;In order to deploy we just have to update our context file which can be easily done by executing 'touch /etc/jetty/contexts/myapp.xml'. We can then add it as a step in our main job in Jenkins if we want want continuous deployment or we can create a separate job if we want to control when we deploy a new version.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-4766832532178222830?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/4766832532178222830/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=4766832532178222830' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4766832532178222830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4766832532178222830'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2011/05/hot-deploy-in-jetty-war-file-built-by.html' title='Hot deploy in Jetty a war file built by Jenkins'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-8410548511871423940</id><published>2011-04-27T22:05:00.011+02:00</published><updated>2011-05-01T11:21:49.267+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>GWT testing using Maven and Eclipse</title><content type='html'>When developing an application using Google Web Toolkit, it's a good practice to have both unit tests which do not require GWT and GWT tests for custom widgets or integration.&lt;div&gt;If you use Maven, you should apply the default naming convention of the &lt;a href="http://mojo.codehaus.org/gwt-maven-plugin/user-guide/testing.html"&gt;Maven GWT plugin&lt;/a&gt; : *Test.java for standard unit tests and GwtTest*.java for GWT test cases. This way you have nothing to configure in your pom.xml.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then you'll get errors from the GWT compiler because your unit tests are located in same java packages as your GWT application code but in a different source directory (e.g. src/test/java) and the compiler cannot find their source files. While these errors are not fatal and could be ignored, they are annoying. You can get rid of them by excluding your unit test classes by file pattern in your .gwt.xml file like below:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;source path='client' excludes=&amp;quot;**/*Test.java,**/Mock*.java&amp;quot; /&amp;gt; &lt;br /&gt;&amp;lt;source path='shared' excludes=&amp;quot;**/*Test.java&amp;quot; /&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When you will run your GWT application, you may see error messages like:&lt;br /&gt;&lt;blockquote&gt;[ERROR] [MyApp] - Line 13: No source code is available for type com.google.gwt.junit.client.GWTTestCase; did you forget to inherit a required module?&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;It does not prevent your application from running but they are annoying.&lt;br /&gt;You can get rid of them by moving your GWT test cases to a dedicated source directory that you will exclude from the classpath of your Eclipse run configuration.&lt;br /&gt;Finally, you'll put your standard unit tests under "src/test/java" and your GWT tests under "src/gwt-test/java". In your pom.xml, you have to use the build-helper-plugin to add this extra test directory.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;build-helper-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;version&amp;gt;1.5&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;id&amp;gt;add-test-source&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;phase&amp;gt;generate-test-sources&amp;lt;/phase&amp;gt;&lt;br /&gt;   &amp;lt;goals&amp;gt;&lt;br /&gt;    &amp;lt;goal&amp;gt;add-test-source&amp;lt;/goal&amp;gt;&lt;br /&gt;   &amp;lt;/goals&amp;gt;&lt;br /&gt;   &amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;sources&amp;gt;&lt;br /&gt;     &amp;lt;source&amp;gt;src/gwt-test/java&amp;lt;/source&amp;gt;&lt;br /&gt;    &amp;lt;/sources&amp;gt;&lt;br /&gt;   &amp;lt;/configuration&amp;gt;&lt;br /&gt;  &amp;lt;/execution&amp;gt;&lt;br /&gt; &amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;If you want to speed up your GWT tests, you can launch them from a GWT test suite but then you must configure the Maven plugin for running only your test suite otherwise you'd end up running same test twice. My naming convention is Gwt*Suite.java which works well with the two other conventions.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt; &amp;lt;groupid&amp;gt;org.codehaus.mojo&amp;lt;/groupid&amp;gt;&lt;br /&gt; &amp;lt;artifactid&amp;gt;gwt-maven-plugin&amp;lt;/artifactid&amp;gt;&lt;br /&gt; &amp;lt;version&amp;gt;2.2.0&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;test&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;!-- Run only test suites not individual test cases. --&amp;gt;&lt;br /&gt;  &amp;lt;includes&amp;gt;**/Gwt*Suite.java&amp;lt;/includes&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/plugin&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/8738651469871299069-8410548511871423940?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/8410548511871423940/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=8410548511871423940' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/8410548511871423940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/8410548511871423940'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2011/04/tricks-about-gwt-testing.html' title='GWT testing using Maven and Eclipse'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-4914396978416549716</id><published>2010-04-29T22:17:00.005+02:00</published><updated>2010-05-01T19:17:01.382+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='french'/><title type='text'>Installer Hudson sur un serveur OVH</title><content type='html'>Pour installer le serveur d'intégration continue &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; sur un serveur dédié OVH tournant Ubuntu, le plus pratique c'est de partir du package Debian et de suivre &lt;a href="http://hudson-ci.org/debian/"&gt;les instructions&lt;/a&gt;.&lt;div&gt;Le script va créer un utilisateur hudson, installer les binaires, les fichiers de configuration et le script de démarrage/arrêt.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Par défaut, l'espace disque est sous /home. &lt;/div&gt;&lt;div&gt;Si vous n'avez pas repartitionné votre serveur, vous pouvez déplacer la home et les logs de hudson.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Stoppons Hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo /etc/init.d/hudson stop&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Passons sous /home/hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo mv /var/lib/hudson /home&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo ln -s /home/hudson /var/lib/hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo mkdir /home/hudson/log&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo mv /var/log/hudson/hudson.log /home/hudson/log/hudson.log&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo ln -s /home/hudson/log/hudson.log /var/log/hudson/hudson.log&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo chown -R hudson:nogroup /home/hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Demarrons Hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo /etc/init.d/hudson start&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style=" ;font-family:Georgia, serif;"&gt;&lt;div&gt;La version Debian est un peu en retard sur la dernière version d'Hudson, voici comment la mettre à jour:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Stoppons Hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo /etc/init.d/hudson stop&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Sauvegarde du war existant et download de la derniere version&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;cd /usr/share/hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo mv hudson.war hudson.war.old&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo wget http://hudson-ci.org/latest/hudson.war&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# Demarrons Hudson&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sudo /etc/init.d/hudson start&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&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/8738651469871299069-4914396978416549716?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/4914396978416549716/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=4914396978416549716' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4914396978416549716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4914396978416549716'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2010/04/installer-hudson-sur-un-serveur-ovh.html' title='Installer Hudson sur un serveur OVH'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-2570379291746268598</id><published>2010-04-17T11:35:00.007+02:00</published><updated>2011-04-27T22:05:23.398+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='french'/><category scheme='http://www.blogger.com/atom/ns#' term='hosting'/><title type='text'>Mise en place d'un serveur de build</title><content type='html'>&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Nous avions besoin d'un serveur de projet (wiki, intégration continue, subversion, ...), j'ai retenu 2 possibilités: &lt;/span&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Une solution "Software as a Service"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Un serveur dédié&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:x-large;"&gt;Software as a Service&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;On trouve beaucoup d'offres très bon marché (moins de 10 euros par mois pour une petite équipe) incluant un dépôt Subversion et une  gestion de projet basée sur Trac ou Redmine mais il manque l'intégration continue&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Atlassian propose avec &lt;a href="http://www.atlassian.com/hosted/studio/"&gt;JIRA Studio&lt;/a&gt; une solution complète a un prix correct et c'est probablement la solution que nous aurions retenue si nous n'avions pas aussi eu à installer d'autres applications comme Nexus.  Donc nous sommes partis sur l'option serveur dédié en tout cas pour quelques mois.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:x-large;"&gt;Serveur dédié&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;J'ai regardé 3 solutions françaises: Dédibox, Gandi et OVH.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Gandi est une offre cloud computing très souple basée sur Xen, on achète des parts de serveur 12 € HT/mois qui correspondent à du CPU, de la RAM et du disque. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;On peut provisionner plus de parts à l'heure près.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Cette offre me semblait sous dimensionnée en terme de CPU, disque et bande passante et dès qu'on rajoute des parts, la facture monte vite.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;J'ai ensuite comparé un Dedibox XL et un OVH Super plan mini qui sont assez proches à 49.99€ HT/mois. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;Au final j'ai opté pour OVH principalement parce qu'ils incluaient 100 Go d'espace de sauvegarde contre 10 chez Dedibox. De manière générale, quand on a beaucoup de données à sauvegarder, les prix grimpent.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;span class="Apple-style-span" style=" ;font-size:16px;"&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=" ;font-size:medium;"&gt;Mon serveur était disponible moins d'une heure plus tard.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=" ;font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=" ;font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=" ;font-size:medium;"&gt;&lt;br /&gt;&lt;/span&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/8738651469871299069-2570379291746268598?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/2570379291746268598/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=2570379291746268598' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2570379291746268598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2570379291746268598'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2010/04/choisir-un-serveur-dedie.html' title='Mise en place d&apos;un serveur de build'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-6237972286415300466</id><published>2009-04-09T13:12:00.009+02:00</published><updated>2010-04-19T01:26:34.480+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='french'/><title type='text'>Créer des interfaces java est-il anti agile?</title><content type='html'>Créer des interfaces java facilite le découplage, permet d'utiliser des mocks pour les test unitaires, de changer d'implémentation, de créer des points d'interception mais peut-on considérer que c'est une pratique anti agile? Ma réponse est bien sur "Ça dépend" ;)&lt;br /&gt;&lt;br /&gt;Oui si on considère que c'est du sur design (YAGNI) et qu'on attend d'avoir complètement défini les interfaces pour commencer a implémenter les  classes concrètes.&lt;br /&gt;&lt;br /&gt;Le Test Driven Design conduit à créer des classes concrètes, introduire des interfaces dans ce processus itératif le ralentit.&lt;br /&gt;&lt;br /&gt;Par contre, on peut au cours d'une session TDD avoir besoin de créer une implémentation mock d'un DAO par exemple et au final en extraire une interface par refactoring quand le design s'est stabilise. On obtient ainsi une interface dont la conception a émergé du TDD et un mock utile pour les test unitaires des classes consommant cette interface.&lt;br /&gt;&lt;br /&gt;Il ne s'agit pas non plus de créer des interfaces a tout bout de champ mais la où ça fait sens comme la couche d'accès aux données (d'où mon exemple sur un DAO) ou tout point d'intégration avec un module ou un composant de l'infrastructure.&lt;br /&gt;&lt;br /&gt;Donc c'est plutôt le moment ou l'on crée une interface et la façon dont on la crée qui peut être non agile.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-6237972286415300466?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/6237972286415300466/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=6237972286415300466' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/6237972286415300466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/6237972286415300466'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2009/04/creer-des-interfaces-java-est-il-anti.html' title='Créer des interfaces java est-il anti agile?'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-7127233675252812872</id><published>2008-08-10T10:49:00.008+02:00</published><updated>2008-08-10T11:35:00.555+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='findbugs'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='j2ee'/><title type='text'>FindBugs on a Wicket +  Spring application</title><content type='html'>&lt;a href="http://findbugs.sourceforge.net/index.html"&gt;FindBugs&lt;/a&gt; is a great static analysis tool and it helped me to find several bugs but recently we switched to &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt; 1.3 framework for web development and we got few false positives which were related to using Spring with Wicket.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Serialization&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We had Wicket page classes with fields being injected by Spring using the @SpringBean annotation.&lt;br /&gt;FindBugs complained that these fields should have been serializable or transient &lt;a href="http://findbugs.sourceforge.net/bugDescriptions.html#SE_BAD_FIELD"&gt;(SE_BAD_FIELD error&lt;/a&gt;) and this seemed an issue as Wicket does use serialization a lot to save pages into its session.&lt;br /&gt;In fact, it turned out to be a false postive because Wicket manages this by using Spring dynamic proxies.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Unitialized fields in constructor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another FindBugs complaint in Wicket page classes was about de-referencing fields in constructor before having initialize them (&lt;a href="http://findbugs.sourceforge.net/bugDescriptions.html#UR_UNINIT_READ"&gt;UR_UNINIT_READ error&lt;/a&gt;).&lt;br /&gt;Again, this turned out to be a false positive because our pages did extend WebPage class that takes care of injecting all SpringBean annotated fields using a PropertyResolver.&lt;br /&gt;Something to remember: the default PropertyResolver is able to initialize private fields and ignores setters.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using Spring beans in Wicket pages introduces a lot of dynamicity that defeats static analysis when dealing with object initialization and serialization.&lt;br /&gt;FindBugs is so valuable that it is worth excluding these rules on Pages and having a naming convention for these classes makes it easier to do. Our page classes are now named with the "Page" suffix.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-7127233675252812872?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/7127233675252812872/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=7127233675252812872' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7127233675252812872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7127233675252812872'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2008/08/findbugs-on-wicket-spring-application.html' title='FindBugs on a Wicket +  Spring application'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-7974507225044653642</id><published>2008-04-19T21:11:00.011+02:00</published><updated>2008-04-23T08:56:40.095+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>My first (useful) script in Groovy</title><content type='html'>We had a large number of XML files to modify and found that Groovy with its GPath syntax was the right tool. Here is an example that takes a (simplified) XML file and changes the value of one attribute for a subset of nodes.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background: #f0f0f0"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;design&amp;gt;&lt;br /&gt;  &amp;lt;process&amp;gt;&lt;br /&gt;    &amp;lt;variable id="V1" visible="true" /&amp;gt;&lt;br /&gt;    &amp;lt;variable id="V2" visible="false" /&amp;gt;&lt;br /&gt;    &amp;lt;variable id="V3" visible="false" /&amp;gt;&lt;br /&gt;  &amp;lt;/process&amp;gt;&lt;br /&gt;&amp;lt;/design&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the script to change all XML files in the current directory.&lt;br /&gt;I found it easier to write and debug it than using a mix of java and XSL.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background: #f0f0f0"&gt;&lt;br /&gt;def basedir = new File( ".")&lt;br /&gt;&lt;br /&gt;// Create a directory for patched files&lt;br /&gt;new File("patched").mkdir()&lt;br /&gt;&lt;br /&gt;// Get files with ".xml" extension&lt;br /&gt;files = basedir.listFiles().grep(~/.*\.xml$/)&lt;br /&gt;&lt;br /&gt;// Iterate on the files&lt;br /&gt;files.each {&lt;br /&gt;  patchXML(it)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def patchXML(file) {&lt;br /&gt; println "-------------------"&lt;br /&gt; println "Patching $file.name"&lt;br /&gt;&lt;br /&gt; def design = new XmlParser().parse(file)&lt;br /&gt; def modified = false&lt;br /&gt;&lt;br /&gt; for (variable in design.process.variable) {&lt;br /&gt;   switch (variable.@id) {&lt;br /&gt;     case "V1":&lt;br /&gt;     case "V2":&lt;br /&gt;         if (variable.@visible == "false") {&lt;br /&gt;             variable.@visible = "true"&lt;br /&gt;             modified = true&lt;br /&gt;         }&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt; if (modified) {&lt;br /&gt;   new File("patched/$file.name").withPrintWriter() {&lt;br /&gt;      new XmlNodePrinter(it).print(design)&lt;br /&gt;   }&lt;br /&gt;   println "Patched $file.name is in \"patched\" directory"&lt;br /&gt; } else {&lt;br /&gt;   println "$file.name was not modified"&lt;br /&gt; }&lt;br /&gt; println "-------------------"&lt;br /&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/8738651469871299069-7974507225044653642?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/7974507225044653642/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=7974507225044653642' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7974507225044653642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7974507225044653642'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2008/04/my-first-useful-script-in-groovy.html' title='My first (useful) script in Groovy'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-6936716801889198523</id><published>2008-04-10T22:32:00.008+02:00</published><updated>2008-08-10T10:42:28.233+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='j2ee'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='ORM'/><title type='text'>Hibernate without a DBA: a sure path to failure!</title><content type='html'>Recently, my team had to deploy a Java web application that we bought from a small company. They used Hibernate as their Object Relational Mapping and were using it to generate their database schema.&lt;br /&gt;&lt;br /&gt;In order to make their installation process easier, the application was creating or updating the database schema at startup time. This may sound like a nice idea but in most companies, you don't want to grant your application DROP, CREATE or ALTER privileges as it could be a security vulnerability if your web application gets hacked. Fortunately, Hibernate provides you with ant tasks to generate your schema creation script and if your customer runs on a different database server, you will generate a script for it.&lt;br /&gt;&lt;br /&gt;That's great but as soon as we started to run our load tests, we got tons of deadlock errors on SQL Server 2005:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Transaction (Process ID 54) was deadlocked on lock resources with another process and  has been chosen as the deadlock victim. Rerun the transaction.&lt;/blockquote&gt;A typical developer reaction is to accuse Hibernate, the driver or the database engine. After a quick search on Google I was under the impression that it should be a bug in the application.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Application bugs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The show_sql flag in Hibernate configuration is a useful tool, it helped the developers to find that under some circumstances the application would save the same data twice. They fixed the code,we ran the load test again and observed a great performance improvement but still deadlock errors.&lt;br /&gt;&lt;br /&gt;Another search on Google leaved me with more questions than answers with few exceptions like this excellent &lt;a href="http://blogs.msdn.com/bartd/archive/2006/09/09/Deadlock-Troubleshooting_2C00_-Part-1.aspx"&gt;article&lt;/a&gt; from Bart Duncan. After reading it, you should be convinced that you need some help from a good DBA. We were fortunate to have a good DBA team even though I found it difficult to explain them what statements or queries we were using because they were generated by Hibernate and not written by ourselves.&lt;br /&gt;The most difficult part was to obtain a trace on the database server when reproducing a deadlock. Many trace flags can be too invasive and change your timing preventing you to reproduce the deadlock. We found that the trace flag 1222 was the most helpful to get data without modifying the execution timing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Unicode encoding&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Our DBA analyzed the data and found a deadlock cause: inserting unicode strings into a varchar column that was indexed, this caused a conversion and index scan resulting in a concurrency between 2 threads executing same statement updating different rows but using same index. Solution: convert column types to nvarchar or change your JDBC driver settings to avoid encoding string parameters in Unicode, both will also bring you an additional gain in performance.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Missing index on a foreign key&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We changed the JDBC driver setting and ran again the load test: deadlocks again but new ones.&lt;br /&gt;Our DBA did analyze the new trace and quickly found a foreign key in a one-to-many relationship which was not indexed, this resulted in an index scan and deadlock on concurrent updates. This is something that you can and should specify in your Hibernate mappings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Other issues&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can get deadlocks also when using clustered indexes. It turns out that by default primary keys in SQL Server are clustered indexes. So by using Hibernate schema, you will get clustered indexes for all your primary keys, it's usually not a problem especially for naturally growing keys like identity columns but if you are using randomly generated strings for your ids it can be a problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hibernate like other ORMs is a useful tool but you should use its schema generation feature for what it is: a help to speed up your initial development but you will not avoid fine tuning of your table definitions, indexes and only an experimented DBA can help you there.&lt;br /&gt;&lt;br /&gt;Do not believe that by using Hibernate you will be able to migrate easily from one database engine to another one, you will almost always end up tuning your schema to solve deadlocks or performance issues in a specific way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-6936716801889198523?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/6936716801889198523/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=6936716801889198523' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/6936716801889198523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/6936716801889198523'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2008/04/hibernate-without-dba-sure-path-to.html' title='Hibernate without a DBA: a sure path to failure!'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-2729546604817559894</id><published>2008-02-27T07:41:00.004+01:00</published><updated>2008-02-27T08:19:49.394+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Public Maven repositories and wrong POMs</title><content type='html'>I experienced an issue with log4j 1.2.15: it comes with a POM that wrongly forces you to include extra dependencies that should be optional (e.g. Java mail if you don't plan to use the SMTPAppender feature). This issue has been reported as bug &lt;a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=43304"&gt;#43304&lt;/a&gt; to log4j team.&lt;br /&gt;&lt;br /&gt;My first reaction was to exclude these dependencies in my project pom.xml but this did not work (I did not take time to investigate why). Anyway, it was faster for me to patch the log4j POM in our intranet repository.&lt;br /&gt;&lt;br /&gt;Lesson learned: managing dependencies can be hard and you should not depend on public repositories as they can be wrong sometimes. Make sure your team has an Intranet repository and make it simple to update with a good repository manager like &lt;a href="http://artifactory.sf.net/"&gt;Artifactory&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-2729546604817559894?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/2729546604817559894/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=2729546604817559894' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2729546604817559894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2729546604817559894'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2008/02/public-maven-repositories-and-wrong.html' title='Public Maven repositories and wrong POMs'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-2101565100309575210</id><published>2007-10-26T13:26:00.001+02:00</published><updated>2008-02-27T08:11:17.413+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Not fully convinced by Maven 2</title><content type='html'>After several weeks of trying to migrate our build process to Maven 2, we decided to stop due to:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Incompatibility with WebLogic&lt;/span&gt;: we use BEA Weblogic ant tasks that are not compatible with Maven build lifecycle phases. For instance, appc mixes generate-sources, compile and package; for this reason the maven-weblogic-plugin that uses these tasks has same flaw. So if you need to use other Maven plugins you must implement workarounds and attach them to unnatural phases to ensure they get executed before or after appc. See my &lt;a href="http://www.blogger.com/2007/09/weblogic-92-is-not-maven-2-friendly.html"&gt;previous post&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Lack of flexibility&lt;/span&gt;: by nature, Maven is not flexible, the only ways to get more flexibility is to use profiles, maven-antrun-plugin or to write your own plugin in java: not really simple nor very productive especially if you need to write simple workarounds. It's strange because there seems to be a growing tendency in open source build tools to enable more flexibility: &lt;a href="http://wiki.apache.org/ant/Ant18/Planning"&gt;ant 1.8 feature list&lt;/a&gt; includes logic/control flow features from ant-contrib (for, if, while, etc…), gant uses groovy as build scripting language on top of ant, &lt;a href="http://buildr.rubyforge.org/"&gt;buildr&lt;/a&gt; uses Ruby.&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Lack of auditability&lt;/span&gt;: with Maven's convenient way to download missing parts and self update, it's difficult to know exactly what was used to build one version of your product. The fact that Maven mixes tool's dependencies of the tool (maven+plugins) and dependencies of the projects being built into one single local repository surely does not help here. it would be better if separation of concerns was implemented in local repository to ensure that the dependencies managed by the developers do not get polluted by dependencies that are out of its control scope.&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;      Issues are &lt;span style="font-weight: bold;"&gt;difficult to diagnose&lt;/span&gt;: I've got examples about classpath, system properties where it's difficult to find the culprit between Maven, plugins or dependencies.&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Plugins quality&lt;/span&gt; ranks from excellent to terrible: this is not a Maven issue by itself but combined with above mentioned difficulty to diagnose it can lead to painful situations.&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;&lt;a href="http://jira.codehaus.org/browse/MNG"&gt;      Maven's defect backlog&lt;/a&gt; is quite impressive and I'm not sure that the situation is going to improve soon.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So, our next approach will be to use ant for building and restrict Maven to managing dependencies and generating project site and quality reports.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-2101565100309575210?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/2101565100309575210/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=2101565100309575210' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2101565100309575210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/2101565100309575210'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/10/not-fully-convinced-by-maven-2.html' title='Not fully convinced by Maven 2'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-5661407982990994621</id><published>2007-09-15T18:14:00.001+02:00</published><updated>2007-09-16T14:48:15.237+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>How to connect to an MS Access database using Ruby and ODBC</title><content type='html'>If you search for an answer to this question in Google, you will get mostly sarcastic answers and if you're lucky maybe some help.&lt;br /&gt;&lt;br /&gt;You must first download Ruby ODBC from &lt;a href="http://ch-werner.de/rubyodbc/"&gt;Christian Werner's site&lt;/a&gt; and copy odbc.so and odbc_utf8.so into the ...\ruby\1.8\i386-msvcrt directory where you installed Ruby. Uf you have installed InstantRails in default location, it should be under C:\InstantRails\ruby\lib\ruby\1.8\i386-mswin32&lt;br /&gt;&lt;br /&gt;In the example below I connect to an Access file (c:\ruby.mdb) and print the contents of a table (Table1)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;&lt;br /&gt;access_dsn_base = 'DBI:ODBC:Driver=Microsoft Access Driver (*.mdb);DBQ='&lt;br /&gt;access_file = 'C:\ruby.mdb'&lt;br /&gt;&lt;br /&gt;DBI.connect(access_dsn_base+access_file) do |dbh|&lt;br /&gt;  dbh.select_all('Select * From Table1') {|row| p row}&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Similarly, you can use DBI:ODBC to read MS Excel files.&lt;br /&gt;In the example below I connect to an Excel file (c:\my_file.xls) and print the contents of a spreadsheet (Sheet1)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;&lt;br /&gt;excel_dsn_base = 'DBI:ODBC:Driver={Microsoft Excel Driver (*.xls)};DBQ='&lt;br /&gt;excel_file = 'C:\my_file.xls'&lt;br /&gt;&lt;br /&gt;DBI.connect(excel_dsn_base+excel_file) do |dbh|&lt;br /&gt;  dbh.select_all('Select * From [Sheet1$]') {|row| p row}&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My configuration is Windows XP + MS Access 2000 + MS Excel 2002 + Ruby 1.8.6 + Ruby ODBC 0.9995&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-5661407982990994621?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/5661407982990994621/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=5661407982990994621' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/5661407982990994621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/5661407982990994621'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/09/how-to-connect-to-ms-access-database.html' title='How to connect to an MS Access database using Ruby and ODBC'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-8507680189975807248</id><published>2007-09-12T08:16:00.000+02:00</published><updated>2007-09-12T16:12:07.238+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='j2ee'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><category scheme='http://www.blogger.com/atom/ns#' term='weblogic'/><title type='text'>WebLogic 9.2 is not Maven 2 friendly</title><content type='html'>Using &lt;a href="http://maven.apache.org"&gt;Maven 2&lt;/a&gt; is more difficult when you use a platform like BEA WebLogic 9.2 because of their &lt;a href="http://edocs.bea.com/wls/docs92/programming/splitcreate.html"&gt;"split directory"&lt;/a&gt; convention which creates a gap with Maven's own conventions.&lt;br /&gt;&lt;br /&gt;A first approach could be to avoid using the split directory structure, however it's not that easy because it comes with a set of specific &lt;span style="font-style: italic;"&gt;ant&lt;/span&gt; tasks to pre-compile your JSPs, generate a web service from an EJB, package an &lt;span style="font-style: italic;"&gt;ear&lt;/span&gt; file, ...&lt;br /&gt;These tasks are not open sourced and are too high level to be easily integrated into Maven: for instance, if you want to pre-compile your JSPs, you cannot use anymore &lt;span style="font-style: italic;"&gt;jspc&lt;/span&gt; because it has been deprecated in favor of &lt;span style="font-style: italic;"&gt;appc&lt;/span&gt; which depends on the split directory structure.&lt;br /&gt;This makes almost impossible to write an equivalent Maven plugin for a 3rd party, only BEA could do it.&lt;br /&gt;&lt;br /&gt;Another issue with these tasks is that they are defined in &lt;span style="font-style: italic;"&gt;weblogic.jar&lt;/span&gt;: a 50 MB jar which contains a lot of stuff that may collides with dependencies in your classpath, especially because BEA chose to specify a relative classpath in its jar manifest.&lt;br /&gt;&lt;br /&gt;An alternative is to use the WebLogic ant tasks from Maven using the &lt;span style="font-style: italic;"&gt;antrun&lt;/span&gt; plugin, unfortunately this plugin is poorly documented and does not offer easy options to configure a classpath to integrate weblogic.jar. Also, &lt;span style="font-style: italic;"&gt;antrun&lt;/span&gt; retrieves its own version of &lt;span style="font-style: italic;"&gt;ant&lt;/span&gt; from Maven's repository that may collide with the one required by WebLogic's tasks; you can find workarounds for this but then you will have to trick Maven to make it think that it has generated the artifact generated by &lt;span style="font-style: italic;"&gt;appc&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;So, unless BEA endorses Maven and provides its own plugins, it will be difficult to use Maven for a non trivial WebLogic application. My next step will be to try to use ant and Maven's &lt;a href="http://maven.apache.org/ant-tasks.html"&gt;antlib&lt;/a&gt; in order to be able to use Maven's dependency management.&lt;br /&gt;&lt;br /&gt;P.S.: I just found Hussein Badakhchani's excellent post &lt;a href="http://dev2dev.bea.com/blog/hoos/archive/2007/09/using_appc_with.html"&gt;about maven and appc&lt;/a&gt;, I may try his approach as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-8507680189975807248?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/8507680189975807248/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=8507680189975807248' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/8507680189975807248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/8507680189975807248'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/09/weblogic-92-is-not-maven-2-friendly.html' title='WebLogic 9.2 is not Maven 2 friendly'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-5647729204870384988</id><published>2007-08-21T12:23:00.000+02:00</published><updated>2007-08-24T17:37:56.633+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='command'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>Windows Environment Variables Trap</title><content type='html'>In Windows, you can easily define environment variables from the "My Computer" icon on your desktop. It's convenient but you can't define the evaluation order, so Windows does it for you but it does it wrongly (at least on Windows XP).&lt;br /&gt;&lt;br /&gt;Define these variables:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;V1=1&lt;br /&gt;V2=%V1%-2&lt;br /&gt;V3=%V2%-3&lt;br /&gt;V4=4-%V5%&lt;br /&gt;V5=5-%V6%&lt;br /&gt;V6=6&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Here is what you get:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;V1=1&lt;br /&gt;V2=1-2&lt;br /&gt;V3=1-2-3&lt;br /&gt;V4=4-%V5%&lt;br /&gt;V5=5-6&lt;br /&gt;V6=6&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So, V4 was not correctly expanded.&lt;br /&gt;We can also see that the evaluation is partly based on alphabetical order (V1, V2, V3) but that there were 2 passes as V5 is correct.&lt;br /&gt;&lt;br /&gt;So, if you want to get safe set an evaluation order on your variables by setting them  in your &lt;code&gt;autoexec.bat&lt;/code&gt; file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-5647729204870384988?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/5647729204870384988/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=5647729204870384988' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/5647729204870384988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/5647729204870384988'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/08/windows-environment-variables-trap.html' title='Windows Environment Variables Trap'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-1787438239054529905</id><published>2007-08-15T12:20:00.000+02:00</published><updated>2007-08-19T20:45:06.700+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cakephp'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><title type='text'>My First Ruby on Rails project</title><content type='html'>It's been a while since I wanted to refactor my PHP+Smarty web site and also to implement additional database driven features. The main purpose of this application is to manage table tennis tournament results.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;CakePHP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Being hosted on a PHP box, my first idea was to look for Ruby on Rails clone in PHP.&lt;br /&gt;I found &lt;a href="http://www.cakephp.org/"&gt;CakePHP&lt;/a&gt; to be the only serious one able to run on PHP4 so the choice was easy.&lt;br /&gt;I spent few hours during 3 weeks to learn the framework and start my project, there was no book to help so I relied mostly on simple tutorials and users forums.&lt;br /&gt;CakePHP is a good framework with may useful features (some of them are even more advanced than Ruby on Rails equivalent ones) and a great community but documentation is sparse and worse: it suffers from PHP's poor syntax (at least from a Java developer's standpoint).&lt;br /&gt;After 3 weeks, I decided to stop and switched to Ruby on Rails even if it meant switching to a new web hosting company.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Switching to Ruby on Rails&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I bought the &lt;a href="http://www.pragmaticprogrammer.com/title/rails/"&gt;"Agile Web Development with Rails"&lt;/a&gt; book and read several tutorials.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Using existing database&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First, I created my application using &lt;code&gt;rails ipttc&lt;/code&gt; then I created a migration from my existing database.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ruby script/generate migration Initial&lt;br /&gt;rake db:schema:dump&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then I copy/pasted from schema.rb into the up method of db/migrate/001_initial.rb&lt;br /&gt;&lt;br /&gt;&lt;code&gt;rake db:migrate&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I found that my legacy schema was not following some of Rails conventions like having a numerical id for tables, I decided to keep it simple and adapt the rails conventions, maybe I'll dig further if needed.&lt;br /&gt;&lt;br /&gt;Being a lazy typist, I looked at ways to generate my models from existing database and I found &lt;a href="http://magicmodels.rubyforge.org/magic_model_generator/"&gt;Dr Nic's Magic Model Generator&lt;/a&gt; which created 7 models with validation rules in a snap, Thanks Doc! By reviewing the generated models, I was able to learn quickly about validations and relations and I really discovered something unexpected: it did create some kind of indirect relations: "has many through".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Tournament has many Medals.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Player has many Medals.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Tournament has many Players through Medals.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And it does make a lot of sense, it's like saying:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Tournament has many Medalists.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After that, I started to play with scaffolding and I was a bit disappointed because it did not take into account relations between models. I searched for better scaffolding and found &lt;a href="http://www.activescaffold.com/"&gt;ActiveScaffold&lt;/a&gt; and &lt;a href="http://hobocentral.net/"&gt;Hobo&lt;/a&gt;. ActiveScaffold provides dynamic scaffolding using Ajax and nice presentation. Hobo is more a framework on top of Rails and provide additional nice features like  a security model with users, roles and permissions. Both of them are very promising but they provide only dynamic scaffolding while I am more looking for a code generator to be able to learn and modify things for my needs. Also, I'm still too new in Rails to be able to select an additional framework, I must try to understand the standard Rails features first.&lt;br /&gt;&lt;br /&gt;Fortunately, I was also looking at RESTful implementation in Rails and found that there was a new scaffold code generator that was deprecating the original one.&lt;br /&gt;The good thing about&lt;code&gt; scaffold_resource &lt;/code&gt;is that it lets you to generate the model, the views, the controller and the database table in migration at once.&lt;br /&gt;You just have to list the name of your fields and types, for instance for Player and Country:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ruby script/generate scaffold_resource Player full_name:string first_name:string last_name:string birth_date:date country_id:integer gender:string class:integer dead:boolean eligible:boolean&lt;br /&gt;&lt;br /&gt;ruby script/generate scaffold_resource Country code:string name:string&lt;br /&gt;&lt;br /&gt;rake db:migrate&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My application will be RESTful and I will create a new database schema.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-1787438239054529905?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/1787438239054529905/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=1787438239054529905' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/1787438239054529905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/1787438239054529905'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/08/my-first-ruby-on-rails-project.html' title='My First Ruby on Rails project'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-7814955441825999976</id><published>2007-08-12T19:38:00.000+02:00</published><updated>2007-08-19T16:44:19.527+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Code Red Alert</title><content type='html'>&lt;p&gt;A little story that happened to me as a hobbyist webmaster of &lt;a href="http://www.ipttc.org/"&gt;www.ipttc.org&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;In previous months, I have seen our network bandwidth consumption  increasing, 2 months ago I found that there was a lot of traffic coming from servers in Vietnam where our sport is not very developed but at this was at the end of the month I did not pay too much attention.&lt;br /&gt;&lt;p&gt;On June, 13&lt;sup&gt;th&lt;/sup&gt;, I noted a major traffic increase, I looked at the most downloaded pages and was surprised to find audio files (.wma) while we don't distribute music of course.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Then, I found that there were about 1500 such files in one directory which was the upload directory of forum for attachments. So, everything indicated that a hacker did exploit a vulnerability in the file upload module of the forum.&lt;br /&gt;I decided to remove the files but it was not possible, so I renamed the directory and I logged a support ticket to get administrators to do the job.&lt;br /&gt;I un-installed the file upload module and updated the forum software to most recent version.&lt;br /&gt;&lt;/p&gt;I sent a mail to my committee qnnouncing that our web site would probably get unavailable because our network bandwidth for the month could be exceeded within next hours or days and that the downtime could last until end of the month.&lt;br /&gt;&lt;br /&gt;Next morning, I got a mail from support saying that they deleted the files.&lt;br /&gt;&lt;p&gt;Unfortunately, our bandwidth got exceeded during the night and so our site was down.&lt;br /&gt;&lt;/p&gt;I decided to look carefully at the web server log files and I found that all requests for music files came from one site &lt;a href="http://www.muzic9.com/"&gt;www.muzic9.com&lt;/a&gt;. In fact, this site proposes "free" music, you choose an album and then click on a song, it then redirects transparently to an external site. So it means that when clicking on some songs you actually downloaded them from www.ipttc.org! I sent an email to the webmaster asking him to delete all links pointing to our site get and that he no longer accepts such links.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I did a "whois" query to find the site owner:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;TUAN&lt;br /&gt;TUAN TUAN (tuan.maxviet@gmail.com)&lt;br /&gt;1.8633630&lt;br /&gt;Fax: 1.8633630&lt;br /&gt;Some where in VN&lt;br /&gt;address&lt;br /&gt;HCM, HCM 70000&lt;br /&gt;VN&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the owner was from Vietnam, same country that consumed our bandwidth last month.&lt;br /&gt;I did send same email to this address. No need to say, I never got any reply.&lt;br /&gt;&lt;br /&gt;I put some additional protections in place and now monitor more seriously my bandwidth consumption report and web log files.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8738651469871299069-7814955441825999976?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/7814955441825999976/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=7814955441825999976' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7814955441825999976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/7814955441825999976'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/08/code-red-alert.html' title='Code Red Alert'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8738651469871299069.post-4158437557676240521</id><published>2007-08-10T15:05:00.000+02:00</published><updated>2007-08-10T22:22:47.129+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Subversion quick protocol benchmark</title><content type='html'>&lt;div&gt;Subversion lets you choose the protocol used to connect from client to server, it has an impact on the authentication scheme but also on data transfer rate. &lt;/div&gt;&lt;br /&gt;&lt;div&gt; I ran a checkout on 2500 files and 50 MB with client running locally on server. As expected, "svn" was the fastest: "http" was 66% slower and "https" was 135% slower. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;Also an export of same source tree is much faster  than a checkout (up to 3 times faster in my tests depending on the number of files) because svn client does not need to create a local copy of each file nor metadata files (checksums, logs, ...) in &lt;span style="font-style: italic;"&gt;.svn&lt;/span&gt; directories. So, it could be a little optimization for a build that does not need to commit any change.&lt;br /&gt;&lt;br /&gt;Of course, when the client is remote, the impact of a slow network connection tends to lower these differences.&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/8738651469871299069-4158437557676240521?l=gmarziou.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gmarziou.blogspot.com/feeds/4158437557676240521/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8738651469871299069&amp;postID=4158437557676240521' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4158437557676240521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8738651469871299069/posts/default/4158437557676240521'/><link rel='alternate' type='text/html' href='http://gmarziou.blogspot.com/2007/08/subversion-quick-protocol-benchmark.html' title='Subversion quick protocol benchmark'/><author><name>Gaël Marziou</name><uri>http://www.blogger.com/profile/01404749103817483595</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://2.bp.blogspot.com/-dViIUk51P7w/Tbh2gnT9KFI/AAAAAAAAAWk/i4D4cxcerqs/s220/gael_marziou.jpg'/></author><thr:total>0</thr:total></entry></feed>
