mardi, février 14, 2012

Techdays Microsoft et HTML 5 : une vrai fausse histoire d'amour ?

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

Le retour de ces 3 jours de Techdays et des quelques sessions sur l’interface Metro ou HTML 5 auxquelles j'ai assisté, laissent un sentiment mitigé vis à vis de Html 5.

D'un côté, il y a la volonté de Microsoft de passer comme le bon élève de la classe HTML 5 : toute une filière de sessions sur HTML 5, des investissements pour que le support d'HTML 5 soit complet dans IE 10…

De l'autre un discours équivoque : on vous présente toutes les nouveautés de HTML 5 mais surtout pour vous mettre en garde : sécurité, limite de la portabilité, problèmes potentiels de performance...

La conclusion de toutes ces sessions : le HTML 5 oui ! mais pour faire quoi ? Car ce n'est pas le langage universel qui va permettre d'écrire une interface universelle et portable sur tous les devices (desktop, iPhone, Androïd et Windows phone). Cela est décevant et frustrant.

Etudions rapidement, les différents arguments avancés par Microsoft et leur pertinence.

Le mythe du design d’interface universel

Voilà quelques années que les informaticiens rêvent d’un design d’interface universelle qui s’adapte comme par miracle à la forme du device : HTML, les layouts de Swing… Toutes ces technologies qui datent, ont recherché ce saint graal avec le succès que l’on connait.

Pendant des années, jusqu’à l’arrivée de l’iPhone, les interfaces des mobiles étaient celle d’un bureau de taille réduite. L’iPhone est arrivée et a présentée une approche radicalement différente qui était expliquée en long dans son guide de développement :

  • une application ne doit pas chercher à reproduire votre site web.
  • votre application et son ergonomie doit tenir compte du contexte d’utilisation de la plateforme (en l’occurrence la mobilité) et répondre à ces besoins spécifiques

5 ans plus tard au vue du succès de l’iPhone, nous sommes obligés de reconnaitre que cette approche était la meilleure.

Il était acquis que pour des besoins différents : le desktop et le mobile, il fallait des interfaces différentes.

Avec Windows 8 et l’interface Metro, Microsoft veut modifier cela : on a des interfaces qui se ressemblent entre le desktop et le Windows Phone et en plus, on peut utiliser Javascript et le HTML 5 pour construire une application Metro. Il est donc possible de rêver de nouveau à un design universelle.

Désolé de briser ce nouveau rêve, mais il suffit de regarder le monde actuel et plus précisément la cohabitation iPad/iPhone pour ce rendre compte de l’impossibilité d’une telle approche. Malgré des technologies identiques, des contextes d’utilisations très proches (même si différent), les interfaces des applications sont construites spécifiquement pour chaque device afin de profiter au mieux de la différence de facteur forme : un écran plus grand.

Si vous étendez le besoin au desktop qui en plus d’un facteur forme très différent, a des contextes d’utilisation très différents, les écarts se creusent encore plus. La totalité des intervenants considèrent qu’à chaque device, il faut son interface utilisateur :

  • l’application doit tenir compte de besoins utilisateurs différents
  • le device utilisé a un facteur forme différent

Mais, pour la majorité des intervenants, il faut également prévoir des interfaces différentes pour chaque type de portable.

Un design pour chaque portable

Il y a deux raisons invoquées pour cette approche :

  • la première est un problème de réactivité : il faut développer dans la technologie native du téléphone afin d’assurer la meilleure réactivité du téléphone.
  • la seconde est un problème d’UX comme ils disent (User eXperience) : le principe de navigation d’un Windows Phone diffère beaucoup de ceux du couple iPhone/Android. Si vous souhaitez que l’utilisateur n’est pas l’impression d’une intrusion d’une technologie inadaptée, il faut respecter ce principe de navigation.

Nous avons donc deux raisons : une technique et une ergonomique qui se renforcent mutuellement pour prôner le développement d’interfaces spécifiques à chaque portable.

Revenons tout d’abord sur le problème des performances : créer une application qui réponde rapidement aux interactions utilisateurs est encore un défi pour le monde des portables. Il faut savoir que le premier téléphone WebOS (à l’époque réalisé par Palm) s’est très bien vendu. Malheureusement, il détient aussi le record des appareils retournés : la raison : l’extrême lenteur de son interface. Palm avait fait le pari d’un développement basé sur le webkit (HTML et javascript). Ce choix novateur s’est avéré catastrophique pour les performances.

Le retour des différents développeurs d’application mobile présents aux Techdays valide cette approche : pour une application fluide il faut encore aujourd’hui utiliser des technologies natives.

De la même manière, les différents développeurs considèrent que les principes ergonomiques des plateformes sont trop différents pour même imaginer un story board identique pour la navigation. Si pour iOS et Androïd les principes sont proches (qui a dit copie ?) et que cela pourrait être acceptable, à l’opposé l’interface Windows Phone 7 est très différente et nécessite une approche différente. L’élément principal évoqué est la notion de Panorama propre à l’interface Windows Phone : il s’agit de la possibilité de naviguer “horizontalement” à travers les détails d’un même objet/concept, en “tournant les pages”.

Et HTML 5 dans tous ça ?

On résume : les interfaces de chaque portable doivent être réalisées en technologies natives (Objective C pour iOS, Java pour Androïd, Silverlight pour WP) et on doit avoir un design pour chaque type de device (desktop, tablette et mobile).

Vous avouerez que comme résultat pour une série de sessions HTML 5, on est en droit de se poser des questions. Ajoutez : les trous de sécurité, le fait que le HTML 5 n’est “pas sec” (la norme n’est pas définitive et semble continuer d’évoluer) et tout particulièrement l’instabilité sur un navigateur IE 10 en alpha, vous obtenez un sentiment très mitigé vis à vis de HTML 5.

L’intérêt de Microsoft n’est certainement pas de nous pousser à développer du code portable dans une technologie indépendante de leur plateforme.

Si HTML 5 n’est certainement pas la solution pour développer un jeu très immersif sur téléphone portable, il reste qu’il existe un segment peu abordé dans toutes ses session qui est le développement d’applications métier. Il est vrai qu’avec VB ou C#, Microsoft dispose de technologies propriétaires bien implantées et garantissant le verrouillage des postes clients des utilisateurs sur Windows. En comprendra peut-être ainsi mieux pourquoi ces aspects auront été passé sous silence.

Une application métier est un type d’application assez particulier qui nécessite généralement peu d’effet visuel, des écrans de saisi interactif mais sans nécessiter des appels à des effets graphiques élaborés : il s’agit généralement d’interdire la frappe de certains caractères et de rafraichir une zone de l’écran en fonction de la saisie. HTML 5 simplifie le développement de ce type d’interface et ne connait pas les problèmes de performance d’un jeu. L’utilisation d’HTML 5 devra à terme, permettre l’indépendance d’un tel développement à travers les plateformes desktop (Windows, MacOs ou Linux). Aujourd’hui le couple Javascript/HTML est tout à fait pertinent pour la partie graphique de tels développements et HTML 5 devrait le renforcer en simplifiant le développement.

Pour ce type d’applications, le desktop est la priorité, mais il n’est pas impossible de faire une version spécifique pour portable ou tablette : on parlera plus de site mobile que d’application. Dans ce cas, on n’installe rien sur le portable, il s’agit d’un site web. On n’aura pas accès au téléphone comme les contacts, la géolocalisation ou d’autres éléments mais cela est tout à fait acceptable. De plus comme il ne s’agit pas d’une application du portable, l’ergonomie peut être unifiée entre les différents types de portable : on retrouve ainsi la portabilité pour un même type de device.

Conclusion : HTML 5 pour des applications métiers

En conclusion, il faut respecter l’approche “un type de device pour une interface” et ne pas croire que HTML 5 va vous permettre d’avoir un design et un développement universelle qui fonctionne du portable au desktop.

Pour des applications très intensives en besoin graphique, il est probable que les technologies natives (Objective C, Java ou Silverlight) restent encore pour quelques temps la seule solution viable.

Pour le développement d’application métier, HTML 5 apporte quelques éléments qui vont simplifier le développement. Le couple HTML/Javascript pour la partie cliente de ce type d’application étant déjà viable, HTML 5 devrait renforcer cette approche qui rend indépendant de la plateforme vos développements métiers.


DiggIt! Enregistrer sur Del.icio.us

mardi, février 07, 2012

Microsoft Techdays 2012

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

C'est partie pour la 6ieme édition de cet évènement qui permet de faire le tour des technologies Microsoft. Comme les 5 premières éditions, cet évènement de 3 jours se tiendra au palais des congrès de Paris à deux pas de la Défense.

