Quick Overview of SOAP (JAX-WS) webservice with CXF

In this tutorial, we will learn how to build a simple SOAP web service using CXF, a popular implementation of JAX-WS.

Example Scenario:

We need to build a web service based on SOAP, which would take two binary numbers in request and provide their added result in response.


Project artifacts:

Technologies used –

a. Eclipse IDE for Java EE developer 4.5.0.20150621-1200 (Mars)
b. Preinstalled Maven with Eclipse Mars
c. Tomcat 7.0.64
d. CXF 3.0.3
e. Java 1.8

Jars used –

cxf-rt-frontend-jaxws-3.0.3.jar
xml-resolver-1.2.jar
asm-3.3.1.jar
cxf-core-3.0.3.jar
woodstox-core-asl-4.4.1.jar
stax2-api-3.1.4.jar
xmlschema-core-2.1.0.jar
cxf-rt-bindings-soap-3.0.3.jar
cxf-rt-wsdl-3.0.3.jar
wsdl4j-1.6.3.jar
cxf-rt-databinding-jaxb-3.0.3.jar
jaxb-impl-2.2.10-b140310.1920.jar
jaxb-core-2.2.10-b140310.1920.jar
cxf-rt-bindings-xml-3.0.3.jar
cxf-rt-frontend-simple-3.0.3.jar
cxf-rt-ws-addr-3.0.3.jar
cxf-rt-ws-policy-3.0.3.jar
neethi-3.0.3.jar
slf4j-log4j12-1.5.6.jar
slf4j-api-1.5.6.jar
log4j-1.2.14.jar
cxf-rt-transports-http-3.0.3.jar
commons-logging-1.1.1.jar
spring-web-4.1.7.RELEASE.jar
spring-aop-4.1.7.RELEASE.jar
aopalliance-1.0.jar
spring-beans-4.1.7.RELEASE.jar
spring-context-4.1.7.RELEASE.jar
spring-expression-4.1.7.RELEASE.jar
spring-core-4.1.7.RELEASE.jar

Before we begin:

Following is the folder structure of maven web project with WSDL in the resource folder.

To learn how to create maven web project, please read this tutorial.

To learn how to create a WSDL, please read this tutorial. We are going to use the same WSDL here.

–    Eclipse initial project folder structure:

CXF Web Project

–     pom.xml ( at the beginning )

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javanbeyond</groupId>
    <artifactId>QuickSOAPOverviewCXF</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>QuickSOAPOverviewCXF Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
            <id>apache-snapshots</id>
            <name>Apache SNAPSHOT Repository</name>
            <url>http://repository.apache.org/snapshots/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>QuickSOAPOverviewCXF</finalName>
        <plugins>
            <!--             Plugin to create equivalent java classes for the wsdl schema -->
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>3.0.3</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <!-- where to create the java classes -->
                            <sourceRoot>${basedir}/src/main/java</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>${basedir}/src/main/resources/BinaryAdditionService.wsdl</wsdl>
                                    <wsdlLocation>classpath:BinaryAdditionService.wsdl</wsdlLocation>
                                    <extraargs>
                                        <!-- We want server side implementation classes -->
                                        <extraarg>-impl</extraarg>
                                        <extraarg>-verbose</extraarg>
                                    </extraargs>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

 

Please run maven clean and install and you should see the following java classes created from WSDL.

 

CXFGeneratedClasses

– WSDL and class mapping

The following image depicts the mapping based on which CXF tool wsdl2java and JAXB created the classes from WSDL and schema.

CXFWSDLClassMappingBinding

