Category: Astuces

tomcat-maven-plugin : debug

By , 29/04/2011

Le plugin tomcat de Maven est très pratique lors du développement d’une application web. Voici comment le configurer :

 <!-- Embedded Tomcat (package tomcat:run) -->
 <!-- Standalone Tomcat (package tomcat:deploy) -->
 <plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>tomcat-maven-plugin</artifactId>
   <configuration>
     <path>/${project.build.finalName}</path>
     <!-- Embedded port -->
     <port>9090</port>
   </configuration>
 </plugin>

Le plugin démarre le serveur dans la sa propre JVM. Pour pouvoir débuger votre application, il faut donc uniquement démarrer Maven avec l’option de debug comme cela :

mvn tomcat:run -DXdebug -DXnoagent -Djava.compiler=NONE -DXrunjdwp:transport=dt_socket,address=3998,suspend=n,server=y

Ou bien, si vous utilisez eclipse avec le plugin m2eclipse : cliquer avec le bouton droit de votre souris sur le projet : Debug As -> Maven build … .

Java : Problème de certificat SSL

By , 04/04/2011

Lorsqu’un traitement Java fait appel à un site internet sécurisé avec le protocole HTTPS,  la JVM vérifie si le certificat SSL est validé par un organisme tiers. Pour cela, il existe dans la JRE une librairie avec des certificats de confiance : $JAVA_HOME/jre/lib/security/cacerts. Voici une erreur possible lors d’un échange entre un client et un serveur SSL :

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Lorsque cette erreur arrive, cela veut dire que le certificat délivré par le serveur n’est pas vérifié par une autorité tierce reconnue par la JVM. Pour résoudre ce problème, il y a deux solutions :

  • Annuler la vérification du certificat
  • Ajouter le certificat à la liste des certificats reconnus de la JVM

Annuler la vérification des certificats

Je vous propose d’annuler la vérification de façon programmatique. Pour cela, il faut créer un “TrustManager” qui ne va rien vérifier puis l’utiliser dans le contexte de session SSL.

// Créer un "trust manager" qui ne valide pas les certificats
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Utiliser le manager qui ne valide pas les certificat
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}

// Accéder à la page en HTTPS
try {
    URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}

Je rappelle qu’en supprimant l’étape de vérification, le client devient sensible aux attaques du type man-in-the-middle. Je déconseille donc cette solution dans le cas général.

Ajouter le nouveau certificat à la JVM

Pour ajouter le certificat dans la JVM, il faut l’exporter depuis votre navigateur. Par exemple, avec Firefox, il faut se rendre dans la fenêtre des options puis  dans le menu Avancé -> Chiffrement cliquer sur le bouton Afficher les certificats. Dans la fenêtre suivante, il est possible d’exporter un certificat.

Enfin pour importer le certificat dans la JVM il faut exécuter cette commande :

keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -file certificat.crt -alias certificat

Le mot de passe par défaut est “changeit”.

Astuce

Pour débugger une conversation SSL, il faut ajouter l’option JVM suivante : -Djavax.net.debug=all

jaxb2-maven-plugin : plusieurs exécutions successives de jaxb2:xjc

By , 11/02/2011

Dans ce ticket, je vais expliquer comment bien configurer le plugin jaxb2-maven-plugin dans le cas où l’on souhaite transformer des fichiers XSD en classes java vers des packages différents. Il faut savoir qu’avec ce plugin il n’est pas possible de définir plusieurs packages de destination dans une même exécution.

Dans l’exemple choisi, je génère deux classes Java à partir de deux fichier XSD vers deux packages différents :

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>id1</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>xjc</goal>
      </goals>
      <configuration>
        <clearOutputDir>false</clearOutputDir>
        <staleFile>${project.build.directory}/generated-sources/jaxb/.staleFlag-id1</staleFile>
        <schemaDirectory>${basedir}/src/main/resources/id1</schemaDirectory>
        <packageName>id1</packageName> <!-- The name of your generated source package -->
      </configuration>
    </execution>
    <execution>
      <id>id2</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>xjc</goal>
      </goals>
      <configuration>
        <clearOutputDir>false</clearOutputDir>
        <staleFile>${project.build.directory}/generated-sources/jaxb/.staleFlag-id2</staleFile>
        <schemaDirectory>${basedir}/src/main/resources/id2</schemaDirectory>
        <packageName>id2</packageName> <!-- The name of your generated source package -->
      </configuration>
    </execution>
  </executions>
  <dependencies>
     <dependency>
       <groupId>xerces</groupId>
       <artifactId>xercesImpl</artifactId>
       <version>2.8.1</version>
     </dependency>
  </dependencies>
