SCDJWS Study Guide: JAX-RPC


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

JAX-RPC Service-Side Programming Models

JAX-RPC defines two server-side programming models for creating J2EE Web service endpoints: JAX-PRC Service Endpoints and Enterprise JavaBeans Endpoints.  The service endpoint is deployed in a container-based JAX-RPC runtime system.

  • Using a JAX-RPC service endpoint (JSE) — The service implementation is a Java class in the Web container. The service adheres to the Web container's servlet lifecycle and concurrency requirements.
  • Using an EJB service endpoint— The service implementation is a stateless session bean in an EJB container. The service adheres to the EJB container's lifecycle and concurrency requirements.

In either case, the service is made portable with the definition of a port component, which provides the service's outside view for Web service implementation. A port component consists of:

  • A WSDL document describing the Web service that its clients can use
  • A service endpoint interface defining the Web service's methods that are available to clients.
  • A service implementation bean implementing the business logic of the methods defined in the service endpoint interface. The implementation may be either a Java class in the Web container or a stateless session bean in the EJB container.

JAX-RPC requires the service definition interfaces must follow RMI conventions, no remote references allowed, and all objects are passed by copy.

Container-specific service interfaces, created by the J2EE container, provide static stub and dynamic proxies for all ports. A client of a J2EE platform Web service can be a Web service peer, a J2EE component, or a stand-alone application. It is not required that the client be a Web service or application implemented in Java.

Use a stateless Session Bean to expose Web services if you: 

  • Need to expose previously existing stateless Session Beans as Web services
  • Need declarative transaction management
  • Need the thread management provided by EJB Container
  • Need role based security

Use Java classes to expose your Web services if you: 

  • Need to expose previously existing Java classes as Web services
  • Want a light-weight system, and don't care much about transactional capabilities that an EJB container provides

JAX-PRC Service Endpoint (JSE)


A JSE is easy to develop because it’s just a POJO.  A JSE is composed of two parts: a service endpoint interface and the service corresponding implementation class. There are some restrictions for the service interface and the service implementation class:

  • The service endpoint interface which MUST extends (directly or indirectly) java.rmi.Remote interface and declares the web service’s publicly accessible methods. All of service endpoint interface’s methods MUST throw the java.rmi.RemoteException type exception.
  • The service endpoint interface may be generated from a WSDL file.
  • The service implementation class that implements all methods defined by the service endpoint interface.
  • The service implementation class may not directly implement the service endpoint interface by using Java "implements" keyword. In such case, the service implementation class MUST provide all methods, that defined in the servince endpoint interface, with the same signatures.
  • The service implementation class' methods MUST NOT throw java.rmi.RemoteException. This is the responsibility of the container as this implementation will be deployed in a managed J2EE container.

Once you have these two parts, you can use them, along with other deployment  files, to generate a WSDL document that provides a platform-independent description of the JSE.

For Example:  Fisrt, let’s define a service endpoint interface:

package tempconverter;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ConverterIF extends Remote {
       public double cToF(double celsius)  throws RemoteException;
       public double ftoC(double fahrenheit)  throws RemoteException;
}

Second, you will now create an implementation class, which is simply a standard Java class that implements the behaviour.

package tempconverter;
 
public class ConverterImpl implements ConverterIF{
           
       public double cToF(double celsius) {
              return celsius/5*9+32;
       }
           
       public double ftoC(double fahrenheit) {
              return (fahrenheit-32)/9*5;
       }

}


JSEs are deployed into a J2EE servlet container, and have access to the same resources and context information a servlet has. The messages passed to the server will be SOAP messages encapsulated in the HTTP protocol, and although servlets understand HTTP they have no SOAP binding. To act as the 'interpreter' the JAX-RPC runtime will create ties from your endpoint interface and implementation. The tie's role is to act as a proxy for the actual implementation class and to call the correct helper objects to (de)serialize the SOAP types to and from Java types.

