📜 ⬆️ ⬇️

Java SOAP Server with Apache CXF and Spring

image Recently, several articles appeared on the SOAP protocol, as well as describing the process of creating a server in various languages ​​and platforms. Let's continue the topic. This article will describe how to create a server in Java using Apache CXF and the Spring Framework. It is assumed that the reader already has a general idea of ​​the mentioned protocol, as well as of working with ant and maven. In order to make the task a little more interesting, we add an initial condition: a WSDL scheme describing a web service is given. So…
(Picture from an article on Wikipedia .)

0. Initial conditions


The task that we set before us: it is necessary to implement a web service that meets the SOAP 1.1 specification , based on a ready-made WSDL scheme. As a protocol for the transfer of "envelopes" we will use HTTP. Thus, our task can be divided into two components:

On the first point it is worth making the following remark. In the particular case, we could manually describe the operations we need, but in the general case it is more convenient to use the tool for automatic interface generation.

This is what the original WSDL scheme looks like:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="CurrentTimeService" targetNamespace="http://artspb.me/cts" xmlns:tns="http://artspb.me/cts" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:types> <xsd:schema targetNamespace="http://artspb.me/cts"> <xsd:element name="timeZoneId" nillable="true" type="xsd:string"/> <xsd:element name="currentTime" type="xsd:dateTime"/> </xsd:schema> </wsdl:types> <wsdl:message name="getCurrentTimeMsg"> <wsdl:part element="tns:timeZoneId" name="timeZoneId"/> </wsdl:message> <wsdl:message name="currentTimeMsg"> <wsdl:part element="tns:currentTime" name="currentTime"/> </wsdl:message> <wsdl:portType name="CurrentTimeService"> <wsdl:operation name="getCurrentTime"> <wsdl:input message="tns:getCurrentTimeMsg" name="getCurrentTime"/> <wsdl:output message="tns:currentTimeMsg" name="currentTime"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CurrentTimeService_HttpBinding" type="tns:CurrentTimeService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getCurrentTime"> <soap:operation soapAction="http://artspb.me/cts" style="document"/> <wsdl:input name="getCurrentTime"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="currentTime"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CurrentTimeService_HttpService"> <wsdl:port binding="tns:CurrentTimeService_HttpBinding" name="CurrentTimeService_HttpPort"> <soap:address location="http://localhost:8080/YetAnotherService/service/currentTimeService"/> </wsdl:port> </wsdl:service> </wsdl:definitions> 

The service has a very simple functionality: returns the current time in the specified time zone. In the case where the belt is not specified, the service returns the current server time.

In the process we will use the following tools:

All of them together is very convenient to use with IntelliJ IDEA , but this tool is not mandatory.
')
Project structure


We define the structure of the project. In the build folder we will store scripts for ant. In the ObjectLibrary module we will keep the original schema, as well as the classes generated from it. The CurrentTimeService module will be the main one, in it we will keep the implementation of the service, and we will also build a war file using it.

In the pom-files, we indicate the dependencies needed by the modules. We will have few external dependencies: spring-web, log4j, cxf-rt-frontend-jaxws and cxf-rt-transports-http — all of them are available at http://repo1.maven.org/maven2 .

1. Creating a java-based interface WSDL scheme


To automatically generate a java interface based on a WSDL scheme, we use the wsdl2java utility from the Apache CXF package. We slightly modify the original Ant-script so that it pre-clears the directory into which the java-classes will be added. This can be useful if the original scheme changes in the future. By default, the directory is not cleared, which can lead to the appearance of "garbage" from classes that are no longer used. Such a problem is characteristic of schemes with complex composite types.

 <?xml version="1.0"?> <project name="BuildObject"> <property name="cxf.home" value="/home/art/tools/apache-cxf-2.5.2"/> <path id="cxf.classpath"> <fileset dir="${cxf.home}/lib"> <include name="*.jar"/> </fileset> </path> <target name="cxfWSDLToJava"> <java classname="org.apache.cxf.tools.wsdlto.WSDLToJava" fork="true"> <arg value="-verbose"/> <arg value="-d"/> <arg value="../ObjectLibrary/src/main/java"/> <arg value="../ObjectLibrary/src/main/resources/CurrentTimeService.wsdl"/> <classpath> <path refid="cxf.classpath"/> </classpath> </java> </target> <target name="regenerate.object.library"> <delete dir="../ObjectLibrary/src/main/java"/> <antcall target="cxfWSDLToJava"/> </target> </project> 

