Archive pour le ‘Java’ catégorie

JSF 2.0, enfin correct !

18 avril 2010 par Florent Garin

Voila quelques mois maintenant sortait dans sa version finalisée la spécification Java EE 6.
Dans la foulée la version 3 de glassfish était mise à disposition.

Globalement, la plateforme va vers plus de modularité et de simplicité avec notamment la généralisation des annotations ou encore l’apparition des profils qui servent à regrouper les API Java EE en plusieurs familles. Pour l’instant, il n’existe que deux profils, le profil complet et le profil Web.

Java EE a clairement atteint aujourd’hui l’âge de la maturité, le modèle de développement standard Java pour les applications d’entreprises n’a plus de véritables faiblesses comme par le passé avec les abominables EJB2. Malgré tout, parmi les nombreuses briques définies par la spécification, il en reste une que les développeurs auront tendance à substituer par une alternative open source ; je pense à JSF.

JSF n’a jamais été le framework brillant devant lequel on tombe en émerveillement le jour où on le découvre. Il n’a pas l’étoffe d’un Struts qui au début des années 2000 structura en MVC nos applications web ni la souplesse de Spring Ioc, la puissance de Spring AOP ou encore la simplicité de GWT. Toutefois la version 2 efface les principaux reproches qui étaient faits au framework en apportant :

  • Support de la méthode HTTP GET qui permet de faire des URLs « bookmarkable »
  • Support d’AJAX avec le rendu partiel de la vue
  • Moteur de templating
  • Navigation implicite entre les pages (<navigation-rules> n’est plus obligatoire)
  • Facelets préféré aux JSP

Ainsi aujourd’hui, il est possible de choisir JSF 2 pour implémenter la couche de présentation d’une application web sans forcément faire une erreur !

Bookmark and Share

Portail Liferay avec GWT intégré en SOA pour Pierre et Vacances

10 février 2010 par Eric Descargues

Aujourd’hui je viens vous faire partager une très belle expérience projet. Je vous parlerai donc d’un projet que nous avons réalisé pour notre client Pierre et Vacances, qui a su nous faire confiance jusqu’au bout pour le développement et l’infogérance de son extranet commercial.

Faire des choix en matière d’architecture logiciel en 2010 peut être un exercice difficile, c’est pourquoi l’approche de DocDoku en matière de choix techniques est basée sur les principes suivants :

  • pragmatisme, dans le choix des langages et des technologies,
  • ouverture d’esprit, nous effectuons une veille technologique permanente,
  • mise en contexte, chaque problème étant différent, les réponses à apporter doivent l’être également,
  • industrialisation, il ne s’agit pas de s’emparer de la toute dernière nouveauté mais de bâtir des solutions robustes, matures et maintenables,
  • respect des standards établis, pour garantir la pérennité des applications, et maximiser l’investissement consenti par nos clients, nous nous appuyons sur les standards unanimement reconnus.

Dans le cadre de l’extranet commercial développé pour Pierre et Vacances, les grands principes architecturaux retenus ont été les suivants :

  • utilisation du composant portail open source Liferay permettant un gain de productivité certain en particulier sur les modules génériques (droits d’accès, profils utilisateurs, agenda, publication de news…) mais respectant également la JSR 286, norme de communication entre le portail et les applications qui y sont hébergées, supportée par de nombreux éditeurs (IBM, Sun, Oracle, RedHat). Ceci permet de surcroît de limiter notre dépendance vis-à-vis d’une solution portail en particulier.
  • développement d’une architecture en couches permettant notamment de découpler les composants les uns des autres et de les faire évoluer indépendamment.  Une séparation en couches permet d’adapter en effet l’architecture physique en fonction des besoins de distribution pour une bonne capacité à monter en charge.  Une architecture n-Tiers en 4 couches distinctes a été choisie :
    • La couche d’accès aux données avec JPA-Hibernate dont le rôle est la connexion à la base de données, l’exécution des requêtes ou l’appel des procédures stockées.
    • La couche de service EJB3 et JAX-WS-Metro, ensemble des règles métiers et processus de l’application. Cette couche sera implémentée en Java via des composants transactionnels.
    • La couche métier POJO qui constitue le diagramme de classes des entités (le modèle objet).
    • La couche de présentation avec GWT et Portlet Liferay : l’interface utilisateur affiche les résultats traités par la couche métier.  Ici le framework Ajax GWT a été choisi pour à la fois offrir une ergonomie poussée et une forte maintenabilité.
  • mise en place d’une architecture de type SOA pour pouvoir exposer de façon universelle les fonctions de l’extranet pour les futures applications du SI.

