<document>
  <header>
    <product>resin</product>
    <title>A JAX-WS Service for the Resin SOA</title>
    <description>
      <p>Resin simplifies deployment of JAX-WS applications by avoiding the
      need for complicated WSDLs and schema.
      </p>
    </description>
    <type>tutorial</type>
    <tutorial-startpage>demo.jsp</tutorial-startpage>
  </header>

  <body>
    <summary/>

  <s1>
<p>JAX-WS (Java API for XML Web Services) offers a powerful new approach to
writing SOAP-based services.  However because its design is so tightly coupled
to WSDL (Web Service Definition Language), getting started writing a simple
service has up until now been difficult and confusing.  This tutorial shows
how to write a simple, straightforward SOAP service starting with Java.  We
will also see how easy it is to deploy web services using Resin's easy to
understand XML configuration.
</p>
</s1>

<s1 title="Files in this tutorial">
<deftable>
<tr><td><viewfile-link file="WEB-INF/classes/example/UserService.java"/>
    </td><td>The main service implementation.
</td></tr><tr><td><viewfile-link file="WEB-INF/classes/example/User.java"/>
    </td><td>User class
</td></tr><tr><td><viewfile-link file="WEB-INF/resin-web.xml"/>
    </td><td>Configures the environment
</td></tr><tr><td><viewfile-link file="demo.jsp"/>
    </td><td>Client JSP
</td></tr></deftable>
</s1>

<s1 title="What are JAX-WS, SOAP, and WSDL?">
<p>
SOAP is essentially an XML-based protocol for invoking remote methods.  For
example, if we have a method <code>int add(int a, int b)</code>, the SOAP 
request and response for this method might look like the following:
</p>

<example title="SOAP request">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  &lt;soapenv:Body>
    &lt;m:add xmlns:m="http://example/">
      &lt;a>1&lt;/a>
      &lt;b>2&lt;/b>
    &lt;/m:add>
  &lt;/soapenv:Body>
&lt;/soapenv:Envelope>
</example>

<example title="SOAP response">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  &lt;soapenv:Body>
    &lt;m:addResponse xmlns:m="http://example/">
      &lt;result>3&lt;/result>
    &lt;/m:addResponse>
  &lt;/soapenv:Body>
&lt;/soapenv:Envelope>
</example>

<p>
WSDL is an XML-based language that describes the interface to SOAP services
like the one above.  It is very flexible and allows for numerous styles of
SOAP invocations.  Unfortunately, it can be very difficult to read.  For
example, the above exchange might have the following WSDL:
</p>

<example title="Add service WSDL">
&lt;?xml version="1.0" standalone="yes"?>
&lt;definitions targetNamespace="http://example/" 
             name="AddService" 
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
             xmlns="http://schemas.xmlsoap.org/wsdl/" 
             xmlns:m="http://example/">
  &lt;types>
    &lt;xsd:schema version="1.0" 
                targetNamespace="http://example/">
      &lt;xsd:element name="add" type="m:add"/>
      
      &lt;xsd:complexType name="add">
        &lt;xsd:sequence>
          &lt;xsd:element name="a" type="xsd:int"/>
          &lt;xsd:element name="b" type="xsd:int"/>
        &lt;/xsd:sequence>
      &lt;/xsd:complexType>

      &lt;xsd:element name="addResponse" type="m:addResponse"/>

      &lt;xsd:complexType name="addResponse"/>
        &lt;xsd:sequence>
          &lt;xsd:element name="result" type="xsd:int"/>
        &lt;/xsd:sequence>
      &lt;/xsd:complexType>
    &lt;/xsd:schema>
  &lt;/types>

  &lt;message name="add">
    &lt;part name="parameters" element="m:add"/>
  &lt;/message>

  &lt;message name="addResponse">
    &lt;part name="parameters" element="m:addResponse"/>
  &lt;/message>

  &lt;portType name="Add">
    &lt;operation name="add">
      &lt;input message="m:add"/>
      &lt;output message="m:addResponse"/>
    &lt;/operation>
  &lt;/portType>

  &lt;binding name="AddPortBinding" type="m:Add">
    &lt;soap:binding transport="http://schemas.xmlsoap.org/wsdl/soap/" 
                  style="document"/>

    &lt;operation name="add">
      &lt;soap:operation soapAction=""/>

      &lt;input>
        &lt;soap:body use="literal"/>
      &lt;/input>
      &lt;output>
        &lt;soap:body use="literal"/>
      &lt;/output>
    &lt;/operation>
  &lt;/binding>

  &lt;service name="AddService">
    &lt;port name="AddPort" binding="m:AddPortBinding">
      &lt;soap:address location="http://example/add-service/"/>
    &lt;/port>
  &lt;/service>
