This post is about developing a JAX-WS web service and deploying on tomcat 6.
The top down approach is used to develope Web Service.
Environment :
Eclipse Juno
Tomcat 6
Apache maven 3
JAX-WS reference implementation - Sun's Metro
Steps to create Web Service :
1)Create a WSDL file using eclipse WSDL editor :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.atulajoshi.org/userDetails/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="userDetails" targetNamespace="http://www.atulajoshi.org/userDetails/">
<wsdl:types>
<xsd:schema targetNamespace="http://www.atulajoshi.org/userDetails/">
<xsd:element name="getUserDetails">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="userId" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getUserDetailsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="userFirstName" type="xsd:string" />
<xsd:element name="userLastName" type="xsd:string"></xsd:element>
<xsd:element name="userAddress" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="getUserDetailsRequest">
<wsdl:part element="tns:getUserDetails" name="parameters"/>
</wsdl:message>
<wsdl:message name="getUserDetailsResponse">
<wsdl:part element="tns:getUserDetailsResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="userDetails">
<wsdl:operation name="getUserDetails">
<wsdl:input message="tns:getUserDetailsRequest"/>
<wsdl:output message="tns:getUserDetailsResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="userDetailsSOAP" type="tns:userDetails">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getUserDetails">
<soap:operation soapAction="http://www.atulajoshi.org/userDetails/getUserDetails"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="userDetails">
<wsdl:port binding="tns:userDetailsSOAP" name="userDetailsSOAP">
<soap:address location="http://localhost:8080/UserDetailsService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
2)Create a maven project with archtype as webapp. It will create a pom.xml file.
Add a jax-ws maven plugin with wsimport as goal. Below is the pom.xml I used.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atul</groupId>
<artifactId>jaxws</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jaxws Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.8</version>
</dependency>
</dependencies>
<build>
<finalName>jaxws</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>execution</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlDirectory>src/wsdl</wsdlDirectory>
<packageName>com.atul.jaxws.service</packageName>
<sourceDestDir>src/main/java</sourceDestDir>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories>
</project>
3)Import this project into eclipse.
4)Now run mvn clean install
5)It will generate following important classes :
1)UserDetails.java : an interface corresponding to service element in wsdl with a method same as operation element defined in portType element.
2)GetUserDetails.java and GetUserDetailsResponse.java : corresonding to input and output message parts.
3)UserDetails_Service.java : A service stub used by client
6)Now implement a web service by implementing the interface UserDetails as below
package com.atul.jaxws.service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebParam.Mode;
import javax.xml.ws.Holder;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.jws.WebService;
@WebService(serviceName = "userDetails", portName = "userDetailsSOAP",
targetNamespace = "http://www.atulajoshi.org/userDetails/", wsdlLocation = "userDetails.wsdl",
endpointInterface = "com.atul.jaxws.service.UserDetails")
public class UserDetailsImpl implements UserDetails {
@WebMethod(action = "http://www.atulajoshi.org/userDetails/getUserDetails")
@RequestWrapper(localName = "getUserDetails", targetNamespace = "http://www.atulajoshi.org/userDetails/", className = "com.atul.jaxws.service.GetUserDetails")
@ResponseWrapper(localName = "getUserDetailsResponse", targetNamespace = "http://www.atulajoshi.org/userDetails/", className = "com.atul.jaxws.service.GetUserDetailsResponse")
public void getUserDetails(
@WebParam(name = "userId", targetNamespace = "") String userId,
@WebParam(name = "userFirstName", targetNamespace = "", mode = Mode.OUT) Holder<String> userFirstName,
@WebParam(name = "userLastName", targetNamespace = "", mode = Mode.OUT) Holder<String> userLastName,
@WebParam(name = "userAddress", targetNamespace = "", mode = Mode.OUT) Holder<String> userAddress) {
// TODO Auto-generated method stub
System.out.println("input param got .."+userId);
userFirstName.value = "Atul";
userLastName.value = "Joshi";
userAddress.value = "Pune";
}
}
The important thing to note here is parameters with Holder classes (userFirstName ,userLastName and userAdress). Please see how these parameters are set with values which are sent back to client. Also please note that their mode is set as OUT meaning they will be filled up with values and sent back to client.
7)Run maven : mvn clean install
8)Since we are deploying this on tomcat6 with Sun'S RI, sun-jaxws.xml should be added which should look like below : (web.xml should be standard one using WSServlet and corresponding listener for Sun's RI)
<?xml version="1.0" encoding="UTF-8"?>
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="userDetails"
implementation="com.atul.jaxws.service.UserDetailsImpl"
url-pattern="/UserDetailsService" />
</endpoints>
8)Deploy the .war file in tomcat.I prefer modofying server.xml file to deploy the exploded web app directory on tomcat.
Following is the Host element snippet from server.xml file
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
-->
<Context docBase="F:/study/jaxws/target/jaxws" path="/jaxws" reloadable="true"/>
</Host>
9)Access the WSDL of web service by :
http://localhost:8080/jaxws/UserDetailsService?wsdl
Problems Faces :
1)While running mvn clean install , I got below maven error :
Failed to execute goal org.jvnet.jax-ws-commons:jaxws-maven-plugin:2.3:wsimport (execution2) on project jaxws: Execution execution2 of goal org.jvnet.jax-ws-commons:jaxws-maven-plugin:2.3:wsimport failed: String index out of range: -1 -> [Help 1]
After I made my eclipse use JDK path as JVM instead of JRE , this error got resolved.
2)The class implementing the interface must be annotate with @WebService annotation.