Tout ceci est en production évidemment depuis la fin octobre 2009.

Agilement.

Bookmark and Share

La référence sur GWT 2

25 janvier 2010 par Florent Garin

J’ai eu le plaisir il y a quelques jours de recevoir, de la main même de l’auteur à l’occasion d’un déjeuner, le livre Programmation GWT 2.

J’ai préféré attendre d’avoir bien parcouru le livre avant d’écrire ce billet. J’aime autant le dire tout de suite : ce livre est LA référence sur GWT 2. Tout y est : les incontournables services RPC, l’intégration JEE, l’UiBinder, la communication avec le monde JavaScript mais aussi les Designs Patterns MVC (Model View Controller) ou MVP (Model View Presenter).

Au niveau de l’approche, la grande force du livre de Sami Jaber est qu’il est didactique et pointu à la fois, il convient donc aussi bien aux débutants qui veulent plonger dans le monde AJAX avec GWT qu’aux développeurs chevronnés. Un signe qui ne trompe pas sur la qualité de l’ouvrage : nos consultants qui ont près de 2 ans d’expériences sur GWT se l’arrachent !

Bookmark and Share

Le cache d’entités JPA

22 janvier 2010 par Florent Garin

Si le recours à un ORM (Object-Relational Mapping) permet des gains de productivité et facilite la maintenance des applications, ce type de framework introduit néanmoins des problématiques nouvelles, qui, pour être évitées, exigent une très bonne connaissance des mécanismes internes au moteur de mapping.

Parmi ces difficultés classiques, on peut citer la gestion du cache d’objets.

La validation finale de la spécification de JEE 1.6 (JSR 316) qui inclut la version 2 de JPA, intégrant des évolutions appréciables en matière de prise en compte du cache, est l’occasion de revenir ici un peu sur le sujet.

En réalité les ORM possèdent deux caches distincts :

jpa_caches

Cache de premier niveau (L1)

Le cache de premier niveau est rattaché à l’objet EntityManager, il s’agit en fait du « persistence context » qui lui est associé. Pour rappel, c’est à partir d’une instance d’EntityManager que les entités (les objets persistés en base de données) sont créés, récupérés ou encore supprimés. La classe EntityManager est définie par l’API standard JPA, elle est l’équivalente de la classe Session dans l’API native Hibernate.

Le contexte de persistance regroupe un ensemble d’entités en garantissant que pour une même entité il n’y aura qu’une seule instance d’objet. En prenant garde à ne pas dupliquer les objets de même identité, le contexte de persistance agit donc comme un cache d’objets : les recherches, qu’elles soient faites au travers d’une Query ou avec la méthode find(Class<T> entityClass, Object primaryKey), retourneront toujours les mêmes instances d’objets, piochées dans le cache, pour matérialiser un même enregistrement en base. Le contexte de persistance est lié à la transaction en cours, il sera vidé à la conclusion de celle-ci.

Le fonctionnement du contexte de persistance qui vient d’être décrit est celui qui est le plus couramment employé, il s’agit du mode PersistenceContextType.TRANSACTION. Néanmoins, il existe un autre mode dit « étendu », le paramétrage du contexte de persistance se fait dans le code Java, lors de l’injection de l’EntityManager :

@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;

Dans cette configuration, le PersistenceContext n’aura pas une durée de vie corrélée à la transaction mais au Stateful Session Bean dans lequel il est déclaré. Ainsi, le cache d’objets sera maintenu sur plusieurs transactions à la base de données. Ce type de contexte de persistance peut par exemple être utilisé pour alimenter en données une page web requêtant en AJAX.

Cache de deuxième niveau (L2)

En dessous de ce cache placé sous la direction des EntityManagers se trouve un autre cache dit de second niveau. Ce cache est global à la JVM ou plus exactement à l’EntityManagerFactory. Il peut aussi être configuré au niveau cluster, dans ce cas le cache sera répliqué sur chaque JVM. Le cache de second niveau est donc partagé entre les EntityManagers qui iront l’interroger, si l’entité recherché n’est pas présent dans leur propre contexte de persistance, avant de se résigner à taper dans la base de données.

Si les règles régissant le cache de premier niveau sont relativement limpides, celles gouvernant le cache de 2ème niveau le sont un peu moins et le développeur peut légitimement se poser de nombreuses questions :

  • Quelle est la durée de rétention des objets dans le cache ?
  • Que se passe t-il si la base de données est modifiée en dehors de l’application JPA ?
  • Peut-on contrôler par configuration ou par du code ce cache ?

