Oracle9i Application Server Oracle9iAS SOAP Developer's Guide Release 1 (v1.0.2.2) Part Number A90297-01 |
|
This chapter describes the procedures you use to write a SOAP Java service, to deploy the service, and to write a SOAP Java client for a service that uses arrays and other nonscalar types for parameters or return values (Table 2-1 lists the scalar types). In addition, this chapter provides information on SOAP encodings. You should be familiar with the information in Chapter 2, "Using Oracle SOAP with Java Services" before reading this chapter.
This chapter covers the following topics:
Developing a SOAP Java service involves building a Java class that includes one or more methods that generate responses to incoming calls. This section describes the procedures for developing an AddressBook service that provides methods to get an address, save a new address, and list all addresses in an AddressBook (the AddressBook data is stored in memory). These methods take arguments and expand on the basic SOAP Java service functionality shown in Chapter 2, "Using Oracle SOAP with Java Services".
The complete Address Book service is supplied in the directory $SOAP_HOME/samples/addressbook
on UNIX or %SOAP_HOME%\samples\addressbook
on Windows NT.
To develop a SOAP Java service that includes user-defined types as parameters or return values, you must complete the following steps:
Create a SOAP Java service by writing a class containing methods that are deployed as a SOAP service. When looking at the AddressBook service supplied with Oracle SOAP, note that the single jar file, samples.jar
contains a samples
package, that includes several samples (the jar file is in the directory $SOAP_HOME/webapps/soap/WEB-INF/lib
). The first line of AddressBook.java
specifies the package name for the service, addressbook
, which is added to samples.jar
.
package samples.addressbook;
The Addressbook
service is implemented with a public class AddressBook
and
defines the following public methods:
public void addEntry(Stringname
, Addressaddress
) public Address getAddressFromName(Stringname
) public Element getAllListings() public int putListings(Elementel
)
When SOAP Java methods take scalar arguments or return scalar types, and use the standard SOAP v1.1 encoding, the Oracle SOAP Request Handler Servlet performs serialization and encoding internally. For services implemented as Java methods that take user-defined types as parameters or return user-defined types as results, the application programmer needs to provide support classes to handle serialization. With the AddressBook service, a user supplied serialization routine is required for the Address
type that addEntry()
takes as a parameter and getAddressFromName()
returns. The Address
user-defined type contains a PhoneNumber
type that also requires a user-supplied serialization routine.
For types not found in Table 2-1, you can provide a JavaBean that supports serialization and deserialization, using the standard SOAP v1.1 encoding. The BeanSerializer
class within Oracle SOAP uses JavaBeans to serialize and deserialize user-defined types with the SOAP-ENC encoding style. This technique enables handling of Java user-defined types for a SOAP service on both the client and server-side.
Perform the following steps to use a JavaBean and the BeanSerializer
:
CLASSPATH
(on the server-side and the client-side). The section, "Adding Compiled JavaBean Classes to the CLASSPATH" describes this step.
The AddressBook sample provides several JavaBeans that the SOAP BeanSerializer
uses to support serialization in the AddressBook service. The files Address.java
and PhoneNumber.java
provide the JavaBean serialization support that allows SOAP to process and pass an address and a phone number between the SOAP client and the SOAP server. These routines are JavaBeans for the Address
and PhoneNumber
types. JavaBeans conform to the JavaBeans specification and have the following characteristics:
See Also:
http://www.javasoft.com/products/javabeans/docs
for information on JavaBeans
Example 3-1 shows the conforming setCity()
set method and getCity()
get method from the Address
JavaBean that supports the AddressBook SOAP service (see Address.java
for the complete JavaBean sample).
public void setCity(String city) { this.city = city; } public String getCity() { return city; }
After creating and compiling the JavaBean, add the generated support class to the CLASSPATH
. Note, this code has to be made available to both the SOAP service on the server-side and to the SOAP client code on the client-side.
On the server-side add the class to the CLASSPATH
for the SOAP Request Handler Servlet routine (the routine that invokes the Java service). There are two ways to add the service class to the CLASSPATH
, depending on the mode the Oracle SOAP Request Handler Servlet is running in, either auto mode or non-auto mode.
wrapper.classpath
in the file jservSoap.properties
in the directory $ORACLE_HOME/Apache/Jserv/etc.
CLASSPATH
in the routine startSoapJServ.sh
on UNIX or startSoapJServ.bat
on Windows NT.
After modifying the CLASSPATH, restart the SOAP Request Handler Servlet.
% stopSoapJServ.sh
On Windows NT, the command is:
> stopSoapJServ.bat
% stopSoapJServ.sh % startSoapJServ.sh
On Windows NT, the command is:
> stopSoapJServ.bat > startSoapJServ.bat
The getAddressFromName()
code segment shown in Example 3-2 gets the address from memory and returns an Address
. The getAddressFromName()
method returns its result to the Oracle SOAP Java Provider.
public Address getAddressFromName(String name) throws IllegalArgumentException { if (name == null) { throw new IllegalArgumentException("The name must not be " + "null."); } return (Address)name2AddressTable.get(name); }
Oracle SOAP supports two types of XML encoding for user-defined parameters and results:
For Java service parameters and results, the map
element of the service descriptor deployment file sets the encoding style, and the XML to Java and Java to XML serialization and deserialization routines for user-defined types.
To deploy a SOAP service with user-defined types, you need to create a service deployment descriptor file and include a mappings element with map
elements for each user-defined type. Example 3-3 shows the mappings element from the AddressBook service descriptor ServiceDescriptor.xml
. This descriptor is included in the directory $SOAP_HOME/samples/addressbook
on UNIX or %SOAP_HOME%\samples\addressbook
on Windows NT. The service descriptor file should conform to the service descriptor schema defined in service.xsd
in the directory $SOAP_HOME/schemas
on UNIX or in %SOAP_HOME%\schemas
on Windows NT. Table 3-1 describes the attributes of the map
element.
After creating the deployment descriptor file, deploy the service using the SOAP Service Manager utility.
<isd:mappings> <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:x="urn:xml-soap-address-demo" qname="x:address" javaType="samples.addressbook.Address" java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer" xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/> <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:x="urn:xml-soap-address-demo" qname="x:phone" javaType="samples.addressbook.PhoneNumber" java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer" xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/> </isd:mappings>
After creating and deploying one or more SOAP services, client-side applications request service invocations. For details on the basic components of a client-side application that makes a SOAP service request, see Chapter 2, "Using Oracle SOAP with Java Services". This section shows additional SOAP client-side techniques that allow you to use parameters to make service requests. The topics covered include:
This section describes the procedure for using the PutAddress
client to make an addEntry()
method request of the AddressBook service. The AddressBook service is supplied with Oracle SOAP in samples.jar
. For complete details on the code for this section, refer to PutAddress.java
in the directory $SOAP_HOME/samples/addressbook
.
The command line arguments specify the address and phone number for the Address
parameter to pass to the SOAP method, addEntry()
. Example 3-4 shows the instantiation for the Address
object. The new Address
is used as a parameter in the addEntry()
service when the service runs on the SOAP server. PutAddress
obtains the args[]
values from the command line.
String nameToRegister = args[1]; PhoneNumber phoneNumber = new PhoneNumber( Integer.parseInt(args[7]), args[8], args[9]); Address address = new Address(Integer.parseInt(args[2]), args[3], args[4], args[5], Integer.parseInt(args[6]), phoneNumber);
Using the standard SOAP encoding, the SOAP Java client-side API handles serialization and encoding for primitive types internally. The PutAddress
class makes a request for the SOAP addEntry()
method from the AddressBook SOAP service. The addEntry()
method takes an Address
parameter, which is not a primitive type. To pass an address, the SOAP client needs to handle serialization and mapping for the Address
and the PhoneNumber
objects. Example 3-5 shows the SOAPMappingRegistry
, the BeanSerializer
, and the encoding style flags that allow the SOAP client to serialize these user-defined objects. Note that the mapTypes()
method takes a QName
argument. The QName
is defined when a service is deployed on the SOAP server.
SOAPMappingRegistry smr = new SOAPMappingRegistry(); BeanSerializer beanSer = new BeanSerializer(); String encodingStyleURI = Constants.NS_URI_SOAP_ENC; // create the type mapping smr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:xml-soap-address-demo", "address"), Address.class, beanSer, beanSer); smr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:xml-soap-address-demo", "phone"), PhoneNumber.class, beanSer, beanSer);
The package org.apache.soap.rpc
contains the SOAP Call
object. A SOAP client-side request uses a Call
object to build a request for a SOAP service. After the request is created, it is invoked to request that the client API pass the request on to the SOAP server. Example 3-6 shows the code that builds a request for a service invocation, including name
and address
that are sent to addEntry()
.
Call call = new Call(); call.setSOAPMappingRegistry(smr); String serviceId = "urn:www-oracle-com:AddressBook"; call.setTargetObjectURI(serviceId); call.setMethodName("addEntry"); call.setEncodingStyleURI(encodingStyleURI); Vector params = new Vector(); params.addElement(new Parameter("name", String.class, nameToRegister, null)); params.addElement(new Parameter("address", Address.class, address, null)); call.setParams(params);
This code does the following:
Call
object
Call
object's target URI
Call
object's method name
Call
object's encoding style
Call
object's parameters with a QName
to establish the mapping
In addition, the setTimeout()
method sets the timeout, an integer representing seconds. The default Call
timeout, implicitly set in this example, specifies no timeout. Setting a timeout value of 0 also specifies no timeout.
In Example 3-7 the Call
object's invoke()
method makes a SOAP request and invokes the service at the specified URL. The Response
object handles the response. The URL that you provide on the command line should be the URL for the SOAP Request Handler Servlet. This value depends on where SOAP is deployed. For example, the URL could be composed as follows:
http://machineName:port/soap/servlet/soaprouter
Response resp; try { resp = call.invoke(url, SOAPactionURI); } catch (SOAPException e) { System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage()); return; }
After writing a SOAP client using parameters, and setting the SOAP environment, run the client as you would any Java program:
cd $SOAP_HOME/bin source clientenv.csh java ${JAXP} samples.addressbook.PutAddress ${SOAP_URL} "John Doe" 123 "Main Street" AnyTown SS 12345 800 555 1212
Consider a SOAP Java service that returns the sum of the elements of an integer array. Example 3-8 shows the SOAPArrayCalculator
service that takes an array parameter and returns the sum. The getSum()
method returns the sum of the input elements of the integer array, array1
.
This section covers the following:
For a SOAP Java service, passing arrays on the server-side is no different than passing other parameters, as shown in Example 3-8.
package SOAPServices; public class SOAPArrayCalculator extends Object { public SOAPArrayCalculator() { } public static int getSum(int[] array1) { int result = 0; for (int i=0; i<array1.length; i++) result += array1[i]; return result; } }
On the client-side, making a request for a SOAP Java service and passing arrays is slightly different than passing other parameters. Example 3-9 shows that the Java client-side application must send an array of Integer
for the corresponding array of int
in the service on the server-side. SOAP handles the encoding and decoding of the array using a reflection mechanism implemented at the SOAP server level. This mechanism allows SOAP to know what to receive and how to stream it in the requests and responses.
Integer[] array = getIntegerArray(); Vector prms = new Vector(); prms.addElement(new Parameter("integerArray", Integer[].class, array, null)); call.setParams(prms);
This section uses the getAllListings()
method in the AddressBook service to describe the procedure for writing a SOAP service using literal XML encoding. The getAllListings()
method returns a list of all AddressBook listings as a literal XML element. The SOAP client application GetAllListings.java
is included in the directory $SOAP_HOME/samples/addressbook
. This section describes the changes you need to make on both the client and server sides to support passing parameters or results using a literal XML encoding.
This section covers the following topics:
When writing a Java SOAP service that uses a literal XML encoding for a parameter or for a return value, add the following imports to support working in XML:
import java.util.*;
import org.w3c.dom.*;
import org.apache.soap.util.xml.*;
import oracle
.soap.util.xml.XmlUtils;
The SOAP Request Handler Servlet uses literal XML encoding for all parameters that specify this encoding in a client request, and for return values when the default encoding style set for the call specifies XML encoding. Use the Call
method, setEncodingStyleURI()
with a value of Constants.NS_URI_LITERAL_XML
to set the default encoding style for a call to literal XML.
The Java service implementation provides either the appropriate literal XML parameters or a literal XML return value. For example, when literal XML encoding is specified as the default encoding in the SOAP request, the return value sent back to the client from the Java service should be a valid XML element, as defined by org.w3c.dom.Element
. Thus, the client call specifies the default encoding that is used for a return value, and for all parameters that do not explicitly set an encoding style. The service provides a valid object that conforms to the encoding. The AddressBook method getAllListings()
shows how a Java service could build an Element
that SOAP could encode literally in XML. Oracle SOAP supplies XmlUtils
methods that support working with XML documents.
On the client-side, a SOAP service that passes a literal XML argument or returns a literal XML value is very similar to the services using the basic SOAP Java functionality shown in Chapter 2, "Using Oracle SOAP with Java Services".
Minor changes are required to support literal XML encoding, including:
To specify a call using literal XML encoding for all parameters and results, use the setEncodingStyleURI()
method, with the value Constants.NS_URI_LITERAL_XML
. Example 3-10 shows the Java that builds the call for getAllListings()
.
Call call = new Call(); String serviceId = "urn:www-oracle-com:AddressBook"; call.setTargetObjectURI(serviceId); call.setMethodName("getAllListings"); call.setEncodingStyleURI(Constants.NS_URI_LITERAL_XML);
After setting up the client to receive a literal XML encoded result, invoke the service on the SOAP server as you would any service. Using GetAllListings
, the result is sent in the response return value. Example 3-11 shows how the return value is placed in a SOAP client API Parameter
object, which is then cast to an Element
using the getValue()
method.
Response resp; try { resp = call.invoke(url, ""); } catch (SOAPException e) { System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage()); return; } Check value // check the response if (!resp.generatedFault()) { Parameter ret = resp.getReturnValue(); Element bookEl = (Element)ret.getValue(); System.out.println(DOM2Writer.nodeToString(bookEl)); } else { Fault fault = resp.getFault(); System.err.println("Generated fault: "); System.out.println (" Fault Code = " + fault.getFaultCode()); System.out.println (" Fault String = " + fault.getFaultString()); } }
|
Copyright © 2001 Oracle Corporation. All Rights Reserved. |
|