Developing SOAP Web service using Apache CXF

In last post I walked through the steps for developing a simple RESTFull service using apache CXF.  In this post I will be talking about developing SOAP web service using CXF. Before moving forward let us understand few of the concepts/elements which makes up a SOAP web service

SOAP or Simple Object Access Protocol 

SOAP is a protocol for exchanging XML-based messages over the network using application protocols like http, smtp, etc as carrier. SOAP message comprises of a SOAP envelope. The envelope can be broken into a header and a body. Header contains context related definitions like security while the body contains actual application data. A typical SOAP message looks like

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
  </soap:Header>
  <soap:Body>
    <m:GetStockPrice xmlns:m="http://www.example.org/stock">
      <m:StockName>IBM</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>

WSDL or Web Services Description Language

WSDL is a standard based XML Language which is used to describe a web service. A WSDL completely describes what public interface an web service exposes, what parameter it expects, structure of output it returns, location of web service. A WSDL defines a web service as collection of communication end points that are capable of exchanging messages. These communication end points are called ports. Port are composed of two parts.

  1. Contains the public interface exposed by the web service. The interface contains all the methods, parameter needed to invoke them and response structure returned by them.
  2. The second part binds the public interface to network protocol like http. The binding comprises of information like location of the public interface and message format for the service.

SOAP communication styles

There exists two types of communication styles

  1. Document
  2. RPC

The communication style used by SOAP web service is defined in its WSDL.

In the Document style the application data which is part of soap body is sent as XML document. This document can be validated completely by a xml schema which is also part of WSDL. As XML can contain structure as per wish of service developer hence the responsibility of marshaling and unmarshaling xml payload lies at end of provider and consumer code.

In RPC style as the name suggests the consumer invokes the methods of service as if he were invoking a local method. To facilitate this the RPC message consists of list of public interface methods that a consumer can invoke. These methods are listed by names as xml elements.  The method parameters needed by these method forms sub elements of  the method element. The responisibility of marshaling/unmarshaling lies with the web service framework. The framework contains its own marshaling/unmarshaling libraries. RPC style results in tightly coupled code between application code and the web service framework, hence norm is create document style services. With Key concepts in place let see an example of how to write a soap web service using Apache CXF.

Getting the source code for this tutorial

I have committed the source files for this tutorial in SVN.

Note: Both are ItelliJ maven projects so you can directly import them to your intelliJ IDE or copy over the files manually to other IDEs

Create a struts2 skeleton application to contain your service.

You can use any MVC framework but I prefer struts2 for my own reasons. You can see an example of how to create an empty struts2 application in eclipse using maven here.

Add CXF dependencies 

In your project POM add following dependencies to download CXF jars

<properties>
       <cxf.version>2.5.0</cxf.version>
</properties>
<dependencies>
       <!-- apache cxf -->
        <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-frontend-jaxrs</artifactId>
          <version>${cxf.version}</version>
       </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
</dependencies>

For example let us create a simple book shelf web service. For simplicity let us assume following use case.

  1. Insert a book in book self
  2. Retrieve a book from book shelf by title.

Developing the service

This can be done in two ways Code first and contract first. We will be using the code first approach.

Creating a Service Endpoint Interface (SEI)

Let us create a SEI interface called BookShelfService

package com.aranin.weblog4j.services;

import com.aranin.weblog4j.vo.BookVO;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface BookShelfService {

    @WebMethod
    public  String insertBook(BookVO bookVO);
    @WebMethod
    public  BookVO getBook(String title);
}

If you look at the above SEI you can tell that it is a normal java interface with exception of two annotation

  • @WebService – This is an annotation JAXWS library. It turns a normal POJO into a webservice. In our case the annotation is placed right above the interface definition and it notifies that BookShelfService is not a normal interface rather an webservice interface or SEI. There are other attributes to this annotation that can completely define the webservice but we will not be using it right now.
  • @WebMethod – This annotation is optional and is mainly used to provide a name attribute to the public method in wsdl.

Implementing the service. 

Now we have our SEI so let us implement the methods in the interface in our BookShelfServiceImpl

package com.aranin.weblog4j.services;

import com.aranin.weblog4j.hashdb.HashDB;
import com.aranin.weblog4j.vo.BookVO;

import javax.jws.WebService;

@WebService(endpointInterface = "com.aranin.weblog4j.services.BookShelfService",
		serviceName="bookShelfService")
public class BookShelfServiceImpl implements BookShelfService {
    public String insertBook(BookVO bookVO) {
        HashDB.insertBook(bookVO);
        return "Book with name : " + bookVO.getBookName() + " is now available on the shelf";  //To change body of implemented methods use File | Settings | File Templates.
    }

    public BookVO getBook(String title) {

        return HashDB.getBook(title);  //To change body of implemented methods use File | Settings | File Templates.
    }
}

This class is a simple POJO implementing the SEI. Only notable thing here is the @WebService annotation. If you look at it closely we have provided the fully qualified class name of the SEI it implements and name of the webservice.

Data Binding class (BookVO)

package com.aranin.weblog4j.vo;

import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@XmlRootElement(name = "Book")
public class BookVO implements Serializable {

    private long bookId;
    private String bookName;
    private String author;

    public long getBookId() {
        return bookId;
    }

