How to write a Document 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 Document literal Web Service using a top down approach
Introduction
This document demonstrates how to develop an Document
Literal Style 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.
Document Literal Web Services are services that process
XML documents. The data exchanged in the SOAP messages between the client
and the Web Service is passed in XML document. There's no formal mapping
between the SOAP messages and programming languages, all it says is that
the SOAP message should conform to a particular XML Schema.
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. Read more on JAX-RPC Web Services here.
The How-To Example
This how-to explains how to create a simple Document
Literal style Web Service using a WSDL file and a client to access the
Web Service. The Web Service provides clients with the facility to log
event messages and to retrieve these event messages. The Web Service uses
various user defined types to exchange log events with the client. The
definition of these types is provided as XML elements in the XML schema
which is referenced from the WSDL file.
The how to uses Oracle's Web Services Assembler tool
to generate the service artifacts. The Web Service assembler tool takes
as input, an XML config file that describes the service. It uses the definitions
in the WSDL file to generate service artifacts like types, interfaces,
tie and stub classes, 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 the method
named getEvents that takes an input parameter
of user defined type and return another user defined type.
<wsdl:types> <xs:schema> <Xs:import namespace="http://www.ws-i.org/LoggingFacility.xsd" schemaLocation="LoggingFacility.xsd"/> </Xs:schema> </wsdl:types>
<wsdl:message name="getEventsRequest"> <wsdl:part name="Document" element="log:getEventsRequestElement"/> </wsdl:message>
<wsdl:message name="getEventsResponse"> <wsdl:part name="Document" element="log:getEventsResponseElement"/> </wsdl:message> <wsdl:portType name="LoggingFacilityLogPortType">
<wsdl:portType name="LoggingFacilityLogPortType">
<wsdl:operation name="getEvents"> <wsdl:documentation>Retrieve entries from the system
log with the specified userId.</wsdl:documentation> <wsdl:input message="tns:getEventsRequest"/> <wsdl:output message="tns:getEventsResponse"/> <wsdl:fault name="RepositoryMissingFault"
message="tns:getEventsRepositoryMissingFault"/> </wsdl:operation> </wsdl:portType>
<wsdl:binding name="LoggingFacilitySoapBinding"
type="tns:LoggingFacilityLogPortType">
<wsdl:documentation> <wsi:Claim conformsTo="http://ws-i.org/profiles/basic1.0/" /> </wsdl:documentation>
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document"/>
<wsdl:operation name="getEvents"> <soap:operation soapAction=""/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="RepositoryMissingFault"> <soap:fault name="RepositoryMissingFault" use="literal"/> </wsdl:fault> </wsdl:operation>
</wsdl:binding>
|
|
Listing 1
The definition of types provided in XML schema. Listing
2 shows a part of LoggingFacility.xsd schema
used by the Web Service. View complete Schema definition here.
<xs:element name="getEventsRequestElement" type="log:getEventsRequestType"/>
<xs:complexType name="getEventsRequestType"> <xs:sequence> <xs:element name="DemoUserID" type="xs:string"/> </xs:sequence> </xs:complexType>
<xs:element name="getEventsResponseElement" type="log:getEventsResponseType"/> <xs:complexType name="getEventsResponseType"> <xs:sequence> <xs:element name="LogEntry" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="Timestamp" type="xs:dateTime"/> <xs:element name="ServiceID" type="xs:string"/> <xs:element name="EventID" type="xs:string"/> <xs:element name="EventDescription" type="xs:string"/> <xs:any namespace="##other" minOccurs="0"
maxOccurs="unbounded" processContents="lax"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType>
|
|
Listing 2
Listing 3 shows the part of Web Service implementation
class, that defines getEvents method.
public class DocLitLoggerImpl implements LoggingFacilityLogPortType{
// variable to store logged events private Set m_logSet;
public DocLitLoggerImpl(){
// initialize HashSet object m_logSet = new HashSet(); }
public GetEventsResponseType getEvents(GetEventsRequestType document) throws GetEventsFaultType_Exception, RemoteException {
// create an object of GetEventsResponseType user defined type GetEventsResponseType response = new GetEventsResponseType();
//initialize an ArrayList to store events List responseList = new ArrayList();
// get an iterator on HashSet that stores logged events Iterator it = m_logSet.iterator();
// get the User Id from input parameter String id = document.getDemoUserID();
// iterate through all the logged events while(it.hasNext()){ // get the next event LogEventRequestType req = (LogEventRequestType)it.next();
// if User id of event is equal to input User id if(id.equals(req.getDemoUserID())){
// create a LogEntry and add to ArrayList responseList.add(createLogEntryFromRequest(req)); } }
private LogEntry createLogEntryFromRequest(LogEventRequestType req) {
// create a LogEntry object from the input parameter LogEntry le = new LogEntry(); le.set_any(req.get_any()); le.setEventDescription(req.getEventDescription()); le.setEventID(req.getEventID()); le.setServiceID(req.getServiceID()); le.setTimestamp(Calendar.getInstance()); return le; }
|
|
Listing 3
The class implements the LoggingFacilityLogPortType
interface that declares the methods exposed by the Web Service. The method
getEvents takes input parameter of user
defined type GetEventRequestType and returns
object of GetEventResponseType type . The
method iterates through the HashSet object that stores all the log entries
and returns the entries of specified User Id in GetEventResponseType
object. The user defined type classes like GetEventResponseType,
GetEventRequestType, LogEntry, the interface
LoggingFacilityLogPortType and other similar artifacts are generated
by the Web Services Assembler tool using the information provided in the
WSDL.
The complete Web Service code can be seen here.
Listing 4 shows the part of client code that calls the getEvents()
method of the Web Service.
private void runDemo() throws Exception{
// load service using the Service URL DocLitLogger service = (DocLitLogger)m_factory.loadService(new URL(m_serviceURL), DocLitLogger.class, null);
// get a handle to remote service LoggingFacilityLogPortType port = service.getDocLitLoggerPort(); ((Stub)port)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,m_serviceURL);
//call method to invoke Web Service method to log events demoLogEvents(port);
//call method to invoke Web Service method to retrieve logged events demoGetEvents(port);
}
private void demoGetEvents(LoggingFacilityLogPortType port) throws Exception {
System.out.println("Here are the events you logged in this session");
// call Web Service method to get the logged events GetEventsResponseType resp = port.getEvents(new GetEventsRequestType(USERID));
// create LogEntry type array from Web Service return types LogEntry entry[] = resp.getLogEntry();
// iterate through LogEntry array and display the event messages for(int i = 0; i < entry.length; i++){ System.out.println("-------- Entry " + (i+1) + " --------"); System.out.println("Service ID= " + entry[i].getServiceID()); System.out.println("Event ID= " + entry[i].getEventID()); System.out.println("Event Description= " + entry[i].getEventDescription()); System.out.println("Event Date & TIme= " + entry[i].getTimestamp().getTime().toString()); System.out.println("------------------------------------------"); System.out.println(); } }
|
|
Listing 4
The complete client code can be seen here.
Preparing and Running the Example
Extract the doc-lit.zip file. This will
create doc-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 doc-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 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
doc-lit/build/src/service directory
using the package name oracle.demo.topdowndoclit.service.
Examine the doc-lit/config/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.topdowndoclit.types.
So for service artifacts the types are generated in doc-lit/src/oracle/demo/topdowndoclit/types.
|
| Step 2: |
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 DocLitTopdownImpl.java
under doc-lit/src/service/oracle/demo/topdowndoclit/service.
Notice that the class implements LoggingFacilityLogPortType
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 3: |
Deploy the Service
The service is now ready to be deployed. Examine the doclit_topdown.ear
in the build directory using WinZip or any zip file browser. It
should contain a WAR file named doclit_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
|
| Step 4: |
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 doc-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 doc-lit/build/src/client.
|
| Step 5: |
Run the demo.
You are now ready to run the client. Examine the file
DocLitTopdownClient.java in doc-lit/src/client/oracle/demo/topdowndoclit/
. 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 client output screen.
|
To undeploy the Web Service execute the command :
ant teardown-demo
Resources
Summary
This how-to document explained how write a Document
literal Web Service from the WSDL using the top down approach.
|