Depuis 2 ou 3 ans, les journées sont très fortement typées en fonction d'une audience. La première journée est historiquement consacrée aux développeurs et cela se sent tout particulièrement dans les plénières. Traditionnellement, cette première plénière est celle des annonces produit. L'année 2012 étant une année particulièrement calme pour Microsoft (Windows 8 est encore loin), l'accent est mis sur l'architecture et l'écoute des utilisateurs : on a une impression de cohérence, de vision globale.

Symptomatique de l'importance de l'architecture, la session commence avec un architecte présenté comme la mage qui va servir de guide dans le monde du développement. Ce positionnement de l'architecte comme guide semble répondre à une attente des développeurs qui ont besoin d'être guidé dans leur choix. De nombreuses sessions autour de l’architecture seront accessibles durant ces 3 jours : confirmant à la fois une demande et l’intérêt de Microsoft pour le sujet.

L'architecte met l'accent sur la multiplicité des interfaces : le tactile, la voix et bien sur la gestuelle pour ne pas oublier Kinect. Il insiste sur le stockage dans le cloud et la synchronisation que cela permet entre les différents devices avec la contrainte d’une forte interopérabilité que cela implique. Microsoft semble pousser le protocole HTTP REST et sa déclinaison OData pour l’accès aux données du nuage.

Coté nouveauté, Microsoft pousse en avant la problématique de l’accès aux données dans le cloud et plus particulièrement celui de sa scalabilité vis à vis de la charge : Le SQL n’est pas adapté à des sites nécessitant de très grosse quantité de données (au delà du To). Microsoft met en avant toute une série de solutions.

Microsoft continue de mettre en avant des mécanismes d'authentification comme ceux de Facebook, Google et LiveID pour le cloud. J’ai l’impression que cette approche leur permet de mettre en avant leur service Azure : Access Control.

Les thèmes de la plénière sont :

  • Tools et ALM
  • Cloud et serveur
  • Phone et device
  • IHM et design

 

Tools et ALM

Dans cette partie les trois points sur lesquels Microsoft met l’accent sont :

  • Team foundation server : conserver et suivre les échanges autour des approches agiles (gestion des sprints et du backlog associé)
  • Roslyn : il s’agit d’une API qui ouvre le compilateur C# et l'IntelliSense, elle permet de contrôler le code en direct ou de pratiquer le tissage en injectant du code à la compilation.
  • Le c++ est à l'honneur avec l'évolution de la norme et le mise en œuvre de nouveaux mots clés concernant l’asynchronisme (async et await) qui permettent d’écrire du mode asynchrone de manière séquentielle. Il y a beaucoup de code cachée derrière. Les tests unitaires deviennent possibles.

Cloud et server

Microsoft a décidé de mettre l’accent sur les éventuels problèmes de la montée en charge des bases de données SQL dans le cloud. Microsoft considère que les bases de données SQL ne peuvent monter en charge correctement sur de gros volume. La solution extrême serait une approche NoSql mais Microsoft propose une solution intermédiaire la SQL Fédération qui multiplie les bases physiques et permet ainsi une scalabilité du système.

Plusieurs sessions sont revenues sur ce problème. Pour Microsoft, une base SQL ne sait pas monter efficacement au delà du tera octect. La Fédération SQL permet de scinder au fur à mesure une base SQL en morceaux afin d’éviter d’atteindre la taille critique.

Microsoft propose également une approche au niveau de l’architecture de partir sur une base SQL classique (plus simple) tout en conservant la possibilité de passer à du  NoSql ensuite pour les gros volumes. Pour Microsoft, le NoSql a l’avantage d’avoir une montée en charge linéaire.

Un autre point qui tient à cœur à Microsoft quand on parle de cloud est le service Access Control. Il permet de fédérer sous une même API les différents mécanismes d’identification du Web (Facebook, Yahoo, Google et Live Id). Le développeur ne se préoccupe pas de savoir quels sont les services autorisés.

Ce mécanisme semble particulièrement important pour Microsoft car il me semble permettre également d’établir un jeton de sécurité qui va permettre au client d’accéder directement à une image ou un document sans repasser par l’application.

On voit apparaitre une nouvelle préoccupation pour le cloud : le besoin de réversibilité. Il semble que les clients Microsoft hésitent à aller vers le cloud par peur de se retrouver coincer chez un fournisseur. Microsoft essaie d’adresser ce problème : les approches HTTP REST et plus précisément le OData on pour vocation de lever cette inquiétude. Avec OData qui est un langage par URI d’interrogation d’une base de données, les accès aux données deviennent indépendants de la technologie de stockage et de leur emplacement : on y accède pas HTTP.

L’OData est mis en avant dans plusieurs sessions d’architecture.

Phone et device

Dans cette partie, on a surtout parler de device et très peu de Phone. C’est d’ailleurs surprenant le peu de bruit qui est fait sur Windows Phone, mais il est vrai que je suis peu sensible au sujet.

On est dans l’internet des objets qui a dépassé celui des êtres humains (en nombre de connexions) et qui devrait continuer d’augmenter. On retrouve là tout l’intérêt pour Microsoft de ses solutions Embedded : ce marché devrait exploser.

La demo faite en plénière était impressionnante : elle mélange un projet Microsoft Lab le Gadget Steer qui est une sorte de carte à laquelle on peut associer des capteurs physiques et un projet software Pachube qui permet la configuration d’un petit device. En un rien de temps, on avait une station météo.

IHM et design

C’est dans cette partie qu’on voit poindre Windows 8 avec notamment son interface Métro.

Cette partie commence par l’annonce suivante : 68% des utilisateurs considèrent leurs applications non intuitives

Cela permet à Microsoft d’insister sur l’importance du Design qui devient d’autant plus importante qu’avec la consumérisation du SI (l’utilisation par leurs employés de leur propre appareil sur le lieu du travail), ils se sont habitués à des produits biens finis (on ne peut une référence plus explicite à l’iPhone).

L’interface Métro est pour Microsoft la solution. Il ne s’agit pas que d’une technologie, il s’agit d’un style et d’une méthodologie. Un développeur peut en respectant quelques règles simples produire un design efficace. On retrouve des règles classiques :

  • Il faut respecter des alignements : c’est pour cela que Metro propose des règles pour aligner aisément les pavés
  • Il faut favoriser le contenu et supprimer les bordures et barre de titre.
  • Limiter les couleurs et les polices de caractères
  • Fast and fluid : montrer la réaction aux actions. Metro propose des effets de transition.

Microsoft semble privilégier une approche dans laquelle, on développe en natif pour chaque plate-forme : objectif C pour iPhone, Java pour Android et Silverlight pour Windows Phone et Desktop.

Microsoft met également en avant HTML 5 avec un très grand nombre de sessions concernant cette nouvelle norme.

Conclusion

Cet évènement reste un succès : les sessions sont pleines 10 minutes avant l’heure de début.

La qualité des intervenants reste excellente.

Pour les messages 2012 de Microsoft : on retiendra le cloud avec OData pour l’accès aux données et Metro et Windows 8 pour les nouvelles interfaces.

De mon coté, je retiens que la communauté Microsoft semble se retrouver dans la même situation que les développeurs Java : il existe une profusion de choix pour résoudre un même problème, et il devient très difficile de faire des choix. L’architecture devient également une préoccupation majeure du monde Microsoft qui semblait jusqu’alors préférer l’approche Code First.


DiggIt! Enregistrer sur Del.icio.us

lundi, décembre 05, 2011

Etape 5 : Déployer un Service Web et compléter son WSDL

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

Il s’agit de la 5ieme étape d’un tutorial sur la création de service web JAX-WS. L’objectif de cette étape est, dans notre approche Contract First, de compléter le WSDL naturellement généré par les annotations JAX-WS. Nous allons en effet constater que les annotations JAX-WS ne permettent pas la génération d’un WSDL contenant toutes les précisions nécessaires (comme la longueur d’une chaine de caractères). Nous allons voir comment surcharger le WSDL généré afin qu’il soit conforme au besoin de notre approche Contract First.

Cette étape s’appuie sur :

Dans cette partie nous allons déployer notre service web sur JBoss 5.1 et analyser le WSDL qui est produit. Ensuite, nous allons compléter le WSDL afin d’ajouter des informations plus précises sur les contraintes des types. Pour cela nous allons enregistrer le WSDL généré et le surcharger en utilisant un schéma XSD complémentaire.

Rappel des étapes du tutorial sur les services avec JAX-WS :

  1. Présentation du tutorial et de l'approche Contract First avec JAX-WS
  2. Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS
  3. Etape 3 : Création des objets métier et d’une exception JAX-WS
  4. Etape 4 : Annotations JAX-WS et JAXB des classes
  5. Etape 5, Ce billet : Déployer un Service Web et compléter son WSDL

