lundi 30 juin 2008

Projets EMF

EMF est un métamodèle qui permet de décrire ses données à travers des éditeur.
Associé à open Architecture, il permettra de faire de la génération de code et sera utile pour générer massivement des services ou des bean (Par exemple si l'on souhaite rendre accessible une référentiel depuis l'extérieur).

Cette solution souffre principalement d'une complexité importante. Une vingtaine de jours environ et nécessaire pour se familiariser avec le produit.
En dépit de cet incontestable défaut EMC c'est une solution de métamodèle qui pourra remplacer avantageusement les outils traditionnel de modélisation dans les entreprise où Eclipse est au centre des développements. Il peu même se substituer à Power AMC ou Pational Rose dans les cas où le développements sont fortement couplés avec la modélisation.

Le premier pas pour se familiariser avec EMF est de suivre le tutorial.

vendredi 27 juin 2008

Sécuriser un service Axis2 avec des certificats

Pour sécuriser un service par une authentification basé sur certificat.


Il faut d'abord créer les magasin de clés pour le serveur et le client. Ces clés serviront pour authentifier les partis.

Ensuite, le serveur fournit un certificat pour le client, il faut considérer ce certificat comme une autorisation de se connecter au serveur (C'est pour cette raison qu'elle doit provenir du serveur). Ensuite, le client l'importe dans son magasin. Ces commandes se passent à laide de keytool.


keytool -genkey -alias serverkey -keystore keystoreserver.jks
keytool -genkey -alias clientkey -keystore keystoreclient.jks
keytool -selfcert -alias serverkey -keystore keystoreserver.jks
keytool -export -alias serverkey -keystore keystoreserver.jks>moncertif
keytool -printcert -file moncertif
keytool -import -keystore keystoreclient.jks -file moncertif


Il ne reste plus qu'à configurer axis2. Copier d'abord, le magasin de clé (keystore du serveur dans le répertoire classes/ de Axis2). Puis, dans le fichier conf/axis2.xml. Modifier les receiver et sender. Dans notre configuration le truststore est confondu avec le keystore. Si le besoin existait de les séparer le truststore doit contenir le certificat importé et le keystore, la clé de signature du serveur.


  <transportReceiver name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener">
<parameter name="port" locked="false">9002</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
<KeyPassword>axis2rules</KeyPassword>
</KeyStore>
</parameter>
<!--parameter name="truststore" locked="false">
<TrustStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
</TrustStore>
</parameter-->
<!--<parameter name="SSLVerifyClient">require</parameter>
supports optional|require or defaults to none -->
</transportReceiver>



    <transportSender name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLSender">
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
<KeyPassword>axis2rules</KeyPassword>
</KeyStore>
</parameter>
<parameter name="truststore" locked="false">
<TrustStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
</TrustStore>
</parameter>
<!--<parameter name="HostnameVerifier">DefaultAndLocalhost</parameter>
supports Strict|AllowAll|DefaultAndLocalhost or the default if none specified -->
</transportSender>



Enfin, il faut en fait rajouter deux lignes dans le code client :

System.setProperty("javax.net.ssl.trustStore", "chemin au clientTruststore");
System.setProperty("javax.net.ssl.trustStorePassword", "mot de passe du clientTruststore");

Pourquoi utiliser Spring dans un Web Service ?

Spring est un framework d'injection, et pour comprendre son intérêt il faut comprendre ce mécanisme et son intérêt.

L'injection est l'affectation d'une propriété par une sorte de container light(C'est le rôle de Spring). Dans le cadre d'une application simple (C'est à dire standalone) l'injection s'identifie simplement à une forme d'utilisation de pattern singleton.

On se sert de l'injection pour principalement deux cas de figure :