De manière générale, les réponses à ces questions dépendent avant tout de l’implémentation JPA choisie. D’ailleurs, si EclipseLink et TopLink activent par défaut un cache de second niveau ce n’est pas le cas d’Hibernate. Ce dernier a par contre été très tôt pensé de façon modulaire et accepte divers « cache provider » comme EhCache, OS Cache ou encore JBoss Cache. Chaque système de cache vient avec ses options et ses fichiers de paramétrages, il est souvent possible de les spécifier dans le fichier persistence.xml entre la balise <properties> ou dans le code par la méthode Query.setHint(String hintName, Object value).

En ce qui concerne les changements opérés dans la base sans passer par les couches de persistance de l’ORM ; là le résultat est identique quelque soit le framework : le cache de niveau 2 se retrouve obsolète et cela tant que l’entité en question ne sera pas rechargé. La plupart des caches d’objets utilisant des SoftReferences ou des WeakReferences, l’éviction de l’objet se produira à un moment indéterminé, au gré des pérégrinations du garbage collector. Pour ceux ne pouvant se contenter du caractère aléatoire des références faibles et qui veulent expressément déclencher le rafraichissement des données la classe EntityManager propose heureusement la méthode refresh qui s’utilise habituellement ainsi :

MonEntity e = em.find(MonEntity.class, id);
try {
em.refresh(e);
} catch(EntityNotFoundException ex){
e = null;
}

Toutefois, ce n’est que depuis la version 2 de JPA que le cache L2 est officiellement mentionné dans la spécification. Dans cette API, une classe Cache accompagnée de ses méthodes « evict » a fait son apparition et certains points de configuration ont été standardisés.

En conclusion

Il y aurait encore beaucoup à dire sur les caches d’entités et plusieurs billets seraient nécessaires, c’est pourquoi je conclurai simplement en invitant tous les développeurs et architectes à regarder sous le capon de leur framework de persistance et à ne pas se laisser « endormir » par la simplicité trompeuse de l’API JPA.

Bookmark and Share

Installation de Glassfish sous linux

31 octobre 2008 par Florent Garin

Comment installer glassfish en tant que service sous linux ?
Contrairement à Windows, installer n’importe quelle application sous forme de service n’est pas très compliqué sous un OS de type Unix.
Le billet suivant explique clairement la démarche à adopter.

Malheureusement, un petit hic survient quand on souhaite faire tourner glassfish sur le port 80.
Sous linux, il est purement et simplement impossible de configurer glassfish sur le port 80 si celui-ci ne tourne pas avec le compte root ce qui est toujours regrettable pour des raisons évidentes de sécurité.

Confronté à ce problème, j’ai tout d’abord envisagé (comme à la grande époque de Tomcat) de positionner un apache écoutant sur le port 80 devant glassfish qui serait lui sur le 8080. Je me suis aussi dit qu’au passage grâce à apache je pourrais faire du « Virtual Hosting » et utiliser les quelques applications php dont nous avons besoin.

Cependant, un tour sur internet, a vite calmé mes ardeurs. Les nombreux commentaires de ce post n’encouragent pas à la confiance.

Finalement, après mûre réflexion, j’ai choisi de laisser glassfish s’exécuter avec le compte root. Hormis cet inconvénient qui je l’espère ne tardera pas à être corrigé, les fonctionnalités natives de « Virtual Hosting » de glassfish, l’architecture modulaire OSGi de la version 3 et le repositionnement de la JVM comme une plateforme multi-langage me font penser que glassfish pourrait bien également concurrencer apache !

Bookmark and Share

JavaOne

23 mai 2008 par Florent Garin

JavaOne s’est déroulé au début du mois à San Francisco. Cette conférence a mis à l’honneur Glassfish, le serveur d’application JavaEE Open Source de Sun, avec le lancement du GlassFish Technology Partner Program dont nous faisons partie. Ce partenariat matérialise notre expertise de la plateforme Java en général et de Glassfish en particulier.
L’autre technologie majeure présentée à JavaOne fut JavaFX. Beaucoup pensent que JavaFX arrive trop tard et qu’il ne pourra pas trouver sa place face à des concurrents comme Flash notamment. Pour ma part, je suis convaincu du contraire.
Le succès de Flash est éclatant et cela est largement justifié : très grande facilité de déploiement, temps de démarrage à froid impressionnant, qualité des outils de production, des codecs vidéo…
Néanmoins, dans le cadre du développement d’une application d’entreprise disposer d’un langage aussi riche que Java sur le client, surtout s’il est aussi utilisé sur le serveur, est un énorme avantage. Si JavaFX continue de progresser et que la version finale de Java SE 6 Update 10 tient toutes ses promesses, je recommanderai JavaFX et non Flex à nos clients industriels.