&lt;/definitions>
</example>
<p>
After looking at this WSDL, which is one of the simpler examples, you might
begin to understand why WSDL has become mostly interpreted by programs and 
not people.  If you are a client of another organization and plan to use their
SOAP services, you may have to use their WSDL to generate Java code for your
client.  However if you are designing your own service, especially for 
intra-organizational use only, there may be no need to use WSDL at all!
</p>
<p>
JAX-WS is a Java API and architecture for writing SOAP services and clients.
Because WSDLs are necessary in some cases, JAX-WS has a lot of functionality
that deals with reading and generating them.  Unfortunately, if you're simply
trying to write your own simple service, dealing with WSDL can be very
confusing and complicated.  In the example below, we will show how to write
a simple, but useful service that uses JAX-WS without ever touching a WSDL!
</p>
</s1>

<s1 title="User Service Client">

<p>
Our service consists of one method, <code>getUsers()</code> that takes a
group id and returns all the users in that group.  If the group doesn't exist,
the service throws an exception.
</p>

<p>First we will need an interface for our service.  The interface is
an actual Java interface.  The service implementation will implement this 
interface and the client will obtain a proxy that exposes it.</p>

<example title="UserService.java">
package example;

import java.util.List;

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

@WebService
public interface UserService {
  @WebMethod
  public List&lt;User> getUsers(int groupId)
    throws InvalidGroupIdException;
}
</example>

<p>Notice the annotations @WebService and @WebMethod.  These are not strictly
necessary, but help to show that this interface is for a SOAP web service.  
Other than those annotations, the interface is like any other Java interface
with a method that takes arguments, returns a value, and even throws an
exception.  Within JAX-WS it will perform almost exactly like a local method
even if it is really being invoked on a remote machine.</p>
<p>
Next we'll look at the User class:
</p>

<example title="User.java">
package example;

public class User {
  private String _name;
  private int _id;
  private int _groupId;

  // 
  // JAXB requires a zero-argument constructor
  //
  public User() {}

  public User(int id, int groupId, String name) 
  {
    _id = id;
    _groupId = groupId;
    _name = name;
  }
    
  public String getName() 
  { 
    return _name; 
  }

  public void setName(String name) 
  {
    _name = name; 
  }
  
  public int getId() 
  { 
    return _id; 
  }

  public void setId(int id)
  {
    _id = id; 
  }

  public int getGroupId() 
  { 
    return _groupId; 
  }

  public void setGroupId(int groupId)
  {
    _groupId = groupId; 
  }

  public String toString()
  {
    return "User[id=" + _id + ", groupId=" + _groupId + ", name=" + _name + "]";
  }
}
</example>

<p>
This is a very simple class with three properties: a user id, a group id, and
a user name.  Because our service will return a list of these User objects
and we're actually using SOAP under the covers, JAX-WS will use another new
Java technology: JAXB.  JAXB is essentially a way to serialize and deserialize
Java to and from XML.  So this class needs to be JAXB compatible.  In this
case, fortunately all that means is that we need a zero-argument constructor.
</p>

