Pour implémenter les web-services dans ePims nous utilisons la technologie apache CXF (Celtix-XFire). Cette librairie permet, entre autres, de créer très facilement, en collaboration avec Spring, des web-services à partir d'interface déjà écrite.
Il faut tout d'abord importer les librairies nécessaires au fonctionnement de CXF. Pour l'utilisation faîtes dans ePims il est nécessaire de prendre les dépendances suivantes (facilement retrouvable grâce à la target resolve
des build.xml).
commons-logging-1.1.jar geronimo-activation_1.1_spec-1.0-M1.jar (or Sun's Activation jar) geronimo-annotation_1.0_spec-1.1.jar (JSR 250) geronimo-javamail_1.4_spec-1.0-M1.jar (or Sun's JavaMail jar) geronimo-servlet_2.5_spec-1.1-M1.jar (or Sun's Servlet jar) geronimo-ws-metadata_2.0_spec-1.1.1.jar (JSR 181) jaxb-api-2.0.jar jaxb-impl-2.0.5.jar jaxws-api-2.0.jar neethi-2.0.jar saaj-api-1.3.jar saaj-impl-1.3.jar stax-api-1.0.1.jar wsdl4j-1.6.1.jar wstx-asl-3.2.1.jar XmlSchema-1.2.jar xml-resolver-1.2.jar
Librairie nécessaire si le databinding utilisé est celui d'Aegis :
jdom-1.0.jar
Côté serveur il faut tout d'abord écrire l'interface comportant les méthodes des services voulus ainsi que la classe d'implémentation de cette interface (nous prendrons respectivement pour exemple l'interface IPlateServices
et son implémentation PlateServices
). L'interface va servir à exposer en web-services uniquement les méthodes voulues et non pas toutes les méthodes présentes dans l'implémentation.
Afin d'exposer ces méthodes en web-services il faut configurer CXF et créer ou modifier 3 fichiers.
PlateServices
) et de définir ses propriétés (delegate
est un attribut de la classe). A noter : l'identifiant de ce bean, qui sera utilisé ensuite.<bean id="plateServices" class="cea.edyp.platews.services.PlateServices"> <property name="delegate"> <ref bean="robotPlanningService"></ref> </property> </bean>
simple:server
. Les “champs” à compléter sont :<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:simple="http://cxf.apache.org/simple" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <simple:server id="plateServicesEndPoint" serviceClass="cea.edyp.platews.services.IPlateServices" address="/PlateServices"> <simple:serviceBean> <ref bean="plateServices" /> </simple:serviceBean> <simple:dataBinding> <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" /> </simple:dataBinding> </simple:server>
Nota: le simple:dataBinding
permet de forcer CXF à utiliser Aegis comme transformateur Java → XML. Par défaut il utilise JAXB, mais celui-ci s'est révélé, au moment de l'intégration de CXF au projet, source de bug.
<context-param> <param-name>contextConfigLocation</param-name> <param-value> WEB-INF/springWSAppContext.xml WEB-INF/services.xml </param-value> </context-param> <!-- Spring Listener --> <!-- Bientôt "obsolète" apparement, a verifier dans les prochaines versions de CXF --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- Servlets --> <!-- CXF servlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
En dehors des tests unitaires on peut tester le fonctionnement des web-services en les interrogeant avec des logiciels dédiés. Exemple : SoapUI. Afin que le logiciel puisse construire des requêtes pour les services il faut lui donner le WSDL (le fichier de description du service). Celui-ci peut être atteint en ajoutant ?WSDL
à l'adresse du web-services. Pour notre exemple précédant l'url du WSDL sera donc http://edyp-epims:8008/eP-WS/PlateServices?WSDL.
La méthode de création de client utilisée dans ePims se base sur l'utilisation des interfaces des web-services. L'exemple pour cette partie sera pris sur la classe WSDataProvider
qui permet d'interroger les services fournis par PlateServices
.
WSDataProvider
), un attribut client du type de l'interface du services (accessible dans eP-Plate grâce à la librairie de communication eP-CoL).private IPlateServices client;
ClientProxyFactoryBean
). Il faut lui donner la classe du service (IPlateServices
), l'url à interroger (exemple http://edyp-epims:8008/eP-WS/PlateServices) et, accessoirement, le databinding à utiliser (pour des raisons de compatibilité avec le serveur nous utilisons aussi Aegis pour le client). Puis il suffit de demander à la fabrique de créer le client et de l'affecter à notre attribut précédemment déclaré.ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); factory.setServiceClass(IPlateServices.class); factory.setAddress(url.toString()); factory.getServiceFactory().setDataBinding(new AegisDatabinding()); client = (IPlateServices) factory.create();
IComVirtualPlate results = client.getVirtualPlate(name);
CXF lancera automatiquement une requête SOAP correctement formé à l'url donnée à la fabrique, attendra la réponse, la traitera et la fournira comme renvoie de la méthode appelée. Attention : les objets renvoyés par CXF sont du bon type mais sont des proxy : ils n'ont que les méthodes d'accès get/set aux attributs, il faut donc faire une transposition de ces objets en vrai objets voulu.
endpoint
au tout début des l'implémentation, en lieu et place des server
(cf le web.xml plus haut) mais ceux-ci générais une erreur au déploiement de l'application : Error creating bean with name 'plateServicesEndPoint': Invocation of init method failed; nested exception is java.security.AccessControlException: access denied (javax.xml.ws.WebServicePermission publishEndpoint )
SecurityManager
de Tomcat auquel doit faire appel CXF (spec JEE5) pour autoriser la publication (PUBLISH_PERMISSION
) des endpoint
.endpoint
des server
qui eux n'ont pas besoin de PUBLISH_PERMISSION. endpoint
, mais nous n'avons pas réussi à le faire.