Bookmark and Share

Le futur de JSF

19 janvier 2008 par Florent Garin

JSF ne s’est pas encore, gardons espoir, véritablement imposé comme LE framework web java.
La première des raisons est sans doute sa complexité. Essayez d’expliquer à un féru de php son Unified Expression Language pour vous en convaincre.
Deuxièmement, la spécification de JSF ne définit qu’une palette de composants graphiques très limité. Dans un projet réel, ceux-ci suffisent rarement ; il faut alors se tourner vers des extensions propriétaires, perdant du même coup la neutralité vis à vis de l’implémentation de JSF.
Enfin, le dernier point problématique est la difficulté d’intégration de JSF et d’AJAX.
Il est en effet compliqué de mixer l’approche purement « server-side » de JSF avec une logique AJAX où une partie du MVC est directement implémentée sur le client en javascript.
La jsr 314, celle de JSF 2.0, devrait remédier à cela en apportant des modifications importantes au cycle de vie notamment le parcours partiel de l’arbre des widgets.
Cela va dans le bon sens, néanmoins, il n’en demeurera pas moins que de plus en plus la logique cliente se trouvera portée par du code AJAX, laissant à JSF la gestion des tâches annexes.
Si JSF 2 marquera indéniablement l’acceptation d’AJAX par Java EE, ne faudrait-il cependant pas aller plus loin, en d’autre terme ; pour préserver sa pertinence, JSF 3 ne devra t-il pas être un framework en bonne partie javascript ?

Bookmark and Share

Upload et download de fichiers avec un web service

18 novembre 2007 par Florent Garin

Comment faire pour « uploader » et « downloader » un fichier vers et depuis un web service ?
Très simple me diriez-vous et depuis longtemps. Il suffit d’utiliser SAAJ (SOAP with Attachments API for Java) ou encore mieux MTOM (Message Transmission Optimization Mechanism) pour bénéficier de l’assurance d’une compatibilité .Net/Java optimale.
En théorie cela semble simple mais quand on passe à la pratique, dans le contexte d’une application réelle, les choses se compliquent bigrement, en tout cas en ce qui concerne l’implémentation de JAXWS.
La plus grosse lacune de JAXWS au niveau MTOM est son incapacité à transmettre les données binaires sous forme de flux de bout en bout. Comme expliqué ici il est bien possible d’indiquer au client d’utiliser le mode « streaming » mais côté serveur rien à faire, l’ensemble des octets constituant le fichier est monté en mémoire.
Même côté client, JAXWS mériterait quelques améliorations. En effet il n’est pas possible de superviser la progression du transfert, de plus le mode « streaming » opère en appelant HttpURLConnection.setChunkedStreamingMode sur la connexion sous-jacente ce qui pose des problèmes car de nombreux serveurs web ou proxy ne supportent pas ce mode. Il serait intéressant que JAXWS calcule la taille du contenu à poster et invoque plutôt la méthode HttpURLConnection.setFixedLengthStreamingMode.

Conclusion de tout cela, pour uploader un fichier en http rien ne vaut d’utiliser directement HttpURLConnection et d’implémenter le basique et standard upload multipart/form-data.

Bookmark and Share

JAXB 2.1 avec Java 6

3 octobre 2007 par Florent Garin

Le choix d’inclure (précipitamment ?) JAXB au jdk 1.6 a des conséquences fâcheuses. En effet, la version de l’API intégrée au jdk est la 2.0, et très souvent il est indispensable de passer à la 2.1 pour bénéficier de fonctionnalités comme par exemple l’annotation XmlSeeAlso.
Pas de problème me diriez-vous, il suffit de rajouter -Djava.endorsed.dirs=jaxb-api.jar à la ligne de commande de java pour « patcher » le jdk.
Malheureusement, si votre application est distribuée au travers de Java Web Start, le mécanisme de classes « endorsed » ne fonctionne pas.
Pour s’en sortir une seule solution faire des acrobaties avec les ClassLoaders. Ce billet explique cela en détail. Dans le cadre d’une application swing, il faudra bien penser à appeler la méthode setContextClassLoader également sur le thread gérant les événements système comme ceci :
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
eq.invokeAndWait(new Runnable() {


public void run() {


Thread.currentThread().setContextClassLoader(modifiedClassLoader);

}


});

C’est du sport mais ça marche !

Bookmark and Share

web services avec JAX-WS