During the deployment of a service endpoint component on a J2EE servlet container based JAX-RPC runtime system, a service endpoint class is associated with a special JAX-RPC servlet provided by the vendor. The associated servlet class is provided by the JAX-RPC runtime system (not by service endpoint developer) during the deployment. This association is configured in a manner specific to a JAX-RPC runtime system and its deployment tool. For example, a JAX-RPC deployment tool may configure a 1-1 association between a servlet class and service endpoint class. The special JAX-RPC associated servlet class is repsonsible fot responding to HTTP based SOAP requests, parsing the SOAP messages, and invoking the corresponding methods of the JSE implementation object. When the JSE returns a value from the method invocation, the JAX-RPC servlet creates a SOAP message to hold the return value (or a SOAP fault if an exception is thrown) and sends that SOAP message back to the requesting client via an HTTP replay message.

The associated servlet typically takes the responsibility of handling transport specific processing of an RPC request and for initiating dispatch to the target service endpoint instance. Each Servlet.service(...) method maps to a single remote method invocation on the target service endpoint instance. The thread model (whether single threaded or concurrent) for the remote method invocation on the service endpoint instance depends on the runtime system specific servlet associated with the corresponding endpoint class. The Servlet specification provides facility for both concurrent and single threaded model (the latter through the SingleThreadModel interface) for the service(...) method on a servlet.

When processing an incoming SOAP request for a one-way operation, the associated servlet is required to send back an HTTP response code of 200 or 202 as soon as it has identified the incoming request as being one-way and before it dispatches it to the target service endpoint instance.

The term JAX-RPC Service Endpoint used within the JAX-RPC specification is somewhat confusing since both Service Implementation Beans require the use of a JAX-RPC run time. However, in this case it refers to the programming model defined within the JAX-RPC specification that is used to create Web services that run within the web container. The requirements are repeated here with clarification. Changes from the JAX-RPC defined programming model are required for running in a J2EE container-managed environment. A JAX-RPC Service Endpoint can be single or multi-threaded. The concurrency requirement is declared as part of the programming model. A JAX-RPC Service Endpoint must implement javax.servlet.SingleThreadModel if single threaded access is required by the component. A container must serialize method requests for a Service Implementation Bean that implements the SingleThreadModel interface. Note, the SingleThreadModel interface has been deprecated in the Servlet 2.4 specification.

The Service Implementation Bean must follow the Service Developer requirements outlined in the JAX-RPC specification and are listed below except as noted:

  • The Service Implementation Bean must have a default public constructor. 
  • The Service Implementation Bean may implement the Service Endpoint Interface as defined by the JAX-RPC Servlet model. The bean must implement all the method signatures of the SEI. In addition, a Service Implementation Bean may be implemented that does not implement the SEI. This additional requirement provides the same SEI implementation flexibility as provided by EJB service endpoints. The business methods of the bean must be public and must not be static. If the Service Implementation Bean does not implement the SEI, the business methods must not be final. The Service Implementation Bean may implement other methods in addition to those defined by the SEI, but only the SEI methods are exposed to the client.
  • A Service Implementation must be a stateless object. A Service Implementation Bean must not save client specific state across method calls either within the bean instance's data members or external to the instance. A container may use any bean instance to service a request.
  • The class must be public, must not be final and must not be abstract.
  • The class must not define the finalize() method.

JAX-RPC Service Endpoint Lifecycle

According to JAX-RPC specification v1.0, if the soap service implements the javax.xml.rpc.server.ServiceLifeycle interface, the servlet container based JAX-RPC runtime system is required to manage the lifecycle of the corresponding service endpoint instances.

Here is javax.xml.rpc.server.ServiceLifeCycle interface:

package javax.xml.rpc.server;
import javax.xml.rpc.ServiceException;

