Pages

Wednesday, October 01, 2008

Step by step CXF Webservice Tutorial

We had an application running, and a webservice had to be exposed. With some experience in Axis2, I decided to learn some thing new, CXF service. Well Initially, I gave up on CXF service.(Will give the details in some time). So, thought let me use the Axis2 service. But, the only way I knew to use it was deploying the axis as webapp,and then writing and deploying the service as aar. So, a search to find integrating Axis2 with an existing webapp begins! And, with shame, I can tell, I was not able to find any where a clue about doing it. I could have experimented by including there axis distribution lib, and its web.xml content in my applications, but decided to learn some thing newer. And, hence the CXF.

I was developing a flex app on the blazeds turnkey server that is distributed by adobe. And, the webservice had to be integrated with this existing application. Since, CXF was the one I wanted to learn, I tried using it(as given below in tutorial), but always ended up either with one or other exceptions as given below.

1. On startup  of server this exception used to occur when all the jars of CXF are put in the WEB-INF/lib folder.

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class pat
h resource [com/ssb/service/data.xml]; nested exception is java.lang.IllegalArgumentException: Class [org.spring
framework.scripting.config.LangNamespaceHandler] does not implement the NamespaceHandler interface
Caused by: java.lang.IllegalArgumentException: Class [org.springframework.scripting.config.LangNamespaceHandler] does no
t implement the NamespaceHandler interface at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.initHandlerMappings(DefaultNamespaceHan


2. When the spring-XXXX.jars were removed(Google helped me to point out this solution!), and the webapp was started, no problem at all. The server was up and running. But, on accessing the service as:

http://localhost:8400/cxftry/services

This exception was that I had:

java.lang.NoSuchMethodError: org.springframework.context.ConfigurableApplicationContext.addApplicationListener(Lorg/springframework/context/ApplicationListener;)V
org.apache.cxf.transport.servlet.CXFServlet.loadSpringBus(CXFServlet.java:104)
org.apache.cxf.transport.servlet.CXFServlet.loadBus(CXFServlet.java:70)
org.apache.cxf.transport.servlet.AbstractCXFServlet.init(AbstractCXFServlet.java:90)

With no information on web about any of these with CXF, I guessed the problem is the appserver, turnkey, that I was using. Though, it uses tomcat 6, not sure why it doesnt work. I downloaded a tomcat 6 server, and put the application on it and it worked like a charm. :o)

System Configurations:

1.CXF 2.1.2

2.JDK 1.5

3.TOMCAT 6

Here is the tutorial, to use CXF to expose as a webservice with Java-First methodology.

1. Download the CXF from http://cxf.apache.org/download.html
2. Extract to a directory(here, I will call it as CXF_HOME)
3. Copy paste all the lib(not recomended, go through WHICH_JARS present in CXF_HOME/lib to decide on the jars you need for your application) to WEB-INF/lib directory.
4. Write your Service Endpoint Interface (SEI), nothing but a java interface that will be exposed as a webservice.

package com.ssb.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.WebFault;

import com.ssb.exception.SomeException;
import com.ssb.model.Data;

@WebService
public interface IDataService {
    @WebMethod(operationName="getData")
    public Data  getData(@WebParam(name="id")String id) throws SomeException;
}

5. Annotate your Exception with @WebFault if any.

package com.ssb.exception;

import javax.xml.ws.WebFault;

@WebFault(name="exception")
public class SomeException extends Exception {

    public String contactInfo = "Sacrosanct Blood.";
    private static final long serialVersionUID = 1L;

    private SomeException() {
    }

    public SomeException(String message, Throwable cause) {
        super(message, cause);
    }

    public SomeException(String message) {
        super(message);
    }
}

6. Annotate your Service Implementation as a webservice.

package com.ssb.service;

import javax.jws.WebService;

import com.ssb.exception.SomeException;
import com.ssb.model.Data;

/**
* @author shreyas.purohit
*
*/
@WebService(endpointInterface="com.ssb.service.IDataService", serviceName="dataService")
public class DataServiceImpl implements IDataService {

    /**
     *
     */
    public DataServiceImpl() {
    }

    public Data getData(String id) throws SomeException{
        Data data = new Data();
        return data;
    }

}

7. Configure the data.xml for the webservice(com/ssb/service/data.xml).

<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" />
  <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  <jaxws:endpoint id="data"
                  implementor="com.ssb.service.DataServiceImpl"
                  address="/dataService"/>
</beans>

8. Configure web.xml for CXF to work.

<?xml version="1.0" encoding="UTF-8"?>
<!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>CXF</display-name>
    <description>CXF Application</description>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:com/ssb/service/data.xml</param-value>
      </context-param>
      <listener>
        <listener-class>
          org.springframework.web.context.ContextLoaderListener
        </listener-class>
      </listener>
      <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>
            org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
      </servlet-mapping>
    <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
    </welcome-file-list>
</web-app>

9. Start the server, and access http://localhost:8080/cxftry/services
You should be able to see the services. On clicking on it, the wsdl can be seen.

The annotations used in the above code is very simple and self explaining.

1. @WebService : Indicates its a webservice.

Attributes used:

endpointInterface=Specifies the full name of the SEI that the implementation class implements.
serviceName=Specifies the name of the published service.

2. @WebMethod    : Indicates a webservice method.

Attributes used:

operationName=Specifies the operation name, i.e the webservice method name.

3. @WebParam    : Used to give the parameters in the operations a meaningfull name in the published WSDL.

Attributes used:

name= Name of the argument to be displayed on the WSDL for the operation.

4. @WebFault    : Defines an exception that the operation/web service method can throw.

Attributes used:

name= The name to be used in the WSDL.

This completes a quick tutorial for publishing a Java-First webservice.

7 comments:

  1. Hi,

    your blog is looking clear and understandable. Thanks...

    can you post complete end to end tutorial(service, client and building stpes in eclipse). so that it will be very useful for new people.

    your profile looks good. looks like you have FLEX and back end webservices experience. are you looking for new opportunities...if yes please let me know. we are looking some body on FLEX.

    by the way I am also from Bangalore.

    reach: edincmail@gmail.com

    Thanks
    eduser

    ReplyDelete
  2. Hi Ed,

    I appreciate your comments.

    We generally use ant for building, and a webservice client is easily writable, you can see my tutorials on Axis2. Hence, I omitted the same.

    And, as for the job offer, thanks a lot, I will definitely contact you when I do look out for a change. :-)

    By the way, can you send me your Blog address, as your profile is not publicly accessible, i could not visit your blog.

    ..Shreyas..

    ReplyDelete
  3. This tutorial is really nice and helpful for me and having lots of information about CXF service through this post.Keep sharing like this.

    ReplyDelete
  4. Anonymous4:23 AM

    Thanks for your effort. Can you please upload the complete project.

    ReplyDelete
  5. Anonymous4:55 AM

    This is the first CXF tutorial that worked for me! :) Thanks!

    ReplyDelete
  6. Anonymous3:40 AM

    It worked for me too.

    I only had to create a Data class for it to work properly and see the Web Service on my browser:
    -------------------------
    package com.ssb.model;

    public class Data {
    private String id;

    // GETTERS & SETTERS
    public String getId() {
    return id;
    }
    public void setId(String id) {
    this.id = id;
    }
    }
    -------------------------

    Thank you very much !

    ReplyDelete
  7. Thank you so much.. it worked form me.

    ReplyDelete