Skip navigation

Hi All,

Great place to buy stuff : Deals2buy

In this series we will look at using JAX-WS for building Web Services. This series will start with simple web services and then we will go on complex topics. I won’t be dealing with advantages and basics of JAX-WS here.

Building a Web Service (Server-Side) :

We will start with a simple Server side class .

import java.util.HashMap;
import java.util.Map;

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

@WebService
public class BookQuoteEndpoint {
	static Map bookPriceMap = new HashMap();

	static {
		bookPriceMap.put("J2EE Web Services","500");
		bookPriceMap.put("SOA using Java Web Service","450");
	}

	@WebMethod
	public String getBookPrice(String bookname) {

		if(bookPriceMap.containsKey(bookname)) {
			return bookPriceMap.get(bookname);
		} else {
			return "Book Not Found";
		}

	}
}

Those who are familiar with JAX-RPC will appreciate the fact that this class looks very simple (thanks to heavy use of Annotations in JAX-WS) .There is no interface to implement , no exceptions to be declared ….
I have declared BookQuoteEndpoint as a Web Service which has its method getBookPrice exposed as a Web Service operation. I get a String as input (name of the boook whose price is to be found) and return back a String which gives the price of the book.

Now we need to deploy this on the server . You can use Tomcat or Glassfish . I used Glassfish for these examples simply because I found it great !

I used the ant file to build this application.I have used the build.xml from the samples which you get here https://jax-ws.dev.java.net/jax-ws-20-fcs/samples/docs/index.html .

To build the server side you need to use apt task. Apt task will process the annotations and generate two source files : GetBookPrice and GetBookPriceResponse . These two classes are the wrappers for input and output parameters of the getBookPrice method.

This is how the ANT task looks like :

    <taskdef name="apt" classname="com.sun.tools.ws.ant.Apt">
        <classpath refid="jaxws.classpath"/>
    </taskdef>

    <target name="build-server-java" depends="setup">
        <apt
                fork="true"
                debug="true"
                verbose="${verbose}"
                destdir="${build.classes.home}"
                sourcedestdir="${build.classes.home}"
                sourcepath="${basedir}/src">
            <classpath>
                <path refid="jaxws.classpath"/>
                <pathelement location="${basedir}/src"/>
            </classpath>
            <option key="r" value="${build.home}"/>
            <source dir="${basedir}">
                <include name="src/**/*.java"/>
            </source>
        </apt>
        <!-- copy handlers descriptor file -->
        <copy todir="${build.classes.home}">
            <fileset dir="${basedir}/src">
                <include name="**/*.xml"/>
            </fileset>
        </copy>
    </target>

We first need to define a new definition to the current project using taskdef. This task is implemented by com.sun.tools.ws.ant.Apt. The jaxws.classpath refers to the jar files of Web service. I am using Sun RI in this tutorial.

Here is the description of the attributes of this task :


destdir                    Location to store the class files.
sourcedestdir           Location to store the source files generated while processing the annotations
sourcepath         	Location of the java files which are to be processed.

The GetBookPrice looks like this :

package com.example.jaxws;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "getBookPrice", namespace = "http://example.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getBookPrice", namespace = "http://example.com/")
public class GetBookPrice {

    @XmlElement(name = "arg0", namespace = "")
    private String arg0;

    /**
     *
     * @return
     *     returns String
     */
    public String getArg0() {
        return this.arg0;
    }

    /**
     *
     * @param arg0
     *     the value for the arg0 property
     */
    public void setArg0(String arg0) {
        this.arg0 = arg0;
    }

}

First thing you would notice here is that the package is com.example.jaxws while the BookQuoteEndpoint had com.example . This class is generated by the APT tool and it generates this package by default. We can of course customize so as to suite our package.

Lets have a look at GetBookPriceResponse class as well.

@XmlRootElement(name = "getBookPriceResponse", namespace = "http://example.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getBookPriceResponse", namespace = "http://example.com/")
public class GetBookPriceResponse {

    @XmlElement(name = "return", namespace = "")
    private String _return;

    /**
     *
     * @return
     *     returns String
     */
    public String getReturn() {
        return this._return;
    }

    /**
     *
     * @param _return
     *     the value for the _return property
     */
    public void setReturn(String _return) {
        this._return = _return;
    }

}

Once you have these classes you just need some configuration files .

Lets see the deployment descriptor first :

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<listener>
	<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <description>JAX-WS endpoint - sample1</description>
        <display-name>sample1</display-name>
        <servlet-name>sample1</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>sample1</servlet-name>
        <url-pattern>/getBookQuote</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
</web-app>

For Glassfish , I had to use one more configuration file called sun-jaxws.xml . It looks like this :

<?xml version="1.0" encoding="UTF-8"?>

<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
    <endpoint
        name='sample1'
        implementation='com.example.BookQuoteEndpoint'
        url-pattern='/getBookQuote'/>

</endpoints>

This file is kept in the same directory as the deployment descriptor (WEB-INF). You then need to create a war and deploy it in Glassfish. Try accessing the wsdl like this:

http://localhost:8080/jaxwsserver/getBookQuote?wsdl

Wow you have deployed your web service successfully !!!

Creating a Web Service Client :
To generate a client we need to use wsimport task . Either you can use ant task for wsimport or you can use wsimport directly on command prompt.This is how you use wsimport in ant .

    <taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
        <classpath refid="jaxws.classpath"/>
    </taskdef>
    <wsimport
                debug="true"
                verbose="${verbose}"
                keep="true"
                destdir="${build.classes.home}"
                package="com.example"
                wsdl="http://localhost:8080/jaxwsserver/getBookQuote?wsdl">
    </wsimport>

This wsimport task is implemented by com.sun.tools.ws.ant.WsImport .

Let us see various attributes of wsimport task :

keep          Keep generated files
destdir       Specify where to place output generated classes
package       Specifies the target package
wsdl          Location of the wsdl file . You can have wsdl in your machine or you can give the URL  where you can get it

When this task is executed, you have java files are generated in the dest dir . You will see these all files generated :

interface BookQuoteEndpoint
class BookQuoteEndpointService extends Service
class GetBookPrice
class GetBookPriceResponse
class ObjectFactory
package-info.java

Now we will see how we use these classes in our Client application :

package com.example;

public class BookQuoteClient {

	public static void main(String args[]) {
		BookQuoteEndpoint bqe = new BookQuoteEndpointService().getBookQuoteEndpointPort();
		String price = bqe.getBookPrice("J2EE Web Services");
		System.out.println(price);
	}
}

As you can see in the client program we are first creating an instance of BookQuoteEndpointService and getting a port from that instance. The class BookQuoteEndpointService extends a Service . A Service is an abstraction which represents a WSDL service.Calling getPort method on the service gives you a Proxy . Proxies provide access to service endpoint interfaces at runtime without requiring static generation of a stub class.

The Proxy returned is of type BookQuoteEndpoint . On this proxy we call the method getBookPrice with paramters and get the result .

This finishes with the creation of our first Web Service application using JAX-WS.

5 Comments

  1. I’m actually facing an error when i generate java classes from the wsdl file. The stubs that are generated from the wsdls doesnt have an @XmlElement annotation and some of them have the @XmlElement with just the name. The targetNamespace is not getting generated.

    The wsdl i’m using is a standard wsdl (not defined by me).

    If you have ever faced such a scenario and if u have found out any solution for that problem please let me know

    • Can you point me to the wsdl file and also the steps which you followed for creating Java classes from wsdl?

  2. Can you give me ur contact email so that i can send u the wsdl that i was referring to

  3. I have a valid WSDL that I run through wsimport, however I do not get endpoint classes or source. Everything else is there, ObjectFactory, package-info, and the other service specific classes, but no endpoint classes or source.

  4. The best tutorial I ever read!!!
    thanks a lot…
    great job


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: