Learn in Java
 


   

JAX-WS SOAP WebService using CXF

 
SOAP(Simple Object Access Protocol) is a protocol to send XML messages over HTTP. JAX-WS is the standard that defines how to create a SOAP based webservices. Let us look at a simple example on how to create a simple JAX-WS SOAP webservice using CXF and Spring. The following software has been used for this tutorial :
    1. Apache Maven 3.0.4
    2. Spring 3.2.6
    3. Apache CXF 3.0.3
    4. Jetty 6.1.10 or Tomcat 7
    

First, we need to create a basic CXF web project structure. For this, use the below command :

mvn archetype:generate -DgroupId=com.learninjava -DartifactId=cxfjaxws -DarchetypeArtifactId=org.apache.cxf.archetype:cxf-jaxws-javafirst -DinteractiveMode=false

Remember:
1. With the new maven version, the above command might not work. In such case, you can simply use the below command :
      
      mvn archetype:generate
      
      then select the appropriate archetype serial number from the list provided. On our development environment, the serial number for 
      our tutorial is,
      
      515: remote -> org.apache.cxf.archetype:cxf-jaxws-javafirst (Creates a project for developing a Web service starting from Java code)
      
2. If you are too busy ;) and in a hurry, you can actually create a SOAP webservice without even writing a single line of code. 
      
      See here :
      http://java-hub.blogspot.in/2015/02/jax-ws-soap-webservice-using-cxf-and.html.Remember, you will just get an unpolished version of 
      the project with out concepts being explained. So, we recommend you going through the below tutorial.

If the command is successful, your basic project structure should look similar to the below :

cxfjaxws
|   pom.xml
|
+---.settings
+---src
|   +---main
|   |   +---java
|   |   |   +---com
|   |   |       +---learninjava
|   |   |               HelloWorld.java
|   |   |               HelloWorldImpl.java
|   |   |
|   |   +---webapp
|   |       +---WEB-INF
|   |               beans.xml
|   |               web.xml
|   |
|   +---test
|       +---java
|           +---com
|               +---learninjava
|                       HelloWorldImplTest.java

Remember:
The maven surefire plugin expects the test file names in the following patterns :

    **/Test*.java
    **/*Test.java
    **/*TestCase.java    

There were many changes made to pom.xml that comes default with this archetype. For instance, we have removed some unused configurations and refactored the configurations for easy and better understanding.

For your convenience, we have provided configurations for running the webservice on both Jetty and Tomcat servers.

First, let us take a look at tomcat configuration. Later we will see about jetty configuration. There is a cool feature in jetty that attracts many developers. we will see what is it later in this tutorial.

Using Tomcat :

1. Change the default pom.xml as below :

<?xml version="1.0" encoding="UTF-8"?>
<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.learninjava</groupId>
    <artifactId>cxfjaxws</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Simple CXF Java-first SOAP project using Spring configuration</name>
    <description>Simple CXF Java-first SOAP project using Spring configuration</description>

    <organization>
        <name>Learn in Java</name>
        <url>http://www.learninjava.com/</url>
    </organization>
	<!-- Change the version numbers or other configurations here -->
    <properties>
        <cxf.version>3.0.3</cxf.version>
        <spring.version>3.2.6.RELEASE</spring.version>
        <junit.version>4.11</junit.version>
        <tomcat7.version>2.0</tomcat7.version>
        <compiler.srcversion>1.6</compiler.srcversion>
        <compiler.tgtversion>1.6</compiler.tgtversion>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <port.number>9090</port.number>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                     
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>${tomcat7.version}</version>
                    <executions>
                        <execution>
                            <id>default-cli</id>
                            <goals>
                                <goal>run</goal>
                            </goals>
                            <configuration>
                                <port>${port.number}</port>
                                <path>/jaxws-service</path>
                                <useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${compiler.srcversion}</source>
                        <target>${compiler.tgtversion}</target>
                    </configuration>
                </plugin>
				
				<!-- Optional plugin, This is added to create an eclipse compatible project. To do it, use : mvn eclipse:eclipse -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-eclipse-plugin</artifactId>
                    <configuration>
                        <projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
                        <wtpmanifest>true</wtpmanifest>
                        <wtpapplicationxml>true</wtpapplicationxml>
                        <wtpversion>2.0</wtpversion>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

