Part of five-cents demo
This topic is part of the ‘old-client’ system of the Five-cents demo :
The source code is available on GitHub, under /backends/client-legacy and/framework/utils folder.
Project initialization
For this project, we want to build an old SOAP Client legacy system, and expose it with Thorntail for ease of use, and avoid a bigger monolithic solution here.
As for the REST resource, we will adopt a code-first approach, and use JAX-WS annotations to expose our service under SOAP format.
In order to generate a Thorntail skeleton, we can follow the same path as Exposing JEE JAX-RS resources under Thorntail with Swagger and Swagger-UI embedded but with JAX-WS fractions this time, alias webservices. We should end up with this dependencies :
<!-- Thorntail BOM --> <dependency> <groupId>io.thorntail</groupId> <artifactId>webservices</artifactId> </dependency> <dependency> <groupId>io.thorntail</groupId> <artifactId>cdi</artifactId> </dependency>
Enterprise service
As for the REST resource, you will find the use of an XML loader to get a few clients from scratch. This initialization takes place in the init method of com.fivecents.backends.clientlegacy.enterprise.ClientEnterpriseService :
@Named @ApplicationScoped public class ClientEnterpriseService { private List<Client> clients; @Inject private GenericXmlStoreLoader storeLoader; @PostConstruct private void init() { // Let's initialize our clients from xml resource. ClientStore clientStore = storeLoader.loadFromResource("clients.xml", ClientStore.class); clients = clientStore.getClients(); } (...) }
I let you find out how the GenericXmlLoader is working, if you are interested.
The rest of the ClientEnterpriseService class contains CRUD methods for legacy clients (search clients, update, create, remove).
Jax-WS exposure
As for the Web Service exposure, well, nothing new under the sun, the code-first approach leads us to the writing of the com.fivecents.backends.clientlegacy.soap.ClientEndpoint class with @WebService or @WebMethod annotations :
/** * SOAP WebService endpoint for the client service. * * @author Laurent CAILLETEAU */ @WebService( portName="clientPort", serviceName="clientService", targetNamespace = "http://clientlegacy.fivecents.com/") public class ClientEndpoint{ @Inject private ClientEnterpriseService clientEnterpriseService; @WebMethod(operationName = "findAllClients") @WebResult(name = "client") public List<Client> findAll() { return clientEnterpriseService.getAllClients(); } @WebMethod @WebResult(name = "client") public Client create(@WebParam(name = "client") Client client) { return clientEnterpriseService.createClient(client); } @WebMethod @WebResult(name = "removalSucceeded") public boolean remove(@WebParam(name = "id") int clientId) { return clientEnterpriseService.removeClient(clientId); } @WebMethod @WebResult(name = "client") public Client search(@WebParam(name = "id") int clientId) { return clientEnterpriseService.searchForClient(clientId); } @WebMethod @WebResult(name = "updateSucceeded") public boolean update(@WebParam(name = "client") Client client) { return clientEnterpriseService.updateClient(client); } }
We can now start Thorntail :
mvn clean install java -jar target/client-legacy-thorntail.jar
The server should display :
2018-09-29 10:25:01,520 INFO [org.jboss.ws.cxf.metadata] (MSC service thread 1-6) JBWS024061: Adding service endpoint metadata: id=com.fivecents.backends.clientlegacy.soap.ClientEndpoint address=http://cailleteau-netbook:8080/clientService implementor=com.fivecents.backends.clientlegacy.soap.ClientEndpoint serviceName={http://clientlegacy.fivecents.com/}clientService portName={http://clientlegacy.fivecents.com/}clientPort annotationWsdlLocation=null wsdlLocationOverride=null mtomEnabled=false (...) 2018-09-29 10:25:03,745 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 5) WFLYUT0021: Registered web context: '/' for server 'default-server' 2018-09-29 10:25:03,783 INFO [org.jboss.as.server] (main) WFLYSRV0010: Deployed "client-legacy.war" (runtime-name : "client-legacy.war") 2018-09-29 10:25:03,795 INFO [org.wildfly.swarm] (main) THORN99999: Thorntail is Ready
Our SOAP web service is exposed on http://localhost:8080/clientService, we can use a SOAPUi test to check responses, located in src/test/resources/client-legacy-soapui-project.xml :
Using qualified namespaces
As you can see on the SOAPUi response, the client XML tag and its children are using the default namespace, and not “http://clientlegacy.fivecents.com/” namespace (prefix ‘leg’). As there is no value for the default target namespace (no xmls=… in the XML response), its value is “”.
Actually, for highly contractual document as preconized by an SOA approach, I have always preferred using qualified tags instead of unqualified ones (who knows, you may have multiple Client types in your system? So distinguishing them in the SOA monolithic ESB with different namespaces isn’t a bad idea).
To get to that, we just need to add a package-info.java in com.fivecents.backends.clientlegacy.enterprise.beans to add a @XmlSchema annotation directly on the package itself, and specify QUALIFIED for element form default entry :
/** * JAXB annotations for the package. We prefer qualified XML form elements, * but generated JAXB elements set it to unqualified. We change that here. * * @author Laurent CAILLETEAU */ @XmlSchema( namespace = "http://clientlegacy.fivecents.com/", xmlns = { @XmlNs(prefix="leg", namespaceURI="http://clientlegacy.fivecents.com/") }, elementFormDefault = XmlNsForm.QUALIFIED) package com.fivecents.backends.clientlegacy.enterprise.beans; import javax.xml.bind.annotation.XmlSchema; import javax.xml.bind.annotation.XmlNs; import javax.xml.bind.annotation.XmlNsForm;
Let’s do the same for com.fivecents.backends.clientlegacy.soap package :
/** * JAXB annotations for the package. We prefer qualified XML form elements, * but generated JAXB elements set it to unqualified. We change that here. * * @author Laurent CAILLETEAU */ @XmlSchema( namespace = "http://clientlegacy.fivecents.com/", xmlns = { @XmlNs(prefix="leg", namespaceURI="http://clientlegacy.fivecents.com/") }, elementFormDefault = XmlNsForm.QUALIFIED) package com.fivecents.backends.clientlegacy.soap; import javax.xml.bind.annotation.XmlSchema; import javax.xml.bind.annotation.XmlNs; import javax.xml.bind.annotation.XmlNsForm;
Let’s restart Thorntail :
mvn clean install java -jar target/client-legacy-thorntail.jar
And replay the SOAPUi test :
This time, the response contains only Qualified tags. We can check this in the generated XML schema, with the elementFormDefault value :
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://clientlegacy.fivecents.com/" xmlns:leg="http://clientlegacy.fivecents.com/" elementFormDefault="qualified" targetNamespace="http://clientlegacy.fivecents.com/" version="1.0">
Leave a Reply