Déployer un service web

Je ne vais pas reprendre dans le détail le déploiement d’un service web. Le déploiement est assez spécifique au serveur d’application et j’ai déjà réalisé trois tutoriaux mettant en œuvre le déploiement d’un service web :

Dans notre cas, nous allons créer un WAR puis le déployer sur le serveur d’application.

Génération du War

Assurez vous d’avoir bien sauvegarder l’ensemble des fichiers.

Cliquez droit dans l’explorateur de ressource d’Eclipse sur votre projet JaxWsContractFirst, sélectionnez Export –> WAR File, dans la dialogue « Export » qui s’affiche choisissez :

  • Web Project : JaxWsContractFirst qui est le nom de votre projet
  • Destination : Naviguez pour sélectionner l’emplacement et le nom du WAR File. Pour ma part je l’ai créé sur le bureau. Le nom du fichier est JaxWsContractFirst.war.
  • Décochez l’option “Optimize for a specific server runtime”

Le nom du war n’a aucune importance, il n’est pas utilisé pour obtenir le WSDL et n’a aucun d’impact sur le contenu du WSDL.

ExportWar

Appuyez, ensuite sur Finish. Vous devriez trouver un fichier JaxWsContractFirst.war sur le bureau.

Déployer le war

Cette partie est très spécifique de votre serveur d’application. Je me contente du cas JBoss 5.1.

Pour WebSphere, je vous renvoie à mon tutoriel : http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html

Avec JBoss, la solution la plus simple est de copier le war dans le répertoire C:\jboss-5.1.0.GA\server\default\deploy.

Vous n’avez pas besoin de redémarrer le serveur s’il est lancé, vous devriez voir apparaitre après quelques secondes dans la console :

12:08:51,352 INFO [DefaultEndpointRegistry] register: jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk
12:08:51,778 INFO [TomcatDeployment] deploy, ctxPath=/JaxWsContractFirst
12:08:52,555 INFO [WSDLFilePublisher] WSDL published to: file:/C:/jboss-5.1.0.GA/server/default/data/wsdl/JaxWsContractFirst.war/WebContractHelpdesk7856945428892376495.wsdl

On y retrouve le nom du War que l’on a déployé et le nom du service web (le endpoint).

Si on tape l’url suivante dans un browser : http://localhost:8080/jbossws/services une page JBossWS/Services s’affiche.

JBossEndpoint

Il doit y a avoir une page avec un Endpoint name jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk, un WSDL est accessible sur la ligne suivante : http://127.0.0.1:8080/JaxWsContractFirst?wsdl

Attention ! les URLs dépendent des serveurs d’application. On a par exemple, pour obtenir le WSDL :

 

Analyse du WSDL généré

En cliquant sur le lien précédent : http://127.0.0.1:8080/JaxWsContractFirst?wsdl on affiche le WSDL du service.

Le WSDL dépend du serveur d’application : par exemple WebSphere 6.1 sépare en deux fichiers le WSDL du schema XSD définissant les types XML. JBoss ne fait lui qu’un seul fichier.

Nous allons analyser succinctement son contenu afin de mettre en évidence les correspondances entre les annotations et le contenu du WSDL.

Dans mes précédents tutoriaux sur JAX-WS, j’ai déjà analysé les différentes correspondances, je me limiterai dans cette étape à quelques points nouveaux :

  • l’objet Question : comment un objet Java apparait dans le WSDL
  • l’énumération
  • le FaultBean qui permet de transférer une exception vers le client

L’objet Question

Il devient un ComplexType, son type QuestionType correspond à l’annotation XmlType.

On constate que les name des différents éléments correspondent à l’annotation XmlElement.

<xs:complexType name="QuestionType">
<xs:sequence>
<xs:element minOccurs="0" name="NUMERO" type="xs:string"/>
<xs:element minOccurs="0" name="DESCRIPTION" type="xs:string"/>
<xs:element minOccurs="0" name="SUBMITDATE" type="xs:dateTime"/>
<xs:element name="TITLE" type="xs:string"/>
<xs:element minOccurs="0" name="PRODUCT" type="xs:string"/>
<xs:element minOccurs="0" name="URGENCY" type="tns:urgencyEnum"/>
<xs:element name="PRIORITY" type="xs:string"/>
<xs:element minOccurs="0" name="TYPE" type="xs:string"/>
</xs:sequence>
</xs:complexType>

On remarque qu’on utilise des types simples provenant du schéma xs,  à l’exception de URGENCY qui pointe vers le schéma tns (c’est le WSDL) et plus particulièrement vers notre type énumération.

Si on compare avec le WSDL généré par Axis2 à l’étape : http://jl2tho.blogspot.com/2007/05/etape-5-tutorial-axis2-gnration-des.html dans notre tutorial Services web avec Axis2 : Approche Contract First, on avait pour l’objet Question :

<xsd:complexType name="Question">
<xsd:sequence>
<xsd:element name="Numero" type="tns:QuestionID"></xsd:element>
<xsd:element name="SubmitDate" type="xsd:date"></xsd:element>
<xsd:element name="Product">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2"></xsd:length>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Type">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="BUGINPROD"></xsd:enumeration>
<xsd:enumeration value="CONFIG"></xsd:enumeration>
<xsd:enumeration value="USAGE"></xsd:enumeration>
<xsd:enumeration value="BUGINDEV"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Priority" type="tns:Urgency"></xsd:element>
<xsd:element name="Description" type="xsd:string"></xsd:element>
<xsd:element name="Title">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="250"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>

On diffère sur plusieurs points significatifs (les noms ne le sont pas car ils sont paramétrables par annotation comme on pu le voir à l’étape suivante) :

  • le type de SubmitDate est date au lieu de dateTime
  • l’énumération est directement incluse dans le type, dans notre cas elle est externalisée.
  • avec axis2, il est possible d’être plus précis sur les restrictions de type : notamment on peut indiquer la taille maximale d’un champ.
  • par défaut, il aurait fallu indiquer systématiquement required à true. cela indique que le nœud est toujours présent et fait disparaitre le minOccurs. Attention, cela n’a rien à voir avec la valeur null.
  • avec axis2, on a pu utiliser un type simple externe QuestionID permettant de préciser les contraintes sur le contenu du nœud.

 

Enumération

On avait surchargé les valeurs des énumérations par annotation, on voit qu’on retrouve un SimpleType qui reprend ces valeurs.

Si on compare à la définition ci-dessus qui provient d’Axis2 et qui était incluse directement dans l’objet Question, on retrouve la même structure.

<xs:simpleType name="urgencyEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="URGENCY_BUGINPROD"/>
<xs:enumeration value="URGENCY_CONFIG"/>
<xs:enumeration value="URGENCY_USAGE"/>
<xs:enumeration value="URGENCY_BUGINDEV"/>
</xs:restriction>
</xs:simpleType>

 

Exception et Fault

Nos méthodes pouvaient renvoyer une exception, on retrouve cette possibilité dans la définition de l’opération :

<operation name="creerNouvelleQuestion" parameterOrder="creerNouvelleQuestion">
<input message="tns:ISwHelpDeskPortType_creerNouvelleQuestion"/>
<output message="tns:ISwHelpDeskPortType_creerNouvelleQuestionResponse"/>
<fault message="tns:BusinessFault" name="BusinessFault"/>
</operation>

On a un attribut fault pour nos opérations.

Par rebond, on arrive à la définition du beanFault :

<xs:complexType name="faultBean">
<xs:sequence>
<xs:element minOccurs="0" name="businessMessage" type="xs:string"/>
<xs:element minOccurs="0" name="code" type="xs:string"/>
</xs:sequence>
</xs:complexType>

On voit qu’il contient les deux propriétés qu’on avait définies.

Vous pouvez chercher dans le WSDL, vous ne trouverez aucune référence à la propriété message d’une exception Java. Cette information n’est pas visible dans le WSDL.

Compléter le WSDL

Nous avons deux éléments en écart par rapport à ce qu’on pouvait faire dans l’approche Axis2 :

  • le format d’un champ date
  • la possibilité de définir des contraintes plus fortes sur un type simple

 

Propriété de type Date

La documentation officielle d’Oracle (http://docs.oracle.com/cd/E17802_01/webservices/webservices/reference/tutorials/wsit/doc/DataBinding2.html) considère que le type à utiliser pour une date est en priorité le type XMLGregorianCalendar : si on utilise le type java Date, on ne pourra aller que vers le type XML dateTime. A contrario, le type XMLGregorianCalendar offre une plus grande liberté et peut être envoyé vers un type XML date.

Pour information, les outils qui génère du Java à partir du WSDL vont généralement vers ce type XMLGregorianCalendar.

On va donc modifier doublement la déclaration de notre propriété submitDate dans l’objet Question :

  • on change son type java
  • on lui ajoute une annotation XmlSchemaType afin de préciser qu’on souhaite un type date et non plus dateTime.

On obtient pour sa déclaration le code suivant :

    @XmlElement(name = "SUBMITDATE")
    @XmlSchemaType(name="date")
     public javax.xml.datatype.XMLGregorianCalendar submitDate;

Il faudra également penser à mettre à son jour son getter et son setter.

 

Propriété de type Token ou normalizedString

Au niveau des types de base du XML, il existe trois types simples pour une chaine de caractères : le type string que nous avons utilisé (il s’agit du défaut pour une String Java) et les types token et normalizedString qui peuvent être précisé avec l’utilisation de XmlSchemaType.

Les deux différent du type string par le traitement des caractères retour à la ligne, Entrée, tabulation ainsi que des espaces en début et fin de chaine :

  • token : indique au processeur XML de simplement supprimer ces caractères. Vous obtenez ainsi une chaine sans caractères espaces en début ou fin et sans tabulation ou retour chariot et cela indépendamment de ce qu’envoie le client du service web.
  • normalizedString va un cran plus loin, car il interdit la présence de tel caractère.

Nous allons modifier les propriété product et type afin d’essayer ces deux types. On obtient pour la définition des propriétés de l’objet Question, le code suivant :

On obtient pour sa déclaration le code suivant :

@XmlType(name="QuestionType", propOrder = { "id", "description", "submitDate", "title", "product", "urgency", "priority", "type" })
@XmlAccessorType(XmlAccessType.FIELD)
public class Question {
    @XmlElement(name = "NUMERO")
    private String id;

    @XmlElement(name = "DESCRIPTION")
    private String description;

    @XmlElement(name = "SUBMITDATE")
    @XmlSchemaType(name="date")
     public javax.xml.datatype.XMLGregorianCalendar submitDate;

    @XmlElement(name = "TITLE", required=true)
    private String title;

    @XmlElement(name = "PRODUCT")
    @XmlSchemaType(name="token")
    private String product;

    @XmlElement(name = "URGENCY")
    private UrgencyEnum urgency;

    @XmlElement(name = "PRIORITY", required=true)
    private String priority;

    @XmlElement(name = "TYPE")
    @XmlSchemaType(name="normalizedString")
    private String type;
   

On a mis en gras les modifications.

Il n’est pas nécessaire de modifier les getter et setters.

 

Ajouter des contraintes à un type simple

Cette dernière opération est la plus délicate : on a vu précédemment que les types simples dans axis2 étaient plus précis : il était possible de spécifier la taille maximale d’une chaine de caractères et il était possible de préciser une expression régulière vérifiée par la chaine.

Les annotations JAX-WS ou JAXB ne permettent pas une telle précision, or cette information (surtout d’ailleurs pour la taille d’une chaine de caractères) est particulièrement importante d’un point de vu contractuel. Nous allons aborder ce dernier point dans ce chapitre.

La seule approche possible est l’utilisation d’un WSDL en local : les annotations n’étant pas assez puissante, il faut les aider en reprenant la main. Il y a bien l’annotation XmlSchemaType qui permet d’indiquer un type de données propriétaire : on n’est pas limité aux types du schema standard, il suffit de préciser un autre namespace. Mais il n’existe pas d’annotation permettant d’inclure son propre schéma XSD. Heureusement, nous disposons d’un attribut wsdlLocation dans l’annotation WebService permettant de préciser son propre WSDL. c’est cette approche que nous allons utiliser mais afin d’être moins intrusif, on va également utiliser un schéma XSD complémentaire.

Le principe de base de notre approche est l’utilisation maximale de la génération automatique du WSDL : on partira d’un fichier WSDL généré. Ce fichier WSDL généré que l’on récupère en l’enregistrant va être complété en se limitant au strict nécessaire (ce qui n’aura pas pu être mis en annotation comme l’inclusion d’un schema XSD complémentaire ou bien les annotations length sur les strings).

Fichier XSD pour les contraintes

Tout d’abord nous allons définir un nouveau schéma XSD afin de définir les types nécessitant des contraintes plus fortes comme dans notre exemple le numéro d’une Question. Le numéro est une chaine de caractères de 9 chiffres. Nous allons définir un type simple. Afin de limiter l’impact sur le WSDL généré, nous allons mettre dans un fichier externe : un nouveau fichier XSD.

On crée un répertoire wsdl dans WEB-INF. Il semble impératif qu’il soit dans WEB-INF : il est préférable de mettre ce fichier à coté du fichier WSDL qui doit être sous WEB-INF pour JBoss.

On se place sur le nœud WEB-INF dans WebContent, et on clique droit, choisir New –> Other… Dans la dialogue qui s’ouvre choisir Folder dans le nœud General. Le nom du dossier sera wsdl puis validez.

Dans ce répertoire wsdl, on crée un fichier xsd : HelpDeskBasic.xsd. On se place sur le nœud wsdl que l’on vient de créer, et on clique droit, choisir New –> Other… Dans la dialogue qui s’ouvre choisir XML dans le nœud XML. Tapez HelpDeskBasic.xsd come File name et validez. Le fichier est créé. S’il est ouvert,fermez le afin de le rouvrir en mode Editeur XML.

Ajoutez, le code suivant :

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:tns="http://basic.demo.jl2tho.fr" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://basic.demo.jl2tho.fr">
<simpleType name="QuestionId">
<annotation>
<documentation>Type pour un numero de question</documentation>
</annotation>
<restriction base="string">
<length value="9"></length>
<pattern value="\d*"></pattern>
</restriction>
</simpleType>
</schema>

Il est important de noter qu’on utilise pour ce fichier un namespace différent de celui du WSDL en l’occurrence : http://basic.demo.jl2tho.fr. J’en profite pour rappeler qu’un namespace est juste une étiquette : par convention il ressemble à une URL mais il n’y a rien à cette emplacement.

Utilisation d’un type propriétaire avec JAXB

Maintenant que notre nouveau type est défini, nous allons l’utiliser dans notre objet Question. Pour cela, on modifie le champ id de l’objet Java en ajoutant une annotation XmlSchemaType.

cette annotation permet de préciser un type XML (nos l’avons déjà utilisé plus haut). Dans notre cas, comme le type n’appartient au schéma par défaut, nous devons également indiquer le namespace : dans notre cas, c’est celui de notre nouveau XSD.

On obtient pour sa déclaration le code suivant :

@XmlElement(name = "NUMERO")
@XmlSchemaType(name="QuestionId", namespace="http://basic.demo.jl2tho.fr")
private String id;

Il n’est pas nécessaire de mettre à jour son getter et son setter puisqu’on a juste ajouter une annotation.

Création du fichier WSDL local

Pour obtenir la version de départ du WSDL, je souhaite m’appuyer sur le WSDL généré automatiquement. Comme je viens de modifier mes annotations, il faut que je déploie ma nouvelle version sur le serveur JBoss. Je crée un nouveau WAR que je copie sous C:\jboss-5.1.0.GA\server\default\deploy comme au début de ce tutorial. Je rappelle qu’il n’est pas nécessaire de redémarrer le serveur pour prendre en compte une nouvelle version.

On obtient lors du déploiement, le message suivant sur la console :

10:25:46,777 INFO  [TomcatDeployment] undeploy, ctxPath=/JaxWsContractFirst
10:25:46,899 INFO  [DefaultEndpointRegistry] remove: jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk
10:25:47,031 INFO  [DefaultEndpointRegistry] register: jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk
10:25:47,102 INFO  [TomcatDeployment] deploy, ctxPath=/JaxWsContractFirst
10:25:47,340 ERROR [JBossXSErrorHandler] JBossWS_demo.jl2tho.fr6970218092484449523.xsd[domain:http://www.w3.org/TR/xml-schema-1]::[key=src-resolve.4.2]::Message=src-resolve.4.2: Error resolving component 'ns1:QuestionId'. It was detected that 'ns1:QuestionId' is in namespace 'http://basic.demo.jl2tho.fr', but components from this namespace are not referenceable from schema document 'file:/C:/jboss-5.1.0.GA/server/default/tmp/jbossws/JBossWS_demo.jl2tho.fr6970218092484449523.xsd'. If this is the incorrect namespace, perhaps the prefix of 'ns1:QuestionId' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'file:/C:/jboss-5.1.0.GA/server/default/tmp/jbossws/JBossWS_demo.jl2tho.fr6970218092484449523.xsd'.
10:25:47,434 INFO  [WSDLFilePublisher] WSDL published to: file:/C:/jboss-5.1.0.GA/server/default/data/wsdl/JaxWsContractFirst.war/WebContractHelpdesk6191007714417398541.wsdl


En dépit du message d’erreur qui indique qu’il ne trouve pas la définition du type QuestionId, il est possible d’obtenir un WSDL à jour (il contient bien la référence au nouveau type QuestionId).

Pour le récupérer, on tape l’URL suivante http://127.0.0.1:8080/JaxWsContractFirst?wsdl.

Dans le navigateur, une fois le WSDL affiché, aller dans le menu “Enregistrer Sous…” et enregistrer votre fichier avec le nom JaxWsContractFirst.wsdl. Attention ! l’extension par défaut est XML.

Copier ce fichier dans le répertoire WebContent/WEB-INF/wsdl. Nous avons donc notre fichier WSDL local.

On modifie le fichier en ajoutant au début du fichier un import du xsd qu’on a créé précédemment. Comme ils sont dans le même répertoire, il n’est pas nécessaire de préciser un répertoire.

On obtient pour sa déclaration le code suivant :

<definitions name="WebContractHelpdesk" targetNamespace="http://demo.jl2tho.fr" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://demo.jl2tho.fr" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types>
  <xs:schema targetNamespace="http://demo.jl2tho.fr" version="1.0" xmlns:tns="http://demo.jl2tho.fr" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xsd:import namespace="http://basic.demo.jl2tho.fr" schemaLocation="HelpDeskBasic.xsd"/>
   <xs:element name="BusinessFault" nillable="true" type="tns:faultBean"/>
   <xs:element name="creerNouvelleQuestion" type="tns:creerNouvelleQuestion"/>
   <xs:element name="creerNouvelleQuestionResponse" type="tns:creerNouvelleQuestionResponse"/>

La déclaration va permettre au WSDL de savoir que si on fait référence au namespace http://basic.demo.jl2tho.fr, il doit chercher la définition dans le nouveau schéma XSD. Il faut faire attention à la correspondance avec le nom du fichier xsd.

Bean Webservice HelpdeskServiceBean

Pour finir, on modifie le bean implémentant le Web Service. L’annotation @WebService dispose d’un attribut wsdlLocation qui permet d’indiquer que l’on souhaite utiliser un WSDL local. Attention ! dans le cas de JBoss, il semble indispensable que le fichier WSDL soit sous WEB-INF.

On obtient pour sa déclaration le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless
@WebService(endpointInterface="fr.j2ltho.webcontracthelpdesk.server.IWebHelpDesk",
        portName="HelpdeskServicePort",  serviceName="WebContractHelpdesk",
        targetNamespace = "http://demo.jl2tho.fr",
        wsdlLocation="WEB-INF/wsdl/JaxWsContractFirst.wsdl")
public class HelpdeskServiceBean implements IWebHelpDesk {

    public String createQuestion(Question pNewQuestion)
            throws BusinessFaultException {
        if (pNewQuestion==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur Question nulle");
            faultBean.setCode("01");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

    public Question getQuestionWithId(String pNumero)
            throws BusinessFaultException {
        if (pNumero==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur : Numero de question nul");
            faultBean.setCode("02");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

}

On voit que la modification au WSDL généré est minimale : cela me permet d’opter pour régénération du WSDL plutôt que la modification du WSDL local lors d’une modification. Je retire le wsdlLocation, je déploie, je récupère le nouveau WSDL, je l’enregistre et je rajoute ma ligne d’import. Je termine en réactivant le wsdlLocation.

Je régénère mon war et le déploie de nouveau. Le message d’erreur dans la console JBoss a disparu. Si on affiche le WSDL on aura une ligne d’import qui apparait en début de WSDL. Elle diffère de celle que l’on a ajouté :

<definitions name="WebContractHelpdesk" targetNamespace="http://demo.jl2tho.fr">
<types>
<xs:schema targetNamespace="http://demo.jl2tho.fr" version="1.0">
<xsd:import namespace="http://basic.demo.jl2tho.fr" schemaLocation="http://127.0.0.1:8080/JaxWsContractFirst?wsdl&resource=HelpDeskBasic.xsd"/>
<xs:element name="BusinessFault" nillable="true" type="tns:faultBean"/>
<xs:element name="creerNouvelleQuestion" type="tns:creerNouvelleQuestion"/>
<xs:element name="creerNouvelleQuestionResponse" type="tns:creerNouvelleQuestionResponse"/>
<xs:element name="retrouverQuestionApartirId" type="tns:retrouverQuestionApartirId"/>
<xs:element name="retrouverQuestionApartirIdResponse" type="tns:retrouverQuestionApartirIdResponse"/>

Le même war se déploie parfaitement sous WebSphere 6.1. Attention ! l’url du WSDL est http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk?WSDL. Avec ce format d’adresse, Websphere sait afficher le WSDL qu’il faut utiliser. Dans notre cas il le remplace par http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/WEB-INF/wsdl/JaxWsContractFirst.wsdl alors que quand il s’agit d’un WSDL généré automatiquement, il le redirige vers http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/webcontracthelpdesk.wsdl (le WEB-INF/wsdl a été supprimé).

On constate que ce n’est pas parce que le WSDL est local, qu’il n’y a pas certaine modification : la définition de l’import change et le nœud soap:address qui contient l’URL du service web sont modifiés à la volée.

Conclusion

Nous avons terminé la partie de création du WSDL avec une approche Contract First. Nous avons obtenu le WSDL de notre choix avec le degré de précision que nous souhaitions.

Nous avons du aider JAX-WS et JAXB car dans la version 2.0, il n’est pas possible en se limitant aux annotations d’être suffisamment précis : il manque des contraintes sur les champs comme la longueur d’une chaine de caractères. La solution retenue repose sur un schéma complémentaire XSD définissant ses contraintes, conjointement utilisé avec un WSDL local afin d’être capable d’ajouter l’import de ce fichier XSD.

Cette approche est beaucoup plus efficace que la solution Axis2 que j’avais décrite en 2007 (voir le tutorial : http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html).

D’autre part, j’ai pu testé que le même WAR se déploie sur différents serveurs d’application : ce point est important car c’est l’objectif d’une norme comme JAX-WS. Toutefois, souvent, quand on essaie d’aller jusqu’au bout d’une norme censé apporter de la portabilité on se heurte à quelques détails qui cassent sur la fin la portabilité. Cela n’a pas été le cas dans notre exemple qui se veut pourtant complet.

Dans les étapes suivantes, nous allons créer un client puis nous allons coder “véritablement” le service web en introduisant Spring.

Etapes : 1 | 2 | 3 | 4 | 5 – Suivant >


DiggIt! Enregistrer sur Del.icio.us

vendredi, décembre 02, 2011

Etape 4 : Annotations JAX-WS et JAXB des classes

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

 

Il s’agit de la 4ieme étape d’un tutorial sur la création de service web JAX-WS. Cette étape s’appuie sur :

Dans cette partie nous allons annoter les objets métiers créés précédemment afin de les transformer en Service Web. L’objectif est d’utiliser les annotations afin d’obtenir une complète maitrise du WSDL généré. Dans cette étape on se concentre sur les possibilités des annotations. On ne complètera pas le fonctionnelle de notre service web. Le code restera identique.

Ce billet peut vous être utile si vous rechercher comment maitriser un aspect du WSDL en utilisant JAX-WS 2.0.

Nous allons annoter les éléments suivants :

  • l’interface et le bean afin de définir le service
  • l’objet métier Question et l’énumération Java afin de préciser la structure du XML permettant le stockage d’un objet Java.

Rappel des étapes du tutorial sur les services avec JAX-WS :

  1. Présentation du tutorial et de l'approche Contract First avec JAX-WS
  2. Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS
  3. Etape 3 : Création des objets métier et d’une exception JAX-WS
  4. Etape 4, Ce billet : Annotations JAX-WS et JAXB des classes

Les annotations JAX-WS

Les annotations JAX-WS se place sur l’interface et son implémentation : elles permettent de définir le service web. Le serveur d’application va les utiliser pour déployer le service web, générer le WSDL et assurer la correspondance entre les messages XML qui arrivent en entrée et l’appel de la méthode Java que l’on aura défini pour le traitement.

Pour une documentation de référence sur les annotations JAX-WS 2.0 vous pouvez vous reporter aux pages suivantes :

 

Interface IWebHelpDesk

C’est au niveau de l’interface qu’on a la plus grande maitrise sur la génération du WSDL :

  • on y définit le protocole utilisé
  • on y définit le nom de la majorité des nœuds XML

Au niveau de l’interface, nous définissons deux types d’annotations :

  • celles qui annotent l’interface directement : @Remote, @WebService et @SOAPBinding
  • celles qui annotent une méthode de l’interface : @WebMethod, @WebResult et @WebParam

Les premières permettent de définir le protocole des messages, comment on assemble les messages, le nom du service…

  • @WebService permet de définir le nom du PortType. Je surcharge systématiquement le targetNameSpace afin de donner une URL neutre (détachée du nom de mes classes). je réutilise la même URL partout. Attention ! une uRL a déjà été utilisée au niveau de la BusinessFaultException.
  • @SOAPBinding : j’utilise systématiquement Document, Literal et Wrapped qui sont les standards de fait (les plus utilisés). Cela m’assure que le client est capable d’accéder correctement au service indépendamment de la qualité de son implémentation.

Les secondes permettent de définir les éléments de base d’une opération : le nom des nœuds ou attributs XML. Ceux sont les annotations les plus déterminantes pour maitriser la forme du message XML et donc de la partie sensible du WSDL.

  • @WebMethod : indique le nom de l’opération du WSDL. Ce nom est également utilisé dans le mode WRAPPED comme nom du message en entrée du service et comme nom du message de réponse (dans ce dernier cas, on ajoute Response au nom). Dans l’exemple, j’ai volontairement pris un nom différent du nom de la méthode, mais il est préférable, dans la mesure du possible, de conserver un nom identique afin de faciliter la phase de test.
  • @WebResult : nom de l’objet XML encapsulant la valeur retournée.
  • @WebParam : permet d’indiquer le nom du paramètre (par défaut on a arg0…). Il s’agit d’un des éléments les plus importants pour maitriser le WSDL et pour le rendre compréhensible.

 

On modifie le code initiale avec les annotations suivantes, afin d’obtenir le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import javax.ejb.Remote;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@Remote
@WebService(name = "ISwHelpDeskPortType", targetNamespace = "
http://demo.jl2tho.fr" )
@SOAPBinding(style=Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle= SOAPBinding.ParameterStyle.WRAPPED)
public interface IWebHelpDesk {
   
    @WebMethod(operationName="retrouverQuestionApartirId")
    @WebResult(name = "QUESTION")
    public Question getQuestionWithId(
            @WebParam(name = "NUMERO")String pNumero
            ) throws BusinessFaultException;
   
    @WebMethod(operationName="creerNouvelleQuestion")
    @WebResult(name = "NUMERO")
    public String createQuestion(
            @WebParam(name = "INPUT_QUESTION") Question pNewQuestion
            ) throws BusinessFaultException;
}

Attention ! Pour que les annotations soit utilisables, il est indispensable d’avoir correctement définis les External Jars de votre projet Eclipse (voir Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS de ce tutorial).

Attention ! WebSphere 6.1 ne supporte pas bien les noms de paramètres avec un tiret (-). Le signe souligné (_) est préférable comme séparateur si vous décidez d’utiliser des noms en majuscule pour les nœuds XML.

 

Bean WebService

Au niveau du bean implémentant le Webservice, il n’y a pas grand chose à préciser si ce n’est le nom du WebService lui même.

Attention ! Dans une approche avec un WAR, il faut assurer la correspondance du nom avec celui indiqué dans le servlet-name de web.xml.

Pour les différents attributs de l’annotation WebService d’un bean nous avons :

  • endpointInterface : elle indique le nom de l’interface Java décrivant le service Web (dans notre cas IWebHelpDesk).
  • portName : la valeur est utilisée comme Port et Binding dans le WSDL. Il s’agit d’un élément de contrôle supplémentaire sur le WSDL mais je doute de l’intérêt de le surcharger.
  • serviceName : ce sera le nom du service web. Il correspond aux nœuds Definition et Service du WSDL. Il doit correspondre au servlet-name du web.xml : dans notre cas : WebContractHelpdesk
  • targetNamespace : je reprends le même que celui définit dans l’interface. Il s’agit plus pour moi d’éviter de voir apparaitre dans le WSDL des informations sur la structure du développement.

On modifie le code initial afin d’obtenir le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless
@WebService(endpointInterface="fr.j2ltho.webcontracthelpdesk.server.IWebHelpDesk",
        portName="HelpdeskServicePort",  serviceName="WebContractHelpdesk",
        targetNamespace = "
http://demo.jl2tho.fr")
public class HelpdeskServiceBean implements IWebHelpDesk {

    public String createQuestion(Question pNewQuestion)
            throws BusinessFaultException {
        if (pNewQuestion==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur Question nulle");
            faultBean.setCode("01");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

    public Question getQuestionWithId(String pNumero)
            throws BusinessFaultException {
        if (pNumero==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur : Numero de question nul");
            faultBean.setCode("02");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

}

On constate que l’impact sur l’implémentation du service Web est bien plus faible que sur l’interface.

Avec l’annotation de l’interface et de la classe implémentant le service web, on a définit une grande partie du WSDL. En fait si on travaille sur des types simples on a tout définis.

 

Annotation JAXB sur la classe Question

Néanmoins, dans le cadre d’un vrai service, il est fort probable qu’il vous faille échanger des données un peu plus structurées comme un objet.

Dans notre cas, nous avons un objet métier Question qui va nous permettre d’aborder ce point. En développement Java, il va de soi, qu’il s’agit d’une classe.

JAX-WS 2.0 travaille de pair avec JAXB 2.0 pour plier les objets Java. JAXB a également recours aux annotations pour préciser le pliage sous forme d’objet XML. Nous allons en utiliser 3 :

  • @XmlType : il s’agit du point départ. elle porte sur l’objet et elle indique que l’on souhaite surcharger le comportement par défaut de JAXB. Elle est un prérequis pur l’utilisation des deux autres. Je l’utilise pour surcharger le nom du type XML correspondant à l’objet. Attention ! Son nom est présent dans la partie Schema du WSDL, mais son nom n’intervient pas dans le balisage XML du message SOAP. C’est également lui qui permet de surcharger le comportement par défaut du targetNameSpace. Il permet pour finir de définir l’ordre d’apparition des propriétés, mais j’avoue ne pas très bien comprendre son utilité.
  • @XmlAccessorType : il permet de choisir entre deux façons de plier un objet Java en XML : XmlAccessType.FIELD dans ce cas, chaque propriété correspond à un nœud XML, XmlAccessType.ATTRIBUTE dans ce cas, il n’y a qu’un seul nœud XML pour l’objet et les propriétés correspondent à des attributs du nœud XML. Je pense que le plus robuste et standard est XmlAccessType.FIELD, c’est pour cela que je préfère son utilisation.
  • @XmlElement : Il se place au niveau de chaque propriété de la classe. Son utilisation nécessite l’annotation XmlType au niveau de la classe. Il permet de préciser le nom du nœud XML correspondant à la propriété. L’attribut required à true retire le minOccurs à 0 du WSDL.

Pour plus d’information sur JAXB, je vous renvoie au très bon article : http://blog.paumard.org/cours/jaxb-rest/chap01-jaxb-annotations.html.

On édite la classe Java Question pour modifier sa première partie. Les constructeurs et getter/setter ne sont pas modifiés.

Le début du code (jusqu’au constructeur) est modifié afin d’obtenir le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(name="QuestionType", propOrder = { "id", "description", "submitDate", "title", "product", "urgency", "priority", "type" })
@XmlAccessorType(XmlAccessType.FIELD)
public class Question {
    @XmlElement(name = "NUMERO")
    private String id;
    @XmlElement(name = "DESCRIPTION")
    private String description;
    @XmlElement(name = "SUBMITDATE")
    private Date submitDate;
    @XmlElement(name = "TITLE", required=true)
    private String title;
    @XmlElement(name = "PRODUCT")
    private String product;
    @XmlElement(name = "URGENCY")
    private UrgencyEnum urgency;
    @XmlElement(name = "PRIORITY", required=true)
    private String priority;
    @XmlElement(name = "TYPE")
    private String type;
   
    
    public Question() {
        super();
    }

Certaines annotations JAXB comme le nillable ne sont pas traitées par JAX-WS. Elles n’auront alors aucun effet sur le WSDL.

Attention ! Les annotations JAXB peuvent nécessiter un jar différent que celles de JAX-WS. C’est notamment le cas de JBoss 5.1 qui nécessite jaxb-api.jar.

Si vous avez suivi à la lettre mon Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS de ce tutorial et que vous utilisez JBoss 5.1, vous ne devriez pas avoir de problème.

XmlEnum et XmlEnumValue

Nous avions définis une énumération comme propriété, nous allons également annoter cette enum java afin de maitriser également sa transformation XML.

L’annotation XmlEnumValue permet de définir la chaine de caractères qui correspond à la valeur de l’énumération dans le message.

Editez UrgencyEnum et modifiez la afin d’obtenir le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;

@XmlType
@XmlEnum(String.class)
public enum UrgencyEnum {
    @XmlEnumValue("URGENCY_BUGINPROD") BUGINPROD,
    @XmlEnumValue("URGENCY_CONFIG") CONFIG,
    @XmlEnumValue("URGENCY_USAGE") USAGE,
    @XmlEnumValue("URGENCY_BUGINDEV") BUGINDEV
}

 

Conclusion

Nous avons finis d’annoter nos classes, interface et énumérations Java. Vous allez voir dans l’étape suivante à quoi correspond le WSDL généré automatiquement à partir de ces annotations.

Vous constaterez alors que nous avons une très grande maitrise grâce aux différentes annotations utilisées à cette étape. Nous n’avons pas progressé sur l’implémentation du service. Nous sommes bien encore dans une approche Contract First : jusqu’à présent tous nos efforts ont consisté à définir l’interface du service web.

Etapes : 1 | 2 | 3 | 4| 5Suivant >


DiggIt! Enregistrer sur Del.icio.us

mercredi, novembre 30, 2011

Etape 3 du tutorial : Création des objets métier et Exception JAX-WS

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

 

Il s’agit de la 3ieme étape d’un tutorial sur la création de service web JAX-WS. Cette étape s’appuie sur le projet Eclipse créé précédemment (http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html).

Dans cette partie nous allons créer les objets métiers indépendamment de l’aspect Web Service (les annotations seront ajoutées dans le billet suivant). La seule spécificité Web Service de cette étape est la définition d’une exception supportant les particularités de JAX-WS et son utilisation.

Nous allons voir, qu’avec JAX-WS, il faut spécialiser sa propre exception si on souhaite que le client du service puisse récupérer toutes les informations.

Nous allons créer les éléments suivants :

  • Question : il s’agit de l’objet métier qui sert à transporter une information structurée
  • l’exception métier pour le service
  • l’interface du service
  • le bean d’implémentation du service

Rappel des étapes du tutorial sur les services avec JAX-WS :

  1. Présentation du tutorial et de l'approche Contract First avec JAX-WS
  2. Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS
  3. Etape 3, Ce billet : Création des objets métier et d’une exception JAX-WS

 

L’objet métier Question

Il s’agit d’un objet métier, un simple POJO permettant le stockage des informations correspondant à la question. Comme il s’appuie sur une énumération pour la propriété Urgency, on commence par créer l’enum suivante : UrgencyEnum

Enumération UrgencyEnum

Dans Eclipse, à partir de la barre de menu : File -> New -> Enum.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : UrgencyEnum

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Il s’agit de définir les différentes valeurs de l’enum :

package fr.j2ltho.webcontracthelpdesk.server;

public enum UrgencyEnum {
    BUGINPROD, CONFIG, USAGE, BUGINDEV
}

 

Création de l’objet Question

L’objet Question est un objet métier qui sert à transporter une information structurée entre le client et le serveur de service web. Il me parait préférable de définir des objets métiers dédiés au service web plutôt que de réutiliser tel quel un objet existant :

  • l’objet est plus simple et probablement plus adapté aux besoins de l’utilisateur
  • vous évitez d’envoyer des informations confidentielles qui pourraient être disponibles dans l’objet métier existant

Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -> New -> Class.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : Question

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Il s’agit de définir les propriétés du bean et ses getter/setter. Nous avons également défini un constructeur.

package fr.j2ltho.webcontracthelpdesk.server;

import java.util.Date;

public class Question {
    private String id;
    private String description;
    private Date submitDate;
    private String title;
    private String product;
    private UrgencyEnum urgency;
    private String priority;
    private String type;
   
    public Question() {
        super();
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Date getSubmitDate() {
        return submitDate;
    }

    public void setSubmitDate(Date submitDate) {
        this.submitDate = submitDate;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public UrgencyEnum getUrgency() {
        return urgency;
    }

    public void setUrgency(UrgencyEnum urgency) {
        this.urgency = urgency;
    }

    public String getPriority() {
        return priority;
    }

    public void setPriority(String priority) {
        this.priority = priority;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

   
    }

 

Exception métier pour un service web

Par défaut, une exception java contient une propriété Message. C’est cette propriété qui contient l’information sur l’exception.

Pour les services web on parle de Fault. Il s’agit d’un message que peut renvoyer un service quand il juge qu’il y a une erreur. Cela est proche de l’exception Java, si ce n’est que JAX-WS n’indique pas la propriété Message d’une exception Java dans le WSDL. Cela rend son utilisation délicate pour une autre technologie. En revanche, JAX-WS recherche une propriété faultInfo.

Afin de rendre exploitable les exceptions, nous allons définir un bean FaultBean qui servira à stocker l’information de l’exception.

Puis nous définirons notre propre exception BusinessFaultException qui définira un getter pour récupérer la propriété faultinfo.

Création de l’objet FaultBean

Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -> New -> Class.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : FaultBean
  • Cocher la case : Constructor from superclass

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Il s’agit de définir les propriétés du bean et ses getter/setter.

Nous définissons deux propriétés (la liste est libre ainsi que les noms) :

  • code pour stocker un identifiant technique
  • businessMessage : pour stocker un libellé associé destiné à l’utilisateur

 

package fr.j2ltho.webcontracthelpdesk.server;

public class FaultBean {
    private String code;
    private String businessMessage;
   
    public FaultBean() {
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getBusinessMessage() {
        return businessMessage;
    }

    public void setBusinessMessage(String businessMessage) {
        this.businessMessage = businessMessage;
    }  
}

Création de l’exception BusinessFaultException

Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -> New -> Class.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : BusinessFaultException
  • Superclass : tapez exception est naviguez pour sélectionner : Exception – java.lang

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Il s’agit de d’ajouter la propriété faultInfo et son getter ainsi que deux constructeurs.

On ajoute également la propriété static serialVersionUID car une exception est serialisable.

Pour finir, on ajoute les annotations :

  • name sera le nom de la Fault dans la définition du service web
  • faultBean indique le nom de l’objet Java contenant l’information
  • targetNamespace indique l’espace nom pour les types XML

On obtient le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

import javax.xml.ws.WebFault;

@WebFault(name="BusinessFault", faultBean="fr.j2ltho.webcontracthelpdesk.server.FaultBean",
        targetNamespace = "http://demo.jl2tho.fr")
public class BusinessFaultException extends Exception {
    private static final long serialVersionUID = 3061940459819421533L;
    private FaultBean faultInfo;
    

    public BusinessFaultException(String internalMessage, FaultBean faultInfo, Throwable cause) {
        super(internalMessage, cause);
        this.faultInfo = faultInfo;
    }

    public BusinessFaultException(String internalMessage, FaultBean faultInfo) {
        super(internalMessage);
        this.faultInfo = faultInfo;
    }

    public FaultBean getFaultInfo() {
        return faultInfo;
    }

}

 

Interface et implémentation du service

Maintenant que les éléments nécessaires à la création du service (Objets métier et exception) existent, nous allons pouvoir créer le service lui même, ou du moins son prototype.

Interface IWebHelpDesk

Nous allons créer une interface avec deux méthodes :

  • getQuestionWithId prend une String et retourne une Question.
  • createQuestion qui prend un objet Question en entrée et qui retourne un numéro de question

Créons notre interface. Dans Eclipse, à partir de la barre de menu : File -> New -> Interface.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : IWebHelpDesk

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Il s’agit de d’ajouter les deux méthodes. On utilisera l’exception créée précédemment pour renvoyer un éventuel message en cas de problème.

On obtient le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

public interface IWebHelpDesk {
    public Question getQuestionWithId(String pNumero) throws BusinessFaultException;
    public String createQuestion(Question pNewQuestion) throws BusinessFaultException;
}

Bean Service HelpdeskServiceBean

Le nom de la classe Java implémentant l’interface doit correspondre à celle définie dans le web.xml pour la servlet. Dans notre cas, ce sera impérativement HelpdeskServiceBean.

Créons notre classe. Dans Eclipse, à partir de la barre de menu : File -> New –> Class.

Dans la dialogue New Java Class :

  • Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server
  • Pour Name tapez : HelpdeskServiceBean
  • Appuyez sur le bouton Add pour l’interface et choisir IWebHelpDesk - fr.j2ltho.webcontracthelpdesk.server

Laissez les autres options par défaut et appuyez sur Finish. Il faut maintenant compléter le code. Nous allons montrer l’utilisation d’une exception Web service sur les deux méthodes :

  • createQuestion retourne une exception si Question est nulle
  • getQuestionWithId retourne une exception si le numéro est nulle.

On obtient le code suivant :

package fr.j2ltho.webcontracthelpdesk.server;

public class HelpdeskServiceBean implements IWebHelpDesk {

    public String createQuestion(Question pNewQuestion)
            throws BusinessFaultException {
        if (pNewQuestion==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur Question nulle");
            faultBean.setCode("01");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

    public Question getQuestionWithId(String pNumero)
            throws BusinessFaultException {
        if (pNumero==null) {
            FaultBean faultBean = new FaultBean();
            faultBean.setBusinessMessage("Erreur : Numero de question nul");
            faultBean.setCode("02");
            // Le message dans l'exception est disponible dans l'exception recu
            // mais sa déclaration est absente du wsdl
            throw new BusinessFaultException("Internal Message" , faultBean );           
        }
        return null;
    }

}

On voit que l’utilisation d’une exception dans le cadre d’un service web est un peu plus compliqué qu’en Java traditionnel si on souhaite que le client puisse correctement récupérer les informations : dans un premier temps on crée notre FaultBean avec les informations transmises au client. Puis on crée l’exception avec ce FaultBean en paramètre.

Conclusion

Nous avons vu dans ce billet, le mécanisme de création d’une exception pour un service web.

Nous avons créé tous les objets Java qui vont être nécessaires à la définition de notre WSDL. Mais, comme vous avez pu le constater, ces objets sont vides : on ne peut pas dire que nous ayons codé. Nous sommes rester concentrer sur la définition du service.

Dans l’étape suivante : http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html, nous allons annoter nos objets Java afin que le WSDL correspondent à notre besoin.

Etapes : 1 | 2 | 3 | 4 | 5Suivant >


DiggIt! Enregistrer sur Del.icio.us

mardi, novembre 29, 2011

Etape 2 du Tutorial : Configuration d’un projet JAX-WS

0 commentaires
DiggIt! Enregistrer sur Del.icio.us

 

Il s’agit du second billet d’un tutorial sur l’approche Contract First avec JAX-WS.

Il suit le premier billet : http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html qui présentait le tutorial et expliquait son approche.

Dans cette étape nous allons définir la configuration du projet et créer le projet Eclipse.

La configuration d’un projet Eclipse pour un service web est relativement simple. il faut :

  1. définir le service web dans le web.xml
  2. ajouter les jars nécessaire à la compilation des annotations comme “externals jars”.

Nous allons créer un projet Eclipse JaxWsContractFirst.

Le nom du service web sera : WebContractHelpdesk et le bean qui l’implémentera sera : fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean .

Configuration

Pour plus de simplicité, je définis précisément mon environnement de travail, cela facilitera votre tâche si vous êtes dans la même configuration

  • Le développement a eu lieu sur un poste Windows 7 sous 64 bits. Cela aura un impact sur les noms des répertoires mais cela est très limité.
  • Le runtime et le jdk Java sont à la version 1.5.0_11.
  • Nous allons utiliser Eclipse : 3.5.2. Nous utilisons la distribution pour le développement JEE qui inclut le projet WTP. Ce projet permet la création d’un projet “Web Dynamic” que nous allons utiliser.

Le serveur d’application utilisé sera JBoss 5.1. Il est installé sous C:\jboss-5.1.0.GA conformément au tutorial suivant : http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html. Attention ! Je rappelle qu’une installation sous “Program files” ou tous répertoires contenant des espaces peut être source d’ennuis.

A partir du moment ou vous utilisez une version de Java supérieure ou égale à la 1.5 et un serveur d’application implémentant JAX-WS 2.0, ce tutorial devrait également fonctionner : il vous faudra néanmoins adapter à votre environnement certaine partie comme notamment la liste des externals jars.

Des éléments de configuration, c’est le serveur JBoss qui nécessite le plus grand effort d’adaptation pour suivre ce tutorial : j’utilise son utilitaire wsconsume pour générer le client, les Externals Jars nécessaires ont des noms et emplacements spécifiques à chaque serveur d’application et version, pour finir le déploiement et l’URL du WSDL dépendent également du serveur d’application.

Je vous encourage donc à utiliser JBoss 5.1 pour suivre ce tutorial.

 

Création du projet Eclipse

Nous allons créer un projet de type “Dynamic Web Project”. Il s’agit d’un type de projet Eclipse qui permet la création de WAR. Il crée l’organisation du projet permettant de disposer d’un répertoire WEB-INF et il crée un fichier web.xml.

Ceux qui ont suivi mes tutoriaux sous JBoss 4.2 ou 5.1, ont créé des projets Java simples car pour un Service Web très simple, nous n’avons pas besoin de ressources extérieures. Pour des projets plus proches de la réalité, il vous faudra accéder à d’autre ressources, configurer le fonctionnement de l’application… Tout cela nécessite un déploiement plus complexe qui est mieux géré à travers un WAR.

Dans Eclipse, on crée un projet de type “Dynamic Web Project” que l’on nommera JaxWsContractFirst. Ces projets permettent la création d’un WAR.

  1. Dans Eclipse, à partir de la barre de menu : File -> New –> Other.
  2. Dans la dialogue New, choisir le dossier “Web” puis le nœud “Dynamic Web Project”. Appuyez sur le bouton Next.
  3. Pour Project name, tapez : JaxWsContractFirst et laissez les autres options par défaut (Dans mon cas cela veut dire que j’utilise un runtime Tomcat 6.0 et un Java 1.5).
  4. Appuyez sur Finish. Acceptez le choix de la perspective si la dialogue « Open Associated Perspective » s’affiche.

 

Fichier web.xml et définition du service web

Dans le répertoire WebContent –> WEB-INF de votre projet, se trouve le fichier web.xml : il s’agit d’une caractéristique d’un “Dynamic Web project”.

En Java 1.5, le service web est un servlet. Nous allons ajouter la déclaration du servlet qui correspondra à notre service web : WebContractHelpdesk.

Editer ce fichier web.xml.

On ajoute la déclaration de la servlet qui correspondra au service web.

  • servlet-name correspond au serviceName de l’annotation WebService du bean implémentant le service web. C’est ce nom qui sera utilisé pour accéder au WSDL. Dans notre cas, ce sera WebContractHelpdesk.
  • servlet-class correspond au nom complet du bean qui implémente le service web : fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean

On obtient le code suivant :

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>JaxWsContractFirst</display-name>
<servlet>
<servlet-name>WebContractHelpdesk</servlet-name>
<servlet-class>fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WebContractHelpdesk</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>

 

Ajout des External Jars

Il s’agit de la partie qui dépend le plus du serveur d’application.

Nous allons ajouté les jars nécessaires à la compilation des annotations JAX-WS et JAXB. Nous avons besoin de ces jars uniquement pour la compilation. A l’exécution, nous utiliserons celles du serveur d’application. Nous ne voulons donc pas que lors de la construction du WAR, les jars soient inclus dans le WAR. Pour cela, il faut les définir comme “external Jars” dans le projet Eclipse.

Il faut importer des jar JBoss : cliquez droit sur le projet dans l’explorateur et choisissez Properties. Dans la dialogue qui s’ouvre choisir « Java Build Path ».

Appuyer sur « Add External Jars.. », et utiliser l’explorateur pour aller dans le répertoire C:\jboss-5.1.0.GA\common\lib et sélectionnez les jar suivant :

  • Jboss-javaee.jar qui définit les annotations @Stateless et @Remote
  • Jbossws-native-jaxws.jar qui définit les annotations @WebService, @SOAPBinding et @SOAPBinding

Validez en appuyant sur Ok et appuyez de nouveau sur « Add External Jars.. », et utiliser l’explorateur pour aller dans le répertoire C:\jboss-5.1.0.GA\lib\endorsed et sélectionnez le jar suivant :

  • jaxb-api.jar qui définit les annotations @XmlElement

Validez en appuyant sur Ok.

 

Je disais, en entrée que cette partie dépend du serveur d’application. Il peut être particulièrement délicat, de trouver les bon jars et leur emplacement.

Par exemple pour WebSphere 6.1, il faut les jars :

  • com.ibm.jaxws.thinclient_6.1.0.jar dans C:\IBM\Websphere\AppServer\runtimes\
  • j2ee.jar dans C:\IBM\Websphere\AppServer\lib\

On voit que le nom, l’emplacement et leur nombre n’ont rien à voir.

Conclusion

Nous avons créer un projet Eclipse JaxWsContractFirst.

Nous avons modifié sa configuration afin que le nom du service web soit : WebContractHelpdesk et le bean qui l’implémentera sera : fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean.

L’étape suivante va consister à créer les objets java nécessaires à la définition du service (dont le bean fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean).

Comme indiqué en première partie, nous nous limiterons aux prototypes de ces classes dans cette étape.

Etapes : 1 | 2 | 3 | 4 | 5Suivant >


DiggIt! Enregistrer sur Del.icio.us