Thursday, December 10, 2009

Develop simple JAX-WS web service using Metro

After working on JAX-RPC web services, it is time to go for much acclaimed web services technology JAX-WS. People says it is an extension of JAX-RPC, some says it’s a replacement of JAX-RPC.

Let me brief you about some difference between JAX-RPC and JAX-WS before we jump to jax-ws service.

  • JAX-WS maps to Java 5. So features of Java 5 are supported like annotations, generics, etc.
  • Support SOAP 1.1 and 1.2
  • support WS-I basic profile 1.1 (new version)
  • JAX-RPC has it’s own data type mapping model and covering 90% of XML schemas. However I have experienced interoperability issue while using JAX-RPC. JAX-WS uses JAXB mapping model which covers all XML Schemas with less interoperability issues.

Detailed features list/comparison is available on http://www.ibm.com/developerworks/webservices/library/ws-tip-jaxwsrpc.html (worth reading!!!!)

Discussing my own experience, Recently I have been involved in assignment where we had to replace existing AXIS services with JAX-WS services. When we started, we were not sure about success because our applications were first one who stared this remediation. I remember we haven’t had any major hitch (like Interoperability) in remediation task. These services have different types of consumers like .NET application, J2EE application, Workflow Tool. Moreover many of these services were using standard java types like HashTable, Map (either as a input parameter or return type) and luckily we did not face any issue during remediation. All these consumers are able to access new service without any issue. :).

Now let’s start with JAX-WS web services. We all know that services can be developed either using Top-down approach(i.e. WSDL-web service) or bottom up (i.e. web service – WSDL) approach . Metro is supporting both approaches. It provides command line/ant tasks utilities (same as wsdl2java and java2wsdl). If you are using NetBeans IDE then it will generate artifacts in few clicks. You will also find eclipse plugin for the same.

Let me explain steps to develop simple JAX-WS service using Metro RI. Here I am talking about top-down approach (which is recommended in web service development).

1) Design your wsdl first. You can use either doc/literal or rpc/encoded. Now a days most of the applications are using doc/literal style of web service. I have also used same style.

   1: <?xml version="1.0" encoding="UTF-8" standalone="no"?>
   2: <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
3: xmlns:tns="http://hello.jaxws.webservice.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
4: xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="HelloService"
5: targetNamespace="http://hello.jaxws.webservice.com">
6: <wsdl:types>
7: <xsd:schema targetNamespace="http://hello.jaxws.webservice.com">
8: <xsd:element name="HelloJAXWSServiceRequest">
9: <xsd:complexType>
10: <xsd:sequence>
11: <xsd:element name="in" type="xsd:string" />
12: </xsd:sequence>
13: </xsd:complexType>
14: </xsd:element>
15: <xsd:element name="HelloJAXWSServiceResponse">
16: <xsd:complexType>
17: <xsd:sequence>
18: <xsd:element name="out" type="xsd:string" />
19: </xsd:sequence>
20: </xsd:complexType>
21: </xsd:element>
22: </xsd:schema>
23: </wsdl:types>
24: <wsdl:message name="HelloJAXWSServiceRequest">
25: <wsdl:part element="tns:HelloJAXWSServiceRequest" name="parameters" />
26: </wsdl:message>
27: <wsdl:message name="HelloJAXWSServiceResponse">
28: <wsdl:part element="tns:HelloJAXWSServiceResponse" name="parameters" />
29: </wsdl:message>
30: <wsdl:portType name="HelloService">
31: <wsdl:operation name="HelloJAXWSService">
32: <wsdl:input message="tns:HelloJAXWSServiceRequest" />
33: <wsdl:output message="tns:HelloJAXWSServiceResponse" />
34: </wsdl:operation>
35: </wsdl:portType>
36: <wsdl:binding name="HelloServiceSOAP" type="tns:HelloService">
37: <soap:binding style="document"
38: transport="http://schemas.xmlsoap.org/soap/http" />
39: <wsdl:operation name="HelloJAXWSService">
40: <soap:operation soapAction="http://www.example.org/HelloService/NewOperation" />
44: <wsdl:output>
  45:                 <soap:body use="literal" />
  46:             </wsdl:output>
  47:         </wsdl:operation>
  48:     </wsdl:binding>
  49:     <wsdl:service name="HelloService">
  50:         <wsdl:port binding="tns:HelloServiceSOAP" name="HelloServiceSOAP">
  51:             <soap:address location="http://localhost:8080/helloservice/HelloWebService" />
  52:         </wsdl:port>
  53:     </wsdl:service>
  54: </wsdl:definitions>

