Archive for August, 2007

SVN Notifier

Friday, August 31st, 2007

I just discovered SVN Notifier that allows to watch a subversion repository. This utility from tigris (they also build subversion) displays an icon in your system tray and pops up when other people commit new versions in the repository you want to watch.

You can configure notifications for repositories or sub-folder, and then update your local view from the tool when you get notified of new commits.
It does not allow to automatically update your local view without manual intervention, which might be useful in some cases (but you can easily plan task invoking svn commands to do that).

Useful when the SVN server is not linked to a web interface supporting RSS, like Trac or webSVN.

Découverte de JAXB

Friday, August 31st, 2007

Dans ce post, j’applique la sugession Chad Fowler dans son livre “My Job Went to India: All I Got Was This Lousy Book” : pour être sûr qu’on a bien compris quelquechose, il faut essayer de l’expliquer.
Voyons ce qu’est JAXB. Ma problématique est d’écrire le contenu d’une table relationnelle en XML. La structure de la table est déjà créée et le format XML déjà connu. Le but est de trouver le moyen le plus adapté dans le langage java.
Après avoir refoulé immédiatement l’idée d’écrire la sauce XML dans un fichier, je me suis intéressé à JAXB.

  1. En entrée, on a un fichier XML “en production”, c’est-à-dire déjà généré il y a quelques années. Or JAXB prend un fichier de structure en entrée. Il est possible de trouver sur internet un service “xml2xsd” qui analyse un fichier XML et en extrait un schéma possible. Après avoir contrôlé ce schéma et supprimé toutes les références aux namespaces propriétaires (de Microsoft pour ne pas le citer), on a notre schéma.
  2. La phase de génération de code de JAXB intervient ici. Voilà la commande à lancer:
    %JDK_HOME%/bin/xjc schema.xsd

    Elle permet de générer une implémentation java d’objets qui se conforment au schéma. On dispose donc d’une hiérarchie d’objets de style javabean qui peuvent recevoir autant de données qu’un fichier XML implémentant le schéma XML.

  3. Ensuite, il faut écrire le code jdbc pour se connecter à la base, requêter la table et extraire les données à plat dans une instanciation de notre hiérarchie d’objets. Concrètement, on instancie l’objet qui représente la balise root et on remplit !
  4. Finalement, il ne reste qu’à faire un marshall (c’est-à-dire une exportation) des objets dans un fichier.

Discussion

Avantages:

  • Rapide, la génération de code
  • Léger, le code à écrire soi-même
  • En Bonus, le unmarshalling au cas où on voudrai lire le fichier XML ailleurs.

Inconvénients:

  • Dangereuse, la génération de code lorsque le schéma va changer, on a clairement deux endroits où sont stockés l’information de structure XML : dans le XSD et dans la hiérarchie d’objets générés…
  • Lourd, la hiérarchie d’objets en mémoire lorsque les volumes de données sont importants

Conclusion: positive pour mon usage.
Evolution: intégrer la génération de code dans la procédure ant pour détecter les changements du schéma ?

Pour en savoir plus, je vous propose consulter cette présentation : JAXB.ppt

GWT 1.4.59-RC2 and Maven2

Friday, August 24th, 2007

Gwt 1.4.59-RC2 was just released. If you use Maven2 to build your project, this latest version can be found on xi8ix repository.

Here is the configuration:

<repositories>
    <repository>
        <id>xi8ix</id>
        <url>http://maven.xi8ix.org/</url>
    </repository>
</repositories>
<dependency>
    <groupId>com.google</groupId>
    <artifactId>gwt-user</artifactId>
    <version>1.4.59-RC2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.google</groupId>
    <artifactId>gwt-servlet</artifactId>
    <version>1.4.59-RC2</version>
</dependency>

I had to tweak a few things in my SpringDispatchService. Maybe it’s time to find a more stable solution…

Ordre juste

Wednesday, August 22nd, 2007

Most of the time we don’t care about the hibernate mapping configuration when we deploy
an application based on JBPM (a
worflow framework from Jboss). But if you want to use the same session factory for
JBPM and your custom objects (the JBPM
spring module
have some helper classes) you have several options for the
sessionFactory bean declaration in the spring configuration file :

  • use two mapping sections : one for the JBPM jar file and one for the directory where
    the mapping files of custom objects are :
            
              <
              bean 
              id="sessionFactory"...>