public interface ServiceLifecycle {
       void init(Object context) throws ServiceException;
       void destroy();
 
}
 

 
The lifecycle of a service endpoint instance is realized through the implementation of the init() and destroy() methods of the ServiceLifecycle interface. The JAX-RPC runtime system is responsible for loading and instantiation of service endpoint instances. The JAX-RPC runtime system may choose to load and instantiate a service endpoint instance during the startup of the runtime system or when a service endpoint instance is needed to service an RPC request. The JAX-RPC runtime system loads the service endpoint class using the Java class loading facility. After service endpoint class is loaded, the JAX-RPC runtime system instantiates the class.

After the service endpoint instance is instantiated, the JAX-RPC runtime system is required to initialize the endpoint instance before any requests can be serviced. The JAX-RPC runtime system is required to invoke the ServiceLifecycle.init method (if this interface is implemented by the soap service) for the initialization of the service endpoint instance. The service endpoint instance uses the init method to initialize its configuration and setup access to any external resources. The context parameter in the init method enables the endpoint instance to access the endpoint context provided by the underlying JAX-RPC runtime system. Once a service endpoint instance has been initialized (and in a method ready state), the JAX-RPC runtime system may dispatch multiple remote method invocations to the service endpoint instance. These method invocations must correspond to the remote methods in the service endpoint interface implemented by the service endpoint class. (Notice here, that the container must call ServiceLifecycle.init method before it can start dispatching request to the service endpoint).

The JAX-RPC runtime system is required to invoke the destroy method when the runtime system determines that the service endpoint instance needs to be removed from service of handling remote invocations. A container MAY NOT call the destroy() method while a request is being processed by the bean instance. For example, the JAX-RPC runtime may remove an endpoint instance from service when the runtime system is shutting down or managing memory resources. The service endpoint class releases its resources and performs cleanup in the implementation of the destroy method.

After successful invocation of the destroy method, a service endpoint instance is ready for garbage collection. The JAX-RPC runtime system SHOULD NOT dispatch any remote method invocations to a destroyed endpoint instance. The JAX-RPC runtime systems are required to instantiate and initialize a new service endpoint instance for servicing new remote method invocations.


ServletEndpointContext


JSEs are deployed into a J2EE servlet container, and have access to the same resources and context information a servlet has. JSEs can access to a private set of enviroment variables and resources using JNDI. Also, JSEs can use javax.xml.rpc.server.ServletEndpointContext interface to interact with its enviroment.

For a service endpoint components deployed on a servlet container based JAX-RPC runtime system, the context parameter in the ServiceLifecycle.init method is required to be of the Java type javax.xml.rpc.server.ServletEndpointContext. The ServletEndpointContext provides an endpoint context maintained by the underlying servlet container based JAX-RPC runtime system. The goal of JAX-RPC specification is not to define a more generic abstraction for the endpoint context or session that is independent of any specific component model, container and protocol binding. Such generic abstractions and endpoint model are outside the scope of the JAX-RPC specification.

Here is ServletEndpointContext Interface:

package javax.xml.rpc.server;
    public interface ServletEndpointContext {
    public java.security.Principal getUserPrincipal();
    public boolean isUserInRole(String role);
    public javax.xml.rpc.handler.MessageContext getMessageContext();
    public javax.servlet.http.HttpSession getHttpSession() throws javax.xml.rpc.JAXRPCException;
    public javax.servlet.ServletContext getServletContext();
}


A servlet container based JAX-RPC runtime system is required to implement the ServletEndpointContext interface. The JAX-RPC runtime system is required to provide appropriate session, message context, servlet context and user principal information per method invocation on service endpoint instances.

Creating Session Oriented SOAP Services

  • The soap service should implement javax.xml.rpc.server.ServiceLifecycle.
  • The soap service should define the init( ), a call back method through which the JAX-RPC runtime system passes the context object to the soap service. destroy( ) method should also be defined.
  • The context passed to the soap service from the JAX-RPC runtime system will be of type ServletEndpointContext. ServletEndpointContext.getHttpSession() will get the current http session.

Let’s see some example:

package tempconverter;