Place this script in the build / build.xml file. Let's run the regenerate task.object.library, as a result of which we will get the interface we need in the ObjectLibrary folder.

 package me.artspb.cts; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.bind.annotation.XmlSeeAlso; /** * This class was generated by Apache CXF 2.5.2 * 2012-02-02T17:39:35.466+04:00 * Generated source version: 2.5.2 * */ @WebService(targetNamespace = "http://artspb.me/cts", name = "CurrentTimeService") @XmlSeeAlso({ObjectFactory.class}) @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) public interface CurrentTimeService { @WebResult(name = "currentTime", targetNamespace = "http://artspb.me/cts", partName = "currentTime") @WebMethod(action = "http://artspb.me/cts") public javax.xml.datatype.XMLGregorianCalendar getCurrentTime( @WebParam(partName = "timeZoneId", name = "timeZoneId", targetNamespace = "http://artspb.me/cts") java.lang.String timeZoneId ); } 


It should be borne in mind that with the help of the wsdl2java utility we could immediately get a ready-made server (-server key) and even an implementation for it (-impl key). However, in this article we will use it only to get the interface we need to avoid hard binding to the generated code.

2. Implementing a web service based on the received interface


The implementation of the CurrentTimeService interface is placed in the module of the same name. The code is simple and does not need additional comments.

 package me.artspb.cts; import org.apache.log4j.Logger; import javax.jws.WebParam; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import java.util.GregorianCalendar; import java.util.TimeZone; public class CurrentTimeServiceImpl implements CurrentTimeService { private Logger logger = Logger.getLogger(CurrentTimeServiceImpl.class); public XMLGregorianCalendar getCurrentTime( @WebParam(partName = "timeZoneId", name = "timeZoneId", targetNamespace = "http://artspb.me/cts") String timeZoneId) { logger.debug("Operation getCurrentTime was requested."); XMLGregorianCalendar gregorianCalendar; try { gregorianCalendar = getXmlGregorianCalendar(timeZoneId); } catch (DatatypeConfigurationException e) { throw new RuntimeException(e); } logger.debug("Successful."); return gregorianCalendar; } private XMLGregorianCalendar getXmlGregorianCalendar(String id) throws DatatypeConfigurationException { TimeZone timeZone; if (!"".equals(id)) { logger.debug("TimeZoneId isn't null: " + id); timeZone = TimeZone.getTimeZone(id); } else { logger.debug("TimeZoneId is null. Will use default value."); timeZone = TimeZone.getDefault(); } GregorianCalendar gregorianCalendar = new GregorianCalendar(timeZone); return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar); } } 


Now, in accordance with the example , we will add the serviceContext.xml and web.xml files to the resources. Also do not forget about log4j.xml. You can find these files in the archive with source codes, a link to it is given at the end of the article. After that, the implementation of the service can be considered complete, it remains to build the application and test its operability.

3. Build and validate


To build a project, let's execute the maven “package” task. The resulting war file is deployed on the Tomcat server. We assume that it is available on port 8080.



For check we will use the soapUI program. The WSDL service schema is available at http: // localhost: 8080 / CurrentTimeService / service / currentTimeService? Wsdl , with which we can create a new soapUI project.

Sending request:
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cts="http://artspb.me/cts"> <soapenv:Header/> <soapenv:Body> <cts:timeZoneId>PST</cts:timeZoneId> </soapenv:Body> </soapenv:Envelope> 


We get the answer:
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <currentTime xmlns="http://artspb.me/cts">2012-02-02T08:48:24.402-08:00</currentTime> </soap:Body> </soap:Envelope> 


Instead of conclusion


The task is achieved: the web service correctly processes requests. We also managed to avoid “hard” binding to the generated implementation, which makes the code more flexible and allows us to put less effort into making changes in the future.

Successes!

Main links together:

Source: https://habr.com/ru/post/137543/


All Articles