</plugin>

A noter que pour chaque exécution :

  • Il est nécessaire d’utiliser un identifiant unique. Sinon maven n’arrivera pas à exécuter le plugin.
  • Il faut impérativement utiliser l’option staleFile pour associer un fichier différent à chaque exécution (ce fichier sert au plugin pour savoir si les classes Java sont déjà générées). Sans cela, la seconde exécution ne génèrera pas de classe Java.
  • Il faut indiquer au plugin de ne pas nettoyer le répertoire de génération avant l’exécution (option clearOutputDir à false) car c’est son comportement par défaut. Sans cela, la seconde exécution supprimera les classes générées pas la première.

Voici l’adresse de l’exemple associé : https://subversion.assembla.com/svn/everythingiswrong/tutorial-jaxb2-maven-plugin/.

jaxws-maven-plugin : générer des services SOAP à partir de plusieurs WSDL

By , 03/01/2011

Dans ce poste je vais générer des services SOAP java à partir de deux fichiers WSDL. La contrainte que je m’impose est de générer dans un même package toutes les classes java. Il faut paramétrer le plugin jaxws-maven-plugin en lui donnant un nom de package pour l’ensemble des WSDL (ou bien utiliser le même namespace pour les deux WSDL et leurs objets associés) :

<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>jaxws-maven-plugin</artifactId>
   <executions>
      <execution>
         <goals>
            <goal>wsimport</goal>
         </goals>
      </execution>
   </executions>
   <configuration>
      <packageName>com.example.myschema</packageName>
   </configuration>
...
</plugin>

Le problème c’est que le plugin génère les objets dans l’ordre de traitement des WSDL. Cela implique que la classe ObjectFactory.java qui permet d’instancier les objets issus de la génération est créée une première fois pour les objets du premier WSDL puis écrasée par la seconde génération avec les objets du second WSDL.

Pour résoudre ce problème, il est possible de mutualiser les objets des deux WSDL dans un même schéma XSD qui va englober tous les objets des deux WSDL. La première génération va toujours être écrasée par la seconde mais cette fois si, les deux générations produisent exactement les mêmes objets et l’objet ObjectFactory va pouvoir instancier tous les objets des deux WSDL.

Voici un exemple : https://subversion.assembla.com/svn/everythingiswrong/multiple-wsdl-same-package/

Rechercher les jar contenant une classe Java

By , 11/12/2010

En programmation Java il arrive de temps en temps qu’un programme tombe en erreur car il manque des classes dans le classpath d’exécution. Jusqu’à présent, je me suis toujours arrangé pour retrouver les artefacts (jar) contenant les classes manquant avec de l’expérience et surtout de la change.

Maintenant c’est fini ! Je viens de découvrir le site internet findjar. Grâce à lui, je retrouve facilement les artefacts contenant ma classe absente !

Richfaces et Ajax

By , 03/11/2010

Sur une interface web faisant des appels AJAX, il est parfois très complexe de comprendre ce qu’il se passe lors des saisies utilisateurs et des multiples rafraichissements. Les développeurs  qui utilisent Richfaces ont à leur disposition un composent JSF plus qu’intéressant depuis la version 3.0.0 : <a4j:log/>. Il affiche tout simplement les échanges entre le client et le serveur dans la page HTML résultat. Voici une possibilité d’utilisation :

<4j:log level="ALL" popup="false" width="400" height="200" />

En utilisant ce “logger”, j’ai remarqué qu’il était souvent nécessaire d’utiliser une queue AJAX dans les interfaces utilisant massivement cette technologie. Là encore, Richfaces propose un composant clé en main pour implémenter cette queue : <a4j:queue/>.