17 juillet 2007 par Florent Garin

Initialement le client (java web start) DocDoku communiquait au serveur (composants ejb) à l’aide du protocole corba IIOP.
Malheureusement, à tort ou à raison, les proxies http sont souvent le passage obligé pour accéder à internet dans de nombreuses sociétés.
Nous avons donc décidé de passer aux web services. Aujourd’hui cette migration est terminée mais je dois avouer que ce fut plus compliqué que prévu. Voici un bref retour d’expérience :

Au niveau sécurité, les options sont nombreuses, nous avons néanmoins opté, par prudence, pour la simplicité : authentification basic sur du SSL.
Ce poste explique ceci en détails.

Ensuite, la grande difficulté a été d’utiliser nos POJOs sur le client et le serveur sans passer par une couche d’objets intermédiaires mappant le wsdl.
Etrangement, aucun tutorial de Sun n’explique clairement cela et les assistants de netbeans génèrent invariablement cette couche d’objets (avec la commande wsimport) même si le webservice a été créé à partir d’une interface SEI (Service Endpoint Interface).
Sous les conseils d’Alexis, j’ai filé un bug chez netbeans.
Enfin, la solution est la suivante, il faut donc définir une interface pour l’EJB avec endpoint webservice et non simplement annoter les méthodes avec @WebMethod.
Ensuite, importer les classes produites par wsgen également sur le client.
Enfin, récupérer le web service Port par javax.xml.ws.Service.getPort(Class<T> serviceEndpointInterface).

Bookmark and Share

JSR-170 (Java Content Repository)

16 mai 2007 par Florent Garin

La JSR-170 (ou JCR) vise à définir une API standard pour accéder aux « content repositories ». Tous dépôts conformes à cette spec présentent une vue hiérarchique des données et méta-données, offrent des services de versioning, d’import-export XML, ainsi qu’une gestion d’évènement permettant d’être notifié en temps réel des modifications. Les JCR sont également interrogeables au travers d’XPath.
Certains parlent de la JSR-170 comme du jdbc des CMS (Content Management System).
La question est donc de savoir si les JCR arriveront à s’imposer comme briques de bases de tous CMS qui se respectent. La réponse n’est pas évidente.
La JSR-170 est d’une manière ou d’une autre en concurrence avec JPA (Java Persistence API) ou plus généralement avec les ORM. La talon d’achille des JCR est, pour l’instant, l’absence d’outil de mapping Objet/JCR. Il existe bien un embryon de projet mais rien de comparable à Hibernate ou Toplink. Du coup, les gains de productivité dus aux services supplémentaires disponibles pourraient être perdus à développer le mapping objet.
Cependant, les choses pourraient changer assez rapidement, et des outils autour des JCR pourraient apparaître.
Enfin, on peut noter que la JSR-283 est sur les rails, elle corrige certains défauts de sa grande sœur ; par exemple, elle rajoute un type de node spécifique pour les metadata ce qui manque cruellement à la JSR-170.

Bookmark and Share

Problème d’accents dans les applications web

20 février 2007 par Florent Garin

La gestion des accents dans les applications web n’est toujours pas, quelque chose de simple qui marche sans qu’on s’en préoccupe !

Quand le navigateur soumet un formulaire, il poste les valeurs des champs en utilisant le même encodage que celui de la page html d’origine.
Dans une jsp, pour spécifier au moteur de servlet l’encodage du flux de la réponse http et donc de la page html générée, nous avons recours à la directive @page comme ceci :

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

Renseigner l’attribut contentType a deux effets ; premièrement d’encoder la réponse dans le format choisi, deuxièmement de l’indiquer au client, par le biais d’une variable dans l’entête http.
Il est cependant intéressant de mentionner cet encodage directement dans la page html. Ainsi, elle pourrait être parsée à nouveau correctement ; par exemple ré-affichée après avoir été sauvegardée sur le disque. Il est donc plus prudent d’ajouter la balise suivante entre les tags head :

<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>

Enfin, nous pouvons remarquer que la directive @page support également un attribut « pageEncoding ». Cet attribut précise simplement l’encodage de la page jsp elle même. Cette information sert au moment de la compilation de la jsp pour produire la servlet correspondante. Cette valeur dépend de l’IDE, NetBeans (dans sa configuration initiale) sauvegarde les fichiers en utilisant l’encodage par défaut de l’OS : CP-1252 pour Windows et UTF-8 pour linux.