package-info.java : It contains the mapping between target namespace of the WSDL (http://www.javanbeyond.com/BinaryAdditionService/) and the created package name (com.javanbeyond.binaryadditionservice).It can be modified by passing -p argument to wsdl2java tool of CXF. Each package has one package-info.java.

ObjectFactory.java : It acts as a factory class to create objects for the classes in its package. If there are multiple namespaces in schema, so will be multiple packages and each package has its own ObjectFactory class.

BinaryAddResponse.java : The Response class whose object will be marshalled to response XML.

BinaryAddRequest.java : The Request class which the incoming payload will be unmarshalled to and passed to implementation operation method.

BinaryAdditionService.java : The web service interface created based on port type in WSDL.

BinaryAdditionServiceSOAPImpl.java : The implementation class of BinaryAdditionService interface. All our business logic will be written here or will start here.

BinaryAdditionService_Service.java : The client representation of the Service.

Let’s Proceed…

  1. Final project directory structure:

SOAP CXF Project Structure

2. Implementation class

file : BinaryAdditionServiceSOAPImpl. This is the implementation class of our web service interface. It has a method created from WSDL operation and all our processing logic will be in this method or will start from this method. The XML request payload is unmarshalled to BinaryAdditionRequest object and passed to the operation name method as an argument.

 


/**
 * Please modify this class to meet your needs
 * This class is not complete
 */

package com.javanbeyond.binaryadditionservice;

import java.util.logging.Logger;
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 3.0.3 2016-06-09T21:50:03.647-05:00
 * Generated source version: 3.0.3
 
 */

@javax.jws.WebService(serviceName = "BinaryAdditionService", portName = "BinaryAdditionServiceSOAP", targetNamespace = "http://www.javanbeyond.com/BinaryAdditionService/", wsdlLocation = "classpath:BinaryAdditionService.wsdl", endpointInterface = "com.javanbeyond.binaryadditionservice.BinaryAdditionService")

public class BinaryAdditionServiceSOAPImpl implements BinaryAdditionService {

    private static final Logger LOG = Logger
            .getLogger(BinaryAdditionServiceSOAPImpl.class.getName());

    /*
     * (non-Javadoc)
     
     * @see
     * com.javanbeyond.binaryadditionservice.BinaryAdditionService#binaryAdd(com
     * .javanbeyond.binaryadditionservice.BinaryAddRequest parameters )*
     */
    public com.javanbeyond.binaryadditionservice.BinaryAddResponse binaryAdd(
            BinaryAddRequest parameters) {
        LOG.info("Executing operation binaryAdd");
        System.out.println(parameters);
        try {
            // Create a Object Factory method for this package to create
            // equivalent java objects for this
            // namespace/package
            ObjectFactory objFactory = new ObjectFactory();
            BinaryAddResponse _return = objFactory.createBinaryAddResponse();
            _return.setOut(Integer
                    .toBinaryString(Integer.parseInt(parameters.getA()2)
                            + Integer.parseInt(parameters.getB()2)));
            return _return;
        catch (java.lang.Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

}

3. Spring configuration.

file : BinaryAdditionConfig.xml. Spring application context file to bind different instances of classes (beans) in spring container including our web service class within an application.

 

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd   http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <!-- The actual implementation class and the corresponding url to access         it -->
    <jaxws:endpoint id="calculateEndpoint" implementor="#binaryCalculate" address="/BinaryCalculatorService"></jaxws:endpoint>
    <bean id="binaryCalculate" class="com.javanbeyond.binaryadditionservice.BinaryAdditionServiceSOAPImpl"></bean>
</beans>

4. Deployment descriptor

file: web.xml. Deployment descriptor file for mapping URIs to CXF servlet. The spring configuration file location is added as a context parameter through web.xml.

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:BinaryAdditionConfig.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>cxf</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxf</servlet-name>
        <url-pattern>/soap/*</url-pattern>
    </servlet-mapping>
</web-app>

5.  Maven Dependencies

file : pom.xml. Maven unit of work to declare project dependencies, compile code and build war file for deployment in Tomcat. Comment the plugin part to prevent it from rebuilding and overriding our changes in Implementation class when we rebuild our code.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javanbeyond</groupId>
    <artifactId>QuickSOAPOverviewCXF</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>QuickSOAPOverviewCXF Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
            <id>apache-snapshots</id>
            <name>Apache SNAPSHOT Repository</name>
            <url>http://repository.apache.org/snapshots/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>QuickSOAPOverviewCXF</finalName>
        <plugins>
            <!--             Plugin to create equivalent java classes for the wsdl schema -->
            <!-- <plugin>                 <groupId>org.apache.cxf</groupId>                 <artifactId>cxf-codegen-plugin</artifactId>                 <version>3.0.3</version>                 <executions>                     <execution>                         <id>generate-sources</id>                         <phase>generate-sources</phase>                         <configuration>                             where to create the java classes                             <sourceRoot>${basedir}/src/main/java</sourceRoot>                             <wsdlOptions>                                 <wsdlOption>                                     <wsdl>${basedir}/src/main/resources/BinaryAdditionService.wsdl</wsdl>                                     <wsdlLocation>classpath:BinaryAdditionService.wsdl</wsdlLocation>                                     <extraargs>                                         We want server side implementation classes                                         <extraarg>-impl</extraarg>                                         <extraarg>-verbose</extraarg>                                     </extraargs>                                 </wsdlOption>                             </wsdlOptions>                         </configuration>                         <goals>                             <goal>wsdl2java</goal>                         </goals>                     </execution>                 </executions>             </plugin> --></plugins>
    </build>
</project>

Example Execution:

  1. Please run maven clean and install and deploy the war file created in Tomcat . You can use your own choice of SOAP client. In this tutorial, we will use SOAPUI, a popular web service client.
  2. Open SOAPUI and create a SOAP project with the url “http://localhost:8080/QuickSOAPOverviewCXF/soap/BinaryCalculatorService?wsdl”

SOAPUI Create Project

3. Press ok. A SOAP project should get created.

SOAPUI Request Create

4. Fill any binary input and press the send button. You should get a response of added binary numbers.

 

SOAP UI response

 

Leave a Reply

Back to Top
%d bloggers like this: