Web Services avec JBoss et ws4ee Introduction

L'objectif de ce document est d'arriver à déployer un Web Service sous JBoss grâce à ws4ee. Ws4ee utilise Axis mais le déploiement automatique demande une structure de fichier WAR particulière. Il y a déjà beaucoup de tutoriels sur internet mais aucun ne m'a permis de comprendre l'intégralité du développement jusqu'au déploiement. Le but de ce document n'est pas d'expliquer le fonctionnement des Web Services dans le détails, j'en suis d'ailleurs incapable. Le but est qu'un développeur habitué a faire du Java, soit capable en suivant ce tutoriel de développer et de déployer un Web Service sous JBoss. Et accessoirement de comprendre comment il y est parvenu.

Logiciels utilisés

Eclipse WTP : http://www.eclipse.org/webtools/main.php Il s'agit là d'une version d'Eclipse avec les PlugIns pour le développement d'applications web pré-installé. Vous pouvez aussi essayé d'installer ces PlugIns à la main mais moi, j'y suis pas arrivé.

Java WSDP : http://java.sun.com/webservices/downloads/previous/index.jsp Il s'agit la des librairie de développement web de Java. Je m'en suis servi pour générer les fichiers wsdl et mapping.xml. On peut certainement faire autrement mais cette solution est la seule qui marchait dans mon cas.

Librairie Axis : http://ws.apache.org/axis/ Théoriquement, elle est déjà incluse avec la version WTP d'éclipse et vous n'aurez donc pas a vous en préoccuper. Mais si vous en avez besoin, vous saurez où la trouver.