Côté serveur, il faut décoder les paramètres de la requête http avec le même encodage que celui qui a servi à la transmission du formulaire.
Mais quel est celui utilisé quand on appelle HttpServletRequest.getParameter(name) ?
En théorie, à l’instar de ce que fait le serveur dans sa réponse, le navigateur est censé communiquer au serveur, dans l’entête http, l’encodage employé.
Malheureusement, dans la pratique ni Internet Explorer ni Firefox ne le fait. Pour s’en convaincre il suffit d’appeller HttpServletRequest.getCharacterEncoding() et constater que la méthode retourne null.
La conséquence de cela est que si l’object HttpServletRequest ne connait pas l’encodage dont s’est servi le client, il en utilisera un par défaut. Ce paramétrage est propre au serveur d’application, Glassfish par exemple, utilise l’ISO-8859-1. Il est évidemment possible de le changer.
Il est aussi possible de modifier le « CharacterEncoding » programmatiquement grâce à la méthode setCharacterEncoding(value). Si l’application est développée à l’aide d’un framework web (JSF, struts…), il faudra définir un HttpServletFilter pour le faire avant que les couches du framework n’accèdent à la requête.

Bookmark and Share

NSIS installeur avec Java Web Start

6 janvier 2007 par Florent Garin

Le client riche DocDoku est une application déployée à l’aide de Java WebStart. Cette technologie nous donne entière satisfaction et nos utilisateurs bénéficient ainsi du système de mise à jour automatique. Cependant, JWS a le léger inconvénient de nécessiter un environnement Java déjà installé.
Nous avons donc créé un setup.exe, avec NSIS. NSIS est un installeur open source uniquement pour Windows. Son utilisation à base de scripts sans assistant ni même interface graphique peut sembler un peu rugueuse mais on finit par s’y faire et apprécier la souplesse que cela procure.
Notre installeur devait être capable de :

  1. vérifier dans le registre la présence d’une JVM 1.5
  2. procéder à son téléchargement et son installation si besoin
  3. installer l’application DocDoku tout en maintenant le « lien » Java Web Start pour conserver la fonctionnalité de maj auto.

Voici notre script NSIS:


; Client Installer

;--------------

Name "DocDoku Client"
Caption "DocDoku Client Installer"
OutFile "docdoku.exe"

!define JRE_VERSION "1.5"
!define JRE_URL "http://dlc.sun.com/jdk/jre-1_5_0_01-windows-i586-p.exe"

Section

Call DetectJRE
ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion"
ReadRegStr $0 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$1" "JavaHome"
ExecWait "$0\bin\javaws.exe -import -silent -shortcut http://www.docdoku.com/apps/docdoku_client.jnlp" $4

StrCmp $4 0 done
MessageBox MB_OK "Failed: your Java Runtime Environment is corrupted, please uninstall it and retry"
done:

SectionEnd

Function GetJRE

MessageBox MB_OK "DocDoku uses Java 1.5, it will now \
be downloaded and installed"
StrCpy $3 "$TEMP\Java Runtime Environment.exe"
nsisdl::download /TIMEOUT=30000 ${JRE_URL} $3
Pop $R0 ;Get the return value
StrCmp $R0 "success" +3
MessageBox MB_OK "Download failed: $R0"
Quit

ExecWait $3
Delete $3
FunctionEnd

Function DetectJRE
ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \
"CurrentVersion"
StrCmp $2 "" download
StrCpy $8 ${JRE_VERSION} 1
StrCpy $9 $2 1
IntCmp $9 $8 0 download done
StrCpy $8 ${JRE_VERSION} 1 2
StrCpy $9 $2 1 2
IntCmp $9 $8 done download done

download:

Call GetJRE

done:

FunctionEnd

Seul petit défaut, nous ne disposons pas d’URL permettant de télécharger (sans aucune interaction utilisateur) le JRE 1.6 ; mais seulement le 1.5.

Bookmark and Share

EJB et les enums 1.5

30 octobre 2006 par Florent Garin

Je suis en pleine refonte de l’application collaborative en ligne DocDoku.
Je migre d’une architecture customisée fondée sur de simples services RMI de base, tournant dans la même JVM que le moteur de servlet (tomcat), vers une architecture standard JEE 1.5 supportée notamment par les EJB 3 (glassfish).
Durant ce portage, je suis tombé sur un bug assez vicieux ; l’implémentation actuelle du protocole IIOP (jdk 1.5) ne sérialise pas correctement les type « enum ». En conséquence, une comparaison de deux enumérations dont l’une a été envoyée par le client, d’apparence identique, échoue lamentablement !
Seule alternative, comparer leur nom…

Bookmark and Share

Open Source Java

18 mai 2006 par Florent Garin