public class ConverterImpl implements ConverterIF,
                javax.xml.rpc.server.ServiceLifecycle {
 
       ServletEndpointContext  servletEndpointContext;
 
       public void init(Object context) throws ServiceExcepion {
            servletEndpointContext = (ServletEndpointContext)context;
            //Open and allocate resources
       }
       public void destory() {
            //Close and Clean up resources
      }

      public double cToF(double celsius) {
           return celsius/5*9+32;
      }

      public double ftoC(double fahrenheit) {
           return (fahrenheit-32)/9*5;
      }
 
}
 

 
A servlet container based JAX-RPC runtime system is required to implement the ServletEndpointContext interface. The JAX-RPC runtime system is required to provide appropriate session, message context, servlet context and user principal information per method invocation on service endpoint instances.

The getHttpSession method returns the current javax.servlet.http.HttpSession. When invoked by the service endpoint instance within a remote method implementation, the getHttpSession returns the HTTP session associated currently with this method invocation. This method is required to return null if there is no HTTP session currently active and associated with this service endpoint instance. An endpoint class should not rely on an active HTTP session being always there; the underlying JAX-RPC runtime system is responsible for managing whether or not there is an active HTTP session.

The getHttpSession method throws JAXRPCException if it is invoked by a non HTTP bound endpoint. The JAX-RPC specification does not specify any transport level session abstraction for non-HTTP bound endpoints.

If the service endpoint class implements the ServiceLifecycle interface, the servlet container based JAX-RPC runtime system is required to manage the lifecycle of the corresponding service endpoint instances. The lifecycle of a service endpoint instance is realized through the implementation of the init and destroy methods of the ServiceLifecycle interface.

Summarize the Servlet-based Endpoint Model:

  • The Service implementation class is an ordinary Java calss.
  • The invocation of the methods provided the service done inside the servlet container.
  • Optioanl ServiceLifecycle interface for initialization and destruction callbacks
  • Access all resources in the web application


Statefull Web Service By JAX-RPC Endpoint Service

In the JAX-RPC 1.1 version, the session management mechanisms require use of HTTP as the transport in the protocol binding. This version of the JAX-RPC specification does not specify (or require) session management using SOAP headers given that there is no standard SOAP header representation for the session information. SOAP based session management may be considered in the future versions of the JAX-RPC specification.

A JAX-RPC runtime system is required to use at least one of the following mechanisms to manage sessions:

  • Cookie based mechanism: On the initial method invocation on a service endpoint, the server side JAX-RPC runtime system sends a cookie to the service client to initiate a new session. If service client wants to participate in this session, the client side JAX-RPC runtime system then sends the cookie for each subsequent method invocation on this service endpoint. The cookie associates subsequent method invocations from the service client with the same session.
  • URL rewriting involves adding session related identifier to a URL. This rewritten URL is used by the server-side JAX-RPC runtime to associate RPC invocations to the service endpoint with a session. The URL that is rewritten depends on the protocol binding in use.
  • SSL session may be used to associate multiple RPC invocations on a service endpoint as part of a single session.

A session (in JAX-RPC) is initiated by the server-side JAX-RPC runtime system. The server-side JAX-RPC runtime system may use javax.servlet.http.HttpSession (defined in the Servlet specification) to implement support for the HTTP session management.

A service client uses the javax.xml.rpc.session.maintain property (set using the Stub or Call interfaces) to indicate whether or not it wants to participate in a session with a service endpoint. By default, this property is False, so the client does not participate in a session by default. However, by setting javax.xml.rpc.session.maintain property to True, the client indicates that it wants to join the session initiated by the server. In the cookie case, the client runtime system accepts the cookie and returns the session tracking information to the server, thereby joining the session.
 

The client code by setting the javax.xml.rpc.session.maintain property assumes that it would participate in a session if one is initiated by the server. The actual session management happens transparent to the client code in the client-side runtime system.

