Developing a simple SOAP-webservice using Spring 3.0.1 and Apache CXF 2.2.6

Phillip Steffensen's picture

In the past few years many techniques have been developed to help applications interact with each other. One of them are webservice-interfaces. These interfaces are extremly popular in the world of Java software development. One Framework that can be used to build such interfaces is Apache CXF. Apache CXF delivers a toolset to develop interfaces using different protocols like XML/HTTP, RESTful HTTP, Corba and SOAP. In this article i'd like to show how easy it could be to develop a simple SOAP-webservice based on Apache CXF 2.2.6 and the Spring Framework 3.0.1. You can download the full example at the bottom of this article.

Setting up the project...

First I set up a small Maven 2 project that packages my application as a web application archive (*.war-file). Therefore I created the following pom.xml:

  1. <project xmlns="...">
  2.     <modelVersion>4.0.0</modelVersion>
  3.     <groupId>com.unitedcoders.demo</groupId>
  4.     <artifactId>CXFExampleService</artifactId>
  5.     <packaging>war</packaging>
  6.     <version>0.0.1-SNAPSHOT</version>
  7.     <name>Example Apache CXF Webservice</name>
  8.     <url>http://united-coders.com</url>
  9.    
  10.     <!-- Dependency properties -->
  11.     <properties>
  12.         <junit-version>4.5</junit-version>
  13.         <cxf.version>2.2.6</cxf.version>
  14.         <spring-version>3.0.1.RELEASE</spring-version>
  15.         <commons-logging-version>1.1.1</commons-logging-version>
  16.     </properties>
  17.    
  18.     <!-- Plugin configuration -->
  19.     <build>
  20.         <finalName>CXFExampleService</finalName>
  21.         <plugins>
  22.             <plugin>
  23.                 <groupId>org.apache.maven.plugins</groupId>
  24.                 <artifactId>maven-compiler-plugin</artifactId>
  25.                 <configuration>
  26.                     <source>1.6</source>
  27.                     <target>1.6</target>
  28.                 </configuration>
  29.             </plugin>
  30.             <plugin>
  31.                 <groupId>org.apache.cxf</groupId>
  32.                 <artifactId>cxf-java2ws-plugin</artifactId>
  33.                 <version>${cxf.version}</version>
  34.                 <dependencies>
  35.                     <dependency>
  36.                         <groupId>org.apache.cxf</groupId>
  37.                         <artifactId>cxf-rt-frontend-jaxws</artifactId>
  38.                         <version>${cxf.version}</version>
  39.                     </dependency>
  40.                     <dependency>
  41.                         <groupId>org.apache.cxf</groupId>
  42.                         <artifactId>cxf-rt-frontend-simple</artifactId>
  43.                         <version>${cxf.version}</version>
  44.                     </dependency>
  45.                 </dependencies>
  46.                 <executions>
  47.                     <execution>
  48.                         <id>process-classes</id>
  49.                         <phase>process-classes</phase>
  50.                         <configuration>
  51.                             <className>com.unitedcoders.demo.PersonService</className>
  52.                             <genWsdl>true</genWsdl>
  53.                             <verbose>true</verbose>
  54.                         </configuration>
  55.                         <goals>
  56.                             <goal>java2ws</goal>
  57.                         </goals>
  58.                     </execution>
  59.                 </executions>
  60.             </plugin>
  61.         </plugins>
  62.     </build>
  63.    
  64.     <!-- Dependency definitions -->
  65.     <dependencies>
  66.    
  67.         <!-- Apache CXF dependencies -->
  68.         <dependency>
  69.             <groupId>org.apache.cxf</groupId>
  70.             <artifactId>cxf-rt-frontend-jaxws</artifactId>
  71.             <version>${cxf.version}</version>
  72.         </dependency>
  73.         <dependency>
  74.             <groupId>org.apache.cxf</groupId>
  75.             <artifactId>cxf-rt-transports-http</artifactId>
  76.             <version>${cxf.version}</version>
  77.         </dependency>
  78.        
  79.         <!-- Spring Dependencies -->
  80.         <dependency>
  81.             <groupId>org.springframework</groupId>
  82.             <artifactId>spring-core</artifactId>
  83.             <version>${spring-version}</version>
  84.         </dependency>
  85.         <dependency>
  86.             <groupId>org.springframework</groupId>
  87.             <artifactId>spring-web</artifactId>
  88.             <version>${spring-version}</version>
  89.         </dependency>
  90.        
  91.         <!-- Logging -->
  92.         <dependency>
  93.             <groupId>commons-logging</groupId>
  94.             <artifactId>commons-logging</artifactId>
  95.             <version>${commons-logging-version}</version>
  96.         </dependency>
  97.        
  98.         <!-- Testing -->
  99.         <dependency>
  100.             <groupId>junit</groupId>
  101.             <artifactId>junit</artifactId>
  102.             <version>${junit-version}</version>
  103.             <scope>test</scope>
  104.         </dependency>
  105.     </dependencies>
  106. </project>