- Configurer et dimensionner par un bean de Configuration.
- Contrôler strictement ses instanciations pour pouvoir dimensionner précisément (Utiliser une seule instance DAO pour l'ensemble de ses instance de service par exemple).

Dans le cadre général des serveurs d'application, la notion d'injection est plus complexe. Il faut avant tout de comprendre qu'elle est liée au classloader et qu'il se pose des problème de scope. Ainsi, ce n'est pas parce qu'on injecte une propriété dans l'application, que cette propriété est injectée dans l'ensemble des instances de services.

Dans le cas des Web-Service, l'utilisation de Spring n'est donc pas triviale. Pour faire court, sil vous utiliser Axis et que vous souhaiter utiliser Spring dans axis, c'est un peu comme de vouloir utiliser deux moteur de Web-Service en un.

Même si cela reste possible, dans la majeur partie des cas il vaut mieux : soit se servir de httpinvoker (inclus dans spring).
Ou bien, si la fonction de container de Web-Service est fondamentale, ne se servir que du conteneur et ne pas utiliser Spring, cela est vrai pour : Axis, Axis2 etc.

Aqcuitement JMS

Comment fonctionne l'acquittement d'un message jms

La méthode acknowledge permet d'acquitter un message JMS. Dans le mode CLIENT_ACKNOWLEDGE, c'est le client qui décide de l'acquittement.

Lorsque le message est lu il disparait de la file dès le début de la lecture. Mais s'il n'est pas acquitté par le consumer, il reviendra dans la file une fois la lecture terminée.

mardi 24 juin 2008

Démarrer JBoss pour être accessible partout

Dans le fichier run.bat ajouter -b0.0.0.0 le Serveur JBoss devient accessible sur tout le réseau.

Problème de mémoire avec maven

%MAVEN_JAVA_EXE% %MAVEN_OPTS%  -Xmx1024m -classpath
%CLASSWORLDS_JAR% "-Dclassworlds.conf=%M2_HOME%\bin\m2.conf"
"-Dmaven.home=%M2_HOME%" org.codehaus.classworlds.Launcher
%MAVEN_CMD_LINE_ARGS%



The system is out of resources.
Consult the following stack trace for details.
java.lang.OutOfMemoryError: Java heap space
at com.sun.tools.javac.code.Scope$ImportScope.makeEntry(Scope.java:385)
at com.sun.tools.javac.code.Scope.enter(Scope.java:196)
at com.sun.tools.javac.code.Scope.enter(Scope.java:183)
at com.sun.tools.javac.comp.MemberEnter.importAll(MemberEnter.java:132)
at com.sun.tools.javac.comp.MemberEnter.visitTopLevel(MemberEnter.java:509)
at com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:446)
at com.sun.tools.javac.comp.MemberEnter.memberEnter(MemberEnter.java:387)
at com.sun.tools.javac.comp.MemberEnter.complete(MemberEnter.java:819)
at com.sun.tools.javac.code.Symbol.complete(Symbol.java:386)
at com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:758)
at com.sun.tools.javac.comp.Enter.complete(Enter.java:451)
at com.sun.tools.javac.comp.Enter.main(Enter.java:429)
at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:819)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:727)
at com.sun.tools.javac.main.Main.compile(Main.java:353)
at com.sun.tools.javac.main.Main.compile(Main.java:279)
at com.sun.tools.javac.main.Main.compile(Main.java:270)
at com.sun.tools.javac.Main.compile(Main.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.plexus.compiler.javac.JavacCompiler.compileInProcess(JavacCompiler.java:420)
at org.codehaus.plexus.compiler.javac.JavacCompiler.compile(JavacCompiler.java:141)
at org.apache.maven.plugin.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:493)
at org.apache.maven.plugin.CompilerMojo.execute(CompilerMojo.java:114)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:447)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:539)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:480)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:459)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:311)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:278)


Les tests unitaires lancés avec maven provoquent des erreurs de mémoire, il est possible de changer le fork afin d'instancier une JVM par test. Par défaut le fork utilisé est once (un seul fork)

<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>pertest</forkMode>
<argLine>-enableassertions</argLine>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>

mardi 17 juin 2008

Débuter avec axis2

Installer Axis2 sous Linux

  • Télécharger Axis2
  • Extraire le jar dans /usr/axis2-1.4
  • Effectuer des liens ln -s /usr/axis2-1.4/bin/wsdl2java.sh /usr/bin/wsdl2java.sh
  • Effectuer des liens ln -s /usr/axis2-1.4/bin/axis2.sh /usr/bin/axis2.sh
  • Modifier la première ligne dir=/usr/axis2-1.4/bin/ avec le chemin d'installation réel dans /usr/axis2-1.4/bin/axis2.sh et /usr/axis2-1.4/bin/wsdl2java.sh
  • Télécharger ANT
  • Extraire le jar dans /usr/apache-ant-xxx
  • Effectuer des liens ln -s /usr/apache-ant-xxx/bin/ant /usr/bin/
  • Exporter la variable export AXIS2_HOME=/usr/axis2-1.4



Supprimer le SOAP12 sur axis2
Modifier le fichier axis2.xml
   <parameter name="disableSOAP12" locked="true">true</parameter>


Utiliser avec Hibernate 3.6.2

Il faut utiliser antlr-1.7.7 et faire ettention au classpath d'une manière générale.
(Le classloader de l'application axis ne permet pas de redescendre plus bas au scope service s'il utilise le scope application.)
Concrètement cela signifie qu'il est impossible de mettre le fichier hibernate dans les librairies de AXIS.
Effectuer une première génération

  • Créer un répertoire pour votre projet
  • wsdl2java.sh -uri http://urlduwebservice.com/monservice
  • Taper ant