You will notice that there are 3 important plugins in the pom.xml out of which 1 are optional. We will see each of them in detail :

tomcat7-maven-plugin - This is the tomcat plugin where will be deploy our angry world webservice.
maven-compiler-plugin - This plugin specifies the Java compiler source and target versions.
maven-eclipse-plugin - [Optional] This plugin is used to generate the .classpath and .project files which enables us to use 
this project in eclipse.

The other important sections includes dependencies and properties which are used to specify the jar file dependencies and properties respectively.


 

2. Renamed HelloWorld.java to HelloAngryWorld.java :

package com.learninjava;

import javax.jws.WebService;

/**
 * @author learninjava.com
 * @see www.learninjava.com
 */
@WebService
public interface HelloAngryWorld {
    String sayHi(String text);
}

This is the actual webservice source file, so lets take a look at it.

This webservice exposes only one method sayHi() which returns a String type. This method uses an important annotation:

@WebService annotation at class level specifies that this is the webservice endpoint interface.

3. Renamed HelloWorldImpl.java to HelloAngryWorldImpl.java :

package com.learninjava;

import javax.jws.WebService;

/**
 * @author learninjava.com
 * @see www.learninjava.com
 */
@WebService(endpointInterface = "com.learninjava.HelloAngryWorld")
public class HelloAngryWorldImpl implements HelloAngryWorld {

    public String sayHi(String text) {
        return "Hello " + text;
    }
}

This class is the webservice implementation class that actually implements the endpoint interface.

4. beans.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:jaxws="http://cxf.apache.org/jaxws"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

        <import resource="classpath:META-INF/cxf/cxf.xml" />

        <jaxws:endpoint 
          id="helloAngryWorld" 
          implementor="com.learninjava.HelloAngryWorldImpl" 
          address="/HelloAngryWorld" />
          
</beans>

The beans.xml has an important tag <jaxws:endpoint> which is the most important tag of this xml.

<jaxws:endpoint> - This lists all the service beans which are nothing but the services we want to make as a webservice

Observe that names of the entities like endpoint, implementor etc. These are in conjunction with SOAP protocol. You will find these names to be different when dealing with JAX-RS.

5. web.xml :