Ca y est, Sun a annoncé officiellement, à l’occasion de la conférence JavaOne, son intention de passer Java sous licence open source !
C’est une grande nouvelle, cela devrait permettre, entre autres, aux distributions linux d’intégrer une JVM Java en standard, de corriger enfin les bugs de Swing, de faciliter le packaging des applications java en y encapsulant un JRE custom…

Je suis curieux de voir l’impacte à long terme de cette nouvelle licence ; « linux + java » va t-il devenir le couple gagnant ? java va t-il enfin décoller sur le client ?

Bookmark and Share

Authentification par formulaire en jsp

23 février 2006 par Florent Garin

La spec jsp prévoit la possibilité de définir une page html pour l’authentification en lieu et place de la popup de logging du navigateur. Pour cela, il suffit de concevoir un formulaire comme ceci :

form method="post" action="j_security">
<input type="text" name="j_username"/>
<input type="password" name="j_password"/>
</form>

Parfait, il est donc possible de personnaliser la fenêtre de logging et de la fondre dans le design général de l’application ; tout en bénéficiant d’une authentification déclarative assurée par le « container » cad le moteur de servlet.

Seulement voilà :

Comment permettre une authentification active des utilisateurs (on se logue volontairement ; on n’est pas contraint de montrer patte blanche seulement après avoir tenté d’accéder à une zone sécurisée) ?
Comment implementer une option « remember me » (l’application dispense l’utilisateur de ressaisir son login et mot de passe systématiquement) ?

C’est impossible !

Si l’on tient à ces fonctionnalités, il nous faut alors laisser tomber l’authentification par container et développer une authentification « custom » à base de ServletFilter et renoncer par la même occasion aux methodes HttpServletRequest.getRemoteUser et HttpServletRequest.isUserInRole.
Tout ceci ne facilitera pas une éventuelle intégration SSO, mais bon, quand le standard est mauvais ou incomplet…

Bookmark and Share

Java autoupdate

6 février 2006 par Florent Garin

Java bénéficie depuis le JRE (Java Runtime Environment) 1.5 d’une fonctionnalité de mis à jour automatique.
Ainsi à interval régulier (par défaut une fois par mois) le système téléchargera et installera la toute dernière version du JRE si nécessaire.
Seul « petit » hic, la version précédente n’est pas désinstallée ! C’est à l’utilisateur de le faire, s’il y pense bien sûr.
Sachant que la nouvelle politique de Sun est de délivrer ses correctifs plus fréquemment, on peut se retrouver avec 4 ou 5 JRE de près de 70Mo sur son poste alors que l’on pensait télécharger de simples patches !
Ce choix de déploiement (excessivement ?) défensif peut se comprendre en entreprise, mais si Sun veut imposer Java sur le client face à des concurrents tel que Flash il devra sans doute revoir sa copie.

Bookmark and Share

RMI et les ports

6 octobre 2005 par Florent Garin

Classiquement, pour développer un serveur RMI, nous devons :

  • Définir une interface avec l’ensemble des méthodes « remotes » (cette interface étendra java.rmi.Remote).
  • Implémenter cette interface dans une class étendant java.rmi.server.UnicastRemoteObject.
  • Enregistrer le serveur auprès d’un registre RMI (il convient d’avoir précédemment lancé la commande rmiregistry).

Au niveau du code côté client, nous devons récupérer une référence de cet objet (son stub) à l’aide de la méthode Naming.lookup(name) qui interroge le service rmiregistry.

Dans le contexte d’un réseau local, cela fonctionne sans que l’on ait vraiment besoin de se préoccuper des ports de communication. Maintenant, si l’on souhaite offrir l’accès à notre serveur aux utilisateurs se trouvant en dehors du LAN, nous devons maîtriser les ports TCP/IP ouverts par notre application pour configurer notre pare-feux et les redirections NAT.

Grâce à la commande netstat nous constatons que rmiregistry écoute le port 1099 et que notre processus java un autre port qui varie à chaque lancement. Le port 1099 est le port par défaut du registre RMI. Il est toutefois possible d’en spécifier un autre en paramètre de la commande rmiregistry. Le second port correspond au port de notre propre service. Toujours grâce à la commande netstat nous remarquons que notre client se connecte une première fois au rmiregistry (sur le port 1099) puis ne dialogue plus qu’à notre application au travers du second port.

Tout ceci ne nous arrange pas, comment définir des règles sur le « router/firewall » si le second port change à chaque redémarrage ?
Un petit tour dans la javadoc nous apprend que le constructeur de la class UnicastRemoteObject admet pour paramètre le port d’écoute. Parfait, nous ajoutons donc super(port) dans le constructeur de notre serveur.

