2010/01/20
20 Jan, 2010

JAX-WS Service development with WSO2 Web Services Application Server – Part I

  • Isuru Suriarachchi
  • Technical Lead and Product Manager - WSO2

Many Web service developers are interested in implementing services using JAX-WS as it is the Java standard for Web Services. If you are trying to use JAX-WS support in WSO2 Web Services Application Server (WSO2 WSAS), this article will provide the necessary foundation for you by starting from the basics and going through code first and contract first development approaches in JAX-WS. This article will be followed by some more articles which will describe more advanced topics on service development and also the client side usage of JAX-WS standards.

Table of Contents

Introduction

The Java API for XML-Based Web Services (JAX-WS) 2.x specification [1] defines a standard set of APIs and conventions for supporting Web services in the Java platform. JAX-WS standard provides an easy way of developing Web services for Java users with a high level of portability. It is defined using Java annotations without using any deployment descriptors. Most Java Web services developers around the world have moved towards JAX-WS due to it's simplicity and portability.

The Java API for XML-Based RPC (JAX-RPC) 1.1 specification [2] was a standard set of APIs for RPC oriented Web services for Java. After the Web services world moved away from RPC, JAX-WS 2.0 specification was defined on top of JAX-RPC 1.1. And also the Java Architecture for XML Binding (JAXB) 2.0 specification [3] was defined in parallel to standardize the data binding functionalities. JAX-WS delegates all data binding aspects to JAXB.

WSO2 Web Services Application Server (WSO2 WSAS) 3.x [4] supports many ways of developing Web services. JAX-WS is also among them. JAX-WS support is implemented by enhancing the underlying Apache Axis2 [5] JAX-WS implementation. WSO2 Web Services Application Server (WSO2 WSAS) management console can be used to deploy and configure JAX-WS services just like any other service type.

JAX-WS Annotations

JAX-WS development is completely dependent on Java annotations which are defined in JSR-181 [6] (Web Services Metadata for the Java Platform), JAX-WS and JAXB specifications. These annotations are used to let the JAX-WS runtime know about the nature of the Web service interface. The developer can customize the Web service interface using these annotations and build the service according to his requirements. Let's have a look at the most important annotations and their member-value pairs which are used in developing JAX-WS services.

  1. @WebService
    This annotation can be used to mark a Java class when implementing a Web service or to mark a Java interface as defining a Web service interface.
    name - Name of the wsdl:portType in WSDL 1.1 [7]
    targetNamespace - The XML namespace used for the WSDL
    serviceName - Name of the wsdl:service in WSDL 1.1. This is not allowed on endpoint interfaces.
    portName - Name of the wsdl:port in WSDL 1.1. This is not allowed on endpoint interfaces.
    wsdlLocation - A URL which points to an already existing WSDL
    endpointInterface - Complete name of the endpoint interface, when the interface and the implementation are separated. This is 
    not allowed on endpoint interfaces.
    
  2. @WebMethod
    This annotation can be used to customize a method which is exposed as a Web service operation.
    operationName - Name of the wsdl:operation matching the particular method
    action - The action for this operation
    exclude - Used to leave a method out of the Web Service interface
  3. @Oneway
    This annotation can be used to indicate that the given method maps to a one way operation. It has only an input message and no output message.
     
  4. @WebParam
    This annotation can be used to customize the mapping of an individual method parameter to a Web service message part and XML element.
    name - Name of the parameter. This property relates to the style (document or rpc) of the operation and the 
    mappings are somewhat complex.
    partName - Name of the wsdl:part which represents this parameter
    targetNamespace - XML namespace for this parameter
    header - If true, the parameter is pulled from a message header, rather than the message body
  5. @WebResult
    This annotation can be used to customize the mapping of the return value to a Web service message part and XML element.
    name - Name of the return value. This property relates to the style (document or rpc) of the operation and the 
    mappings are somewhat complex.
    partName - Name of the wsdl:part which represents the return value
    targetNamespace - XML namespace for the return value
    header - If true, the return value is in a message header, rather than the message body
  6. @SOAPBinding
    Specifies the mapping of the Web service onto the SOAP message protocol.
    style - DOCUMENT or RPC
    use - LITERAL or ENCODED
    parameterStyle - WRAPPED or BARE
    JAX-WS 2.x supports the following combinations
    DOCUMENT/LITERAL/WRAPPED (default)
    DOCUMENT/LITERAL/BARE
    RPC/LITERAL/WRAPPED

    If you are not much familiar with these operation styles, please refer to these [8][9] articles which describes non JAX-WS contract first development with Apache Axis2.

Java to WSDL development model with JAX-WS