< property name="mappingDirectoryLocations"> <list> <value>classpath*:**/your/custom/objects/mapping</value> </list> </property> <property name="mappingJarLocations"> <list> <value>file:**/jbpm-jpdl.jar</value></list> </property> </bean>


  • or extract the JBPM mapping files (find all .hbm.xml files in the extracted JAR) and
    add the directory to the mappingDirectoryLocations :

    <property name="mappingDirectoryLocations"> <list> <value>classpath*:**/your/custom/objects/mapping</value> <value>classpath:/the/directory/JBPM/mapping/files/</value> </list> </property>

    but the order of the mapping files is important : JBPM has a custom type (string_max)
    declared in the hibernate.queries.hbm.xml file, this file should be before any other
    JBPM mapping file.
    I not you encounter this exception when the session factory
    is build :

Caused by: org.hibernate.MappingException: Could not determine type for: string_max,
for columns: [org.hibernate.mapping.Column(MESSAGE_)]


or


Caused by: org.hibernate.MappingException: Could not determine type for: string_max,
for columns: [org.hibernate.mapping.Column(DESCRIPTION_)] …

And if you use the 3.2 version of JBPM with the spring module (for 3.1) one minor
modification is needed from the manual :  

  • The transactionnal service in the jbpm.cfg.xml : <service name="tx" factory="org.jbpm.tx.TxServiceFactory"
    />
    is mandatory

Travailler dans l’”IT” est gratifiant

Wednesday, August 22nd, 2007

Si vous travaillez dans l’IT (Technologie de l’Information), vous vous inscrivez dans un grand mouvement général. Vous devenez un rouage essentiel de l’économie ou plutôt de la compétitivité de l’économie.

Un des objectifs pathologiques de la civilisation occidentale est d’en vouloir toujours plus. En faisant du bon travail, on permet en particulier à nos utilisateurs d’être plus efficaces dans leur tâches quotidiennes. Leur productivité étant améliorée, ils peuvent en faire plus dans le même intervalle de temps. Cette contribution à l’augmentation de la productivité est une des gratifications que l’on peut retirer en travaillant dans l’IT.

D’autre part, la caractéristique “molle” du logiciel (software) en fait une matière flexible dont l’efficacité de la forme finale dépend entièrement de la créativité et de l’efficacité des concepteurs et des réalisateurs. Le logiciel a ce grand pouvoir de créer des marchés. Sun met en place une spécification J2EE et c’est un marché de composants logiciel qui voit le jour (même si cette vision idéale ne s’est pas tout à fait réalisée), Linus Torvals parvient à fédérer une communauté de développeurs autour d’un système d’exploitation libre et c’est un marché de distributions Linux, solutions d’hébergement qui voit le jour. L’innovation dans ce milieu permet réellement de répondre ou même de créer des besoins. C’est une des autres raisons pour lesquelles je trouve ce business si intéressant et motivant.

Hibernate4gwt : 4 mois plus tard

Monday, August 13th, 2007

(3 petit pas dans l’Open-Source)

Un petit billet un peu moins technique de d’habitude sur mes premiers pas dans le monde de l’Open-Source.
C’est donc avec insouciance que je lançais à la fin avril hibernate4gwt, petite librairie de niche prenant en charge la cohabitation de deux formidables librairies à fort caractère : Hibernate (sa persistance, sa transparence… et ses proxies !) et GWT (sa simplicité, sa souplesse… et son JavaScript !).

Première surprise : on ne dépose pas un projet comme ça sur SourceForge ! Il faut avant tout en faire la demande, exposer le but de son projet, gentiment, poliment et en anglais.

Ensuite, il faut document, packager, tester. Mine de rien, cela force un peu à organiser son travail, à le formaliser d’avantage que juste un bout de code dans son coin. Au final, j’estime passer près de la moitié du temps total sur une release à ces aspects non directement productifs.

Deuxième enseignement : cela prend du temps, beaucoup de temps. Outre le travail de développement, il faut faire un peu de pub sur les groupes de discussions, surveiller les topics pour trouver ceux que votre librairie peut solutionner, répondre aux questions posées sur le forum du projet, etc…

Troisième enseignement : c’est gratifiant D J’avoue que quelques mots d’encouragement, postés à la fin d’un message, un simple « thanks » me remplit de contentement. Le simple fait de savoir que des gens à travers le monde utilisent le fruit de mon labeur, que celui-ci leur évite les soucis que j’ai eu à affronter, me conforte dans l’idée que la démarche est la bonne. Et puis, j’adore lire des messages de gens dont j’ignore la nationalité du prénom