My projects structure

  1. phil@invader:~/Projects/CXFExample$ tree
  2. .
  3. |-- README.txt
  4. |-- pom.xml
  5. `-- src
  6.     |-- main
  7.     |   |-- java
  8.     |   |   `-- com
  9.     |   |       `-- unitedcoders
  10.     |   |           `-- demo
  11.     |   |               |-- Person.java
  12.     |   |               |-- PersonService.java
  13.     |   |               `-- PersonServiceImpl.java
  14.     |   |-- resources
  15.     |   |   `-- application-context.xml
  16.     |   `-- webapp
  17.     |       `-- WEB-INF
  18.     |           `-- web.xml
  19.     `-- test
  20.         `-- java
  21.             `-- com
  22.                 `-- unitedcoders
  23.                     `-- demo
  24.                         |-- PersonServiceImplTest.java
  25.                         `-- PersonTest.java
  26.  
  27. 14 directories, 9 files
  28. phil@invader:~/Projects/CXFExample$

Let's first take a look on what has happened here. I defined some Apache CXF 2.2.6 dependencies which are needed to create my SOAP-webservice. To use the Spring framework in my little project I also added spring-core and spring-web in version 3.0.1 to my dependencies. Additionally I defined some other dependencies like JUnit and Apache commons-logging. But what has happend to the Maven 2 plugins? The first plugin I configured in my project is the maven-compiler-plugin. This plugin is a plugin of Mavens standard lifecycle. My configuration lets Maven 2 know which Java version should be used to compile my source. I prefer to use Java 1.6. The second plugin I defined is the cxf-java2ws-plugin. This Maven 2 plugin helps me to generate a WSDL-file from my annotated Java webservice-class.

Developing the SOAP webservice

To have a little showcase I created a simple class "Person" containing the only one member field "name". Later on the webservice should get a persons name from a client and answer with a short greeting like „Hello [NAME]!“.

  1. package com.unitedcoders.demo;
  2.  
  3. public class Person {
  4.  
  5.     private String name;
  6.    
  7.     public Person(String name) {
  8.         this.name = name;
  9.     }
  10.  
  11.     public String getName() {
  12.         return name;
  13.     }
  14.  
  15.     public void setName(String name) {
  16.         this.name = name;
  17.     }
  18.    
  19. }
After that I created a simple endpoint-interface for my webservice and annotated it as a @WebService.
  1. package com.unitedcoders.demo;
  2.  
  3. import javax.jws.WebService;
  4.  
  5. @WebService
  6. public interface PersonService {
  7.  
  8.     public String greetPerson(String name);
  9.  
  10. }
The implementation is as simple as the interface and is also annotated as a @WebService. Additionally the "endpointInterface" is defined as an annotation-parameter.
  1. package com.unitedcoders.demo;
  2.  
  3. import javax.jws.WebService;
  4.  
  5. @WebService(endpointInterface = "com.unitedcoders.demo.PersonService")
  6. public class PersonServiceImpl implements PersonService {
  7.  
  8.     public String greetPerson(String name) {
  9.         Person person = new Person(name);
  10.  
  11.         return "Hello " + person.getName() + "!";
  12.     }
  13.  
  14. }
That's all. These three little files are representing my whole webservice.

Combining everything

To get the webservice working I finally combined Spring and my webservice-implementation. Therefore I first defined the applications context. First I added three imports to my applications context. There are three imports that add CXF-specific bean definitions and configurations to my applications context. After that a singleton bean of my webservice is needed. And at least a jaxws:endpoint is defined that maps my bean to the endpoint to the path "/personService".
application-context.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="..."
  3.    xsi:schemaLocation="...">
  4.    
  5.     <import resource="classpath:META-INF/cxf/cxf.xml" />
  6.     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
  7.     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  8.    
  9.     <!-- Spring manage ServiceBean -->
  10.     <bean id="personServ" class="com.unitedcoders.demo.PersonServiceImpl" />
  11.  
  12.     <!-- JAX-WS Service Endpoint -->    
  13.     <jaxws:endpoint id="personService" implementor="#personServ" address="/personService" />
  14.    
  15. </beans>
Now the context is ready to use. But what about the web.xml. The web.xml should now define a ContextLoaderListener to start up my Spring application context. Additionally a CXFServlet must be defined to make the application accessible as a webservice. I mapped to the CXFServlet to "/*". "/*" means that all services delivered by the CXFServlet are accessible right after the context (e.g. http://[HOST]:[PORT]/[CONTEXT]/[CXFSERVLET]).
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.    xsi:schemaLocation="...">
  4.  
  5.     <display-name>CXF Example Webservice</display-name>
  6.  
  7.     <listener>
  8.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  9.     </listener>
  10.  
  11.     <context-param>
  12.         <param-name>contextConfigLocation</param-name>
  13.         <param-value>classpath:application-context.xml</param-value>
  14.     </context-param>
  15.  
  16.     <servlet>
  17.         <servlet-name>CXFServlet</servlet-name>
  18.         <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  19.         <load-on-startup>1</load-on-startup>
  20.     </servlet>
  21.  
  22.     <servlet-mapping>
  23.         <servlet-name>CXFServlet</servlet-name>
  24.         <url-pattern>/*</url-pattern>
  25.     </servlet-mapping>
  26.    
  27. </web-app>

Testing the new SOAP-webservice

After building this Maven 2 project with „mvn clean package“ a new war-file will be placed in the target folder. This war-file now contains an entire webservice. If it is deployed on a Java web container like Apache Tomcat you can reach the webservice by accessing it in your browser.

http://[YOUR TOMCAT]:[PORT]/CXFExampleService/personService?wsdl

Webservice test in browser

To run some functional tests on the new webservice an test if the webservice works as expected I used soapUI which can be downloaded here. soapUI is a really famous tool that can be used to test webservices. It can be used as a standalone application or as a IDE plugin (e.g. for eclipse).

Webservice test in soapUI

Download the full example:

DOWNLOAD

Some resources:

http://cxf.apache.org
http://www.springsource.org/download
http://www.soapui.org

Trackback URL for this post:

http://united-coders.com/trackback/53
AttachmentSize
united-coders.com-CXFExample.tar_.bz22.53 KB

Comments

Anonymous's picture

Thanks for your guide!

Anonymous's picture

good work, I appreciate it! detailed clean and easy to understand!

Anonymous's picture

Can you give us a little more insight into the cxf files referenced within the application-context.xml?



I don't see those files in your tar file. What a they for and are they needed?

Phillip Steffensen's picture

The cxf files referenced in application-context.xml are delivered by the cxf dependencies.
You can take a closer look on them if you browse into these dependencies.

Christian Harms's picture
Anonymous's picture

Excellent work, just what I was looking for!-)

Anonymous's picture

hi,

Thanks you for your example. But i 'd like to ask you in which directory is generated the wsdl using the plugin cxf-java2ws-plugin.

Anonymous's picture

Hi,

Excellent Job you did, it is very very useful to me.

Thanks,
Vincent

Anonymous's picture

Ecellent example. This is really helped me.

Anonymous's picture

Excellent example, would be nice if wsdl had Person::name like in java rather than Person::arg0.
Also it offers manual testing using SOAP UI rather than having honest http junit test.

Anonymous's picture

Here is the fix to make wsdl look better (person should have "name" attribute instead of "arg0"):
public String greetPerson(@WebParam(name = "name") String name);