We will go through creating and implementating web services in our openhub-example module.
VersioningUse versions in format <major>.<minor>. Minor version is for compatible changes, major version indicates non-compatible changes. Versioning should be explicit - it means to present version number in elements, URLs etc.:
If there is change in WSDL's version then change versions of XSDs as well. See Best practices for more development tips. |
hello-v1.0.wsdl:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="http://openhubframework.org/ws/Common-v1" xmlns:tns="http://openhubframework.org/ws/HelloService-v1" targetNamespace="http://openhubframework.org/ws/HelloService-v1"> <wsdl:types> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"> <xs:import namespace="http://openhubframework.org/ws/HelloService-v1" schemaLocation="helloOperations-v1.0.xsd"/> </xs:schema> </wsdl:types> <wsdl:message name="traceHeaderMsg"> <wsdl:part element="cc:traceHeader" name="traceHeader"/> </wsdl:message> <wsdl:message name="syncHelloRequestMsg"> <wsdl:part element="tns:syncHelloRequest" name="syncHelloRequest"> </wsdl:part> </wsdl:message> <wsdl:message name="syncHelloResponseMsg"> <wsdl:part element="tns:syncHelloResponse" name="syncHelloResponse"> </wsdl:part> </wsdl:message> <wsdl:message name="asyncHelloRequestMsg"> <wsdl:part element="tns:asyncHelloRequest" name="asyncHelloRequest"> </wsdl:part> </wsdl:message> <wsdl:message name="asyncHelloResponseMsg"> <wsdl:part element="tns:asyncHelloResponse" name="asyncHelloResponse"> </wsdl:part> </wsdl:message> <wsdl:portType name="hello-v1.0"> <wsdl:operation name="syncHello"> <wsdl:input message="tns:syncHelloRequestMsg" name="syncHelloRequest"> </wsdl:input> <wsdl:output message="tns:syncHelloResponseMsg" name="syncHelloResponse"> </wsdl:output> </wsdl:operation> <wsdl:operation name="asyncHello"> <wsdl:input message="tns:asyncHelloRequestMsg" name="asyncHelloRequest"> </wsdl:input> <wsdl:output message="tns:asyncHelloResponseMsg" name="asyncHelloResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="helloBindingSoap11-v1.0" type="tns:hello-v1.0"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="syncHello"> <soap:operation soapAction=""/> <wsdl:input name="syncHelloRequest"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="syncHelloResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="asyncHello"> <soap:operation soapAction=""/> <wsdl:input name="asyncHelloRequest"> <soap:header message="tns:traceHeaderMsg" part="traceHeader" use="literal"/> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="asyncHelloResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="helloService-v1.0"> <wsdl:port binding="tns:helloBindingSoap11-v1.0" name="helloSoap11-v1.0"> <soap:address location="/ws/hello/v1"/> </wsdl:port> </wsdl:service> </wsdl:definitions> |
helloOperations-v1.0.xsd:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:cc="http://openhubframework.org/ws/Common-v1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://openhubframework.org/ws/HelloService-v1"> <!-- Note: all XSD/WSDL files are copied together at one place during XJC (Maven) code generation --> <xs:import namespace="http://openhubframework.org/ws/Common-v1" schemaLocation="commonTypes-v1.0.xsd"/> <!-- syncHello --> <xs:element name="syncHelloRequest"> <xs:annotation> <xs:documentation>Synchronous calling of hello service</xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element name="name" type="xs:string"> <xs:annotation> <xs:documentation>Greeting's name</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="syncHelloResponse"> <xs:complexType> <xs:sequence> <xs:element name="greeting" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> <!-- asyncHello --> <xs:element name="asyncHelloRequest"> <xs:annotation> <xs:documentation>Asynchronous calling of hello service</xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element name="name" type="xs:string"> <xs:annotation> <xs:documentation>Greeting's name</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="asyncHelloResponse"> <xs:complexType> <xs:sequence> <xs:element name="confirmAsyncHello" type="cc:callbackResponse"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> |
We use jaxws-maven-plugin plugin for generating Java classes from WSDL/XSD:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <configuration> <sourceDestDir>${modules.output.directory}</sourceDestDir> <wsdlDirectory>${modules.import.directory}</wsdlDirectory> <bindingDirectory>${modules.import.directory}</bindingDirectory> <bindingFiles> <bindingFile>jaxb_global_bindings.xjb</bindingFile> </bindingFiles> </configuration> <executions> <execution> <id>WSDL-import-in-hello-model</id> <goals> <goal>wsimport</goal> </goals> <configuration> <staleFile>${project.build.directory}/jaxws/.in.hello.model</staleFile> <packageName>org.openhubframework.openhub.modules.in.hello.model</packageName> <wsdlFiles> <wsdlFile>hello-v1.0.wsdl</wsdlFile> </wsdlFiles> <bindingFiles> <bindingFile>jaxb_global_bindings.xjb</bindingFile> <bindingFile>jaxb_common_bindings.xjb</bindingFile> </bindingFiles> </configuration> </execution> </executions> </plugin> |
Web service configuration for openhub-example module is in org.openhubframework.openhub.modules.ExampleWebServiceConfig:
@Configuration @Profile(ExampleProperties.EXAMPLE_PROFILE) public class ExampleWebServiceConfig { static final ClassPathResource HELLO_OPERATIONS_XSD_RESOURCE = new ClassPathResource( "org/openhubframework/openhub/modules/in/hello/ws/v1_0/helloOperations-v1.0.xsd"); @Bean(name = "helloOperations-v1.0") public XsdSchema helloOperations() { return new SimpleXsdSchema(HELLO_OPERATIONS_XSD_RESOURCE); } @Bean(name = "hello") public SimpleWsdl11Definition helloWsdl() { SimpleWsdl11Definition wsdl = new SimpleWsdl11Definition(); wsdl.setWsdl(new ClassPathResource( "org/openhubframework/openhub/modules/in/hello/ws/v1_0/hello-v1.0.wsdl")); return wsdl; } } |
Implementation of WebServiceValidatingSources that registers XSD schemas for validation incoming/outgoing messages (traceHeader is mandatory for asynchronous requests only - set synchronnous requests to ignore requests)
@Component @Profile(ExampleProperties.EXAMPLE_PROFILE) public class ExampleWebServiceValidatingSources implements WebServiceValidatingSources { @Override public Resource[] getXsdSchemas() { return new Resource[] {ExampleWebServiceConfig.HELLO_OPERATIONS_XSD_RESOURCE}; } @Override public String[] getIgnoreRequests() { return new String[] {"{http://openhubframework.org/ws/HelloService-v1}syncHelloRequest"}; } } |
@CamelConfiguration(value = SyncHelloRoute.ROUTE_BEAN) @Profile(ExampleProperties.EXAMPLE_PROFILE) public class SyncHelloRoute extends AbstractBasicRoute { static final String ROUTE_BEAN = "syncHelloRouteBean"; private static final String OPERATION_NAME = "syncHello"; private static final String ROUTE_ID_SYNC_HELLO = getRouteId(ServiceEnum.HELLO, OPERATION_NAME); static final String HELLO_SERVICE_NS = "http://openhubframework.org/ws/HelloService-v1"; @Override protected void doConfigure() throws Exception { from(getInWsUri(new QName(HELLO_SERVICE_NS, "syncHelloRequest"))) .routeId(ROUTE_ID_SYNC_HELLO) .policy(RouteConstants.WS_AUTH_POLICY) .to("throttling:sync:" + OPERATION_NAME) .unmarshal(jaxb(SyncHelloRequest.class)) .log(LoggingLevel.DEBUG, "Calling hello service with name: ${body.name}") .bean(this, "composeGreeting") .marshal(jaxb(SyncHelloResponse.class)); } @Handler public SyncHelloResponse composeGreeting(@Body SyncHelloRequest req) { Assert.notNull(req, "req must not be null"); String greeting = "Hello " + req.getName(); SyncHelloResponse res = new SyncHelloResponse(); res.setGreeting(greeting); return res; } } |
Unit test implementations
@ActiveRoutes(classes = SyncHelloRoute.class) public class SyncHelloRouteTest extends AbstractExampleModuleTest { @Produce(uri = TestWsUriBuilder.URI_WS_IN + "syncHelloRequest") private ProducerTemplate producer; @EndpointInject(uri = "mock:test") private MockEndpoint mock; /** * Checking successful calling. */ @Test public void testSyncHelloRoute() throws Exception { String xml = "<syncHelloRequest xmlns=\"http://openhubframework.org/ws/HelloService-v1\">" + " <name>Mr. Parker</name>" + "</syncHelloRequest>"; String output = producer.requestBody((Object)xml, String.class); SyncHelloResponse res = Tools.unmarshalFromXml(output, SyncHelloResponse.class); assertThat(res, notNullValue()); assertThat(res.getGreeting(), is("Hello Mr. Parker")); } } |