Vous pouvez retrouver ces composants dans le showroom de Richfaces : <a4j:log/> et <a4j:queue/>.

c:forEach (java.lang.OutOfMemoryError: Java heap space)

By , 04/10/2010

Il m’ait arrivé récemment d’avoir une erreur de mémoire sur une page xhtml alors que les autres interfaces de mon application fonctionnaient correctement. L’erreur provenait de mon tag <c:forEach/>. Voici la boucle provoquant le problème de mémoire :


<c:forEach value="#{myList}">
   ...
</c:forEach>

En réalité, j’avais transformé une boucle <ui:repeat/> en <c:forEach/> sans modifier le nom de l’attribut correspondant au bean sur lequel il faut faire l’itération : value pour <ui:repeat/> et items pour <c:forEach/>. Voici les deux bonnes syntaxes :


<ui:repeat value="#{myList}">
   ...
</ui:repeat>

<c:forEach items="#{myList}">
   ...
</c:forEach>

Je ne suis visiblement pas le seul à avoir eu ce problème, si vous voulez avoir plus d’information sur la cause exacte de cette exception voici comment j’ai trouvé la solution : http://wiki.foochal.org/index.php/ForEachHandler_OutOfMemoryError.

Seam : Exporter une dataTable à l’interieure d’une subview

By , 30/09/2010

Lorsqu’un développeur utilise Seam, il a à sa disposition tout un panel de composant pour l’aider à développer. Par exemple le composant dataTable Exporter permet d’exporter un tableau JSF (h:dataTable, rih:dataTable, etc.) sous la forme d’un fichier Excel. Voici la syntaxe directement récupérée de la documentation de référence de Seam :

<h:form id="theForm">
    <h:dataTable id="theDataTable" value="#{personList.personList}"
        var="person">
         ...
    </h:dataTable>
</h:form>
...
<h:commandLink
    value="Export"
    action="#{excelExporter.export('theForm:theDataTable')}" />

Lorsque la table se trouve dans une sous vue (<f:subview/>) ou tout autre composant qui joue un rôle de conteneur de nom (NamingContainer), il faut que le paramètre de la méthode d’export soit sous la forme idNamingContainer1:idNamingContainer2:…:…:idDataTable. De cette manière, la table est identifiée de façon unique dans la RootView.

JSF, Facelets : duplicateComponentId

By , 29/09/2010

Lors d’un développement, j’ai été confronté à un problème de duplication d’identifiant de composant. J’utilisais des rafraichissements AJAX sur une page XHML (Facelets)  qui incluait une autre page XHTML.

...
<c:forEach items="#{maList}" var="monObjet">
    <ui:include src="page.xhtml">
        <ui:param name="title" value="#{monObjet.title}" />
    </ui:include>
</c:forEach>
...

La duplication se trouvait sur un composant de la page inclue. En cherchant sur les blogs et les forums j’ai trouvé comment rendre indépendant les identifiants des composants de la page inclue entre les itérations et la page “mère”. Il faut utiliser le composant <f:subwiev/> de cette manière :

...
<c:forEach items="#{maList}" var="monObjet">
    <f:subview>
        <ui:include src="page.xhtml">
            <ui:param name="title" value="#{monObjet.title}" />
        </ui:include>
    </f:subview>
</c:forEach>
...

D’après ce que j’ai lu, l’utilisation de <f:subview/> est recommandée mais non obligatoire. Il garantit qu’aucun identifiant de composant dans la page inclue ne rentrera en conflit avec les identifiants des composants de la page “mère”. Attention les composants de la subview ne pourront pas faire de références aux composants en dehors de cette même subview.

Transformer du HTML en text standard

By , 20/09/2010

Il est de temps en temps utile de convertir du texte avec des caractères spéciaux en texte HTML. J’ai eu le problème inverse et j’ai trouvé une solution “séduisante” grâce à la librairie apache commons-lang : StringEscapeUtils.unescapeHtml(). Pour utiliser cette librairie dans un projet Maven il faut ajouter la dépendance suivante :


<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.5</version>
</dependency>

OfficeFolders theme by Themocracy