Property javax.xml.rpc.session.maintain accepts objects of java.lang.Boolean class. This boolean property is used by a service client to indicate whether or not it wants to participate in a session with a service endpoint. If this property is set to True, the service client indicates that it wants the session to be maintained. If set to False, the session is not maintained. The default value for this property is False.
 

package javax.xml.rpc;
public interface Stub {
     // ...
     void _setProperty(String name, Object value);
     Object _getProperty(String name);
     java.util.Iterator _getPropertyNames();
}                                                          
 
                                                           
package javax.xml.rpc;                                                  
public interface Call {
     // ...
     void setProperty(String name, Object value);
     Object getProperty(String name);
     boolean removeProperty(String name);
     java.util.Iterator getPropertyNames();
}

The JAX-RPC service endpoint class may implement ServiceLifecycle interface.

To change the default session timeout globally, add the following element in your web.xml (service endpoint implementation deployment descriptor):

<web-app>
    ...
    <session-config>
       <!-- set global default timeout to 15 minutes -->
       <session-timeout>15</session-timeout>
    </session-config>
    ...
</web-app>
                                                           

 
The session-timeout element defines the default session timeout interval for all sessions created in this web application. The specified timeout must be expressed in a whole number of MINUTES. If the timeout is 0 or less, the container ensures the default behaviour of sessions is never to timeout. If this element is not specified, the container must set its default timeout period.

JAX-RPC EJB Endpoints

EJB components, by design, are meant for distributed computing and are hence well suited for exposure as Web services. EJB supports declarative transactions and security, and these benefits can also be leveraged if you decide to use EJB components as Web services. J2EE 1.4 allows exposing only stateless session beans as Web services with JAX-RPC. Any Web service client can access the EJB webservice using SOAP 1.1 over HTTP.

You can use a stateless session Web service to accomplish any of these business operations by accessing a persistence layer such as CMP (container-managed persistence) entity beans or sending a message to a JMS (Java Message Service) queue that activates an MDB (message-driven bean) to process the business rule.

The developer can choose a web service endpoint interface for a stateless session bean whenever he wants to expose the functionality of the bean as a web service endpoint through WSDL. The clients for EJB Web Service endpoint may be Java clients and/or clients written in a programming language other than Java. A Java client that accesses the EJB Web Service has to use JAX-RPC client APIs.

Making a stateless session bean accessible as a web service involves basically the same process used to deploy a stateless session bean with a remote or local interface. The only big differece is that you define an endpoint interface that extends javax.rmi.Remote, instead of a remote interface that extends javax.ejb.EJBObject or javax.ejb.EJBLocalObject. In addution, you do not define a home interfacem because an EJB endpoint does not have one.

This is an example shows how can you expose your existing EJB applications as a webservice endpoint and how a pure Java client accesses the ejb webservice.  We will use a simple Stateless Session bean TimeBean that displays the current time and locale information. For exposing the webservice endpoint you do not need to have home or remote interfaces for the EJBs, only the end-point interface that extends java.rmi.Remote and bean implementation class is required. Following the code for the service-endpoint for the EJB:

package time;

import java.rmi.RemoteException;
import java.rmi.Remote;
 
public interface TimeService extends Remote {
            public String getDateTime (String name) throws RemoteException;
}

The endpoint interface MUST comply with the rules for WSDL-to-Java mapping defined by the JAX-RPC specification. Every business method defineed in the endpoint interface MUST declare the java.rmi.RemoteException in its throw clause. RemoteException is used to report any networking problems associated with processing a client’s SOAP request. The SOPA client will not use the EJB endpoint interface directly. Instead SOAP clients will use the WSDL document associated with the EJB endpoint to generateee their own service interface.

                                                           

Once you have defined the endpoint interface, you can define the bean class, which will do the actual implementation of the endpoint interface:

package time;
 