<p>
The InvalidGroupIdException class is just a basic exception:
</p>

<example title="InvalidGroupIdException.java">
package example;

public class InvalidGroupIdException extends Exception
{
  public InvalidGroupIdException()
  {
    super();
  }

  public InvalidGroupIdException(String message)
  {
    super(message);
  }
}
</example>

<p>
These three classes are all that the client needs to use the service.  JAX-WS
has a way to obtain a client programmatically.  However, since we know that 
this client will be used frequently, we can create a client instance and 
register it in JNDI using Resin's &lt;web-service-client> configuration tag:
</p>

<example title="Client configuration">
  &lt;web-service-client jndi-name="soap/UserService">
    &lt;url>soap:${webApp.url}/user/&lt;/url>
    &lt;interface>example.UserService&lt;/interface>
  &lt;/web-service-client>
</example>

</s1>

<s1 title="Service Implementation">
<p>
The implementation of this service is as simple as writing a class which
implements UserService.  In our simple example, we store user groups in
a HashMap, but in a more complicated service, we might retrieve the users
from a database.  The only unusual thing about the implementation is the
@WebService annotation which indicates that the UserService interface is
the <em>endpointInterface</em> for this service.  This simply means that
the service will expose that interface as a SOAP service.
</p>
<example title="UserServiceImpl.java">
package example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.jws.WebService;

@WebService(endpointInterface="example.UserService")
public class UserServiceImpl implements UserService {
  private final HashMap&lt;Integer,List&lt;User>> _userGroupMap
    = new HashMap&lt;Integer,List&lt;User>>();

  public UserServiceImpl()
  {
    List&lt;User> group1 = new ArrayList&lt;User>();
    group1.add(new User(1, 1, "Bruce"));
    group1.add(new User(2, 1, "Harvey"));

    List&lt;User> group2 = new ArrayList&lt;User>();
    group2.add(new User(1, 2, "Lois"));
    group2.add(new User(2, 2, "Lex"));

    _userGroupMap.put(1, group1);
    _userGroupMap.put(2, group2);
  }

  public List&lt;User> getUsers(int groupId)
    throws InvalidGroupIdException 
  {
    List&lt;User> users = _userGroupMap.get(groupId);

    if (users == null)
      throw new InvalidGroupIdException("Invalid group id");

    return users;
  }
}
</example>

<p>
Now for the deployment of this service.  No WAR file is necessary, just a
simple &lt;servlet-mapping> tag in the resin-web.xml file:
</p>

<example title="Service Configuration">
  &lt;servlet-mapping url-pattern="/user/*"
                   jndi-name="service/UserService"
                   servlet-class="example.UserServiceImpl">
    &lt;protocol type="soap"/>
  &lt;/servlet-mapping>
</example>
</s1>

<s1 title="JSP Client Script">

<p>The client can now connect to the UserService by doing a lookup in JNDI.
This allows simple access even using JSP:</p>

<example title="demo.jsp">
&lt;%@ page import="java.util.List" %>
&lt;%@ page import="javax.naming.*" %>
&lt;%@ page import="javax.xml.ws.Holder" %>
&lt;%@ page import="example.UserService" %>
&lt;%@ page import="example.User" %>
&lt;%
Context context = (Context) new InitialContext().lookup("java:comp/env");

UserService service = (UserService) context.lookup("soap/UserService");
List&lt;User> users = service.getUsers(2);

Exception invalid = null;

try {
  service.getUsers(0);
}
catch (Exception e) {
  invalid = e;
}
%>
&lt;pre>
UserService.getUsers(1): &lt;%= holder.value %>
UserService.getUsers(0): &lt;%= invalid %>
&lt;/pre>
</example>

<results>
UserService.getUsers(1): [User[id=1, groupId=2, name=Lois], User[id=2, groupId=2, name=Lex]]
UserService.getUsers(0): example.InvalidGroupIdException
</results>

</s1>

  </body>
</document>