2) Add ws-import task in your ant script. Make sure you have jax-ws libraries in classpath before executing it. (note: to execute this task from build script, just add jaxws-tools.jar in Ant classpath)


   1: <taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
   2:      <classpath refid="jaxws.classpath"/>
   3:  </taskdef>

3) add below target to generate jax-ws artifacts using ws-import task.

   1: <target name="wsgeneration" description="generating jax-ws artifacts">
   2:         <wsimport wsdl="${basedir}/WebContent/WEB-INF/wsdl/HelloService.wsdl"
   3:             destdir="${build.home}" sourcedestdir="${root}/src" verbose="true"
   4:             keep="true">
   5:         </wsimport>
   6: </target>

I have shown basic attributes here for generating artifacts. “wsdl” contains wsdl location (you can keep it anywhere). “dest-dir” should be directory in which generated artifact classes will be placed. “sourcedestdir” contains generated source files.

Successful execution of buid script will generate below set of artifacts.(Note: Below list may vary depending upon your schema definition)

HelloJAXWSServiceRequest.java (request object as defined in wsdl)
HelloJAXWSServiceResponse.java(response object as defined in wsdl
HelloService_Service.java
HelloService.java (SEI – service endpoint interface)
ObjectFactory.java (annotated source files)
package-info.java

4) Now create an implementation class say HelloServiceImpl which implements SEI (i.e. HelloService here)

  1: /**
   2:  * 
   3:  */
   4: package com.webservice.jaxws.hello;
   5:  
   6: /**   
   7:  * @author chintz
   8:  *
   9:  */
  10: public class HelloServiceImpl implements HelloService {
  13:     @Override
  14:     public HelloJAXWSServiceResponse helloJAXWSService(
  15:             HelloJAXWSServiceRequest parameters) {
  17:         //get web service in parameters from request
  18:         String inParam = parameters.getIn();
  20:         //do some processing
  21:         String response = "Hello" + inParam;
  23:         //set response in HelloJAXWSServiceResponse object
  24:         HelloJAXWSServiceResponse wsRes = new HelloJAXWSServiceResponse();
  25:         wsRes.setOut(response);
  27:         //return response
  28:         return wsRes;
  29:     }
  31: }

5) Add JAX-WS listener and servlet entries in web.xml. This listener and servlet is useful in initializing JAX-WS runtime. Listener is same like Spring’s ServletContextLoaderListener whose job is to initialize Spring framework.



   1: <listener>
   2:     <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
   3: </listener>
   4: <servlet>
   5:     <description>JAX-WS endpoint</description>
   6:     <display-name>JAXWS servlet</display-name>
   7:     <servlet-name>helloservice</servlet-name>
   8:     <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
   9:     <load-on-startup>1</load-on-startup>
  10: </servlet>
  11: <servlet-mapping>
  12:     <servlet-name>helloservice</servlet-name>
  13:     <url-pattern>/helloservice</url-pattern>
  14: </servlet-mapping>

6) Create sun-jaxws.xml which contains endpoint implementation details.

   1: <endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
   2:     <endpoint
   3:         name='helloService'
   4:         implementation='com.webservice.jaxws.hello.HelloServiceImpl'
   5:         url-pattern='/helloservice'/>
   6: </endpoints>

So whenever any request comes with defined url-pattern (in our case “helloservice”) it will look for service implementation details from sun-jaxws.xml and execute corresponding service method.

Now bundle everything in WAR file and deploy it. If you see message like “Initialized WSServlet” and “JAX-WS framework ready” (on server console) during deployment it means that you are all set.
Verify your service deployment by accessing: (http://localhost:8080/helloservice/HelloWebService) or wsdl (http://localhost:8080/helloservice/HelloWebService?wsdl)

So your simple Hello JAX-WS service ready. Now test it using client application. To start with, test it using SoapUI tool.

Hope this article will help you in developing JAX-WS service.

No comments:

Subscribe in Reader