import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.text.DateFormat;
import java.util.Locale;
import java.util.Date;
 
 
public class TimeServiceBean implements SessionBean
{
    public String getDateTime (String name)
    {
         System.out.println("TimeServiceBean:getDateTime() invoked");
         DateFormat formater = DateFormat.getDateTimeInstance();
 
                         return "Hi "+name +" ! \n today is "+ formater.format(new Date())+
                                                         " in "+Locale.getDefault().getCountry();
 
    }
 
    public TimeServiceBean() {}
    public void ejbCreate() {}
    public void ejbRemove() {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
    public void setSessionContext(SessionContext sc) {}
}

Although the bean class MUST implement all methods with the same signature defined in the endpoint interface, it’s not required to explicit implement the interface itself. This is in keeping with the EJB platform convetion of not implementing remote or local interfaces. Each methods in the implementation class MUST throw the same exceptions defined in endpoint interface throw – except one: java.rmi.RemorteException. The endpoint bean’s methods MUST NEVER declare RemoteException.

Then we have to define the end-point interface in ejb-jar.xml as follows:

<session>
  <display-name>TimeServiceEJB</display-name>
  <ejb-name>TimeServiceEJB</ejb-name>
  <service-endpoint>time.TimeService</service-endpoint>
  <ejb-class>time.TimeServiceBean</ejb-class>
  <session-type>Stateless</session-type>
  ...
</session>

The WSDL file defines the web services e.g. the following MyTimeService.wsdl describes the Time ejb webservice:

<?xml version="1.0" encoding="UTF-8"?>
 
<definitions name="MyTimeService" targetNamespace="urn:oracle-ws" xmlns:tns="urn:oracle-ws"
             xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types/>
 
  <message name="TimeService_getDateTime">
    <part name="String_1" type="xsd:string"/>
   </message>
 
  <message name="TimeService_getDateTimeResponse">
    <part name="result" type="xsd:string"/>
  </message>
  
  <portType name="TimeService">
    <operation name="getDateTime" parameterOrder="String_1">
      <input message="tns:TimeService_getDateTime"/>
      <output message="tns:TimeService_getDateTimeResponse"/>
    </operation>
  </portType>
 
  <binding name="TimeServiceBinding" type="tns:TimeService">
    <operation name="getDateTime">
      <input>
        <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   use="encoded" namespace="urn:oracle-ws"/>
      </input>
      <output>
        <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   use="encoded" namespace="urn:oracle-ws"/>
      </output>
      <soap:operation soapAction=""/>
    </operation>
 
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
  </binding>
  
  <service name="MyTimeService">
    <port name="TimeServicePort" binding="tns:TimeServiceBinding">
    <soap:address location="REPLACE_WITH_ACTUAL_URL"/></port>
  </service>
 
</definitions>

The mapping.xml file specifies the Java to WSDL mapping i.e. it contains the mapping between package names and XML namespaces, WSDL root types and Java artifacts, and the set of mappings for services. For example we will have the following contents for our mapping.xml:

<package-mapping>
  <package-type>time</package-type>
  <namespaceURI>urn:oracle-ws</namespaceURI>
</package-mapping>

Deployment of webservices requires a deployment descriptor named webservices.xml in META-INF of the ejb-jar file. This descriptor specifies the set of web service descriptions that are to be deployed into the J2EE Application Server and the dependencies they have on container resources and services:

<webservice-description>
  <webservice-description-name>TimeServiceEJB</webservice-description-name>
  <wsdl-file>META-INF/MyTimeService.wsdl</wsdl-file>
  <jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-mapping-file>
  <port-component>
    <description>port component description</description>
    <port-component-name>TimeServicePort</port-component-name>
    <wsdl-port>
      <namespaceURI>urn:oracle-ws</namespaceURI>
      <localpart>TimeServicePort</localpart>
    </wsdl-port>
    <service-endpoint-interface>time.TimeService</service-endpoint-interface>
    <service-impl-bean>
      <ejb-link>TimeServiceEJB</ejb-link>
    </service-impl-bean>
  </port-component>
</webservice-description>

 


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |