Aujourd’hui nous verrons comment publier un web service depuis Camel . Il y a plusieurs façons de le faire. En fait c’est très simple avec Spring. Cependant, ça l’est moins quand il faut traiter une requête entrante et déclencher le bon routage en fonction de la méthode invoquée.
Il faut donc tester une en-tête du message qui contient la méthode invoquée. Pour se faire, il y a deux méthodes. Nous allons faire tourner le tout sur un Tomcat (cf article précédent ). Prenons donc cette belle interface représentant notre non moins magnifique service :
package org.giwi.camel.ws;import javax.jws.WebParam;import javax.jws.WebResult;@javax .jws.WebService(name = "sayHelloService" , targetNamespace = "http://giwi.free.fr" )public interface SayHelloService { @WebResult(name = "status") public String sayHello (@WebParam(name = "name") String name) ; @WebResult(name = "status") public String sayGoodby (@WebParam(name = "name") String name) ; }
Et ce splendide ApplicationContext.xml :
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:cxf ="http://camel.apache.org/schema/cxf" xmlns:http ="http://cxf.apache.org/transports/http/configuration" xmlns:sec ="http://cxf.apache.org/configuration/security" xsi:schemaLocation =" http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.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" /> <camelContext xmlns ="http://camel.apache.org/schema/spring" > <package > org.giwi.camel.route</package > </camelContext > </beans >
La première consiste à utiliser l’EIP “Content Based Router “ :
package org.giwi.camel.route;import org.apache.camel.Exchange;import org.apache.camel.Processor;import org.apache.camel.builder.RouteBuilder;import org.apache.camel.component.cxf.CxfConstants;public class SayHelloRoute extends RouteBuilder { @Override public void configure () throws Exception { from("cxf:/helloService?serviceClass=org.giwi.camel.ws.SayHelloService" ) .choice() .when (header(CxfConstants.OPERATION\_NAME).isEqualTo("sayHello" )) .to("direct:sayHello1" ) .when (header(CxfConstants.OPERATION\_NAME).isEqualTo("sayGoodby" )) .to("direct:sayGoodBy1" ) .otherwise().throwException(new Exception ("unknown method" )); from("direct:sayHello1" ).process(new Processor () { @Override public void process (Exchange ex) throws Exception { ex.getOut().setBody("hello" ); } }); from("direct:sayGoodBy1" ).process(new Processor () { @Override public void process (Exchange ex) throws Exception { ex.getOut().setBody("goodby" ); } }); } }
Bref, c’est un peu lourd. La seconde méthode consiste à utiliser l’EIP “Recipient List “ :
package org.giwi.camel.route;import org.apache.camel.Exchange;import org.apache.camel.Processor;import org.apache.camel.builder.RouteBuilder;public class SayBetterHello extends RouteBuilder { @Override public void configure () throws Exception { from("cxf:/helloBetterService?serviceClass=org.giwi.camel.ws.SayHelloService" ) .recipientList(simple("direct:${header.operationName}2" )); from("direct:sayHello2" ).process(new Processor () { @Override public void process (Exchange ex) throws Exception { ex.getOut().setBody("hello" ); } }); from("direct:sayGoodby2" ).process(new Processor () { @Override public void process (Exchange ex) throws Exception { ex.getOut().setBody("goodby" ); } }); } }
Plus simple, non?
Camel CXF avec Spring Boot (approche moderne) Quinze ans plus tard, les choses ont bien changé. Avec Spring Boot et les starters Camel, plus besoin de tout ce XML. Voici la version moderne avec camel-cxf-starter.
Dépendances Maven <dependency > <groupId > org.apache.camel.springboot</groupId > <artifactId > camel-spring-boot-starter</artifactId > <version > 4.4.0</version > </dependency > <dependency > <groupId > org.apache.camel.springboot</groupId > <artifactId > camel-cxf-starter</artifactId > <version > 4.4.0</version > </dependency > <dependency > <groupId > org.apache.cxf</groupId > <artifactId > cxf-rt-frontend-jaxws</artifactId > <version > 4.0.5</version > </dependency >
Configuration dans application.yml camel: springboot: name: CamelCxfService cxf: path: /services camel: component: cxf: address: http://localhost:8080/services/hello service-class: org.giwi.camel.ws.SayHelloService
Route Spring Boot moderne @Component public class SayHelloRoute extends RouteBuilder { @Override public void configure () { from("cxf:bean:helloEndpoint" ) .choice() .when (header(CxfConstants.OPERATION_NAME).isEqualTo("sayHello" )) .transform(constant("Hello depuis Spring Boot !" )) .when (header(CxfConstants.OPERATION_NAME).isEqualTo("sayGoodby" )) .transform(constant("Goodbye depuis Spring Boot !" )) .otherwise() .throwException(new IllegalArgumentException ("Méthode inconnue" )); } }
Et la configuration du endpoint CXF @Configuration public class CxfConfig { @Bean public CxfEndpoint helloEndpoint () { CxfEndpoint endpoint = new CxfEndpoint (); endpoint.setAddress("/helloBetterService" ); endpoint.setServiceClass(SayHelloService.class); return endpoint; } }
REST vs SOAP avec Camel Aujourd’hui, on préfère souvent REST aux services SOAP . Camel le fait aussi en quelques lignes :
@Component public class RestRoute extends RouteBuilder { @Override public void configure () { restConfiguration() .component("servlet" ) .port(8080 ) .bindingMode(RestBindingMode.json); rest("/hello" ) .get("/{name}" ) .to("direct:sayHello" ) .post() .type(Personne.class) .outType(String.class) .to("direct:sayHelloPost" ); from("direct:sayHello" ) .transform(simple("Hello ${header.name} !" )); from("direct:sayHelloPost" ) .log("Reçu: ${body}" ) .transform(simple("Bonjour ${body.nom} !" )); } }
La tendance actuelle est au REST JSON, mais SOAP reste très présent dans le monde de l’assurance, de la banque et des ERP. Camel gère les deux avec la même élégance.