Enfin, il y a la satisfaction de poster une release dont vous êtes fier. La dernière version d’hibernate4gwt commence à ressembler à ce que j’avais en tête il y a quelques mois : transparente et légère. En mode Java 1.4, les services GWT doivent juste hériter de HibernateRemoteService pour fonctionner. Pas d’autre impact sur le code 
J’ai également rajouté le support d’objets du Domaine Java5, la demande à ce sujet étant forte (tout comme l’attente du support natif par GWT) en essayant de rester là aussi le moins intrusif possible (pas de fichier de mapping Dozer, qui d’après les retours d’expérience que j’ai, ressemblent plus à une plaie qu’à une solution).

J’ai encore un peu de pain sur la planche (supprimer les derniers héritages techniques !), mais après les efforts que m’ont demandé la dernière release, je vais faire une petite pause… le temps d’écrire un ou deux articles que j’avais promis à developpez.com (non Ricky, je n’ai pas oublié ;-) ) et de finir « Jonathan Strange et Mr. Norrell », un roman aussi prometteur qu’épais D

Stay tuned !

Twitter Viewer in WPF

Sunday, August 12th, 2007

I just finished the first version of the "twitter viewer" in C# with WPF. I’ve some
layout modifications to be done but the application is ready.

Download the source (Visual Studio 2008 beta 2)


Download the application (unzip and launch the .exe file)

Some screenshots :


first window

when the user clicks on an hyperlink : 


when a hyperlink is clicked

the settings page, username and password for the first version :


settings page

Gwt and Maven2

Tuesday, August 7th, 2007

Trying to use Maven2 to build a GWT project, here is the simplest pom.xml I came up with, starting from Xavier’s

The project can be tested in debug mode with mvn gwt:gwt. It is tested in deployed mode with mvn jetty:run-war

Don’t forget to provide the gwt-user.jar in src/main/webapp/WEB-INF/lib.

Code legend:
Blue parts depend on your project and installation path.
Red part is only needed on a Mac.
Green part makes it easier to use the Jetty plugin.

<project>
  <properties>
    <google.webtoolkit.home>
    /Users/david/Applications/java/gwt-mac-1.4.10/
    </google.webtoolkit.home>
    <google.webtoolkit.extrajvmargs>
    -XstartOnFirstThread
    </google.webtoolkit.extrajvmargs>
  </properties>

  <repositories>
      <repository>
          <id>gwt-maven</id>
          <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo</url>
      </repository>
  </repositories>

  <pluginRepositories>
      <pluginRepository>
          <id>gwt-maven</id>
          <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo</url>
      </pluginRepository>
  </pluginRepositories>

  <build>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>com.totsp.gwt</groupId>
        <artifactId>maven-googlewebtoolkit2-plugin</artifactId>
        <version>1.5.1</version>
        <configuration>
            <logLevel>ERROR</logLevel>
            <runTarget>com.valtech.planning.Planning/JnfPage.html</runTarget>
            <compileTarget>com.valtech.planning.Planning</compileTarget>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                </goals>
            </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt-user</artifactId>
        <version>1.4.10</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt-servlet</artifactId>
        <version>1.4.10</version>
    </dependency>
  </dependencies>
</project>

Spring and GWT integration

Tuesday, August 7th, 2007

Googling for ways to integrate GWT with Spring, I didn’t find any simple solution.

Here is what I need :

  • GWT RPC services should be Spring beans.
  • They should be POJOs NOT extending RemoteServiceServlet.
  • Mapping between Servlet paths and beans should be straightforward.

Here is what I came up with :

  • It’s a very simple Servlet that receives every RPC request.
  • It then gets a Spring bean by the name of the Servlet path used for the call.
  • The method call to the bean is done with reflection.

public class SpringDispatchService extends RemoteServiceServlet {
    private final ClassPathXmlApplicationContext context;

    public SpringDispatchServiceImpl() {
        context=new ClassPathXmlApplicationContext(”beans.xml”);
    }

    public String processCall(String payload)
        throws SerializationException {
        try {
            Object target=context.getBean(getServletName());

            RPCRequest rpcRequest=RPC.decodeRequest(
                payload,target.getClass());
            
            Method method=rpcRequest.getMethod();
            Object[] params=rpcRequest.getParameters();

            Object result=method.invoke(target,params);
            
            return RPC.encodeResponseForSuccess(method,result);
        } catch(Throwable ex) {
            return RPC.encodeResponseForFailure(null,ex);
        }
    }
}