<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>WEB-INF/beans.xml</param-value>
        </context-param>

        <listener>
                <listener-class>
                        org.springframework.web.context.ContextLoaderListener
                </listener-class>
        </listener>

        <servlet>
                <servlet-name>CXFServlet</servlet-name>
                <display-name>CXF Servlet</display-name>
                <servlet-class>
                        org.apache.cxf.transport.servlet.CXFServlet
                </servlet-class>
                <load-on-startup>1</load-on-startup>
        </servlet>

        <servlet-mapping>
                <servlet-name>CXFServlet</servlet-name>
                <url-pattern>/*</url-pattern>
        </servlet-mapping>
</web-app>

The configurations in web.xml are straighforward. CXFServlet is the actual servlet that reads the xml configurations and makes the service beans as webservices and handles the requests and responses to the exposed services.

ContextLoaderListener is the ROOT web application context that is used by spring.

Once the above files are ready, type the below command to start the tomcat container :

mvn clean package -DskipTests=true tomcat7:run

This command cleans the target directory, compiles, builds war and deploys it to tomcat. Notice that we used skipTests = true switch. This is to make sure that the test case are not run before the server starts.

Navigate to the URL :

http://localhost:9090/jaxws-service/HelloAngryWorld?wsdl

Output:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://learninjava.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloAngryWorldImplService" targetNamespace="http://learninjava.com/">
  <wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://learninjava.com/" elementFormDefault="unqualified" targetNamespace="http://learninjava.com/" version="1.0">

  <xs:element name="sayHi" type="tns:sayHi"/>

  <xs:element name="sayHiResponse" type="tns:sayHiResponse"/>

  <xs:complexType name="sayHi">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="sayHiResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
  </wsdl:types>
  <wsdl:message name="sayHiResponse">
    <wsdl:part element="tns:sayHiResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHi">
    <wsdl:part element="tns:sayHi" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloAngryWorld">
    <wsdl:operation name="sayHi">
      <wsdl:input message="tns:sayHi" name="sayHi">
    </wsdl:input>
      <wsdl:output message="tns:sayHiResponse" name="sayHiResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloAngryWorldImplServiceSoapBinding" type="tns:HelloAngryWorld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sayHi">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="sayHi">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHiResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HelloAngryWorldImplService">
    <wsdl:port binding="tns:HelloAngryWorldImplServiceSoapBinding" name="HelloAngryWorldImplPort">
      <soap:address location="http://localhost:9090/jaxws-service/HelloAngryWorld"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

This is an echo service. You need a SOAP client to create a request message to test this webservice.

If you are unware of your endpoint address, you can use the below url to find out,

http://localhost:9090/jaxws-service/cxf/services

This lists all the REST and SOAP services running on your server.

Using Jetty :

1. pom.xml :

The pom.xml is pretty much similar to the one we have used for tomcat configuration except that the tomcat plugin is replaced with the jetty equivalent. Also the port number is changed 8080 just to distinguish between tomcat and jetty.

<?xml version="1.0" encoding="UTF-8"?>
<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.learninjava</groupId>
    <artifactId>cxfjaxws</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Simple CXF Java-first SOAP project using Spring configuration</name>
    <description>Simple CXF Java-first SOAP project using Spring configuration</description>

    <organization>
        <name>Learn in Java</name>
        <url>http://www.learninjava.com/</url>
    </organization>
	<!-- Change the version numbers or other configurations here -->
    <properties>
        <cxf.version>3.0.3</cxf.version>
        <spring.version>3.2.6.RELEASE</spring.version>
        <junit.version>4.11</junit.version>
		<jetty.version>6.1.10</jetty.version>
        <compiler.srcversion>1.6</compiler.srcversion>
        <compiler.tgtversion>1.6</compiler.tgtversion>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <port.number>8080</port.number>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
				<plugin>
					<groupId>org.mortbay.jetty</groupId>
					<artifactId>maven-jetty-plugin</artifactId>
					<version>${jetty.version}</version>
					<configuration>
						<scanIntervalSeconds>10</scanIntervalSeconds>
						<connectors>
							<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
								<port>${port.number}</port>
								<maxIdleTime>60000</maxIdleTime>
							</connector>
						</connectors>
						<webAppConfig>
							<contextPath>/jaxws-service</contextPath>
						</webAppConfig>
                  </configuration>
                </plugin>
					
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${compiler.srcversion}</source>
                        <target>${compiler.tgtversion}</target>
                    </configuration>
                </plugin>
				
				<!-- Optional plugin, This is added to create an eclipse compatible project. To do it, use : mvn eclipse:eclipse -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-eclipse-plugin</artifactId>
                    <configuration>
                        <projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
                        <wtpmanifest>true</wtpmanifest>
                        <wtpapplicationxml>true</wtpapplicationxml>
                        <wtpversion>2.0</wtpversion>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

All other steps are same as above.

To start the jetty container and the webservice use the below command :

mvn clean package -DskipTests=true jetty:run

Navigate to the URL :

http://localhost:8080/jaxws-service/HelloAngryWorld?wsdl

Output:
Same WSDL as above

Advantage of using Jetty - Hot code deployment :

By default, Jetty scans the following directories :

  target/classes  -  for changes to Java sources and 
  src/main/webapp -  for changes to web sources. 

If any source file is modified, the changes are autodeployed to the jetty container without manually restarting for the changes to take effect.

To test this hot code deployment, try to change any source file and recompile the source using mvn compile command.

The moment the source file is compiled, notice the server console. You will observe that jetty hot deploys the code automatically and you can access the changes via browser instantly.


 
   

Related Articles

Restful WebService using CXF
Restful Client using CXF
SOAP Client using CXF
Restful WebService using Jersey
Restful Client using Jersey
 
   

Recommended Articles

User and Daemon Threads
Thread States
Java 8 Stream
Java 8 Functional Interfaces
Java 8 Lambda Expressions
Top 10 Free Tutorials




LIKE/SHARE
 
 
 
Download Source:

Comments:


 

Top Picks

1. Top 5 websites offering free e-books

2. Top 10 websites for free Java Articles and Tutorials

3. Top 5 websites for Java Certifications

4. Top 5 Softwares for Java developers




   
   
   
 
 
© Copyright 2017. All rights reserved. All trademarks and logos belongs to their owners.         Website Counter