Cependant, nous ne pouvons choisir 1099 car ce port est déjà utilisé par le processus rmiregistry. Heureusement, il y a une solution, nous n’exécuterons plus la commande rmiregistry ; nous créerons directement le registre RMI dans la JVM de notre serveur au moyen de l’instruction LocateRegistry.createRegistry(pPort).

Ainsi nous arrivons à nos fins, notre application ne monopolise qu’un unique port connu et paramétrable.

Bookmark and Share

Harmony

30 août 2005 par Florent Garin

Voilà quelques mois, le projet harmony a officiellement démarré à la fondation Apache.
Ce projet a pour but d’offrir une implémentation open source des spécifications de « Java 2 Platform, Standard Edition ».
Concrètement, il s’agit de développer l’environnement d’exécution, les APIs, le compilateur et l’ensemble des outils standards.
Certains pensent que ce projet est sans intérêt car l’implémentation de Sun, bien que sous licence propriétaire, est gratuite.
Je ne pense pas comme cela. Je vois trois avantages majeurs à bénéficier d’un environnement java open source :

  • Plus de plateformes supportées

Java est un langage multi-plateforme. Cependant Sun ne fournit « que » trois verions de son dernier JRE (Java Runtime Environment) 1.5 ; une pour MS Windows (x86 et AMD64), une pour Solaris (SPARC, x86 et AMD64) et une pour linux (x86 et AMD64).
Apple met aussi à disposition de ses clients la dernière JVM pour MacOS (processeur PPC).
Mais que faire si l’on souhaite installer une JVM sur un serveur linux PPC ? Se tourner vers la distribution d’IBM et se contenter de la version 1.4.2.
Pire encore, si l’on utilise l’OS freeBSD il faut se satisfaire d’une version 1.3 qui n’a pas passé les tests de conformité.
Que dire des nouvelles consoles de jeux ; Xbox360, playstation3 et nintendo révolution, aucune d’entre elles ne peut, pour l’instant, faire tourner java.
Le slogan « Write once run everywhere » de java n’est aujourd’hui que partiellement vrai. Le projet Harmony s’il aboutit pourrait changer la donne.

  • Accélérer la correction des bugs

Certaines anomalies concernant l’API Swing (interface graphique) sont enregistrés dans la base de bugs de Sun depuis plus de 7 ans…
Avec une JVM open source, la communauté des développeurs ne serait plus dépendante d’un éditeur et les « bug fix » se feraient certainement plus rapidement.

  • Distribution du JRE plus aisée

Les JRE de Sun bien qu’étant librement téléchargeable n’en demeurent pas moins propriétaire et leur distribution soumise à de nombreuses contraintes. Il n’est pas possible par exemple de livrer une application java avec un JRE allégé des classes non utilisées. Il n’est pas non plus possible d’intégrer le JRE dans les distribs linux (programmes sous licence GPL et propriétaire ne peuvent cohabiter sur le même media).
Interdit aussi de repackager le JRE sous forme de package debian ou rpm et profiter ainsi des mis à jour en ligne du système (l’équivalent, en mieux ;=), du Windows update).
Une fois de plus, un projet comme harmony lèverait ces limitations.

Bookmark and Share

Non-blocking I/O

18 juillet 2005 par Florent Garin

« New I/O » is a feature appeared with jdk 1.4, implemented in package java.nio.channels.

This feature allows to define multiplexed Non-blocking I/O operations. Thus, on the server side, it’s not required to spawn a new thread each time a client connects. It’s the responsibility of the application to create a working thread.

Below, a simple example extracted from the NetCopyPaste program in start() method of org.florentgarin.netcopypaste.network.SocketListener class. It’s probably overkill but NetCopyPaste has been voluntarily written using all the latest technologies.

Selector selector = Selector.open();

//we only register read operation
_channel.register(selector, SelectionKey.OP_READ);

//selector.select() method blocks until a registered operation occurs.
//Thus, it's a infinite loop
while (selector.select() > 0 ) {

Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iti = readyKeys.iterator();

while (iti.hasNext()) {

SelectionKey key = iti.next();
iti.remove();
if (key.isReadable()) {

//we can have created a thread to do the job but in our case
//there's not so much to do, so we have kept our code simple.
MessageEvent messageEvent = readMessage(key);
fireMessage(messageEvent);

}


}


}

Most application servers such as tomcat has been rewritten to take advantage of the nio packages. If your application has some performance or memory usage issues, you must consider refactoring your code.

Bookmark and Share