How to write a RPC Literal Top-Down Service
Date: 19-Sep-2003
After reading this how-to document you should be able
to:
-
Understand what is a JAX-RPC Web Service
- Write a RPC literal Web Service using a top down approach
Introduction
This document demonstrates how to develop an RPC Literal
Web Service for Oracle Application Server 10g using the Top-Down
paradigm i.e. start with the WSDL and generate all the classes and service
artifacts using the definition of types and operations in the WSDL. Web
Services Description Language (WSDL) is an XML-based language used to
define Web services and describe how to access them. WSDL file describes
the operations (i.e. methods) exposed by the service, the parameters taken
by these operations, the request and response messages associated with
each operation call. WSDL also specifies the location from where the Web
Service can be accessed.
RPC Literal webservices are services that are invoked
by clients in the same way that remote objects are invoked in the Java
language using Remote Procedure Calls. Oracle Application Server 10g
provides the marshalling support and location transparency so methods,
method data, and return data are translated into SOAP messages and the
remote endpoint is invoked even though the client appears to be calling
a local object. The Top-Down paradigm implies that you are starting with
a WSDL and will write the implementation classes after the WSDL has been
processed and the necessary service classes and interfaces are generated.
Once the generation process is complete the Web Service implementation
class can be compiled and included into the Web Service archive (EAR file)
to be deployed to OC4J
Software Requirements
-
Oracle Application Server Containers for J2EE
10g or later. You can download
the OC4J from Oracle Technology Network.
-
JDK1.4.x or above This can be downloaded
here .
Apache Ant v1.5 or later.
How To Example source code zip.
Description
Overview of JAX-RPC Web Services
The Java API for XML-based remote procedure calls (JAX-RPC)
provides standard way of building portable and interoperable SOAP based
Web Services. It simplifies the process of building Web services that
incorporate XML-based RPC . It defines mappings between XML types and
Java types that attempt to hide the details of XML and provide a familiar
method-call paradigm. Read more on JAX-RPC Web Services here.
The How-To Example
This how-to explains how to create a simple JAX-RPC
Web Service using a WSDL file and a client to access the Web Service.
The Web Service provides various methods that show different types of
input parameters and return types that JAX -RPC Web Services can handle.
On each method call of Web Service, the server echoes out the data type
and values of the input parameter to the method.
The how to uses Oracle's Web Services Assembler tool
to generate the service artifacts. The Web Service assembler tool takes
an XML config file that describes the service as input, generates service
artifacts, compiles all the classes and produces an Enterprise Archive
file that can be deployed to an application server to run the Web Service.
Here
is the WSDL file that will be used to generate the Web Service artifacts.
Listing 1 shows the part of WSDL definition required to define a method
named echoStringArray that takes a String
array as input and return a String array.
<types> <schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://soapbuilders.org/rpc-lit-test/types">
<!-- define a complex type for array of string --> <element name="stringItem" type="xsd:string" /> <complexType name="ArrayOfstring"> <sequence> <element ref="types:stringItem" minOccurs="0" maxOccurs="unbounded"/> </sequence> </complexType> </schema> </types> <!--define request and response message for echoStringArray rpc operation --> <message name="echoStringArrayRequest"> <part name="inputStringArray" type="types:ArrayOfstring"/> </message> <message name="echoStringArrayResponse"> <part name="return" type="types:ArrayOfstring"/> </message>
<portType name="SoapTestPortTypeRpc"> <!-- define echoStringArray rpc operation using input and output message--> <operation name="echoStringArray" parameterOrder="inputStringArray"> <input message="tns:echoStringArrayRequest"/> <output message="tns:echoStringArrayResponse"/> </operation> </portType><binding name="Soap11TestRpcLitBinding" type="tns:SoapTestPortTypeRpc"> <soap11:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <!-- bind echoStringArray rpc operation --> <operation name="echoStringArray"> <soap11:operation soapAction="http://soapinterop.org/"/> <input> <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> </input> <output> <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test"
/> </output> </operation> </binding> <service name="WhiteMesaSoapRpcLitTestSvc"> <port name="Soap11TestRpcLitPort" binding="tns:Soap11TestRpcLitBinding"> <soap11:address location="http://localhost:8888/test-rpc-lit"/> </port> </service>
|
|
Listing 1
Listing 2 shows the part of Web Service implementation
class, that defines echoStringArray method.
public class RpcLitTopdownImpl implements SoapTestPortTypeRpc{
private Logger m_logger;
public RpcLitTopdownImpl(){
// create an anonymous logger m_logger = Logger.getAnonymousLogger
("oracle.demo.topdownrpc.service.RpcLitTopdownImpl");
// Set the log level specifying which message levels will
// be logged by this logger
m_logger.setLevel(Level.ALL);
// create the formatter SimpleFormatter formatter = getFormatter();
// parent handler for logging messages should not be used m_logger.setUseParentHandlers(false);
// Add a log Handler to receive logging messages. m_logger.addHandler(new StreamHandler(System.out,formatter){ public synchronized void publish(LogRecord record){
// Format and publish a LogRecord. super.publish(record); flush(); } }); }
public ArrayOfstring echoStringArray(ArrayOfstring inputStringArray)
throws RemoteException { //get the string array String array[] = inputStringArray.getStringItem();
// log the value of each element in String array for(int i = 0; i < array.length;i++){ m_logger.log(Level.INFO, "demo.stringarraydata.msg",new
Object[]{"String", "" + i, array[i]}); }
// return the ArrayofString type to client return inputStringArray; }
.... .... }
|
|
Listing 2
The class implements the SoapTestPortTypeRpc
interface that declares the methods exposed by the Web Service. The method
echoStringArray takes input parmeter of user
defined type ArrayOfString. The method iterates
through the string array and logs the values of each String element to
the console. The class ArrayOfString, the
interface SoapTestPortTypeRpc and other similar
artifacts are generated by the Web Services Assembler tool using the information
provided in the WSDL.
The implementation class methods use java.util.logging.Logger
class to log the values of parameters to the OC4J console. The complete
code can be seen here.
Listing 3 shows the part of client code that calls the echoStringArray()
method of the Web Service.
Public SoapTestPortTypeRpc initializeService() throws Exception{
WhiteMesaSoapRpcLitTestSvc service = (WhiteMesaSoapRpcLitTestSvc) m_factory.loadService(new URL(m_serviceURL), WhiteMesaSoapRpcLitTestSvc.class, null);
SoapTestPortTypeRpc port = service.getSoap11TestRpcLitPort(); ((Stub)port)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,m_serviceURL);
return port; }
private void demoEchoStringArray() throws Exception{ m_logger.log(Level.INFO,"demo.echoStringArray.enter");
//initialize Service and get the handle of remote Web Service SoapTestPortTypeRpc port = initializeService(); // create object of user defined type containing String
// array as an attribute ArrayOfstring aos = new ArrayOfstring(new String[]{ VAL_STRING1,VAL_STRING2}); // call method on Web Service aos = port.echoStringArray(aos);
// log the values of elements in String array return by the Service m_logger.log(Level.INFO,"demo.echoStringArray.msg",new
Object[]{ new String() + aos.getStringItem()[0], new String() + aos.getStringItem()[1]});
m_logger.log(Level.INFO,"demo.echoStringArray.exit");
}
|
|
Listing 3
The complete client code can be seen here.
Preparing and Running the Example
Extract the rpc-lit.zip file. This will
create rpc-lit directory containing documentation
and source code of the how-to.
In the following steps <OC4J> refers
to directory where OC4J is installed.
| Step a: |
Start OC4J from <OC4J>/j2ee/home
directory on a command promt as follows:
java -jar oc4j.jar
|
| Step b: |
Navigate to rpc-lit, the sample home directory on
new command window . Include ANT_HOME/bin
in the PATH environment variable. Set the following properties required
by the ant build script
-
Set the ORACLE_HOME environment
variable to your <OC4J> root
directory.
Example:
Windows : set ORACLE_HOME=c:\oc4j10g
Unix : export ORACLE_HOME=/home/oc4j10g
-
Set the J2EE_HOME environment
variable to your <OC4J>/j2ee/home
directory.
Example:
Windows : set J2EE_HOME=c:\oc4j10g\j2ee\home
UNIX : export J2EE_HOME=/home/oc4j10g/j2ee/home
-
Set the JAVA_HOME environment
variable to your Java installation directory.
Example:
Windows : set JAVA_HOME=c:\j2sdk1.4
UNIX : export JAVA_HOME=/home/j2sdk1.4
|
| Quick
Start |
|
Once you have the server configured and running, execute the following
command from the prompt in Step b:
>ant
The service artifacts and implementation class will be compiled
and placed into a WAR which is then placed into an EAR.
The EAR will be deployed to OC4J. Next the stubs and client will
be compiled. Finally the service will be invoked by the client and
you should see the output both in the server's message output and
on the stdout of the client.
|
| Step
by Step |
| Step 1: |
Generate the service artifacts. Execute the following command:
This step will generate the service artifacts which include interfaces
and Tie classes. Examine the rpc-lit/config/service-config.xml
file. Notice that the implementation-class-name element is filled
in with the implementation class provided by the demo. This class
is not compiled yet so WSA will generate the artifacts and use the
class name as a place holder. Once the artifacts are generated,
the implementation class will have to be compiled and WSA will have
to be run again with the same config file.
To generate the service artifacts type: ant
gen-service.
The source code for the service-artifacts will be placed in the
build/src/service directory using the
package name oracle.demo.topdownrpc.service.
Examine the type-mapping.xml file.
This file is used to instruct WSA how to map types to package name.
A namespace URI is mapped to a specific package name. Notice that
this example maps its types to the package oracle.demo.topdownrpc.types.
So for service artifacts the types are generated in rpc-lit/src/oracle/demo/topdownrpc/types.
|
| Step 2: |
Generate the stubs (client artifacts)
This step will generate the stubs for the service. A client application
uses a stub to invoke operations on a remote service. Examine the
file rpc-lit/config/client-config.xml.
This is the configuration file that the WebServices Assembler (WSA)
tool uses to generate the stubs.
To generate the stubs type: ant gen-stubs
The source for the stubs will be placed in rpc-lit/build/src/client.
|
| Step 3: |
Update the implementation.
This step will compile the implementation classes and regenerate
the EAR file that will now contain both service artifacts and the
implementation class. Examine the file RpcLitTopdownImpl.java
under rpc-lit/src/service/oracle/demo/topdowndoclit/service.
Notice that the class implements SoapTestPortTypeRpc
which is a service artifact and thus generated by the tool. Before
the first step there were no generated files so compiling this class
would have failed. Now that you have already ran the gen-service
task you are ready to compile the class and update the EAR.
To update the implementation type: ant update-impl
|
| Step 4: |
Deploy the Service
The service is now ready to be deployed. Examine the rpclit_topdown.ear
in the rpc-lit/dist directory using
WinZip or any zip file browser. It should contain a WAR file named
rpclit_topdown-web.war. This WAR file
contains all the service artifacts, implementation classes, as well
as the web deployment descriptor (web.xml)
and the jaxrpc deployment descriptor (jaxrpc-ri-runtime.xml).
To deploy this ear to a running instance of oc4j type: ant
deploy-demo
After this task is complete you can check your application by
typing in the following url into a web browser: http://localhost:8888/rpclit_topdown/rpclit_topdown
You should be able to invoke some of the methods on this service
from the web browser. Currently, invoking services using the browser
is restricted to simple types.
|
| Step 5: |
Run the demo.
You are now ready to run the client. Examine the file
RpcLitTopdownClient.java in rpc-lit/src/client/oracle/demo/topdownrpc/
. Notice that this class uses the stubs to set an endpoint address
and to invoke methods on the remote service.
To run the client type: ant run-demo
You should see some sample output on both the oc4j and client
output screens.
|
To undeploy the Web Service execute the command :
ant teardown-demo
Resources
Summary
This how-to document explained how write a RPC literal
Web Service from the WSDL using the top down approach.
|