Voilà, on partira du principe que JBoss et Java sont déjà installé. Eclipse est installé dans "C:\Program Files\eclipse", Java est installé dans "C:\Program Files\Java", Wsdp est installé dans "C:\Program Files\Java\jwsdp-2.0" Rq : J'ai ajouté un le NLPack d'éclipse pour l'avoir en français. (http://download.eclipse.org/eclipse/downloads/#Language%20Pack) Le tuto donne donc les noms de menu et d'écran en français (sauf s'il ne sont pas traduit).

Développement du Web Service
On va développer un WS basique qui du bonjour. C'est ce que l'on trouve le plus souvent dans les tutoriel.

Paramétrage éclipse
Après le premier lancement d'éclipse, on va paramétrer un poil la bête histoire de se sentir plus à l'aise. Conseil, lors du démarrage il vous demande quel est le répertoire de l'espace de travail. Changez celui par défaut pour un répertoire qui n'a pas d'espace dans le nom. Autrement, cela pose des problèmes lors de l'utilisation de wscompile. Allez donc dans Fenêtre > Préférences puis "Java > Chemin de génération"

A "Dossier source de sortie" changez pour "Dossiers" et laissez les valeurs. Eclipse va pour chaque projet créer des sous-répertoires où il mettra les sources et le classes.

Création du projet
Une fois le paramétrage effectué, on va pouvoir créer le projet : Choisissez "Fichier > Nouveau > Projet ..." puis dans la liste "Web > Dynamic Web Project" Renseignez le nom du projet puis faites "Terminer".

A la demande d'acceptation de licence répondez "I Agree".

Développement du EndPoint
Déjà qu'est ce qu'un EndPoint ? Un EndPoint une l'URL donnant accès à un service par un protocol spécifique. En gros, c'est un point d'accès à une classe Java ou plutôt à une classe dérivé d'une interface qui étend la classe java.rmi.Remote. (cf. http://www.w3.org/TR/ws-gloss/#endpoint) Créez un nouveau package "bonjour" et à l'intérieur une interface "BonjourIF" qui ressemble à ça :
package bonjour; import java.rmi.Remote; import java.rmi.RemoteException; public interface BonjourIF extends Remote { public String salutToi(String p_nom) throws RemoteException; }

Puis on crée la classe "Bonjour" qui implémente cette interface :
package bonjour; public class Bonjour implements BonjourIF { public String salutToi (String p_name) { return "Salut "+p_name+" !"; } }

Je ne vais pas m'étendre sur l'écriture de la classe, c'est du Java standard. Toutes les fonctions publiques de la classe seront visible dans le Web Service. (En réalité, les fonctions utilisables dans le cadre du WS sont paramétrées dans le fichier wsdl).

Retourner des objet complexe
Voilà un problème auquel je viens de me retrouver confronté ! Dans certains cas, vous aurez besoin de retourner des objets complexes. Dans une classe contenant un statut, un possible message d'erreur et un tableau d'une autre classe. Ce qui rend la chose un poil plus compliqué. Ce qu'il faut garder en tête c'est que les classes à retournés doivent être les plus simple possible. Composés de variables membre, d'un constructeur par défaut et des getter et setter. Rien d'autre. N'utilisez pas non plus de conteneur complexe comme variables membre, il ne sont pas compatible avec JAX-RPC. Idem pour les constantes (private static final), elles ne seront pas prisent en compte dans le WSDL et lors de la génération du client elle ne seront pas générées. Si par exemple on veut que la fonction "salutToi" de notre WS retourne la liste des gens qui répondent au bonjour avec leur nom et leur réponse (oui je sais, c'est débile mais c'est un exemple !) on va avoir quelque chose comme ça :
package bonjour; public class Bonjour implements BonjourIF { public WSReponse salutToi (String p_name) { return new WSReponse(); } }

Commençons par créer la classe UneReponse avec les variables membres qui vont bien :
public class UneReponse { private String nom; private String reponse; public UneReponse() { } }

On peut constater que la classe est dans un autre package "bonjour.types". Ca permettra de mieux structurer et pour ceux qui vont faire le client, c'est plus facile à relire. Ensuite, juste ça ne suffira pas pour pourvoir générer le WSDL. Donc on va vite fait bien fait générer les getter & setter grâce à éclipse.

Pour cela on se positionne sur la classe, puis on fait click-droit et on va dans "Source > Générer les methodes d'accés get et set..."

Ici, vous cochez tout les champs et vous faites OK !

Vous avez alors tout les accésseurs nécessaires à votre classe pour quelle soit correctement interprété par wscompile.

Passons maintenant à la classe WSReponse qui ressemble à ça une fois que les accésseurs sont créé :
package bonjour.types; public class WSReponse { private String statut; private String msgErreur; private UneReponse[] lstResponses; public WSReponse() { } public UneReponse[] getLstResponses() { return lstResponses; } public void setLstResponses(UneReponse[] lstResponses) { this.lstResponses = lstResponses; } public String getMsgErreur() { return msgErreur; } public void setMsgErreur(String msgErreur) { this.msgErreur = msgErreur; } public String getStatut() { return statut; } public void setStatut(String statut) { this.statut = statut; } }

On notera que j'ai volontairement utilisé un simple tableau plutôt qu'un Vector ou un ArrayList. Pour des raison de compatibilités on n'utilisera pas de type complexe. En cherchant sur internet j'ai vue que cela n'était pas impossible mais si, par exemple, vous créez un WS en Java avec ce genre de classe, et que derrière quelqu'un veux développer un client en C++, l'utilisation de classe complexe va poser des problème voir rendre cela impossible. Voilà, maintenant que les classes de retour sont créer, il faut vous débrouiller avec les accésseur pour remplir correctement vos champs. Ne créer pas d'autre fonction membre de ces classes, elles ne seraient pas utilisables dans les clients générés à partir du wsdl. C'est pas toujours pratique mais c'est comme ça :).

Empaquetage du Web Service dans un WAR
Ant
Ant est pour le Java ce que Make est pour le C++. Cela permet de créer des scripts de compilation pour automatiser les actions fastidieuses et répétitives. Justement, la génération de certains fichier XML ainsi que de certaines classe est une opération relativement fastidieuse. On crée donc un script Ant pour générer automatiquement ces deux fichiers xml et les classes à l'aide de wscompile (inclus dans Java WSDP).

Création des fichiers de déploiement
Bon bon, on a finit le plus facile. On va maintenant s'attaquer a générer les fichiers de déploiement. C'est un palanqué de fichiers XML qui permettent a JBoss et Axis de déployer et mettre a disposition le Web Service.

WSDL et mapping
Les premiers fichiers que l'ont va créer sont le fichier wsBonjour.wsdl et jaxrpc-mapping.xml. Pour ce faire, on utilise wscompile, un utilitaire présent dans Java WSDP. Le truc c'est que l'opération est un peu fastidieuse et que vous risquez de la reproduire un paquet de fois. On va donc créer un script Ant. Ant est à Java ce que Make est au C++. Cela permet de créer des script de compilation pour automatiser les actions fastidieuses et répétitives.

J'ai testé plusieurs façon de créer le script et plusieurs syntaxes mais la seule chose qui ai bien marché pour moi c'est de créer manuellement le fichier "wscompile.xml" dans le répertoire du projet :
<?xml version="1.0" encoding="UTF-8"?> <project basedir="." default="wscompile" name="wsBonjour"> <property name="build.webinf.dir" value="WebContent/WEB-INF" /> <property name="build.classes.dir" value="build/classes" /> <target name="wscompile"> <exec executable="wscompile.bat"> <arg line ="-verbose -cp ${build.classes.dir} -gen:server -f: rpcliteral -d ${build.webinf.dir}/wsdl -mapping ${build.webinf.dir}/jaxrpcmapping.xml ${basedir}\wsconfig.xml"/> </exec> <move todir= "${build.classes.dir}"> <fileset dir = "${build.webinf.dir}/wsdl"> <exclude name="*.wsdl"/> </fileset> </move> </target> </project>

Ainsi que le fichier de configuration "wsconfig.xml" toujours dans le répertoire :
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> <service name="wsBonjour" targetNamespace="http://localhost:8080/wsBonjour" typeNamespace="http://localhost:8080/wsBonjour/types" packageName="bonjour"> <interface name="bonjour.BonjourIF" servantName="bonjour.Bonjour" /> </service> </configuration>

Les paramètres du fichier de configuration sont les suivants : ● name : Nom du service ● targetNamespace : URL du EndPoint. Pas super important; c'est JBoss qui va se le gérer. ● typeNamespace : URL des types, idem, JBoss se la gère. ● PackageName : Nom du package contenant la classe du WS ● interface name : package.interface d'implementation du WS ● interface servantName : package.classe implémentant l'interface précédemment citée. Concernant le script Ant, on s'assurera que "wscompil.bat" est bien accessible, sinon il faudra le mettre dans la variable PATH de la machine. Sur la ligne contenant les arguments de wscompile on retrouve : ● -cp <classpath> qui contient le classpath nécessaire pour générer les fichiers. On y met le répertoire de sortie de nos classes. ● -gen:server qui indique que l'on génère la partie serveur du WS. ● -f:rcplitteral qui est l'encodage (enfin, je suis pas sur de moi sur celui là ● -d <rep de sortie> qui est le répertoire de sortie pour les fichiers générés ● -mapping <mapping.xml> qui est le nom du fichier de mapping a générer ● <wsconfig.xml> qui est le nom du fichier de configuration Une fois que tout est prêt, clic droit sur "wscompile.xml" puis "Exécuter en tant que ... > Génération Ant ..."

A la sortie de la génération, vous devez obtenir quelque chose qui ressemble a ça :

Les fichiers wsdl, mapping.xml et le répertoire BonjourIFService ont été générés. Le fichier wsBonjour.wsdl doit absoluement se trouver dans WEB-INF/wsdl et jaxrpcmapping.xml doit se trouver dans WEB-INF.

Conseil : Les fichiers wsdl et mapping.xml générés contient des entête avec des liens pour la validation. En supprimant ces liens et ne laissant que le paramètre version, JBoss met moins de temps à les déployer.

Fichier web.xml
Celui ci est normalement déjà présent dans votre répertoire WEB-INF. Mais il n'est pas terrible alors on va le modifier :
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4"> <servlet> <servlet-name>wsBonjourServlet</servlet-name> <servlet-class>bonjour.Bonjour</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsBonjourServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>

Ce fichier va servir a déclarer une servlet au niveau du serveur d'applications (je suis pas hyper sur de ça). Donnez un nom à cette servlet, indiqué la classe correspondante.

Fichiers JBoss
Maintenant il ne nous reste plus que les fichiers JBoss. Tout d'abord, le fichier jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web.dtd"> <jboss-web> <!-- Resource references --> <!-- EJB References --> </jboss-web>

Je sais pas trop bien à quoi est ce qu'il sert celui là, il est quasi vide mais j'ai pas essayé sans. Et enfin, le fichier "webservices.xml"
<?xml version="1.0" encoding="UTF-8"?> <webservices version="1.1"> <webservice-description> <webservice-description-name>wsBonjour</webservice-description-name> <wsdl-file>WEB-INF/wsdl/wsBonjour.wsdl</wsdl-file> <jaxrpc-mapping-file>WEB-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file> <port-component> <port-component-name>bonjour.Bonjour</port-component-name> <wsdl-port>BonjourIFPort</wsdl-port> <service-endpoint-interface>bonjour.BonjourIF</service-endpointinterface> <service-impl-bean> <servlet-link>wsBonjourServlet</servlet-link> </service-impl-bean> </port-component> </webservice-description> </webservices>

Ce fichier indique à JBoss que c'est un Web Services qu'il va déployer et lui donne la localisation des différents fichier dont il aura besoin pour le déploiement. Tout ces derniers fichier sont a créer manuellement dans le répertoire "WebContent\WEB-INF" de votre projet.

Déploiement
Voilà, tous les fichiers sont créés et correctement rempli. Il ne reste plus qu'a déployer le WS. Pour cela, vous faites un click droit sur le projet puis "Exporter...". Dans la liste choisissez "Web > WAR file". Ce que vous pouvez faire c'est choisir directement la destination du répertoire de déploiement de votre JBoss. Sinon, il faudra l'y copier manuellement.

Une fois que le fichier WAR s'y trouve, JBoss va faire tout le boulot :
15:29:38,288 INFO [TomcatDeployer] deploy, ctxPath=/wsBonjour, warUrl=.../tmp/deploy/tmp36525wsBonjour-exp.war/ 15:29:38,519 INFO [WSDLFilePublisher] WSDL published to: file:/C:/install/jboss4.0.3SP1/server/CCS/data/wsdl/wsBonjour.war/wsBonjour.wsdl 15:29:38,569 INFO [AxisService] WSDD published to: C:\install\jboss4.0.3SP1\server\CCS\data\wsdl\wsBonjour.war\bonjour.Bonjour.wsdd 15:29:38,579 INFO [AxisService] Web Service deployed: http://Albator:8080/wsBonjour

Si tout a marché comme prévu, en vous rendant a cette adresse : http://localhost:8080/ws4ee/services Vous devriez avoir quelque chose comme ça :

Sur certain tuto, vous trouverez des URL du genre http://localhost:8080/wsBonjour?method=salutToi&p_name=Fred pour tester si votre WS fonctionne. Dans notre cas, cette URL ne retourne jamais rien mais cela ne veut pas dire que le WS ne fonctionne pas. Je pense que ws4ee ne gère pas ce mode d'appel. Une fois votre WS déployé, il faut le tester. Pour cela, deux solutions : ● Développer un client qui va faire appel à celui ci. C'est un peu long si on est pressé et que l'on a pas besoin de client par la suite. ● Utiliser ce merveilleux outil qu'est Eclipse pour tester que cela fonctionne bien.

Test du Web Service
Eclipse WTP dispose d'un outil plutôt très sympa pour tester un web service sans se faire chier à faire un client. C'est le "Web Service Explorer" ! Donc allez dans "Run > Launch Web Service Explorer"

Voilà gromo-dosso ce que vous devriez avoir. Cliquez sur l'avant dernier bouton en haut à droite de la fenêtre pour accéder à la partie de test via WSDL Vous rentrez l'adresse du WS que JBoss vous a donné lors du déploiement avec "?wsdl" pour accéder au fichier wsdl ! (Ici les captures d'écran porte sur un autre WS car il est plus intéressant que wsBonjour et qu'en plus, je n'ai plus les sources de ce dernier). Faites "Go"

Et la magie s'accomplit ! Nous avons la la liste des fonctions déployé pour le web service demandé. Un clic sur l'une des fonctions permettra de la tester. Rq: Si eclipse est configurer pour passer par un proxy et que votre WS est déployé en local, assurer vous qu'éclipse n'utilisera pas le proxy pour accéder à votre machine. Pour configurer cela allez dans "Fenêtre > Préférences > Internet > Proxy Settings". Voici par exemple ce que vous avez si vous voulez tester une des fonctions. Vous renseignez les valeurs, appuyez sur Go et dans le section inférieure le résultat s'affiche.

Consommation du Web Service
Bon, là ya pas grand chose de compliqué !

Génération du Stub
Le Stub est l'ensemble des classes clientes pour l'appel à un web service. Elles sont automatiquement générée grâce au fichier wsdl (Fichier de description que l'on a généré lors de la création du web service). Si vous ne l'avez pas, il est toujours possible de le trouvé en tapant l'URL http://localhost:8080/endpoint?wsdl . Dans un nouveau projet, importez le fichier wsdl. Puis faites un clic droit sur celui-ci "Web Services > Generate Client". Descendez le curseur jusqu'à "Develop client" puis cliquez sur "Terminer".

Si cela a bien fonctionné, vous avez une arborescence qui ressemble à ça : Le générateur a automatiquement ajouté les librairie Axis.

Création de la classe de consommation
Ajoutez une classe à votre projet : clientBonjour.java
import localhost.wsBonjour.BonjourIF; import localhost.wsBonjour.WsBonjourLocator; public class clientBonjour { public static void main(String[] args)throws Exception { WsBonjourLocator w_service; BonjourIF w_port; // Création du service w_service = new WsBonjourLocator(); // Changement de l'URL de endpoint // Il est possible de ne rien mettre, dans ce cas, l'URL utilisé // est celle paramétré automatiquement lors de la génération du // fichier WsBonjourLocator.java w_service.setBonjourIFPortEndpointAddress("http://albator:8080/wsBonjour"); // On récupère le port qui va bien pour faire les appels w_port = w_service.getBonjourIFPort(); // Le port s'utilise maintenant comme une classe java standard System.out.println(w_port.salutToi("Fred")); }

}

Et voilà, en exécutant ça, vous allez avoir :
22 mai 2007 17:03:35 org.apache.axis.utils.JavaUtils isAttachmentSupported ATTENTION: Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled. Salut Fred !

L'avertissement vient du fait que l'on a pas inclus la librairie mail.jar dans le classpath du projet. C'est pas grave mais ça pourrait poser des problèmes selon les web services que l'on consomme. Il suffira d'ajouter mail.jar dans la liste des librairies du projet pour que l'avertissement disparaisse.

Sign up to vote on this title
UsefulNot useful