Structure d'une archive AXIS2
On peut déployer un service axis sous forme d'un fichier aar.

META-INF/services.xml
lib/*.jar



Il est également possible de le déployer sous forme d'un répertore ayant la même structure.

Note pour se servir du mapping adb à partir de POJO.

Si le bean retourné contient une liste d'élément, il n'est pas possible de se servir des typecast de liste, il faut se servir de tableau.

Génerer un Web Service à partir d'un WSDL et de Maven

Ajouter le bloc

<build>
<plugins>
<plugin>
<groupId>org.apache.axis2.maven2</groupId>
<artifactId>axis2-wsdl2code-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>wsdl2code</goal>
</goals>
<configuration>
<package>com.foo.myservice</package>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>




mvn -U axis2-wsdl2code:wsdl2code -DwsdlFile=http://10.202.48.12:8080/axis2/services/OrganisationControleService?wsdl -Daxis2.wsdl2code.package=joe.bigood


Il faut rajouter manuellement et en local la dépendance au plugin.

<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>

dimanche 15 juin 2008

Utiliser xpath

Dans cet article, je présente une petite collection de requête exemple de xpath. En la matière, l'empirisme est roi !

Comment retrouver tous les élément img dans un document html (Quelque soit leur hiérarchie)

XPath xpath = XPathFactory.newInstance().newXPath();
InputSource is = new InputSource(new FileInputStream(
"src/test/resources/testXpath.xml"));
NodeList str =(NodeList) xpath.evaluate("//img",
is,XPathConstants.NODESET);
log.debug(str.getLength());


Comment effectuer une transformation à l'aide de XPATH (Sans utiliser XQuery)
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilder db = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document document = db.parse(new File(
"src/test/resources/testXpath.xml"));
InputSource is = new InputSource(new FileInputStream(
"src/test/resources/testXpath.xml"));
NodeList str = (NodeList) xpath.evaluate("//img", document,
XPathConstants.NODESET);
Element el = (Element) str.item(0);
el.setAttribute("src", "newValue");
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
Source source = new DOMSource(document);
StreamResult sr = new StreamResult(System.out);
transformer.transform(source, sr);



Attention à la manipulation des namespaces dans XPATH !

Quand les requêtes xpath utilisent des namespaces, deux options sont possible :

La première est d'utiliser les noms absolus et non pas les alias pour effectuer la recherche :

//urn:oasis:names:tc:opendocument:xmlns:text:1.0:span


Malheureusement, cette méthode ne fonctionne lorsque les namespaces comportent le caractère '/' (qui sont descaractère utilisé pour écrire les requête Xpath). Dans ce cas, une deuxième méthode consiste à fournir à Xpath les alias des namspaces que nous utiliserons dans la requête. Cette approche est préférable, car les namespaces qui ne comportent pas de '/' sont plutôt rares.


NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("w")) {
uri = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
else if (prefix.equals("ns2")) {
uri = "http://www.davber.com/sales-format";
}
else {
uri = null;
}
return uri;
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
};
xpath.setNamespaceContext(ctx);


Il faut également rappeler que les namespaces sont héritables par les balise fille lorsque le namespace est déclaré par un attribut xmlns. Concrétement, dans l'exemple suivant, la balise Relationship est à rechercher dans le namespace : http://schemas.openxmlformats.org/package/2006/relationships car la balise parente Relationships est affectée à ce namespace par l'attribut xmlns.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/><Relationship Id="rId2"



Dans le cas ou le JDK a une version inférieure à la 1.5, JDOM fournira l'api XPath.



SAXBuilder sxb = new SAXBuilder();
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);
InputSource is = new InputSource(fis);
is.setEncoding("ISO-8859-1");
org.jdom.Document document = sxb.build(is);
// On initialise un nouvel élément racine avec l'élément racine du
// document.
Element racine = document.getRootElement();
XPath xpath = XPath.newInstance("count(/document/firstBranch/order/orderStatus/OrderStatusCode[text()='MARECHERCHE'])");
String result = xpath.valueOf(racine);


Exemple de requête

Pour compter le nombre de balise ayant l'arborescence /document/firstBranch/order/orderStatus/OrderStatusCode et contenant le texte 'MARECHERCHE'

/document/firstBranch/order/orderStatus/OrderStatusCode[text()='MARECHERCHE'])



Pour récuppérer toutes les balises img sous forme de nodeset


xpath.evaluate("//img", document,
XPathConstants.NODESET);