JAX-RPC
Introduction
JAX-RPC is a Java API for XML based RPC allowing for executing methods on remote systems. Generally, it describes the relationship between SOAP 1.1, WSDL 1.1, XML and Java. The API provides both, a client and a server programming model.
Client Programming Model
In order to access a web service from a client written in Java, three APIs have been made available.
- Generated Stubs
- Dynamic Proxies
- DII (Dynamic Invocation Interface)
In this context, generated stubs, which base on the Java RMI programming model, are further discussed.
Generated Stubs
The figure above demonstrates the procedure of accessing a web service.
1) A Client operates on a remote interface (the “endpoint interface”) to invoke a remote service 2) A Stub is generated that handles the method invocation and transforms the RPC call into an XML based protocol, such as SOAP. 3) The SOAP message is sent via HTTP (or other transport protocols). 4) The web service processes the request and sends a SOAP Response Message. 5) This SOAP message is transformed in either a value or an exception (if SOAP default is declared in the WSDL document)
As a matter of fact, a developer must not generate or parse SOAP messages. It is the JAX-RPC runtime system that converts the APIs calls and responses to and from SOAP messages.
The role of WSDL
Both, endpoint interface and stub, rely on the WSDL document which needs to be at the client’s disposal. Whereas the JAX-RPC compiler receives the necessary information for generating the endpoint interface in the <portType> and <message> pieces of the WSDL document, it can find the data for the stub in the <binding> and <port> part.
The endpoint interface
The endpoint interface serves as the remote interface extending java.rmi.Remote. Each methods throws a java.rmi.RemoteException.
In order to express the data types of the XML based definition in the Java programming language JAX-RPC provides a mapping. For instance, xsd:string is mapped to the java.lang.String class. Furthermore, the compiler is also able to map nillable and complex types. Thus, certain Java datatypes such as char can not be mapped.
The following code presents an example of a WSDL document and its corresponding endpoint interface.
WSDL document:
<message name ="reservationRequest"> <part name ="name" type="xsd:string"/> <part name ="idNumber" type="xsd:string"/> <part name ="date" type = "xsd:dateTime"/> <part name ="carType" type = "xsd:string"/> <part name ="price" type = "xsd:float"/> </message> <message name = "reservationResponse"> <part name = "param2" type="xsd:int"/> </message> <portType name = "TaxiProcessor"> <operation name = "book"> <input message = "tns:reservationRequest"/> <output message = "tns:reservationResponse"/> </operation> </portType>
Endpoint Interface:
public interface TaxiProcessor extends java.rmi.Remote { public int book (String name, String idNumber, java.util.Calendar date, String carType, float price) throws java.rmi.RemoteException; }
The stub
The stub converts the method invocation on the endpoint interface into a SOAP message. Therefore it needs the <binding> piece of the WSDL element. This part provides the messaging style, the operation name, and the encoding style to use in the SOAP message body. Additionally, the port part describes the location of the Web Service, so that the compiler can generate the specific stub.
The service interface
The service interface can be compared to the home interface. Unlike the stub and the endpoint interface, which are generated at deployment time, the service interface is generated at runtime. Its purpose is to get an instance of the generated stub. Therefore, it provides methods helping to obtain the stub.
How does EJB use JAX-RPC generated stubs?
Bound to a specific namespace, the EJB obtains a reference to a resource factory from JNDI ENC. It receives the service interface and invokes its “getStub” method to get an instance of the stub. Finally it can use the stub to invoke the web service’s operations.
... public class TaxiAgentBean implements javax.ejb.SessionBean { ... // obtain a reference to a resource factory from JNDI ENC TaxiProcessorService webService = (TaxiProcessorService) jndiContext.lookup( „java:comp/env/service/TaxiProcessorService“); // get the stub Processor endpointStub = webService.getProcessorPort(); ... /any code // use stub to invoke operations on web service endpointStub.book(customerName, idNumber ,date, carType, price); ... }
Deployment element and JAX-RPC mapping file
In the deployment descriptor the web service needs to be published to the JNDI ENC. Therefore, <service ref> is declared. This element embraces the following subelements:
<service-ref-name>: Declares the name of the JAX-RPC service in JNDI ENC, relative to the „java:comp/env“ context
<service-interface>: Indentifies the JAX-RPC Service interface
<wsdl-file>: Identifies the location of the WSDL document
<jaxrpc-mapping-files>: Specifies the location of the mapping file
<service-qname>: Identifies the fully qualified XML name of the WSDL <service> definition
The JAX-RPC mapping file defines the relationship between the JAX-RPC interfaces and their corresponding WSDL document. It helps the deployment tools to generate a proper stub with correct protocols and messaging methods.
Normally, developers need to create the file. Since it is very error-prone, tools exist to generate the mapping file automatically. The lightweight version of this mapping file includes the mapping of Java packages and XML namespaces. Thus, a WSDL document needs to fulfil certain conditions in order to that simple. For instance, the <binding> definition needs to declare the RPC messaging style.
Dynamic Proxies
In contrast to the previous API, where stubs are generated at deployment time, the client creates dynamic stubs at runtime using the javax.xml.rpc.Service interface. The client has a priori knowledge of the WSDL and the service it is going to invoke. It uses the ServiceFactory classes to create the service and get the proxy. [4]
DII (Dynamic Invocation Interface)
This software pattern eliminates the need for clients to know in advance a service's exact name and parameters. A DII client can discover this information at runtime using a service broker that can look up the service's information. This flexibility in service discovery enables the run-time system to use service brokers, which can adopt varying service discovery mechanisms -- registries, UDDI, etc. [4]
The server-side programming model
In EJB 2.1 only stateless session beans can serve as a web service. The conversational state of stateful session beans contradicts to the stateless nature of web services.
The beans are exposed through a new interface: the endpoint interface. As presented in the client-side programming model, remote clients can access the methods via SOAP 1.1. The EJB container manages transaction and security.
Endpoint Interface
To support exposing a stateless session bean as a Web Service endpoint, the EJB 2.1 specification has added a new interface type to the ejb-jar.xml deployment descriptor. A stateless session bean can now have three interfaces: a remote interface, a local interface for Java clients in the same JVM and a service endpoint interface describing the web service.
The interface itself is generated from the <portType>, <message> and <types> pieces of the WSDL document. As already described in the endpoint interface part of the client-side programming model, the JAX-RPC compiler needs to ensure that
- the appropriate mapping between Java and XML types takes place
- the interface extends Java.rmi.Remote
- each operation throws the Java.rmi.Remote exception.
The stateless session bean itself implements the methods defined by the endpoint interface. Furthermore, it implements the endpoint interface directly since the latter is an immediate descendent of java.rmi.Remote.
Relevant parts in a WSDL document:
<xml version=‚1.0‘?> <definitions name = „TaxiReservation“> ... <! Message elements describe the parameters and return values -- > <message name =„RequestMessage“> <part name=„taxiId“ type=“xsd:int“ /> <part name=„customerId“ type=“xsd:int“/> <part name=„price“ type=„xsd:double“/> </message> <message name= „ResponseMessage“> <part name=„reservationId“ type=„xsd:string“/> </message> <! -- portType element describes the abstract interface of a web service -- > <portType name = „TaxiReservationEndpoint“> <operation name=„makeReservation“> <input message=„taxi:RequestMessage“/> <output message=„taxi:ResponseMessage“/> </operation> </portType> ...
Endpoint Interface
public interface TaxiReservationEndpoint extends java.rmi.Remote { public java.lang.String makeReservation (int taxiId, int customerId, double price) throws java.rmi.RemoteException; }
Deployment Files
In order to expose a stateless session bean as a web service, four deployment files are required:
- ejb-jar.xml
- WSDL file
- JAX-RPC mapping file
- webservice.xml
The deployment descriptor (ejb-jar.xml file), declares the service endpoint interface. Please note, that the <session-type> elements needs to be set to “stateless” and the optional <transaction-type> (if included) to “Container”.
The webservice.xml document describes the web service, tying the separate deployment files together.
The JAX-RPC mapping file maps Java packages and WSDL/XML. Please refer to the client side programming model to obtain further information.