Java to WSDL or code first approach is one of the two main development models when it comes to Web services. In this approach, development starts from the code or the service implementation and the Web service engine generates the WSDL for the developer. POJO (Plain Old Java Object) development with Apache Axis2 [10] is one such example. Similarly, almost all Web service engines support POJO development in their own ways. But it doesn't provide enough control for the developer over the generated WSDL. If the code changes at some point, the generated WSDL can also be changed and that is not recommended in Web services development. In other words, the contract should not be changed after the deployment of the service.

JAX-WS provides a perfect answer for this problem through its usage of annotations. The developer can write his POJO service in the same way as earlier and use the annotations to control the structure of the WSDL. JAX-WS runtime will generate the WSDL according to these annotations. After clearly defining the WSDL interface through annotations, implementation can be changed without affecting the generated WSDL contract. Therefore, JAX-WS is the standard development technique when it comes to POJO development.

Now let's move onto some sample POJO services using JAX-WS.

Sample 01

This simple example uses the @WebService annotation to convert a simple POJO into a Web service. When you use this annotation, all the public methods in the class become operations in the service by default. If you want to exclude a particular method, you have to specify it using the 'exclude' property of the @WebMethod annotation. And also if some method should be mapped into a one way operation, you have to use the @Oneway annotation. The sample code for this simple POJO is shown below.

package org.wso2.jaxws.sample01;

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

@WebService
public class SimpleSample {

    public String echo(String echoInput) {
        return echoInput;
    }

    @Oneway
    public void ping(String pingInput) {
        System.out.println("Ping : " + pingInput);
    }

    @WebMethod(exclude = true)
    public String hideMethod(String hideInput) {
        return "Hiding : " + hideInput;
    }
}


You can just compile this class and create a jar archive and deploy it in WSO2 Web Services Application Server (WSO2 WSAS). Please refer to deployment section of this article for more details on how to deploy. After deploying it, you can see the generated WSDL 1.1 file just by clicking on the WSDL 1.1 link in front of our SimpleSampleService.

Sample 02

Now lets have a look at a somewhat complex sample which contains most of the annotations described above. This StudentMarksService contains two operations called 'computeAverage' and 'computeHighestMarks'. Both these methods gets a Student object as a parameter. You can see how we can customize the WSDL service interface using the annotations. The sample code for this sample is shown below.

StudentMraksService.java
class

package org.wso2.jaxws.sample02;

import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.soap.SOAPBinding;

@WebService(
        name = "StudentMarks",
        serviceName = "StudentMarksService",
        targetNamespace = "https://wso2.org/jaxws/sample02"
)
@SOAPBinding(
        style = SOAPBinding.Style.DOCUMENT,
        use = SOAPBinding.Use.LITERAL,
        parameterStyle = SOAPBinding.ParameterStyle.WRAPPED
)

public class StudentMarksService {

    @WebMethod(
            operationName = "computeAverage",
            action = "urn:getAverage"
    )
    @WebResult(
            name = "average",
            targetNamespace = "https://wso2.org/jaxws/sample02"
    )
    public double getAverage(
            @WebParam(name = "student", targetNamespace = "https://wso2.org/jaxws/sample02")
            Student student) {

        double totalMarks = 0;
        for (int i = 0; i < student.getMarks().length; i++) {
            totalMarks += student.getMarks()[i];
        }
        return totalMarks / student.getMarks().length;
    }

    @WebMethod(
            operationName = "computeHighestMarks",
            action = "urn:getHighestMarks"
    )
    @WebResult(
            name = "highest",
            targetNamespace = "https://wso2.org/jaxws/sample02"
    )
    public int getHighestMarks(
            @WebParam(name = "student", targetNamespace = "https://wso2.org/jaxws/sample02")
            Student student) {

        int highest = 0, temp;
        for (int i = 0; i < student.getMarks().length; i++) {
            temp = student.getMarks()[i];
            if (temp > highest) {
                highest = temp;
            }
        }
        return highest;
    }
}

Student.java class

package org.wso2.jaxws.sample02;

public class Student {

    private String name;
    private int age;
    private int[] marks;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int[] getMarks() {
        return marks;
    }

    public void setMarks(int[] marks) {
        this.marks = marks;
    }
}


Just create the jar archive and deploy the service to see the generated WSDL 1.1 file. You can check whether the WSDL elements are correctly generated according to our annotations.

Note : The deployable jar archives for both these samples can be found under attachments and you can just deploy those into WSO2 Web Services Application Server (WSO2 WSAS). And also, you can use some tool like SOAP UI [11] to invoke these services. And also try to use different customizations using annotations to have a better understanding.

WSDL to Java development model with JAX-WS

WSDL to Java or contract first approach is the other well known Web service development model. Here the WSDL contract is used to generate the service skeleton and other binding classes through the usage of some WSDL to Java tool. When it comes to JAX-WS, 'wsimport' tool which is shipped with the JDK, can be used for this purpose. It will generate the Service Endpoint Interface (SEI) and the JAXB binding classes according to the WSDL and the schema. Service developer only has to write the service class by implementing the SEI.

Now let's move on to a WSDL to Java sample using JAX-WS.

Sample 01


Here I'm going to create the same StudentMarksService above with the generated WSDL. You can see that the JAX-WS generated WSDLs in WSO2 Web Services Application Server (WSO2 WSAS) contains a schema import. In order to make it simple, I've included the schema in the WSDL itself just by removing the schema import and pasting the schema under the 'types' section. You can have a look at the 'StudentMarksService.wsdl' which can be found under attachments.

First of all, we have to generate the code using the 'wsimport' tool. You can use the following command on the console to easily generate the code. Create a folder (Ex: wsdl2java) to place your generated source files.

wsimport -s wsdl2java StudentMarksService.wsdl


Now we have the generated Java files. Next step is to write the service implementation class. Just use your favorite IDE and create a project using the generated classes. Then write the service class by implementing the SEI. Use the @WebService annotation to map the properties according to your WSDL and make sure you point to your WSDL file using the 'wsdlLocation' property. Service class is shown below.

package org.wso2.jaxws.sample02.service;

import org.wso2.jaxws.sample02.StudentMarksPort;
import org.wso2.jaxws.sample02.Student;

import javax.jws.WebService;

@WebService(
        serviceName = "StudentMarksService",
        portName = "StudentMarksPort",
        targetNamespace = "https://wso2.org/jaxws/sample02",
        endpointInterface = "org.wso2.jaxws.sample02.StudentMarksPort",
        wsdlLocation = "StudentMarksService.wsdl"       
)
public class StudentMarksImpl implements StudentMarksPort {
    
    public double computeAverage(Student student) {
        double totalMarks = 0;
        for (int i = 0; i < student.getMarks().size(); i++) {
            totalMarks += student.getMarks().get(i);
        }
        return totalMarks / student.getMarks().size();
    }

    public int computeHighestMarks(Student student) {
        int highest = 0, temp;
        for (int i = 0; i < student.getMarks().size(); i++) {
            temp = student.getMarks().get(i);
            if (temp > highest) {
                highest = temp;
            }
        }
        return highest;
    }
}


Now compile your project and create the jar archive to be deployed. Note that you have to include your WSDL file at the root level of your jar archive (find the completed jar archive under attachments). Finally deploy the service and invoke it. 

Deploying your JAX-WS services in WSO2 Web Services Application Server (WSO2 WSAS)

After implementing your JAX-WS service using one of the above mentioned approaches, you can easily deploy it in WSO2 Web Services Application Server (WSO2 WSAS). Here are the steps to follow.

  1. Compile your annotated classes.
  2. Create a jar archive to be deployed including your compiled classes with the proper package structure. If your service depends on third party libraries, place those in a 'lib' folder inside the jar archive. If your service depends on an already existing WSDL file, include it at the root level of the archive. (You can use a WSDL which is located somewhere in the file system as well. In that case, you have to use the absolute path for 'wsdlLocation')

  3. Download WSO2 Web Services Application Server (WSO2 WSAS) 3.x and extract it. Copy jaxws-rt.jar [12] and jaxws-tools.jar [13] in to WSAS_HOME/repository/components/extensions folder and start the server.
  4. Log into the management console and upload your JAX-WS jar archive using the 'JAX-WS' service link under Services/Add.
  5. Refresh the service listing page. You can see the deployed service.

Conclusion

In this article, first we discussed the JAX-WS standards with basic annotations. After that we moved into Java to WSDL and WSDL to Java development approaches using JAX-WS with comprehensive samples. Finally we discussed how to deploy JAX-WS artifacts in WSO2 Web Services Application Server (WSO2 WSAS).

Although this article provides the foundation for JAX-WS development, there are many more areas defined in the JAX-WS specification. We'll be discussing more advanced topics in the next steps in this series of articles. In addition to that, there will be some articles on client side usage of JAX-WS as well.

References

[1] JAX-WS 2.2 specification
[2] JAX-RPC 1.1 specification
[3] JAXB 2.2 specification
[4] WSO2 Web Services Application Server (WSO2 WSAS)
[5] Apache Axis2
[6] JSR 181 specification
[7] WSDL 1.1 specification
[8] Contract first article – Part 1
[9] Contract first article – Part 2
[10] Apache Axis2 POJO guide
[11] SOAP UI
[12] jaxws-rt.jar
[13] jaxws-tools.jar

Author

Isuru Suriarachchi, Senior Software Engineer, WSO2, isuru AT wso2 DOT com.

 

 

About Author

  • Isuru Suriarachchi
  • Technical Lead and Product Manager
  • WSO2 Inc.