<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-36895966</id><updated>2012-01-18T00:52:32.040+02:00</updated><category term='Dojo'/><category term='JPA'/><category term='JBoss'/><category term='GWT'/><category term='Microsoft'/><category term='MySQL'/><category term='REST'/><category term='Javascript'/><category term='Outlook'/><category term='Hibernate'/><category term='wsdl2java'/><category term='Synchronisation'/><category term='NatStar'/><category term='BPM'/><category term='Tutorial'/><category term='wsdl'/><category term='Oracle'/><category term='Java'/><category term='Web 2.0'/><category term='SOA'/><category term='WebSphere'/><category term='Google'/><category term='Ajax'/><category term='Blogging'/><category term='ITIL'/><category term='Tomcat'/><category term='Flash'/><category term='Echo2'/><category term='Mashup'/><category term='Firefox'/><category term='iPhone'/><category term='Service Web'/><category term='ejb'/><category term='Eclipse'/><category term='Actionscript'/><category term='Revue'/><category term='Flex'/><category term='JAX-WS'/><category term='Free'/><category term='Spring'/><category term='JUnit'/><category term='iPad'/><category term='HsqDb'/><category term='Axis2'/><category term='Windows 7'/><title type='text'>Architecture des S.I.</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default?start-index=101&amp;max-results=100'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>109</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-36895966.post-5825908596401073305</id><published>2011-12-05T14:48:00.001+02:00</published><updated>2011-12-05T15:01:02.186+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSphere'/><category scheme='http://www.blogger.com/atom/ns#' term='JAX-WS'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><title type='text'>Etape 5 : Déployer un Service Web et compléter son WSDL</title><content type='html'>&lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Cette étape s’appuie sur :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’étape précédente qui a permis l’annotation des classes métiers précédemment créées &lt;a href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;Etape 4 : Annotations JAX-WS et JAXB des classes&lt;/a&gt;. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Rappel des étapes du tutorial sur les services avec JAX-WS :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;Présentation du tutorial et de l'approche Contract First avec JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;Etape 3 : Création des objets métier et d’une exception JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;Etape 4 : Annotations JAX-WS et JAXB des classes&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Etape 5, Ce billet : Déployer un Service Web et compléter son WSDL &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Déployer un service web&lt;/h2&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html" href="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html"&gt;http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html&lt;/a&gt; : pour WebSphere 6.1 &lt;/li&gt;    &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt; : Pour JBoss 5.1 &lt;/li&gt;    &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html" href="http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html"&gt;http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html&lt;/a&gt; : Pour JBoss 4.2 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Dans notre cas, nous allons créer un WAR puis le déployer sur le serveur d’application.&lt;/p&gt;  &lt;h3&gt;Génération du War&lt;/h3&gt;  &lt;p&gt;Assurez vous d’avoir bien sauvegarder l’ensemble des fichiers.&lt;/p&gt;  &lt;p&gt;Cliquez droit dans l’explorateur de ressource d’Eclipse sur votre projet JaxWsContractFirst, sélectionnez Export –&amp;gt; WAR File, dans la dialogue « Export » qui s’affiche choisissez :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Web Project : JaxWsContractFirst qui est le nom de votre projet &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;Décochez l’option “Optimize for a specific server runtime” &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-89xav5DZqbc/Tty9dUqj9cI/AAAAAAAAFek/VV9P4j056aA/s1600-h/ExportWar1.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ExportWar" border="0" alt="ExportWar" src="http://lh4.ggpht.com/-0BHzEWcaXPU/Tty9eTAGZnI/AAAAAAAAFes/b9MKQxeMgZs/ExportWar_thumb.png?imgmax=800" width="567" height="430" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Appuyez, ensuite sur Finish. Vous devriez trouver un fichier JaxWsContractFirst.war sur le bureau.&lt;/p&gt;  &lt;h3&gt;Déployer le war&lt;/h3&gt;  &lt;p&gt;Cette partie est très spécifique de votre serveur d’application. Je me contente du cas JBoss 5.1.&lt;/p&gt;  &lt;p&gt;Pour WebSphere, je vous renvoie à mon tutoriel : &lt;a title="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html" href="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html"&gt;http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;div class="code"&gt;12:08:51,352 INFO [DefaultEndpointRegistry] register: jboss.ws:context=JaxWsContractFirst,endpoint=&lt;strong&gt;WebContractHelpdesk&lt;/strong&gt;     &lt;br /&gt;12:08:51,778 INFO [TomcatDeployment] deploy, ctxPath=/&lt;strong&gt;JaxWsContractFirst&lt;/strong&gt;     &lt;br /&gt;12:08:52,555 INFO [WSDLFilePublisher] WSDL published to: file:/C:/jboss-5.1.0.GA/server/default/data/wsdl/JaxWsContractFirst.war/WebContractHelpdesk7856945428892376495.wsdl&lt;/div&gt;  &lt;p&gt;On y retrouve le nom du War que l’on a déployé et le nom du service web (le endpoint).&lt;/p&gt;  &lt;p&gt;Si on tape l’url suivante dans un browser : &lt;a href="http://localhost:8080/jbossws/services"&gt;http://localhost:8080/jbossws/services&lt;/a&gt; une page JBossWS/Services s’affiche. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-T73eo82f8cI/Tty9fTuWNGI/AAAAAAAAFe0/VwKbO-M3VYM/s1600-h/JBossEndpoint3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="JBossEndpoint" border="0" alt="JBossEndpoint" src="http://lh5.ggpht.com/-5PHZGhzCcvA/Tty9gNqkkHI/AAAAAAAAFe8/WbO5F_ZkBxw/JBossEndpoint_thumb1.png?imgmax=800" width="660" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;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 : &lt;a href="http://127.0.0.1:8080/JaxWsContractFirst?wsdl"&gt;http://127.0.0.1:8080/JaxWsContractFirst?wsdl&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Attention ! les URLs dépendent des serveurs d’application. On a par exemple, pour obtenir le WSDL :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour JBoss 5.1 : &lt;a title="http://127.0.0.1:8080/JaxWsContractFirst?wsdl" href="http://127.0.0.1:8080/JaxWsContractFirst?wsdl"&gt;http://127.0.0.1:8080/JaxWsContractFirst?wsdl&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Pour WebSphere 6.1 : &lt;a title="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk" href="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk?WSDL"&gt;http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk?WSDL&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Analyse du WSDL généré&lt;/h2&gt;  &lt;p&gt;En cliquant sur le lien précédent : &lt;a title="http://127.0.0.1:8080/JaxWsContractFirst?wsdl" href="http://127.0.0.1:8080/JaxWsContractFirst?wsdl"&gt;http://127.0.0.1:8080/JaxWsContractFirst?wsdl&lt;/a&gt; on affiche le WSDL du service.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Nous allons analyser succinctement son contenu afin de mettre en évidence les correspondances entre les annotations et le contenu du WSDL.&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’objet Question : comment un objet Java apparait dans le WSDL &lt;/li&gt;    &lt;li&gt;l’énumération &lt;/li&gt;    &lt;li&gt;le FaultBean qui permet de transférer une exception vers le client &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;L’objet Question&lt;/h3&gt;  &lt;p&gt;Il devient un ComplexType, son type QuestionType correspond à l’annotation XmlType.&lt;/p&gt;  &lt;p&gt;On constate que les name des différents éléments correspondent à l’annotation XmlElement.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;QuestionType&amp;quot;&amp;gt;      &lt;br /&gt;&amp;lt;xs:sequence&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;NUMERO&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;DESCRIPTION&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;SUBMITDATE&amp;quot; type=&amp;quot;xs:dateTime&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;TITLE&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;PRODUCT&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;URGENCY&amp;quot; type=&amp;quot;tns:urgencyEnum&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;PRIORITY&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;TYPE&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;/xs:sequence&amp;gt;       &lt;br /&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On remarque qu’on utilise des types simples provenant du schéma xs,&amp;#160; à l’exception de URGENCY qui pointe vers le schéma tns (c’est le WSDL) et plus particulièrement vers notre type énumération.&lt;/p&gt;  &lt;p&gt;Si on compare avec le WSDL généré par Axis2 à l’étape : &lt;a title="http://jl2tho.blogspot.com/2007/05/etape-5-tutorial-axis2-gnration-des.html" href="http://jl2tho.blogspot.com/2007/05/etape-5-tutorial-axis2-gnration-des.html"&gt;http://jl2tho.blogspot.com/2007/05/etape-5-tutorial-axis2-gnration-des.html&lt;/a&gt; dans notre tutorial &lt;a href="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html"&gt;Services web avec Axis2 : Approche Contract First&lt;/a&gt;, on avait pour l’objet Question :&lt;/p&gt;  &lt;div class="code"&gt;&amp;lt;xsd:complexType name=&amp;quot;Question&amp;quot;&amp;gt;    &lt;br /&gt;&amp;lt;xsd:sequence&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Numero&amp;quot; type=&amp;quot;tns:QuestionID&amp;quot;&amp;gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;SubmitDate&amp;quot; type=&amp;quot;xsd:date&amp;quot;&amp;gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Product&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;xsd:restriction base=&amp;quot;xsd:string&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:length value=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;/xsd:length&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:restriction&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Type&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;xsd:restriction base=&amp;quot;xsd:string&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:enumeration value=&amp;quot;BUGINPROD&amp;quot;&amp;gt;&amp;lt;/xsd:enumeration&amp;gt;     &lt;br /&gt;&amp;lt;xsd:enumeration value=&amp;quot;CONFIG&amp;quot;&amp;gt;&amp;lt;/xsd:enumeration&amp;gt;     &lt;br /&gt;&amp;lt;xsd:enumeration value=&amp;quot;USAGE&amp;quot;&amp;gt;&amp;lt;/xsd:enumeration&amp;gt;     &lt;br /&gt;&amp;lt;xsd:enumeration value=&amp;quot;BUGINDEV&amp;quot;&amp;gt;&amp;lt;/xsd:enumeration&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:restriction&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Priority&amp;quot; type=&amp;quot;tns:Urgency&amp;quot;&amp;gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Description&amp;quot; type=&amp;quot;xsd:string&amp;quot;&amp;gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;xsd:element name=&amp;quot;Title&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;xsd:restriction base=&amp;quot;xsd:string&amp;quot;&amp;gt;     &lt;br /&gt;&amp;lt;xsd:maxLength value=&amp;quot;250&amp;quot;&amp;gt;&amp;lt;/xsd:maxLength&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:restriction&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:simpleType&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:element&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:sequence&amp;gt;     &lt;br /&gt;&amp;lt;/xsd:complexType&amp;gt;&lt;/div&gt;  &lt;p&gt;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) :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le type de SubmitDate est date au lieu de dateTime &lt;/li&gt;    &lt;li&gt;l’énumération est directement incluse dans le type, dans notre cas elle est externalisée. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;avec axis2, on a pu utiliser un type simple externe QuestionID permettant de préciser les contraintes sur le contenu du nœud.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Enumération&lt;/h3&gt;  &lt;p&gt;On avait surchargé les valeurs des énumérations par annotation, on voit qu’on retrouve un SimpleType qui reprend ces valeurs.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:simpleType name=&amp;quot;urgencyEnum&amp;quot;&amp;gt;      &lt;br /&gt;&amp;lt;xs:restriction base=&amp;quot;xs:string&amp;quot;&amp;gt;       &lt;br /&gt;&amp;lt;xs:enumeration value=&amp;quot;URGENCY_BUGINPROD&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:enumeration value=&amp;quot;URGENCY_CONFIG&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:enumeration value=&amp;quot;URGENCY_USAGE&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:enumeration value=&amp;quot;URGENCY_BUGINDEV&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;/xs:restriction&amp;gt;       &lt;br /&gt;&amp;lt;/xs:simpleType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Exception et Fault&lt;/h3&gt;  &lt;p&gt;Nos méthodes pouvaient renvoyer une exception, on retrouve cette possibilité dans la définition de l’opération :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;operation name=&amp;quot;creerNouvelleQuestion&amp;quot; parameterOrder=&amp;quot;creerNouvelleQuestion&amp;quot;&amp;gt;      &lt;br /&gt;&amp;lt;input message=&amp;quot;tns:ISwHelpDeskPortType_creerNouvelleQuestion&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;output message=&amp;quot;tns:ISwHelpDeskPortType_creerNouvelleQuestionResponse&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;fault message=&amp;quot;tns:BusinessFault&amp;quot; name=&amp;quot;BusinessFault&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;/operation&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On a un attribut fault pour nos opérations.&lt;/p&gt;  &lt;p&gt;Par rebond, on arrive à la définition du beanFault :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;faultBean&amp;quot;&amp;gt;      &lt;br /&gt;&amp;lt;xs:sequence&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;businessMessage&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;xs:element minOccurs=&amp;quot;0&amp;quot; name=&amp;quot;code&amp;quot; type=&amp;quot;xs:string&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;lt;/xs:sequence&amp;gt;       &lt;br /&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On voit qu’il contient les deux propriétés qu’on avait définies.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;h2&gt;Compléter le WSDL&lt;/h2&gt;  &lt;p&gt;Nous avons deux éléments en écart par rapport à ce qu’on pouvait faire dans l’approche Axis2 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le format d’un champ date &lt;/li&gt;    &lt;li&gt;la possibilité de définir des contraintes plus fortes sur un type simple &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Propriété de type Date&lt;/h3&gt;  &lt;p&gt;La documentation officielle d’Oracle (&lt;a href="http://docs.oracle.com/cd/E17802_01/webservices/webservices/reference/tutorials/wsit/doc/DataBinding2.html"&gt;http://docs.oracle.com/cd/E17802_01/webservices/webservices/reference/tutorials/wsit/doc/DataBinding2.html&lt;/a&gt;) 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.&lt;/p&gt;  &lt;p&gt;Pour information, les outils qui génère du Java à partir du WSDL vont généralement vers ce type XMLGregorianCalendar.&lt;/p&gt;  &lt;p&gt;On va donc modifier doublement la déclaration de notre propriété submitDate dans l’objet Question :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;on change son type java &lt;/li&gt;    &lt;li&gt;on lui ajoute une annotation XmlSchemaType afin de préciser qu’on souhaite un type date et non plus dateTime. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient pour sa déclaration le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;SUBMITDATE&amp;quot;)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @XmlSchemaType(name=&amp;quot;date&amp;quot;)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public javax.xml.datatype.XMLGregorianCalendar submitDate;       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il faudra également penser à mettre à son jour son getter et son setter.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Propriété de type Token ou normalizedString&lt;/h3&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;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.&lt;/li&gt;    &lt;li&gt;normalizedString va un cran plus loin, car il interdit la présence de tel caractère.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;p&gt;On obtient pour sa déclaration le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;@XmlType(name=&amp;quot;QuestionType&amp;quot;, propOrder = { &amp;quot;id&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;submitDate&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;product&amp;quot;, &amp;quot;urgency&amp;quot;, &amp;quot;priority&amp;quot;, &amp;quot;type&amp;quot; })     &lt;br /&gt;@XmlAccessorType(XmlAccessType.FIELD)      &lt;br /&gt;public class Question {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;NUMERO&amp;quot;)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String id;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;DESCRIPTION&amp;quot;)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String description;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;SUBMITDATE&amp;quot;)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @XmlSchemaType(name=&amp;quot;date&amp;quot;)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public javax.xml.datatype.XMLGregorianCalendar submitDate;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;TITLE&amp;quot;, required=true)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String title;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;PRODUCT&amp;quot;)     &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlSchemaType(name=&amp;quot;token&amp;quot;)       &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String product;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;URGENCY&amp;quot;)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private UrgencyEnum urgency;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;PRIORITY&amp;quot;, required=true)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String priority;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;TYPE&amp;quot;)     &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlSchemaType(name=&amp;quot;normalizedString&amp;quot;)       &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String type;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&lt;/p&gt; …&lt;/div&gt;  &lt;p&gt;On a mis en gras les modifications. &lt;/p&gt;  &lt;p&gt;Il n’est pas nécessaire de modifier les getter et setters.&lt;/p&gt;  &lt;h3&gt;&amp;#160;&lt;/h3&gt;  &lt;h3&gt;Ajouter des contraintes à un type simple&lt;/h3&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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).&lt;/p&gt;  &lt;h4&gt;Fichier XSD pour les contraintes&lt;/h4&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;On se place sur le nœud WEB-INF dans WebContent, et on clique droit, choisir New –&amp;gt; Other… Dans la dialogue qui s’ouvre choisir Folder dans le nœud General. Le nom du dossier sera wsdl puis validez.&lt;/p&gt;  &lt;p&gt;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 –&amp;gt; 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.&lt;/p&gt;  &lt;p&gt;Ajoutez, le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;      &lt;br /&gt;&amp;lt;schema xmlns:tns=&amp;quot;&lt;a href="http://basic.demo.jl2tho.fr&amp;quot;"&gt;http://basic.demo.jl2tho.fr&amp;quot;&lt;/a&gt; xmlns=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/a&gt; targetNamespace=&amp;quot;&lt;a href="http://basic.demo.jl2tho.fr&amp;quot;"&gt;http://basic.demo.jl2tho.fr&amp;quot;&lt;/a&gt;&amp;gt;       &lt;br /&gt;&amp;lt;simpleType name=&amp;quot;QuestionId&amp;quot;&amp;gt;       &lt;br /&gt;&amp;lt;annotation&amp;gt;       &lt;br /&gt;&amp;lt;documentation&amp;gt;Type pour un numero de question&amp;lt;/documentation&amp;gt;       &lt;br /&gt;&amp;lt;/annotation&amp;gt;       &lt;br /&gt;&amp;lt;restriction base=&amp;quot;string&amp;quot;&amp;gt;       &lt;br /&gt;&amp;lt;length value=&amp;quot;9&amp;quot;&amp;gt;&amp;lt;/length&amp;gt;       &lt;br /&gt;&amp;lt;pattern value=&amp;quot;\d*&amp;quot;&amp;gt;&amp;lt;/pattern&amp;gt;       &lt;br /&gt;&amp;lt;/restriction&amp;gt;       &lt;br /&gt;&amp;lt;/simpleType&amp;gt;       &lt;br /&gt;&amp;lt;/schema&amp;gt;       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il est important de noter qu’on utilise pour ce fichier un namespace différent de celui du WSDL en l’occurrence : &lt;a href="http://basic.demo.jl2tho.fr"&gt;http://basic.demo.jl2tho.fr&lt;/a&gt;. 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.&lt;/p&gt;  &lt;h4&gt;Utilisation d’un type propriétaire avec JAXB&lt;/h4&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;On obtient pour sa déclaration le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;@XmlElement(name = &amp;quot;NUMERO&amp;quot;)      &lt;br /&gt;&lt;strong&gt;@XmlSchemaType(name=&amp;quot;QuestionId&amp;quot;, namespace=&amp;quot;&lt;/strong&gt;&lt;a href="http://basic.demo.jl2tho.fr&amp;quot;)"&gt;&lt;strong&gt;http://basic.demo.jl2tho.fr&amp;quot;)&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;        &lt;br /&gt;&lt;/strong&gt;private String id;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il n’est pas nécessaire de mettre à jour son getter et son setter puisqu’on a juste ajouter une annotation.&lt;/p&gt;  &lt;h4&gt;Création du fichier WSDL local&lt;/h4&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;On obtient lors du déploiement, le message suivant sur la console :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;10:25:46,777 INFO&amp;#160; [TomcatDeployment] undeploy, ctxPath=/JaxWsContractFirst     &lt;br /&gt;10:25:46,899 INFO&amp;#160; [DefaultEndpointRegistry] remove: jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk      &lt;br /&gt;10:25:47,031 INFO&amp;#160; [DefaultEndpointRegistry] register: jboss.ws:context=JaxWsContractFirst,endpoint=WebContractHelpdesk      &lt;br /&gt;10:25:47,102 INFO&amp;#160; [TomcatDeployment] deploy, ctxPath=/JaxWsContractFirst      &lt;br /&gt;10:25:47,340 ERROR [JBossXSErrorHandler] JBossWS_demo.jl2tho.fr6970218092484449523.xsd[domain:&lt;a href="http://www.w3.org/TR/xml-schema-1]::[key=src-resolve.4.2]::Message"&gt;http://www.w3.org/TR/xml-schema-1]::[key=src-resolve.4.2]::Message&lt;/a&gt;=src-resolve.4.2: Error resolving component 'ns1:QuestionId'. It was detected that 'ns1:QuestionId' is in namespace '&lt;a href="http://basic.demo.jl2tho.fr'"&gt;http://basic.demo.jl2tho.fr'&lt;/a&gt;, 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'.      &lt;br /&gt;10:25:47,434 INFO&amp;#160; [WSDLFilePublisher] WSDL published to: file:/C:/jboss-5.1.0.GA/server/default/data/wsdl/JaxWsContractFirst.war/WebContractHelpdesk6191007714417398541.wsdl&lt;/p&gt;    &lt;p&gt;     &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;    &lt;p&gt;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). &lt;/p&gt;  &lt;p&gt;Pour le récupérer, on tape l’URL suivante &lt;a href="http://127.0.0.1:8080/JaxWsContractFirst?wsdl"&gt;http://127.0.0.1:8080/JaxWsContractFirst?wsdl&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Copier ce fichier dans le répertoire WebContent/WEB-INF/wsdl. Nous avons donc notre fichier WSDL local.&lt;/p&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;On obtient pour sa déclaration le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;definitions name=&amp;quot;WebContractHelpdesk&amp;quot; targetNamespace=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt; xmlns=&amp;quot;&lt;a href="http://schemas.xmlsoap.org/wsdl/&amp;quot;"&gt;http://schemas.xmlsoap.org/wsdl/&amp;quot;&lt;/a&gt; xmlns:soap=&amp;quot;&lt;a href="http://schemas.xmlsoap.org/wsdl/soap/&amp;quot;"&gt;http://schemas.xmlsoap.org/wsdl/soap/&amp;quot;&lt;/a&gt; xmlns:tns=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt; xmlns:xsd=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/a&gt;&amp;gt;       &lt;br /&gt;&amp;lt;types&amp;gt;       &lt;br /&gt;&amp;#160; &amp;lt;xs:schema targetNamespace=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt; version=&amp;quot;1.0&amp;quot; xmlns:tns=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt; xmlns:xs=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/a&gt;&amp;gt;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160; &amp;lt;xsd:import namespace=&amp;quot;&lt;/strong&gt;&lt;a href="http://basic.demo.jl2tho.fr&amp;quot;"&gt;&lt;strong&gt;http://basic.demo.jl2tho.fr&amp;quot;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; schemaLocation=&amp;quot;HelpDeskBasic.xsd&amp;quot;/&amp;gt;        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160; &amp;lt;xs:element name=&amp;quot;BusinessFault&amp;quot; nillable=&amp;quot;true&amp;quot; type=&amp;quot;tns:faultBean&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160; &amp;lt;xs:element name=&amp;quot;creerNouvelleQuestion&amp;quot; type=&amp;quot;tns:creerNouvelleQuestion&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160; &amp;lt;xs:element name=&amp;quot;creerNouvelleQuestionResponse&amp;quot; type=&amp;quot;tns:creerNouvelleQuestionResponse&amp;quot;/&amp;gt;       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;La déclaration va permettre au WSDL de savoir que si on fait référence au namespace &lt;a href="http://basic.demo.jl2tho.fr&amp;quot;"&gt;&lt;strong&gt;http://basic.demo.jl2tho.fr&lt;/strong&gt;&lt;/a&gt;, il doit chercher la définition dans le nouveau schéma XSD. Il faut faire attention à la correspondance avec le nom du fichier xsd.&lt;/p&gt;  &lt;h4&gt;Bean Webservice HelpdeskServiceBean &lt;/h4&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;On obtient pour sa déclaration le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;import javax.ejb.Stateless;      &lt;br /&gt;import javax.jws.WebService;&lt;/p&gt;    &lt;p&gt;@Stateless      &lt;br /&gt;@WebService(endpointInterface=&amp;quot;fr.j2ltho.webcontracthelpdesk.server.IWebHelpDesk&amp;quot;,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; portName=&amp;quot;HelpdeskServicePort&amp;quot;,&amp;#160; serviceName=&amp;quot;WebContractHelpdesk&amp;quot;,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; targetNamespace = &amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt;,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;wsdlLocation=&amp;quot;WEB-INF/wsdl/JaxWsContractFirst.wsdl&lt;/strong&gt;&amp;quot;)       &lt;br /&gt;public class HelpdeskServiceBean implements IWebHelpDesk {&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String createQuestion(Question pNewQuestion)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNewQuestion==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur Question nulle&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;01&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public Question getQuestionWithId(String pNumero)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNumero==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur : Numero de question nul&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;02&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;}      &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;        &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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é :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;definitions name=&amp;quot;WebContractHelpdesk&amp;quot; targetNamespace=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt;&amp;gt;      &lt;br /&gt;&amp;lt;types&amp;gt;      &lt;br /&gt;&amp;lt;xs:schema targetNamespace=&amp;quot;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;http://demo.jl2tho.fr&amp;quot;&lt;/a&gt; version=&amp;quot;1.0&amp;quot;&amp;gt;      &lt;br /&gt;&lt;strong&gt;&amp;lt;xsd:import namespace=&amp;quot;&lt;/strong&gt;&lt;a href="http://basic.demo.jl2tho.fr&amp;quot;"&gt;&lt;strong&gt;http://basic.demo.jl2tho.fr&amp;quot;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; schemaLocation=&amp;quot;&lt;/strong&gt;&lt;a href="http://127.0.0.1:8080/JaxWsContractFirst?wsdl&amp;amp;resource=HelpDeskBasic.xsd&amp;quot;/"&gt;&lt;strong&gt;http://127.0.0.1:8080/JaxWsContractFirst?wsdl&amp;amp;resource=HelpDeskBasic.xsd&amp;quot;/&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&amp;gt;       &lt;br /&gt;&lt;/strong&gt;&amp;lt;xs:element name=&amp;quot;BusinessFault&amp;quot; nillable=&amp;quot;true&amp;quot; type=&amp;quot;tns:faultBean&amp;quot;/&amp;gt;      &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;creerNouvelleQuestion&amp;quot; type=&amp;quot;tns:creerNouvelleQuestion&amp;quot;/&amp;gt;      &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;creerNouvelleQuestionResponse&amp;quot; type=&amp;quot;tns:creerNouvelleQuestionResponse&amp;quot;/&amp;gt;      &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;retrouverQuestionApartirId&amp;quot; type=&amp;quot;tns:retrouverQuestionApartirId&amp;quot;/&amp;gt;      &lt;br /&gt;&amp;lt;xs:element name=&amp;quot;retrouverQuestionApartirIdResponse&amp;quot; type=&amp;quot;tns:retrouverQuestionApartirIdResponse&amp;quot;/&amp;gt;       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le même war se déploie parfaitement sous WebSphere 6.1. Attention ! l’url du WSDL est &lt;a href="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk?WSDL"&gt;http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk?WSDL&lt;/a&gt;. Avec ce format d’adresse, Websphere sait afficher le WSDL qu’il faut utiliser. Dans notre cas il le remplace par &lt;a title="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/WEB-INF/wsdl/JaxWsContractFirst.wsdl" href="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/WEB-INF/wsdl/JaxWsContractFirst.wsdl"&gt;http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/WEB-INF/wsdl/JaxWsContractFirst.wsdl&lt;/a&gt; alors que quand il s’agit d’un WSDL généré automatiquement, il le redirige vers &lt;a title="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/webcontracthelpdesk.wsdl" href="http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/webcontracthelpdesk.wsdl"&gt;http://localhost:9080/JaxWsContractFirst/WebContractHelpdesk/webcontracthelpdesk.wsdl&lt;/a&gt; (le WEB-INF/wsdl a été supprimé).&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Cette approche est beaucoup plus efficace que la solution Axis2 que j’avais décrite en 2007 (voir le tutorial : &lt;a title="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html" href="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html"&gt;http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Dans les étapes suivantes, nous allons créer un client puis nous allons coder “véritablement” le service web en introduisant Spring.&lt;/p&gt;  &lt;p&gt;Etapes : &lt;a title="Présentation du tutorial et de l&amp;#39;approche Contract First avec JAX-WS" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;1&lt;/a&gt; | &lt;a title="Etape 2 : Configuration d&amp;#39;un projet Eclipse pour un WebService JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;2&lt;/a&gt; | &lt;a title="Etape 3 : Création des objets métiers et d&amp;#39;une exception JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;3&lt;/a&gt; | &lt;a title="Etape 4 : Annotations JAX-WS et JAXB des classes" href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;4&lt;/a&gt; | &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;5&lt;/a&gt; – Suivant &amp;gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-5825908596401073305?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/5825908596401073305/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=5825908596401073305&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/5825908596401073305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/5825908596401073305'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html' title='Etape 5 : Déployer un Service Web et compléter son WSDL'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/-0BHzEWcaXPU/Tty9eTAGZnI/AAAAAAAAFes/b9MKQxeMgZs/s72-c/ExportWar_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-1321315063066827513</id><published>2011-12-02T12:28:00.001+02:00</published><updated>2011-12-05T15:11:41.607+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JAX-WS'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><title type='text'>Etape 4 : Annotations JAX-WS et JAXB des classes</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Il s’agit de la 4ieme étape d’un tutorial sur la création de service web JAX-WS. Cette étape s’appuie sur :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le projet Eclipse créé précédemment (&lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html&lt;/a&gt;) qui référencent les jars contenant les annotations &lt;/li&gt;    &lt;li&gt;les objets Java (classe métier, interface et bean de service) créés à l’étape précédente &lt;a href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;Etape 3 : Création des objets métier et d’une exception JAX-WS&lt;/a&gt; . &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Ce billet peut vous être utile si vous rechercher comment maitriser un aspect du WSDL en utilisant JAX-WS 2.0.&lt;/p&gt;  &lt;p&gt;Nous allons annoter les éléments suivants :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’interface et le bean afin de définir le service &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Rappel des étapes du tutorial sur les services avec JAX-WS :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;Présentation du tutorial et de l'approche Contract First avec JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;Etape 3 : Création des objets métier et d’une exception JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Etape 4, Ce billet : Annotations JAX-WS et JAXB des classes &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Les annotations JAX-WS&lt;/h2&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Pour une documentation de référence sur les annotations JAX-WS 2.0 vous pouvez vous reporter aux pages suivantes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.wsfep.multiplatform.doc%2Finfo%2Fae%2Fae%2Frwbs_jaxwsannotations.html"&gt;http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.wsfep.multiplatform.doc%2Finfo%2Fae%2Fae%2Frwbs_jaxwsannotations.html&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jax-ws.java.net/jax-ws-ea3/docs/annotations.html"&gt;http://jax-ws.java.net/jax-ws-ea3/docs/annotations.html&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Interface IWebHelpDesk &lt;/h3&gt;  &lt;p&gt;C’est au niveau de l’interface qu’on a la plus grande maitrise sur la génération du WSDL :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;on y définit le protocole utilisé &lt;/li&gt;    &lt;li&gt;on y définit le nom de la majorité des nœuds XML &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Au niveau de l’interface, nous définissons deux types d’annotations :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;celles qui annotent l’interface directement : @Remote, @WebService et @SOAPBinding &lt;/li&gt;    &lt;li&gt;celles qui annotent une méthode de l’interface : @WebMethod, @WebResult et @WebParam &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Les premières permettent de définir le protocole des messages, comment on assemble les messages, le nom du service…&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;@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. &lt;/li&gt;    &lt;li&gt;@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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;@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. &lt;/li&gt;    &lt;li&gt;@WebResult : nom de l’objet XML encapsulant la valeur retournée. &lt;/li&gt;    &lt;li&gt;@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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;On modifie le code initiale avec les annotations suivantes, afin d’obtenir le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;import javax.ejb.Remote;        &lt;br /&gt;import javax.jws.WebMethod;         &lt;br /&gt;import javax.jws.WebParam;         &lt;br /&gt;import javax.jws.WebResult;         &lt;br /&gt;import javax.jws.WebService;         &lt;br /&gt;import javax.jws.soap.SOAPBinding;         &lt;br /&gt;import javax.jws.soap.SOAPBinding.Style;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;@Remote        &lt;br /&gt;@WebService(name = &amp;quot;ISwHelpDeskPortType&amp;quot;, targetNamespace = &amp;quot;&lt;/strong&gt;&lt;a href="http://demo.jl2tho.fr&amp;quot;"&gt;&lt;strong&gt;http://demo.jl2tho.fr&amp;quot;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; )        &lt;br /&gt;@SOAPBinding(style=Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle= SOAPBinding.ParameterStyle.WRAPPED)         &lt;br /&gt;&lt;/strong&gt;public interface IWebHelpDesk {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebMethod(operationName=&amp;quot;retrouverQuestionApartirId&amp;quot;)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @WebResult(name = &amp;quot;QUESTION&amp;quot;)         &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; public Question getQuestionWithId(       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@WebParam(name = &amp;quot;NUMERO&amp;quot;)&lt;/strong&gt;String pNumero       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) throws BusinessFaultException;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebMethod(operationName=&amp;quot;creerNouvelleQuestion&amp;quot;)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @WebResult(name = &amp;quot;NUMERO&amp;quot;)         &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; public String createQuestion(       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@WebParam(name = &amp;quot;INPUT_QUESTION&amp;quot;)&lt;/strong&gt; Question pNewQuestion       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) throws BusinessFaultException;       &lt;br /&gt;}       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Attention ! Pour que les annotations soit utilisables, il est indispensable d’avoir correctement définis les External Jars de votre projet Eclipse (voir &lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS&lt;/a&gt; de ce tutorial).&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Bean WebService &lt;/h3&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Attention ! Dans une approche avec un WAR, il faut assurer la correspondance du nom avec celui indiqué dans le servlet-name de web.xml.&lt;/p&gt;  &lt;p&gt;Pour les différents attributs de l’annotation WebService d’un bean nous avons :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;endpointInterface : elle indique le nom de l’interface Java décrivant le service Web (dans notre cas IWebHelpDesk). &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;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 &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On modifie le code initial afin d’obtenir le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;import javax.ejb.Stateless;        &lt;br /&gt;import javax.jws.WebService;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;@Stateless        &lt;br /&gt;@WebService(endpointInterface=&amp;quot;fr.j2ltho.webcontracthelpdesk.server.IWebHelpDesk&amp;quot;,         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; portName=&amp;quot;HelpdeskServicePort&amp;quot;,&amp;#160; serviceName=&amp;quot;WebContractHelpdesk&amp;quot;,         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; targetNamespace = &amp;quot;&lt;/strong&gt;&lt;a href="http://demo.jl2tho.fr&amp;quot;)"&gt;&lt;strong&gt;http://demo.jl2tho.fr&amp;quot;)&lt;/strong&gt;&lt;/a&gt;       &lt;br /&gt;public class HelpdeskServiceBean implements IWebHelpDesk {&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String createQuestion(Question pNewQuestion)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNewQuestion==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur Question nulle&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;01&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public Question getQuestionWithId(String pNumero)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNumero==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur : Numero de question nul&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;02&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;}      &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On constate que l’impact sur l’implémentation du service Web est bien plus faible que sur l’interface.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Annotation JAXB sur la classe Question&lt;/h2&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;@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é. &lt;/li&gt;    &lt;li&gt;@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. &lt;/li&gt;    &lt;li&gt;@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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pour plus d’information sur JAXB, je vous renvoie au très bon article : &lt;a href="http://blog.paumard.org/cours/jaxb-rest/chap01-jaxb-annotations.html"&gt;http://blog.paumard.org/cours/jaxb-rest/chap01-jaxb-annotations.html&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;On édite la classe Java Question pour modifier sa première partie. Les constructeurs et getter/setter ne sont pas modifiés. &lt;/p&gt;  &lt;p&gt;Le début du code (jusqu’au constructeur) est modifié afin d’obtenir le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;import java.util.Date;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;import javax.xml.bind.annotation.XmlAccessType;        &lt;br /&gt;import javax.xml.bind.annotation.XmlAccessorType;         &lt;br /&gt;import javax.xml.bind.annotation.XmlElement;         &lt;br /&gt;import javax.xml.bind.annotation.XmlType;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;@XmlType(name=&amp;quot;QuestionType&amp;quot;, propOrder = { &amp;quot;id&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;submitDate&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;product&amp;quot;, &amp;quot;urgency&amp;quot;, &amp;quot;priority&amp;quot;, &amp;quot;type&amp;quot; })        &lt;br /&gt;@XmlAccessorType(XmlAccessType.FIELD)         &lt;br /&gt;&lt;/strong&gt;public class Question {       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;NUMERO&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String id;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;DESCRIPTION&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String description;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;SUBMITDATE&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private Date submitDate;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;TITLE&amp;quot;, required=true)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String title;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;PRODUCT&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String product;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;URGENCY&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private UrgencyEnum urgency;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;PRIORITY&amp;quot;, required=true)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String priority;       &lt;br /&gt;&amp;#160;&lt;strong&gt;&amp;#160;&amp;#160; @XmlElement(name = &amp;quot;TYPE&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; private String type;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public Question() {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; super();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&lt;/p&gt; …&lt;/div&gt;  &lt;p&gt;Certaines annotations JAXB comme le nillable ne sont pas traitées par JAX-WS. Elles n’auront alors aucun effet sur le WSDL.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Si vous avez suivi à la lettre mon &lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS&lt;/a&gt; de ce tutorial et que vous utilisez JBoss 5.1, vous ne devriez pas avoir de problème.&lt;/p&gt;  &lt;h3&gt;XmlEnum et XmlEnumValue&lt;/h3&gt;  &lt;p&gt;Nous avions définis une énumération comme propriété, nous allons également annoter cette enum java afin de maitriser également sa transformation XML.&lt;/p&gt;  &lt;p&gt;L’annotation XmlEnumValue permet de définir la chaine de caractères qui correspond à la valeur de l’énumération dans le message.&lt;/p&gt;  &lt;p&gt;Editez UrgencyEnum et modifiez la afin d’obtenir le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;import javax.xml.bind.annotation.XmlEnum;        &lt;br /&gt;import javax.xml.bind.annotation.XmlEnumValue;         &lt;br /&gt;import javax.xml.bind.annotation.XmlType;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;@XmlType        &lt;br /&gt;@XmlEnum(String.class)         &lt;br /&gt;&lt;/strong&gt;public enum UrgencyEnum {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@XmlEnumValue(&amp;quot;URGENCY_BUGINPROD&amp;quot;)&lt;/strong&gt; BUGINPROD,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@XmlEnumValue(&amp;quot;URGENCY_CONFIG&amp;quot;)&lt;/strong&gt; CONFIG,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@XmlEnumValue(&amp;quot;URGENCY_USAGE&amp;quot;)&lt;/strong&gt; USAGE,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;@XmlEnumValue(&amp;quot;URGENCY_BUGINDEV&amp;quot;)&lt;/strong&gt; BUGINDEV       &lt;br /&gt;}&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;Nous avons finis d’annoter nos classes, interface et énumérations Java. Vous allez voir dans &lt;a href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;l’étape suivante à quoi correspond le WSDL généré&lt;/a&gt; automatiquement à partir de ces annotations.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Etapes : &lt;a title="Présentation du tutorial et de l&amp;#39;approche Contract First avec JAX-WS" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;1&lt;/a&gt; | &lt;a title="Etape 2 : Configuration d&amp;#39;un projet Eclipse pour un WebService JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;2&lt;/a&gt; | &lt;a title="Etape 3 : Création des objets métiers et d&amp;#39;une exception JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;3&lt;/a&gt; | 4| &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;5&lt;/a&gt; – &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;Suivant &amp;gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-1321315063066827513?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/1321315063066827513/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=1321315063066827513&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1321315063066827513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1321315063066827513'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html' title='Etape 4 : Annotations JAX-WS et JAXB des classes'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-6828520578205050435</id><published>2011-11-30T21:43:00.001+02:00</published><updated>2011-12-05T15:09:52.463+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JAX-WS'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Etape 3 du tutorial : Création des objets métier et Exception JAX-WS</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;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 (&lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Nous allons créer les éléments suivants :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Question : il s’agit de l’objet métier qui sert à transporter une information structurée &lt;/li&gt;    &lt;li&gt;l’exception métier pour le service &lt;/li&gt;    &lt;li&gt;l’interface du service &lt;/li&gt;    &lt;li&gt;le bean d’implémentation du service &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Rappel des étapes du tutorial sur les services avec JAX-WS :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;Présentation du tutorial et de l'approche Contract First avec JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration d'un projet Eclipse pour un WebService JAX-WS&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Etape 3, Ce billet : Création des objets métier et d’une exception JAX-WS &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;L’objet métier Question&lt;/h2&gt;  &lt;p&gt;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&lt;/p&gt;  &lt;h3&gt;Enumération UrgencyEnum&lt;/h3&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Enum.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : UrgencyEnum &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;public enum UrgencyEnum {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; BUGINPROD, CONFIG, USAGE, BUGINDEV       &lt;br /&gt;}       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Création de l’objet Question&lt;/h3&gt;  &lt;p&gt;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 : &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’objet est plus simple et probablement plus adapté aux besoins de l’utilisateur &lt;/li&gt;    &lt;li&gt;vous évitez d’envoyer des informations confidentielles qui pourraient être disponibles dans l’objet métier existant &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : Question &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;import java.util.Date;&lt;/p&gt;    &lt;p&gt;public class Question {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String id;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String description;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private Date submitDate;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String title;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String product;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private UrgencyEnum urgency;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String priority;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String type;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public Question() {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; super();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getId() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return id;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setId(String id) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.id = id;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getDescription() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return description;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setDescription(String description) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.description = description;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public Date getSubmitDate() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return submitDate;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setSubmitDate(Date submitDate) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.submitDate = submitDate;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getTitle() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return title;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setTitle(String title) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.title = title;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getProduct() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return product;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setProduct(String product) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.product = product;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public UrgencyEnum getUrgency() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return urgency;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setUrgency(UrgencyEnum urgency) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.urgency = urgency;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getPriority() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return priority;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setPriority(String priority) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.priority = priority;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getType() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return type;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setType(String type) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.type = type;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Exception métier pour un service web&lt;/h2&gt;  &lt;p&gt;Par défaut, une exception java contient une propriété Message. C’est cette propriété qui contient l’information sur l’exception.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Afin de rendre exploitable les exceptions, nous allons définir un bean FaultBean qui servira à stocker l’information de l’exception.&lt;/p&gt;  &lt;p&gt;Puis nous définirons notre propre exception BusinessFaultException qui définira un getter pour récupérer la propriété faultinfo.&lt;/p&gt;  &lt;h3&gt;Création de l’objet FaultBean&lt;/h3&gt;  &lt;p&gt;Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : FaultBean &lt;/li&gt;    &lt;li&gt;Cocher la case : Constructor from superclass &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;Nous définissons deux propriétés (la liste est libre ainsi que les noms) :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;code pour stocker un identifiant technique &lt;/li&gt;    &lt;li&gt;businessMessage : pour stocker un libellé associé destiné à l’utilisateur &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;public class FaultBean {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String code;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private String businessMessage;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public FaultBean() {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getCode() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return code;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setCode(String code) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.code = code;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String getBusinessMessage() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return businessMessage;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public void setBusinessMessage(String businessMessage) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.businessMessage = businessMessage;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;br /&gt;}       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;h3&gt;Création de l’exception BusinessFaultException &lt;/h3&gt;  &lt;p&gt;Nous pouvons maintenant créer notre objet Question. Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : BusinessFaultException &lt;/li&gt;    &lt;li&gt;Superclass : tapez exception est naviguez pour sélectionner : Exception – java.lang &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;On ajoute également la propriété static serialVersionUID car une exception est serialisable.&lt;/p&gt;  &lt;p&gt;Pour finir, on ajoute les annotations :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;name sera le nom de la Fault dans la définition du service web &lt;/li&gt;    &lt;li&gt;faultBean indique le nom de l’objet Java contenant l’information &lt;/li&gt;    &lt;li&gt;targetNamespace indique l’espace nom pour les types XML &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;import javax.xml.ws.WebFault;&lt;/p&gt;    &lt;p&gt;@WebFault(name=&amp;quot;BusinessFault&amp;quot;, faultBean=&amp;quot;fr.j2ltho.webcontracthelpdesk.server.FaultBean&amp;quot;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; targetNamespace = &amp;quot;&lt;a title="http://demo.jl2tho.fr" href="http://demo.jl2tho.fr"&gt;http://demo.jl2tho.fr&lt;/a&gt;&lt;a href="http://webservice.tutorial.jl2tho.fr&amp;quot;)"&gt;&amp;quot;)&lt;/a&gt;       &lt;br /&gt;public class BusinessFaultException extends Exception {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private static final long serialVersionUID = 3061940459819421533L;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private FaultBean faultInfo;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public BusinessFaultException(String internalMessage, FaultBean faultInfo, Throwable cause) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; super(internalMessage, cause);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.faultInfo = faultInfo;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public BusinessFaultException(String internalMessage, FaultBean faultInfo) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; super(internalMessage);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this.faultInfo = faultInfo;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public FaultBean getFaultInfo() {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return faultInfo;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;}      &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Interface et implémentation du service&lt;/h2&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;h3&gt;Interface IWebHelpDesk&lt;/h3&gt;  &lt;p&gt;Nous allons créer une interface avec deux méthodes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;getQuestionWithId prend une String et retourne une Question. &lt;/li&gt;    &lt;li&gt;createQuestion qui prend un objet Question en entrée et qui retourne un numéro de question &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Créons notre interface. Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Interface.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : IWebHelpDesk &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;public interface IWebHelpDesk {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public Question getQuestionWithId(String pNumero) throws BusinessFaultException;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public String createQuestion(Question pNewQuestion) throws BusinessFaultException;       &lt;br /&gt;}       &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;h3&gt;Bean Service &lt;strong&gt;HelpdeskServiceBean&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;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 &lt;strong&gt;HelpdeskServiceBean.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Créons notre classe. Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New –&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt;    &lt;li&gt;Pour Name tapez : &lt;strong&gt;HelpdeskServiceBean&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;Appuyez sur le bouton Add pour l’interface et choisir IWebHelpDesk - fr.j2ltho.webcontracthelpdesk.server &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;createQuestion retourne une exception si Question est nulle &lt;/li&gt;    &lt;li&gt;getQuestionWithId retourne une exception si le numéro est nulle. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.webcontracthelpdesk.server;&lt;/p&gt;    &lt;p&gt;public class HelpdeskServiceBean implements IWebHelpDesk {&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public String createQuestion(Question pNewQuestion)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNewQuestion==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur Question nulle&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;01&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public Question getQuestionWithId(String pNumero)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throws BusinessFaultException {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (pNumero==null) {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FaultBean faultBean = new FaultBean();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setBusinessMessage(&amp;quot;Erreur : Numero de question nul&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; faultBean.setCode(&amp;quot;02&amp;quot;);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Le message dans l'exception est disponible dans l'exception recu       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // mais sa déclaration est absente du wsdl       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new BusinessFaultException(&amp;quot;Internal Message&amp;quot; , faultBean );&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return null;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;}      &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;Nous avons vu dans ce billet, le mécanisme de création d’une exception pour un service web.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Dans l’étape suivante : &lt;a href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html&lt;/a&gt;, nous allons annoter nos objets Java afin que le WSDL correspondent à notre besoin.&lt;/p&gt;  &lt;p&gt;Etapes : &lt;a title="Présentation du tutorial et de l&amp;#39;approche Contract First avec JAX-WS" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;1&lt;/a&gt; | &lt;a title="Etape 2 : Configuration d&amp;#39;un projet Eclipse pour un WebService JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;2&lt;/a&gt; | 3 | &lt;a title="Etape 4 : Annotations JAX-WS et JAXB des classes" href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;4&lt;/a&gt; | &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;5&lt;/a&gt; – &lt;a title="Etape 4 : Annotations JAX-WS et JAXB des classes" href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;Suivant &amp;gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-6828520578205050435?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/6828520578205050435/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=6828520578205050435&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6828520578205050435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6828520578205050435'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html' title='Etape 3 du tutorial : Création des objets métier et Exception JAX-WS'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-6543628537832983588</id><published>2011-11-29T23:25:00.001+02:00</published><updated>2011-12-05T15:08:38.532+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSphere'/><category scheme='http://www.blogger.com/atom/ns#' term='JAX-WS'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><title type='text'>Etape 2 du Tutorial : Configuration d’un projet JAX-WS</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Il s’agit du second billet d’un tutorial sur l’approche Contract First avec JAX-WS.&lt;/p&gt;  &lt;p&gt;Il suit le premier billet : &lt;a href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html&lt;/a&gt; qui présentait le tutorial et expliquait son approche.&lt;/p&gt;  &lt;p&gt;Dans cette étape nous allons définir la configuration du projet et créer le projet Eclipse.&lt;/p&gt;  &lt;p&gt;La configuration d’un projet Eclipse pour un service web est relativement simple. il faut :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;définir le service web dans le web.xml &lt;/li&gt;    &lt;li&gt;ajouter les jars nécessaire à la compilation des annotations comme “externals jars”. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Nous allons créer un projet Eclipse JaxWsContractFirst.&lt;/p&gt;  &lt;p&gt;Le nom du service web sera : WebContractHelpdesk et le bean qui l’implémentera sera : fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean .&lt;/p&gt;  &lt;h2&gt;Configuration&lt;/h2&gt;  &lt;p&gt;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&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;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é. &lt;/li&gt;    &lt;li&gt;Le runtime et le jdk Java sont à la version 1.5.0_11. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Le serveur d’application utilisé sera JBoss 5.1. Il est installé sous C:\jboss-5.1.0.GA conformément au tutorial suivant : &lt;a title="http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html" href="http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html"&gt;http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html&lt;/a&gt;. Attention ! Je rappelle qu’une installation sous “Program files” ou tous répertoires contenant des espaces peut être source d’ennuis.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Je vous encourage donc à utiliser JBoss 5.1 pour suivre ce tutorial.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Création du projet Eclipse&lt;/h2&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New –&amp;gt; Other. &lt;/li&gt;    &lt;li&gt;Dans la dialogue New, choisir le dossier “Web” puis le nœud “Dynamic Web Project”. Appuyez sur le bouton Next. &lt;/li&gt;    &lt;li&gt;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). &lt;/li&gt;    &lt;li&gt;Appuyez sur Finish. Acceptez le choix de la perspective si la dialogue « Open Associated Perspective » s’affiche. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Fichier web.xml et définition du service web&lt;/h3&gt;  &lt;p&gt;Dans le répertoire WebContent –&amp;gt; WEB-INF de votre projet, se trouve le fichier web.xml : il s’agit d’une caractéristique d’un “Dynamic Web project”.&lt;/p&gt;  &lt;p&gt;En Java 1.5, le service web est un servlet. Nous allons ajouter la déclaration du servlet qui correspondra à notre service web : WebContractHelpdesk.&lt;/p&gt;  &lt;p&gt;Editer ce fichier web.xml.&lt;/p&gt;  &lt;p&gt;On ajoute la déclaration de la servlet qui correspondra au service web.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;servlet-class correspond au nom complet du bean qui implémente le service web : fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;      &lt;br /&gt;&amp;lt;web-app xmlns:xsi=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema-instance&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/a&gt; xmlns=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee&amp;quot;&lt;/a&gt; xmlns:web=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/a&gt; xsi:schemaLocation=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee"&gt;http://java.sun.com/xml/ns/javaee&lt;/a&gt; &lt;a href="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/a&gt; id=&amp;quot;WebApp_ID&amp;quot; version=&amp;quot;2.5&amp;quot;&amp;gt;       &lt;br /&gt;&amp;lt;display-name&amp;gt;JaxWsContractFirst&amp;lt;/display-name&amp;gt;       &lt;br /&gt;&lt;strong&gt;&amp;lt;servlet&amp;gt;        &lt;br /&gt;&amp;lt;servlet-name&amp;gt;WebContractHelpdesk&amp;lt;/servlet-name&amp;gt;         &lt;br /&gt;&amp;lt;servlet-class&amp;gt;fr.j2ltho.webcontracthelpdesk.server.HelpdeskServiceBean&amp;lt;/servlet-class&amp;gt;         &lt;br /&gt;&amp;lt;/servlet&amp;gt;         &lt;br /&gt;&amp;lt;servlet-mapping&amp;gt;         &lt;br /&gt;&amp;lt;servlet-name&amp;gt;WebContractHelpdesk&amp;lt;/servlet-name&amp;gt;         &lt;br /&gt;&amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;         &lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;         &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;welcome-file-list&amp;gt;      &lt;br /&gt;&amp;lt;welcome-file&amp;gt;index.html&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;welcome-file&amp;gt;index.htm&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;welcome-file&amp;gt;index.jsp&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;welcome-file&amp;gt;default.html&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;welcome-file&amp;gt;default.htm&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;welcome-file&amp;gt;default.jsp&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;lt;/welcome-file-list&amp;gt;       &lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h3&gt;Ajout des External Jars&lt;/h3&gt;  &lt;p&gt;Il s’agit de la partie qui dépend le plus du serveur d’application.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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 ».&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jboss-javaee.jar qui définit les annotations @Stateless et @Remote &lt;/li&gt;    &lt;li&gt;Jbossws-native-jaxws.jar qui définit les annotations @WebService, @SOAPBinding et @SOAPBinding &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;jaxb-api.jar qui définit les annotations @XmlElement &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Validez en appuyant sur Ok.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Par exemple pour WebSphere 6.1, il faut les jars :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;com.ibm.jaxws.thinclient_6.1.0.jar dans C:\IBM\Websphere\AppServer\runtimes\ &lt;/li&gt;    &lt;li&gt;j2ee.jar dans C:\IBM\Websphere\AppServer\lib\ &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On voit que le nom, l’emplacement et leur nombre n’ont rien à voir.&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;Nous avons créer un projet Eclipse JaxWsContractFirst.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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).&lt;/p&gt;  &lt;p&gt;Comme indiqué en première partie, nous nous limiterons aux prototypes de ces classes dans cette étape.&lt;/p&gt;  &lt;p&gt;Etapes : &lt;a title="Présentation du tutorial et de l&amp;#39;approche Contract First avec JAX-WS" href="http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html"&gt;1&lt;/a&gt; | 2 | &lt;a title="Etape 3 : Création des objets métiers et d&amp;#39;une exception JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;3&lt;/a&gt; | &lt;a title="Etape 4 : Annotations JAX-WS et JAXB des classes" href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;4&lt;/a&gt; | &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;5&lt;/a&gt; – &lt;a title="Etape 3 : Création des objets métiers et d&amp;#39;une exception JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;Suivant &amp;gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-6543628537832983588?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/6543628537832983588/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=6543628537832983588&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6543628537832983588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6543628537832983588'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html' title='Etape 2 du Tutorial : Configuration d’un projet JAX-WS'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-8032055907860773662</id><published>2011-11-29T18:19:00.001+02:00</published><updated>2011-12-05T15:05:05.483+02:00</updated><title type='text'>Tutorial Approche Contract First avec JAX-WS</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Voilà plus de 4 ans (avril 2007), j’ai fait un long tutoriel sur l’approche Contract First avec Axis2 : &lt;a href="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html"&gt;http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Peu après, je découvrais la norme JAX-WS pour les Services Web et réalisais un tutorial pour créer un service web pour JBoss 4.2 en utilisant JAX-WS : &lt;a href="http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html"&gt;http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html&lt;/a&gt;. On était toujours en 2007. &lt;/p&gt;  &lt;p&gt;Plus récemment, j’ai actualisé ce dernier tutorial pour une utilisation avec JBoss 5.1 &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt; puis WebSphere 6.1 : &lt;a title="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html" href="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html"&gt;http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html&lt;/a&gt;. Mais ces tutoriaux JAX-WS, ne montre qu’un cas d’utilisation très simple.&lt;/p&gt;  &lt;p&gt;Aujourd’hui, avec ce nouveau tutorial, je souhaite montrer toute la puissance de l’approche JAX-WS sur un exemple plus complet, proche de celui de mon tutoriel sur Axis2.&lt;/p&gt;  &lt;p&gt;Avant d’aller plus loin, je vais vous présenter les étapes de ce tutorial :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Etape 1 : Approche Contract first (ce bilet)      &lt;ul&gt;       &lt;li&gt;Approche Contract First &lt;/li&gt;        &lt;li&gt;JAX-WS &lt;/li&gt;        &lt;li&gt;La synthèse &lt;/li&gt;        &lt;li&gt;Le projet &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Etape 2 : Configuration du projet&lt;/a&gt;       &lt;ul&gt;       &lt;li&gt;Création du projet Eclipse &lt;/li&gt;        &lt;li&gt;web.xml &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;Etape 3 : Le métier&lt;/a&gt;       &lt;ul&gt;       &lt;li&gt;Objet Question &lt;/li&gt;        &lt;li&gt;FaultBean et exception &lt;/li&gt;        &lt;li&gt;Interface &lt;/li&gt;        &lt;li&gt;Implémentation &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;Etape 4 : Annotation&lt;/a&gt;       &lt;ul&gt;       &lt;li&gt;JAX-WS : interface et implémentation &lt;/li&gt;        &lt;li&gt;JAXB pour décrire l’objet question &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;Etape 5 : déploiement et WSDL&lt;/a&gt;       &lt;ul&gt;       &lt;li&gt;WSDL &lt;/li&gt;        &lt;li&gt;Type simple plus compliqué &lt;/li&gt;        &lt;li&gt;inclure son propre WSDL &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Etape 6 : Injection Spring pour le métier      &lt;ul&gt;       &lt;li&gt;Ajout des jar Spring &lt;/li&gt;        &lt;li&gt;Surcharge du bean pour activation de l’autowired &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Chaque étape fera l’objet d’un billet. L’objectif de ce tutorial est de faire le tour d’un exemple suffisamment complexe pour être un cas significatif de la problématique qui sera rencontrée dans le cadre d’un véritable développement.&lt;/p&gt;  &lt;p&gt;Si vous êtes débutant sur JAX-WS, je vous encourage à suivre au préalable mon tutorial d’introduction à JAX-WS avec JBoss 5.1 : &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt;. Ce tutorial présente les concepts et mécanismes de base sur lesquels je vais m’appuyer sans pour autant les reprendre de manière détaillée dans ce tutorial.&lt;/p&gt;  &lt;p&gt;Dans la suite de ce billet, je développe les raisons de mon choix et de mon approche.&lt;/p&gt;  &lt;h2&gt;Approche Contract First : Avantages et inconvénients&lt;/h2&gt;  &lt;p&gt;Dans l’absolu, l’approche Contract First consiste à définir le contrat qui va lier le consommateur du service web avec son fournisseur. Dans la norme Web Service, ce contrat est le WSDL. Il s’agit d’un fichier XML qui décrit le format des messages XML qui seront échangés entre le client et le service. &lt;/p&gt;  &lt;p&gt;Sa structure est normée mais sa lecture et compréhension sont peu aisées ou du moins fastidieuses. Dans mon tutorial Axis2 &lt;a href="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html"&gt;http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html&lt;/a&gt;, je présente un outil permettant d’écrire ce fichier WSDL&lt;/p&gt;  &lt;p&gt;Pour moi, cette approche Contract First est intéressante car elle permet de dégager le contrat des implémentations technologiques du service : les types simples ne dépendent pas du langage choisi, on augmente ses chances que le service que l’on va produire puisse être réutilisé par des clients dans des technologies différentes. &lt;/p&gt;  &lt;p&gt;En revanche, la solution retenue est longue et fastidieuse : il faut définir des messages ainsi que tous les champs constitutifs un à un. &lt;/p&gt;  &lt;p&gt;D’autre part, la solution Axis2 utilisée, n’offrait pas à l’époque, un modèle de développement très efficace : mon code d’appel du service sans passer par la couche Service Web diffère trop (à mon gout) de l’appel du même service en direct. Cela me dérange, car je pense aux cas de tests jUnit que je pourrais plus facilement réutiliser avec une approche dans laquelle les deux interfaces seraient plus proches.&lt;/p&gt;  &lt;h2&gt;JAX-WS&lt;/h2&gt;  &lt;p&gt;Très rapidement après cette première expérience Axis2, j’ai découvert JAX-WS. Il s’agit d’un élément de la norme des EJB 3.0 sur laquelle elle s’appuie.&lt;/p&gt;  &lt;p&gt;Ce qui m’a plu dans l’approche JAX-WS est son efficacité au niveau du développement : on ne multiplie pas les fichiers de configuration grâce aux annotations. Mais surtout, on ne manipule plus la structure des fichiers XML (les messages) que l’on soit sur le client ou le serveur.&lt;/p&gt;  &lt;p&gt;La vision du développement du service ou du client utilisateur du service est celle d’un simple appel d’une méthode possédant des paramètres : on ne peut faire plus simple.&lt;/p&gt;  &lt;p&gt;Les différents tutoriaux que j’ai réalisé sur cette approche, montre bien cette simplicité :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;JBoss 4.2 : &lt;a href="http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html"&gt;http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;JBoss 5.1 &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;WebSphere 6.1 : &lt;a title="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html" href="http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html"&gt;http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html&lt;/a&gt;. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ils montrent également la puissance de la norme, car au delà des différences de configuration de l’environnement de développement et du déploiement, le développement est identique. Si on retient l’approche WAR utilisée pour WebSphere, le même binaire (WAR) peut être déployé sur les différents serveurs d’application sans modification.&lt;/p&gt;  &lt;p&gt;Dès 2007, nous avons opté pour l’approche JAX-WS au niveau de tous nos développements en remplacement de la solution Axis (version 1) que nous utilisions jusqu’à présent. Cela montre l’intérêt que j’ai eu pour cette approche.&lt;/p&gt;  &lt;h2&gt;JAX-WS et l’approche Contract First&lt;/h2&gt;  &lt;p&gt;Je vais certainement choquer quelques extrémistes, mais je souhaitais concilier les deux approches : utiliser les annotations JAX-WS pour définir mon contrat : le fichier WSDL.&lt;/p&gt;  &lt;p&gt;JAX-WS fonctionnant par annotation d’une classe Java représentant de fait du code, il peut paraitre contradictoire de parler d’approche Contract First : j’écris du code Java avant le WSDL.&lt;/p&gt;  &lt;p&gt;Néanmoins, en premier lieu, je me limite à la déclaration de mon interface et une implémentation vide : je n’ai que des prototypes de classe : parler de code est un peu excessif à ce niveau. De plus, je décris en Java le service que je veux offrir plus que son implémentation qui reste vide à cette étape.&lt;/p&gt;  &lt;p&gt;Je vais ensuite annoter ces classes et interfaces par itération jusqu’à obtenir le WSDL qui me convient. Ce n’est qu’ensuite que je commence à coder l’implémentation du métier.&lt;/p&gt;  &lt;p&gt;De mon point de vu, au lieu d’utiliser un outil graphique comme celui que j’ai utilisé avec Axis2, pour définir le WSDL, j’utilise le langage Java et les annotations JAX-WS. Je considère cette approche doublement plus efficace :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;elle est plus naturelle : on commence par décrire le prototype d’un service. &lt;/li&gt;    &lt;li&gt;j’ai eu l’impression d’avoir une plus grande maitrise du WSDL produit avec les annotations JAX-WS qu’avec l’outil graphique &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Cela ne fonctionne que parce que JAX-WS produit un WSDL technologiquement neutre : les types simples ne sont pas Java. Je n’ai pas eu à faire des efforts démesurés pour utiliser des types basics.&lt;/p&gt;  &lt;p&gt;Un dernier avantage et un petit inconvénient (les deux sont liés) :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Il est possible d’avoir une démarche agile avec cette approche : je peux travailler sur le WSDL en adaptant les annotations tout en avançant sur l’implémentation du service à chaque run. &lt;/li&gt;    &lt;li&gt;On peut avoir tendance à passer aux développements trop rapidement (avant d’avoir fini la partie WSDL) et/ou à réutiliser des objets provenant du développement dans les prototypes des méthodes de service. Cela peut être problématique car l’objet peut avoir une complexité ou une structure inadaptée au service souhaité. &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Projet du tutorial&lt;/h2&gt;  &lt;p&gt;Notre mini projet consistera à rendre disponible un service de consultation des Questions soumise à un Helpdesk (on reprend la thématique du projet Axis2).&lt;/p&gt;  &lt;p&gt;Nous allons créer 3 services qui manipulent un objet Question en paramètre :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;rechercher une question à partir de son ID (validation d’un format en entrée 9 caractères numériques) &lt;/li&gt;    &lt;li&gt;créer une question : retourne un ID de question (objet complexe en entrée, un format date, une énumération, un entier compris en 0 et 4 pour l’urgence) &lt;/li&gt;    &lt;li&gt;récupérer une liste de questions avec une énumération en entrée (liste d’objets en sortie et énumération) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;J’ai recherché à tester les aspects suivants :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Manipulation d’objets métier structurés &lt;/li&gt;    &lt;li&gt;Typage fort des données : au delà du simple type (entier, string…) spécifier la taille limite, des plages de valeurs… &lt;/li&gt;    &lt;li&gt;Manipulation de liste d’objets structurés &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Il s’agit des mêmes objectifs que ceux que j’avais adopté lors de mon tutoriel Axis 2 : Approche Contract First.&lt;/p&gt;  &lt;p&gt;Afin de rester dans une approche Contract First malgré l’utilisation de JAX-WS, l’implémentation réelle des services ne sera abordé qu’en dernier lieu avec l’injection de bean Spring.&lt;/p&gt;  &lt;p&gt;Toutes les étapes préliminaires vont servir à définir le plus précisément le WSDL du service en utilisant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;les annotations JAX-WS &lt;/li&gt;    &lt;li&gt;les annotations JAXB : il s’agit d’une norme sœur de JAX-WS permettant de décrire comment un objet Java est transformé en XML. &lt;/li&gt;    &lt;li&gt;l’utilisation d’une exception particulière afin de définir précisément les messages d’erreur retournés par le service &lt;/li&gt;    &lt;li&gt;la surcharge du WSDL produit afin de compléter les déclarations de type &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ce n’est qu’une fois le WSDL validé que l’on se penchera sur la récupération des ressources configurées (DAO, Factory Hibernate…) nécessaires à l’implémentation du service. C’est à ce moment que Spring sera introduit.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;J’ai fini de présenter les objectifs de ce tutorial, nous allons passer dans le billet suivant dans le vif du sujet : &lt;a href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;la configuration du projet (étape 2 du tutorial)&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Etapes : 1 | &lt;a title="Etape 2 : Configuration d&amp;#39;un projet Eclipse pour un WebService JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;2&lt;/a&gt; | &lt;a title="Etape 3 : Création des objets métiers et d&amp;#39;une exception JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-3-du-tutorial-creation-des-objets.html"&gt;3&lt;/a&gt; | &lt;a title="Etape 4 : Annotations JAX-WS et JAXB des classes" href="http://jl2tho.blogspot.com/2011/12/etape-4-annotations-jax-ws-et-jaxb-des.html"&gt;4&lt;/a&gt; | &lt;a title="Etape 5 : Déployer un Service Web et compléter son WSDL" href="http://jl2tho.blogspot.com/2011/12/etape-5-deployer-un-service-web-et.html"&gt;5&lt;/a&gt; –&amp;#160; &lt;a title="Etape 2 : Configuration d&amp;#39;un projet Eclipse pour un WebService JAX-WS" href="http://jl2tho.blogspot.com/2011/11/etape-2-du-tutorial-configuration-dun.html"&gt;Suivant &amp;gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-8032055907860773662?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/8032055907860773662/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=8032055907860773662&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/8032055907860773662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/8032055907860773662'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/tutorial-approche-contract-first-avec.html' title='Tutorial Approche Contract First avec JAX-WS'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-8748341972515525929</id><published>2011-11-21T12:44:00.001+02:00</published><updated>2011-12-02T12:50:44.976+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSphere'/><category scheme='http://www.blogger.com/atom/ns#' term='JAX-WS'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><title type='text'>Tutorial Service Web avec WebSphere 6.1</title><content type='html'>&lt;p&gt;Ce tutorial adapte pour IBM WebSphere 6.1, mon tutorial sur la création de Service Web avec JBoss 5.1 qui peut être trouvé à l’adresse suivante : &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Il s’agit d’un tutorial qui présente la création d’un Service Web très simple en utilisant le mécanisme d’annotation JAX-WS avec comme serveur d’application WebSphere 6.1.&lt;/p&gt;  &lt;p&gt;J’ai cherché dans ce tutorial à me débarrasser de l’outillage IBM qui semble ajouter de nombreux fichiers de configuration spécifiques à WebSphere. L’ensemble du tutorial (en dehors du serveur d’application) est indépendant de l’outillage IBM.&lt;/p&gt;  &lt;h3&gt;Une rapide présentation des Services Web avec WebSphere 6.1&lt;/h3&gt;  &lt;p&gt;Tout d’abord, il faut savoir que la version standard de WebSphere 6.1 ne permet pas la réalisation de Service Web reposant sur la norme JAX-WS. Pour bénéficier du support de la norme, il faut ajouter deux Feature Packs (Service Web et EJB 3.0) ainsi que 3 Fix Packs.&lt;/p&gt;  &lt;p&gt;Le même WAR que j’avais déployé sur la version 6.1.0 qui ne fonctionnait pas, fonctionne parfaitement une fois toutes ces installations réalisées.&lt;/p&gt;  &lt;p&gt;WebSphere s’appuie sur les EJB 3.0 pour définir et implémenter les Services Web. Il respecte les spécifications de JAX-WS pour la définition des services web. Cette norme définit un ensemble d’annotations qui permettent la transformation d’un EJB 3.0 en service web. Les annotations sont interprétées par le serveur d’application afin de transformer les classes Java en service web.&lt;/p&gt;  &lt;p&gt;La définition des différentes annotations peut être trouvée sur le site de Sun à l’adresse suivante : &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/jws/package-summary.html"&gt;http://java.sun.com/javaee/5/docs/api/javax/jws/package-summary.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Les annotations simplifient grandement la réalisation de services web. Elles permettent de définir :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;toutes les informations pertinentes pour construire un WSDL à partir de la classe Java &lt;/li&gt;    &lt;li&gt;les correspondances entre les messages SOAP du service web et la méthode de la classe Java responsable du traitement. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Par exemple, il est possible de définir le nom du service web, des opérations et des paramètres.&lt;/p&gt;  &lt;p&gt;Les services web nécessite la présence d’un serveur d’application capable d’être serveur de service web : dans notre tutorial nous allons utiliser WebSphere dans sa version 6.1.&lt;/p&gt;  &lt;h3&gt;Organisation du tutorial&lt;/h3&gt;  &lt;p&gt;Ce tutorial a pour objectif de présenter une mise en œuvre basique d’un Service Web avec WebSphere 6.1.&lt;/p&gt;  &lt;p&gt;Le tutorial comprendra les étapes suivantes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;La configuration du serveur WebSphere &lt;/li&gt;    &lt;li&gt;La réalisation du service web dans Eclipse &lt;/li&gt;    &lt;li&gt;Le déploiement du service web dans WebSphere. &lt;/li&gt;    &lt;li&gt;L’analyse du code et du WSDL &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Configuration&lt;/h3&gt;  &lt;h4&gt;Configuration de Websphere 6.1&lt;/h4&gt;  &lt;p&gt;Le tutorial a été réalisé sur un poste Windows 7.&lt;/p&gt;  &lt;p&gt;Ce tutorial repose sur l’utilisation d’Eclipse 3.5 et sa distribution JEE. Le runtime JDK utilisé par Eclipse est la version 1.5.0_11.&lt;/p&gt;  &lt;p&gt;Le serveur d’application utilisée est une version d’essai de IBM WebSphere 6.1 : il s’agit d’une version 32 bits pour Windows que j’ai installé dans C:\IBM afin d’éviter tout problème de droits lié à Windows 7. Pour que l’installation fonctionne sur mon poste, j’ai du utiliser le fichier responsefile.base.txt et faire une installation en mode commande.&lt;/p&gt;  &lt;p&gt;Je ne rentrerai pas dans le détail de cette installation, ce n’est pas l’objet de ce billet. De même, je ne rentrerai pas dans le détail des installations nécessaires pour les services web : j’ai suivi, l’excellent tutorial (en anglais) qui se trouve à l’adresse suivante : &lt;a title="http://www.myeclipseide.com/documentation/quickstarts/blueedition/blue_install_websphere6.1/" href="http://www.myeclipseide.com/documentation/quickstarts/blueedition/blue_install_websphere6.1/"&gt;http://www.myeclipseide.com/documentation/quickstarts/blueedition/blue_install_websphere6.1/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Je précise que j’ai du récupérer :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’UpdateInstaller de Webphere 6.1.9 : download.updii.61019.windows.ia32.zip : Cet utilitaire est nécessaire à l’installation des Fix Pack. Je l’ai installé dans C:\IBM\WebSphere. &lt;/li&gt;    &lt;li&gt;les 3 Fix Packs suivants :      &lt;ul&gt;       &lt;li&gt;6.1.0-WS-WAS-WinX32-FP0000013.pak &lt;/li&gt;        &lt;li&gt;6.1.0.9-WS-WASWebSvc-IFPK53084.pak &lt;/li&gt;        &lt;li&gt;6.1.0-WS-WASWebSvc-WinX32-FP0000013.pak &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;les 2 feature Packs suivants :      &lt;ul&gt;       &lt;li&gt;6.1.0-WS-WAS-WSFEP-WinX32.zip : pour les Services Web &lt;/li&gt;        &lt;li&gt;fep.61.ejb3.windows.ia32.zip : pour les EJB 3.0 &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Tous les fichiers ont été récupéré depuis le site IBM : il s’agit d’autant de téléchargements supplémentaires. J’ai utilisé l’utilitaire DownLoad Director d’IBM pour tous à l’exception du Fix Pack 6.1.0.9-WS-WASWebSvc-IFPK53084.pak pour lequel le serveur a répondu pendant toute une journée qu’il était occupé. Pour ce dernier, j’ai utilisé le téléchargement par HTTP.&lt;/p&gt;  &lt;p&gt;Attention ! utilisant Windows 7 qui n’est pas officiellement supporté par WebSphere 6.1, j’ai du à plusieurs reprises acquitter un message m’indiquant que je n’avais pas passé le test de compatibilité. Il a toujours été possible de Continuer l’installation. &lt;/p&gt;  &lt;p&gt;De même à chaque fin d’installation, on m’a averti que l’installation s’était peut-être mal passée, j’ai du répondre que je considérais que l’installation était correcte&lt;/p&gt;  &lt;p&gt;En dehors de ces petits avertissements, j’ai respecté à la lettre la procédure d’installation indiquée plus haut qui se décompose comme suit :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;J’ai arrêté mon serveur WebSphere : je suis passé par le menu “Tous les programmes” –&amp;gt; “IBM Websphere” –&amp;gt; “Application Server V6.1” –&amp;gt; Profils –&amp;gt; AppSrv01 –&amp;gt; “Arrêter le serveur”. &lt;/li&gt;    &lt;li&gt;J’ai installé l’UpdateInstaller. &lt;/li&gt;    &lt;li&gt;J’ai copié le fichier 6.1.0-WS-WAS-WinX32-FP0000013.pak dans C:\IBM\WebSphere\updateInstaller\maintenance &lt;/li&gt;    &lt;li&gt;J’ai lancé son installation par l’updateInstaller en cliquant droit sur le menu “Tous les programmes” –&amp;gt; “IBM Websphere” –&amp;gt; “Update Installer for Websphere V6.1 Software –&amp;gt; Update Installer” et choisissant “Executer en tant qu’administrateur” &lt;/li&gt;    &lt;li&gt;J’ai installé (sans passer par l’update installer) le Feature Pack 6.1.0-WS-WAS-WSFEP-WinX32.zip après l’avoir dézippé. &lt;/li&gt;    &lt;li&gt;J’ai copié les fichiers 6.1.0.9-WS-WASWebSvc-IFPK53084.pak et 6.1.0-WS-WASWebSvc-WinX32-FP0000013.pak dans C:\IBM\WebSphere\updateInstaller\maintenance &lt;/li&gt;    &lt;li&gt;J’ai lancé l’installation de 6.1.0.9-WS-WASWebSvc-IFPK53084.pak par l’updateInstaller (toujours en tant qu’administrateur) &lt;/li&gt;    &lt;li&gt;J’ai lancé l’installation de 6.1.0-WS-WASWebSvc-WinX32-FP0000013.pak par l’updateInstaller (toujours en tant qu’administrateur) &lt;/li&gt;    &lt;li&gt;J’ai installé (sans passer par l’update installer) le Feature Pack fep.61.ejb3.windows.ia32.zip après l’avoir dézippé. &lt;/li&gt;    &lt;li&gt;J’ai fait l’augmentation du Profil AppSrv01 en lui ajoutant le profil EJB 3.0 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Je n’ai pas eu besoin de récréé un Profil avec le profil Service Web JAX-WS.&lt;/p&gt;  &lt;p&gt;Cette phase de configuration peut bien prendre un ou deux jours. Il s’agit réellement d’une opération fastidieuse.&lt;/p&gt;  &lt;h4&gt;Création d’un projet Eclipse pour le service web&lt;/h4&gt;  &lt;p&gt;Autant avec JBoss, j’avais pu me contenter de créer un jar (voir mon tutorial &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt;), avec WebSphere 6.1, j’ai été obligé de passer par un WAR.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, on crée un projet de type “Dynamic Web Project” que l’on nommera MaCalculetteWasSwWar. Ces projets permettent la création d’un WAR.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New –&amp;gt; Other.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New, choisir le dossier “Web” puis le nœud “Dynamic Web Project”. Appuyez sur le bouton Next.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-_HFabh4fIrU/TsoraOCXebI/AAAAAAAAFco/PDWpHkpAi90/s1600-h/WSSW40NewWebProject2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW40NewWebProject" border="0" alt="WSSW40NewWebProject" src="http://lh6.ggpht.com/-HfJUTT30H3Y/TsorbALjGrI/AAAAAAAAFcw/fC1P6aXBMv4/WSSW40NewWebProject_thumb.png?imgmax=800" width="244" height="235" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Pour Project name, tapez : MaCalculetteWasSwWar et laissez les autres options par défaut (je rappelle que WebSphere 6.1 utilise un Runtime Java 1.5, il faudra donc éviter d’utiliser un Runtime 1.6).&lt;/p&gt;  &lt;p&gt;Appuyez sur Finish. Acceptez le choix de la perspective si la dialogue « Open Associated Perspective » s’affiche.&lt;/p&gt;  &lt;h4&gt;Ajout des External Jars&lt;/h4&gt;  &lt;p&gt;Nous allons ajouter des external jars au projet : ces jars ne sont pas déployé dans le war. Ils sont juste nécessaire pour la phase de compilation. Il s’agit de jar qui font parti du serveur d’application.&lt;/p&gt;  &lt;p&gt;Il faut importer des jar WebSphere : cliquez droit sur le projet dans l’explorateur et choisissez Properties. Dans la dialogue qui s’ouvre choisir « Java Build Path ».&lt;/p&gt;  &lt;p&gt;Appuyer sur « Add External Jars.. », et utiliser l’explorateur pour aller dans le répertoire &lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;C:\IBM\WebSphere\AppServer\lib et sélectionnez le jar suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;j2ee.jar qui définit l’annotation @Remote &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Validez en appuyant sur Ouvrir.&lt;/p&gt;  &lt;p&gt;Appuyer sur « Add External Jars.. », et utiliser l’explorateur pour aller dans le répertoire C:\IBM\WebSphere\AppServer\runtimes et sélectionnez le jar suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;com.ibm.jaxws.thinclient_6.1.0.jar qui définit les annotations @WebService, @SOAPBinding et @SOAPBinding &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Validez en appuyant sur Ouvrir.&lt;/p&gt;  &lt;p&gt;Validez en appuyant sur le bouton OK.&lt;/p&gt;  &lt;p&gt;Notre poste est maintenant correctement configuré pour construire un Service Web.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Création de l’interface&lt;/h3&gt;  &lt;p&gt;Nous commençons par créer l’interface du service. L’interface définit les méthodes qui seront disponibles dans l’EJB et le service web.&lt;/p&gt;  &lt;p&gt;Nous allons créer l’interface fr.j2ltho.calculette.was.Calculette. Par rapport à la définition d’un EJB, il faut ajouter deux autres informations au niveau de la classe :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le nom du service web qui sera dans notre cas ICalculetteSw &lt;/li&gt;    &lt;li&gt;Le format et le style des messages échangés entre le client et le serveur. En d’autre terme, on choisit entre RPC/encoded et Document/literal, tout comme on choisit pour un Document/Literal s’il est wrapped ou unwrapped. Le format le plus répandu et portable étant Document/Literal/Wrapped c’est ce dernier que l’on retiendra. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ensuite pour chaque méthode, il faut indiquer qu’elle est accessible comme opération du service web, il est possible de définir son nom pour le service web, le nom du paramètre de sortie et le nom des paramètres dans le fichier WSDL (ce point est important car par défaut, leur nom est arg0, arg1…).&lt;/p&gt;  &lt;h4&gt;Création de l’interface&lt;/h4&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Interface.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Interface:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.calculette.was &lt;/li&gt;    &lt;li&gt;Pour Name tapez : Calculette &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Laissez les autres options par défaut et appuyez sur Finish.&lt;/p&gt;  &lt;p&gt;On modifie le code pour définir les deux méthodes add et substract du service.&lt;/p&gt;  &lt;p&gt;On ajoute l’annotation @Remote pour spécifier au conteneur d’EJB qu’il devra créé un lien de type Remote avec cette interface pour l’EJB.&lt;/p&gt;  &lt;h4&gt;Ajout des annotations Service Web&lt;/h4&gt;  &lt;p&gt;On ajoute l’annotation @WebService qui déclare la classe comme un service web. Le paramètre name, permet de définir un nom différent de celui de la classe. C’est le nom du portType du WSDL. Ce sera le nom également de &lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;la classe d’interface cliente si on utilise l’outil JBoss wsconsume pour créer les classes clientes à partir du WSDL.&lt;/p&gt;  &lt;p&gt;On ajoute ensuite l’annotation @SOAPBinding qui permet de définir le format des messages :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le paramètre style permet de choisir entre DOCUMENT et RPC, &lt;/li&gt;    &lt;li&gt;le paramètre use permet de choisir entre LITERAL et ENCODED &lt;/li&gt;    &lt;li&gt;le paramètre parameterStyle entre WRAPPED ou BARE (unwrapped). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Il faut ensuite pour chaque méthode ajouter le tag @WebMethod pour indiquer qu’il s’agira d’une opération du service web. Le paramètre operationName permet de définir un nom dans le WSDL différent de celui de la méthode Java. Il est également possible grâce au tag @WebResult de définir le nom du paramètre de sortie de la méthode tel qu’il apparait dans le WSDL.&lt;/p&gt;  &lt;p&gt;Pour chaque paramètre, il est possible de définir grâce au tag @WebParam son nom (par défaut ce sera arg0, arg…) mais également grâce à la propriété mode si un paramètre est IN, OUT ou IN/OUT.&lt;/p&gt;  &lt;p&gt;On obtient le code suivant (en gras le code ajouté par rapport à l’EJB):&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.calculette.was;&lt;/p&gt;    &lt;p&gt;import javax.ejb.Remote;      &lt;br /&gt;import javax.jws.WebMethod;       &lt;br /&gt;import javax.jws.WebParam;       &lt;br /&gt;import javax.jws.WebResult;       &lt;br /&gt;import javax.jws.WebService;       &lt;br /&gt;import javax.jws.soap.SOAPBinding;       &lt;br /&gt;import javax.jws.soap.SOAPBinding.Style;&lt;/p&gt;    &lt;p&gt;     &lt;br /&gt;@Remote       &lt;br /&gt;&lt;strong&gt;@WebService(name = &amp;quot;ICalculetteSw&amp;quot;)        &lt;br /&gt;@SOAPBinding(style=Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle= SOAPBinding.ParameterStyle.WRAPPED)         &lt;br /&gt;&lt;/strong&gt;public interface Calculette {&lt;/p&gt;    &lt;p&gt;     &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebMethod(operationName=&amp;quot;ajouterWithWAS&amp;quot;)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @WebResult(name = &amp;quot;resultat&amp;quot;)         &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; public int add(int x, int y);&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebMethod        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; public int subtract(       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebParam(name = &amp;quot;x&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; int x,       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; @WebParam(name = &amp;quot;y&amp;quot;)        &lt;br /&gt;&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; int y);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;    &lt;p&gt;}      &lt;br /&gt;&lt;/p&gt; &lt;/div&gt;  &lt;h3&gt;Création du Bean&lt;/h3&gt;  &lt;p&gt;Pour la classe qui implémente le service web défini par l’interface précédente, il est possible d’utiliser l’implémentation de l’EJB : Il suffira d’y ajouter l’annotation @Webservice en indiquant la propriété endpointInterface : cette propriété doit pointer vers l’interface du service. C’est grâce aux informations contenue dans l’interface que le conteneur saura quel WSDL généré.&lt;/p&gt;  &lt;p&gt;Nous commençons par créer la classe qui implémente le service.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.calculette.was &lt;/li&gt;    &lt;li&gt;Pour Name tapez : CalculetteBean &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Appuyez, sur le bouton Add.. afin de définir l’interface. Dans la dialogue « Implemented Interfaces Selection » tapez Calculette puis sélectionnez l’interface Calculette – fr.j2ltho.calculette.was de votre projet. Validez en appuyant sur Ok. La dialogue se referme et l’interface apparait dans la liste Interfaces de la dialogue « New java Class ».&lt;/p&gt;  &lt;p&gt;Laissez les autres options par défaut et appuyez sur Finish. Le code de la classe apparait avec les deux méthodes créées, il faut maintenant compléter le code.&lt;/p&gt;  &lt;p&gt;Il faut également ajouter :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’annotation @Stateless en début de classe. Cette annotation précise que cet EJB sera sans état : il ne conserve pas une mémoire de ce qu’il a fait précédemment. &lt;/li&gt;    &lt;li&gt;l’annotation @WebService pour indiquer la classe d’interface qui contient les annotations décrivant le service web. Il permet également de définir le nom du service web tel qu’il apparait dans le WSDL. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.calculette.was;&lt;/p&gt;    &lt;p&gt;import javax.ejb.Stateless;      &lt;br /&gt;import javax.jws.WebService;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;@Stateless        &lt;br /&gt;@WebService(endpointInterface=&amp;quot;fr.j2ltho.calculette.was.Calculette&amp;quot;, serviceName=&amp;quot;CalculetteWasSw&amp;quot;)         &lt;br /&gt;&lt;/strong&gt;public class CalculetteBean implements Calculette {&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public int add(int x, int y) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return x + y ;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public int subtract(int x, int y) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return x - y;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Assurez vous d’avoir bien sauvegarder la classe et son interface.&lt;/p&gt;  &lt;h3&gt;Déploiement du service web sur Websphere 6.1&lt;/h3&gt;  &lt;p&gt;Nous avons du créer un Dynamic Web Project afin de pouvoir créer simplement un WAR pour déployer le Service Web dans Websphere.&lt;/p&gt;  &lt;p&gt;Avant de créer le war puis de le déployer, nous allons finir la configuration du projet en modifiant le fichier web.xml afin d’y déclarer notre service web.&lt;/p&gt;  &lt;h4&gt;Déclarer un service web dans le web.xml&lt;/h4&gt;  &lt;p&gt;Dans le répertoire WebContent –&amp;gt; WEB-INF de votre projet, se trouve le fichier web.xml. Editer ce fichier.&lt;/p&gt;  &lt;p&gt;On ajoute la déclaration de la servlet qui correspondra au service web.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;servlet-name correspond au serviceName de l’annotation WebService du bean CalculetteBean. C’est ce nom qui sera utilisé pour accéder au WSDL &lt;/li&gt;    &lt;li&gt;servlet-class correspond au nom complet du bean qui implémente le service web. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;      &lt;br /&gt;&amp;lt;web-app xmlns:xsi=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema-instance&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/a&gt; xmlns=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee&amp;quot;&lt;/a&gt; xmlns:web=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/a&gt; xsi:schemaLocation=&amp;quot;&lt;a href="http://java.sun.com/xml/ns/javaee"&gt;http://java.sun.com/xml/ns/javaee&lt;/a&gt; &lt;a href="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;"&gt;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/a&gt; id=&amp;quot;WebApp_ID&amp;quot; version=&amp;quot;2.5&amp;quot;&amp;gt;       &lt;br /&gt;&amp;#160; &amp;lt;display-name&amp;gt;MaCalculetteWasSwWar&amp;lt;/display-name&amp;gt;       &lt;br /&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;servlet&amp;gt;        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;servlet-name&amp;gt;CalculetteWasSw&amp;lt;/servlet-name&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;servlet-class&amp;gt;fr.j2ltho.calculette.was.CalculetteBean&amp;lt;/servlet-class&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/servlet&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;servlet-mapping&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;servlet-name&amp;gt;CalculetteWasSw&amp;lt;/servlet-name&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/servlet-mapping&amp;gt;         &lt;br /&gt;&lt;/strong&gt;&amp;#160; &amp;lt;welcome-file-list&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;index.html&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;index.htm&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;index.jsp&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;default.html&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;default.htm&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;welcome-file&amp;gt;default.jsp&amp;lt;/welcome-file&amp;gt;       &lt;br /&gt;&amp;#160; &amp;lt;/welcome-file-list&amp;gt;       &lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;h4&gt;Génération du War&lt;/h4&gt;  &lt;p&gt;Assurez vous d’avoir bien sauvegarder l’ensemble des fichiers.&lt;/p&gt;  &lt;p&gt;Cliquez droit dans l’explorateur de ressource d’Eclipse sur votre projet MaCalculetteWasSwWar, sélectionnez Export –&amp;gt; WAR File, dans la dialogue « Export » qui s’affiche choisissez :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Web Project : MaCalculetteWasSwWar qui est le nom de votre projet &lt;/li&gt;    &lt;li&gt;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 MaCalculetteWasSwWar.war. &lt;/li&gt;    &lt;li&gt;Décochez l’option “Optimize for a specific server runtime” &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-CqVsho3ducY/TsorcNAMECI/AAAAAAAAFc4/cE6g_LOqT4A/s1600-h/WSSW410exportWar3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW410exportWar" border="0" alt="WSSW410exportWar" src="http://lh5.ggpht.com/-3Mb9v60raxg/TsordY75uPI/AAAAAAAAFdA/EPQcR-KHOa4/WSSW410exportWar_thumb1.png?imgmax=800" width="638" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Appuyez, ensuite sur Finish. Vous devriez trouver un fichier MaCalculetteWasSwWar.war sur le bureau.&lt;/p&gt;  &lt;h4&gt;Déploiement sous WebSphere 6.1&lt;/h4&gt;  &lt;p&gt;Le serveur doit être lancé, soit il est lancé automatiquement au démarrage (en tant que service Windows), soit il peut être démarré par le menu : “Tous les programmes” –&amp;gt; “IBM Websphere” –&amp;gt; “Application Server V6.1” –&amp;gt; Profils –&amp;gt; AppSrv01 –&amp;gt; “Démarrer le serveur”. &lt;/p&gt;  &lt;p&gt;On se connecte à la console d’administration : &lt;a title="https://localhost:9043/ibm/console/logon.jsp" href="https://localhost:9043/ibm/console/logon.jsp"&gt;https://localhost:9043/ibm/console/logon.jsp&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Sélectionnez sous le nœud Applications le lien “Installation d’une nouvelle application”&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-GnkfA_OBoKs/TsoreebrGLI/AAAAAAAAFdI/ol2f2w1fEVE/s1600-h/WSSW30AddApplication3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW30AddApplication" border="0" alt="WSSW30AddApplication" src="http://lh4.ggpht.com/-nDEG7zek4Qo/Tsorfcdwp7I/AAAAAAAAFdQ/vlvKT_RvblI/WSSW30AddApplication_thumb1.png?imgmax=800" width="644" height="251" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Dans Système de fichiers local, sélectionnez MaCalculetteWasSwWar.war et saisir pour :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Racine du contexte : MaCalculetteWasSwWar : j’ai repris le nom du projet Eclipse qui est également le display name du web.xml. Cela sera utile pour récupérer le WSDL. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;En théorie, cet écran permet le déploiement direct d’un JAR. Cette option ne fonctionne que suite à l’installation de la série de Feature et Fix Packs. Sans ces packs, il n’est pas possible d’installer simplement un jar dans WebSphere 6.1. Néanmoins dans mon cas, si le JAR semble avoir été correctement déployé, je n’ai pas pu accéder au WSDL. L’application WebSphere résultant du déploiement n’avait pas les mêmes options que celle contenant un Service Web correctement déployé. C’est pour cette raison que nous sommes passé dans ce tutorial par un WAR.&lt;/p&gt;  &lt;p&gt;Appuyez sur Suivant.&lt;/p&gt;  &lt;p&gt;Sur l’écran “sélection des options d’installation”, on choisit :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;On coche : “Déploiement de beans entreprise” &lt;/li&gt;    &lt;li&gt;Nom de l’application : on laisse le nom par défaut en : MaCalculetteWasSwWar_war &lt;/li&gt;    &lt;li&gt;On coche “Déploiement de services Web” &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-djpiEwB_uRI/Tsorg2lEALI/AAAAAAAAFdY/eQKRv13GNXU/s1600-h/WSSW42AddAppOption3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW42AddAppOption" border="0" alt="WSSW42AddAppOption" src="http://lh3.ggpht.com/-4vLNcsnTmjk/Tsorh8rlGLI/AAAAAAAAFdg/4PzkC3wkMXo/WSSW42AddAppOption_thumb1.png?imgmax=800" width="524" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;On appuie sur Suivant, sur l’écran “Mapper les modules vers les serveurs”, je laisse les options par défaut :&lt;/p&gt;  &lt;p&gt;On appuie sur Suivant puis Terminer. L’écran Installation en cours s’affiche. On obtient après un délai, la page suivante :&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-AOcMoFkymRk/TsorkKydEII/AAAAAAAAFds/2lSgZIAvPnk/s1600-h/WSSW43ResultAddApp3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW43ResultAddApp" border="0" alt="WSSW43ResultAddApp" src="http://lh3.ggpht.com/-7bsbCYzVkNM/TsorlgZ6abI/AAAAAAAAFd0/m-dBB5pCkhY/WSSW43ResultAddApp_thumb1.png?imgmax=800" width="593" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;On appuie sur le lien Sauvegarder qui se trouve en bas de la page.&lt;/p&gt;  &lt;p&gt;Si on clique ensuite sur “Applications d’entreprise”, on doit voir une ligne MaCalculetteWasSwWar_war qui s’affiche : il s’agit du nom par défaut laissé à l’étape “Sélection des options d’installation”&lt;/p&gt;  &lt;p&gt;Il faut démarrer l’application : cochez la case en début de ligne puis appuyez sur le bouton Démarrer. Après un lapse de temps, une flèche verte s’affiche en fin de ligne.&lt;/p&gt;  &lt;h4&gt;Vérifier le déploiement&lt;/h4&gt;  &lt;p&gt;Dans “Applications d’entreprise”,&amp;#160; il est possible de cliquer sur le lien MaCalculetteWasSwWar_war. Cela affiche la page de configuration de l’application.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-YX5dK2a2AIs/TsormW0paNI/AAAAAAAAFd8/QyUdBNqee9I/s1600-h/WSSW44DefAppSW3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW44DefAppSW" border="0" alt="WSSW44DefAppSW" src="http://lh6.ggpht.com/-jGqny4Dz5aM/TsornZG-1DI/AAAAAAAAFeE/vnA74nDCTPg/WSSW44DefAppSW_thumb1.png?imgmax=800" width="644" height="443" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Pour un application contenant un service web fonctionnant correctement, vous pouvez appuyer sur le lien “Publication des fichiers WSDL” dans la rubrique “Propriétés des services Web”.&lt;/p&gt;  &lt;p&gt;Sur la nouvelle page, vous devriez avoir une ligne indiquant un fichier zip contenant le WSDL de votre service web.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-qlISG6qKwvw/TsoroRJnQFI/AAAAAAAAFeM/DblIFY_jTTY/s1600-h/WSSW45WSDL3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WSSW45WSDL" border="0" alt="WSSW45WSDL" src="http://lh4.ggpht.com/-F5gSLGhEImA/TsorpTIkNaI/AAAAAAAAFeU/jTpVAnJM3IQ/WSSW45WSDL_thumb1.png?imgmax=800" width="644" height="172" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Si vous obtenez le même résultat, cela indique que votre service web est correctement déployé.&lt;/p&gt;  &lt;h3&gt;Analyse du WSDL&lt;/h3&gt;  &lt;p&gt;Dans cette dernière partie nous allons récupérer le WSDL non pas par la console d’administration mais directement par un navigateur puis, nous allons l’analyser.&lt;/p&gt;  &lt;h4&gt;Récupération du WSDL&lt;/h4&gt;  &lt;p&gt;Pour récupérer le WSDL d’un Web Service déployé sous WebSphere 6.1, il faut taper l’URL suivante : &lt;a href="http://localhost:9080/MaCalculetteWasSwWar/CalculetteWasSw?WSDL" target="_blank"&gt;http://localhost:9080/MaCalculetteWasSwWar/CalculetteWasSw?WSDL&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Où :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;MaCalculetteWasSwWar est la Racine du contexte qui est spécifiée lors du déploiement du Service Web dans la console d’administration &lt;/li&gt;    &lt;li&gt;CalculetteWasSw est le servlet-name dans le web.xml. Il correspond également au serviceName du bean. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Si vous obtenez l’erreur suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Error 404: No target servlet configured for uri:&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Vérifier le nom MaCalculetteWasSwWar qui doit correspondre à la racine du contexte.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Si vous obtenez l’erreur suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Error 404: SRVE0201E: Le servlet [fr.j2ltho.calculette.was.CalculetteBean] : n'est pas une classe de servlet&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Vérifier le nom CalculetteWasSw qui doit correspondre au servlet name du web.xml. La racine du contexte est correcte. C’est le nom du service qui est incorrecte.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Nous allons analyser succinctement son contenu afin de mettre en évidence les correspondances entre les annotations et le contenu du WSDL.&lt;/p&gt;  &lt;h4&gt;ServiceName&lt;/h4&gt;  &lt;p&gt;Tout d’abord le premier tag, le tag definition :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;definitions name=&amp;quot;&lt;strong&gt;CalculetteWasSw&lt;/strong&gt;&amp;quot; targetNamespace=&amp;quot;&lt;a href="http://was.calculette.j2ltho.fr/&amp;quot;"&gt;http://was.calculette.j2ltho.fr/&amp;quot;&lt;/a&gt;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il contient le nom du Service Web tel qu’il est définit par la propriété serviceName dans l’annotation @WebService du bean d’implémentation.&lt;/p&gt;  &lt;p&gt;On retrouve ce nom de service dans le tag service à la fin du WSDL :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;service name=&amp;quot;&lt;strong&gt;CalculetteWasSw&lt;/strong&gt;&amp;quot;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Choix du protocole et du format des messages&lt;/h4&gt;  &lt;p&gt;Le service web est la collection de protocoles qu’il est possible d’utiliser pour déclencher un traitement donné. Dans certains cas plusieurs protocoles peuvent être mis à disposition comme SOAP 1.1, SOAP 1.2 et http.&lt;/p&gt;  &lt;p&gt;Le protocole est de type SOAP 1.1. Un seul mécanisme est retenu dans cette implémentation. Il n’y a qu’un seul tag port dans le tag service, de même il n’y a qu’un seul tag binding. C’est la présence de l’annotation @SOAPBinding qui est responsable du choix du protocole SOAP.&lt;/p&gt;  &lt;p&gt;Cette annotation permet également de définir le format du message :&lt;/p&gt;  &lt;p&gt;Le paramètre style permet de choisir entre DOCUMENT et RPC : cela est visible dans le tag soap:binding la propriété style indique le style.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;soap:binding style=&amp;quot;&lt;strong&gt;document&lt;/strong&gt;&amp;quot; transport=&amp;quot;&lt;a href="http://schemas.xmlsoap.org/soap/http&amp;quot;/"&gt;http://schemas.xmlsoap.org/soap/http&amp;quot;/&lt;/a&gt;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le paramètre use permet de choisir entre LITERAL et ENCODED : cela est visible dans les tags soap:body avec la propriété use qui indique le mécanisme d’encodage :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;soap:body use=&amp;quot;&lt;b&gt;literal&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Pour finir, le paramètre parameterStyle permettait de choisir entre WRAPPED ou BARE (unwrapped). Le mode WRAPPED implique que dans le message appelant, les paramètres sont encapsulés dans un type portant le nom de l’opération. On peut le vérifier dans la partie message ou operation du WSDL où l’on voit la définition de l’opération ajouterWithWAS indiquer un input message (notez que cette partie diffère de ce que l’on obtient sur JBoss : les noms de message diffère) :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;operation name=&amp;quot;&lt;strong&gt;ajouterWithWAS&lt;/strong&gt;&amp;quot;&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;input message=&amp;quot;tns:ajouterWithWAS&amp;quot;&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/input&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;output message=&amp;quot;tns:ajouterWithWASResponse&amp;quot;&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/output&amp;gt;       &lt;br /&gt;&amp;lt;/operation&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Cet input message fait référence à un message composé d’un unique élément qui porte comme nom ajouterWithWAS (le nom de l’opération) :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;message name=&amp;quot;ajouterWithWAS&amp;quot;&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;part name=&amp;quot;parameters&amp;quot; element=&amp;quot;tns:ajouterWithWAS&amp;quot;&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/part&amp;gt;       &lt;br /&gt;&amp;lt;/message&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;h4&gt;Les annotations sur les méthodes&lt;/h4&gt;  &lt;p&gt;Les annotations @WebMethod, @WebResult et @WebParam utilisées dans l’interface modifie les noms par défaut des opérations dans le WSDL.&lt;/p&gt;  &lt;p&gt;On a pu constater que la propriété operationName de @WebMethod a permis pour la méthode add que celle-ci apparaisse sous le nom de ajouterWithWAS dans le WSDL. Le nom par défaut aurez été add (on peut le vérifier avec la méthode substract).&lt;/p&gt;  &lt;h4&gt;Définition des types&lt;/h4&gt;  &lt;p&gt;Le WSDL généré par WebSphere n’inclut pas la définition des types : les arguments et les résultats.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;types&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160; &amp;lt;xsd:schema&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;xsd:import namespace=&amp;quot;&lt;a href="http://was.calculette.j2ltho.fr/&amp;quot;"&gt;http://was.calculette.j2ltho.fr/&amp;quot;&lt;/a&gt; schemaLocation=&amp;quot;CalculetteWasSw_schema1.xsd&amp;quot;/&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160; &amp;lt;/xsd:schema&amp;gt;       &lt;br /&gt;&amp;lt;/types&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le tag types indique qu’on importe un schéma qui se trouve dans le fichier CalculetteWasSw_schema1.xsd. &lt;/p&gt;  &lt;p&gt;Pour afficher la définition, il faut taper l’URL suivante : &lt;a href="http://localhost:9080/MaCalculetteWasSwWar/CalculetteWasSw/CalculetteWasSw_schema1.xsd"&gt;http://localhost:9080/MaCalculetteWasSwWar/CalculetteWasSw/CalculetteWasSw_schema1.xsd&lt;/a&gt; où l’on a remplacé le wsdl par le nom du schéma devant être importé : CalculetteWasSw_schema1.xsd.&lt;/p&gt;  &lt;p&gt;Avec l’opération ajouterWithWAS, on constate que les noms des arguments de la méthode sont peu significatifs :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;ajouterWithWAS&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;arg0&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot;/&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;arg1&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot;/&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le WSDL étant le contrat entre le client et le serveur, il est également la première source de documentation pour utiliser un service web, il est donc souhaitable que les noms d’éléments soient plus significatifs. On a utilisé pour cela l’annotation @WebParam pour la méthode substract afin d’imposer la valeur de la propriété name. Il faut également savoir que c’est cette valeur qui sera prise par l’outil wsconsume de JBoss afin de nommer les paramètres lors de la génération du stub client (comme on le verra plus loin). En conséquence des noms correctes et significatifs vont grandement simplifier l’utilisation du service.&lt;/p&gt;  &lt;p&gt;Pour finir, on constate que l’annotation @WebResult a permis de renommer le nom de l’élément de sortie (la valeur renvoyée par la méthode) :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;ajouterWithWASResponse&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;resultat&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On obtient une valeur resultat au lieu de return : cela n’a priori pas d’intérêt particulier dans notre cas.&lt;/p&gt;  &lt;h4&gt;PortType ou name de @WebService&lt;/h4&gt;  &lt;p&gt;On constate que la propriété name du tag portType du WSDL reprend la valeur de la propriété name de l’annotation @Webservice de l’interface.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;portType name=&amp;quot;&lt;strong&gt;ICalculetteSw&lt;/strong&gt;&amp;quot;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Ce nom est utilisé lors de la génération des classes Java cliente avec l’outil wsconsume comme nom pour la classe d’interface qui sera utilisée. Je vous conseille donc d’utiliser le même nom que celui de l’interface afin de simplifier votre développement.&lt;/p&gt;  &lt;h4&gt;Types des données&lt;/h4&gt;  &lt;p&gt;Les données pour les types simples qu’on a utilisés utilisent des types simples du XMLSchema :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;b&gt;arg0&lt;/b&gt;&amp;quot; type=&amp;quot;&lt;b&gt;xs:int&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;b&gt;arg1&lt;/b&gt;&amp;quot; type=&amp;quot;&lt;b&gt;xs:int&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Ces types simples sont indépendants des langages de programmation. Cela est un point positif.&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Ce tutorial est déjà bien long, je ne montrerai pas la création d’un client. Vous pouvez néanmoins vous reporter à mon tutorial sur les Service Web avec JBoss 5.1 : &lt;a title="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html" href="http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html"&gt;http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html&lt;/a&gt;. J’y décris longuement la création d’un client. Faites attention ! l’url du WSDL n’est pas la même et les noms de méthodes et services sont différents : il vous faudra faire preuve d’un minimum d’adaptation.&lt;/p&gt;  &lt;p&gt;L’exemple est volontairement simple et certainement pas très significatif vis-à-vis de la problématique d’un véritable projet mais il donne un point de départ pour la création de service web sans utiliser tout l’outillage d’IBM : Nous n’avons, hors phase de déploiement, utilisé que des mécanismes standards : ceux sont les mêmes que j’ai utilisé dans mon tutorial JBoss 5.1.&lt;/p&gt;  &lt;p&gt;La seule adaptation a été l’utilisation d’un WAR pour le déploiement du service web : on reste ainsi dans une approche standard du déploiement.&lt;/p&gt;  &lt;p&gt;Le service web déployé sous WebSphere 6.1 peut être appelé en utilisant un client JBoss 5.1. J’ai testé avec succès l’utilisation du wsconsume de JBoss pour générer mon client. La norme des services web joue (sur une exemple simple) son rôle : faciliter l’interopérabilité entre différentes technologies.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-8748341972515525929?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/8748341972515525929/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=8748341972515525929&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/8748341972515525929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/8748341972515525929'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/ce-tutorial-adapte-pour-ibm-websphere-6.html' title='Tutorial Service Web avec WebSphere 6.1'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-HfJUTT30H3Y/TsorbALjGrI/AAAAAAAAFcw/fC1P6aXBMv4/s72-c/WSSW40NewWebProject_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-7184755040757478778</id><published>2011-11-11T18:57:00.001+02:00</published><updated>2011-11-15T15:13:29.476+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Service Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><title type='text'>Tutorial Service Web avec JBosss 5.1</title><content type='html'>&lt;p&gt;Ce tutorial actualise la version que j’avais écrite en 2007 avec le serveur JBoss 4.2 : elle est disponible à l’url suivante : &lt;a href="http://jl2tho.blogspot.com/2007/05/tutorial-service-web-avec-jbosss-42.html" target="_blank"&gt;Tutorial Service Web avec JBoss 4.2&lt;/a&gt;. Ce nouveau tutorial présente la création d’un Service Web très simple avec JBoss 5.1.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Une rapide présentation des Services Web avec JBoss&lt;/h3&gt; JBoss s’appuie sur les EJB 3.0 pour définir et implémenter les Services Web. La version 5.1 de JBoss inclut à la fois le conteneur d’EJB et un module Service Web.   &lt;p&gt;Aucun rappel ne sera fait sur les EJB dans ce post : je vous renvoie donc au post que j’avais écris à l’époque : &lt;a href="http://jl2tho.blogspot.com/2007/05/tutorial-ejb-30-de-session-avec-jboss.html"&gt;Tutorial EJB 3.0 de session avec JBoss 4.2&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Le module service web fait partie du package default. Vous devez trouver dans le répertoire deploy de la configuration default, un sous répertoire jbossws.sar. &lt;/p&gt;  &lt;p&gt;JBoss respecte les spécifications de JAX-WS pour la définition des services web. Cette norme définit un ensemble d’annotations qui permettent la transformation d’un EJB 3.0 en service web. Les annotations sont interprétées par le serveur d’application afin de transformer les classes Java en service web.&lt;/p&gt;  &lt;p&gt;La définition des différentes annotations peuvent être trouvées sur le site de Sun à l’adresse suivante : &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/jws/package-summary.html"&gt;http://java.sun.com/javaee/5/docs/api/javax/jws/package-summary.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Les annotations simplifient grandement la réalisation de services web. Elles permettent de définir :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;toutes les informations pertinentes pour construire un WSDL à partir de la classe Java &lt;/li&gt;    &lt;li&gt;les correspondances entre les messages SOAP du service web et la méthode de la classe Java responsable du traitement. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Par exemple, il est possible de définir le nom du service web, des opérations et des paramètres.&lt;/p&gt;  &lt;p&gt;Les services web nécessite la présence d’un serveur d’application capable d’être serveur de service web : dans notre tutorial nous allons utiliser JBoss dans sa version 5.1.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Organisation du tutorial&lt;/h3&gt;  &lt;p&gt;Ce tutorial a pour objectif de présenter une mise en œuvre basique d’un Service Web avec JBoss 5.1.&lt;/p&gt;  &lt;p&gt;Nous ne reprendrons pas l’installation et la configuration de JBoss 5.1 décrite dans le tutorial : &lt;a href="http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html" target="_blank"&gt;Installation de JBoss 5.1 sur Windows 7 64 bits&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Un Service Web est avant tout un EJB, il est possible de reprendre n’importe quel EJB et de le compléter afin de le transformer en Service Web.&lt;/p&gt;  &lt;p&gt;Ce tutorial repose sur l’utilisation d’Eclipse 3.5 et sa distribution JEE.&lt;/p&gt;  &lt;p&gt;Le tutorial comprendra les étapes suivantes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;La réalisation du service web dans Eclipse &lt;/li&gt;    &lt;li&gt;La construction du client pour ce service web réalisé dans un autre projet Eclipse. &lt;/li&gt;    &lt;li&gt;L’analyse du code et du WSDL &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Configuration&lt;/h3&gt;  &lt;p&gt;Le tutorial a été réalisé sur un poste Windows 7.&lt;/p&gt;  &lt;p&gt;Le runtime et le jdk Java sont à la version 1.5.0_11.&lt;/p&gt;  &lt;p&gt;Pour JBoss, j’ai utilisé la version 5.1 : l’installation est décrite dans le billet : &lt;a href="http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html" target="_blank"&gt;Installation de JBoss 5.1 sur Windows 7 64 bits&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Création d’un projet Eclipse pour le service web&lt;/h3&gt;  &lt;p&gt;Dans Eclipse, on crée un projet Java simple que l’on nommera MaCalculetteSW.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Project.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Project, choisir le dossier Java puis le nœud Java Project. Appuyez sur le bouton Next.&lt;/p&gt;  &lt;p&gt;Pour Project name, tapez : MaCalculetteSW et laissez les autres options par défaut.&lt;/p&gt;  &lt;p&gt;Appuyez sur Finish. Acceptez le choix de la perspective Java si la dialogue « Open Associated Perspective » s’affiche.&lt;/p&gt;  &lt;p&gt;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 ».&lt;/p&gt;  &lt;p&gt;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 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jboss-javaee.jar qui définit les annotations @Stateless et @Remote &lt;/li&gt;    &lt;li&gt;Jbossws-native-jaxws.jar qui définit les annotations @WebService, @SOAPBinding et @SOAPBinding &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Validez en appuyant sur Ok.&lt;/p&gt;  &lt;p&gt;Notre poste est maintenant correctement configuré pour construire un Service Web.&lt;/p&gt;  &lt;p&gt;Pour information, avec JBoss 6.0 Final, les jars ont de nouveau changé : il s’agit de :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;jboss-ejb-api_3.1_spec.jar&lt;/li&gt;    &lt;li&gt;jsr181-api.jar&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;qui se trouvent tous les deux dans c:\jboss-6.0.0\common\lib&lt;/p&gt;  &lt;h3&gt;Création de l’interface&lt;/h3&gt;  &lt;p&gt;Nous commençons par créer l’interface du service. L’interface définit les méthodes qui seront disponibles dans l’EJB et le service web.&lt;/p&gt;  &lt;p&gt;Nous allons créer l’interface fr.j2ltho.calculette.ejb. MaCalculette. Par rapport à la définition d’un EJB, il faut ajouter deux autres informations au niveau de la classe :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le nom du service web qui sera dans notre cas MaCalculetteSw &lt;/li&gt;    &lt;li&gt;Le format et le style des messages échangés entre le client et le serveur. En d’autre terme, on choisit entre RPC/encoded et Document/literal, tout comme on choisit pour un Document/Literal s’il est wrapped ou unwrapped. Le format le plus répandu et portable étant Document/Literal/Wrapped c’est ce dernier que l’on retiendra. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ensuite pour chaque méthode, il faut indiquer qu’elle est accessible comme opération du service web, il est possible de définir son nom pour le service web, le nom du paramètre de sortie et le nom des paramètres dans le fichier WSDL (ce point est important car par défaut, leur nom est arg0, arg1…).&lt;/p&gt;  &lt;h4&gt;Création de l’interface&lt;/h4&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Interface.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Interface:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.calculette.ejb &lt;/li&gt;    &lt;li&gt;Pour Name tapez : MaCalculette &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Laissez les autres options par défaut et appuyez sur Finish.&lt;/p&gt;  &lt;p&gt;On modifie le code pour définir les deux méthodes add et substract du service.&lt;/p&gt;  &lt;p&gt;On ajoute l’annotation @Remote pour spécifier au conteneur d’EJB qu’il devra créé un lien de type Remote avec cette interface pour l’EJB.&lt;/p&gt;  &lt;h4&gt;Ajout des annotations Service Web&lt;/h4&gt;  &lt;p&gt;On ajoute l’annotation @WebService qui déclare la classe comme un service web. Le paramètre name, permet de définir un nom différent de celui de la classe. C’est le nom du portType du WSDL. Ce sera le nom également de la classe d’interface cliente si on utilise l’outil JBoss wsconsume pour créer les classes clientes à partir du WSDL.&lt;/p&gt;  &lt;p&gt;On ajoute ensuite l’annotation @SOAPBinding qui permet de définir le format des messages :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le paramètre style permet de choisir entre DOCUMENT et RPC, &lt;/li&gt;    &lt;li&gt;le paramètre use permet de choisir entre LITERAL et ENCODED &lt;/li&gt;    &lt;li&gt;le paramètre parameterStyle entre WRAPPED ou BARE (unwrapped). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Il faut ensuite pour chaque méthode ajouter le tag @WebMethod pour indiquer qu’il s’agira d’une opération du service web. Le paramètre operationName permet de définir un nom dans le WSDL différent de celui de la méthode Java. Il est également possible grâce au tag @WebResult de définir le nom du paramètre de sortie de la méthode tel qu’il apparait dans le WSDL.&lt;/p&gt;  &lt;p&gt;Pour chaque paramètre, il est possible de définir grâce au tag @WebParam son nom (par défaut ce sera arg0, arg…) mais également grâce à la propriété mode si un paramètre est IN, OUT ou IN/OUT.&lt;/p&gt;  &lt;p&gt;On obtient le code suivant (en gras le code ajouté par rapport à l’EJB):&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.calculette.ejb;&lt;/p&gt;    &lt;p&gt;import javax.ejb.Remote;&lt;/p&gt;    &lt;p&gt;import javax.jws.WebMethod;&lt;/p&gt;    &lt;p&gt;import javax.jws.WebParam;&lt;/p&gt;    &lt;p&gt;import javax.jws.WebResult;&lt;/p&gt;    &lt;p&gt;import javax.jws.WebService;&lt;/p&gt;    &lt;p&gt;import javax.jws.soap.SOAPBinding;&lt;/p&gt;    &lt;p&gt;import javax.jws.soap.SOAPBinding.Style;&lt;/p&gt;    &lt;p&gt;@Remote&lt;/p&gt;    &lt;p&gt;&lt;b&gt;@WebService&lt;/b&gt;&lt;b&gt;(name = &lt;/b&gt;&lt;b&gt;&amp;quot;MaCalculetteSw&amp;quot;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;@SOAPBinding&lt;/b&gt;&lt;b&gt;(style=Style.&lt;/b&gt;&lt;b&gt;&lt;i&gt;DOCUMENT&lt;/i&gt;&lt;/b&gt;&lt;b&gt;, use=&lt;/b&gt;&lt;b&gt;SOAPBinding&lt;/b&gt;&lt;b&gt;.Use.&lt;/b&gt;&lt;b&gt;&lt;i&gt;LITERAL&lt;/i&gt;&lt;/b&gt;&lt;b&gt;, parameterStyle= &lt;/b&gt;&lt;b&gt;SOAPBinding&lt;/b&gt;&lt;b&gt;.ParameterStyle.&lt;/b&gt;&lt;b&gt;&lt;i&gt;WRAPPED&lt;/i&gt;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;public interface MaCalculette {&lt;/p&gt;    &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;@WebMethod&lt;/b&gt;&lt;b&gt;(operationName=&lt;/b&gt;&lt;b&gt;&amp;quot;ajouter&amp;quot;&lt;/b&gt;&lt;b&gt;) &lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;@WebResult&lt;/b&gt;&lt;b&gt;(name = &lt;/b&gt;&lt;b&gt;&amp;quot;resultat&amp;quot;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;public int add(int x, int y);&lt;/p&gt;    &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;@WebMethod&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;public int subtract(&lt;/p&gt;    &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;@WebParam&lt;/b&gt;&lt;b&gt;(name = &lt;/b&gt;&lt;b&gt;&amp;quot;x&amp;quot;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;int x,&lt;/p&gt;    &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;@WebParam&lt;/b&gt;&lt;b&gt;(name = &lt;/b&gt;&lt;b&gt;&amp;quot;y&amp;quot;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;int y);&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt; &lt;/div&gt;  &lt;h3&gt;Création du Bean&lt;/h3&gt;  &lt;p&gt;Pour la classe qui implémente le service web défini par l’interface précédente, il est possible d’utiliser l’implémentation de l’EJB : Il suffira d’y ajouter l’annotation @Webservice en indiquant la propriété endpointInterface : cette propriété doit pointer vers l’interface du service. C’est grâce aux informations contenue dans l’interface que le conteneur saura quel WSDL généré.&lt;/p&gt;  &lt;p&gt;Nous commençons par créer la classe qui implémente le service.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.calculette.ejb &lt;/li&gt;    &lt;li&gt;Pour Name tapez : MaCalculetteBean &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Appuyez, sur le bouton Add.. afin de définir l’interface. Dans la dialogue « Implemented Interfaces Selection » tapez MaCalculette puis sélectionnez l’interface MaCalculette – fr.j2ltho.calculette.ejb de votre projet. Validez en appuyant sur Ok. La dialogue se referme et l’interface apparait dans la liste Interfaces de la dialogue « New java Class ».&lt;/p&gt;  &lt;p&gt;Laissez les autres options par défaut et appuyez sur Finish. Le code de la classe apparait avec les deux méthodes créées, il faut maintenant compléter le code.&lt;/p&gt;  &lt;p&gt;Il faut également ajouter :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;l’annotation @Stateless en début de classe. Cette annotation précise que cet EJB sera sans état : il ne conserve pas une mémoire de ce qu’il a fait précédemment. &lt;/li&gt;    &lt;li&gt;l’annotation @WebService pour indiquer la classe d’interface qui contient les annotations décrivant le service web. Il permet également de définir le nom du service web tel qu’il apparait dans le WSDL. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On obtient le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;package fr.j2ltho.calculette.ejb;&lt;/p&gt;    &lt;p&gt;import javax.ejb.Stateless;&lt;/p&gt;    &lt;p&gt;import javax.jws.WebService;&lt;/p&gt;    &lt;p&gt;@Stateless&lt;/p&gt;    &lt;p&gt;&lt;b&gt;@WebService&lt;/b&gt;&lt;b&gt;(endpointInterface=&lt;/b&gt;&lt;b&gt;&amp;quot;fr.j2ltho.calculette.ejb.MaCalculette&amp;quot;&lt;/b&gt;&lt;b&gt;, serviceName=&lt;/b&gt;&lt;b&gt;&amp;quot;MaSwCalculette&amp;quot;&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;public class MaCalculetteBean implements MaCalculette {&lt;/p&gt;    &lt;p&gt;public int add(int x, int y) {&lt;/p&gt;    &lt;p&gt;return x + y ;&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;public int subtract(int x, int y) {&lt;/p&gt;    &lt;p&gt;return x - y;&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt; &lt;/div&gt;  &lt;h3&gt;Génération du jar&lt;/h3&gt;  &lt;p&gt;Assurez vous d’avoir bien sauvegarder la classe et son interface.&lt;/p&gt;  &lt;p&gt;Cliquez droit dans l’explorateur de ressource d’Eclipse sur votre projet MaCalculetteSW, sélectionnez Export…, dans la dialogue « Export » qui s’affiche choisissez, dans Java, JAR file. Puis Next. Sélectionner l’emplacement et le nom du JAR File. Pour ma part je l’ai créé directement dans le répertoire C:\jboss-5.1.0.GA\server\default\deploy qui est le répertoire de déploiement pour la configuration par default. Le nom du fichier est MaCalculette.jar.&lt;/p&gt;  &lt;p&gt;Le nom du jar n’a aucune importance, il n’est pas utilisé pour obtenir le WSDL et n’a aucun d’impact sur le contenu du WSDL.&lt;/p&gt;  &lt;p&gt;Appuyez, ensuite sur Finish. Vous devriez trouver un fichier MaCalculette.jar dans le répertoire C:\jboss-5.1.0.GA\server\default\deploy.&lt;/p&gt;  &lt;p&gt;On lance JBoss, si on tape l’url suivante dans un browser : &lt;a href="http://localhost:8080/jbossws/services"&gt;http://localhost:8080/jbossws/services&lt;/a&gt; une page JBossWS/Services s’affiche. Il doit y a avoir une page avec un ServiceEndID avec MaCalculetteBeanService, un WSDL est accessible sur la ligne suivante : &lt;a href="http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl" target="_blank"&gt;http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Analyse du WSDL&lt;/h3&gt;  &lt;p&gt;En cliquant sur le lien précédent : &lt;a href="http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl" target="_blank"&gt;http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl&lt;/a&gt; on affiche le WSDL du service.&lt;/p&gt;  &lt;p&gt;Nous allons analyser succinctement son contenu afin de mettre en évidence les correspondances entre les annotations et le contenu du WSDL.&lt;/p&gt;  &lt;h4&gt;ServiceName&lt;/h4&gt;  &lt;p&gt;Tout d’abord le premier tag, le tag definition :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;definitions &lt;strong&gt;name=&amp;quot;MaSwCalculette&amp;quot;&lt;/strong&gt; targetNamespace=&amp;quot;http://ejb.calculette.j2ltho.fr/&amp;quot;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il contient le nom du Service Web tel qu’il est définit par la propriété serviceName dans l’annotation @WebService du bean d’implémentation.&lt;/p&gt;  &lt;p&gt;On retrouve ce nom de service dans le tag service à la fin du WSDL :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;service name=&amp;quot;&lt;b&gt;MaSwCalculette&lt;/b&gt;&amp;quot;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le service web est la collection de protocoles qu’il est possible d’utiliser pour déclencher un traitement donné. Dans certains cas plusieurs protocoles peuvent être mis à disposition comme SOAP 1.1, SOAP 1.2 et http.&lt;/p&gt;  &lt;h4&gt;Choix du protocole et du format des messages&lt;/h4&gt;  &lt;p&gt;Le protocole est de type SOAP 1.1. Un seul mécanisme est retenu dans cette implémentation. Il n’y a qu’un seul tag port dans le tag service, de même il n’y a qu’un seul tag binding. C’est la présence de l’annotation @SOAPBinding qui est responsable du choix du protocole SOAP.&lt;/p&gt;  &lt;p&gt;Cette annotation permet également de définir le format du message :&lt;/p&gt;  &lt;p&gt;Le paramètre style permet de choisir entre DOCUMENT et RPC : cela est visible dans le tag soap:binding la propriété style indique le style.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;soap:binding style=&amp;quot;&lt;b&gt;document&lt;/b&gt;&amp;quot; transport=&amp;quot;http://schemas.xmlsoap.org/soap/http&amp;quot; /&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le paramètre use permet de choisir entre LITERAL et ENCODED : cela est visible dans les tags soap:body avec la propriété use qui indique le mécanisme d’encodage :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;soap:body use=&amp;quot;&lt;b&gt;literal&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Pour finir, le paramètre parameterStyle permettait de choisir entre WRAPPED ou BARE (unwrapped). Le mode WRAPPED implique que dans le message appelant, les paramètres sont encapsulés dans un type portant le nom de l’opération. On peut le vérifier dans la partie message ou operation du WSDL où l’on voit la définition de l’opération ajouter indiquer un input message :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;operation name=&amp;quot;&lt;strong&gt;ajouter&lt;/strong&gt;&amp;quot; parameterOrder=&amp;quot;ajouter&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;input message=&amp;quot;tns:&lt;strong&gt;MaCalculetteSw_ajouter&lt;/strong&gt;&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;output message=&amp;quot;tns:MaCalculetteSw_ajouterResponse&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/operation&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Cet input message fait référence à un message composé d’un unique élément qui porte comme nom ajouter (le nom de l’opération) :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;message name=&amp;quot;&lt;strong&gt;MaCalculetteSw_ajouter&lt;/strong&gt;&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;part element=&amp;quot;tns:ajouter&amp;quot; name=&amp;quot;&lt;strong&gt;ajouter&lt;/strong&gt;&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/message&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;h4&gt;Les annotations sur les méthodes&lt;/h4&gt;  &lt;p&gt;Les annotations @WebMethod, @WebResult et @WebParam utilisées dans l’interface modifie les noms par défaut des opérations dans le WSDL.&lt;/p&gt;  &lt;p&gt;On a pu constater que la propriété operationName de @WebMethod a permis pour la méthode add que celle-ci apparaisse sous le nom de ajouter dans le WSDL. Le nom par défaut aurez été add (on peut le vérifier avec la méthode substract).&lt;/p&gt;  &lt;p&gt;Avec l’opération ajouter, on constate que les noms des arguments de la méthode sont peu significatifs :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;ajouter&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;arg0&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;arg1&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le WSDL étant le contrat entre le client et le serveur, il est également la première source de documentation pour utiliser un service web, il est donc souhaitable que les noms d’éléments soient plus significatifs. On a utiliser pour cela l’annotation @WebParam pour la méthode substract afin d’imposer la valeur de la propriété name. Il faut également savoir que c’est cette valeur qui sera prise par l’outil wsconsume de JBoss afin de nommer les paramètres lors de la génération du stub client (comme on le verra plus loin). En conséquence des noms correctes et significatifs vont grandement simplifier l’utilisation du service.&lt;/p&gt;  &lt;p&gt;Pour finir, on constate que l’annotation @WebResult a permis de renommer le nom de l’élément de sortie (la valeur renvoyée par la méthode) :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:complexType name=&amp;quot;ajouterResponse&amp;quot;&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;strong&gt;resultat&lt;/strong&gt;&amp;quot; type=&amp;quot;xs:int&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:sequence&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On obtient une valeur resultat au lieu de return : cela n’a priori pas d’intérêt particulier dans notre cas.&lt;/p&gt;  &lt;h4&gt;PortType ou name de @WebService&lt;/h4&gt;  &lt;p&gt;On constate que la propriété name du tag portType du WSDL reprend la valeur de la propriété name de l’annotation @Webservice de l’interface.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;portType name=&amp;quot;&lt;b&gt;MaCalculetteSw&lt;/b&gt;&amp;quot;&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Ce nom est utilisé lors de la génération des classes Java cliente avec l’outil wsconsume comme nom pour la classe d’interface qui sera utilisée. Je vous conseille donc d’utiliser le même nom que celui de l’interface afin de simplifier votre développement.&lt;/p&gt;  &lt;h4&gt;Types des données&lt;/h4&gt;  &lt;p&gt;Les données pour les types simples qu’on a utilisés utilisent des types simples du XMLSchema :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;b&gt;arg0&lt;/b&gt;&amp;quot; type=&amp;quot;&lt;b&gt;xs:int&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt;    &lt;p&gt;&amp;lt;xs:element name=&amp;quot;&lt;b&gt;arg1&lt;/b&gt;&amp;quot; type=&amp;quot;&lt;b&gt;xs:int&lt;/b&gt;&amp;quot; /&amp;gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Ces types simples sont indépendants des langages de programmation. Cela est un point positif.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Création d’un projet Eclipse pour le client&lt;/h3&gt;  &lt;p&gt;Qu’on est récupéré le projet EJB ou créé un projet de rien, il faut dans tous les cas créé un nouveau client. Dans Eclipse, on crée un second projet Java simple que l’on nommera MonClientSW.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Project.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Project, choisir le dossier Java puis le nœud Java Project. Appuyez sur le bouton Next.&lt;/p&gt;  &lt;p&gt;Pour Project name, tapez : MonClientSW et laissez les autres options par défaut.&lt;/p&gt;  &lt;p&gt;Appuyez sur Finish. Acceptez le choix de la perspective Java si la dialogue « Open Associated Perspective » s’affiche.&lt;/p&gt;  &lt;p&gt;Il faut importer des jar JBoss nécessaire à l’appel d’un Service Web : cliquez droit sur le projet dans l’explorateur et choisissez Properties. Dans la dialogue qui s’ouvre choisir « Java Build Path ».&lt;/p&gt;  &lt;p&gt;Appuyer sur « Add External Jars.. », et utiliser l’explorateur pour aller dans le répertoire C:\jboss-5.1.0.GA\client et sélectionnez les jar :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;activation.jar &lt;/li&gt;    &lt;li&gt;javassist.jar &lt;/li&gt;    &lt;li&gt;jaxb-api.jar &lt;/li&gt;    &lt;li&gt;jaxb-impl.jar &lt;/li&gt;    &lt;li&gt;jaxb-xjc.jar &lt;/li&gt;    &lt;li&gt;jboss-serialization.jar &lt;/li&gt;    &lt;li&gt;jboss-system-client.jar &lt;/li&gt;    &lt;li&gt;mail.jar &lt;/li&gt;    &lt;li&gt;policy.jar &lt;/li&gt;    &lt;li&gt;stax-api.jar &lt;/li&gt;    &lt;li&gt;wsdl4j.jar &lt;/li&gt;    &lt;li&gt;wstx.jar &lt;/li&gt;    &lt;li&gt;jbossws-native-core.jar &lt;/li&gt;    &lt;li&gt;jbossws-native-jaxrpc.jar &lt;/li&gt;    &lt;li&gt;jbossws-native-jaxws.jar &lt;/li&gt;    &lt;li&gt;jbossws-native-jaxws-ext.jar &lt;/li&gt;    &lt;li&gt;jbossws-native-saaj.jar &lt;/li&gt;    &lt;li&gt;jboss-xml-binding.jar &lt;/li&gt;    &lt;li&gt;ejb3-persistence.jar &lt;/li&gt;    &lt;li&gt;jbossws-spi.jar &lt;/li&gt;    &lt;li&gt;jbossws-common.jar &lt;/li&gt;    &lt;li&gt;jboss-logging-spi.jar &lt;/li&gt;    &lt;li&gt;jboss-common-core.jar &lt;/li&gt;    &lt;li&gt;commons-logging.jar &lt;/li&gt;    &lt;li&gt;jboss-remoting.jar&lt;!--EndFragment--&gt;      &lt;ul&gt;&lt;!--EndFragment--&gt;&lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt; Puis ajouter depuis le répertoire C:\jboss-5.1.0.GA\lib\endorsed   &lt;ul&gt;   &lt;li&gt;serializer.jar &lt;/li&gt;    &lt;li&gt;xalan &lt;/li&gt;    &lt;li&gt;xercesImpl &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Validez en appuyant sur Ok.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Génération des stubs&lt;/h4&gt;  &lt;p&gt;Nous allons utiliser l’utilitaire wsconsume.bat qui est livré avec JBoss. Il se trouve dans le répertoire C:\jboss-5.1.0.GA\bin. Cet utilitaire permet à partir d’un WSDL de générer un ensemble de classes qui facilitent l’appel du Service Web.&lt;/p&gt;  &lt;p&gt;On ouvre une fenêtre invite de commandes DOS. On se positionne sur le répertoire, il faut positionner la variable JAVA_HOME vers l’installation Java de votre poste.&lt;/p&gt;  &lt;p&gt;On lance la commande en indiquant à la fois le WSDL et le répertoire du projet Eclipse :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Cd C:\jboss-5.1.0.GA\bin&lt;/p&gt;    &lt;p&gt;SET JAVA_HOME=C:\Program Files\Java\jdk1.6.0_18&lt;/p&gt;    &lt;p&gt;wsconsume.bat -k -p fr.j2ltho.client.jboss.ejb &lt;a href="http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl"&gt;http://127.0.0.1:8080/MaCalculette/MaCalculetteBean?wsdl&lt;/a&gt; -o &amp;quot;C:\Documents and Settings\jltho\Mes documents\PrjJava\MonClientSW\src&amp;quot;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où C:\Documents and Settings\j2ltho\Mes documents\PrjJava est le nom de mon répertoire contenant mes projets Java.&lt;/p&gt;  &lt;p&gt;Si vous avez l’erreur “Le chemin d'accès spécifié est introuvable.”, c’est que probablement la variable JAVA_HOME a été incorrectement spécifiée.&lt;/p&gt;  &lt;p&gt;Les lignes suivantes s’affichent :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;fr\j2ltho\client\jboss\ejb\Ajouter.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\AjouterResponse.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\MaCalculetteSw.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\MaSwCalculette.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\ObjectFactory.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\Subtract.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\SubtractResponse.java&lt;/p&gt;    &lt;p&gt;fr\j2ltho\client\jboss\ejb\package-info.java&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Dans Eclipse si on fait F5 sur le projet, un nouveau package fr.j2ltho.client.jboss.ejb apparait.&lt;/p&gt;  &lt;h4&gt;Création de la classe cliente&lt;/h4&gt;  &lt;p&gt;Dans Eclipse. Nous allons créer une classe de type Main afin d’appeler ce service web.&lt;/p&gt;  &lt;p&gt;Dans Eclipse, à partir de la barre de menu : File -&amp;gt; New -&amp;gt; Class.&lt;/p&gt;  &lt;p&gt;Dans la dialogue New Java Class :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pour Package, tapez : fr.j2ltho.client.test.sw &lt;/li&gt;    &lt;li&gt;Pour Name tapez : TestMaCalculetteMain &lt;/li&gt;    &lt;li&gt;Cochez la checkbox public static void main(String[] args) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;et laissez les autres options par défaut.&lt;/p&gt;  &lt;p&gt;Appuyez sur Finish.&lt;/p&gt;  &lt;p&gt;Le code à ajouter est très simple :&lt;/p&gt;  &lt;p&gt;On récupère d’abord un objet sur le service web que l’on souhaite appeler. Le nom de la classe correspond au nom du service. Il s’agit à ce niveau d’une collection de protocole de communication qu’il est possible d’appeler.&lt;/p&gt;  &lt;p&gt;Ensuite on récupère une interface sur ce service : c’est cette interface que l’on va pouvoir utiliser comme une simple classe. Vous pouvez constater que sa définition ressemble à celle de l’interface client. Le nom de la classe est celui du tag portType du WSDL. Comme on a forcé son nom à MaCalculetteSw, c’est ce nom qu’il prend. Dans la pratique, il est probablement plus intéressant de conserver le même nom que l’interface.&lt;/p&gt;  &lt;p&gt;Pour finir, on appelle les deux services.&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&lt;b&gt;package&lt;/b&gt; fr.j2ltho.client.test.sw;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;import&lt;/b&gt; java.util.Date;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;import&lt;/b&gt; fr.j2ltho.client.jboss.ejb.MaCalculetteSw;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;import&lt;/b&gt; fr.j2ltho.client.jboss.ejb.MaSwCalculette;&lt;/p&gt;    &lt;p&gt;&lt;b&gt;public&lt;/b&gt; &lt;b&gt;class&lt;/b&gt; TestMaCalculetteMain {&lt;/p&gt;    &lt;p&gt;/**&lt;/p&gt;    &lt;p&gt;* &lt;b&gt;@param&lt;/b&gt; args&lt;/p&gt;    &lt;p&gt;*/&lt;/p&gt;    &lt;p&gt;&lt;b&gt;public&lt;/b&gt; &lt;b&gt;static&lt;/b&gt; &lt;b&gt;void&lt;/b&gt; main(String[] args) {&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(&amp;quot;debut:&amp;quot;+&lt;b&gt;new&lt;/b&gt; Date());&lt;/p&gt;    &lt;p&gt;MaSwCalculette service = &lt;b&gt;new&lt;/b&gt; MaSwCalculette();&lt;/p&gt;    &lt;p&gt;MaCalculetteSw calculator =service.getMaCalculetteBeanPort();&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(&amp;quot;apres initialisation:&amp;quot;+&lt;b&gt;new&lt;/b&gt; Date());&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(calculator.ajouter(2, 4));&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(&amp;quot;fin du add:&amp;quot;+&lt;b&gt;new&lt;/b&gt; Date());&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(calculator.subtract(8, 3));&lt;/p&gt;    &lt;p&gt;System.&lt;i&gt;out&lt;/i&gt;.println(&amp;quot;fin du substract:&amp;quot;+&lt;b&gt;new&lt;/b&gt; Date());&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Création du fichier META-INF/standard-jaxws-client-config.xml&lt;/h4&gt;  &lt;p&gt;Dans le répertoire src, on créé un nouveau Folder META-INF : Cliquez droit sur le répertoire src et sélectionnez New –&amp;gt; Other. La dialogue “New – Select a wizard” apparait. Choisir dans le noeud General, l’élément Folder et appuyez sur Next. Saisir le nom du folder qui doit impérativement être META-INF et validez.&lt;/p&gt;  &lt;p&gt;Le répertoire META-INF a été créé dans le répertoire src de votre projet.&lt;/p&gt;  &lt;p&gt;Ensuite, on copie depuis C:\jboss-5.1.0.GA\server\default\deployers\jbossws.deployer\META-INF, le fichier satandard-jaxws-client-config.xml dans le nouveau répertoire META-INF : il suffit de faire un glisser/déposer de l’explorateur Windows vers le répertoire META-INF dans le Project explorer d’Eclipse.&lt;/p&gt;  &lt;p&gt;Aucune adaptation n’est nécessaire à ce fichier. Il s’agit d’une nouveauté nécessaire avec JBoss 5.1.&lt;/p&gt;  &lt;p&gt;Sans ce fichier vous auriez eu à l’exécution l’erreur suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;exception in thread &amp;quot;main&amp;quot; org.jboss.ws.WSException: Cannot find configFile: META-INF/standard-jaxws-client-config.xml     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.config.JBossWSConfigFactory.filenameToURL(JBossWSConfigFactory.java:196)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.config.JBossWSConfigFactory.getConfig(JBossWSConfigFactory.java:150)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.umdm.EndpointMetaData.initEndpointConfigMetaData(EndpointMetaData.java:874)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.umdm.EndpointMetaData.initEndpointConfig(EndpointMetaData.java:851)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.builder.jaxws.JAXWSClientMetaDataBuilder.rebuildEndpointMetaData(JAXWSClientMetaDataBuilder.java:292)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.getPortInternal(ServiceDelegateImpl.java:269)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.getPort(ServiceDelegateImpl.java:200)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at javax.xml.ws.Service.getPort(Service.java:141)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at fr.j2ltho.client.jboss.ejb.MaSwCalculette.getMaCalculetteBeanPort(MaSwCalculette.java:55)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at fr.j2ltho.client.test.sw.TestMaCalculetteMain.main(TestMaCalculetteMain.java:18)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Tester l’application&lt;/h4&gt;  &lt;p&gt;Pour tester, on sauve, puis on clique droit sur la classe TestMaCalculetteMain dans le Package Explorer d’Eclipse. Choisissez le menu Run As, puis le sous menu Java Application.&lt;/p&gt;  &lt;p&gt;La console affichée en bas est rafraichie et affiche deux lignes :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;debut:Tue May 22 10:59:32 CEST 2007&lt;/p&gt;    &lt;p&gt;apres initialisation:Tue May 22 10:59:33 CEST 2007&lt;/p&gt;    &lt;p&gt;6&lt;/p&gt;    &lt;p&gt;fin du add:Tue May 22 10:59:33 CEST 2007&lt;/p&gt;    &lt;p&gt;5&lt;/p&gt;    &lt;p&gt;fin du substract:Tue May 22 10:59:33 CEST 2007&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On constate que le temps d’initialisation de l’appel est long (de l’ordre de 2s sur mon poste, un core duo 2 avec 2 Go). La documentation de JBoss indique que cette opération est longue et ne doit être faite qu’une seule fois et recommande de conserver cette classe en mémoire. Le test met l’accent sur l’importance de suivre cette recommandation.&lt;/p&gt;  &lt;h4&gt;Quelques exceptions et leur solution&lt;/h4&gt;  &lt;p&gt;Lorsqu’on lance l’exécution de l’application de test, on est susceptible d’obtenir des exceptions s’il manque un ou plusieurs jar. J’indique ci dessous certaines des erreurs que j’ai rencontré et le jar que j’ai du ajouté pour résoudre le problème :&lt;/p&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : jbossws-spi.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.NoClassDefFoundError: org/jboss/wsf/spi/deployment/UnifiedVirtualFile     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:63)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : jbossws-common.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.NoClassDefFoundError: org/jboss/wsf/common/ResourceLoaderAdapter     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.&amp;lt;init&amp;gt;(ServiceDelegateImpl.java:118)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : policy.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.NoClassDefFoundError: org/apache/ws/policy/Policy     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.builder.jaxws.JAXWSClientMetaDataBuilder.buildMetaData(JAXWSClientMetaDataBuilder.java:91)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.&amp;lt;init&amp;gt;(ServiceDelegateImpl.java:138)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : jboss-remoting.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; javax.xml.ws.WebServiceException: java.lang.IllegalStateException: Failed to load org.jboss.ws.core.client.RemoteConnection.http: org.jboss.ws.core.client.SOAPProtocolConnectionHTTP     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.client.ClientImpl.handleRemoteException(ClientImpl.java:396)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.client.ClientImpl.invoke(ClientImpl.java:302)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.client.ClientProxy.invoke(ClientProxy.java:170)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.client.ClientProxy.invoke(ClientProxy.java:150)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at $Proxy15.ajouter(Unknown Source)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at fr.j2ltho.client.test.sw.TestMaCalculette3Main.main(TestMaCalculette3Main.java:22)      &lt;br /&gt;Caused by: java.lang.IllegalStateException: Failed to load org.jboss.ws.core.client.RemoteConnection.http: org.jboss.ws.core.client.SOAPProtocolConnectionHTTP      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.wsf.spi.util.ServiceLoader.loadFromServices(ServiceLoader.java:97)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.wsf.spi.util.ServiceLoader.loadService(ServiceLoader.java:59)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.client.RemoteConnectionFactory.getRemoteConnection(RemoteConnectionFactory.java:61)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.CommonClient.invoke(CommonClient.java:339)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.client.ClientImpl.invoke(ClientImpl.java:290)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ... 4 more      &lt;br /&gt;Caused by: java.lang.NoClassDefFoundError: org/jboss/remoting/marshal/Marshaller      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.getDeclaredConstructors0(Native Method)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.privateGetDeclaredConstructors(Class.java:2357)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.getConstructor0(Class.java:2671)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.newInstance0(Class.java:321)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.newInstance(Class.java:303)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.wsf.spi.util.ServiceLoader.loadFromServices(ServiceLoader.java:92)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ... 8 more&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : commons-logging.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.ws.policy.util.Loader.&amp;lt;clinit&amp;gt;(Loader.java:32)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.ws.policy.util.PolicyFactory.getPolicyReader(PolicyFactory.java:56)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.extensions.policy.metadata.PolicyMetaDataBuilder.processPolicyExtensions(PolicyMetaDataBuilder.java:155)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.builder.jaxws.JAXWSClientMetaDataBuilder.buildMetaData(JAXWSClientMetaDataBuilder.java:92)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.&amp;lt;init&amp;gt;(ServiceDelegateImpl.java:138)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:63)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at javax.xml.ws.Service.&amp;lt;init&amp;gt;(Service.java:79)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;L’exception suivante est résolue par l’ajout du jar : jboss-common-core.jar&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.NoClassDefFoundError: org/jboss/util/NotImplementedException     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.umdm.ServiceMetaData.&amp;lt;init&amp;gt;(ServiceMetaData.java:85)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.metadata.builder.jaxws.JAXWSClientMetaDataBuilder.buildMetaData(JAXWSClientMetaDataBuilder.java:80)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.&amp;lt;init&amp;gt;(ServiceDelegateImpl.java:138)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.jboss.ws.core.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:63)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at javax.xml.ws.Service.&amp;lt;init&amp;gt;(Service.java:79)&lt;/p&gt;     &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Conclusion &lt;/h3&gt;  &lt;p&gt;L’exemple est volontairement simple et certainement pas très significatif vis-à-vis de la problématique d’un véritable projet. Néanmoins, il me parait intéressant de mettre l’accent sur quelques points qui devront être confirmé avant de s’enthousiasmer plus :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le WSDL généré est standard. Pour cet exemple simple il ne contient aucune référence au langage Java. Sur un exemple un peu plus compliqué en utilisant l’approche POJO de Axis2 cela n’avait pas été du tout le cas. &lt;/li&gt;    &lt;li&gt;Les diverses annotations ont permis de générer un WSDL qui peut être extrêmement précis et indépendant de l’implémentation Java. On obtient ainsi à la fois des classes Java proche du métier mais également le WSDL que l’on souhaite. Toujours sur un exemple plus compliqué, j’ai eu beaucoup plus de mal avec Axis2 (voir le tutorial &lt;a href="http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html"&gt;http://jl2tho.blogspot.com/2007/04/tutorial-services-web-avec-axis2.html&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;A priori, le code est indépendant de la solution retenu : tout serveur d’application respectant JAX-WS doit être capable d’héberger le service web. Le Jar ServiceWeb généré avec un runtime JBoss 4.2 fonctionne sur JBoss 5.1. Seule l’URL du WSDL a changé. Le code du service et sa définition (annotation) ne change pas. &lt;/li&gt;    &lt;li&gt;Le code client généré par l’utilitaire wsconsume.bat de JBoss est plus simple et plus portable que celui généré par wsdl2java d’Axis2 en utilisant le binding ADB. &lt;/li&gt;    &lt;li&gt;L’EJB est accessible : pour ceux qui ont réalisé le tutorial sur les EJB, ils peuvent relancer l’application cliente et constater qu’elle continue de s’exécuter correctement. &lt;/li&gt;    &lt;li&gt;Les modèles de programmations pour le client que l’on utilise un EJB, un service web ou bien que l’on appelle directement la classe d’implémentation restent très proches. La seule différence réside dans l’obtention de la classe d’interface, le reste du code peut être identique. Cela peut être un gros avantage pour la mise en œuvre de la solution lors du développement, en supprimant les étages. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Comme on le voit tout cela semble très positif. Le seul point qui parait négatif mais pour lequel je n’ai pas de comparaison c’est l’aspect performance : la création d’un bean permettant l’appel d’un service web est long.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-7184755040757478778?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/7184755040757478778/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=7184755040757478778&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7184755040757478778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7184755040757478778'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/tutorial-service-web-avec-jbosss-51.html' title='Tutorial Service Web avec JBosss 5.1'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-5717374051792052401</id><published>2011-11-01T10:46:00.001+02:00</published><updated>2011-11-01T10:46:22.111+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>Passer son iPhone sous iOS 5</title><content type='html'>&lt;p&gt;Depuis le 12/10/2011, la nouvelle version de iOS est disponible en téléchargement depuis iTunes.&lt;/p&gt;  &lt;p&gt;Ce billet décrit la mise à jour d’un iPhone (en l’occurrence un iPhone 4) avec cette version. Il est fort probable qu’il faudra prendre les mêmes précautions (tout comme il fallait déjà prendre les mêmes précautions) pour les versions suivantes.&lt;/p&gt;  &lt;p&gt;Attention ! un iPhone 3G ainsi que les version précédentes ne peuvent pas installer iOS 5.0. Cette opération est réservée aux possesseurs d’iPhone 3GS et 4 ainsi qu’aux possesseurs d’iPad et iPad2.&lt;/p&gt;  &lt;h3&gt;Retrouver le PC avec lequel l’iPhone est synchronisé&lt;/h3&gt;  &lt;p&gt;La mise à jour de iOS 5 nécessite le PC de référence avec lequel vous synchronisez votre iPhone. Apple considère qu’un iPhone se synchronise avec un ordinateur principal unique : c’est avec ce PC que votre iPhone synchronise sa musique, ses contacts son calendrier, ses Apps…&lt;/p&gt;  &lt;p&gt;Pour beaucoup de personnes, la première étape sera de se souvenir du PC et du compte Windows avec lequel l’iPhone est synchronisé. Une piste pour reconnaitre le bon PC : lors de la synchronisation de l’iPhone avec iTunes ce dernier reconnait votre iPhone et ne demande pas si vous souhaitez écraser votre iPhone ou s’il s’agit d’un nouvel iPhone ou tout autre question indiquant que iTunes ne connait pas cet iPhone.&lt;/p&gt;  &lt;p&gt;Une autre piste, est le fait que toutes les options de synchronisations pour les Contacts, le Calendrier, la Musique et les Apps soient actives.&lt;/p&gt;  &lt;p&gt;Si ce n’est pas le cas et que vous ne retrouvez pas le bon PC, je vous encourage en premier lieu de resynchroniser complètement votre iPhone avec ce PC et cet iTunes. Attention aux pertes de données, tout particulièrement la musique qui ne peut pas redescendre d’un iPhone. Il vous faudra récupérer la bibliothèque avec laquelle vous vous synchronisiez.&lt;/p&gt;  &lt;h3&gt;Mettre à jour iTunes&lt;/h3&gt;  &lt;p&gt;Une fois retrouvé le bon ordinateur et le bon compte Windows, la première étape consiste à mettre à jour iTunes. &lt;/p&gt;  &lt;p&gt;Lors de son lancement, il vous avertira probablement qu’il existe une nouvelle mise à jour. Je vous recommande d’accepter systématiquement la mise à jour iTunes avant une mise à jour iPhone. Bien souvent, ces mises à jours iTunes embarquent des fonctionnalités nécessaires à l’exploitation des nouvelles fonctionnalités de l’iPhone. Vouloir sauter cette étape ne me parait pas être un bon calcul : vous vous exposez à vous retrouver bloqué au milieu du gué.&lt;/p&gt;  &lt;h3&gt;Télécharger la mise à jour&lt;/h3&gt;  &lt;p&gt;Lorsque que vous connectez votre iPhone à l’ordinateur, il vous avertit qu’une nouvelle version de iOS est disponible. Vous avez la possibilité soit de la télécharger soit de la télécharger et de l’installer.&lt;/p&gt;  &lt;p&gt;Personnellement, je choisis systématiquement le téléchargement seul. Cela permet de découper la mise à jour en tâches interruptibles simplement et de dissocier les problèmes.&lt;/p&gt;  &lt;p&gt;Les nouvelles versions sont volumineuses généralement entre 700 et 900 Mo et cela peut prendre un certain temps sur une connexion bas débit. Un téléchargement s’interrompt facilement s’il prend trop de temps. Si vous faites les deux en même temps, il sera plus difficile de savoir à quelle étape vous en êtes.&lt;/p&gt;  &lt;h3&gt;Synchroniser votre iPhone avant la mise à jour&lt;/h3&gt;  &lt;p&gt;L’avantage de ne faire que le téléchargement et de permettre une synchronisation de l’iPhone avec votre PC.&lt;/p&gt;  &lt;p&gt;Vous avez également tout le loisir de régler d’éventuels problèmes de synchronisation dans le cas où vous ne synchronisez que très rarement votre iPhone.&lt;/p&gt;  &lt;p&gt;N’hésitez pas à relancer plusieurs synchronisations. Cela va vous permettre de disposer d’une copie de sauvegarde de votre iPhone.&lt;/p&gt;  &lt;h3&gt;Mettre à jour iOS&lt;/h3&gt;  &lt;p&gt;Une fois téléchargée la mise à jour et synchronisé votre iPhone, vous pouvez commencer la mise à jour. Cette opération prend plus ou moins de temps en fonction de l'âge de votre PC : il est néanmoins recommandé de prévoir d’une à deux heures pour cette opération qui ne pourra pas être interrompue.&lt;/p&gt;  &lt;p&gt;Avant de commencer cette opération, il vous faut vous souvenir de votre Code SIM : celui-ci est indispensable pour ré-activer votre iPhone à la fin de l’installation.&lt;/p&gt;  &lt;p&gt;Quand votre iPhone est branché, si vous le sélectionnez dans la barre latérale gauche, vous pouvez choisir l’onglet Info. Vous devez avoir un bouton “Mettre à jour l’iPhone” qui s’affiche. Cliquez dessus pour démarrer la mise à jour.&lt;/p&gt;  &lt;p&gt;Lisez avec attention les messages d’avertissement afin de vérifier qu’ils ne vous concernent pas.&lt;/p&gt;  &lt;p&gt;La mise à jour démarre. Cela commence par une sauvegarde de votre iPhone, cela enchaine avec l’installation de iOS.&lt;/p&gt;  &lt;p&gt;Au bout d’un certain temps, votre iPhone affiche le message : “Veuillez saisir votre code SIM pour déverrouiller votre iPhone”.&lt;/p&gt;  &lt;p&gt;Attention ! la Slider en bas affiche un message Configurer en diverses langues. Il ne faut surtout pas l’utiliser ! Il lance une configuration Standalone de votre iPhone : si vous suivez cette démarche, il configure un iPhone vierge et vous fait perdre toutes vos données..&lt;/p&gt;  &lt;p&gt;Il faut cliquer sur le message demandant le déverrouillage de votre iPhone et saisir votre code SIM.&lt;/p&gt;  &lt;h3&gt;Récupérer vos informations&lt;/h3&gt;  &lt;p&gt;Une fois cette opération faite, il faut débrancher et rebrancher l’iPhone à votre ordinateur. Lors du rebranchement, il finit la mise à jour en recopiant toutes les informations sauvegardées en début de synchronisation. Cette opération peut durer une bonne heure en fonction de votre PC et de la quantité d’informations stockées sur l’iPhone : Musique et Apps principalement.&lt;/p&gt;  &lt;p&gt;Lorsque l’opération est terminée : vous devriez avoir la totalité de vos données Musiques, Apps, Contacts et Calendrier qui se retrouve sur votre iPhone.&lt;/p&gt;  &lt;h3&gt;Configuration iCloud&lt;/h3&gt;  &lt;p&gt;Cette étape est nouvelle avec iOS 5. Pour terminer la mise à jour, il faut configurer iCloud. Le premier message vous demande si vous souhaitez activer la localisation (personnellement je coche Activer). L’écran suivant vous propose d’activer iCloud : il existe un petit lien en bas de l’écran “Ignorer cette étape”. N’étant pas intéressé par iCloud j’ai cliqué dessus afin d’éviter son activation.&lt;/p&gt;  &lt;p&gt;Si vous souhaitez l’activer, l’identifiant Apple qui vous est demandé, est celui de votre compte iTunes que vous avez du créer auparavant pour activer votre iPhone et qu’il vous réclame à chaque chargement d’une nouvelle application depuis l’AppStore.&lt;/p&gt;  &lt;p&gt;Il vous demandera ensuite les services que vous souhaitez utiliser : mais pour cette étape, vous comprendrez que je ne suis pas d’une grande aide.&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Normalement, votre iPhone est maintenant en iOS 5 et vous avez retrouvé la totalité des données. Si vous faites bien attention d’utiliser pour la mise à jour le PC de synchronisation de votre iPhone vous ne devriez rien perdre.&lt;/p&gt;  &lt;p&gt;Les personnes que j’ai rencontré qui avez perdu des données lors de la mise à jour avaient toutes comme point commun de synchroniser rarement leur iPhone et pas toujours avec le même PC. Si vous êtes dans ce cas, je ne peux que vous encourager à rétablir un PC de référence pour la synchronisation de votre iPhone avant de tenter la mise à jour.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-5717374051792052401?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/5717374051792052401/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=5717374051792052401&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/5717374051792052401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/5717374051792052401'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2011/11/passer-son-iphone-sous-ios-5.html' title='Passer son iPhone sous iOS 5'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-694940923713116632</id><published>2010-12-16T19:52:00.001+02:00</published><updated>2010-12-16T19:52:28.484+02:00</updated><title type='text'>Effacer son mot de passe ou son login de la liste de suggestion d'un navigateur</title><content type='html'>&lt;p&gt;Il arrive que lorsqu’on saisisse son nom utilisateur ou son login pour se connecter (par exemple à Gmail, Yahoo, Facebook, Hotmail ou tout autre service), on se trompe et on saisisse son mot de passe. Si par malheur on a appuyé sur la touche Entrée, cette information réapparaitra à chaque fois que l'on commence à taper la première lettre dans la liste de suggestion : dévoilant ainsi le mot de passe.&lt;/p&gt;  &lt;p&gt;Il faut noter que cette liste de suggestion dépend du site : si vous utilisez myyahoo sur &lt;a href="http://www.yahoo.fr/"&gt;www.yahoo.fr&lt;/a&gt;, il n’apparaitra pas dans la liste de suggestion sur le site &lt;a href="http://www.gmail.com/"&gt;www.gmail.com&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Néanmoins cette information reste &amp;quot;éternellement&amp;quot; présente pour un site donné : effacer les cookies du site n'y fait rien (ce n'est pas le site qui conserve l’information mais votre navigateur).&lt;/p&gt;  &lt;p&gt;Ce problème existe pour Chrome et Firefox (je n'ai pas testé sous IE). Pour faire disparaitre une suggestion de la liste des comptes ou utilisateurs fournie par Firefox ou Chrome, le processus est simple et identique :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Ouvrir la page de connexion du site concerné&lt;/li&gt;    &lt;li&gt;Se positionner sur le champ Utilisateur, Compte ou login&lt;/li&gt;    &lt;li&gt;Taper la première lettre du mot&lt;/li&gt;    &lt;li&gt;Lorsque la liste s'affiche, utiliser les flèches de son clavier pour sélectionner la ligne que vous voulez supprimer. &lt;/li&gt;    &lt;li&gt;Une fois la sélection faite, appuyer sur la touche Suppr. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;La ligne est supprimée de la liste et n’apparaitra plus jusqu'à la prochaine erreur de saisie.&lt;/p&gt;  &lt;p&gt;J'espère que cela vous aura rendu service car il est toujours délicat de laisser son mot de passe apparaitre en clair dans la liste de suggestion des utilisateurs d'un site. &lt;/p&gt;  &lt;p&gt;Comme la majorité des personnes utilise le même mot de passe sur différents sites, la faille de sécurité est d'autant plus importante.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-694940923713116632?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/694940923713116632/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=694940923713116632&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/694940923713116632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/694940923713116632'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/12/effacer-son-mot-de-passe-ou-son-login.html' title='Effacer son mot de passe ou son login de la liste de suggestion d&amp;#39;un navigateur'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-2220999411794476690</id><published>2010-11-05T16:14:00.001+02:00</published><updated>2010-11-05T16:14:46.804+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><title type='text'>Couverture de code : Mise en œuvre de Cobertura pour une application Web</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Ce billet présente la mise en œuvre de Cobertura pour une application Web. Vous y trouverez une rapide présentation de Cobertura, suivie d’un tutorial pour son utilisation dans le cadre des tests d’une application Web s’exécutant sur un serveur Tomcat.&lt;/p&gt;  &lt;h2&gt;Présentation de Cobertura&lt;/h2&gt;  &lt;p&gt;Cobertura est un outil qui permet de mesurer la couverture de code d’un jeu de tests. Il ne permet pas de réaliser les tests, ni de les automatiser : Cobertura mesure juste la pertinence et la complétude de ces tests.&lt;/p&gt;  &lt;p&gt;Les outils qui mesurent la couverture de votre code Java fonctionnent tous de la même manière :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;il n’est pas nécessaire de modifier le code Java : les solutions ne sont pas intrusives. &lt;/li&gt;    &lt;li&gt;il y a tout d’abord une phase d’instrumentalisation des fichiers compilés (class, jar ou war) : cette phase qui a lieu après la compilation semble construire une couche de proxies sur les binaires existant afin d’intercepter tous les appels. &lt;/li&gt;    &lt;li&gt;on exécute les tests avec les binaires instrumentalisés en ajoutant un jar nécessaire au bon fonctionnement de la couche de proxy. &lt;/li&gt;    &lt;li&gt;on termine le test par une sortie violente (Ctrl C souvent) afin que la couche de proxy reprenne la main est crée le fichier de compte rendu &lt;/li&gt;    &lt;li&gt;hors exécution, on transforme le fichier de compte rendu en pages HTML : on obtient un site qui montre pour chaque classe java : le pourcentage de code exécuté, le nombre de branches conditionnelles exécutées et le détail du code exécuté ou non. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Le résultat du processus est donc un rapport qui indique si la totalité du code a été testé et qui permet la détection du code non exécuté.&lt;/p&gt;  &lt;p&gt;Ci dessous, un exemple de la page index.html qui est la synthèse du rapport est le point de départ des différentes pages d’analyse.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/TNQRRyhUQZI/AAAAAAAADeA/oBmoUoS7KU8/s1600-h/CoberturaRapportIndex%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CoberturaRapportIndex" border="0" alt="CoberturaRapportIndex" src="http://lh6.ggpht.com/_Y8Z3ymNuOiE/TNQRTnfLeWI/AAAAAAAADeI/T5xRZbJi6l0/CoberturaRapportIndex_thumb%5B1%5D.png?imgmax=800" width="916" height="772" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;On constate que pour chaque package, on a une synthèse du code couvert : &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;on a le nombre de classes composant le package &lt;/li&gt;    &lt;li&gt;on a le pourcentage de lignes de code exécutées (les lignes de commentaire ne sont pas comptabilisées) &lt;/li&gt;    &lt;li&gt;on a le nombre de lignes exécutées et le nombre total de lignes de code de ce package (toutes classes confondues) &lt;/li&gt;    &lt;li&gt;ce que Cobertura appelle branch est tout branchement conditionnel (if ,else…) : il mesure si pour chaque test, on a eu à le cas du true et du false. Si vous n’avez eu que le cas du true, vous ne serez qu’à 50% du test de couverture des branchs. &lt;/li&gt;    &lt;li&gt;la dernière colonne est la complexité “cyclotimique” du code (j’avoue ne pas avoir utilisé cette information) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pour une classe, il est possible d’avoir le détail. Ce point peut être très utile quand on essaie d’améliorer ses tests : il faut comprendre quelle partie du code n’a pas été testé afin de construire le test qui la couvrira.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/TNQRUdJnJ9I/AAAAAAAADeQ/Hz3DbOOQFzU/s1600-h/CoberturaDetail%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CoberturaDetail" border="0" alt="CoberturaDetail" src="http://lh6.ggpht.com/_Y8Z3ymNuOiE/TNQRVMZVEXI/AAAAAAAADeY/GKX323jlEEs/CoberturaDetail_thumb%5B1%5D.png?imgmax=800" width="744" height="772" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;On constate que l’on a en haut, une synthèse de la couverture de la classe avec son pourcentage et le nombre de lignes testées sur le nombre de lignes totales de la classe.&lt;/p&gt;  &lt;p&gt;On a ensuite le code, en vert les lignes exécutées avec le nombre de fois, en rouge les lignes qui ne l’ont pas été : dans l’exemple ci-dessus seuls le constructeur et la méthode getSolde ont été exécuté.&lt;/p&gt;  &lt;h2&gt;Mise en œuvre de Cobertura pour une application Web&lt;/h2&gt;  &lt;p&gt;La majorité des documentations présente l’utilisation de Cobertura dans les phases de tests unitaires jUnit. La mise en œuvre avec une application Web déployée sur un serveur d’application JEE comme Tomcat est plus délicate : le bon fonctionnement de Cobertura repose sur la bonne gestion du fichier de données (appelé datafile et dont le nom par défaut est cobertura.ser). Or cette gestion repose sur ce que le serveur d’application considère comme le point de départ de son système de fichiers et ce paramètre change énormément d’une configuration à l’autre et d’un serveur à l’autre.&lt;/p&gt;  &lt;h3&gt;Configuration du serveur Tomcat 6.0&lt;/h3&gt;  &lt;p&gt;Le test a été fait sur un serveur Tomcat 6.0. Le serveur est lancé avec le startup.bat et non pas comme service Windows : cela a un impact important sur l’endroit ou doit se trouver le fichier cobertura.ser.&lt;/p&gt;  &lt;p&gt;Pour ma part, j’ai téléchargé depuis le site &lt;a href="http://tomcat.apache.org/download-60.cgi"&gt;http://tomcat.apache.org/download-60.cgi&lt;/a&gt; la version core pour Windows 32 bits : 32-bits Windows.zip.&lt;/p&gt;  &lt;p&gt;Le répertoire obtenu lors du unzip : apache-tomcat-6.0.29 a été copié dans un nouveau dossier placé sur mon bureau TestCouverture créé pour l’occasion. J’ai donc un environnement dédié pour mes tests.&lt;/p&gt;  &lt;p&gt;J’ouvre le Catalina.bat qui se trouve dans Bin et j’ajoute en tout début de fichier la ligne suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_18&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;L’avantage de cette solution est de m’affranchir d’éventuelles restrictions de droits sur les répertoires : par défaut, Tomcat est souvent installé dans Program Files qui est soumis pour les versions récentes de Windows (Vista et Seven) a une politique de droits restrictive qui peut empêcher la mise à jour par Cobertura du fichier de données cobertura.ser.&lt;/p&gt;  &lt;h3&gt;Installation de Cobertura&lt;/h3&gt;  &lt;p&gt;J’ai utilisé la dernière version disponible (au moment de mes tests), la version 1.9.4.1.&lt;/p&gt;  &lt;p&gt;Elle peut être téléchargée depuis le site suivant : &lt;a href="http://cobertura.sourceforge.net/download.html"&gt;http://cobertura.sourceforge.net/download.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Il suffit de la dézipper dans un répertoire, dans mon cas le même dossier TestCouverture&amp;#160; du bureau.&lt;/p&gt;  &lt;h3&gt;Instrumentalisation des classes avec Cobertura&lt;/h3&gt;  &lt;p&gt;Avant d’instrumentaliser mes classes de mon projet JEE Eclipse TestCobertura, je génère depuis Eclipse le war.&lt;/p&gt;  &lt;p&gt;Je le déploie dans mon serveur Tomcat configuré pour le test : Bureau\apache-tomcat-6.0.29\webapps. Pensez aux éventuels jar qui doivent être installés dans Tomcat/lib comme ceux des drivers base de données.&lt;/p&gt;  &lt;p&gt;J’exécute l’application après lancement du serveur Tomcat avec le startup.bat. Cela explose le fichier war TestCobertura. On arrête le serveur.&lt;/p&gt;  &lt;p&gt;Pour instrumentaliser les classes java, on va partir du répertoire build du projet Eclipse qui contient les class et on va écraser ces mêmes class du répertoire explosé TestCobertura du serveur Tomcat (d’où l’importance de l’exécution de l’application) :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Le répertoire de mon projet Eclispe est dans Mes Documents\eclipsewsp, les fichiers class sont donc dans : C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Documents\eclipsewsp\TestCobertura\build\classes. &lt;/li&gt;    &lt;li&gt;Le répertoire du war explosé dans Tomcat est : C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\webapps\TestCobertura. &lt;/li&gt;    &lt;li&gt;Le fichier de données cobertura.ser devra être créé dans le répertoire bin de Tomcat : C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\bin &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pensez que :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt; doit être remplacé par la chaine de caractères correspondant à votre configuration. &lt;/li&gt;    &lt;li&gt;TestCobertura est le nom de mon projet Eclipse. &lt;/li&gt;    &lt;li&gt;eclipsewsp est le nom de mon répertoire workspace Eclipse. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On ouvre un fichier Commande DOS. on se positionne dans le répertoire Cobertura :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cd C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\cobertura-1.9.4.1&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;On tape la commande suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cobertura-instrument.bat --datafile &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\bin\cobertura.ser&amp;quot; --destination &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\webapps\TestCobertura\WEB-INF\classes&amp;quot; &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Documents\eclipsewsp\TestCobertura\build\classes&amp;quot;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Attention à bien utiliser les guillemets “ pour éviter les problèmes d’espaces dans d’éventuels noms longs. Le résultat devrait être :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Cobertura 1.9.4.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file&lt;/p&gt;    &lt;p&gt;Instrumenting 1 file to C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\webapps\TestCobertura\WEB-INF\classes&lt;/p&gt;    &lt;p&gt;Cobertura: Saved information on 131 classes.&lt;/p&gt;    &lt;p&gt;Instrument time: 4129ms&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Dans le répertoire bin de votre serveur Tomcat, vous devriez trouver un fichier cobertura.ser. Ce fichier est nécessaire au bon fonctionnement de Cobertura : il indique la liste des classes qu’il doit instrumentaliser ainsi que le résultat des tests. Ce fichier devra être accessible en lecture/écriture durant l’exécution du test.&lt;/p&gt;  &lt;p&gt;Si on souhaite pouvoir recommencer les tests à zéro, il est possible de sauvegarder cette version du fichier qui contient les classes instrumentalisées avec un compteur d’utilisation à zéro.&lt;/p&gt;  &lt;p&gt;Les fichiers .class du répertoire WEB-INF\classes ont été modifié (leur date a été modifié).&lt;/p&gt;  &lt;p&gt;Les classes sont instrumentalisées.&lt;/p&gt;  &lt;h3&gt;Test de l’application instrumentalisée&lt;/h3&gt;  &lt;p&gt;Si vous essayez de relancer l’application, vous allez avoir une erreur dans la log localhost :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Caused by: java.lang.NoClassDefFoundError: net/sourceforge/cobertura/coveragedata/HasBeenInstrumented     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.ClassLoader.defineClass1(Native Method)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.ClassLoader.defineClass(ClassLoader.java:616)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2733)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1124)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1612)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.forName0(Native Method)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at java.lang.Class.forName(Class.java:169)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.hibernate.util.ReflectHelper.classForName(ReflectHelper.java:192)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.hibernate.cfg.AnnotationConfiguration.parseMappingElement(AnnotationConfiguration.java:647)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ... 57 more      &lt;br /&gt;Caused by: java.lang.ClassNotFoundException: net.sourceforge.cobertura.coveragedata.HasBeenInstrumented      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ... 69 more&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Cette erreur signifie qu’il manque le jar cobertura qui est utilisé par les classes instrumentalisées. &lt;/p&gt;  &lt;p&gt;Dans la mesure, où l’on a construit un serveur Tomcat pour ses tests, il suffit d’ajouter cobertura.jar dans le répertoire bin de Tomcat.&lt;/p&gt;  &lt;p&gt;Le jar cobertura se trouve dans le répertoire TestCouverture\cobertura-1.9.4.1. Il suffit de le copier dans TestCouverture\apache-tomcat-6.0.29\lib.&lt;/p&gt;  &lt;p&gt;Vous pouvez redémarrer Tomcat avec Startup.bat et exécuté votre test.&lt;/p&gt;  &lt;p&gt;A la fin de votre test, vous arrêtez Tomcat en vous mettant dans la console qu’il aura ouverte et tapez Ctrl C. Tomcat s’arrête et met à jour le fichier cobertura.ser avec les logs de votre utilisation.&lt;/p&gt;  &lt;h3&gt;Génération du rapport HTML&lt;/h3&gt;  &lt;p&gt;La phase finale est la génération du rapport au format HTML.&lt;/p&gt;  &lt;p&gt;Le rapport utilise le fichier cobertura.ser mis à jour lors de votre utilisation. Pour que cela fonctionne, il faut que lors de l’exécution de votre application, Tomcat ait bien trouvé le fichier cobertura.ser créé lors de l’instrumentalisation. S’il ne le trouve pas, il créera un fichier cobertura.ser dans apache-tomcat-6.0.29\bin mais il ne contiendra aucune information.&lt;/p&gt;  &lt;p&gt;L’emplacement de ce fichier dépend du mécanisme de lancement de tomcat : avec startup.bat, il se trouve dans apache-tomcat-6.0.29\bin.&lt;/p&gt;  &lt;p&gt;Attention à ce que Tomcat puisse modifier ce fichier : cela sera probablement un problème si Tomcat s’exécute en service ou s’il se trouve dans un répertoire Program Files. C’est pour toutes ces raisons que je vous ai encouragé au début à installer votre propre version de test Tomcat.&lt;/p&gt;  &lt;p&gt;Pour que le rapport est le maximum de détail, il faut disposer des sources.&lt;/p&gt;  &lt;p&gt;Dans mon exemple, elles se trouvent dans le projet Eclipse sous : C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Documents\eclipsewsp\TestCobertura\src.&lt;/p&gt;  &lt;p&gt;On va générer le rapport dans le sous répertoire rapportCobertura du répertoire TestCouverture. Pour cela on crée le sous répertoire rapportCobertura &lt;/p&gt;  &lt;p&gt;On se replace dans le répertoire TestCouverture\cobertura-1.9.4.1 et on tape la commande suivante :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cobertura-report.bat –source &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Documents\eclipsewsp\TestCobertura\src&amp;quot; --datafile &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\apache-tomcat-6.0.29\bin\cobertura.ser&amp;quot; --destination &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Desktop\TestCouverture\rapportCobertura&amp;quot; &amp;quot;C:\Users\&lt;em&gt;MONCOMPTEWINDOWS&lt;/em&gt;\Documents\eclipsewsp\TestCobertura\build\classes&amp;quot;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Pour information, les différentes options utilisées sont :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;source : le répertoire contenant les sources&lt;/li&gt;    &lt;li&gt;datafile : emplacement du fichier cobertura.ser&lt;/li&gt;    &lt;li&gt;destination : répertoire dans lequel on génère le rapport&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Le dernier paramètre est l’emplacement des fichiers classes d’origine.&lt;/p&gt;  &lt;p&gt;Attention à bien utiliser les guillemets “ pour éviter les problèmes d’espaces dans d’éventuels noms longs. Le résultat devrait être :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Cobertura 1.9.4.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file     &lt;br /&gt;Cobertura: Loaded information on 23 classes.      &lt;br /&gt;Report time: 569ms&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Dans le répertoire TestCouverture\rapportCobertura vous devriez voir une série de fichier html dont le fichier index.html.&lt;/p&gt;  &lt;p&gt;Si le répertoire est vide, vérifiez le nom et le chemin de vos différents fichiers et répertoire. Le message est malheureusement le même entre un succès et un échec.&lt;/p&gt;  &lt;p&gt;Pour consulter le rapport, double cliquer sur index.html.&lt;/p&gt;  &lt;p&gt;Si quand vous consultez le détail d’une classe, vous n’avez pas le code de la classe mais le message&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Unable to locate fr/natsystem/demonatjet/gettingstarted/DemoNatJet40.java. Have you specified the source directory?&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;C’est que vous avez oublié de spécifier l’option source de la commande ou bien que le nom du répertoire contenant vos sources est incorrect.&lt;/p&gt;  &lt;h3&gt;Cobertura et Spring et AspectJ&lt;/h3&gt;  &lt;p&gt;Cobertura et le module AspectJ de spring utilisent tous les deux des mécanismes de proxy qui entrent en collision. Il peut donc arriver, que lors de l’exécution d’une classe instrumentalisée, vous obteniez le message suivant (alors que cette même classe non instrumentalisée fonctionne parfaitement) :&lt;/p&gt;  &lt;div class="code"&gt;org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy17 implementing net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'fr.j2ltho.impression.ImpressionManager' for property 'impressionManager'; &lt;/div&gt;  &lt;div class="code"&gt;nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy17 implementing net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [fr.j2ltho.impression.ImpressionManager] for property 'impressionManager': no matching editors or conversion strategy found   &lt;br /&gt;org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:462)    &lt;br /&gt;&lt;/div&gt;  &lt;p&gt;Dans mes fichiers de configuration Spring j’avais la déclaration suivante :&lt;/p&gt;  &lt;div class="code"&gt;&amp;lt;context:annotation-config/&amp;gt;   &lt;br /&gt;&lt;/div&gt;  &lt;p&gt;Pour Spring cela correspond à l’utilsation d’aspectJ avec le défaut suivant &amp;lt;aop:aspectj-autoproxy/&amp;gt;.&lt;/p&gt;  &lt;p&gt;Pour résoudre le problème j’ai juste ajouté la ligne suivante en gras :&lt;/p&gt;  &lt;div class="code"&gt;&amp;lt;context:annotation-config/&amp;gt;   &lt;br /&gt;    &lt;p&gt;&lt;strong&gt;&amp;lt;aop:aspectj-autoproxy proxy-target-class=&amp;quot;true&amp;quot; /&amp;gt;&lt;/strong&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Cela a fait disparaitre mon erreur et j’ai pu continuer mes tests.&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;Nous avons fait un rapide tour de l’utilisation de Cobertura dans un contexte JEE. Vous pouvez maintenant valider si vos tests couvrent la totalité de votre code.&lt;/p&gt;  &lt;p&gt;Le bon fonctionnement de ces tests reposent sur la capacité du serveur d’application à trouver le bon fichier cobertura.ser et à le mettre à jour. L’emplacement où un serveur d’application cherche se fichier reste pour moi un grand mystère. Dans le cas d’un serveur Tomcat démarré avec startup.bat il se trouve dans le répertoire Tomcat/bin. Dans les autres as, je vous laisse découvrir son emplacement. Une solution consiste à lancer votre serveur sur des classes instrumentalisées sans ajouter le fichier cobertura.ser. Il créera à la fin de l’exécution un nouveau fichier cobertura.ser vide mais qui vous indiquera son emplacement.&lt;/p&gt;  &lt;p&gt;L’autre difficulté de l’utilisation avec un serveur d’application est le mécanisme de terminaison qui doit être utilisé. Cobertura semble placer une sorte de hook sur un certain type de sortie violente (le Ctrl C notamment). Il faut passer par ce hook, pour qu’il mette à jour le fichier cobertura.ser. Pour certaine configuration et certain serveur, l’arrêter en déclenchant ce hook peut être difficile à mettre en œuvre. Pour Tomcat, il suffit de démarrer avec Startup.bat et de l’arrêter avec Ctrl C.&lt;/p&gt;  &lt;p&gt;Je prévois d’écrire rapidement, un second billet qui se concentrera sur l’opportunité et l'intérêt d’utiliser Cobertura dans un projet.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-2220999411794476690?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/2220999411794476690/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=2220999411794476690&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/2220999411794476690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/2220999411794476690'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/11/couverture-de-code-mise-en-uvre-de.html' title='Couverture de code : Mise en œuvre de Cobertura pour une application Web'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Y8Z3ymNuOiE/TNQRTnfLeWI/AAAAAAAADeI/T5xRZbJi6l0/s72-c/CoberturaRapportIndex_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-3102114868061078334</id><published>2010-04-18T22:22:00.001+02:00</published><updated>2010-04-18T22:22:08.344+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Perte d’accès à Google Sites suite à abonnement à Google Apps</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Nous utilisons depuis déjà un peu plus d’un an Google Sites comme outil de travail collaboratif. Il y a quelques jours nous avons lancé une expérimentation avec Google Apps afin de remplacer notre serveur Exchange. Surprise, je n’arrive plus à me connecter à Google Sites. Il se trouve que le compte utilisé comme login à Google Sites n’est pas un compte GMAIL mais mon email professionnel : le même que celui qui a est passé dans Google Apps.&lt;/p&gt;  &lt;p&gt;Le symptôme est très particulier : quand je me connecte à Google Sites, il me redirige vers la mire de connexion Google Apps. Si j’utilise mon mot de passe Google Apps, je me connecte mais je ne vois pas le site.&lt;/p&gt;  &lt;p&gt;On dirait que j’ai deux comptes qui correspondent à la même adresse email : &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le premier en tant qu’un indivu isolé : c’est celui qui autorise l’accès à mon Google Sites&lt;/li&gt;    &lt;li&gt;le second en tant que membre d’une société dont le compte est géré par Google Apps&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Google Sites semble vérifier s’il existe un compte Google Apps correspondant et bascule vers ce dernier s’il existe.&lt;/p&gt;  &lt;p&gt;Google Docs sépare les deux environnements, les urls pour Google Docs personnels et Google Docs pour Google Apps diffèrent : il est donc possible de séparer les deux connexions. Je n’ai donc pas de problème sous Google Docs.&lt;/p&gt;  &lt;p&gt;Pour résoudre le problème Google Sites, j’ai utilisé la procédure suivante qui ma permis de changer le login personnel qui correspondait à mon adresse professionnel (disons &lt;a href="mailto:prenomnom@masociete.com"&gt;prenomnom@masociete.com&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;Pour cela, il faut une autre adresse email personnel qui ne soit pas affectée à Google (disons &lt;a href="mailto:alias@yahoo.fr"&gt;alias@yahoo.fr&lt;/a&gt; pour faciliter la compréhension de la manœuvre).&lt;/p&gt;  &lt;p&gt;On se connecte à &lt;a href="https://www.google.com/accounts/ManageAccount"&gt;https://www.google.com/accounts/ManageAccount&lt;/a&gt; pour accéder aux informations de son compte &lt;a href="mailto:prenomnom@masociete.com"&gt;prenomnom@masociete.com&lt;/a&gt;. On utilise son login personnel avec son email professionnel (&lt;a href="mailto:prenomnom@masociete.com"&gt;prenomnom@masociete.com&lt;/a&gt;). &lt;/p&gt;  &lt;p&gt;On arrive sur la page Google comptes. Dans la rubrique Sécurité, il y a un lien “Modifier l’adresse e-mail”. Cliquez dessus.&lt;/p&gt;  &lt;p&gt;La page Modifier l’adresse e-mail (URL &lt;a title="https://www.google.com/accounts/EditEmail" href="https://www.google.com/accounts/EditEmail"&gt;https://www.google.com/accounts/EditEmail&lt;/a&gt;) s’affiche.&lt;/p&gt;  &lt;p&gt;Dans nouvelle adresse e-mail vous avez votre adresse email professionnelle qui correspond à votre compte (&lt;a href="mailto:prenomnom@masociete.com"&gt;prenomnom@masociete.com&lt;/a&gt;). Il faut taper une autre adresse email (&lt;a href="mailto:alias@yahoo.fr"&gt;alias&lt;/a&gt;&lt;a href="mailto:prenomnom@yahoo.fr"&gt;@yahoo.fr&lt;/a&gt;). Saisir un mot de passe. Et appuyer sur “Enregistrer l’adresse e-mail”&lt;/p&gt;  &lt;p&gt;Vous allez recevoir un email qui vous demandera de confirmer l’adresse en cliquant sur le lien. Cliquer sur le lien de confirmation dans l’email.&lt;/p&gt;  &lt;p&gt;Une fois la confirmation faite, vous pouvez vous reconnecter au compte en utilisant la nouvelle adresse email (&lt;a href="mailto:alias@yahoo.fr"&gt;alias&lt;/a&gt;&lt;a href="mailto:prenomnom@yahoo.fr"&gt;@yahoo.fr&lt;/a&gt;) et le mot de passe spécifié. &lt;/p&gt;  &lt;p&gt;Attention ! ce changement affecte également Google Docs, iGoogle et tout les autres services. Il est maintenant possible de se reconnecter à Google Sites avec le nouvel email (&lt;a href="mailto:alias@yahoo.fr"&gt;alias&lt;/a&gt;&lt;a href="mailto:prenomnom@yahoo.fr"&gt;@yahoo.fr&lt;/a&gt;). &lt;/p&gt;  &lt;p&gt;J’espère que ce billet aura permis à d’autre de résoudre la mésaventure qui m’est arrivé. Notez que cette procédure permet de changer son login pour un compte Google.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-3102114868061078334?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/3102114868061078334/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=3102114868061078334&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/3102114868061078334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/3102114868061078334'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/04/perte-dacces-google-sites-suite.html' title='Perte d’accès à Google Sites suite à abonnement à Google Apps'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-6687209903690639709</id><published>2010-03-05T14:48:00.001+02:00</published><updated>2010-03-05T14:48:42.594+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><title type='text'>Installation de JBoss 5.1 sur Windows 7 64 bits</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;JBoss nécessite un JDK 5 ou 6. Le JDK n’est pas installé par défaut sur une machine. Seul la JRE est installé.&lt;/p&gt;  &lt;h3&gt;Installation d’un JDK 6 pour Windows 7 64 bits&lt;/h3&gt;  &lt;p&gt;Sur le site &lt;a href="http://developers.sun.com/downloads/"&gt;http://developers.sun.com/downloads/&lt;/a&gt; on choisit le nœud Java SE de la liste des téléchargement puis on clique sur Java SE (JDK) 6.&lt;/p&gt;  &lt;p&gt;Ensuite je choisis la version JDK 6 update 18 et non pas le Development Kit Bundle.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9gexlebI/AAAAAAAACgA/WKa0cgDL7sc/s1600-h/DownloadJDK4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DownloadJDK" border="0" alt="DownloadJDK" src="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9hUK5SWI/AAAAAAAACgE/KRa3yxxZS-Y/DownloadJDK_thumb2.png?imgmax=800" width="403" height="428" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Il existe un installeur spécifique à Windows 64 bits : jdk-6u18-windows-x64.exe.&lt;/p&gt;  &lt;p&gt;On exécute l’exe téléchargé. Le UAC demande l’acceptation des modifications faites par le programme.&lt;/p&gt;  &lt;p&gt;Personnellement, j’ai supprimé le Source code.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9h_trjEI/AAAAAAAACgI/E2t_HkKat0M/s1600-h/jdksetup4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="jdksetup" border="0" alt="jdksetup" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S5D9isQ5xgI/AAAAAAAACgM/b0P70lz-Rks/jdksetup_thumb2.png?imgmax=800" width="406" height="314" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On appuie sur Next &amp;gt; ce qui lance une première partie de l’installation.&lt;/p&gt;  &lt;p&gt;A la fin, une nouvelle dialogue apparaît :&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S5D9jYoENaI/AAAAAAAACgQ/2cFBz-kXOgQ/s1600-h/jresetup3.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="jresetup" border="0" alt="jresetup" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S5D9kJL8c2I/AAAAAAAACgU/-IUIKAVltH0/jresetup_thumb1.png?imgmax=800" width="328" height="252" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;L’apparition de cette dialogue doit correspondre au choix de l’option Public JRE du premier setup.&lt;/p&gt;  &lt;p&gt;Je confirme l’installation de la JRE. L’installation se poursuit.&lt;/p&gt;  &lt;p&gt;J’ai maintenant dans mon répertoire C:\Program Files\Java deux sous répertoires :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;jdk1.6.0_18 : le jdk. C’est nécessaire pour compiler des classes java ou des JSP. &lt;/li&gt;    &lt;li&gt;jre6 : le runtime java. Ce répertoire existait déjà &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h3&gt;Installation de JBoss 5.1&lt;/h3&gt;  &lt;p&gt;Le téléchargement d’un serveur JBoss commence à la page suivante : &lt;a href="http://www.jboss.org/jbossas/downloads/"&gt;http://www.jboss.org/jbossas/downloads/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S5D9k8olxSI/AAAAAAAACgY/_dkreT_0aow/s1600-h/jbossdownload7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="jbossdownload" border="0" alt="jbossdownload" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S5D9mGj3jxI/AAAAAAAACgc/fHkcr-jep9s/jbossdownload_thumb5.png?imgmax=800" width="513" height="446" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Il faut choisir Download pour le serveur 5.1. Un message d’avertissement s’affiche en indiquant qu’ils’agit d’une version Community ne disposant pas de support. Il faut continuer.&lt;/p&gt;  &lt;p&gt;Sur la page suivante, on choisit la ligne jboss-5.1.0.GA-jdk6.zip.&lt;/p&gt;  &lt;p&gt;Attention ! il y a deux versions différentes de JBoss 5.1 : une version pour le jdk 1.5 et une version pour le jdk 1.6. Ne vous trompez pas !&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S5D9msz65HI/AAAAAAAACgg/062F4_-97d0/s1600-h/jboss51jdk65.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="jboss51jdk6" border="0" alt="jboss51jdk6" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S5D9nXVbXYI/AAAAAAAACgk/s3M42uk6G8g/jboss51jdk6_thumb3.png?imgmax=800" width="457" height="563" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Le téléchargement commence.&lt;/p&gt;  &lt;p&gt;Je dezippe le fichier téléchargé jboss-5.1.0.GA-jdk6.zip et le copie directement sous C:\ de façon à avoir : C:\jboss-5.1.0.GA.&lt;/p&gt;  &lt;h3&gt;Modification de run.bat&lt;/h3&gt;  &lt;p&gt;Dans le répertoire C:\jboss-5.1.0.GA\bin j’ouvre en modification le fichier run.bat.&lt;/p&gt;  &lt;p&gt;On ajoute en première ligne du bat :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_18&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Il s’agit a priori de l’emplacement de votre jdk 1.6 64 bits. Sous Windows 7, un JDK 64 bits s’installe sous C:\Program Files.&lt;/p&gt;  &lt;p&gt;Personnellement, je ne positionne pas la variable d’environnement JBOSS_HOME. Le bat run.bat semble être capable de la positionner correctement tant qu’on le lance depuis son répertoire d’installation.&lt;/p&gt;  &lt;h3&gt;Rappel de l’organisation des répertoires&lt;/h3&gt;  &lt;p&gt;Si vous avez installé JBoss dans le répertoire C:\jboss-5.1.0.GA, voici un rapide tour d’horizon des quelques répertoires les plus importants pour le développement.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;C:\jboss-5.1.0.GA\bin : répertoire dans lequel se trouve run.bat qui permet de lancer le serveur&lt;/li&gt;    &lt;li&gt;C:\jboss-5.1.0.GA\common\lib : répertoire permettant d’ajouter un jar qui sera commun à toutes vos applications et toutes vos configurations. C’est là qu’on ajoute généralement les jar permettant l’accès à la base de données.&lt;/li&gt;    &lt;li&gt;C:\jboss-5.1.0.GA\server\&lt;strong&gt;default&lt;/strong&gt;\lib : répertoire commun à toutes vos applications de la configuration “default”&lt;/li&gt;    &lt;li&gt;C:\jboss-5.1.0.GA\server\default\tmp : répertoire temporaire qui semble être utilisé par le déploiement. Il peut être supprimé sans problème en phase de développement. Il sera recréé au prochain lancement du serveur.&lt;/li&gt;    &lt;li&gt;C:\jboss-5.1.0.GA\server\&lt;strong&gt;default&lt;/strong&gt;\log : répertoire contenant la log du serveur quand on utilise la configuration “default”. Le fichier server.log contient la log Log4j de votre application.&lt;/li&gt;    &lt;li&gt;C:\jboss-5.1.0.GA\server\default\deploy : répertoire de déploiement de vos war pour la configuration “default”. Glisser/déposer un war dans ce répertoire est la seule opération à faire pour déployer une application sur un serveur JBoss.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pour finir, il reste &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;C:\jboss-5.1.0.GA\lib : auquel il ne faut pas toucher. Il contient les jar du serveur. Ce répertoire ne doit plus être utilisé, il faut favoriser (a priori) le répertoire C:\jboss-5.1.0.GA\server\&lt;strong&gt;default&lt;/strong&gt;\lib qui n’affectera que la configuration par default. &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Rappel sur les configurations de JBoss&lt;/h3&gt;  &lt;p&gt;Par défaut, JBoss livre 5 configurations :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;all&lt;/li&gt;    &lt;li&gt;default : celle qui est utilisé quand on lance run.bat sans paramètre&lt;/li&gt;    &lt;li&gt;minimal&lt;/li&gt;    &lt;li&gt;standard : c’est la config JavaEE de JBoss&lt;/li&gt;    &lt;li&gt;web : cela semble être une configuration légère.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Personnellement je n’utilise que default car elle semble contenir ce dont j’ai besoin et elle possède l’avantage d’être simple à lancer.&lt;/p&gt;  &lt;h3&gt;Test de l’installation&lt;/h3&gt;  &lt;p&gt;Pour lancer le serveur JBoss, on double clique sur le bat : run.bat qui se trouve dans C:\jboss-5.1.0.GA\bin. Un message vous demande de confirmer son exécution, il faut l’acquitter.&lt;/p&gt;  &lt;p&gt;Windows 7 affiche un message d’alerte du parefeu : il faut l’accepter.&lt;/p&gt;  &lt;p&gt;Quand le lancement du serveur est terminé, la boite de commande affiche une ligne : &lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;2010-03-05 13:19:49,240 INFO&amp;#160; [org.jboss.bootstrap.microcontainer.ServerImpl] (main) JBoss (Microcontainer) [5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)] &lt;strong&gt;Started in&lt;/strong&gt; 1m:7s:671ms&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Votre serveur JBoss s’exécute avec la configuration par défaut : default.&lt;/p&gt;  &lt;p&gt;Taper dans un navigateur : &lt;a title="http://localhost:8080/" href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Vous devriez voir apparaître dans votre navigateur :&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9oHtaUxI/AAAAAAAACgo/ywOLgGZKOEg/s1600-h/jbossconsole4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="jbossconsole" border="0" alt="jbossconsole" src="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S5D9o6dq2YI/AAAAAAAACgs/k_g-dU8pklQ/jbossconsole_thumb2.png?imgmax=800" width="651" height="330" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt; Si vous cliquez sur le lien JBoss Web Console, vous obtenez un second écran :&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9pp0oIoI/AAAAAAAACgw/50_9ATwGi0c/s1600-h/JbossWebConsole%5B5%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="JbossWebConsole" border="0" alt="JbossWebConsole" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S5D9qS8mpCI/AAAAAAAACg0/YjI-ISb_Q2A/JbossWebConsole_thumb%5B3%5D.png?imgmax=800" width="703" height="365" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Dans la partie JVM Hardware vous pouvez vérifier la JVM utilisée : &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;JVM Name : Java HotSpot(TM) 64 bits Server VM &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cela indique que vous utilisez bien le JDK 64 bits.&lt;/p&gt;  &lt;p&gt;Vous pouvez également ouvrir le Gestionnaire de tâches Windows : tapez Processus et sélectionnez “Affichez les processus en cours d’exécution avec le Gestionnaire de tâche”.&lt;/p&gt;  &lt;p&gt;Le gestionnaire de tâches indique si le processus java.exe est ou non en 32 bits :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;java.exe *32 : s’il s’agit d’un process 32 bits&lt;/li&gt;    &lt;li&gt;java.exe : s’il s’agit d’un process 64 bits.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pour arrêter le serveur JBoss, il suffit de taper Ctrl C dans la console DOS.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;L’installation de JBoss 5.1 demande de faire particulièrement attention au JDK utilisé (5 ou 6) : en fonction de ce dernier il faudra télécharger le bon zip de JBoss.&lt;/p&gt;  &lt;p&gt;JBoss étant un processus Java, c’est la JVM utilisée qui fera ou non fonctionner JBoss 5.1 en 32 ou 64 bits.&lt;/p&gt;  &lt;p&gt;Pour finir, l’installation décrite dans ce billet correspond à une installation pour un poste développeur : elle ne prend pas en compte la problématique de la sécurité et ne sera de toute façon pas visible depuis un autre poste. Seule l’adresse localhost fonctionnera (c’est la cas depuis au moins la 4.2).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-6687209903690639709?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/6687209903690639709/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=6687209903690639709&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6687209903690639709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6687209903690639709'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/03/installation-de-jboss-51-sur-windows-7.html' title='Installation de JBoss 5.1 sur Windows 7 64 bits'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Y8Z3ymNuOiE/S5D9hUK5SWI/AAAAAAAACgE/KRa3yxxZS-Y/s72-c/DownloadJDK_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-4347777289975571791</id><published>2010-03-03T16:22:00.001+02:00</published><updated>2010-03-03T16:22:46.540+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Petit guide de survie MySql pour le développeur</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Dans ce billet, je vais essayer de faire un tour rapide des différentes fonctions de MySql dont un développeur peut avoir besoin. Cela va comprendre :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le démarrage et arrêt d’un serveur MySql &lt;/li&gt;    &lt;li&gt;la création/destruction d’une base MySql &lt;/li&gt;    &lt;li&gt;l’import/export d’une base MySql &lt;/li&gt;    &lt;li&gt;la consultation du contenu d’une base MySQL en mode commande &lt;/li&gt;    &lt;li&gt;la configuration d’hibernate pour accéder à une base MySQL &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ces mécanismes ont été testé sur un serveur MySql 5.0 sous XP ou 5.1 sous Windows 7 64 bits.&lt;/p&gt;  &lt;h3&gt;MySql pour Windows 7 64 bits&lt;/h3&gt;  &lt;p&gt;Avant de commencer, je tiens à indiquer l’existence d’une version 64 bits de MySql pour Windows 7. Le msi porte le nom de “mysql-5.1.43-winx64.msi”.&lt;/p&gt;  &lt;p&gt;Il s’installe correctement dans le répertoire “C:\Program Files\MySQL\MySQL Server 5.1” qui correspond à l’emplacement pour les process 64 bits.&lt;/p&gt;  &lt;p&gt;Je l’ai installé en tant que service que je démarre manuellement.&lt;/p&gt;  &lt;p&gt;Cette dernière version ne semble plus accepter un mot de passe vide pour root.&lt;/p&gt;  &lt;h3&gt;Démarrage et arrêt d’un serveur MySql&lt;/h3&gt;  &lt;p&gt;Le démarrage et l’arrêt dépendent de votre installation du serveur MySql entant que service ou non.&lt;/p&gt;  &lt;h4&gt;MySql n’est pas un service&lt;/h4&gt;  &lt;p&gt;Pour démarrer est arrêter MySql s’il n’est pas installé en tant que service, je crée deux fichiers BAT mais les lignes qu’ils contiennent peuvent être tapés directement en ligne de commande :&lt;/p&gt;  &lt;p&gt;Pour démarrer le serveur :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;quot;C:\Program Files\MySQL\MySQL Server 5.0\bin\mysqld&amp;quot;&amp;#160; --console&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Pour arrêter le serveur :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;&amp;quot;C:\Program Files\MySQL\MySQL Server 5.0\bin\mysqladmin&amp;quot; -u root shutdown&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Attention les doubles quotes (“) servent à prendre en compte les espaces et doivent se terminer impérativement à la fin de la commande (avant ses paramètres).&lt;/p&gt;  &lt;p&gt;Vérifiez bien le répertoire d’installation de votre MySQL, celui-ci a un impact sur la commande donnée ci dessus.&lt;/p&gt;  &lt;h4&gt;MySql est un service&lt;/h4&gt;  &lt;p&gt;J’utilise l’interface de service de Windows : dans Windows 7, j’ai “Epinglé le programme dans la barre de tâche”. Pour cela, il suffit de cliquer droit sur son icône une fois qu’il a été lancé et de choisir “Epingler ce programme dans la barre de tâche”. Pour le relancer, il vous suffit de cliquer une fois dessus.&lt;/p&gt;  &lt;p&gt;Pour le démarrer sous Windows 7, si on n’a pas fait un raccourci, je tape Services dans la zone de saisie et je sélectionne le programmes Services (et non pas services.exe).&lt;/p&gt;  &lt;p&gt;Il est également possible de passer par le panneau de configuration, puis &amp;quot;outils d’administration” et Services.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S45wsXjxPCI/AAAAAAAACf4/kS4SD8vWqWo/s1600-h/ServicesMySQL7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ServicesMySQL" border="0" alt="ServicesMySQL" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S45wtdWYtXI/AAAAAAAACf8/x0heJgoIy1I/ServicesMySQL_thumb5.png?imgmax=800" width="487" height="356" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Une fois la fenêtre “Service” ouverte, il suffit de sélectionner le Services (local) MySQL dans la liste puis d’appuyer sur le lien Démarrer pour le démarrer ou Arrêter pour l’arrêter.&lt;/p&gt;  &lt;h3&gt;Créer ou détruire une base MySQL&lt;/h3&gt;  &lt;p&gt;Par défaut il existe une base test. Vous pouvez avoir besoin de créer une base particulière pour une démo ou un développement particulier si vous travaillez sur plusieurs projets.&lt;/p&gt;  &lt;p&gt;Avec ce mécanisme les données des différentes bases sont isolées. Vous pouvez sans risque non seulement ajouter des données à une base sans impacter l’autre mais vous pouvez même créer des tables avec un même nom et des structures différentes dans deux bases différentes.&lt;/p&gt;  &lt;p&gt;Pour commencer, il est impératif que le serveur MySQL fonctionne (Voir comment démarrer le serveur MySQL dans le chapitre précédent).&lt;/p&gt;  &lt;p&gt;Ensuite, nous allons lancer une console de commande sur MySQL. Pour cela, on ouvre une console DOS, en tapant par exemple cmd.exe.&lt;/p&gt;  &lt;p&gt;Au prompt, on se déplace dans le répertoire contenant le binaire MySQL :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cd C:\Program Files\MySQL\MySQL Server 5.0\bin&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Puis on tape :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;mysql –uroot –pmonmotdepasse&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où root est l’utilisateur et monmotdepasse le mot de passe de cet utilisateur root.&lt;/p&gt;  &lt;p&gt;Pour créer la base, on tape :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;create database nombase;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où nombase est le nom que vous voulez donner à votre base (évitez test qui est déjà utilisé).&lt;/p&gt;  &lt;p&gt;Pour utiliser la base, il faut faire ensuite :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;use nombase;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;ce qui permet de se mettre dans la base concernée.&lt;/p&gt;  &lt;p&gt;Pour détruire une base, il suffit de taper :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;drop database nombase;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Attention ! aucun message de confirmation n’est affiché. Vous perdez tout : donnée et structure de la base.&lt;/p&gt;  &lt;h3&gt;Export/Import d’une base de données MySQL&lt;/h3&gt;  &lt;p&gt;Pour faire ces opérations, il faut que la base de départ de l’export fonctionne ainsi que celle d’arrivée pour l’import. Pour démarrer une base MySQL voir le chapitre précédent.&lt;/p&gt;  &lt;h4&gt;Exporter une base MySQL&lt;/h4&gt;  &lt;p&gt;L’opération est réalisé à partir du mode ligne de commande de MySQL. Il faut démarrer une console DOS grâce à cmd.exe. Ensuite, on doit réaliser les étapes suivantes : &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Se positionner sur le répertoire bin de MySQL &lt;/li&gt;    &lt;li&gt;Faire le dump. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cd C:\Program Files\MySQL\MySQL Server 5.0\bin&lt;/p&gt;    &lt;p&gt;mysqldump nombase –uroot –pmonmotdepasse &amp;gt; nomfichier.log&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;nombase est le nom de la base MySQL &lt;/li&gt;    &lt;li&gt;root est le nom de l”utilisateur (dans un contexte de développement, on utilise souvent l’administrateur par défaut) &lt;/li&gt;    &lt;li&gt;monmotdepasse est le mot de passe de l’utilisateur root &lt;/li&gt;    &lt;li&gt;nomfichier.log est le nom du fichier d’export. Il sera créé dans le répertoire où l’on se trouve. En l’occurrence “C:\Program Files\MySQL\MySQL Server 5.0\bin”. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Le fichier créé était dans mon cas au format ANSI. Ma base était au format ANSI.&lt;/p&gt;  &lt;h4&gt;Importer une base MySQL&lt;/h4&gt;  &lt;p&gt;L’opération est réalisé à partir du mode ligne de commande de MySQL. Le fichier a été exporté avec le mécanisme précédemment décrit. Il faut démarrer une console DOS grâce à cmd.exe. Ensuite, on doit réaliser les étapes suivantes : &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Se positionner sur le répertoire bin de MySQL &lt;/li&gt;    &lt;li&gt;Se connecter au serveur MySQL &lt;/li&gt;    &lt;li&gt;Créer la base MySQL dans laquelle l’import va être réalisé &lt;/li&gt;    &lt;li&gt;Se positionner sur la base &lt;/li&gt;    &lt;li&gt;Importer (commande source) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cd C:\Program Files\MySQL\MySQL Server 5.1\bin&lt;/p&gt;    &lt;p&gt;mysql –uroot –pmonmotdepasse&lt;/p&gt;    &lt;p&gt;create database nombase;&lt;/p&gt;    &lt;p&gt;use nombase;&lt;/p&gt;    &lt;p&gt;source c:/nomfichier.log&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;nombase est le nom de la base MySQL &lt;/li&gt;    &lt;li&gt;root est le nom de l”utilisateur (dans un contexte de développement, on utilise souvent l’administrateur par défaut) &lt;/li&gt;    &lt;li&gt;monmotdepasse est le mot de passe de l’utilisateur root &lt;/li&gt;    &lt;li&gt;nomfichier.log est le nom du fichier d’export. Il avait été placé dans le répertoire C:\. Notez que j’utilise la syntaxe C:/ au lieu de C:\ car l’antislash est un caractère d’échappement pour MySQL. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Dans mon cas, le fichier créé était au format ANSI. Ma base destination était quant à elle au format UTF-8. En faisant simplement l’import, les caractères accentués ne sont plus affichés au bon format. Pour résoudre le problème, j’ai utilisé PSPad pour passer le format de mon fichier en UTF-8. Il suffit juste dans le menu Format de sélectionner UTF-8 au lieu de ANSI.&lt;/p&gt;  &lt;h3&gt;Consulter les données d’une base MySQL&lt;/h3&gt;  &lt;p&gt;Avant toute chose, le serveur MySQL doit être démarré (voir pour cela le second chapitre de ce billet). &lt;/p&gt;  &lt;p&gt;L’opération est réalisé à partir du mode ligne de commande de MySQL.Il faut démarrer une console DOS grâce à cmd.exe. Ensuite, on doit réaliser les étapes suivantes : &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Se positionner sur le répertoire bin de MySQL &lt;/li&gt;    &lt;li&gt;Se connecter au serveur MySQL &lt;/li&gt;    &lt;li&gt;Se positionner sur la base &lt;/li&gt;    &lt;li&gt;Taper les commandes SQL &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;cd C:\Program Files\MySQL\MySQL Server 5.1\bin&lt;/p&gt;    &lt;p&gt;mysql –uroot –pmonmotdepasse&lt;/p&gt;    &lt;p&gt;use test;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Où :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;test est le nom de la base MySQL &lt;/li&gt;    &lt;li&gt;root est le nom de l”utilisateur (dans un contexte de développement, on utilise souvent l’administrateur par défaut) &lt;/li&gt;    &lt;li&gt;monmotdepasse est le mot de passe de l’utilisateur root &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Les commandes SQL les plus classiques sont :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;show tables; : liste les tables de la base&lt;/li&gt;    &lt;li&gt;desc nomtable; : donne la description de la structure de la table nomtable &lt;/li&gt;    &lt;li&gt;select * from nomtable where …; : liste les données d’une table. Attention à préciser une where clause si vous ne voulez pas parcourir toutes les données d’une table &lt;/li&gt;    &lt;li&gt;select count(*) from nomtable where…; : compte le nombre d’enregistrement de la table qui vérifie la where clause. Il peut être judicieux d’utiliser cette commande avant d’utiliser la précédente. &lt;/li&gt;    &lt;li&gt;show variables like ‘character_set%’; permet de connaitre le charset de la base.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pour quitter, il suffit de taper :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;exit&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Configuration d’hibernate.cfg.xml pour MySQL&lt;/h3&gt;  &lt;p&gt;Pour utiliser hibernate, il faut définir un fichier hibernate.cfg.xml (généralement placé sous src) qui contient les informations nécessaires à hibernate pour se connecter à la base MySQL.&lt;/p&gt;  &lt;p&gt;&amp;lt;session-factory&amp;#160; &amp;gt;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;property name=&amp;quot;hibernate.connection.driver_class&amp;quot;&amp;gt;com.mysql.jdbc.Driver&amp;lt;/property&amp;gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;property name=&amp;quot;hibernate.connection.url&amp;quot;&amp;gt;jdbc:mysql://localhost/test&amp;lt;/property&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;property name=&amp;quot;hibernate.connection.username&amp;quot;&amp;gt;root&amp;lt;/property&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;property name=&amp;quot;hibernate.connection.password&amp;quot;&amp;gt;monmotdepasse&amp;lt;/property&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;property name=&amp;quot;hibernate.dialect&amp;quot;&amp;gt;org.hibernate.dialect.MySQL5InnoDBDialect&amp;lt;/property&amp;gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&amp;lt;/session-factory&amp;gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;Où :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;test est le nom de la base MySQL &lt;/li&gt;    &lt;li&gt;root est le nom de l”utilisateur (dans un contexte de développement, on utilise souvent l’administrateur par défaut) &lt;/li&gt;    &lt;li&gt;monmotdepasse est le mot de passe de l’utilisateur root &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Il faut également un jar MySQL. Ce jar MySQL “mysql-connector-java-5.0.8-bin.jar” peut se placer en deux endroits :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;directement dans le répertoire lib de votre installation Tomcat : Par exemple : “C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib”. dans ce cas, le jar MySQL sera disponible pour toutes les applications Web de ce serveur Tomcat &lt;/li&gt;    &lt;li&gt;soit dans le répertoire WebContent/WEB-INF/lib de votre projet. Dans ce cas, il faudra répéter l’opération autant de fois que nécessaire (pour chaque projet) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;La seconde solution n’a de sens que dans le cas de demo ou d’exemples qui ne rentre pas dans un processus normal d’exploitation : on recherche l’autonomie et la facilité sans aucun besoin de traçabilité. C’est pour cela qu’on va intégrer le driver MySQL dans son package de déploiement.&lt;/p&gt;  &lt;p&gt;La philosophie de JEE correspond à la première solution : installation dans les librairies du serveur JEE. La base de donnée est quelque chose de suffisamment sérieux pour que l’exploitation soit concernée par le sujet et doive établir une traçabilité des versions utilisées.&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Ce billet a pour vocation de donner à un développeur le minimum nécessaire pour se sentir à l’aise dans la manipulation de MySQL. Les informations de ce billet ne doivent être en aucun cas utilisées comme ligne de conduite pour l’installation et le déploiement d’une base MySQL en production.&lt;/p&gt;  &lt;p&gt;Pour compléter les aspects développements, vous pouvez lire mon billet sur &lt;a href="http://jl2tho.blogspot.com/2009/09/type-de-donnees-jpa-et-hibernate.html"&gt;les types de données JPA et Hibernate&lt;/a&gt; qui montre les relations entre les types MySQL et les annotations JPA.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-4347777289975571791?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/4347777289975571791/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=4347777289975571791&amp;isPopup=true' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4347777289975571791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4347777289975571791'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/03/petit-guide-de-survie-mysql-pour-le.html' title='Petit guide de survie MySql pour le développeur'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Y8Z3ymNuOiE/S45wtdWYtXI/AAAAAAAACf8/x0heJgoIy1I/s72-c/ServicesMySQL_thumb5.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-94582717326153658</id><published>2010-02-25T18:09:00.001+02:00</published><updated>2010-02-25T18:09:05.662+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NatStar'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Fichier invisible dans l’explorateur Windows 7 64 bits</title><content type='html'>&lt;p&gt;Ce billet est un nouvel épisode dans ma tentative de prise de contrôle de ma nouvelle machine Windows 7 64 bits.&lt;/p&gt;  &lt;p&gt;Windows 7 64 bits (mais cela est probablement déjà le cas en Vista 64 bits) possède une notion de VirtualStore qui est susceptible de poser quelques problèmes surprenants. J’en ai détecté deux :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le fichier que j’ai créé avec un programme 32 bits (en l’occurrence Eclipse) dans un répertoire (en l’occurrence un sous répertoire de ProgramFiles) n’apparait pas quand je passe par l’explorateur.&lt;/li&gt;    &lt;li&gt;depuis une application 32 bits (NS-DK ou NatStar en l’occurrence) les valeurs que je lis dans un fichier (en l’occurrence dans un sous répertoire de ProgramFiles(x86)) ne sont pas celles que je peux lire quand j’ouvre le même fichier par l’explorateur.&lt;/li&gt;    &lt;li&gt;depuis une application 32 bits (la même que précédemment) j’arrive à lire un fichier (en l’occurrence dans un sous répertoire de ProgramFiles(x86)) qui n’est pas visible dans l’explorateur alors que j’affiche les fichiers cachés (c’est en fait un doublon du premier cas)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;L’explication de ce phénomène est la création par le système d’un VirtualStore. Le signe visuel que vous avez qu’un VirtualStore qui correspond à votre répertoire a été créé est la présence d’un bouton “Fichiers de compatibilité” dans la barre d’outil de l’explorateur.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S4agkAeWlKI/AAAAAAAACeY/HCITwEXQ51k/s1600-h/Windows7FichierCompatibilite%5B6%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Windows7FichierCompatibilite" border="0" alt="Windows7FichierCompatibilite" src="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S4agk_wIT_I/AAAAAAAACec/Mp0MuDowz4A/Windows7FichierCompatibilite_thumb%5B4%5D.png?imgmax=800" width="678" height="310" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Remarquez dans l’exemple ci-dessus, la présence de deux fichiers :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;DemoNatJetCompleted.war le 18/02/2010 à 11:20&lt;/li&gt;    &lt;li&gt;NatJxt3DemoMultiPannel.war le 30/05/2008&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On est dans le répertoire “C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps”. Les deux fichiers présents on été copié à la main par l’explorateur. Le processus Tomcat 64 bits détecte correctement ces deux fichiers.&lt;/p&gt;  &lt;p&gt;Si on appuie sur le bouton “Fichiers de compatibilité”, on bascule vers le répertoire “C:\Users\jltho.NATSYSTEM\AppData\Local\VirtualStore\Program Files\Apache Software Foundation\Tomcat 6.0\webapps” du VirtualStore.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/S4aglz_ZiQI/AAAAAAAACeg/nFZUYrbquTA/s1600-h/Windows7VirtualStore%5B4%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Windows7VirtualStore" border="0" alt="Windows7VirtualStore" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S4agmci9pCI/AAAAAAAACek/V9li9gUt204/Windows7VirtualStore_thumb%5B2%5D.png?imgmax=800" width="518" height="152" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On a maintenant deux fichiers :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;DemoNatJetCompleted.war du 17/02/2010 à 18:41 : sa date indique qu’il est plus ancien que celui qu’on voyait plus haut.&lt;/li&gt;    &lt;li&gt;NatVie30WF &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ces deux fichiers ont été créé directement depuis un Eclipse 32 bits par la fonction Export/War… Le processus Tomcat ne voit pas ces deux fichiers. Eclipse lui les voit.&lt;/p&gt;  &lt;p&gt;Dans le cas de mon application NatStar/NS-DK (il s’agit d’un binaire 32 bits à base de C), le problème était encore plus surprenant : le fichier du VirtualStore a été créé par un autre mécanisme (mon application consulte le fichier exclusivement en lecture). Mon application lisait pourtant ce fichier du VirtualStore. Quand je modifie le fichier dans le répertoire d’origine en passant par l’explorateur, les modifications que je réalise ne sont pas visibles par l’application : elle continue de lire les anciennes valeurs. Si je supprime le fichier dans le répertoire d’origine (ProgramFiles(x86)), l’application continue d’être capable de lire les données alors que depuis l’explorateur je ne vois rien.&lt;/p&gt;  &lt;p&gt;Pour info, nous avons détecté le problème grâce à l’utilisation de Process Monitor qui nous a permis de constater que le process ne lisait pas dans le répertoire ProgramFiles(x86) mais dans un autre répertoire.&lt;/p&gt;  &lt;p&gt;Une fois dans le VirtualStore (grâce au bouton), vous pouvez surprimer les fichiers. Dans le cas de mon application NatStar/NS-DK, elle s’est mise à lire le bon fichier et ne l’a pas recréé dans le VirtualStore. J’ai modifié ce fichier par l’explorateur depuis, sans que le VirtualStore ne soit recréé.&lt;/p&gt;  &lt;p&gt;La règle que l’on peut déduire est la suivante :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;si un process 32 bits écrit dans certains répertoires (a priori ProgramFiles(x86) et ProgramFiles), le système redirige son écriture dans un autre répertoire physique : le VirtualStore&lt;/li&gt;    &lt;li&gt;si une application 32 bits lit un fichier dans un répertoire possédant un VirtualStore, elle lit en premier lieu le fichier s’il existe dans le VirtualStore. Si le fichier n’existe pas dans le VirtualStore et seulement dans ce cas, il va lire le fichier dans le répertoire d’origine.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On constate que pour un processus 32 bits, c’est le fichier dans le VirtualStore qui prévaut.&lt;/p&gt;  &lt;p&gt;Pour un processus 64 bits, il ne voit que le répertoire d’origine.&lt;/p&gt;  &lt;h4&gt;Comment savoir pourquoi un fichier a été virtualisé ?&lt;/h4&gt;  &lt;p&gt;Cela est possible en utilisant l’Observateur d’événements de Windows 7. Il s’ouvre en tapant dans la zone de commande : Obs puis en sélectionnant ce dernier dans la liste qui apparait.&lt;/p&gt;  &lt;p&gt;La rubrique qui nous intéresse est : “Journaux des applications et des services” puis “Microsoft” puis “Windows” puis “UAC-FileVirtualization”. On clique sur le nœud Opérationnel, une liste apparait. Les événements d’ID 4000 indiquent les création de fichiers de virtualisation.&lt;/p&gt;  &lt;p&gt;En cliquant sur l’onglet détail, il est possible de savoir qui a créé le fichier concerné :&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S4agnJWDPcI/AAAAAAAACeo/qEZCaERzwF4/s1600-h/Windows7VirtualizationDetail%5B6%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Windows7VirtualizationDetail" border="0" alt="Windows7VirtualizationDetail" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S4agoG6qzpI/AAAAAAAACes/pthoEwlS74E/Windows7VirtualizationDetail_thumb%5B4%5D.png?imgmax=800" width="619" height="427" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On voit ainsi qu’un fichier war temporaire a été créé dans le VirtualStore par un process javaw.exe lancé depuis un répertoire C:\NatJet3.0.2\thirdparty\jdk1.5.0_15\bin.&lt;/p&gt;  &lt;p&gt;C’est grâce à cela que j’ai compris comment pour mon application NatStar, les fichiers de Virtualisation avaient été créé : il s’agissait de la procédure d’installation de mon application qui lançait un processus 32 bits (switch.exe) pour faire des substitutions dans les fichiers installés dans ProgramFiles(x86).&lt;/p&gt;  &lt;h4&gt;Conclusion&lt;/h4&gt;  &lt;p&gt;Ce mécanisme de virtualisation est très surprenant : la volonté de Microsoft semble avoir été d’augmenter la compatibilité des nombreuses applications qui ne respectent pas les droits sur les répertoires ProgramFiles. Cela afin de faciliter la migration lors du passage à Vista : avant Vista les applications avaient les privilèges d’un administrateur, depuis elles tournent avec els droits d’un simple utilisateur : elles n’ont plus le droit d’écrire n’importe où.&lt;/p&gt;  &lt;p&gt;Vous trouverez plus d’information sur le sujet dans les deux pages suivantes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://support.microsoft.com/kb/927387"&gt;http://support.microsoft.com/kb/927387&lt;/a&gt; : elle présente d’autres problèmes liés à la virtualisation&lt;/li&gt;    &lt;li&gt;&lt;a href="http://windowsteamblog.com/blogs/developers/archive/2009/08/04/user-account-control-data-redirection.aspx"&gt;http://windowsteamblog.com/blogs/developers/archive/2009/08/04/user-account-control-data-redirection.aspx&lt;/a&gt; : un très bon article en anglais qui explique le fonctionnement de la virtualisation et ses raisons. Il décrit également l’utilisation de Proc Monitor pour détecter les applications qui déclenche la virtualisation.&lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-94582717326153658?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/94582717326153658/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=94582717326153658&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/94582717326153658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/94582717326153658'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/02/fichier-invisible-dans-lexplorateur.html' title='Fichier invisible dans l’explorateur Windows 7 64 bits'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Y8Z3ymNuOiE/S4agk_wIT_I/AAAAAAAACec/Mp0MuDowz4A/s72-c/Windows7FichierCompatibilite_thumb%5B4%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-4084674591717205700</id><published>2010-02-23T14:57:00.001+02:00</published><updated>2010-02-23T14:58:03.701+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><title type='text'>Problème pour définir une variable d’environnement utilisant ProgramFiles(x86)</title><content type='html'>&lt;p&gt;Je fais ce rapide billet suite à un problème de configuration dans un fichier cmd sous Windows 7 64 bits.&lt;/p&gt;  &lt;p&gt;Windows 7 64 bits définit deux variables d’environnement et deux répertoires :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ProgramFiles(x86) qui pointe vers C:\Program Files (x86) : c’est là que sont installés normalement les programmes 32 bits. &lt;/li&gt;    &lt;li&gt;ProgramFiles qui pointe vers&amp;#160; C:\Program Files qui s’appelle dans l’explorateur Programmes : c’est le répertoire qui contient les programmes 64 bits. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette distinction devait déjà exister sous Vista 64 bits. Elle n’est visible que si l’OS est 64 bits. Sur une version 32 bits, il n’existe que ProgramFiles.&lt;/p&gt;  &lt;p&gt;Pour savoir si l’OS est 32 ou 64 bits, la variable d’environnement PROCESSOR_ARCHITECTURE peut être utilisée : elle prend les valeurs :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;AMD64 pour du 64 bits &lt;/li&gt;    &lt;li&gt;x86 pour du 32 bits &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette variable existe déjà sous Windows XP et elle prend bien x86 sous un environnement 32 bits.&lt;/p&gt;  &lt;p&gt;Les applications qui m’intéressent utilisent un cmd qui positionne les variables d’environnement&amp;#160; à son exécution (un mécanisme commun pour les applications NS-DK ou NatStar), le répertoire de base de mon application est sous %ProgramFiles% en 32 bits. Lors du passage sous 64 bits, le binaire restant un binaire 32 bits, il s’installe sous %ProgramFiles(x86)% j’ai donc cherché à redéfinir mes différentes variables d’environnement pour le cas du 64 bits. Je passe par une variable d’environnement local au cmd et temporaire PRGROOT afin d’éviter de modifier toutes les définitions.&lt;/p&gt;  &lt;p&gt;J’ai commencé par faire :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;if &amp;quot;%PROCESSOR_ARCHITECTURE%&amp;quot; == &amp;quot;AMD64&amp;quot; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET PRGROOT=%programfiles(x86)%       &lt;br /&gt;)       &lt;br /&gt;if &amp;quot;%PROCESSOR_ARCHITECTURE%&amp;quot; == &amp;quot;x86&amp;quot; (       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET PRGROOT=%programfiles%       &lt;br /&gt;)&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Et là bizarrement, PRGROOT prend la valeur C:\Program Files (x86 sans la parenthèse fermante.&lt;/p&gt;  &lt;p&gt;Après de nombreux essais, j’ai essayé la syntaxe (notez l’utilisation de guillemet autour de l’affectation complète)&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;if &amp;quot;%PROCESSOR_ARCHITECTURE%&amp;quot; == &amp;quot;AMD64&amp;quot; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET &amp;quot;PRGROOT=%programfiles(x86)%&amp;quot;       &lt;br /&gt;)       &lt;br /&gt;if &amp;quot;%PROCESSOR_ARCHITECTURE%&amp;quot; == &amp;quot;x86&amp;quot; (       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET PRGROOT=%programfiles%       &lt;br /&gt;)&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Et là, tout se passe bien : je retrouve ma parenthèse fermante.&lt;/p&gt;  &lt;p&gt;J’espère que ce billet sera utile à d’autres. On dirait qu’il y a un petit bug dans le cas du IF : il remplace %programfiles(x86)% par sa valeur puis, il fait l’affectation. Il prend la parenthèse fermante pour la fin du IF et non pas comme faisant partie de la valeur qu’il doit affecter. Les guillemet le force à considérer la parenthèse fermante comme faisant partie de l’affectation.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-4084674591717205700?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/4084674591717205700/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=4084674591717205700&amp;isPopup=true' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4084674591717205700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4084674591717205700'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/02/probleme-pour-definir-une-variable.html' title='Problème pour définir une variable d’environnement utilisant ProgramFiles(x86)'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-1755841468199242565</id><published>2010-02-21T19:52:00.001+02:00</published><updated>2010-02-21T19:55:49.509+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Free'/><title type='text'>Problème de connexion Wifi avec une FreeBox</title><content type='html'>&lt;p&gt;Ceci est un rapide billet pour éviter que d'autres restent bloquer par le problème que j'ai rencontré avec ma FreeBox.&lt;/p&gt; &lt;p&gt;Le symptôme est plus ou moins simple : impossibilité de rejoindre le réseau Wifi de sa propre FreeBox. Le réseau est effectivement visible mais quand on tape la clé WEP/WAP que l'on a sur l'interface de sa FreeBox HD, la connexion est refusée. Il peut même arriver que l'on saisisse une clé trop longue supérieure aux 63 caractères attendus (mais là, suivant l'interface utilisée on sera ou non prévenu).&lt;/p&gt; &lt;p&gt;Il se trouve que mon réseau Wifi fonctionne, j'ai un autre PC connecté qui l'atteste.&lt;/p&gt; &lt;p&gt;La cause du problème est l'interface de la FreeBox HD : j'ai préféré utiliser celle-ci plutôt que d'utiliser l'interface Web de la FreeBox. L'interface de la FreeBox HD est accessible sur la télé après l'appuie sur le touche FreeBox de la télécommande puis on va dans Paramètres. La rubrique Wifi, indique la clé du réseau. La version actuel du FirmWare possède un bug pour les caractères &amp;gt; mais je suppose que c'est également vrai pour &amp;lt; : il ne les affichent pas correctement, il les remplace par leur code html : &amp;amp;gt et j'imagine &amp;amp;lt.&lt;/p&gt; &lt;p&gt;Le résultat des courses : vous saisissez une clé erronée qui sera trop longue (supérieure à la limite de 63 caractères).&lt;/p&gt; &lt;p&gt;La bonne solution est définitivement de passer par l'interface Web de votre FreeBox : &lt;a title="http://subscribe.free.fr/login/" href="http://subscribe.free.fr/login/"&gt;http://subscribe.free.fr/login/&lt;/a&gt;. Cela nécessite au préalable de se connecter par un câble Ethernet à la freebox. Tapez l'adresse, puis cliquez sur Internet et pour finir choisissez le lien "Configurer mon réseau Wifi".&lt;/p&gt; &lt;p&gt;La valeur de votre clé WAP se trouve tout en bas de votre page. Il suffit de la copier/coller dans le mot de passe demandé pour votre réseau Wifi. une fois l'opération terminée vous pouvez débrancher le câble Ethernet.&lt;/p&gt; &lt;p&gt;J'espère que ce rapide billet aura aidé d'autres freenautes. Et dire que j'ai failli accuser Windows 7 !!!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-1755841468199242565?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/1755841468199242565/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=1755841468199242565&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1755841468199242565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1755841468199242565'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/02/probleme-de-connexion-wifi-avec-une.html' title='Problème de connexion Wifi avec une FreeBox'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-255938075973994023</id><published>2010-02-16T12:00:00.001+02:00</published><updated>2010-02-16T12:00:00.055+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Windows 7 et un serveur Samba</title><content type='html'>&lt;p&gt;Comme je viens de recevoir un nouveau portable Dell XT2 sous Windows, il s’agit probablement du premier billet d’une série sur Windows 7 que je compléterai au grés de mes problèmes ou découvertes.&lt;/p&gt;  &lt;p&gt;J’ouvre la série avec un problème. Voilà qu’il m’est impossible de me connecter à un disque Samba. J’ai beau essayer différents comptes utilisateurs rien n’y fait. La même erreur revient.&lt;/p&gt;  &lt;p&gt;Une petite recherche google, nous amène directement sur des articles qui indiquent une configuration minimum de Samba 3.4 pour une connectivité avec Windows 7 :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.clubic.com/tout-savoir/windows-7/joindre-un-controleur-de-domaine-samba-avec-windows-seven-671672.html"&gt;http://www.clubic.com/tout-savoir/windows-7/joindre-un-controleur-de-domaine-samba-avec-windows-seven-671672.html&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://wiki.samba.org/index.php/Windows7"&gt;http://wiki.samba.org/index.php/Windows7&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Alors que notre vieux serveur Samba est en 3.0.&lt;/p&gt;  &lt;p&gt;Non content de cette réponse, je continue de chercher ce qui a pu être modifié entre XP et Seven. J’ai finis par comprendre que cela devait être la stratégie de sécurité. Que ce soit sous XP ou Windows 7, vous pouvez définir cette stratégie dans l’écran “Stratégie de sécurité locale” accessible depuis : Panneau de configuration –&amp;gt; Outils d'administration –&amp;gt; Stratégie de sécurité locale.&lt;/p&gt;  &lt;p&gt;Dans cet écran, il faut ensuite choisir “Stratégies locales” puis “Options de sécurité”. Une série d’options apparait.Celles qui nous intéressent sont :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Sécurité réseau : niveau d'authentification LAN Manager : Non défini &lt;/li&gt;    &lt;li&gt;Sécurité réseau : sécurité de session minimale pour les clients basés sur NTLM SSP (y compris RPC sécurisé) : Exiger un niveau de chiffrement à 128 bits. &lt;/li&gt;    &lt;li&gt;Sécurité réseau : sécurité de session minimale pour les serveurs basés sur NTLM SSP (y compris RPC sécurisé) : Exiger un niveau de chiffrement à 128 bits. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S3psnc1ItvI/AAAAAAAACeI/GKH9vRP6JQE/s1600-h/StrategieSecuriteLocal7%5B1%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="StrategieSecuriteLocal7" border="0" alt="StrategieSecuriteLocal7" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S3psn7bbrAI/AAAAAAAACeM/WySunDcJym8/StrategieSecuriteLocal7_thumb.jpg?imgmax=800" width="244" height="122" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Une comparaison avec un poste XP ainsi que la lecture de l’aide Microsoft, indique que le défaut de ces valeurs a été modifié entre XP/Vista d’un coté et Windows 7 de l’autre.&lt;/p&gt;  &lt;p&gt;Alors que “Sécurité réseau : niveau d'authentification LAN Manager” vaut “Non défini en Seven, il valait “Envoyer les réponses LM et NTLM”.&lt;/p&gt;  &lt;p&gt;De même les deux “Sécurité réseau : sécurité de session minimale pour les XXXXX basés sur NTLM SSP (y compris RPC sécurisé)” valent “Pas de minimum” sous XP et Vista alors qu’on a “Exiger un niveau de chiffrement à 128 bits” sous Windows 7.&lt;/p&gt;  &lt;p&gt;NTLM SSP (NT Lan Manager Security Support Provider) est le mécanisme utilisé par Samba pour vérifier les authentifications avec les clients Windows. Le support des différents paramètres de configuration dépend une double cohérence entre les serveurs et les clients.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;LM (Stimulation/réponse LAN Manager) est le protocole le plus ancien assurant la compatibilité avec les postes Windows 95 et 98 &lt;/li&gt;    &lt;li&gt;NTLM offre une sécurité accrue à partir de NT. &lt;/li&gt;    &lt;li&gt;NTLM version 2 offre une sécurité encore accrue mais exclue les postes sous Windows 95 et nécessite l’installation d’une extension du client Active Directory pour 98. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Dans notre cas, Samba 3.0 doit être capable de supporter NTLM version 2, je pense que mon problème était principalement du à l’encryption 128 bits.&lt;/p&gt;  &lt;p&gt;Bizarrement, si je revient en &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Sécurité réseau : niveau d'authentification LAN Manager : Envoyer LM et NTLM – utiliser la sécurité de session NTLM2 si négociée &lt;/li&gt;    &lt;li&gt;et “Exiger un niveau de chiffrement à 128 bits” pour les deux autres, &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;ma connexion reste établie même après un reboot. cela voudrait dire que l’authentification est négociée une fois pour toute.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-255938075973994023?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/255938075973994023/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=255938075973994023&amp;isPopup=true' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/255938075973994023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/255938075973994023'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/02/windows-7-et-un-serveur-samba.html' title='Windows 7 et un serveur Samba'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Y8Z3ymNuOiE/S3psn7bbrAI/AAAAAAAACeM/WySunDcJym8/s72-c/StrategieSecuriteLocal7_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-4525785725319560581</id><published>2010-01-30T20:59:00.001+02:00</published><updated>2010-01-30T21:04:34.502+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><category scheme='http://www.blogger.com/atom/ns#' term='iPad'/><category scheme='http://www.blogger.com/atom/ns#' term='Revue'/><title type='text'>iPad innovation et monde de l’entreprise</title><content type='html'>&lt;p&gt;Il y a deux jours, Apple lançait son nouveau produit et on retrouve les mêmes remarques qu’à la sortie de l’iPhone :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ce n’est pas une innovation , il n’y a rien de nouveau c’est juste du marketing… &lt;/li&gt;    &lt;li&gt;il manque le flash &lt;/li&gt;    &lt;li&gt;il n’y a pas de caméra &lt;/li&gt;    &lt;li&gt;Il n’est pas multitâche &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Il est surprenant que la mémoire des gens soit aussi courte : la sortie de l’iphone n’a que deux ans et demi et aujourd’hui plus personne ne remet en cause le coté innovateur de l’iPhone.&lt;/p&gt;  &lt;h3&gt;Un rapide retour en arrière : Invention et innovation de l’iPhone&lt;/h3&gt;  &lt;p&gt;Les deux mots recouvrent des choses différentes : &lt;/p&gt;  &lt;p&gt;L’essentiel des inventions de l’iPhone concerne le logiciel : sa nouvelle interface homme-machine même si la gestuelle utilisée n’avait rien de neuf (voir Surface de MicroSoft) son interface ne correspond à rien qui existait auparavant. Il fallait inventer une solution qui rentre sur un écran de 3,5” là où tout le monde travailler sur des écrans mur du type Minority Report&lt;/p&gt;  &lt;p&gt;Coté Hardware, l’invention principal de l’iPhone est un grand écran (3,5” à une époque où grand voulait dire 2,8”) tactile, multipoint et capacitif. L’importance de cet écran a été sous-estimé : sans sa qualité l’interface aurait été inefficace et réunir les 4 paramètres dans un même écran reste encore assez rare : le dernier produit phare de Google le Nexus One ne possède d’ailleurs pas le multipoint.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S2SBi0VeXaI/AAAAAAAACbw/xa8OCF4HO1k/s1600-h/iphone3gs_4up%5B1%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="iphone3gs_4up" border="0" alt="iphone3gs_4up" src="http://lh6.ggpht.com/_Y8Z3ymNuOiE/S2SBjS1M6fI/AAAAAAAACb0/eXfbdWj2j0k/iphone3gs_4up_thumb%5B1%5D.png?imgmax=800" width="240" height="128" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Pour moi, l’innovation dépasse la capacité technique d’un appareil : il faut aller au delà du fait qu’une personne bien formée soit capable d’utiliser une fonctionnalité, il faut la rendre accessible et utilisée par le grand public. Prenons l’exemple de l’Internet et de l’iPhone, cette fonctionnalité était déjà disponible sur d’autres téléphones bien avant l’iPhone mais cette fonctionnalité était peu utilisée : entre la sortie de l’iPhone et aujourd’hui le trafic data sur le réseau américain a cru de 7000%.&lt;/p&gt;  &lt;p&gt;L’iPhone a grâce à son interface tactile permis d’augmenter la mobilité des smartphones : avant, le smartphone était un appareil mobile mais dont l’utilisation demandé d’être arrêté : le stylet est précis mais demande du calme et de l’attention. Avec l’iPhone, on voit apparaître de plus en plus de personnes utiliser leur iPhone en se déplaçant. De plus l’iPhone est plus accessible qu’un appareil avec stylet, on l’allume puis on appuie sur l’action qu’on veut faire : on n’a pas besoin de sortir un stylet ou d’utiliser un joystick pour se déplacer. Ce point est très important pour les petites actions : s’il vous faut 4-5 s vous le faites, s’il vous faut 10 à 30s&amp;#160; vous ne faites pas l’effort.&lt;/p&gt;  &lt;p&gt;L’iPhone est une innovation car il a changé la façon dont les gens utilisent leur “smartphone” : ils l’utilisent dans le métro, en marchant, pour s’orienter, pour lire le journal…&lt;/p&gt;  &lt;h3&gt;L’iPad&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/S2SBkqZ2QZI/AAAAAAAACcA/AT1CHsttxKg/s1600-h/ipad_2up_hometimes%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="ipad_2up_hometimes" border="0" alt="ipad_2up_hometimes" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/S2SBlUAuD5I/AAAAAAAACcI/OkjeIB3Ld-k/ipad_2up_hometimes_thumb%5B2%5D.png?imgmax=800" width="640" height="439" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;Il s’agit en tout point d’un gros iPhone : forme, OS et absence du multitâche. Sur ce point, il diffère des tablet PC et des NetPc qui sont plus des petits PC portables. Ce n’est peut être pas une innovation mais c’est au moins un sacré pari.&lt;/p&gt;  &lt;p&gt;Je pense que cela inverse complètement le point de vu de l’analyse de l’intérêt de l’iPad : on ajoute à l’iPhone et non pas on retire au portable. &lt;/p&gt;  &lt;p&gt;L’iPhone est un appareil extrêmement mobile : petit, on peut l’avoir toujours sur soi, facilement accessible il est toujours disponible. Quelles sont ses limites ? L’écran et le partage :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;L’écran car pour consulter des sites internet ou lire des journaux ou des livres un écran plus grand serait certainement plus confortable.&lt;/li&gt;    &lt;li&gt;Le partage : avez vous essayer de montrer quelque chose sur votre iPhone, c’est difficile (à cause de l’écran). Il faut le passer à son interlocuteur et là, ça ne rate jamais, un doigt effleure l’écran, et ce que vous souhaitez montrer a disparu.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;De mon point de vu, l’iPad remplit parfaitement ces deux objectifs : un écran plus spacieux qui répond aux deux points, mais même cette énorme marge décriée par de nombreux commentateurs y trouve son intérêt.&lt;/p&gt;  &lt;p&gt;Certes on y perd en mobilité, il ne rentre plus dans une poche de chemise, mais on y gagne en confort d’utilisation.&lt;/p&gt;  &lt;p&gt;Des inventions ? A part un écran tactile multi-point de grande taille, il y a peut-être la nouvelle puce A4 : il faudra voir ce point et tout particulièrement son équilibre entre puissance et consommation.&lt;/p&gt;  &lt;p&gt;Une innovation ? Je pense que oui, le marché est mur pour un appareil permettant de lire son journal dans son fauteuil. Le public est habitué à la lecture de site internet. Les lecteurs sont matures : ils sont devenus sensibles à la fois au temps de démarrage d’un PC et au confort d’une lecture bien confortablement installé dans un fauteuil.&lt;/p&gt;  &lt;p&gt;Les succès du Kindle d’Amazon et des NetPC sont deux bons indicateurs de l’existence d’un besoin :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;la lecture sur un livre électronique pour le kindle&lt;/li&gt;    &lt;li&gt;le PC est bien trop complet pour un grand nombre d’utilisateurs : l’utilisateur du NetPC se limite à la consultation d’internet et à la rédaction d’emails, de blogs ou de sites. Peut-être regarde-t-il ses photos et quelques video dessus mais on ne va pas beaucoup plus loin.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;A priori, l’iPad répond parfaitement à ces deux tranches d’utilisateur pour un prix sensiblement identique et il offre toute une nouvelle gamme d’applications ludiques que l’on a déjà sur l’iPhone.&lt;/p&gt;  &lt;p&gt;Beaucoup de commentateurs considèrent que le kindle 2 DX à 480$ est mort. Et les personnes qui attendaient de voir l’iPad avant d’opter pour le kindle 2, semblent décider majoritairement d’attendre la sortie de l’iPad. &lt;/p&gt;  &lt;p&gt;L’iPad devrait être capable de capter tout ce segment d’utilisateurs qui n’ont pas réellement besoin de toute la puissance d’un PC et de les amener vers un nouveau type d’utilisation et d’application comme a su si bien le faire l’iPhone. S’il réussit, on dira dans un ou deux ans que l’iPad aura été une nouvelle innovation d’Apple.&lt;/p&gt;  &lt;h4&gt;Facteur de succès pour l’iPad&lt;/h4&gt;  &lt;p&gt;Contrairement à la majorité des commentateurs, je ne pense pas que le support du Flash ou le multi-tâche seront des éléments importants pour l’iPad.&lt;/p&gt;  &lt;p&gt;La première inconnue et probablement la plus importante est pour moi l’accueil qui sera fait à son clavier tactile : on l’a vu plus haut, je considère qu’un des segments d’utilisateurs les plus important de l’iPad est la clientèle actuelle des NetPC dont une de leur activité principale est la saisie de documents. Ces utilisateurs seront de gros consommateur du clavier tactile et leur retour d’expérience sera très important dans le succès ou non de l’iPad.&lt;/p&gt;  &lt;p&gt;La seconde inconnue majeure est pour moi l’autonomie de l’iPad : non pas l’autonomie de sa batterie mais le besoin ou non d’utiliser un Mac ou PC. Pourra-t-on posséder un iPad sans posséder un Mac ou PC ? Je pense que certains utilisateurs de NetPC ne possèdent pas d’autre ordinateur. J’ai du mal pour le moment à déterminer si l’iPad nécessite un autre ordinateur. Je ne vois qu’éventuellement l’activation de l’iPad qui nécessiteraient impérativement un PC. Mais sans PC, remplir l’iPad de musique ou de Photo risque d’être compliqué. Il ne semble pas non plus prévu de synchroniser un iPhone à partir d’un iPad. De manière générale, l’absence de port USB semble réduire grandement les possibilités d’indépendance de l’iPad.&lt;/p&gt;  &lt;p&gt;Coté photo, Apple annonce déjà deux connecteurs pour l’iPad : un lecteur de carte SD pour récupérer les photos et un connecteur de type USB pour l’import des photo et video directement à partir de l’appareil. On a vu précédemment que je considérai la photo comme une des activités majeures que devraient être capable de traiter l’iPad afin de capter la clientèle des NetPC, on constate qu’Apple a pris les devant. Pour le reste, l’excellent iPhoto permettra de jouer avec ses photo dans l’iPad.&lt;/p&gt;  &lt;p&gt;Toujours dans l’image, l’absence d’une camera video pour chatter risque de décevoir quelques utilisateurs potentiels : mais l’eco système Apple ne manquera pas de palier à cet absence qui pourra être corrigé par Apple dans une seconde version.&lt;/p&gt;  &lt;p&gt;Personnellement le Flash ne m’a jamais manqué sur l’iPhone et je pense que le multi-tâche n’est pas nécessaire pour établir l’appareil sur le marché. Peut-être que ce dernier deviendra disponible dans les versions futures mais je ne pense pas qu’il manquera aux utilisateurs que l’iPad vise.&lt;/p&gt;  &lt;h3&gt;l’IPad en entreprise&lt;/h3&gt;  &lt;p&gt;L’iPhone n’a pas encore supplanté le BlackBerry dans l’entreprise, mais il a fait une percée du coté de nombreux administrateurs Systèmes et on commence à voir (même en France) les premières entreprises qui l’adopte.&lt;/p&gt;  &lt;p&gt;L’iPad bénéficiera dès sa sortie d’une connectivité avec MS Exchange contrairement à l’iPhone ainsi qu’une suite d’applications iPhone dédiées à l’entreprise comme SalesForce par exemple.&lt;/p&gt;  &lt;p&gt;Pourtant, l’iPad est un appareil dont la totalité de la présentation a concerné exclusivement les loisirs. Est-ce pour autant que l’iPad n’a pas de rôle à jouer dans l’entreprise ?&lt;/p&gt;  &lt;p&gt;Personnellement, je pense que la population des commerciaux itinérants est une cible de choix pour l’iPad : il s’agit d’une solution légère susceptible de supporter les modes connectés et déconnectés permettant une synchronisation a posteriori. L’écran est suffisamment grand pour permettre la saisie d’un contrat ou montrer quelque chose à un client.&lt;/p&gt;  &lt;p&gt;En usine ou atelier, il peut être utilisé pour suivre des travaux, commander des pièces ou consulter une documentation. Il faudra pour cela, que l’iPad montre de la robustesse aux éléments de ces environnements agressifs.&lt;/p&gt;  &lt;p&gt;L’iPad avec 10h d’autonomie (si elle est réelle) permettra aux personnels médicales de faire une tournée complète. Ils pourront consulter et compléter un dossier simplement : l’interface tactile qui permet d’éviter l’utilisation d’un stylet pourrait être un plus. L’iPhone possède déjà un certain nombre d’applications professionnelles dédiées aux secteurs de la santé.&lt;/p&gt;  &lt;p&gt;On le voit, l’iPad pourrait être un superbe appareil pour un certain nombre d’utilisations professionnelles. Cela peut être d’autant plus intéressant qu’il devrait profiter des solutions d’administration qui ont été mise au point pour l’iPhone. Pour finir, le coté ludique de l’appareil pourrait éviter la traditionnelle résistance au changement.&lt;/p&gt;  &lt;p&gt;Dans ces différents cas, on constatera que la force de l’iPad reposera sur &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;une capacité à être disponible immédiatement : absence de temps de démarrage.&lt;/li&gt;    &lt;li&gt;une grande autonomie, supérieure à la journée de travail&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;En bref, je pense que l’iPad a un fabuleux potentiel dans différents cadres d’utilisations : loisirs personnels ou professionnels itinérants.&lt;/p&gt;  &lt;p&gt;Il deviendra une innovation majeure s’il réussit à agréger les différentes communautés disparates : lecteur d’ebook, utilisateur de NetPC… et à créer de nouvelles applications comme par exemple cet exemple de la Major BaseBall League : une application iPad entre le site internet et la télé qui permet de regarder un match tout en consultant les statistiques d’un joueur ou d’une équipe.&lt;/p&gt;  &lt;p&gt;Une innovation ne se décrète pas : ceux sont les utilisateurs par leur adoption d’une solution qui font d’un nouveau produit une innovation. C’est eux qui décideront si l’iPad en est une. Je pense que l’appareil possède de nombreux atouts pour réussir, mais seul le marché sera le juge.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-4525785725319560581?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/4525785725319560581/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=4525785725319560581&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4525785725319560581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/4525785725319560581'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/01/ipad-innovation-et-monde-de-lentreprise.html' title='iPad innovation et monde de l’entreprise'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Y8Z3ymNuOiE/S2SBjS1M6fI/AAAAAAAACb0/eXfbdWj2j0k/s72-c/iphone3gs_4up_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-7750992242858185437</id><published>2010-01-13T18:10:00.001+02:00</published><updated>2010-01-13T18:34:18.442+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NatStar'/><title type='text'>Récupérer un SID ou un login Windows depuis NatStar</title><content type='html'>&lt;p&gt;J’ai du récemment pour un projet ajouter une authentification intégrée à une application NatStar : l’objectif étant d’éviter à l’utilisateur de saisir un mot de passe si l’utilisateur Windows connecté est autorisé à utiliser l’application.&lt;/p&gt;  &lt;p&gt;L’utilisateur “Windows” peut recouvrir des informations techniques différentes, dans ce billet j’en traiterai deux :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;le login Windows : le nom du compte Windows utilisé pour se connecter &lt;/li&gt;    &lt;li&gt;le SID de l’utilisateur : il s’agit d’une notion MicroSoft qui permet l’identification unique d’un utilisateur (Security ID) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;La récupération de ces informations et leur utilisation depuis NatStar n’étant pas très simple, je vous propose dans ce billet une description détaillée du mécanisme.&lt;/p&gt;  &lt;p&gt;L’exercice est fait dans le cadre de NatStar, il ne doit pas être très compliqué de l’adapter au cas NS-DK.&lt;/p&gt;  &lt;h2&gt;Les fonctions MicroSoft&lt;/h2&gt;  &lt;p&gt;Nous allons utiliser 5 fonctions MicroSoft depuis NatStar :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;advapi32.GetUserNameA : Cette fonction est le point de départ du mécanisme, elle retourne le login de l’utilisateur connecté. &lt;/li&gt;    &lt;li&gt;advapi32.LookupAccountNameA : cette fonction permet à partir du login récupéré grâce à la fonction précédente de récupérer un pointeur sur la structure SID. &lt;/li&gt;    &lt;li&gt;Advapi32.ConvertSidToStringSidA : cette fonction permet d’obtenir à partir du SID récupéré par la fonction précédente une chaine de caractère correspondant au SID. &lt;/li&gt;    &lt;li&gt;KERNEL32.GetLastError : cette fonction permet de récupérer le dernier message d’erreur levé par Windows. Les 3 fonctions précédentes positionnent en cas de problème cette erreur. &lt;/li&gt;    &lt;li&gt;KERNEL32.LocalFree : cette fonction permet de libérer certaines ressources allouées par Windows. Elle permettra de libérer l’information renvoyée par ConvertSidToStringSidA. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Les 3 premières fonctions retournent 0 en cas d’erreur et une valeur différente de 0 si tout se passe bien.&lt;/p&gt;  &lt;h3&gt;LookupAccountNameA &lt;/h3&gt;  &lt;p&gt;Cette fonction a un mode opératoire peu commun : il faut l’appeler deux fois :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;une première fois avec une taille à 0 et un pointeur SID à 0 : la fonction retourne alors la taille du SID. Il faut allouer alors l’espace nécessaire pour le SID. &lt;/li&gt;    &lt;li&gt;le second appel prend l’adresse de l’espace alloué et la taille du buffer pour le remplir. On dispose alors d’un SID. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Pour corser le tout, dans le premier cas, il ne faut pas tenir compte de la valeur retournée : il y a une erreur si la taille est nulle.&lt;/p&gt;  &lt;h2&gt;Mapping des fonctions MicroSoft dans NatStar&lt;/h2&gt;  &lt;p&gt;Pour pouvoir utiliser les fonctions précédemment définies depuis NatStar nous avons du définir des fonctions Externes. Pour ce faire, nous avons créé une librairie de service dans laquelle nous avons ajouter 5 fonctions.&lt;/p&gt;  &lt;p&gt;Pour ces 5 fonctions, le radio bouton External de la définition devra être coché.&lt;/p&gt;  &lt;h3&gt;MSGETLASTERROR% pour GetLastError &lt;/h3&gt;  &lt;p&gt;Nous commençons par la plus simple. Nous éditons la définition de la fonction. Dans la dialogue “Modify Definition for Function or Instruction MSGETLASTERROR%” on précise :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Result Type : INT (4) &lt;/li&gt;    &lt;li&gt;External : KERNEL32.GetLastError &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette fonction ne prenant pas paramètre, il n’y a rien d’autre à faire.&lt;/p&gt;  &lt;h3&gt;MSLOCALFREE pour LocalFree&lt;/h3&gt;  &lt;p&gt;Nous continuons par un peu plus compliqué. Nous éditons la définition de la fonction. Dans la dialogue “Modify Definition for Function or Instruction MSLOCALFREE” on précise :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Result Type : POINTER &lt;/li&gt;    &lt;li&gt;External : KERNEL32.LocalFree &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette fonction possède un paramètre, on ajoute donc dans l’onglet Parameters le paramètre suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : HMEM &lt;/li&gt;    &lt;li&gt;On coche : In &lt;/li&gt;    &lt;li&gt;Type : POINTER &lt;/li&gt;    &lt;li&gt;Size : vide &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pensez à appuyer sur Append puis Ok afin de ne pas perdre vos modifications.&lt;/p&gt;  &lt;h3&gt;MSGETUSERNAME% pour GetUserNameA&lt;/h3&gt;  &lt;p&gt;Nous continuons par un peu plus compliqué. Nous éditons la définition de la fonction. Dans la dialogue “Modify Definition for Function or Instruction MSGETUSERNAME%” on précise :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Result Type : INT (4) &lt;/li&gt;    &lt;li&gt;External : advapi32.GetUserNameA &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette fonction possède 2 paramètres, on ajoute donc dans l’onglet Parameters les paramètres suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : LPBUFFER$ &lt;/li&gt;    &lt;li&gt;On coche : Out &lt;/li&gt;    &lt;li&gt;Type : CSTRING &lt;/li&gt;    &lt;li&gt;Size : 255 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pensez à appuyer sur Append puis Ok afin de ne pas perdre vos modifications, puis ajoutez le second :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : NSIZE% &lt;/li&gt;    &lt;li&gt;On coche : In et Out &lt;/li&gt;    &lt;li&gt;Type : INT &lt;/li&gt;    &lt;li&gt;Size : 4 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;C’est le premier paramètre LPBuffer$ qui contiendra le nom du compte Windows de l’utilisateur.&lt;/p&gt;  &lt;h3&gt;MSGETUSERSID% pour LookupAccountNameA&lt;/h3&gt;  &lt;p&gt;Nous continuons par un peu plus compliqué. Nous éditons la définition de la fonction. Dans la dialogue “Modify Definition for Function or Instruction MSGETUSERSID%” on précise :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Result Type : INT (4) &lt;/li&gt;    &lt;li&gt;External : advapi32.LookupAccountNameA &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette fonction possède 7 paramètres, on ajoute donc dans l’onglet Parameters les paramètres suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : LPSYSTEMNAME &lt;/li&gt;    &lt;li&gt;On coche : In &lt;/li&gt;    &lt;li&gt;Type : CSTRING &lt;/li&gt;    &lt;li&gt;Size : 255 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pensez à appuyer sur Append puis Ok afin de ne pas perdre vos modifications, puis ajoutez le second :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : LPACCOUNTNAME &lt;/li&gt;    &lt;li&gt;On coche : In &lt;/li&gt;    &lt;li&gt;Type : CSTRING &lt;/li&gt;    &lt;li&gt;Size : 255 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Passons au troisième :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : SID &lt;/li&gt;    &lt;li&gt;On coche : In &lt;/li&gt;    &lt;li&gt;Type : POINTER &lt;/li&gt;    &lt;li&gt;Size : vide &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Passons au quatrième :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : CBSID &lt;/li&gt;    &lt;li&gt;On coche : In et Out &lt;/li&gt;    &lt;li&gt;Type : INT &lt;/li&gt;    &lt;li&gt;Size : 4 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Passons au cinquième :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : REFERENCEDDOMAINNAME &lt;/li&gt;    &lt;li&gt;On coche : Out &lt;/li&gt;    &lt;li&gt;Type : CSTRING &lt;/li&gt;    &lt;li&gt;Size : 255 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Passons au sixième :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : CCHREFERENCEDDOMAINNAME &lt;/li&gt;    &lt;li&gt;On coche : In et Out &lt;/li&gt;    &lt;li&gt;Type : INT &lt;/li&gt;    &lt;li&gt;Size : 4 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Passons au septième :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : PEUSE &lt;/li&gt;    &lt;li&gt;On coche : Out &lt;/li&gt;    &lt;li&gt;Type : INT &lt;/li&gt;    &lt;li&gt;Size : 4 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;C’est le 3ieme paramètre SID qui correspond au pointeur SID de Windows. C’est cette valeur qui sera utilisée avec MSCONVERTSIDTOSTRINGSID% pour récupérer la chaine de caractères correspondante.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;MSCONVERTSIDTOSTRINGSID% pour ConvertSidToStringSidA&lt;/h3&gt;  &lt;p&gt;Nous finissons par la plus compliquée. Avant d’éditer la définition de cette fonction,nous allons créer un nouveau segment PSTRSID qui sera utilisé pour récupérer la valeur qui contient la chaine de caractère.&lt;/p&gt;  &lt;p&gt;Il faut savoir que la fonction MicroSoft, déclare ce paramètre en C++ comme :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;BOOL ConvertSidToStringSid(&amp;#160; &lt;/p&gt;    &lt;p&gt;__in PSID &lt;em&gt;Sid&lt;/em&gt;,&amp;#160; &lt;/p&gt;    &lt;p&gt;__out LPTSTR *&lt;em&gt;StringSid&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;&lt;/em&gt;);&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Le StringSid est donc un pointeur sur un pointeur d’une chaine. Pour faire la même chose, nous avons besoin d’un segment intermédiaire.&lt;/p&gt;  &lt;p&gt;Ce segment est très simple, il ne possède qu’un seul Field :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : STRINGSID$ &lt;/li&gt;    &lt;li&gt;Type : CSTRING &lt;/li&gt;    &lt;li&gt;Size : 255 &lt;/li&gt;    &lt;li&gt;On coche la case Reference (attention ce point est très important) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Nous pouvons maintenant éditer la définition de la fonction. Dans la dialogue “Modify Definition for Function or Instruction MSCONVERTSIDTOSTRINGSID%” on précise :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Result Type : INT (4) &lt;/li&gt;    &lt;li&gt;External : advapi32.ConvertSidToStringSidA &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cette fonction possède 2 paramètres, on ajoute donc dans l’onglet Parameters les paramètres suivant :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : SID &lt;/li&gt;    &lt;li&gt;On coche : In &lt;/li&gt;    &lt;li&gt;Type : POINTER &lt;/li&gt;    &lt;li&gt;Size : vide &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pensez à appuyer sur Append puis Ok afin de ne pas perdre vos modifications, puis ajoutez le second :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Name : STRINGSID &lt;/li&gt;    &lt;li&gt;On coche : Out &lt;/li&gt;    &lt;li&gt;Type : PSTRSID (c’est le segment créé précédemment il apparait dans la partie qui est en ordre alphabétique) &lt;/li&gt;    &lt;li&gt;Size : vide &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;C’est le 1er paramètre SID qui correspond au pointeur SID de Windows récupéré dans la fonction précédente. &lt;/p&gt;  &lt;p&gt;Le second paramètre permettra de récupérer la chaine de caractère grâce à : L_SID_USER_WINDOWS.STRINGSID$ si L_SID_USER_WINDOWS est la valeur récupérée comme second paramètre.&lt;/p&gt;  &lt;h2&gt;Utilisation des fonctions&lt;/h2&gt;  &lt;p&gt;Nous avons définis les fonctions externes qui permettent l’appel des services MicroSoft, nous allons maintenant utiliser ces services.&lt;/p&gt;  &lt;h3&gt;Récupération du login Windows&lt;/h3&gt;  &lt;p&gt;Cette première étape est simple :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;On initialise les variables &lt;/li&gt;    &lt;li&gt;On appelle la fonction MSGETUSERNAME% &lt;/li&gt;    &lt;li&gt;On vérifie qu’il n’y a pas eu d’erreur &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Ce qui donne en NCL :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;LOCAL CSTRING Buffer$      &lt;br /&gt;LOCAL int SizeBuffer%       &lt;br /&gt;LOCAL int Retour% &lt;/p&gt;    &lt;p&gt;Local Cstring USER_WINDOWS$(255)&lt;/p&gt;    &lt;p&gt;USER_WINDOWS$ = ''      &lt;br /&gt;L_LPBUFFER$ = ''       &lt;br /&gt;SizeBuffer% = 255 ; taille du buffer       &lt;br /&gt;Retour% = 0 &lt;/p&gt;    &lt;p&gt;Retour% = MSGETUSERNAME%(Buffer$, SizeBuffer%)      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;; Si le retour est différent de 0 alors tout est OK      &lt;br /&gt;If Retour% &amp;lt;&amp;gt; 0       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; USER_WINDOWS$ = skip L_LPBUFFER$&lt;/p&gt;    &lt;p&gt;Endif&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;La valeur récupérée dans la variable USER_WINDOWS$ est le login Windows de l’utilisateur. Il peut être utilisé pour vérifier en base de données si cet utilisateur a le droit de se connecter à votre application.&lt;/p&gt;  &lt;h3&gt;Récupération du SID Windows&lt;/h3&gt;  &lt;p&gt;Le login Windows est simple à récupérer, il possède une signification fonctionnelle pour les utilisateurs mais il est moins permanent que le SID : si l’utilisateur change de login suite à un mariage par exemple, le compte Windows est modifié mais pas son SID. Son inconvénient est que le SID est un numéro incompréhensible sans aucun sens fonctionnel.&lt;/p&gt;  &lt;p&gt;Il peut être également intéressant de récupérer le SID pour interroger d’autres services de sécurité, mais nous n’aborderons pas ce point.&lt;/p&gt;  &lt;p&gt;Pour utiliser le SID, il faut d’abord récupérer le USER_WINDOWS$. On ajoute ensuite le code suivant :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;Retour% = 0      &lt;br /&gt;L_LPSYSTEMNAME$ = ''       &lt;br /&gt;SizeBuffer% = 0 ; taille du buffer       &lt;br /&gt;L_LPSYSTEMNAME$ = ''       &lt;br /&gt;L_CCHREFERENCEDDOMAINNAME% = 255 ; taille du buffer &lt;/p&gt;    &lt;p&gt;; Le premier appel de la fonction avec un 3eme paramètre à 0, renvoie la taille de la structure PSID (SizeBuffer%)      &lt;br /&gt;Retour% = MSGETUSERSID%(L_LPSYSTEMNAME$, USER_WINDOWS$, 0, SizeBuffer%, L_REFERENCEDDOMAINNAME$, L_CCHREFERENCEDDOMAINNAME%, L_PSID_NAME_USE%)       &lt;br /&gt;things_trace &amp;quot;1ere appel SizeBuffer%= &amp;quot; &amp;amp; SizeBuffer% &lt;/p&gt;    &lt;p&gt;If (SizeBuffer%&amp;lt;=0)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; things_trace &amp;quot;ERREUR lors du 1er MSGETUSERSID% GetLastError%=&amp;quot;&amp;amp;&amp;#160; String(MsGetLastError%, 16)       &lt;br /&gt;Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; New&amp;#160; SizeBuffer%,&amp;#160; L_PSID       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ; Récupère le pointer de la structure SID du USER Windows       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Retour% = MSGETUSERSID%(L_LPSYSTEMNAME$, USER_WINDOWS$, L_PSID, SizeBuffer%, L_REFERENCEDDOMAINNAME$, L_CCHREFERENCEDDOMAINNAME%, L_PSID_NAME_USE%) &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; if (Retour%=0)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; things_trace &amp;quot;ERREUR lors du 2nd MSGETUSERSID% GetLastError%=&amp;quot;&amp;amp;&amp;#160; String(MsGetLastError%, 16)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ; Convertie le pointer de la structure SID du USER Windows en chaîne       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Retour% = MSCONVERTSIDTOSTRINGSID%(L_PSID, L_SID_USER_WINDOWS)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (Retour%=0)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; things_trace &amp;quot;ERREUR lors du MSCONVERTSIDTOSTRINGSID% GetLastError%=&amp;quot;&amp;amp;&amp;#160; String(MsGetLastError%, 16)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; SID_USER_WINDOWS$ = L_SID_USER_WINDOWS.STRINGSID$       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; things_trace &amp;quot;SID_USER_WINDOWS$=&amp;quot; &amp;amp; SID_USER_WINDOWS$ &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ; Il faut liberer la chaine récupérée      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; P = MSLocalFree(@L_SID_USER_WINDOWS.STRINGSID$)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; things_trace &amp;quot;Resultat LocalFree=&amp;quot;&amp;amp; P &amp;amp;&amp;amp; String(MsGetLastError%, 16)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Endif &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Endif      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; dispose L_PSID       &lt;br /&gt;Endif&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Pour qu’il fonctionne, il faut ajouter au début les déclarations suivantes :&lt;/p&gt;  &lt;div class="code"&gt;   &lt;p&gt;LOCAL pointer L_PSID, pointer P      &lt;br /&gt;Local int L_PSID_NAME_USE%       &lt;br /&gt;Local int L_CCHREFERENCEDDOMAINNAME%       &lt;br /&gt;Local CSTRING L_LPSYSTEMNAME$       &lt;br /&gt;Local CSTRING L_REFERENCEDDOMAINNAME$       &lt;br /&gt;Local PSTRSID L_SID_USER_WINDOWS&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;La valeur récupérée dans SID_USER_WINDOWS$&amp;#160; est la chaine de caractères correspondant à l’identifiant du SID.&lt;/p&gt;  &lt;p&gt;On notera l’utilisation de la syntaxe : String(MsGetLastError%, 16). Le GetLastError renvoie un code d’erreur. Ce code d’erreur est un numérique mais apparait généralement dans la documentation sous forme hexadécimal. cette syntaxe permet de tracer directement le code hexadécimal.&lt;/p&gt;  &lt;h2&gt;Paramètre de compilation&lt;/h2&gt;  &lt;p&gt;La compilation du code ci-dessus demande d’être capable de se linker avec la librairie advapi32.dll. Cette DLL système est disponible sur tous les postes et ne nécessite aucun déploiement supplémentaire.&lt;/p&gt;  &lt;p&gt;La compilation nécessite d’avoir accès à son LIB. Pour que cela soit possible, il faut modifier la variable d’environnement LIB et ajouter les deux répertoires suivants (dans le cas de MSVC 8) :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib&lt;/li&gt;    &lt;li&gt;C:\Program Files\Microsoft Visual Studio 8\VC&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Si vous utilisez NatStar directement (sans NsaConfig) cela suffit.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Dans le cadre d’une utilisation de NsaConfig où le lancement et l’environnement de travail de NatStar dépend de la configuration de NsaConfig, il est nécessaire de modifier le fichier C:\NSAC\INI\wspmgr.ini en :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;ajoutant dans la déclaration EnvVar les deux variables suivantes MsSdklib et COMPPATH (c’est indispensable pour que les définitions qui suivent soient prises en compte.&lt;/li&gt;    &lt;li&gt;puis en ajoutant les deux lignes de définition suivantes dans la partie qui suit la déclaration de EnvVar&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;MsSdklib=C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib&lt;/li&gt;      &lt;li&gt;COMPPATH=C:\Program Files\Microsoft Visual Studio 8\VC&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;puis en modifiant la déclaration de LIB qui devient : &lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;LIB=%NS-GLOB%\CLASSES\LIB;%NS-GLOB%\SERVICES\LIB;%COMPPATH%\LIB;%MsSdklib%;%NATSTARPATH%\LIB;%LIB%&lt;/li&gt;   &lt;/ul&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;J’espère que ce billet vous aura été utile. Il montre qu’il est possible de mettre en œuvre une authentification intégrée dans une application NatStar ou NS-DK même si cela n’a rien d’évident. On notera au passage que la complexité provient principalement des API MicroSoft mise à disposition (Je sais, je suis directeur technique de Nat System et donc probablement un peu partial).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-7750992242858185437?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/7750992242858185437/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=7750992242858185437&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7750992242858185437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7750992242858185437'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2010/01/recuperer-un-sid-ou-un-login-windows.html' title='Récupérer un SID ou un login Windows depuis NatStar'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-1596264189031827311</id><published>2009-09-22T23:21:00.001+02:00</published><updated>2009-10-01T09:00:48.445+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='HsqDb'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>Type de données JPA et Hibernate</title><content type='html'>&lt;p&gt;L'efficacité du développement d'une application de gestion et l'efficacité de cette même application (les temps de réponse) repose grandement sur la construction d'un modèle de données "efficace".&lt;br&gt;Dans ce billet nous allons nous concentrer sur un choix "efficace" des types simples pour une application Java reposant sur JPA et Hibernate.&lt;/p&gt; &lt;p&gt;Cette article complète une série d'autres billets sur JPA de ce même Blog :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2007/08/choisir-ejb-entite-3-jpa.html"&gt;Faut-il utiliser les EJB 3.0 et la Java Persistence API&lt;/a&gt; : Il s'agit d'une réflexion sur l'opportunité d'utiliser les EJB 3.0 et JPA  &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2007/08/tutorial-mapping-annotation-ejb-entity.html"&gt;Tutorial sur le mapping par annotation JPA&lt;/a&gt; : un tutorial d'introduction sur les annotations JPA  &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2007/08/tutorial-ajax-jpa-echo2.html"&gt;Réalisation d'une application Web Ajax et JPA&lt;/a&gt; : un tutorial qui met en oeuvre JPA dans une application Web Ajax&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;br&gt;Si le mot "efficace" a été mis à plusieurs reprises entre guillemets, c'est que ce mot peut prendre des aspects contradictoires suivant le point de vu :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;l'efficacité d'un modèle de données pour le DBA (Database Administrateur) va reposer sur l'espace de stockage et la rapidité d'exécution des requêtes,  &lt;li&gt;pour un développeur cela reposera en grande partie sur la facilité qu'il a à écrire les requêtes qui correspondent au besoin fonctionnel  &lt;li&gt;pour l'utilisateur ce sera les temps de réponses de l'application&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Mon soucis dans ce billet, est de proposer un certain équilibre, une sorte de compromis entre ces différentes aspirations sans perdre de vu, le besoin pragmatique auquel nous devons tous faire face, développer une application au meilleur prix pour un client exigeant.&lt;br&gt;Dans un premier temps, nous énoncerons un certain nombre de règles simples permettant de choisir rapidement les types de données de ses propriétés. Dans un second temps nous expliquerons avec différents exemples les raisons de ces choix. Cette seconde partie devrait permettre une meilleure compréhension du comportement d'Hibernate et des limites de la portabilité des différentes solutions.&lt;/p&gt; &lt;h2&gt;Contraintes pour l'efficacité d'un modèle de données&lt;/h2&gt; &lt;p&gt;Nous nous concentrons dans ce billet aux seuls aspects du typage des propriétés et colonnes simples.  &lt;p&gt;Pour pouvoir choisir efficacement un type de données il faut :  &lt;ul&gt; &lt;li&gt;comprendre les nuances entre les différents types  &lt;li&gt;être capable pour une donnée du monde réel (la valeur que l'on veut stocker) de distinguer les différentes nuances associées aux différents types&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;br&gt;Par exemple, un double et un BigDecimal représentent tout les deux un nombre décimal. Alors que le double ne connaît pas de limite à sa précision : la même variable peut contenir un nombre précis à 2 ou 10 chiffres après la virgule, ce n'est pas le cas d'un BigDecimal, cet objet possède un attribut précision qui indique le nombre de chiffres après la virgule. Pour changer sa précision il faut faire appel à une méthode. &lt;/p&gt; &lt;p&gt;Pour un float, 1,23 et 1,230 sont identiques, ce n'est pas le cas pour un BigDecimal car l'attribut précision n'est pas le même.&lt;/p&gt; &lt;p&gt;De même, si l'on sait aujourd'hui, qu'une valeur en euro sera inférieure disons à 1 000 000 €, on ne peut que difficilement savoir la limite qu'il faudra prendre en compte dans une dizaine d'années surtout s'il faut prendre en compte un changement de monnaie.&lt;/p&gt; &lt;p&gt;En conséquence, vouloir pour chaque montant définir des limites différentes en fonction de l'information n'est pas nécessairement pertinent : cela augmente la difficulté du choix et on n'a pas toujours la possibilité de prévoir les évolutions (on augmente le risque d'erreur en voulant être précis).&lt;/p&gt; &lt;p&gt;Pour que ces choix restent pertinents et efficaces sur la durée de vie de l'application (souvent plusieurs années), il faut que les différents développeurs manipulant ces données sachent les manipuler efficacement. On a donc bien souvent intérêt à :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;se limiter à un ensemble de types restreint : une trop grande précision peu provoquer dans certain cas des effets de bords néfastes par exemple dans la taille des Strings : à la fin, on ne sait jamais quelle est la taille d'un champ et du coup la probabilité d'un développeur pressé de se tromper dans le contrôle est plus grande.  &lt;li&gt;utiliser des types bien connus et maîtrisés par l'ensemble de l'équipe : si un type est mal maîtrisé, son utilisation peut être catastrophique car un des premiers réflexes est bien souvent de revenir à un type connu, ce qui a le double effet de rajouter une surcharge de travail ainsi que des risques d'apparition d'effets de bord lors des conversions. Les effets de bords sont bien évidemment ceux là même qu'on souhaitait éviter avec le choix de ce type.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;br&gt;Mon expérience acquise à travers l'audit de projets montre que bien souvent le mieux est l'ennemi du bien. Une optimisation trop poussée qui force à sortir des sentiers balisés a souvent des effets bien plus pervers pour un projet qu'une optimisation plus raisonnable.&lt;/p&gt; &lt;p&gt;Pour finir, le typage d'une "information" n'est pas intrinsèque à son contenu. Son utilisation a également son importance. Prenant pas exemple un numéro composé exclusivement de chiffres, cela ne veut pas dire qu'il devra être stocké sous forme d'un entier en base. Dans de nombreux cas, il est préférable de le stocker sous forme d'une chaîne de caractères. Cela va dépendre des contrôles que l'on souhaite faire, des recherches que l'on souhaite réaliser...&lt;/p&gt; &lt;p&gt;D'autre part, si une information doit être stockée en base, elle doit également être manipulée en Java et affichée dans un écran. Pour un développement efficace, il faut que le passage d'une représentation à l'autre et les contrôles soient rapides et efficaces. Hibernate et JPA facilitent ce travail, encore ne faut-il pas lui mettre trop de bâtons dans les roues en le forçant à utiliser des types incompatibles.&lt;/p&gt; &lt;p&gt;Les règles retenues sont :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;limitation du nombre de types  &lt;li&gt;des types connus  &lt;li&gt;une certaine portabilité à travers les bases de données  &lt;li&gt;un typage cohérent de la base à l'affichage en passant par la représentation mémoire en Java&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;Typage des données&lt;/h2&gt;Nous avons cinq grands types de données que nous subdivisons en des types plus proches des utilisations :  &lt;ul&gt; &lt;li&gt;Les types numériques  &lt;ul&gt; &lt;li&gt;Les montants monétaires : il s'agit des valeurs dans une monnaies comme les prix, soldes, montant, commissions...  &lt;li&gt;Les mesures : il s'agit d'une valeur décimale qui correspond à la mesure d'un objet qu'il s'agissent d'une distance, d'un poids...  &lt;li&gt;Les taux et pourcentages : il s'agit de valeurs décimales faibles (inférieur à 100) et nécessitant parfois une précision un peu plus grande (certains taux possèdent 4 chiffres après la virgule)  &lt;li&gt;Les quantités : il s'agit de valeurs entières permettant de donner un nombre d'unités d'un produit.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les valeurs alphanumériques  &lt;ul&gt; &lt;li&gt;Les chaînes de caractères : les chaînes de caractères classiques qui stockent une information en claire (non codée)  &lt;li&gt;Les codes : il s'agit d'une information courte (moins d'une dizaine de caractères) qui est codé.  &lt;li&gt;Les commentaires : il s'agit d'un texte composé de plusieurs mots.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les valeurs énumérées  &lt;ul&gt; &lt;li&gt;Les valeurs Vrai-Fausse : cela correspond aux cases à cocher  &lt;li&gt;Les listes déroulantes et énumérations : il s'agit d'information dont la sélection se fait dans une liste déroulante. on stocke en base un code et on affiche un libellé grâce à une table de paramètre qui assure la correspondance. &lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les dates et timestamp  &lt;ul&gt; &lt;li&gt;Les dates traditionnelles précises au jour près  &lt;li&gt;les heures : une heure dans la journée indépendante de la date  &lt;li&gt;les tags horaires (TimeStamp) qui permettent de conserver la trace de l'heure précise d'un événement. Ceux sont des dates précises à la milliseconde&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les identifiants  &lt;ul&gt; &lt;li&gt;les numéro de dossier  &lt;li&gt;les séquences&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Type Montant Monétaire&lt;/h3&gt; &lt;p&gt;Les montants monétaires ont une particularité : le nombre de chiffres après la virgule est une constante (souvent 2). Les problèmes d'arrondis doivent toujours être résolu avec cette contrainte : il n'est pas possible d'augmenter temporairement le nombre de chiffres après la virgule.&lt;/p&gt; &lt;p&gt;D'autre part, le BigDecimal est d'une précision absolue dans les comparaisons de nombre décimaux ce qui est impératif pour les montants monétaires.&lt;/p&gt; &lt;p&gt;Pour plus de détail sur l'intérêt de l'utilisation des BigDecimal vous pouvez lire mon billet : &lt;a href="http://jl2tho.blogspot.com/2009/07/tutorial-sur-les-montants-et-l-des.html"&gt;Tutorial sur les BigDecimal&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Le stockage par hibernate d'un BigDecimal est un Number de 19 chiffres avec 2 chiffres après la virgule. Nous utiliserons ce format pour tous les montants. &lt;/p&gt; &lt;p&gt;Le nombre de chiffres (19) peut paraître excessif si on compte en Euro, mais en Yen cela se réduit et encore plus pour d'autres monnaies.&lt;/p&gt; &lt;p&gt;Il me parait donc plus sage de rester sur la taille par défaut. &lt;/p&gt; &lt;p&gt;Exemple de définition d'un montant :&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_AMOUNT", precision=19, scale=2)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private BigDecimal amountDefault;  &lt;p&gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&lt;br&gt;Le BigDecimal étant un objet, il peut être Null comme les colonnes correspondantes en base. Il n'aura donc aucun problème à s'adapter au cas où la valeur peut être Null.&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="362"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="137"&gt;NUMBER(19,2)&lt;/td&gt; &lt;td valign="top" width="359"&gt;Le nombre est tronqué si la précision est plus grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="138"&gt;decimal(19,2)&lt;/td&gt; &lt;td valign="top" width="358"&gt;Une exception est envoyée si la précision est plus grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;HSqlDb&lt;/td&gt; &lt;td valign="top" width="139"&gt; &lt;p&gt;numeric&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="357"&gt;Le stockage ne connaît ni précision ni contrôle on stocke exactement ce que l'on a reçu&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="139"&gt;numeric(19,2)&lt;/td&gt; &lt;td valign="top" width="357"&gt;Le nombre est tronqué si la précision est plus grande, le nombre est complété pour respecter la précision&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Type Mesure&lt;/h3&gt; &lt;p&gt;Une mesure ressemble à un Montant monétaire, à une différence près : la précision des chiffres après la virgule n'est pas d'une grande importance (il ne faut pas oublier que la précision d'une mesure physique est rarement supérieure à 1%).  &lt;p&gt;Il peut donc être judicieux de stocker une mesure dans un double ou Double, ce qui facilite la programmation.  &lt;p&gt;Exemple de définition d'un montant :  &lt;p&gt;&amp;nbsp; &lt;div class="code"&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_MESURE", nullable=false)  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private double mesure; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="136"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="361"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="138"&gt;double precision &lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="139"&gt;double precision&lt;/td&gt; &lt;td valign="top" width="357"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="140"&gt;double&lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="140"&gt;double precision&lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Type Taux et Pourcentage&lt;/h3&gt; &lt;p&gt;Les taux et pourcentage sont généralement associés aux données de type monétaire. Il s'agit souvent de réaliser des multiplications d'un montant monétaire afin d'obtenir une nouvelle somme. Généralement, un taux pourcentage peut être stockées avec 2 ou 4 chiffres après la virgule et ne dépasse pas les 3 chiffres avant la virgule. Afin de simplifier la modélisation, on utilisera donc la définition suivante :&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_TAUX", precision=7, scale=4, nullable=false)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private BigDecimal taux;  &lt;p&gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&lt;br&gt;Notez l'attribut nulllable positionné à false par défaut : il est fort probable que par défaut, un taux soit positionné à 0 et non pas laissé à Null. La valeur Null rend délicat les opérations réalisée par défaut alors qu'avec la valeur 0, le résultat serait fonctionnellement correct dans de nombreux cas.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="362"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="137"&gt;NUMBER(7,4)&lt;/td&gt; &lt;td valign="top" width="359"&gt;Le nombre est tronqué si la précision est plus grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="138"&gt;decimal(7,4)&lt;/td&gt; &lt;td valign="top" width="358"&gt;Une exception est envoyée si la précision est plus grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="139"&gt;numeric&lt;/td&gt; &lt;td valign="top" width="357"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="139"&gt;numeric(7,4)&lt;/td&gt; &lt;td valign="top" width="357"&gt;Le nombre est tronqué si la précision est plus grande, le nombre est complété pour respecter la précision&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Type Quantité entière&lt;/h3&gt; &lt;p&gt;Il s'agit de valeurs entières comme le nombre d'articles achetés. On optera pour un type Long si la valeur peut être Null autrement on optera pour un long. Attention ! dans ce cas, il faut préciser l'attribut nullable à false. Il est fort probable que dans de nombreux cas, le défaut d'une quantité soit la valeur 0 : Dans ce cas, le long sera plus approprié.&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_QUANTITY", nullable=false)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private long longNumeric;&lt;br&gt; &lt;p&gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;ou bien &lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_QUANTITYNULL")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Long longObject;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="362"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="137"&gt;NUMBER(19,0)&lt;/td&gt; &lt;td valign="top" width="359"&gt;Le nombre est tronqué si la précision est plus grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="138"&gt;bigint&lt;/td&gt; &lt;td valign="top" width="358"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="139"&gt;bigint&lt;/td&gt; &lt;td valign="top" width="357"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="139"&gt;numeric(19,0)&lt;/td&gt; &lt;td valign="top" width="357"&gt;Le nombre est tronqué si la précision est plus grande&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;h3&gt;Type Chaîne de caractères&lt;/h3&gt; &lt;p&gt;Il s'agit de toutes les chaînes de caractères classiques qui correspondent à une information relativement structurée comme un nom, un prénom, un nom de rue... Ces chaînes sont d'une taille raisonnable : inférieure à 250 caractères. Au delà, ce sera probablement une donnée de type Commentaire.&lt;/p&gt; &lt;p&gt;Le stockage d'une chaîne de caractères est des plus simples : une String.&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;@Column(name="JLTS_NAME", length=40)  &lt;p&gt;private String name; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar2(40 char)&lt;/td&gt; &lt;td valign="top" width="361"&gt;Où 40 est la length. Oracle ne distingue pas les chaînes vide des chaînes Null. Il ne stocke que des chaînes Null. L'attribut char après la longueur indique la prise en compte des caractères UTF-8.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(40)&lt;/td&gt; &lt;td valign="top" width="360"&gt;MySql fait la différence entre une chaîne vide et une chaîne Null.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(40)&lt;/td&gt; &lt;td valign="top" width="359"&gt;Il n'envoie aucune exception en cas de chaine trop grande&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(40)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Type Code&lt;/h3&gt; &lt;p&gt;Certaines informations sont stockées sous la forme d'un code :  &lt;ul&gt; &lt;li&gt;code postaux  &lt;li&gt;code monnaie  &lt;li&gt;code d'un état  &lt;li&gt;code d'une banque  &lt;li&gt;Siren  &lt;li&gt;Siret&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;En règle général les codes ont une longueur fixe et relativement courte (inférieur à 10 caractères). Ils peuvent être alphanumériques ou numériques.  &lt;p&gt;Ils peuvent également correspondre au type "Liste déroulante" décris plus loin. Les distinguer n'a pas d'intérêt car le résultat sera le même. On utilise un type String.  &lt;p&gt;&amp;nbsp; &lt;div class="code"&gt; &lt;p&gt;@Column(name="JLTS_SHORTCODE", nullable=true, length=2)&lt;br&gt;private String ShortCode; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar2(2 char)&lt;/td&gt; &lt;td valign="top" width="361"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="360"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;h3&gt;Type Commentaire&lt;/h3&gt; &lt;p&gt;Il y a de forte chance que toute information qui dépasse la centaine de caractères soit un champ de type commentaire. Même s'il est confortable de limiter ce champ à un type String et un stockage en base limité à un ou deux milles caractères, cette approche à de forte chance de ne pas résister aux besoins futures des utilisateurs. Il est donc préférable d'utiliser une représentation sous forme de CLOB.  &lt;p&gt; &lt;div class="code"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Lob&amp;nbsp; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_COMMENT")  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private String commentaire;  &lt;p&gt;&amp;nbsp; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;CLOB&lt;/td&gt; &lt;td valign="top" width="361"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;longtext&lt;/td&gt; &lt;td valign="top" width="360"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;longvarchar&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;text &lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp; &lt;h3&gt;Type Booléen Vrai-Faux&lt;/h3&gt; &lt;p&gt;Il s'agit des informations qui sont affichées généralement sous forme de case à cocher (CheckBox). La valeur peut être Vrai ou Fausse.  &lt;p&gt;Toutes les bases mais surtout la plus connue et la plus employée (Oracle) ne possèdent pas de type Booléen. L'information devra être stockée sous forme d'un caractère (Y,N par exemple) ou d'un nombre (0,1).  &lt;p&gt;L'annotation standard JPA est celle là.  &lt;p&gt; &lt;div class="code"&gt;@Column(name="JLTS_BOOLEAN")&lt;br&gt;private boolean booleanType;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;number(1,0)&lt;/td&gt; &lt;td valign="top" width="361"&gt;0 pour false et 1 pour true&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;bit&lt;/td&gt; &lt;td valign="top" width="360"&gt;correspondance directe avec true et false&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;bit&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;tinyint &lt;/td&gt; &lt;td valign="top" width="359"&gt;0 pour false et 1 pour true&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;p&gt;Il existe une annotation propre à Hibernate (non JPA) qui permet d'indiquer le stockage en base :  &lt;p&gt; &lt;div class="code"&gt;@Type(type="yes_no")&lt;br&gt;@Column(name="JLTS_YESNO")&lt;br&gt;public boolean yesNo;  &lt;p&gt;&amp;nbsp; &lt;p&gt;@Type(type="true_false")&lt;br&gt;@Column(name="JLTS_TF")&lt;br&gt;public boolean trueFalse;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;char(1 char)&lt;/td&gt; &lt;td valign="top" width="361"&gt;Stockage sous forme de lettre Y et N pour yes_no&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;CHAR(1)&lt;/td&gt; &lt;td valign="top" width="360"&gt;T et F pour true_false,&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;char(1)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;/p&gt; &lt;h3&gt;Type Liste déroulante et énumération&lt;/h3&gt; &lt;p&gt;Il s'agit du cas représenté généralement par une liste déroulante (ComboBox ou composant SELECT HTML). Il y a une série de libellés qui correspondent à un code.  &lt;p&gt;Le stockage en base est un code.  &lt;p&gt;Généralement le code appartient à une autre colonne (notion de Foreign Key).  &lt;p&gt;Le stockage aura lieu sous forme de chaîne de caractère classique :  &lt;div class="code"&gt; &lt;p&gt;@Column(name="JLTS_COMBOBOX", nullable=true, length=2)&lt;br&gt;private String selection; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Je ne recommande pas l'utilisation de many-to-one pour ce type de relation : ce type de relation alourdit l'affichage quand il s'agit d'une information qui correspond à une table de paramètre. Le many-to-one doit être réservé aux liaisons entre véritables objets. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar2(2 char)&lt;/td&gt; &lt;td valign="top" width="361"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="360"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(2)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;h3&gt;Type Date précise au jour&lt;/h3&gt; &lt;p&gt;Le cas des dates est très particulier, le type Date est d'une précision bien supérieure au besoin de stockage des dates qui se limite à une précision au jour près. &lt;/p&gt; &lt;p&gt;JPA définit une annotation Temporal qui permet de limiter la précision au jour (DATE), à l'heure (TIME) où une précision extrême et complète (TIMESTAMP)&lt;/p&gt; &lt;p&gt;La précision est importante au niveau des dates : il est souhaitable qu'une recherche sur les enregistrements ayant une colonne Date qui correspond à la date du jour 22/09/2009 renvoie tous les enregistrements en passant par une égalité. &lt;/p&gt; &lt;p&gt;Si la précision est trop grande (au niveau de la seconde) cela ne fonctionnera pas. &lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;@Temporal(TemporalType.DATE)&lt;br&gt;@Column(name="JLTS_DATE", nullable=true)&lt;br&gt;private Date dayDate;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;date&lt;/td&gt; &lt;td valign="top" width="361"&gt;Le stockage est sous une précision dd/MM/yyyy. L'égalité au niveau jour fonctionne dans les requêtes Oracle (en utilisant To_Date)&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;date&lt;/td&gt; &lt;td valign="top" width="360"&gt;L'égalité au niveau jour fonctionne dans les requêtes MySql (en utilisant str_to_date)&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;date&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;datetime &lt;/td&gt; &lt;td valign="top" width="359"&gt;Le stockage est sous une précision dd/MM/yyyy. L'égalité au niveau jour fonctionne dans les requêtes Sql Server(en utilisant Cast)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;/p&gt; &lt;h3&gt;Type Heure&lt;/h3&gt; &lt;p&gt;Il s'agit d'une heure dans la journée, indépendante du jour. Ce type est rarement utilisé. Son manque de portabilité me pousse à préférer le TimeStamp.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;@Temporal(TemporalType.TIME)  &lt;p&gt;@Column(name="JLTS_TIME", nullable=true)  &lt;p&gt;private Date time; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;date&lt;/td&gt; &lt;td valign="top" width="361"&gt;Ce format ne fonctionne pas en Oracle&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;time&lt;/td&gt; &lt;td valign="top" width="360"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;time&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;datetime &lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;h3&gt;Type TimeStamp&lt;/h3&gt; &lt;p&gt;Il s'agit d'une date précise souvent à la milliseconde qui permet de conserver une trace d'un événement. Ce type de colonne est souvent dans des tables d'historiques ou d'audit qui conservent une trace des modifications faites par les utilisateurs.  &lt;p&gt;Ce type de trace sert principalement au besoin d'audit et de traçabilité de l'information.  &lt;p&gt;Sa précision à la seconde ne permet pas de rechercher simplement les enregistrements dont la valeur du TimeStamp est égale à une date.&amp;nbsp; &lt;p&gt; &lt;div class="code"&gt;@Temporal(TemporalType.TIMESTAMP)&lt;br&gt;@Column(name="JLTS_TIMESTAMP", nullable=true)&lt;br&gt;private Date timeStampAudit;  &lt;p&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="136"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="361"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="138"&gt;timestamp&lt;/td&gt; &lt;td valign="top" width="358"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="140"&gt;datetime&lt;/td&gt; &lt;td valign="top" width="356"&gt;La précision de ce format est plus faible qu'en Oracle&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="141"&gt;timestamp&lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="141"&gt;datetime &lt;/td&gt; &lt;td valign="top" width="356"&gt;La précision de ce format est plus faible qu'en Oracle&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Type Identifiant Séquence&lt;/h3&gt; &lt;p&gt;L'identifiant le plus simple est une clé numérique automatique. Oracle possède la notion de séquence pour cela. Dans d'autre cas, il faut passer par une autre table qui permet de stocker le compteur.  &lt;p&gt;Pour la portabilité, il est souhaitable d'utiliser le type automatique suivant : GenerationType.AUTO.  &lt;p&gt;GenerationType.SEQUENCE fonctionne bien avec Oracle mais pas avec MySql.  &lt;p&gt;GenerationType.IDENTITY : fonctionne bien avec MySql mais pas avec Oracle.  &lt;p&gt;&amp;nbsp; &lt;div class="code"&gt; &lt;p&gt;@Id  &lt;p&gt;@GeneratedValue(strategy=GenerationType.AUTO)  &lt;p&gt;@Column(name="LONG_ID", nullable=false)  &lt;p&gt;private long id=0;  &lt;p&gt;&amp;nbsp; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Cela correspond à une séquence&amp;nbsp; &lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="635"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="136"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="361"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="138"&gt;number(19,0)&lt;/td&gt; &lt;td valign="top" width="358"&gt;Il y a création est utilisation d'une Séquence Oracle hibernate_sequence.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="140"&gt;bigint&lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="141"&gt;bigint generated by default as identity (start with 1)&lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="141"&gt;numeric(19,0) identity &lt;/td&gt; &lt;td valign="top" width="356"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;h3&gt;Type Numéro de dossier&lt;/h3&gt; &lt;p&gt;Il existe des informations qui sous une apparence numérique (elles ne sont composées que de chiffres) sont plus souvent manipulées comme une chaîne de caractères que comme un nombre.&lt;/p&gt; &lt;p&gt;Par exemple, on ne fait pas d'opération arithmétique sur un numéro de dossier ou le numéro de sécurité sociale : additionner un nombre, le multiplier, le diviser ou le comparer non pas de sens.&lt;/p&gt; &lt;p&gt;Il est plus courant de faire des concaténations de chaînes : le code sexe, le code département pour un numéro de sécurité sociale. &lt;/p&gt; &lt;p&gt;Pour un numéro de dossier, on peut trouver pratique de faire une recherche en ne tapant qu'une partie du numéro en utilisant un Like.&lt;/p&gt; &lt;p&gt;Pour ces champs, il est souhaitable d'utiliser un type String.&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt; &lt;p&gt;@Column(name="JLTS_NUMERO", nullable=true, length=10)&lt;br&gt;private String NumeroDossier; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="636"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Base de données&lt;/td&gt; &lt;td valign="top" width="135"&gt;Type Base&lt;/td&gt; &lt;td valign="top" width="363"&gt;Remarque&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;Oracle&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar2(10 char)&lt;/td&gt; &lt;td valign="top" width="361"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="140"&gt;MySql&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(10)&lt;/td&gt; &lt;td valign="top" width="360"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;HsqlDb&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(10)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="141"&gt;Sql Server&lt;/td&gt; &lt;td valign="top" width="136"&gt;varchar(10)&lt;/td&gt; &lt;td valign="top" width="359"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp; &lt;/p&gt; &lt;h2&gt;Nullité d'une colonne&lt;/h2&gt; &lt;p&gt;Une colonne peut être nulle ce qui est différent de la valeur 0 pour un nombre et d'une chaîne vide "" pour une String. Oracle est une exception notoire pour les String : Oracle insère un Null dans une colonne quand on lui passe une chaîne vide. Ce point est encore d'actualité avec un Oracle 10G et le driver ojdc14.jar.  &lt;p&gt;Les types Java acceptent s'ils sont d'un type objets (BigDecimal, Double, Long...) la valeur Null ce qui n'est pas le cas des types natifs (double, long, integer...). Le type String accepte la valeur Null.  &lt;p&gt;D'un point de vu technique, il n'est pas judicieux d'utiliser un type natif si la colonne ne possède pas l'attribut Not Null : on risque des problèmes ou des incohérences si on récupère une valeur Null.  &lt;p&gt;&amp;nbsp; &lt;p&gt;D'un point de vu fonctionnel, le Null doit servir à distinguer une valeur non saisie des autres : On utilisera le Null s'il est pertinent de distinguer 0 de l'absence de saisie.  &lt;p&gt;Par exemple, il n'est pas souhaitable que la note d'un enfant soit par défaut 0. Il est important d'être capable de distinguer l'absence de notation (le Null) d'une note nulle (0).  &lt;p&gt;Dans le cas, d'un rabais, c'est probablement l'inverse, on souhaite que par défaut la valeur soit 0. Cela permet de faire simplement les calculs. La valeur peut rester à 0 sans grand impact. En règle générale, le changement de cette valeur nécessite des attributions spéciales (par exemple être manager).&amp;nbsp; &lt;p&gt;&amp;nbsp; &lt;p&gt;Pour les chaînes de caractères on évitera de distinguer le cas des null des chaînes vides afin de conserver la portabilité vers Oracle. Cela n'est pas nécessairement un problème important. Le statut d'un objet (qui peut être détecté par la différence entre un champ Null et vide) peut également et probablement mieux rendu par une colonne spécifique STATUT/ETAT (il s'agit du type Code).  &lt;p&gt;Pour les nombres, le choix est plus délicat :  &lt;ul&gt; &lt;li&gt;l'absence de null facilite les calculs : le calcul n'a pas beson de tester l'existence d'un Null  &lt;li&gt;le 0 peut souvent être pris comme une valeur par défaut  &lt;li&gt;il existe des cas (comme pour une note) ou le 0 ne peut être considéré comme une valeur par défaut, dans ce cas, le Null est indispensable.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp; &lt;p&gt;Il ne faut pas perdre de vu que le créateur de l'objet métier n'a pas nécessairement tous les droits pour saisir toutes les valeurs. il peut s'agir d'un opérateur de saisi qui n'a pas les habilitations pour remplir certaines valeurs sensibles. Dans ce type de process, il peut être important que la personne qui possède les droits pour compléter le dossier puisse distinguer d'un rapide coup d'oeil les informations qui lui reste à saisir. Dans ce cas, les Null peuvent être utiles même si dans d'autres cas, la valeur 0 sera très pertinente.&lt;/p&gt; &lt;p&gt;Dans notre exemple précédent, le rabais pourra rester à 0.&lt;/p&gt; &lt;p&gt;S'il faut une règle simple : je donnerai la règle suivante : Le null est utile si la valeur par défaut du champ ne peut pas être 0, dans les autres cas, il sera préférable de ne pas utiliser de Null.&lt;/p&gt; &lt;h2&gt;Conclusion&lt;/h2&gt; &lt;p&gt;La phase de conception du modèle de données peut être grandement simplifiée en limitant la définition des types à la liste précédemment donnée :&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="903"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="161"&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="312"&gt;&lt;strong&gt;Notation JPA&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="121"&gt;&lt;strong&gt;Oracle&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt;&lt;strong&gt;Mysql&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt;&lt;strong&gt;HsqlDb&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;&lt;strong&gt;Sql Server&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="160"&gt; &lt;p&gt;Montant monétaires&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="310"&gt; &lt;p&gt;@Column(name="JLTS_AMOUNT", nullable=true, precision=19, scale=2)&lt;/p&gt; &lt;p&gt;private BigDecimal amount; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="121"&gt; &lt;p&gt;NUMBER(19,2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="113"&gt; &lt;p&gt;decimal(19,2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt; &lt;p&gt;numeric&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;numeric(19,2)&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="159"&gt; &lt;p&gt;Mesure &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="309"&gt; &lt;p&gt;@Column(name="JLTS_MESURE", nullable=false)&lt;/p&gt; &lt;p&gt;private double mesure; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="121"&gt; &lt;p&gt;double precision&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="112"&gt; &lt;p&gt;double precision&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt; &lt;p&gt;double &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt; &lt;p&gt;double precision&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="158"&gt; &lt;p&gt;Taux et pourcentages&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="307"&gt; &lt;p&gt;@Column(name="JLTS_TAUX", nullable=true, precision=7, scale=4)&lt;/p&gt; &lt;p&gt;private BigDecimal taux; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="120"&gt; &lt;p&gt;NUMBER(7,4)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="112"&gt; &lt;p&gt;decimal(7,4)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt; &lt;p&gt;numeric&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;numeric(7, 4)&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="157"&gt; &lt;p&gt;Quantité&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="306"&gt; &lt;p&gt;@Column(name="JLTS_LONG", nullable=false)&lt;/p&gt; &lt;p&gt;private long longNumeric; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;NUMBER(19,0)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;bigint &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt; &lt;p&gt;bigint &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;numeric(19,0)&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="157"&gt; &lt;p&gt;Chaînes de caractères &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="306"&gt; &lt;p&gt;@Column(name="JLTS_STRING",&amp;nbsp; length=40)&lt;/p&gt; &lt;p&gt;private String textString; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;VARCHAR2(40 CHAR)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;varchar(40)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt; &lt;p&gt;varchar(40)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt; &lt;p&gt;varchar(40)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt; &lt;p&gt;Code &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="305"&gt; &lt;p&gt;@Column(name="JLTS_SHORTCODE", nullable=true, length=2)&lt;/p&gt; &lt;p&gt;private String shortCode; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;VARCHAR2(2 CHAR)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt; &lt;p&gt;Commentaire&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="304"&gt; &lt;p&gt;@Lob &lt;/p&gt; &lt;p&gt;@Column(name="JLTS_COMMENT")&lt;/p&gt; &lt;p&gt;private String commentaire;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;CLOB&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;longtext&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;longvarchar&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;text &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt; &lt;p&gt;Vrai-Fausse et Booléen&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="304"&gt; &lt;p&gt;@Column(name="JLTS_BOOLEAN")&lt;/p&gt; &lt;p&gt;private boolean booleanType; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;NUMBER(1,0)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;bit&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;bit&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;tinyint &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Liste déroulante &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="304"&gt; &lt;p&gt;@Column(name="JLTS_SHORTCODE", nullable=true, length=2)&lt;/p&gt; &lt;p&gt;private String shortCode; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="119"&gt; &lt;p&gt;VARCHAR2(2 CHAR)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="111"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt; &lt;p&gt;varchar(2)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Date&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="303"&gt; &lt;p&gt;@Temporal(TemporalType.DATE)&lt;/p&gt; &lt;p&gt;@Column(name="JLTS_DATE", nullable=true)&lt;/p&gt; &lt;p&gt;private Date dayDate; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="118"&gt; &lt;p&gt;DATE&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt; &lt;p&gt;date&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;date&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;datetime &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Heure&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="303"&gt; &lt;p&gt;@Temporal(TemporalType.TIME)&lt;/p&gt; &lt;p&gt;@Column(name="JLTS_TIME", nullable=true)&lt;/p&gt; &lt;p&gt;private Date time; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="118"&gt; &lt;p&gt;DATE&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt; &lt;p&gt;time&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;time&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;datetime &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Tags horaires (TimeStamp)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="303"&gt; &lt;p&gt;@Temporal(TemporalType.TIMESTAMP)&lt;/p&gt; &lt;p&gt;@Column(name="JLTS_TIMESTAMP", nullable=true)&lt;/p&gt; &lt;p&gt;private Date timeStampAudit; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="118"&gt; &lt;p&gt;TIMESTAMP&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt; &lt;p&gt;datetime&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;timestamp&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;datetime &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Numéro de dossier &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="303"&gt; &lt;p&gt;@Column(name="JLTS_NUMERO", nullable=true, length=10)&lt;/p&gt; &lt;p&gt;private String numero; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="118"&gt; &lt;p&gt;VARCHAR2(10 CHAR)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt; &lt;p&gt;varchar(10)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="114"&gt; &lt;p&gt;varchar(10)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt; &lt;p&gt;varchar(10)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="155"&gt; &lt;p&gt;Séquence&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="304"&gt; &lt;p&gt;@Id&lt;/p&gt; &lt;p&gt;@GeneratedValue(strategy=GenerationType.AUTO)&lt;/p&gt; &lt;p&gt;@Column(name="LONG_ID", nullable=false)&lt;/p&gt; &lt;p&gt;private long id=0; &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="120"&gt; &lt;p&gt;NUMBER(19,0)&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="112"&gt; &lt;p&gt;bigint &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="115"&gt; &lt;p&gt;bigint &lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="76"&gt;numeric(19,0) identity&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Dans le cas d'une phase de ré-ingénierie d'un modèle de données existant, il sera probablement possible de se baser sur les mêmes types en changeant peut être leur représentation JPA afin de l'adapter à l'existant en base.&lt;/p&gt; &lt;p&gt;Par exemple, si en base les montants sont des NUMBER(11,2), le type montant pourra être de type &lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp; @Column(name="JLTS_MONTANT", &lt;strong&gt;precision=11, scale=2&lt;/strong&gt;, nullable=false)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private BigDecimal montant;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Dans la pratique, on ne devrait pas voir apparaître plus de deux déclinaisons d'un même type dans un modèle existant.&lt;/p&gt; &lt;p&gt;J'espère que ce tutorial simplifiera la conception de vos prochains modèles de données. Un prochain billet présentera un projet de test permettant de mieux appréhender les différents comportements.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-1596264189031827311?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/1596264189031827311/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=1596264189031827311&amp;isPopup=true' title='6 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1596264189031827311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1596264189031827311'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2009/09/type-de-donnees-jpa-et-hibernate.html' title='Type de données JPA et Hibernate'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-6331159829992514427</id><published>2009-07-07T16:55:00.001+02:00</published><updated>2009-07-07T16:55:46.931+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Tutorial sur les montants et l'utilisation des BigDecimal en Java :</title><content type='html'>&lt;p&gt;L'objectif de ce billet est double. Premièrement, il s'agit d'une sensibilisation au besoin impérieux d'utiliser des BigDecimal à la place des double dans les applications de gestion.&lt;/p&gt; &lt;p&gt;Secondement, nous allons donner quelques recommandations pour l'utilisation efficace des BigDecimal.&lt;/p&gt; &lt;h2&gt;Pourquoi utiliser des BigDecimal et non des double&lt;/h2&gt; &lt;p&gt;La manipulation de montant en programmation s'est souvent heurtée à quelques problèmes de comparaison : deux chiffres censés être égaux sont testés comme différents : par exemple 7273.27x10 est différent de 72732.7.&lt;/p&gt; &lt;p&gt;Le mécanisme de stockage traditionnel des nombres en binaire : une somme de puissance de 2, est responsable de ce problème. &lt;/p&gt; &lt;p&gt;Des nombres aussi simple que 0,1 ne peuvent pas être stockés précisément sous cette forme. En conséquence 0,1 n'est jamais exactement égale à 0,1. Donc 0,1x10 n'est pas exactement égale à 1. Hors 1 = 2^0, donc 1 possède lui une représentation exacte. Si on faisait 0,1x10 une comparaison avec 1 donne dans ce cas un résultat erronée.&lt;/p&gt; &lt;p&gt;N.B. Il semble que le cas du 0,1 soit mieux traité maintenant puisqu'en Java, si on utilise des double, on a bien 0,1x10=1.0.&lt;/p&gt; &lt;p&gt;Dans les applications de gestion, les nombres sont souvent des montants ou des pourcentages : le nombre de chiffres après la virgule est généralement connu (entre 2 et 4 voir 6 ou 8 pour certaines applications financières).&lt;/p&gt; &lt;p&gt;En cas de division, il existe des règles d'arrondies et il n'est pas souhaitable de modifier le stockage pour gagner en "précision". Ces applications ne connaissent pas les réels : 1/3 va être égale à 0,33.&lt;/p&gt; &lt;h2&gt;Le BigDecimal en Java&lt;/h2&gt; &lt;p&gt;En Java, il existe un type BigDecimal qui permet de prendre en compte ce type de problématique : il repose sur le fait qu'un entier possède une représentation binaire exacte.&lt;/p&gt; &lt;p&gt;Pour un montant, il suffit de définir le nombre de chiffres après la virgule et de stocker le nombre sous forme entière : par exemple on stockera 7273.27 sous la forme d'une valeur de 727327&amp;nbsp; possédant 2 chiffres après la virgule. Le nombre de chiffres après la virgule correspond à la propriété scale du BigDecimal.&lt;/p&gt; &lt;p&gt;L'utilisation de BigDecimal entraîne une petite contrainte : il ne s'agit pas d'un type natif mais d'un objet. Il n'est donc pas possible d'utiliser les opérateurs +, -, * et /.&lt;/p&gt; &lt;p&gt;Par exemple &lt;/p&gt; &lt;p&gt;7273.27*10.0 qui avec des doubles s'écrit :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;double doubleApproche=7273.27;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;double resultat=10*doubleApproche; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;devient en BigDecimal :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;BigDecimal doubleApproche=new BigDecimal("7273.27");&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;BigDecimal resultat=doubleApproche.multiply(new BigDecimal(10)); &lt;/p&gt;&lt;/div&gt; &lt;h2&gt;Exemple de projet&lt;/h2&gt; &lt;p&gt;Nous allons créer un projet Eclipse simple afin d'illustrer les différents cas.&lt;/p&gt; &lt;p&gt;Dans le menu : File -&amp;gt; New Project&lt;/p&gt; &lt;p&gt;Choisir ensuite dans le noeud Java : Java Project.&lt;/p&gt; &lt;p&gt;Le nom du projet sera TestBigDecimal.&lt;/p&gt; &lt;p&gt;Appuyer sur le bouton Finish.&lt;/p&gt; &lt;p&gt;Sur le noeud src, clique droit et choisir New -&amp;gt; New Junit Test Case&lt;/p&gt; &lt;p&gt;Chosir le radio button New JUnit 4 test.&lt;/p&gt; &lt;p&gt;Package : fr.j2ltho.test.bigdecimal&lt;/p&gt; &lt;p&gt;Name : TestDifferences&lt;/p&gt; &lt;p&gt;Puis appuyer sur le bouton Finish.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Une boite de dialogue apparaît : "JUnit 4 is not on the build path. Do you want to add it ?".&lt;/p&gt; &lt;p&gt;Choisir le radio bouton : Perform the following action:&lt;/p&gt; &lt;p&gt;Et vérifier qu'il y a bien : Add JUnit 4 library to the build path.&lt;/p&gt; &lt;p&gt;Valider en appuyant sur le bouton OK.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;On ajoute le code suivant :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;package fr.j2ltho.test.bigdecimal;  &lt;p&gt;import static org.junit.Assert.assertEquals;  &lt;p&gt;import java.math.BigDecimal;  &lt;p&gt;import org.junit.Test;  &lt;p&gt;public class TestDifferences {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Test(timeout=1000)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void testProblemeDouble() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double doubleApproche=7273.27;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double resultat=10*doubleApproche;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("Double fois 10", 72732.7, resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resultat==72732.7) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (resultat-72732.7));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Test(timeout=1000)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void testProblemeBigDecimal() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal doubleApproche=new BigDecimal("7273.27");&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal resultat=doubleApproche.multiply(new BigDecimal(10));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("BigDecimal fois 10", new BigDecimal("72732.7"), resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resultat.compareTo(new BigDecimal("72732.7")) ==0){&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (resultat.subtract(new BigDecimal("72732.7"))));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Test(timeout=1000)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void testDixiemeDouble() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double doubleApproche=0.1;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double resultat=10*doubleApproche;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("Double fois 10", 1.0, resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resultat==1.0) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (resultat-1.0));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Test(timeout=1000)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void testCentiemeDouble() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double doubleApproche=0.01;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double resultat=10*doubleApproche;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("Double fois 10", 0.10, resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resultat==0.10) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (resultat-0.10));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Test(timeout=1000)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void testDixiemmeCentiemeDouble() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double doubleApproche=0.11;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double resultat=10*doubleApproche;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("Double fois 10", 1.10, resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resultat==1.10) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + resultat);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (resultat-1.10));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}  &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;L'éxécution du test : Run As -&amp;gt; JUnit Test donne un test réussi à 100% mais avec le résultat suivant dans la Console :&lt;/p&gt; &lt;p&gt;Ecart:&amp;nbsp; 1.4551915228366852E-11&lt;br&gt;Egale:&amp;nbsp; 72732.70&lt;br&gt;Egale:&amp;nbsp; 1.0&lt;br&gt;Egale:&amp;nbsp; 0.1&lt;br&gt;Egale:&amp;nbsp; 1.1  &lt;p&gt;On constate donc que la comparaison JUnit assertEquals : assertEquals("Double fois 10", 72732.7, resultat); renvoie un résultat juste alors que la comparaison des doubles renvoient une erreur et que la différence renvoie un écart.&lt;/p&gt; &lt;p&gt;Si on manipule des doubles Java, il faut se méfier de assertEquals qui semblent prendre en compte un écart d'arrondi.&lt;/p&gt; &lt;h2&gt;Création d'un BigDecimal&lt;/h2&gt; &lt;p&gt;Le BigDecimal est un objet, il est créé avec un new. Son constructeur accepte une String, un long ou un double.&lt;/p&gt; &lt;p&gt;Il ne faut jamais utiliser le constructeur du double car on réintroduit le problème de l'arrondie.&lt;/p&gt; &lt;p&gt;Le test suivant illustre le problème :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;@Test(timeout=1000)&lt;br&gt;public void testProblemeConstructeurDouble() {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal doubleApproche=new BigDecimal(7273.27);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal stringApproche=new BigDecimal("7273.27");&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; assertEquals("BigDecimal fois 10", doubleApproche, stringApproche);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (doubleApproche.compareTo(stringApproche) ==0){&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Egale:&amp;nbsp; " + doubleApproche);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println("Ecart:&amp;nbsp; " + (doubleApproche.subtract(stringApproche)));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;} &lt;/p&gt;&lt;/div&gt; &lt;p&gt;La console affiche :&lt;/p&gt; &lt;p&gt;Ecart:&amp;nbsp; 4.3655745685100555419921875E-13&lt;/p&gt; &lt;p&gt;Là encore, on constate que le assertEquals pour les BigDecimals n'est pas fiable puisqu'il indique une égalité qui n'est pas réelle.&lt;/p&gt; &lt;p&gt;Pour les entiers, il est préférable d'utiliser la méthode static valueOf() qui est plus lisible :&lt;/p&gt; &lt;p&gt;BigDecimal.valueOf(40)&lt;/p&gt; &lt;p&gt;Il existe trois méthodes statiques pour créer un BigDecimal de valeur 1 ou 0 ou 10.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;BigDecimal.ONE  &lt;li&gt;BigDecimal.ZERO  &lt;li&gt;BigDecimal.TEN&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;En bref, on recommande d'utiliser :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Pour un montant, un taux ou un pourcentage, le constructeur avec un paramètre String :&amp;nbsp; BigDecimal stringApproche=new BigDecimal("7273.27");  &lt;li&gt;Pour un nombre d'unités, la méthode static valueOf : BigDecimal.valueOf(40)  &lt;li&gt;Pour les valeurs remarquables 0, 1 et 10 : on utilise les méthodes statics : BigDecimal.ZERO, BigDecimal.ONE et BigDecimal.TEN&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;Addition et soustraction avec BigDecimal.&lt;/h2&gt; &lt;p&gt;L'addition et la soustraction ne présentent pas de particularité en dehors de l'obligation d'utiliser une méthode :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;subtract  &lt;li&gt;add&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;On aura par exemple &lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal valeur=new BigDecimal("70.36")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // resAddition = valeur + 1&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal resAddition = valeur.add(BigDecimal.ONE);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // resSoustraction = valeur -10&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BigDecimal resSoustraction = valeur.subtract(BigDecimal.TEN);&lt;br&gt;&lt;/p&gt;&lt;/div&gt; &lt;h2&gt;Multiplication et Division de BigDecimal&lt;/h2&gt; &lt;p&gt;La multiplication répond au même principe que l'addition et la soustraction avec la méthode : multiply.&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;BigDecimal pricePerShare=new BigDecimal("70.36");&lt;br&gt;// coutTotal = pricePerShare * 3&lt;br&gt;BigDecimal coutTotal =pricePerShare.multiply(BigDecimal.valueOf(3));&lt;/p&gt;&lt;/div&gt; &lt;p&gt;&lt;br&gt;Pour la division, c'est plus compliqué car il faut indiquer : &lt;/p&gt; &lt;ol&gt; &lt;li&gt;le nombre par lequel on divise  &lt;li&gt;mais surtout le nombre de chiffre après la virgule que l'on souhaite conserver pour le résultat (une division ne tombe pas toujours juste)  &lt;li&gt;et pour finir le mécanisme d'arrondi : nous utiliserons généralement BigDecimal.ROUND_HALF_UP&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Par exemple, le nombre de parts achetées :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;BigDecimal pricePerShare=new BigDecimal("70.36");&lt;br&gt;BigDecimal purchaseAmount=BigDecimal.valueOf(200);&lt;br&gt;// nbPart = purchaseAmount/pricePerShare&lt;br&gt;BigDecimal nbPart = purchaseAmount.divide(pricePerShare, 4, BigDecimal.ROUND_HALF_UP);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Il existe deux méthodes qui permettent de simplifier les multiplications et les divisions par des multiples de 10 :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;movePointLeft(2) on déplace la virgule de 2 vers la gauche ce qui correspond à une division par 100.  &lt;li&gt;movePointRight(1) on déplace la virgule de 1 vers la droite ce qui correspond à une multiplication par 10.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Ces deux méthodes sont particulièrement utiles lorsqu'on calcule des taux ou des pourcentages.&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;BigDecimal total=BigDecimal.valueOf(950);&lt;br&gt;BigDecimal percentage=BigDecimal.valueOf(20);&lt;br&gt;// On veut 20% de 950&lt;br&gt;// montant = (total*percentage)/100&lt;br&gt;BigDecimal montant = total.multiply(percentage).movePointLeft(2);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;/div&gt; &lt;h2&gt;Comparaison &lt;/h2&gt; &lt;p&gt;il faut favoriser la méthode : compareTo qui fait abstraction du nombre de chiffres après la virgule. compareTo considère que 15.2 et 15.200 sont identiques. Ce n'est pas le cas avec equals().&lt;/p&gt; &lt;p&gt;La méthode compareTo renvoie un entier et non pas un booléen :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;0 si la valeur est identique  &lt;li&gt;1 si la valeur est supérieure à celle du paramètre  &lt;li&gt;-1 si la valeur est inférieure à celle du paramètre&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Dans le cadre de l'utilisation de JUnit nous recommandons d'utiliser :&lt;/p&gt; &lt;p&gt;assertEquals("Comparaison", 0, doubleApproche.compareTo( stringApproche));&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;p&gt;à la place de :&lt;/p&gt; &lt;p&gt;assertEquals("Comparaison imprécise", doubleApproche, stringApproche);  &lt;p&gt;En effet dans certain cas (petit écart) : la première indiquera bien une différence alors que la seconde indiquera une égalité.&lt;/p&gt; &lt;h2&gt;Affichage&lt;/h2&gt; &lt;p&gt;Pour afficher un BigDecimal, il existe deux méthodes :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;plainString  &lt;li&gt;toString&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Nous recommandons l'utilisation d'une troisième solution : l'utilisation du formatage avec DecimalFormat. ce mécanisme permet de forcer la représentation du BigDecimal suivant un format défini.&lt;/p&gt; &lt;p&gt;L'exemple suivant est significatif : nous avons volontairement utilisé le constructeur double pour montrer la différence.&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;BigDecimal doubleApproche=new BigDecimal(7273.27);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;p&gt;System.out.println("7273.27 toPlainString:&amp;nbsp; " + doubleApproche.toPlainString());&lt;br&gt;System.out.println("7273.27 toString :&amp;nbsp; " + doubleApproche.toString());  &lt;p&gt;DecimalFormat decimalFormat = new DecimalFormat("##,###,###,##0.00");&lt;br&gt;System.out.println("7273.27 DecimalFormat :&amp;nbsp; " + decimalFormat.format(doubleApproche)); &lt;/p&gt;&lt;/div&gt; &lt;h2&gt;Conclusion&lt;/h2&gt; &lt;p&gt;L'utilisation de BigDecimal est un peu plus lourde que celle de double. Mais on retrouve un ensemble de méthodes qui simplifie le travail et surtout l'assurance de ne pas avoir de problème d'arrondi à la fin.&lt;/p&gt; &lt;p&gt;Cela nous force à lever l'ambiguïté du choix des arrondis très tôt : Cela permet d'éviter des déconvenues avec les équipes métiers lors des phases de recette. Les équipes métiers connaissent parfaitement ces règles, elles leur sont tellement naturelles qu'ils en oublient de les spécifier. L'utilisation de BigDecimal nous force à déterminer dés le début de la programmation ce qu'il faut faire.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-6331159829992514427?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/6331159829992514427/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=6331159829992514427&amp;isPopup=true' title='3 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6331159829992514427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6331159829992514427'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2009/07/tutorial-sur-les-montants-et-l-des.html' title='Tutorial sur les montants et l&amp;#39;utilisation des BigDecimal en Java :'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-6313625249365621170</id><published>2009-05-25T23:08:00.001+02:00</published><updated>2009-05-25T23:08:15.662+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>AppStore : Analyse d'un succès</title><content type='html'>&lt;p&gt;Ce billet fait parti d'une réflexion plus large sur les aspects révolutionnaires de l'iPhone. Il se concentre sur l'AppStore dont le succès dépasse les simples chiffres fournis par Apple : 35 000 applications et 1 milliard de téléchargements en date de mai 2009 (le communiqué de presse d'Apple : &lt;a title="http://www.apple.com/fr/pr/library/2009/04/24appstore.html?sr=hotnews" href="http://www.apple.com/fr/pr/library/2009/04/24appstore.html?sr=hotnews"&gt;http://www.apple.com/fr/pr/library/2009/04/24appstore.html?sr=hotnews&lt;/a&gt;). &lt;/p&gt; &lt;p&gt;Cette approche de place de marché a été reprise depuis par Google, Nokia, Microsoft et RIM (pour les BlackBerry). Le concept semble être suffisamment novateur et intéressant pour être repris par la concurrence.&lt;/p&gt; &lt;p&gt;Depuis avril 2009, les publicités pour l'iPhone se concentre exclusivement sur les applications disponibles sur l'AppStore et non plus sur l'iPhone lui-même. C'est un signe de l'importance de l'écosystème iPhone dans la décision d'achat. Et qui mieux que l'AppStore symbolise cet écosystème.&lt;/p&gt; &lt;h2&gt;L'AppStore&lt;/h2&gt; &lt;p&gt;Commençant par présenter rapidement l'AppStore surtout pour les lecteurs qui ne sont pas familier avec l'iPhone. L'AppStore est un super marché d'applications pour iPhone et iPod Touch. On y trouve des applications payantes et des applications gratuites.&lt;/p&gt; &lt;p&gt;L'AppStore est un département du fameux iTunes Store (leader mondial de la vente de musique). Il est accessible à partir du logiciel iTunes : Pour naviguer à travers l'AppStore, il n'est donc pas nécessaire de posséder un iPhone, il suffit d'utiliser iTunes. Il existe une version de l'AppStore pour iPhone, il est donc possible de consulter et charger des applications directement depuis l'iPhone.&lt;/p&gt; &lt;p&gt;L'AppStore possède différent classement des applications : en règle générale il existe deux classements séparés : un pour les applications gratuites et un pour les applications payantes. Les applications gratuites ne sont ni cachées ni enterrées au fond du site : elles disposent de la même visibilité que les applications payantes.&lt;/p&gt; &lt;h2&gt;Ampleur du succès de l'AppStore&lt;/h2&gt; &lt;p&gt;Apple annonce 35 000 applications dans le monde, 10 000 disponibles pour la France. Le chiffre est éloquent et il est difficile de ne pas trouver l'application dont on a besoin.&lt;/p&gt; &lt;p&gt;Sur les 10 000 applications on va trouver dans la rubrique Actualité une application par journal et cela pour l'ensemble de la presse mondiale. On y trouvera donc une application permettant :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;la lecture du Monde  &lt;li&gt;la lecture du New York Times  &lt;li&gt;la lecture d'El Pais (Espagne)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Et bien d'autres encore. On notera que cela fait trois applications différentes.&lt;/p&gt; &lt;p&gt;L'iPhone peut également servir de lecteur de livre : il est possible d'acheter des livres au format éléctronique : dans ce cas, un livre est une application.&lt;/p&gt; &lt;p&gt;Ces exemples sont donnés pour montrer que le nombre effectif d'applications est dans la pratique inférieur à 10 000. Néanmoins, il reste très important et dépasse probablement ce qui est disponible sur les plates-formes concurrentes.&lt;/p&gt; &lt;p&gt;Apple annonce un milliard de téléchargements : on peut estimer le nombre d'iPhones vendus aux alentours de 20 millions. On aurait donc en moyenne 50 téléchargement par iPhone. Cela me parait excessif. Je pense qu'Apple compte un téléchargement par mise à jour. Par exemple, le lecteur du New York Times que j'utilise a du être mis à jour une dizaine de fois : Apple compte probablement 10 téléchargements.&lt;/p&gt; &lt;p&gt;Ceci étant dit, toutes les applications n'ont pas plusieurs versions et qui plus est : un utilisateur n'est pas obligé de faire la mise à jour. L'un dans l'autre, j'estime qu'un utilisateur a du chargé en moyenne une petite vingtaine d'applications différentes. Ce chiffre reste très important si l'on considère qu'il s'agit d'une moyenne pour un produit grand public composé majoritairement de non informaticien.&lt;/p&gt; &lt;p&gt;A l'époque sur mon Palm j'avais chargé 4 ou 5 applications en 4 années d'utilisation. Sur l'iPhone et grâce à l'AppStore, un utilisateur moyen a téléchargé une vingtaine d'applications en 9 mois d'utilisation.&lt;/p&gt; &lt;p&gt;Une telle augmentation (facteur 4) sur une population aussi large ne peut être le fait que d'un changement majeur, révolutionnaire. C'est ce ou ces changements que nous allons identifier.&lt;/p&gt; &lt;h2&gt;Mes Applications&lt;/h2&gt; &lt;p&gt;Avant d'aller plus loin dans l'analyse, je vais lister les 29 applications que j'ai installé sur mon iPhone : cela permettra d'illustrer les différents types d'application.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Les sites actualités :  &lt;ul&gt; &lt;li&gt;ElPais.com : l'application du journal El Pais (Espagne)  &lt;li&gt;Le Monde.fr : l'application du Monde. Elle permet une lecture Hors connexion des articles du site. Attention les articles sont plus courts que ceux de journal papier.  &lt;li&gt;NYTimes : l'application du journal New York Times (Etats-Unis). Les articles semblent complets (ils sont beaucoup plus longs que ceux du Monde) mais le mode Hors Connexion fonctionne moins bien.  &lt;li&gt;Sports.fr : Un journal sportif avec un mode Live qui permet de suivre les événements sportifs (comme une journée de championnat de foot) en direct.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les Jeux  &lt;ul&gt; &lt;li&gt;Crash Bandicoot Nitro : Une sorte de Mario Kart qui utilise l'accéléromètre. Pour moi du niveau de Mario Kart pour Nintendo DS à l'exception du mode multi-joueur qui n'est pas disponible.  &lt;li&gt;Hanoi : le casse tête des tours de Hanoï  &lt;li&gt;iChess (Free) : un jeux d'échec  &lt;li&gt;Mastermind : le jeux du MasterMind  &lt;li&gt;TouchMines : une version du démineur. Un peu difficile à jouer car les cases sont trop petites.  &lt;li&gt;Virtual Pool Lite : un très bon jeu de billard américain qui rend très bien les sensations du véritable billard.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les applications de productivité  &lt;ul&gt; &lt;li&gt;SimpleMind Xpress : Une application de brainstorming  &lt;li&gt;Evernote : une très bonne application de prise de notes quelles soient vocales, écrites ou également des photo prises avec l'iPhone. Il existe également un pendant Windows ainsi qu'un plug-in Firefox pour noter des morceaux de site Internet.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les références et dictionnaires  &lt;ul&gt; &lt;li&gt;Dictionnaire Littré : une version très ancienne et un peu passé du dictionnaire Littré que j'utilise pour expliquer des mots aux enfants  &lt;li&gt;PagesJaunes : cette application étend le site Web en rendant disponible l'utilisation de la localisation.  &lt;li&gt;Wapedia - Wiki mobile : Une version très conviviale de Wikipedia pour iPhone.  &lt;li&gt;160 000 Recipes : Un site de recette de cuisines (en anglais)&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Aide aux déplacements  &lt;ul&gt; &lt;li&gt;Wikango : un excellent avertisseur de Radar  &lt;li&gt;PanameTraffic : Permet de visualiser l'état du trafic sur la région parisienne, devenu un peu moins utile depuis que le trafic est également disponible directement sur l'application Plan (Google Map)  &lt;li&gt;GoVelib : Permet de connaître les stations Velib autour de vous et leur disponibilité en vélo.  &lt;li&gt;Locly : permet de connaître quelques types de commerces ou services (comme les guichets carte bleu) autour de vous.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Divertissements  &lt;ul&gt; &lt;li&gt;Liveradio d'Orange : permet d'écouter des stations radio à travers internet.  &lt;li&gt;Première : les dernières critiques de cinéma avec les séances près de chez vous.  &lt;li&gt;Stanza : un lecteur de livres pour iPhone. L'application permet le téléchargement d'une grande quantité de livres français ou anglais (tous anciens).&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Utilitaires  &lt;ul&gt; &lt;li&gt;Orange spot'finder : Permet de connaître les Hot Spot Wifi autour de vous.  &lt;li&gt;Speedtest : Permet de mesurer le débit de votre connexion internet. Une des applications qui a permis en août/septembre 2009 de mettre en évidence le bridage de la 3G par Orange.  &lt;li&gt;9 - Toolbox (Free Event) : une série de petits utilitaires qui va du convertisseur d'unités au niveau à bulle&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Réseaux sociaux  &lt;ul&gt; &lt;li&gt;LinkedIn : l'application qui permet de se connecter au site social professionnel LinkedIn&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les applications ludiques  &lt;ul&gt; &lt;li&gt;LightSaber Unleashed : un sabre laser Star War. Idéal pour épater les jeunes enfants.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Les applications publicitaires  &lt;ul&gt; &lt;li&gt;Angoulême 2009 : Application créé pour le festival de la BD d'Angoulême qui permet de feuilleter une série de BD.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;De cette liste d'applications seule Crash Bandicoot Nitro Kart 3D est payante : au tarif de 5 € son prix est très compétitif par rapport à un jeu Nintendo DS à 35 €.&lt;/p&gt; &lt;h2&gt;Avantages du concept AppStore&lt;/h2&gt; &lt;p&gt;L'AppStore peut être considérée comme une déclinaison de l'iTunes Store : une place de marché pour des applications. On bénéficie des mêmes avantages :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;simplifie la recherche : il n'est pas nécessaire de rechercher dans plusieurs magasins ou sur différents sites quelles applications est la meilleure ou quelle application est disponible. Il suffit d'aller sur l'AppStore et regarder s'il y a une nouvelle application susceptible de nous intéresser. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Mais l'AppStore ajoute une caractéristique propre aux marchés des applications :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;la confiance dans les applications : les applications sont "validées" par Apple. Même si on ne sait pas ce que cela sous entend réellement, on a la certitude que cela exclu les virus. &lt;li&gt;La création d'une place de marché a eu un autre effet bénéfique pour les utilisateurs : la concurrence entre producteurs d'applications à provoquer une baisse des prix significatives : la majorité des éditeurs de jeux ont lancé leurs jeux à des prix proches des 17$, quelques jours plus tard ont retrouvé les mêmes jeux autour des 7$. Du coup, on retrouve de nombreuses applications à des prix significativement plus faibles sur l'iPhone que sur les plate-formes concurrentes. Dans ma liste Crash Bandicoot Nitro Kart est un excellent exemple : pour 5 € on a un jeu qui vaudrait 35 € sur Nintendo DS.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Ces trois points expliquent certainement le milliard de téléchargements réalisés en moins d'un an. &lt;/p&gt; &lt;h2&gt;L'AppStore comme un lien social&lt;/h2&gt; &lt;p&gt;La confiance et la simplicité poussent aux téléchargements "ludiques" : j'entends par là, le téléchargement d'applications (bien souvent gratuites) juste pour voir ce qu'elles font. On ne cherche pas forcément l'utilité mais le coté "ludique" : un mélange de surprise et de "fun", voir un certain décalage. Ceux sont des applications que l'on va montrer qui vont servir à amorcer une discussion : elle serve à créer un lien social entre deux personnes comme on utilise parfois un article de journal, un événement où plus systématiquement un événement sportif.&lt;/p&gt; &lt;p&gt;Parmi ces applications on retrouvera l'emblématique Shazam qui permet de reconnaître un morceau de musique et qui est régulièrement utilisée dans les pub Apple. Dans ma liste, on trouvera Light Saber qui permet de lier la conversation avec des enfants. Certains petits jeux sont également idéals pour peu qu'ils soient simples courts et drôles. &lt;/p&gt; &lt;p&gt;Dans la liste des applications farfelues on retrouvera une boite à meuh (qui fait meuh quand on la retourne), un coussin péteur, des aquariums...&lt;/p&gt; &lt;p&gt;Ces téléchargements "ludiques" constituent un véritable phénomène parmi les utilisateurs d'iPhone et peuvent facilement compter pour un bon tiers des téléchargements. Ce phénomène est d'autant plus fort que grâce à la version iPhone de l'AppStore, le spectateur conquis peut s'empresser de télécharger la nouvelle application immédiatement et cela en toute confiance car hébergée sur un site contrôlé par Apple.&lt;/p&gt; &lt;p&gt;Ce type de comportement ne pourrait pas être aussi important (une demi-douzaine de téléchargement par personne en moyenne) sans le sentiment de confiance qu'inspire l'AppStore : c'est le coup de génie d'Apple. Il s'agit d'une véritable révolution du comportement des utilisateurs même si j'en convient son utilité me parait limité.&lt;/p&gt; &lt;p&gt;Au delà de cet aspect ludique, le choix d'un lot d'applications doit également constituer une certaine affirmation identitaire du possesseur de l'iPhone : le choix d'un journal n'est pas neutre par exemple. On retrouve un équivalent moderne des bibliothèques familiales qui permet d'afficher à travers le choix des livres disposés bien en vue sur les étagères un statut social. Il en est des applications comme pour les livres : ce n'est pas parce qu'elle est présente sur un iPhone qu'elle est utilisée.&lt;/p&gt; &lt;h2&gt;Conclusion&lt;/h2&gt; &lt;p&gt;L'AppStore est un élément révolutionnaire de l'offre iPhone par les changements de comportements qu'il a provoqué. Ce changement n'a été possible que parce que les utilisateurs se sont sentis en confiance grâce à l 'existence d'une place de marché sous le contrôle du constructeur.&lt;/p&gt; &lt;p&gt;Ce qui est également révolutionnaire, c'est l'attention et l'importance que porte Apple à son écosystème : de nombreux analystes ont expliqué la défaite du MacOs sur Windows par le peu d'attention qu'Apple avaient porter aux développeurs alors que ceux-ci ont toujours été choyé par Microsoft. La leçon semble avoir bien été retenue par Steve Jobs et le milliers de nouvelle API attendue avec le firmware 3.0 de l'iPhone ne devrait pas démentir ce revirement.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-6313625249365621170?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/6313625249365621170/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=6313625249365621170&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6313625249365621170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/6313625249365621170'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2009/05/appstore-analyse-d-succes.html' title='AppStore : Analyse d&amp;#39;un succès'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-7352859501360492719</id><published>2009-02-25T15:32:00.001+02:00</published><updated>2009-02-25T15:32:13.337+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Initialisation d'une propriété de type Date ou Enum avec Spring</title><content type='html'>&lt;p&gt;Le framework Spring permet de construire des objets par configuration. Les objets sont créés et peuvent être initialisés.&lt;/p&gt; &lt;p&gt;Cela marche bien et simplement pour des types simples String ou int par exemple quand il s'agit d'Enum c'est simple mais il faut savoir quand il s'agit de date c'est bien plus difficile.&lt;/p&gt; &lt;p&gt;Je me propose d'expliquer rapidement comment faire pour ces deux cas.&lt;/p&gt; &lt;h2&gt;Le cas des Enum dans Spring&lt;/h2&gt; &lt;p&gt;L'exemple fonctionne pour la version 2.5.6 de Spring avec un JDK 1.5. Je pense que la version 2.0 ou 2.5 ont apporté des simplifications que j'utilise dans cette exemple.&lt;/p&gt; &lt;p&gt;Pour une propriété simple d'un bean. Si cette propriété est de type RoleStatAppel qui est une énumération qui prend les valeurs : RoleStatAppel.ECOUTANT ou RoleStatAppel.ADMINISTRATEUR. Pour définir, la valeur de cette propriété roleUtilisateur, il suffit d'ajouter dans la définition du Bean :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;lt;property name="roleUtilisateur" value="ECOUTANT" /&amp;gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Spring prend tout en charge, il connaît le type de la propriété et il est capable de faire la correspondance avec la valeur indiquée dans value.&lt;/p&gt; &lt;p&gt;La même règle est applicable pour un objet créé avec des arguments dans son constructeur :&lt;/p&gt; &lt;p&gt;Le code initial est :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;new NsGUIFactory(NsGUIFactory.NsImplementationMode.GuiEcho2);&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Où&lt;/p&gt; &lt;ul&gt; &lt;li&gt;NsGUIFactory est un singleton que l'on souhaite créé  &lt;li&gt;GuiEcho2 est une valeur de l'énumération NsImplementationMode qui est prise en paramètre du constructeur. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;La solution pour créer cet objet via Spring est tout simplement :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;lt;bean id="FactoryBean" class="fr.natsystem.natjet.application.NsGUIFactory"&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;constructor-arg&amp;gt;&amp;lt;value&amp;gt;GuiEcho2&amp;lt;/value&amp;gt;&amp;lt;/constructor-arg&amp;gt;&lt;br&gt;&amp;lt;/bean&amp;gt; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Pour information, dans le dernier exemple, il s'agissait dans mon cas d'une énumération définie dans la classe NsGUIFactory.  &lt;h2&gt;Le cas des Date dans Spring&lt;/h2&gt; &lt;p&gt;Pour les dates, le problème est un peu plus compliqué :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Spring n'est pas capable de convertir automatiquement une valeur 01/02/2009 dans une propriété de type Date  &lt;li&gt;il existe un format. C'est d'ailleurs pour cette raison que Spring n'est pas capable de faire la conversion tout seul.  &lt;li&gt;il peut être intéressant de récupérer la date du jour sans avoir besoin de modifier son fichier de configuration.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Pour résoudre le problème des valeurs de types complexes pour lesquelles la conversion d'une String simple n'est pas immédiate ou ambiguë, Spring met à disposition ce qu'il appelle une bean factory post-processor qui permet de compléter les mécanismes standards pour ces types.&lt;/p&gt; &lt;p&gt;C'est cette solution que nous allons étudier pour traiter le cas des dates. La factory Spring CustomEditorConfigurer va être paramétrée grace à une interface dans le fichier de configuration Spring applicationContext.xml.&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;lt;bean id="customEditorConfigurer"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; class="org.springframework.beans.factory.config.CustomEditorConfigurer"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property name="customEditors"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;map&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;entry key="java.util.Date"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;bean class="org.springframework.beans.propertyeditors.CustomDateEditor"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;constructor-arg index="0"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;bean class="java.text.SimpleDateFormat"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;constructor-arg&amp;gt;&amp;lt;value&amp;gt;dd/MM/yyyy&amp;lt;/value&amp;gt;&amp;lt;/constructor-arg&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/bean&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/constructor-arg&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;constructor-arg index="1"&amp;gt;&amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;&amp;lt;/constructor-arg&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/bean&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/entry&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/map&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/property&amp;gt;&lt;br&gt;&amp;lt;/bean&amp;gt; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Le tag map permet de lister, si nécessaire, plusieurs conversion pour différents types. Il s'agit une liste de Entry.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Le entry possède une clé : key qui indique le type Java qui sera concerné par la conversion : dans notre cas, c'est le type java.util.Date. cela veut dire que dès que Spring rencontre une propriété de type Date, il appellera automatiquement notre PropertyEditor.  &lt;li&gt;Le PropertyEditor pour ce type est défini dans le tag bean en indiquant la classe utilisée. Spring met à disposition une classe pour les Date. Cet objet prend deux arguments en entrée, un SimpleDateFormat qui permet de définir le format à utiliser pour la conversion et un second argument qui prend la valeur true. je ne sais pas à quoi correspond cette avleur (il s'agit peut être de la propriété lenient qui permet de forcer ou non une erreur sur une date invalide)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;On choisit le format que l'on souhaite utilisé dans &amp;lt;constructor-arg&amp;gt;&amp;lt;value&amp;gt;&lt;strong&gt;dd/MM/yyyy&lt;/strong&gt;&amp;lt;/value&amp;gt;&amp;lt;/constructor-arg&amp;gt;.&lt;/p&gt; &lt;p&gt;Je rappelle que mm en java fait référence aux minutes alors que MM fait référence aux mois.&lt;/p&gt; &lt;p&gt;Une fois cette déclaration ajoutée dans le fichier applicationContext.xml, il suffit de définir la valeur comme cela :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;lt;property name="dateArrivee" value="22/02/2009" /&amp;gt; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Maintenant si je souhaite utiliser automatqiuement la valeur du jour, il est possible de définir un bean dateJour de la façon suivante :  &lt;div class="code"&gt; &lt;p&gt;&amp;lt;bean id="dateJour" class="java.util.Date" scope="prototype"/&amp;gt; &lt;/p&gt;&lt;/div&gt; &lt;p&gt;Puis d'utiliser cet objet comme valeur de la propriété, ce qui donne dans notre cas :&lt;/p&gt; &lt;div class="code"&gt; &lt;p&gt;&amp;lt;property name="dateArrivee"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ref bean="dateJour" /&amp;gt;&amp;nbsp; &lt;br&gt;&amp;lt;/property&amp;gt; &lt;/p&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-7352859501360492719?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/7352859501360492719/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=7352859501360492719&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7352859501360492719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/7352859501360492719'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2009/02/initialisation-d-propriete-de-type-date.html' title='Initialisation d&amp;#39;une propriété de type Date ou Enum avec Spring'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-2716507091132176141</id><published>2009-02-23T15:35:00.001+02:00</published><updated>2009-02-23T15:35:40.137+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Microsoft TechDays 2009</title><content type='html'>&lt;p&gt;Du 10 au 12 février, se tenait au palais des Congrès de Paris, la troisième édition des&amp;nbsp; Microsoft Techdays.&lt;br&gt;Vous pouvez consulter mes comptes rendus des versions précédentes : &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a title="http://jl2tho.blogspot.com/2008/02/microsoft-techdays-2008.html" href="http://jl2tho.blogspot.com/2008/02/microsoft-techdays-2008.html"&gt;http://jl2tho.blogspot.com/2008/02/microsoft-techdays-2008.html&lt;/a&gt;  &lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2007/02/microsoft-techdays-2007-part-1.html"&gt;http://jl2tho.blogspot.com/2007/02/microsoft-techdays-2007-part-1.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Cette année nous avons eu droit à moins de superlatif pour qualifier les TechDays : les années passées il s'agissait de l'événement Microsoft le plus important dans le monde. Cette année on parlait d'événement le plus important pour l'Europe.&lt;/p&gt; &lt;h2&gt;Le format&lt;/h2&gt; &lt;p&gt;Il n'a pas changé, je reprends en grande partie mes commentaires de l'année dernière : Il s'agit d'une série de conférences sur 3 jours, ouvertes chaque jour par une conférence plénières.  &lt;p&gt;Chaque plénière possède son propre thème qui donne une connotation aux sessions de la journée :  &lt;ul&gt; &lt;li&gt;1ère : le Développement  &lt;li&gt;2nde : IT  &lt;li&gt;3ème : R&amp;amp;D&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Les sessions&lt;/h3&gt; &lt;p&gt;Les conférences ou sessions durent chacune une heure. Plusieurs ont lieu en parallèle : il y avait une vingtaine de salles plus trois amphi (le nombre de sessions est constant par rapport à&amp;nbsp; l'année dernière). Il n'est donc absolument pas envisageable d'assister à toutes les conférences. Mais celles-ci sont enregistrées et devrait être disponibles en webcast sur le site Microsoft. &lt;/p&gt; &lt;p&gt;Lors de l'inscription en ligne (gratuite), il était possible de s'inscrire aux différents sessions. Ces inscriptions ne donnent aucune garantie d'avoir une place. Les places sont servies aux premiers arrivés. On note une nette amélioration par rapport aux années précédentes : l'attribution des salles semble avoir pris en compte les pré-inscriptions, on a pu constaté qu'afin de faire face aux 3000 pré-inscriptions à la présentation de Windows 7, celle-ci a été programmée deux fois par jours en grand amphi. Cette année je n'ai pas eu l'impression qu'il y ait eu des gens refoulés à l'entrée, et je n'ai assisté qu'à une seule session dans laquelle il y a eu quelques personnes debout.&amp;nbsp; &lt;p&gt;Chaque conférence dure une heure. Le niveau technique des intervenants est très élevé. Le discours n'est pas pollué par le marketing : c'est de la technique brute. De toute manière, l'auditoire est également très technique et ne laisserait pas passer le moindre déviation marketting.&lt;br&gt;Une heure c'est court pour faire une présentation technique d'un produit : chaque présentation est donc accès sur un aspect technique d'un produit. Il ne faut pas s'attendre à une formation sur cet aspect du produit : en revanche il est tout a fait possible de savoir ce que le produit est capable de faire, ses limites et le travail à fournir pour l'utiliser.&lt;br&gt;Pour moi, cette possibilité de bien comprendre à la fois l'adaptation d'un produit à un besoin et les efforts nécessaires à leur mise en oeuvre font des techdays un événement extrêmement intéressant.&lt;br&gt;Au vu du succès persistant des séances (y compris encore lors du troisième jour), j'en déduis que cet avis était partagé par le grand nombre.  &lt;p&gt;Cette année les séances de questions/réponses à la fin des sessions ont quasiment disparu : la salle se vide rapidement à la fin de l'exposé, et ne reste que quelques irréductibles.  &lt;h3&gt;Les stands&lt;/h3&gt; &lt;p&gt;Il y a avait un grand espace stands (sur un seul niveau). Les stands partenaires étaient moins nombreux cette année. J'ai pu constater le bon niveau des interlocuteurs sur les stands.  &lt;p&gt;J'ai l'impression que l'espace qui permettait de manipuler les différents produits a disparu.  &lt;h2&gt;Affluence&lt;/h2&gt; &lt;p&gt;C'est sans aucun doute un succès indéniable de Microsoft : un monde impressionnant et des sessions pleines. Le second jour, Microsoft annonçait 6000 participants à la séance plénière initiale (à comparer au 5400 de l'année précédente et aux 4500 de la première édition). De fait l'amphi a été les 3 jours plein.  &lt;p&gt;L'organisation étant en nette amélioration et Microsoft tirant profit des deux premières années a mieux calibré les salles et les sessions. L'impression de fouillis et de trop grande affluence a complètement disparu.  &lt;h2&gt;Thèmes&lt;/h2&gt; &lt;p&gt;Les thèmes couverts sont très nombreux : cela va de la production à la méthodologie.&amp;nbsp; On va des produits de développement jusqu'aux produits d'exploitation. Il m'a semblé cette année, il n'y avait pas de sessions de R&amp;amp;D  &lt;p&gt;La variété est grande et une session n'aborde qu'un aspect du produit. Un produit est généralement couvert par une série de plusieurs sessions.  &lt;p&gt;Les produits en vogue cette année :  &lt;ul&gt; &lt;li&gt;Windows 7 et Internet Explorer 8.  &lt;li&gt;WPF et Silverlight  &lt;li&gt;Windows Azure : l'OS pour le Cloud Computing de Microsoft&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Ces trois produits ont retenu mon attention car ils apparaissent quasi systématiquement dans chaque session. Bien sur, on parle de Visual Studio, SharePoint, Biztalk... mais ces trois premiers produits semblent être omniprésents.  &lt;h3&gt;WPF et Silverlight&lt;/h3&gt; &lt;p&gt;Le choix d'une techno pour développer une interface utilisateur parait un grand challenge avec Microsoft. On dispose de pas moins de 4 solutions différents :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;WindowsForm  &lt;li&gt;WPF et sa déclinaison WPF Browser Application  &lt;li&gt;ASP.net avec ou sans Ajax  &lt;li&gt;Silverlight&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Dans tous les cas, il faudra probablement utiliser Visual Studio (qui aurait 60% de part de marché) pour le développement des règles de gestion. On peut être amené à utiliser des solutions de la gamme Expression si on souhaite faire ses propres contrôles ou faire des animations. Ma compréhension est que pour un développement d'une application de gestion standard Visual Studio suffit quelle que soit la solution.&lt;/p&gt; &lt;p&gt;Les critères influant le choix sont :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Le contrôle de l' environnement client : accès aux ressources du poste  &lt;li&gt;Le besoin du mode déconnecté et la possibilité d'une synchronisation  &lt;li&gt;Le degré d'interactivité  &lt;li&gt;Le besoin d'utiliser des animations et des transformations  &lt;li&gt;L'expérience des équipes de développement  &lt;li&gt;Les contraintes de déploiement : type de poste et possibilité d'installation en local&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Le critère le plus discriminant est le besoin de déploiement :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Asp.Net peut être déployé sur tout poste possédant un navigateur web. Le développement est susceptible de tourner dans un mobile.  &lt;li&gt;Silverlight : il nécessite l'installation d'un plug-in dans le navigateur (sa taille est de 4 à 5 Mo). Un plug-in existe pour IE, Firefox et Safari. Il tourne sur Windows et MacOs. Un portage est en cours pour Linux. A priori un développement SilverLight ne tournera pas sur un iPhone ou un Blackberry. Le portage sous Windows Mobile est en cours de route.  &lt;li&gt;WindowsForm : Il faut déployer l'application et se limiter aux postes windows  &lt;li&gt;WPF : il faut également déployer l'application ainsi que le framework .Net  &lt;li&gt;WPF Browser Application tourne dans un navigateur web mais nécessite l'installation du framework .Net en local. Cela exclu donc la plateforme MacOs.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;De mon point de vu, si vous n'avez pas besoin d'accéder aux ressources locales du poste (fichier ou autres applications par exemple) j'opterai pour une solution web.&lt;/p&gt; &lt;p&gt;Silverlight permet d'avoir des animations très puissantes, de faire du temps réel mais le temps de chargement d'une application m'a paru long. Je ne suis pas sur que cette solution soit viable à travers un réseau bas débit (genre Edge). Silverlight depuis la v2, semble plus mature : il possède plus de contrôles.&lt;/p&gt; &lt;p&gt;ASP.Net enrichi par Ajax permet de construire une application HTML Javascript avec du fenétrage et du drag &amp;amp; drop. Je suis surpris de voir que pour ASP.Net on découvre l'intérêt du MVC.&lt;/p&gt; &lt;p&gt;Dans le cas contraire, la solution que pousse actuellement Microsoft est WPF (les WindowsForm ne sont plus censées évoluer). Malheureusement la solution semble manquer de maturité même s'il y a eu une grosse amélioration depuis la sortie de Visual Studio 2008 SP1. Par exemple, il manque le DataGrid et le DatePicker même s'ils sont disponibles sur CodePlex.&lt;/p&gt; &lt;p&gt;WPF nécessite le framework 3.0 de .NET. Il repose sur DirectX et permet un affichage vectoriel. C'est cette solution qui permet de construire des présentations à base de carrousel.&lt;/p&gt; &lt;p&gt;Travaillant principalement sous Java, le pattern MVC est pour moi un acquis, j'ai donc été fort surpris de voir plusieurs sessions insister sur ce pattern pour les développements ASP.Net ou Silverlight.&lt;/p&gt; &lt;h3&gt;Silverlight avancée&lt;/h3&gt; &lt;p&gt;Il s'agit d'une série de trucs pour la programmation avancée de Silverlight. Ces aspects sont liés à une approche MVC et la volonté de conserver un historique et du deeplinking (possibilité d'accéder directement à une page par son url).&lt;/p&gt; &lt;p&gt;On a deux services ASPX :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;une page qui contient l'application Silverlight. Cette page contient un code Javascript et le code HTML. Le code Javascript cache le code HTML.  &lt;li&gt;un service REST qui renvoie les données à l'application Silverlight&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;La correspondance entre les noms des urls permet de passer de l'un à l'autre sans difficulté.&lt;/p&gt; &lt;p&gt;Un autre élément est le framework Unity qui permet de faire de l'injection de dépendances. Son mécanisme associé à la notion de Weak Event permet de faire du bootstrapping et donc du chargement de modules à la demande. Il est également possible de remplacer un service ce qui permet de faire des tests unitaires.&lt;/p&gt; &lt;p&gt;Cette solution ressemble beaucoup dans les objectifs au framework J2EE Spring. Néanmoins l'approche de Unity est moins configurable que celle de Spring. Avec Unity tout se passe par programmation, là où Spring fonctionne par fichier de configuration.&lt;/p&gt; &lt;h3&gt;Internet Explorer 8&lt;/h3&gt; &lt;p&gt;L'élément le plus important de IE 8 pour un développeur est son nouveau moteur de rendu : le parsing et le rendu ont été modifié afin de respecter les standards et l'amélioration de la rapidité.&lt;/p&gt; &lt;p&gt;Cette évolution qui permet à IE 8 de passer le test ACID2 casse la compatibilité des nombreux sites conçues pour IE 6. Un mode de compatibilité a été prévu il est activable à plusieurs niveaux :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Il est possible d'activer le mode compatibilité en cliquant sur un bouton au bout de l'url. Cela rétablit le rendu du moteur IE 6.  &lt;li&gt;Il est possible d'ajouter un tag X-UA-compatible dans la page afin d'indiquer à IE 8 d'utiliser le moteur de rendu d'IE 6.  &lt;li&gt;Il est possible d'ajouter le tag pour toutes les pages du site en modifiant le web.config de IIS. Cette opération est également possible dans Apache.  &lt;li&gt;Microsoft maintient une liste des sites non compatibles, il est possible d'indiquer au navigateur d'utiliser cette liste et de compléter cette liste.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;IE 8 rejoint l'approche de Google Chrome avec l'isolation des onglets dans des processus distincts.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;il est possible d'avoir une authentification séparée pas onglet  &lt;li&gt;le crash d'un onglet n'a pas d'impact sur les autres onglets&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Autre nouveauté de IE 8 pour les développeurs : une toolbar de profiling et déboggage.&lt;/p&gt; &lt;p&gt;Cette toolbar reprend la MS Dev Toolbar de IE 7.0 mais est cette fois directement intégrée dans IE 8. Elle ajoute des fonctionnalités de profiling et déboggage.&lt;/p&gt; &lt;p&gt;Pour les utilisateurs IE 8.0 introduit deux nouvelles fonctionnalités :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;WebSlice : permet de définir comme favori un morceau de page. Le navigateur traite le WebSlice comme un flux RSS en allant vérifier la présence d'une mise à jour.  &lt;li&gt;Accelerator : permet de déclencher des actions sur une sélection comme afficher une adresse sur une carte. Cette fonctionnalité permet d'éviter le copier/coller.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Ces fonctionnalités ne peuvent apparaître que si le site met à disposition le service des utilisateurs, ce service nécessitant du développement :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;WebSlice : il faut modifier la page HTML en ajoutant l'attribut Class HSLICE. Il existe deux autres attributs de class qui vont permettre la définition du titre et du contenu. L'activation pourra être réalisé en modifiant un attribut de class en ajoutant les nouveaux attributs ou en ajoutant de nouveaux tags class.  &lt;li&gt;Accelerator : il faut définir le service dans un fichier xml Open Service. Ce fichier disponible au niveau du navigateur permet l'apparition du menu sur le clic droit et indique au navigateur le service qu'il va devoir appeler avec la sélection.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Ces deux services ont donc tous les deux la particularité de nécessiter des développement spécifiques qui ne pourront être utilisés que par des utilisateurs de IE 8.0&lt;/p&gt; &lt;h3&gt;Windows 7 &lt;/h3&gt; &lt;p&gt;C'est le thème qui a connu le plus fort engouement : 6 sessions en grand amphi.&lt;/p&gt; &lt;p&gt;Pour Microsoft les 3 thèmes principaux de cette nouvelle version qu'ils appellent Windows Sept (le marketing a frappé) sont :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Expérience utilisateur  &lt;li&gt;Sécurité et le contrôle  &lt;li&gt;Gestion des postes de travail&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Coté expérience utilisateur, Microsoft est parti de la constatation que 75% des utilisateurs avaient 5 à 9 fenêtres ouvertes en même temps. La refonte de la barre des taches doit permettre de résoudre cette problématique tout comme la possibilité de docker une fenêtre sur un coté de l'écran.&lt;/p&gt; &lt;p&gt;Honnêtement ces deux fonctionnalités doivent pouvoir amener des gains de productivité intéressant dans l'utilisation de windows.&lt;/p&gt; &lt;p&gt;Autre élément pour l'expérience utilisateur, la recherche "unifiée" avec la Desktop Search de Vista. La présentation de cette fonctionnalité ne m'a pas paru d'une grande clarté et je n'ai pas très bien compris son principe au delà de la soupe marketing.&lt;/p&gt; &lt;p&gt;Pour finir le coté expérience utilisateur, Windows 7 est tactile sans programmation. J'ai pu jouer sur le stand Dell avec le Latitude XT2 (un tablet PC tactile présenté sous Windows 7) : c'est très agréable et efficace : la réactivité est bonne et on retrouve des sensations proches de l'iPhone.&lt;/p&gt; &lt;p&gt;Néanmoins, au delà de l'aspect tactile, l'interface n'a pas été pensé pour cela : les menus et boutons continuent d'avoir leur bonne vieille taille adaptée à une souris mais pas du tout en accord avec un doigt. Microsoft gagnerait à lire les conseils d'Apple pour le développement d'application iPhone : la taille d'un doigt étant globalement connu, cela amène un certain nombre de contraintes immédiates qu'énumère le document Apple.&lt;/p&gt; &lt;p&gt;Peut-être faut-il prévoir au niveau de Windows une modification de l'interface dès qu'elle perçoit qu'on est passé en mode tactile. &lt;/p&gt; &lt;p&gt;Pour le moment, je pense que pour un tablet PC comme le altitude XT2 de Dell, l'aspect tactile de Windows 7 est quelque chose de génial : on peut le prendre chez soi comme un livre et parcourir le web du doigt (l'iPhone se montre redoutablement efficace dans cette tâche). Pour d'autres utilisations comme la prise de note, le bon vieux stylets (également disponible sur le XT2) reste supérieur.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Pour la gestion du poste de travail, on notera tout d'abord une meilleure gestion de l'énergie qui permet un accroissement de 15% de l'autonomie. Les personnes de Dell, semblait très surprise (agréablement) de l'autonomie du XT2. Windows 7 réalise cette prouesse en désactivant les services inutiles.&lt;/p&gt; &lt;p&gt;il faut noter que Windows 7 tourne sur un netbook et que le démarrage semblait rapide : certe il s'agit d'une machine de démonstration avec 1 Go de RAM. on sait que les temps de démarrage des différents Windows se dégradent au fur et à mesure des installations et de son utilisation. Donc le test de démarrage ne peut pas être considéré comme significatif en dehors du fait que Windows 7 tourne sur un Netbook.&lt;/p&gt; &lt;p&gt;Pour les déploiements, Microsoft indique que les mêmes outils de déploiement et d'administration qui marchent avec Vista (pas avec XP) fonctionneront avec Seven. Microsoft compte également sur 3&amp;nbsp; autres solutions (qui m'ont paru nécessiter un petit supplément financier) pour faciliter la phase de transition et de déploiement :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;App-V : Les applications sont virtualisées et déployer en central. L'application tourne sur le poste Windows 7 normalement.  &lt;li&gt;MED-V on ouvre une machine virtuelle pour lancer l'application. Cette machine virtuelle peut être de type XP. Cette solution permet de réduire les problèmes de compatibilité entre une application et le système d'exploitation. L'utilisateur ne se rend compte de rien : il ne passe par sur un bureau XP. Il voit son application comme tout autre application Windows 7.  &lt;li&gt;VDI (Virtual Desktop Infrastructure) : Le PC est juste un terminal graphique comme avec Citrix.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Pour la sécurité, Windows 7 amène 4 nouveautés :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Amélioration de User account control : mais je n'ai pas vu quelles améliorations  &lt;li&gt;Bitlocker : il permet d'encrypter le contenu d'une clé USB  &lt;li&gt;AppLocker : élimine les applications interdites en permettant la définition d'une liste d'applications autorisées ou interdites. Il est possible de se limiter à une version ou de l'étendre à toutes les application d'un éditeur  &lt;li&gt;IE 8 permet d'autoriser un activex a un site &lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Du coté de la mobilité&lt;/h3&gt; &lt;p&gt;J'ai assisté à deux présentations sur le sujet toutes les deux fort décevantes. Microsoft est très en retard sur Apple (c'est l'utilisateur d'iPhone qui parle).  &lt;p&gt;Une des présentations essayait de montrer différentes applications pour Mobile toute de pale clone de version existante sur l'iPhone.  &lt;p&gt;Le plus gros reproche que l'on peut faire à Microsoft est de ne pas comprendre les enjeux du tactiles : certes toutes les applications et terminaux étaient tactiles et cela semble être une direction irrémédiable du monde mobile, mais leur interface est inadaptée : un pouce à une certaine taille et il faut accepter de faire tout les boutons d'une certaine taille, tout comme les menus et les listes clicables. C'est la règle. On a l'impression que Blackberry et Palm ont fait évoluer leur OS afin de prendre cela en considération (il suffit somme toute de copier Apple) mais Microsoft reste à la traîne obligeant les constructeur à rhabiller l'OS afin de le rendre utilisable.  &lt;h3&gt;Windows Azure et le cloud computing&lt;/h3&gt; &lt;p&gt;Il s'agit d'un des sujets phare de ces TechDays et l'affluence était au rendez-vous.  &lt;p&gt;Le Cloud Computing c'est globalement faire héberger ses applications dans un gros datacenter chez un fournisseur d'infrastructure. Cela diffère de l'hébergement classique par l'accent qui est mis sur la virtuallisation : il ne s'agit pas d'espace partagé ou d'une machine physique dédiée mais d'un environnement virtuel. On voit la boucle de la virtualisation se fermer avec l'intéret majeur que représente la virtuallisation pour le cloud computing.  &lt;p&gt;Le Cloud Computing est marketé en mettant l'accent sur le on-demand cher à IBM : je ne sais pas de quelle puissance je vais avoir besoin ou si j'ai besoin d'une forte puissance ponctuelle, le cloud computing est la solution adaptée car l'allocation est dynamique et l'on paye à la consommation.  &lt;p&gt;Le Cloud computing rejoint pour Microsoft leur slogan Software + Service qui reste pour moi une vaste fumisterie du Marketing Microsoft : vous pouvez tout faire, où plutôt tout nous acheter : acheter de bon vieux logiciel comme Windows, Word, SharePoint ou bien nous acheter des services comme Azure mais également Microsoft Live ou Microsoft Live Office dans laquelle on retrouvera SharePoint en service. N'ayez pas peur Monsieur le client, tout est légitime et stratégique.  &lt;p&gt;En langage marketing S+S c'est mélanger les différentes approches : se faire héberger et payer un service dans certain cas (offre Windows Live pour les particuliers et Office Live pour les entreprises) et acheter ses propres logiciels dans d'autres cas.  &lt;p&gt;Un point récurrent des présentations d'Azure, c'est l'importance que Microsoft accorde et met en avant sur son savoir faire en gestion de très grosses infrastructures :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;240 milliard de messages MS Messenger envoyés par mois  &lt;li&gt;10 milliard de page MSM consultés par mois  &lt;li&gt;10 000 serveurs ajoutés par mois à son infrastructure&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;On apprend que Microsoft prévoit l'ouverture de 3 nouveaux datacenter (500 M$ chacun d'investissement) et que Microsoft est maintenant capable de construire en 3 mois un DataCenter, là ou il y a deux ans il leur fallait 18 mois.  &lt;p&gt;Microsoft veut être perçu comme un acteur majeur de l'hébergement avec en ligne de mire Google et Amazon. Pour ceux qui ne le savent pas, Amazon avec son offre Amazon ec2 est probablement le premier arrivé dans ce domaine du Cloud Computing.&lt;/p&gt; &lt;p&gt;Le Cloud Computing est un secteur à gros investissement (un datacenter de l'ordre de 500 M$) qui nécessite un savoir faire dans l'administration et la gestion de ce type d'infrastructure.&lt;br&gt;&lt;/p&gt; &lt;p&gt;Windows Azure est une offre en construction : ce que l'on peut dire c'est qu'il s'agit de service car c'est Microsoft qui héberge vos applications. Microsoft prend à sa charge les coûts d'exploitation et d'administration. L'approche est de permettre grâce à la virtuallisation des gains d'échelle sur l'exploitation grâce à un meilleur savoir faire notamment en gestion de l'énergie.&lt;/p&gt; &lt;p&gt;Le service comprend à la fois l'hébergement physique mais également ce qui conviendrait d'appeler un "système d'exploitation virtuel" : c'est probablement ce qu'il convient d'appeler Azure. Au dessus de ce système d'exploitation, il y a une série de services techniques (comme le stockage de données) qui s'appelle Azure Services Platform. &lt;/p&gt; &lt;p&gt;Contrairement à de l'hébergement dédié où l'on doit gérer sa plate-forme et ses mises à jour, là tout est compris mais il n'est pas possible d'espérer rester sur une version antérieur : on retrouve le principe de la beta permanente du Web 2.0. Il faudra donc bien gérer ses différentes interfaces.&lt;/p&gt; &lt;p&gt;Aujourd'hui Azure est en beta, il est possible de demander un jeton qui donne droit à un projet et 50 Go de stockage. Attention, il faut des jetons pour chaque service comme l'identification ou le stockage.&lt;/p&gt; &lt;p&gt;Nous allons maintenant nous concentrer sur Azure l'OS pour le cloud et le développement d'application.&lt;/p&gt; &lt;p&gt;Un projet correspond à une machine virtuelle dont la création a été pris en charge par Microsoft : vous disposez de deux environnement : production et pré-production avec pour ce dernier une url temporaire.&lt;/p&gt; &lt;p&gt;La programmation est pour l'heure exclusivement en .Net : il existe des templates de projet dans Visual Studio qui sont dédié à Azure. Microsoft fait miroiter l'ouverture dans le futur au développement PHP, Ruby ou même Java. Il est vrai qu'un hébergeur se doit d'être "ouvert" et beaucoup d'intervenants (je ne parle pas que de Azure) ont pris soin de montrer que certaines solutions Microsft s'interfacer parfaitement avec d'autres technologies. Il sera peut-être même possible d'héberger grâce à la virtuallisation des applications en code non-managé.&lt;/p&gt; &lt;p&gt;Néanmoins aujourd'hui pour développer pour Azure, se sera avec Visual Studio en .Net sous Vista. XP n'est pas et ne sera pas supporté : il est possible de tester le développement en local mais cela nécessite IIS 7 qui ne tourne pas sous XP.&lt;/p&gt; &lt;p&gt;Les API de Azure sont orientées Cloud computing on retrouve notamment les services suivants :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Stockage : même si cela repose sur une version de SQL server, il ne s'agit pas de SQL. On retrouve des tables et des blobs.  &lt;li&gt;Identification : on utilise la connexion Windows Live. Il travaille actuellement sur le support de la norme OpenId  &lt;li&gt;Communication par messages avec des services de queue  &lt;li&gt;Des services pour le déploiement avec la production et préproduction  &lt;li&gt;Des services d'administrations avec notamment un service de log. Les logs sont stockées comme un BLOB qu'il est ensuite facile de récupérer pour analyse.  &lt;li&gt;Data Sync : un service pour utilisateur occasionnel  &lt;li&gt;Workflow qui assure le support de scénario  &lt;li&gt;ESB qui est une sorte de bus dans le cloud.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Tous les services sont accessibles à travers un service REST (il est donc possible de les appeler depuis du Java) y compris le service de stockage.&lt;/p&gt; &lt;p&gt;La programmation doit tenir compte d'un premier aspect primordial : on doit travailler en mode medium trust (le mode de mutualisation des applications web). Il faudra ensuite faire très attention à la Retry Policies : c'est le comportement d'une application quand un utilisateur plus ou moins patient clique plusieurs fois sur un même bouton. Ce point est très important en Web et donc sur le cloud.&lt;/p&gt; &lt;p&gt;Azure distingue 2 rôles :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Rôles web aspx : création d'une interface web  &lt;li&gt;Rôle worker .cs batch : création d'un traitement&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;L'offre Azure semble être quelque chose de très intéressant : on sent toute la puissance et la cohérence des investissements de Microsoft. Il s'agit probablement pour Microsoft d'un enjeux majeur voir de l'enjeux majeur et identifier comme tel. &lt;br&gt;&lt;/p&gt; &lt;h3&gt;La Programmation fonctionnelle&lt;/h3&gt; &lt;p&gt;La programmation fonctionnelle est un des axes de réflexion de la R&amp;amp;D de Microsoft. Sa déclinaison "commerciale" est le langage F#. &lt;p&gt;Les langages classiques sont des langages impératifs : on donne des ordres explicites à la machine. On programme la machine : on lui dit ce qu'elle doit faire et dans quel ordre. Cette approche nécessite de déclarer les variables. Cette approche est difficilement parallelisable : on pilote la machine étape par étape. &lt;p&gt;La programmation fonctionnelle se veut déclarative : le compilateur ou la machine virtuelle pourra plus facilement optimiser la parallelisation des traitements. Je pense que l'importance que revêt pour Microsoft cette approche repose principalement sur cette possibilité de parallélisation accrue : pour Microsoft, il n'est plus possible de pousser le cadencement des processeurs, il faut s'orienter vers des approches multi-coeur ou multi-processeurs : dans ces deux cas, la parallélisation est importante pour profiter pleinement des nouvelles architectures. C'est pour cette raison que la programmation focntionnelle a besoin de définir de l'asynchronisme et des points de rencontre/synchronisation. &lt;p&gt;Microsoft semble considérer linq (solution de mapping objet/relationnel proche de hibernate et de jpa) comme une approche de type déclarative alors que le SQL repose sur une approche impérative. &lt;p&gt;Le F# est loin de me paraître plus compréhensible que le C# (sachant que je ne connais ni l'un ni l'autre et qu'ils sont très proche en terme de syntaxe). De mon point de vu, le F# est un projet de long haleine pour Microsoft qui n'a pas réellement d'utilité immédiate aujourd'hui. &lt;p&gt;La présentation a mis l'accent sur la possibilité et les intérêts de ne pas typer en F# : le var du C# (solution qui permet de ne pas définir le type d'une variable en lui disant de prendre le type du coté gauche de l'expression). &lt;p&gt;Le typage en F# permet une approche générique qui permet de travailler avec un type inconnu qui est résolu plus tard dans le code ou ailleurs. Attention ! le type est connu par l'éditeur, l'intellisense fonctionne ! &lt;p&gt;Dans cette perspective de typage, le Let doit être vu comme un binding permettant de résoudre un typage et non pas comme une affectation simple. &lt;h2&gt;Conclusion&lt;/h2&gt; &lt;p&gt;les Techdays ont été comme les années précédentes à la hauteur de mes attentes. Microsoft a su améliorer son organisation rendant moins sensible la grande affluence de cet événement.&lt;/p&gt; &lt;p&gt;Les deux axes futures à moyen terme qui m'ont paru intéressant sont : Silverlight et Azure. La programmation fonctionnelle est quelque chose qui reste pour moi très lointain et Windows 7 est du présent.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-2716507091132176141?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/2716507091132176141/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=2716507091132176141&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/2716507091132176141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/2716507091132176141'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2009/02/microsoft-techdays-2009.html' title='Microsoft TechDays 2009'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-1452311629170960574</id><published>2008-11-22T22:18:00.002+02:00</published><updated>2008-11-22T22:21:20.323+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>StreetView de l'iPhone 2.2</title><content type='html'>&lt;p&gt;La dernière mise à jour (au 22/11/2008) du firmware de l'iPhone inclus une évolution majeure du logiciel de cartographie Google Map : Plans.&lt;/p&gt; &lt;p&gt;La fonctionnalité StreetView  de Google a été ajouté. Cette fonctionnalité est réellement surprenante et permet de visualiser la rue, un rond point comme si on y était.&lt;/p&gt; &lt;p&gt;L'utilisation de StreetView n'est pas des plus intuitives c'est pourquoi je vous propose un rapide tutorial illustré.&lt;/p&gt; &lt;p&gt;La première étape est d'ouvrir l'application Plan. On se place sur le lieux qui nous intéresse : disons par exemple la place de l'Etoile à Paris&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SSho5jJ0ikI/AAAAAAAABFU/vQCtafnWShU/s1600-h/S1GooglePlan2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S1GooglePlan" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SSho6r22-QI/AAAAAAAABFY/fZV_d6B4Wi8/S1GooglePlan_thumb.jpg?imgmax=800" width="164" border="0" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;StreetView est accessible depuis le mode Plan ou le mode Satellite (c'est au choix). Pour l'activer, il faut placer un repère. Pour cela, il faut que le lieux visé soit si possible au centre de l'écran. On appuie sur l'image en bas à droite de la page qui se soulève. &lt;/p&gt; &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SSho7mKsT1I/AAAAAAAABFc/g4rCxLq2hmw/s1600-h/S2PlacerRepere2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S2PlacerRepere" src="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SSho8Qbx8ZI/AAAAAAAABFg/7EYc1GuAqLs/S2PlacerRepere_thumb.jpg?imgmax=800" width="164" border="0" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;On appuie sur Replacer le repère et on obtient :&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/SSho84Oc__I/AAAAAAAABFk/hOO1k9b7XOY/s1600-h/s3Repere2.jpg"&gt;&lt;img style="border-width: 0px;" alt="s3Repere" src="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SSho9vToOrI/AAAAAAAABFo/oZV34EqCUNA/s3Repere_thumb.jpg?imgmax=800" width="164" border="0" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Notez, le petit icône orange à gauche de Faite glisser le repère. Si vous attendez quelques secondes, le nom du lieu apparaît sous Faite glisser le repère.&lt;/p&gt; &lt;p&gt;Si vous appuyez sur l'icone Orange vous basculer en mode StreetView (j'imagine que le petit bonhomme blanc symbolise le piéton qui se promène pour nous dans les rues de Paris).&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/SSho-EKTO_I/AAAAAAAABFs/7Yt4VugmVwU/s1600-h/S4StreetViewH2.jpg"&gt;&lt;/a&gt;&lt;a href="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SSho-yMX1BI/AAAAAAAABFw/koa_LZF9zME/s1600-h/S4StreetView2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S4StreetView" src="http://lh4.ggpht.com/_Y8Z3ymNuOiE/SSho_qI9_PI/AAAAAAAABF0/ufPBJgGHCaI/S4StreetView_thumb.jpg?imgmax=800" width="244" border="0" height="164" /&gt;&lt;/a&gt;  &lt;/p&gt;  &lt;p&gt;Le mode StreetView nécessite de tenir l'iPhone en mode paysage. Le petit cercle en bas à droite indique notre position sur le plan. La zone plus clair indique notre angle de vue.&lt;/p&gt; &lt;p&gt;Vous pouvez utiliser votre doigt pour faire tourner la vue et découvrir l'arc de Triomphe :&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SShpAPCkUZI/AAAAAAAABF4/NU8yx0tpe-k/s1600-h/S5ArcTriomphe2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S5ArcTriomphe" src="http://lh3.ggpht.com/_Y8Z3ymNuOiE/SShpAhuc7JI/AAAAAAAABF8/Esde6evmCzc/S5ArcTriomphe_thumb.jpg?imgmax=800" width="244" border="0" height="164" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Par moment quand vous tourner vous voyez apparaître une ligne au sol avec des flèches.&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/SShpBMovT1I/AAAAAAAABGA/1U37oYym200/s1600-h/S6NomRue2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S6NomRue" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SShpB6udR3I/AAAAAAAABGE/-51AFDgn-90/S6NomRue_thumb.jpg?imgmax=800" width="244" border="0" height="164" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Ceux sont les axes que vous pouvez parcourir avec StreetView : vous allez pouvoir avancer en le suivant. Il y a également le nom de la rue qui est inscrit : cela nécessite de regarder vers le bas : Utilisez pour cela votre doigt (un mouvement du haut vers le bas).&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Y8Z3ymNuOiE/SShpC7b4F7I/AAAAAAAABGI/EfrcsbDkJiI/s1600-h/S7NomRue5.jpg"&gt;&lt;img style="border-width: 0px;" alt="S7NomRue" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SShpD59F6jI/AAAAAAAABGM/GbsUcLqVDDY/S7NomRue_thumb1.jpg?imgmax=800" width="244" border="0" height="164" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Pour avancer, appuyer sur la flèche que vous voyez au loin. Attention, on avance doucement et il faut patienter un petit peu entre chaque coup.&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SShpERRn1SI/AAAAAAAABGQ/hsx4h9Fmgf4/s1600-h/S8Wagram2.jpg"&gt;&lt;img style="border-width: 0px;" alt="S8Wagram" src="http://lh5.ggpht.com/_Y8Z3ymNuOiE/SShpFDTcIcI/AAAAAAAABGU/ea03jpjV-DY/S8Wagram_thumb.jpg?imgmax=800" width="244" border="0" height="164" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Si vous voulez avancer plus vite n'attendez pas que l'image s'affiche et appuyez de nouveau sur la flèche. Vous pouvez appuyer plusieurs fois d'affilées et progresser ainsi plus rapidement. Le petit cercle est mise à jour, vous pouvez ainsi surveiller votre progression.&lt;/p&gt; &lt;p&gt;Pour sortir du mode StreetView il suffit d'appuyer sur le cercle. On revient à la vue du Plan.&lt;/p&gt; &lt;p&gt;Et voila, on a fait un tour de la fonctionnalité StreetView du firmware 2.2 de l'iPhone. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-1452311629170960574?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/1452311629170960574/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=1452311629170960574&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1452311629170960574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/1452311629170960574'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2008/11/streetview-de-l-22.html' title='StreetView de l&amp;#39;iPhone 2.2'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Y8Z3ymNuOiE/SSho6r22-QI/AAAAAAAABFY/fZV_d6B4Wi8/s72-c/S1GooglePlan_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-3111411003545961221</id><published>2008-08-29T22:44:00.005+02:00</published><updated>2008-08-29T23:00:14.701+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>Comment desimlocker légalement son iPhone v1 ?</title><content type='html'>Un grand nombre d'iPhone v1 ont été acheté il y a plus de 6 mois. Si c'est votre cas vous pouvez le déverrouiller en toute légalité. Une fois déverrouillé vous pourrez utiliser votre iPhone avec une autre carte SIM d'un autre opérateur. &lt;p&gt;La procédure est relativement simple : &lt;/p&gt; &lt;ol&gt; &lt;li&gt;elle commence par un appel au service client d'Orange : le 700 depuis votre mobile ou 3970 depuis une ligne fixe. Tapez le 9 pour parler à un conseiller.&lt;/li&gt; &lt;li&gt;Le conseiller va vous demander le numéro de la ligne et le code IMEI de l'iPhone. Il est accessible dans Réglage -&amp;gt; Générale -&amp;gt; Informations et IMEI ou tout simplement au dos de votre iPhone.&lt;/li&gt; &lt;li&gt;Après vérification que cela fait bien plus de 6 mois que l'iPhone est en votre possession, il demande un email. C'est à cet email qu'Apple enverra la procédure pour déverrouiller l'iPhone&lt;/li&gt; &lt;li&gt;Quelques jours après cet appel (1 jour dans mon cas) vous recevrez un email décrivant la procédure.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Avant de suivre la procédure, il est souhaitable de faire une synchronisation avec votre PC. Il peut être utile au préalable de vous assurer d'avoir installé la dernière version du Firmware de l'iPhone. Je ne l'avais pas fait et la procédure a différé de celle décrite dans l'email et je n'ai pu éviter l'installation de la 2.0.2. &lt;/p&gt;&lt;p&gt;La procédure de synchronisation consiste : &lt;/p&gt;&lt;ol&gt; &lt;li&gt;Connecter son PC à Internet. Cela est fondamentale car je pense que iTunes va vérifier sur un site d'Apple qu'il peut bien desimlocker voter iPhone.&lt;/li&gt; &lt;li&gt;Il faut brancher son iPhone au PC.&lt;/li&gt; &lt;li&gt;Il faut appuyer sur le bouton Restaurer&lt;/li&gt; &lt;li&gt;Si comme moi la version de l'iPhone est ancienne, il affiche le message ci-dessous, vous n'avez que le choix d'opter pour une Restauration et mise à jour. Il va installer la nouvelle version.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Y8Z3ymNuOiE/SLhggTdgYEI/AAAAAAAAA44/3eMDMrPcXVc/s1600-h/ITunesRestaurerMessage.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_Y8Z3ymNuOiE/SLhggTdgYEI/AAAAAAAAA44/3eMDMrPcXVc/s320/ITunesRestaurerMessage.JPG" alt="" id="BLOGGER_PHOTO_ID_5240044274541682754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;A la fin du processus, il indique que la SIM est Locked. Il faut la déverrouiller en tapant votre code. &lt;/p&gt;&lt;p&gt;A la fin du processus, vous devriez voir apparaître le message suivant : &lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Y8Z3ymNuOiE/SLhgVBlBHNI/AAAAAAAAA4w/6qUAf9AiKI0/s1600-h/ITunesDeverouille.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_Y8Z3ymNuOiE/SLhgVBlBHNI/AAAAAAAAA4w/6qUAf9AiKI0/s320/ITunesDeverouille.JPG" alt="" id="BLOGGER_PHOTO_ID_5240044080762789074" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Vous n'aurez que le choix de continuer, il propose de reconfigurer votre iPhone : &lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Y8Z3ymNuOiE/SLhgFuLyN7I/AAAAAAAAA4o/msapZiX_rkE/s1600-h/ITunesConfigurer.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_Y8Z3ymNuOiE/SLhgFuLyN7I/AAAAAAAAA4o/msapZiX_rkE/s320/ITunesConfigurer.JPG" alt="" id="BLOGGER_PHOTO_ID_5240043817858643890" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Pour ma part, j'ai choisi l'option Restaurer à partir de la sauvegarde. &lt;/p&gt;&lt;p&gt;Après quelques minutes, votre iPhone est enfin déverrouillé. &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;Maintenant si vous éteignez votre iPhone vous pouvez changer de carte SIM et mettre celle d'un autre opérateur. Vous pouvez le rallumer, vous pouvez utiliser pour appeler, votre carnet d'adresse et votre calendrier son toujours présent. En fait seul le réseau a changé. &lt;/p&gt;&lt;p&gt;Vous pouvez synchroniser et mettre à jour votre iPhone avec iTunes sans problème. &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;En conclusion, la procédure est simple même si elle peut être un peu longue. J'ai été fort surpris de la bonne volonté du conseiller Orange. Il suffit juste de demander. &lt;/p&gt;&lt;p&gt;Attention ! La procédure peut laisser penser qu'on peut déverrouiller son iPhone en faisant un Restaurer. Ce n'est pas le cas, la procédure, doit vérifier dans une base de données qu'il est possible de le déverrouiller.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Dans la série iPhone, vous pouvez consulter ces autres billets :&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2008/01/se-prparer-pour-l-et-la-synchronisation.html"&gt;Se préparer pour l'iPhone et la synchronisation Outlook&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2008/04/retour-d-iphone.html"&gt;Retour d'expérience de l'iPhone&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2008/01/iphone-wi-fi-orange-et-internet.html"&gt;Utilisation du Wifi avec l'iPhone&lt;/a&gt; : que ce soit sa box personnel ou d'un hotspot Wifi&lt;/li&gt;&lt;li&gt;&lt;a href="http://jl2tho.blogspot.com/2008/08/comment-synchroniser-son-iphone-avec-un.html"&gt;Comment synchroniser son iPhone avec un nouvel ordinateur ?&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36895966-3111411003545961221?l=jl2tho.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jl2tho.blogspot.com/feeds/3111411003545961221/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36895966&amp;postID=3111411003545961221&amp;isPopup=true' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/3111411003545961221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36895966/posts/default/3111411003545961221'/><link rel='alternate' type='text/html' href='http://jl2tho.blogspot.com/2008/08/comment-desimlocker-lgalement-son.html' title='Comment desimlocker légalement son iPhone v1 ?'/><author><name>jl2tho</name><uri>http://www.blogger.com/profile/07861296648178815984</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://1.bp.blogspot.com/_Y8Z3ymNuOiE/TQJ73xsxt7I/AAAAAAAADgw/OlXt2Ug-X6U/S220/PhotoJLT.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Y8Z3ymNuOiE/SLhggTdgYEI/AAAAAAAAA44/3eMDMrPcXVc/s72-c/ITunesRestaurerMessage.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36895966.post-5108441537851710906</id><published>2008-08-18T23:11:00.001+02:00</published><updated>2008-08-18T23:11:06.340+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>Divers chiffres du succès de l'iPhone et de leur interprétation</title><content type='html'>&lt;p&gt;L'origine de ce billet réside dans une réaction à l'interprétation abusive faite par plusieurs sites grand public d'un communiqué de Mediamétrie : l'augmentation du traffic en provenance de l'iPhone serait due à un changement d'habitude due à la 3G.&lt;/p&gt; &lt;p&gt;Médiametrie est un organisme qui surveille l'audience de différents sources de diffusion : traditionnellement la télé et la radio mais également l'internet. L'étude de médiamétrie peut être trouvé là : &lt;a t