    public void setBookId(long bucketId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

The only thing to note here is the @XmlRootElement annotation. This annotation is part of JAXB library. CXF uses JAXB as default data binding component. As BookVO needs to be transported as XML during the webservice calls hence it needs to marshalled/unmarshalled by the JAXB engine in the CXF installation. Using @XmlRootElement annotation we help JAXB in mapping the BookVO class to an xml with its name attribute as root element of the xml.

Spring Based Server Bean

What makes CXF a first rate choice as webservice framework is that it publishes its service endpoints via a spring based configuration file. Lets create a  the configuration file and register our service in it. We will name the file as beans.xml and save it in WEB-INF folder of our application

<?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"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
	xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans.xsd


http://cxf.apache.org/jaxrs


http://cxf.apache.org/schemas/jaxrs.xsd


http://cxf.apache.org/jaxws

http://cxf.apache.org/schemas/jaxws.xsd">

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

<jaxws:endpoint
       id="bookShelfService"
       implementor="com.aranin.weblog4j.services.BookShelfServiceImpl"
       address="/bookshelfservice" />

</beans>

Now to load the beans.xml we simply add following in web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans.xml,/WEB-INF/applicationContext.xml</param-value>
</context-param>

Finally we need to wire spring and CXF through web.xml.

<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>2</load-on-startup>
</servlet>

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

Note: I have not included loading of Spring ContextLoaderListner. If you create a struts2 application via maven using struts2 starter archetype then spring is downloaded and registered by maven project itself.

Now your webservice is ready. Compile and deploy the application in any servlet container. If everything is good then you can see your wsld on following location: http://localhost:8080/weblog4jdemo/bookshelfservice?wsdl

Create your client

There are many tools which can be used to generate client code using the wsdl. To save you further trouble we will utilize CXF’s own front end apis. So let us look at the steps.

  1. Create a simple maven project using IDE of your choice. I am using IntelliJ currently and it is awesome. Lets say name of the project is DemoClient.
  2. Add the CXF dependencies as shown in create skeleton application section.
  3. Since we know what the SEIs and public method and binding objects are. We will create them in the client side to save us trouble. In case there are many such classes we can use tools like wsdl2java etc to generate our code.
  4. Create a stub SEI in exact same package structure as the parent SEI.
  5. Create BookVO in same package structure as the parent BookVO.
  6. The above classes should be exactly same as you have created in the parent application.
  7. We need not create the SEI implementation at client end.
  8. Now we will create a client using JaxWsProxyFactoryBean. This class is a factory which works with the SEI proxies to invoke web service methods. Here is the class.
package com.aranin.weblog4j.client;

import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class DemoClient {
    public static void main(String[] args){
        String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setServiceClass(BookShelfService.class);
		factory.setAddress(serviceUrl);
		BookShelfService bookService = (BookShelfService) factory.create();

        //insert book
        BookVO bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Earth");

        String result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Empire");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Arthur C Clarke");
        bookVO.setBookName("Rama Revealed");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        //retrieve book

        bookVO = bookService.getBook("Foundation and Earth");

        System.out.println("book name : " + bookVO.getBookName());
        System.out.println("book author : " + bookVO.getAuthor());

    }
}

Here is the output of above calls

INFO: Creating Service {http://services.weblog4j.aranin.com/}BookShelfServiceService from class com.aranin.weblog4j.services.BookShelfService
result : Book with name : Foundation and Earth is now available on the shelf
result : Book with name : Foundation and Empire is now available on the shelf
result : Book with name : Rama Revealed is now available on the shelf
book name : Foundation and Earth
book author : Issac Asimov

Process finished with exit code 0

There are tons of other stuff you can explore in Apache CXF like Creating dynamic clients, interceptors, leveraging other transport protocol, webservice over https etc. But I intend this post as getting started tutorial.

Phew this is a long post again. I need to improve my writing skills to shorten the length. But still I hope that you enjoyed it and found it useful. I intend to write about a javascript client for webservices in my next post. Until then goodbye and happy coding.
 

Reference: Developing SOAP Web service using Apache CXF from our JCG partner Niraj Singh at the Weblog4j blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

8 Responses to "Developing SOAP Web service using Apache CXF"

  1. Balu says:

    Very good post Neeraj!!!

  2. Thanks Guys,

    I am glad you found it useful.

    Regards
    Niraj

  3. Ken says:

    This is nicely done. I learned more from this post than I learned reading one of the Packt books on the subject. Just one question: Are you planning to provide more post on CXF development. Some treatments on messaging , filters and interceptors will be really be helpful.

    • Hi Ken,

      Thanks for the encouraging comment :-). I do intend to write more on the subject. Lately finding less and less time to devote to blogging. I will drop a comment here once I write something on CXF.

      Regards
      Niraj

  4. srinivas says:

    Hi,
    Its very helpful article for Beginners like me.
    I’m trying to execute the above and I’m strucked at class BookShelfServiceImpl is using HashDB class/interface. which is not having code snippet. can please place or add to complete this example.

    Thanks in advance.

    -Srinivas

  5. Raj says:

    Hi,
    really nice blog for beginners like me to start.
    am not able to find a jar file containing META-INF/cxf/cxf-extension-soap.xml
    I am trying this with latest apache cfx 3.0.1. Do i need to replace it with META-INF/cxf/cxf-extension-jaxws.xml Please let me know thanks.

Leave a Reply


+ nine = 11



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close