Skip Headers
Oracle® Application Server Web Services Developer's Guide
10g Release 2 (10.1.2)
Part No. B14027-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

11 Consuming Web Services in J2EE Applications

This chapter describes how to consume Web Services in Java 2 Platform, Enterprise Edition (J2EE) applications. One type of Web-based information or services is supported:

In addition, when a J2EE application acquires a WSDL document at runtime, the dynamic invocation API is used to invoke any SOAP operation described in the WSDL document. See Dynamic Invocation of Web Services for information about how to use the dynamic invocation API.

11.1 Consuming SOAP-Based Web Services Using WSDL

The wsdl2ejb utility can be used by J2EE developers to consume a Web Service described in Web Services Description Language (WSDL) document into their applications. This utility takes a WSDL document and some additional optional parameters and produces an EJB EAR file that can be deployed into OC4J. The EJB Remote Interface is generated based on the WSDL portType. Each WSDL operation is mapped to an EJB method. The EJB method parameters are derived from the WSDL operation input message parts, while the EJB method return value is mapped from the parts of the WSDL operation output message. The Oracle SOAP Mapping Registry is used to map XML types to the corresponding Java types.

Additional references regarding WSDL and SOAP can be found in the following locations:




The command-line options for running the wsdl2ejb utility are described in Table 11-1.

Table 11-1 wsdl2ejb Utility Command-Line Options

Option Description
-conf <config file> Allows the wsdl2ejb utility to load a configuration file.
-d <destDir> Allows a destination directory to be specified where the generated EJB EAR file is to be written.
-Dhttp.proxyHost Allows the proxy host name to be specified when an HTTP URL is used to supply the location of the WSDL document and an HTTP proxy server is required to access it.
-Dhttp.proxyPort Allows the proxy port number to be specified when an HTTP URL is used to supply the location of the WSDL document and an HTTP proxy server is required to access it.
-jar Allows you to specify the wsdl2ejb utility as a JAR file.

To run the wsdl2ejb utility, enter the following command where <destDir> is the destination directory to where the generated EJB EAR file is to be written and the file mydoc.wsdl is the location of the WSDL document:

java -jar wsdl2ejb.jar -d <destDir> mydoc.wsdl


Note:

The wsdl2ejb.jar file is located in your $ORACLE_HOME/webservices/lib installation directory for UNIX or %ORACLE_HOME\webservices\lib installation directory for Windows.

If an HTTP URL is used to supply the location of the WSDL document and an HTTP proxy is required to access it, the following command and syntax must be used to run the utility:

java -Dhttp.ProxyHost=myProxyHost -Dhttp.proxyPort=80 -jar wsdl2ejb.jar -d <destDir> http://myhost/mydoc.wsdl

In this example, the utility uses the supplied WSDL to generate the EJB EAR file in the destination directory (<destDir>). The EJB class name, Java Naming and Directory Interface (JNDI) binding key, and Java package name are derived from the location of the SOAP service described in the WSDL.

In this command syntax, the wsdl2ejb utility maps the XML types, which are supported by default by the Oracle SOAP Mapping Registry.

The wsdl2ejb utility generates the following sets of files located within the destination directory name (<destDir>) that you specify in the command line. The utility saves the generated files using the following directory layout:

 Root /
      + app.ear
      + src/
        + ... generated java sources ...
      + classes/
        + META-INF/
          + ejb-jar.xml
        + ... compiled classes and xml resources ....
      + deploy/
        + ejb.jar
        + META-INF/
          + application.xml

11.1.1 Advanced Configuration

To have more controls on the EJB generated from a WSDL document, an XML configuration file can be supplied to the wsdl2ejb utility. Through the configuration file, developers can control several options on the WSDL source, as well as options on the generated EJB.

Developers can also use the configuration file to supply additional xml to Java type maps, so that WSDL documents using complex types can be supported.

The syntax of the wsdl2ejb configuration file is shown in its Document Type Definition (DTD) as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Specify the properties of the source WSDL document and of the target EJB. -->
<!ELEMENT wsdl2ejb (useProxy?, useWallet?, wsdl, ejb?, mapTypes?)>

<!-- Specify if the generated EJB should use the supplied HTTP proxy when accessing HTTP URLs -->
<!ELEMENT useProxy (#PCDATA)>
<!ATTLIST useProxy
          proxyHost CDATA   #REQUIRED
          proxyPort CDATA   #REQUIRED>

<!-- Specify the location of the wallet credential file used by the generated EJB for opening HTTPS connection -->
<!ELEMENT useWallet (#PCDATA)>
<!ATTLIST useWallet
          location  CDATA   #REQUIRED>

<!-- 
    Specify how the wsdl2ejb tools should process the source WSDL document.
     In additional to the mandatory location of the WSDL document, the name of the WSDL service and 
     its port can be specified. In this case, an EJB will be generated only for the supplied service and
    port. 
     An alternative: the name of a WSDL service binding and the SOAP location to be used can be supplied.
     In the latter case, an EJB using the specified binding and the supplied SOAP location will be used.
     This is particularly useful when generating an EJB from a WSDL stored in a UDDI registry. 
     In fact, following a UDDI best practice, the WSDL SOAP location will be managed separately from the 
    WSDL document.
 -->
<!ELEMENT wsdl (location, ((service-name, service-port) | (service-binding, soap-location))?)>

<!-- Specify the location of the source WSDL document (for example, "/home/mywsdl.wsdl", "http://myhost/mywsdl.wsdl") -->
<!ELEMENT location (#PCDATA)>


<!-- Specify the name of the WSDL service to be used for the generation. 
     It is the name of one of the services defined in the source WSDL. -->
<!ELEMENT service-name (#PCDATA)>


<!-- Specify the service port of the WSDL service to be used for the generation. 
     It is the name of one ports of the service name defined above in the source WSDL. -->
<!ELEMENT service-port (#PCDATA)>


<!-- Specify the name of the WSDL binding to be used for the generation. 
     It is the name of one of the bindings defined in the source WSDL. -->
<!ELEMENT service-binding (#PCDATA)>

<!-- Specify the SOAP location service port of the WSDL service to be used for the generation. 
     It is the name of one ports of the service name defined above in the source WSDL. -->
<!ELEMENT soap-location (#PCDATA)>

<!-- Specify the properties related to the generated EJB. -->
<!ELEMENT ejb (application-name?, ejb-name?, package-name?, remote-name?, session-type?)>

<!-- Specify the name of the J2EE application for the generated EAR.  -->
<!ELEMENT application-name (#PCDATA)>

<!-- Specify the JNDI binding key name for the generated EJB.  -->
<!ELEMENT ejb-name (#PCDATA)>

<!-- Specify the name for Java package under which the generated EJB will belong. (for example, com.oracle)  -->
<!ELEMENT package-name (#PCDATA)>

<!-- Specify the class name for the EJB Remote Interface (for example, MyWsdlEjb)  -->
<!ELEMENT remote-name (#PCDATA)>

<!-- Specify the if the generated EJB should be stateless or stateful (for example, Stateless | Stateful)  -->
<!ELEMENT session-type (#PCDATA)>

<!-- 
    Specify the custom Java types and map them to XML types. 
     The JAR attribute value will point to a JAR file containing the definition of the custom 
     types or the serializer/deserializer to be used for the custom type. 
-->
<!ELEMENT mapTypes (map*)>
<!ATTLIST mapTypes
          jar           CDATA   #IMPLED>

!-- 
     Specify a new XML to JAR type map. 
     EncodingStyle: name of the encodingStyle under which this map will belong 
                    (for example, http://schemas.xmlsoap.org/soap/encoding/)
     namespace-uri      : uri of the namespace for the XML type defined in this map
     local-name         : localname of the XML type defined in this map
      java-type          : Java class name to which this type is mapped to (for example, com.org.MyBean)
     java2xml-class-name: Java class name of the type serializer 
                          (for example, org.apache.soap.encoding.soapenc.BeanSerializer)
     xml2java-class-name: Java class name of the type deserializer 
                          (for example, org.apache.soap.encoding.soapenc.BeanSerializer)
-->
<!ELEMENT map (#PCDATA)>
<!ATTLIST map
          encodingStyle       CDATA   #REQUIRED
          namespace-uri       CDATA   #REQUIRED
          local-name          CDATA   #REQUIRED
          java-type           CDATA   #REQUIRED
          java2xml-class-name CDATA   #REQUIRED
          xml2java-class-name CDATA   #REQUIRED>

Table 11-2 describes the elements, subelements, and attributes of the wsdl2ejb XML configuration file as defined in the DTD. Required elements and attributes are shown as bold text.

Table 11-2 Elements, Subelements, and Attributes of the wsdl2ejb XML Configuration File as Defined in the DTD

Element Subelement Attribute Description
useProxy

Optional element. Specifies the proxy server attributes.


proxyHost Required attribute. Specifies the host name of the proxy server.


proxyPort Required attribute. Specifies the port number of the proxy server.
useWallet

Optional element. Specifies the Oracle Wallet attribute.


location Required attribute. Specifies the location of the Oracle Wallet credential file used by the EJB for opening the HTTPS connection.
wsdl

Required element. Specifies how the wsdl2ejb utility should process the source WSDL document. Requires the location element be specified and optionally, either the service-name and service-port pair of elements or the service-binding and soap-location pair of elements be specified.

location
Required element. Specifies the location of the source WSDL document. Can be a file path or an URL.

service-name
Optional element. Specifies the name of the WSDL service to be used for the generated EJB. If specified, must be specified with the service-port element as a pair of elements.

service-port
Optional element. Specifies the service port of the WSDL service to be used for the generated EJB. If specified, must be specified with the service-name element as a pair of elements.

service-binding
Optional element. Specifies the name of the WSDL binding to be used for the generated EJB. If specified, must be specified with the soap-location element as a pair of elements.

soap-location
Optional element. Specifies the SOAP location service port of the WSDL service to be used for the generated EJB. If specified, must be specified with the service-binding element as a pair of elements.
ejb

Optional element. Specifies the properties related to the generated EJB.

application-name
Optional element. Specifies the name of the J2EE application for the generated EAR file.

ejb-name
Optional element. Specifies the JNDI binding key name for the generated EJB.

package-name
Optional element. Specifies the name for the Java package under which the generated EJB belongs.

remote-name
Optional element. Specifies the class name for the EJB Remote Interface.

session-type
Optional element. Specifies whether the generated EJB should be stateless or stateful.
mapTypes

Optional element. Specifies the custom Java types and maps them to XML types.

map
Optional element. Specifies the XML to JAR type map.


encodingStyle Required attribute. Specifies the name of the encoding style under which this map belongs.


namespace-uri Required attribute. Specifies the URI of the namespace for the XML type defined in this map.


local-name Required attribute. Specified the local name of the XML type defined in this map.


java-type Required attribute. Specifies the Java class name to which this type is mapped.


java2xml-class-name Required attribute. Specifies the Java class name of the type serializer.


xml2java-class-name Required attribute. Specifies the Java class name of the type deserializer.

Developers can run the wsdl2ejb utility with a configuration file using the following command:

java -jar wsdl2ejb.jar -conf wsdlconf.xml

Supported WSDL Documents

The wsdl2ejb utility supports most WSDL documents using SOAP binding. This support includes both Remote Procedure Call (RPC) and document style documents as well as types that are encoded or literal. Table 11-3 shows how the supported XML Schema types are mapped to the corresponding Java type by default. Any other required type will have to be supported though the custom type mapping described previously.

Table 11-3 Supported XML Schema Types and Corresponding Java Type

Supported XML Schema Type Corresponding Java Type
string java.lang.String
int int
decimal BigDecimal
float float
double double
Boolean Boolean
long long
short short
byte byte
date GregorianCalendar
timeInstant java.util.Date


Note:

Arrays of supported types, shown in Table 11-3 are also supported.

11.1.2 Known Limitations of the wsdl2ejb Utility

The following information describes the known limitations of the wsdl2ejb utility:

  • Supports only types defined by the W3C recommendation XML schema version whose namespace is: http://www.w3.org/2001/XMLSchema

  • Supports only the One-way and Request-Response transmission primitives defined in the WSDL 1.1 specification.

  • Does not support WSDL documents that use the <import> tag to include other WSDL documents.

  • Does not support HTTP, MIME, or any other custom bindings.

11.1.3 Running the Demonstration

The wsdl2ejb demo directory contains examples on how to use the wsdl2ejb utility. All the commands are assumed to be executed from the $ORACLE_HOME/webservices/demo/basic/wsdl2ejb directory. The demonstration (demo) will use some sample WSDL documents as sources and generate EJB that can be used to invoke the Web Service operations.

The demos can be run using Jakarta ant. Review the build.xml file to make sure that the initial properties (RMI_HOST, RMI_PORT, RMI_ADMIN, RMI_PWD) are set correctly according to your configuration. The build.xml file will execute the wsdl2ejb utility on the demo WSDL documents, deploy the generated EJB, and execute the EJB clients.


Note:

IIf you are executing the demos behind a firewall and need to set proxy information to access external HTTP sites, make sure this proxy information is specified in the wsdl2ejb configuration files (rpc_doc_conf.xml, base_conf.xml).


Note:

The demos are based on WSDL/SOAP interoperability test suites. They access live SOAP services available on the Internet as SOAP interoperability test cases. The successful execution of these demos depends on the availability of these services.

The directory structure of the demos is as follows:

demo/web_services/wsdl2ejb:
   - README.txt                : Readme file
   - build.xml                 : Jakarta ant build file to run all the demos
   - rpc_doc                   : directory for simple RPC and document style operations
       - rpc_doc_conf.xml      : wsdl2ejb configuration file for the rpc_doc demo
       - TestRpcDocClient.java : client for the rpc_doc demo
       - DocAndRpc.wsdl        : sample WSDL for the rpc_doc demo
       - (generated)           : directory where the EJB will be generated
   - base
       - base_conf.xml         : wsdl2ejb configuration file for the base interoperability demo
       - TestInteropBaseClient.java : client for the base interoperability demo
       - InteropTest.wsdl           : WSDL document for the base interoperability demo
       - MySoapStructBean.java      : bean utilized to map the custom type used
                                        in the example defined in the WSDL document
       - MySoapStructBean.jar       : packaged-compiled custom type bean
       - (generated)                : directory where the EJB will be generated

11.1.3.1 RPC and Document Style with Simple Types Example

This example uses a simple WSDL document that shows a couple of operations: Add and Multiply. Add is using the document-style operation using literal parts, while Multiply is RPC-style and uses encoded parts.

To generate the EJB stub, use the following command:

On UNIX
cd $ORACLE_HOME/webservices/demo/basic/wsdl2ejb
java -jar ../../../lib/wsdl2ejb.jar -conf rpc_doc/rpc_doc_conf.xml

On Windows
cd %ORACLE_HOME%\webservices\demo\basic\wsdl2ejb
java -jar ..\..\..\lib\wsdl2ejb.jar -conf rpc_doc\rpc_doc_conf.xml

The utility generates the TestApp.ear file containing the definition of a stateless EJB, which can be used as a proxy for the Web Service. The EAR file can be deployed in OC4J as any standard EJB. Refer to Oracle Application Server Containers for J2EE User's Guide for information on how to deploy an EJB.

By looking at the generated EJB Remote Interface, you can see how the WSDL portType DocAndRpc.wsdl file has been mapped to Java.

WSDL PortType:

  <types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://soapinterop.org">
      <s:element name="Add">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" />
            <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="AddResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:int" />
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </types>
  <message name="AddSoapIn">
    <part name="parameters" element="s0:Add" /> 
  </message>
  <message name="AddSoapOut">
    <part name="parameters" element="s0:AddResponse" /> 
  </message>
  <message name="MultiplySoapIn">
    <part name="a" type="xsd:int" /> 
    <part name="b" type="xsd:int" /> 
  </message>
  <message name="MultiplySoapOut">
    <part name="MultiplyResult" type="s:int" /> 
  </message>
  <portType name="TestSoap">
    <operation name="Add">
      <input message="s0:AddSoapIn" /> 
      <output message="s0:AddSoapOut" /> 
    </operation>
    <operation name="Multiply">
      <input message="s0:MultiplySoapIn" /> 
      <output message="s0:MultiplySoapOut" /> 
    </operation>
  </portType>

From the Test.java file, the EJB Remote Interface is:

  public org.w3c.dom.Element add(org.w3c.dom.Element parameters)
    throws RemoteException;
 
  public int multiply(int a, int b)
    throws RemoteException;

When the WSDL operation is using RPC style and its parts are encoded, the parts XML schema type is mapped to a corresponding Java native type. In this example, xsd:int is mapped to Java int. In a document style using literal parts, each part is simply mapped to an org.w3c.dom.Element.

The following client code in the TestRpcDocClient.java file can be used to invoke the Add and Multiply Web Service operations. The code has been produced by modifying the client code stub generated by the wsdl2ejb utility.

import java.io.*;
import java.util.*;
import javax.naming.*;

import org.w3c.dom.*;
import oracle.xml.parser.v2.*;

import org.mssoapinterop.asmx.Test;
import org.mssoapinterop.asmx.TestHome;


/**
 * This is a simple client template. To compile it, 
 * please include the generated EJB jar file as well as
 * EJB and JNDI libraries in classpath.
 */
public class TestRpcDocClient
{
  // replace the values
  private static String RMI_HOST  = "localhost";
  private static String RMI_PORT  = "23791";
  private static String RMI_ADMIN = "admin";
  private static String RMI_PWD   = "welcome";

  public TestRpcDocClient () {}

  public static void main(String args[]) {

    TestRpcDocClient client = new TestRpcDocClient();

    try {

      RMI_HOST  = args[0];
      RMI_PORT  = args[1];
      RMI_ADMIN = args[2];
      RMI_PWD   = args[3];

      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory");
      env.put(Context.SECURITY_PRINCIPAL, RMI_ADMIN);
      env.put(Context.SECURITY_CREDENTIALS, RMI_PWD);
      env.put(Context.PROVIDER_URL, "ormi://" + RMI_HOST + ":" + RMI_PORT + "/Wsdl2EjbTestApp1");
      Context ctx = new InitialContext(env);
      TestHome home = (TestHome) ctx.lookup("mssoapinterop.org/asmx/DocAndRpc.asmx");
      
      Test service = home.create();
      
      // call any of the Remote methods that follow to access the EJB
      
      //
      // Add test
      //
      Document  doc = new XMLDocument();
      Element elAdd = doc.createElementNS("http://soapinterop.org", "s:Add");
      Element   elA = doc.createElementNS("http://soapinterop.org", "s:a");
      Element   elB = doc.createElementNS("http://soapinterop.org", "s:b");
      elA.appendChild(doc.createTextNode("4"));
      elB.appendChild(doc.createTextNode("3"));
      elAdd.appendChild(elA);
      elAdd.appendChild(elB);
      doc.appendChild(elAdd);
      
      Element elAddResponse = service.add(elAdd);
      Node tNode = elAddResponse.getFirstChild().getFirstChild();
      System.out.println("AddResponse: "+tNode.getNodeValue());

      //
      // Multiply Test
      //
      int a = 4;
      int b = 3;
      int iMultiplyResponse = service.multiply(a, b);
      System.out.println("MultiplyResponse: "+iMultiplyResponse);
      
      
    } 
    catch (Throwable ex) {
      ex.printStackTrace();
    }
  }
} 


The result of the execution of the client is the following:

AddResponse: 7
MultiplyResponse: 12

11.1.3.2 Round 2 Interop Services: Base Test Suite Example

This example starts from a subset of the WSDL document defined by the base test suite of the second round of SOAP interoperability tests. The purpose of this demo example is to show the usage of built-in types in the SOAP Mapping Registry as well as how to add custom types mapping.

Start by looking at the WSDL portType in the InteropTest.wsdl file.

<types>
   <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soapinterop.org/xsd">
      <complexType name="ArrayOfstring">
         <complexContent>
            <restriction base="SOAP-ENC:Array">
               <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="string[]"/>
            </restriction>
         </complexContent>
       </complexType>
       <complexType name="ArrayOfint">
          <complexContent>
            <restriction base="SOAP-ENC:Array">
               <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="int[]"/>
            </restriction>
          </complexContent>
       </complexType>
       <complexType name="ArrayOffloat">
          <complexContent>
             <restriction base="SOAP-ENC:Array">
                <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="float[]"/>
             </restriction>
          </complexContent>
       </complexType>
       <complexType name="ArrayOfSOAPStruct">
          <complexContent>
             <restriction base="SOAP-ENC:Array">
                <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="s:SOAPStruct[]"/>
             </restriction>
         </complexContent>
      </complexType>
      <complexType name="SOAPStruct">
            <all>
                <element name="varString" type="string"/>
                <element name="varInt" type="int"/>
                <element name="varFloat" type="float"/>
            </all>
      </complexType>
   </schema>
</types>

<message name="echoStringRequest">
   <part name="inputString" type="xsd:string"/>
</message>
<message name="echoStringResponse">
   <part name="return" type="xsd:string"/>
</message>
<message name="echoStringArrayRequest">
   <part name="inputStringArray" type="s:ArrayOfstring"/>
</message>
<message name="echoStringArrayResponse">
   <part name="return" type="s:ArrayOfstring"/>
</message>
<message name="echoIntegerRequest">
   <part name="inputInteger" type="xsd:int"/>
</message>
<message name="echoIntegerResponse">
   <part name="return" type="xsd:int"/>
</message>
<message name="echoIntegerArrayRequest">
   <part name="inputIntegerArray" type="s:ArrayOfint"/>
</message>
<message name="echoIntegerArrayResponse">
   <part name="return" type="s:ArrayOfint"/>
</message>
<message name="echoFloatRequest">
   <part name="inputFloat" type="xsd:float"/>
</message>
<message name="echoFloatResponse">
   <part name="return" type="xsd:float"/>
</message>
<message name="echoFloatArrayRequest">
   <part name="inputFloatArray" type="s:ArrayOffloat"/>
</message>
<message name="echoFloatArrayResponse">
   <part name="return" type="s:ArrayOffloat"/>
</message>
<message name="echoStructRequest">
   <part name="inputStruct" type="s:SOAPStruct"/>
</message>
<message name="echoStructResponse">
   <part name="return" type="s:SOAPStruct"/>
</message>
<message name="echoStructArrayRequest">
   <part name="inputStructArray" type="s:ArrayOfSOAPStruct"/>
</message>
<message name="echoStructArrayResponse">
   <part name="return" type="s:ArrayOfSOAPStruct"/>
</message>
<message name="echoVoidRequest"/>
<message name="echoVoidResponse"/>
<message name="echoBase64Request">
   <part name="inputBase64" type="xsd:base64Binary"/>
</message>
<message name="echoBase64Response">
   <part name="return" type="xsd:base64Binary"/>
</message>
<message name="echoDateRequest">
   <part name="inputDate" type="xsd:dateTime"/>
</message>
<message name="echoDateResponse">
   <part name="return" type="xsd:dateTime"/>
</message>
<message name="echoDecimalRequest">
   <part name="inputDecimal" type="xsd:decimal"/>
</message>
<message name="echoDecimalResponse">
   <part name="return" type="xsd:decimal"/>
</message>
<message name="echoBooleanRequest">
   <part name="inputBoolean" type="xsd:boolean"/>
</message>
<message name="echoBooleanResponse">
   <part name="return" type="xsd:boolean"/>
</message>

<portType name="InteropTestPortType">
   <operation name="echoString" parameterOrder="inputString">
      <input message="tns:echoStringRequest"/>
      <output message="tns:echoStringResponse"/>
   </operation>
   <operation name="echoStringArray" parameterOrder="inputStringArray">
      <input message="tns:echoStringArrayRequest"/>
      <output message="tns:echoStringArrayResponse"/>
   </operation>
   <operation name="echoInteger" parameterOrder="inputInteger">
      <input message="tns:echoIntegerRequest"/>
      <output message="tns:echoIntegerResponse"/>
   </operation>
   <operation name="echoIntegerArray" parameterOrder="inputIntegerArray">
      <input message="tns:echoIntegerArrayRequest"/>
   <output message="tns:echoIntegerArrayResponse"/>
   </operation>
   <operation name="echoFloat" parameterOrder="inputFloat">
      <input message="tns:echoFloatRequest"/>
   <output message="tns:echoFloatResponse"/>
   </operation>
   <operation name="echoFloatArray" parameterOrder="inputFloatArray">
      <input message="tns:echoFloatArrayRequest"/>
      <output message="tns:echoFloatArrayResponse"/>
   </operation>
   <operation name="echoStruct" parameterOrder="inputStruct">
      <input message="tns:echoStructRequest"/>
      <output message="tns:echoStructResponse"/>
   </operation>
   <operation name="echoStructArray" parameterOrder="inputStructArray">
      <input message="tns:echoStructArrayRequest"/>
      <output message="tns:echoStructArrayResponse"/>
   </operation>
   <operation name="echoVoid">
      <input message="tns:echoVoidRequest"/>
      <output message="tns:echoVoidResponse"/>
   </operation>
   <operation name="echoBase64" parameterOrder="inputBase64">
      <input message="tns:echoBase64Request"/>
      <output message="tns:echoBase64Response"/>
   </operation>
   <operation name="echoDate" parameterOrder="inputDate">
      <input message="tns:echoDateRequest"/>
      <output message="tns:echoDateResponse"/>
   </operation>
   <operation name="echoDecimal" parameterOrder="inputDecimal">
      <input message="tns:echoDecimalRequest"/>
      <output message="tns:echoDecimalResponse"/>
   </operation>
   <operation name="echoBoolean" parameterOrder="inputBoolean">
      <input message="tns:echoBooleanRequest"/>
      <output message="tns:echoBooleanResponse"/>
   </operation>
</portType>

Notice that the WSDL document contains more complex types than the previous demo. Array of primitives types are now used as well as the struct primitive types. With the exception of the SOAPStruct complex type, every other type is supported as built-in type in the SOAP Mapping Registry. You then need to add a new complex type definition to the SOAP Mapping Registry to handle the SOAPStruct complex type.

The SOAPStruct schema definition is the following:

<complexType name="SOAPStruct">
      <all>
            <element name="varString" type="string"/>
            <element name="varInt" type="int"/>
            <element name="varFloat" type="float"/>
      </all>
</complexType>

In the MySoapStructBean.java file, this SOAPStruct complex type can be mapped to a simple JavaBean class such as the following, and have the marshalling and unmarshalling actions handled by the BeanSerializer.

public class MySoapStructBean implements java.io.Serializable 
{
  private String m_varString = null;
  private int m_varInt = 0;
  private float m_varFloat = 0;

  public MySoapStructBean() {}
  public MySoapStructBean(String s, int i, float f) {
    m_varString = s;
    m_varInt    = i;
    m_varFloat  = f;
  }

  public String getVarString () { return m_varString; }
  public int getVarInt() { return m_varInt; }
  public float getVarFloat() { return m_varFloat; }

  public void setVarString (String s) { m_varString = s; }
  public void setVarInt(int i) { m_varInt = i; }
  public void setVarFloat(float f) { m_varFloat = f; }
}

With the mapping JavaBean class ready, and having identified what serializer and deserializer to use, you can now configure the wsdl2ejb utility so that a new schema to Java map is added. This can be achieved by adding the following to the wsdl2ejb configuration file, base_conf.xml:

<mapTypes jar="base/MySoapStructBean.jar" >
  <map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
       local-name="SOAPStruct"
       namespace-uri="http://soapinterop.org/xsd"
       java-type="MySoapStructBean"
       java2xml-class-name="org.apache.soap.encoding.soapenc.BeanSerializer"
       xml2java-class-name="org.apache.soap.encoding.soapenc.BeanSerializer" />
</mapTypes>

The MySoapStructBean.jar file contains the definition of the MySoapStructBean class. With this map, the SOAPStruct complex type, belonging to the http://soapinterop.org/xsd namespace, will be mapped to the MySoapStructBean JavaBean class and the converse is true as well. For more information about SOAP serializers and deserializers, see the Oracle SOAP documentation.

With this additional configuration, you can now run the wsdl2ejb utility with the following command:

On UNIX
cd $ORACLE_HOME/webservices/demo/basic/wsdl2ejb
java -jar ../../../lib/wsdl2ejb.jar -conf base/base_conf.xml
On Windows
cd %ORACLE_HOME%/webservices/demo/basic/wsdl2ejb
java -jar ..\..\..\lib\wsdl2ejb.jar -conf base\base_conf.xml

The wsdl2ejb utility generates the InteropLabApp.ear file that contains the definition of a stateless EJB, which can be used as a proxy for the Web Service. The EAR file can be deployed in OC4J as any standard EJB. See Oracle Application Server Containers for J2EE User's Guide for information on how to deploy an EJB.

The TestInteropBaseClient.java class file, saved in the base directory, can be used to test the generated EJB after it has been deployed. The result of the execution of the client is the following:

echoString: Hello World!
echoStringArray[0]: Hello World!
echoStringArray[1]: Seems to work!
echoStringArray[2]: Fine!
echoStringArray[3]: WOW
echoInteger: 7
echoIntegerArray[0]: 1
echoIntegerArray[1]: 2
echoIntegerArray[2]: 3
echoIntegerArray[3]: 4
echoFloat: 1.7777
echoFloatArray[0]: 1.1
echoFloatArray[1]: 1.2
echoFloatArray[2]: 1.3
echoFloatArray[3]: 1.4
echoStruct: varString=Hello World , varInt=1 , varFloat=1.777
echoStructArray: varString[0]=Hello World , varInt[0]=0 , varFloat=[0]=1.7771
echoStructArray: varString[1]=Hello World 1 , varInt[1]=1 , varFloat=[1]=1.7772
echoStructArray: varString[2]=Hello World 2 , varInt[2]=2 , varFloat=[2]=1.7773
echoStructArray: varString[3]=Hello World 3 , varInt[3]=3 , varFloat=[3]=1.7774
echoVoid.
echoDecimal: 1.77709999999999990194510246510617434978485107421875
echoBoolean: true
echoBase64[0]: 1
echoBase64[1]: 2
echoBase64[2]: 3
echoBase64[3]: 4
echoDate: Sat Nov 10 12:30:00 EST 2001

11.2 Dynamic Invocation of Web Services

When a Java2 Platform Enterprise Edition (J2EE) application acquires a WSDL document at runtime, the dynamic invocation API is used to invoke any SOAP operation described in the WSDL document. The dynamic invocation API describes a WebServiceProxyFactory factory class that can be used to build instances of a WebServiceProxy. Each created WebServiceProxy instance is based on the location of the WSDL document, (and optionally on additional qualifiers), that identify which service and port should be used. The WebServiceProxy class exposes methods to determine the WSDL portType, including the syntax and signatures of all operations exposed by the WSDL service and to invoke the defined operations.

This section briefly describes the dynamic invocation API and how to use it.

For Java samples, refer to the code supplied with Oracle Application Server Web Services in $ORACLE_HOME/webservices/demo/basic/java_services/dynamicproxy on UNIX or in %ORACLE_HOME%\webservices\demo\basic\java_services\dynamicproxy on Windows. For EJB samples, refer to the code supplied in the directory $ORACLE_HOME/webservices/demo/basic/stateless_ejb on UNIX or %ORACLE_HOME%\webservices\demo\basic\stateless_ejb on Windows.

11.2.1 Dynamic Invocation API

The dynamic invocation API contains two packages, oracle.j2ee.ws.client and oracle.j2ee,ws.client.wsdl, which contain additional classes grouped by interface, class, and exception, as shown in Table 11-4 and Table 11-5.

Table 11-4 The oracle.j2ee.ws.client Package

Classes Description
Classes
WebServiceProxyFactory This class creates a WebServiceProxy class given a WSDL document.
Interfaces
WebServiceProxy This interface represents a service defined in a WSDL document.
WebServiceMethod This interface invokes a Web Service method.
Exceptions
WebServiceProxyException This class describes exceptions raised by the WebServiceProxy API.

Table 11-5 The oracle.j2ee.ws.client.wsdl Package

Classes Description
Interfaces
PortType This interface represents a port type.
Operation This interface represents a WSDL operation.
Input This interface represents an input message, and contains the name of the input and the message itself.
Output This interface represents an output message, and contains the name of the output and the message itself.
Fault This interface represents a fault message, and contains the name of the fault and the message itself.
Message This interface describes a message used for communication with an operation.
Part This interface represents a message part and contains the part's name, elementName, and typeName.
Classes
OperationType This class represents an operation type which can be one of request-response, solicit response, one way, or notification.

The oracle.j2ee.ws.client package is described in more detail in this section. The API documentation describes to use this proxy API can be found in the Oracle Application Server 10g Documentation Library as Proxy API Reference (Javadoc) under Oracle Application Server Web Services, which is located under the J2EE and Internet Applications tab.

The WebServiceProxyFactory class contains methods that can instantiate a WebServiceProxy class given either the URL or the Java input stream of the WSDL document. Four methods let you use either the first service and its first port in the supplied WSDL document or use the name of one of services and the name of one of the ports of the service to create a WebServiceProxy instance. Two methods also let you create a WebServiceProxy instance for a WSDL document, which has been authored following the UDDI best practices for WSDL. A method lets you supply additional optional initialization parameters to the WebServiceProxy instance.

Table 11-6 briefly describes the WebServiceProxyFactory factory class methods and the required parameters for each method. See the JavaDoc for more detailed information about this factory class and its methods.

Table 11-6 WebServiceProxyFactory Factory Methods and Parameters

Methods Parameters
createWebServiceProxy() java.io.InputStream isWsdl java.net.URL baseURL
createWebServiceProxy() java.net.URL wsdlURL
createWebServiceProxyFromBinding() java.io.InputStream wsdlis java.net.URL baseUrl java.lang.String szBindingName java.lang.String szSoapLocation
createWebServiceProxyFromService() java.io.InputStream wsdlis java.net.URL baseUrl java.lang.String szServiceName java.lang.String szServicePort
createWebServiceProxyFromBinding() java.net.URL wsdlUrl java.lang.String szBindingName java.lang.String szSoapLocation
createWebServiceProxyFromService() java.net.URL wsdlUrl java.lang.String szServiceName java.lang.String szServicePort
setProperties() java.util.Hashtable ht

Table 11-7 describes the WebServiceProxy interface. The WebServiceProxyFactory factory methods optionally take additional parameters that are provided in the WebServiceProxy interface that can be used to dynamically invoke an operation in a WSDL document.

Table 11-7 WebServiceProxy Interface Methods and Parameters

Methods Parameters Description
getXMLMapping Registry() None Returns the SOAP mapping registry used by the WebServiceProxy and contains information that lets clients use this registry to query for XML to or from Java type mapping as well as extend the mapping registry with new map definitions.
getPortType() None Returns a structure describing the WSDL portType used by this proxy and contains information about operations associated with this port type.
getMethod()

szOperationName szInputName szOutputName

Returns a WebServiceMethod method, which can be used to invoke Web Service methods.

Name of the WSDL operation to be executed. Name of the wsdl:input tag for the operation to be executed. Name of the wsdl:output tag for the operation to be executed.

getMethod() szOperationName Returns a WebServiceMethod method, which can be used to invoke Web service methods and provides a signature that can be used for non-overloaded WSDL operations. Name of the WSDL operation to be executed.

Table 11-8 describes the WebServiceMethod interface, which is used to invoke a Web Service method.

Table 11-8 WebServiceMethod Interface Methods and Parameters

Methods Parameters Description
getInputEncodingStyle() None Returns the encoding style to be used by the input message parts, null if none has been specified in the source WSDL.
getOutputEncodingStyle() None Returns the encoding style to be used by the output message parts, null if none has been specified in the source WSDL.
invoke() inMsgPartNames inMsgPartValues Executes one of the service operations with the set of supplied input parts and returns the object, if the response message contains only one part, return the response part, otherwise an array of the output message parts. If the invoked WSDL operation has no output parts, null will be returned. Name of the parts supplied in the input message. Corresponding value of the parts whose name is supplied in the inMsgPartNames parameter. If the invoked WSDL operation has no input parts, null or empty arrays parameters can be supplied

The oracle.j2ee.ws.client.wsdl package exposes methods to determine the WSDL portType, including the syntax and signatures of all operations exposed by the WSDL service.

11.2.2 WebServiceProxy Client

The following client code shows the use of the dynamic invocation API followed by the output of the client execution. The client code shows the following:

  • Initializes proxy parameters in the WebServiceProxyFactory.

  • Creates an instance of the proxy given a URL of a WSDL document.

  • Performs WSDL introspection.

  • Shows the input message parts.

  • Executes a Web Service operation with a set of supplied input parts and returns the result.

The WSDL document is described as follows:

  <?xml version="1.0" encoding="utf-8" ?> 
- <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soapinterop.org" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://soapinterop.org" xmlns="http://schemas.xmlsoap.org/wsdl/">
  <types /> 
  - <message name="AddSoapIn">
      <part name="a" type="s:int" /> 
      <part name="b" type="s:int" /> 
    </message>
  - <message name="AddSoapOut">
      <part name="AddResult" type="s:int" /> 
    </message>
  - <portType name="TestSoap">
    - <operation name="Add">
        <input message="tns:AddSoapIn" /> 
        <output message="tns:AddSoapOut" /> 
      </operation>
    </portType>
  - <binding name="TestSoap" type="tns:TestSoap">
     <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> 
    - <operation name="Add">
         <soap:operation soapAction="http://soapinterop.org/Add" style="rpc" /> 
       - <input>
        <soap:body use="encoded" namespace="http://soapinterop.org" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> 
         </input>
       - <output>
          <soap:body use="encoded" namespace="http://soapinterop.org" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> 
        </output>
      </operation>
    </binding>
  - <service name="Test">
    - <port name="TestSoap" binding="tns:TestSoap">
        <soap:address location="http://mssoapinterop.org/asmx/Rpc.asmx" /> 
      </port>
    </service>
  </definitions>

package oracle.j2ee.ws.client.impl;

import java.util.*;
import java.io.*;
import java.net.*;
import oracle.j2ee.ws.client.*;
import oracle.j2ee.ws.client.wsdl.*;
import org.apache.soap.util.xml.QName;
import org.apache.soap.util.xml.XMLJavaMappingRegistry;

public class Client {

  public static void main(String[] args) throws Exception {

    String szWsdlUrl = "http://mssoapinterop.org/asmx/Rpc.asmx?WSDL";

    URL urlWsdl = new URL(szWsdlUrl);
    System.err.println("Wsdl url = " + urlWsdl);

    WebServiceProxyFactory wsfact= new WebServiceProxyFactory();

    //
    // Set some initial parameters
    //
    Hashtable ht = new Hashtable();
    ht.put("http.proxyHost", "www-proxy.us.oracle.com");
    ht.put("http.proxyPort", "80");
    wsfact.setProperties(ht);

    //
    // Create an instance of the proxy
    //
    WebServiceProxy wsp = wsfact.createWebServiceProxy(urlWsdl);

    //
    // Optional: Wsdl Introspection
    //
    PortType pt = wsp.getPortType();
    List opList = pt.getOperations();
    for (int i = 0; i < opList.size(); i++) {

      Operation op = (Operation) opList.get(i);
      String szOpName = op.getName();
      String szInput  = op.getInput().getName();
      String szOutput = op.getOutput().getName();

      System.err.println("operation["+i+"] = [" + szOpName +
                         "," + szInput + "," + szOutput + "]");

      //
      // show input message parts
      //
      Message msgIn = op.getInput().getMessage();
      Map     mapParts = msgIn.getParts();
      Collection colParts   = mapParts.values();
      Iterator itParts = colParts.iterator();

      WebServiceMethod wsm = wsp.getMethod(szOpName);
      String szInEncStyle = wsm.getInputEncodingStyle();
      XMLJavaMappingRegistry xmr = wsp.getXMLMappingRegistry();

      while (itParts.hasNext()) {
        Part part = (Part) itParts.next();
        String szPartName = part.getName();
        QName qname       = part.getTypeName();
        String szJavaType = xmr.queryJavaType(qname,
szInEncStyle).getName();
        System.err.println("part name = " + szPartName +
                           ", type = " + qname +
                           ", java type = " + szJavaType);
      }
    }

    //
    // invoke operation/method Add(2,10)
    //
    String[] inMsgPartNames = new String[2];
    inMsgPartNames[0] = "a";
    inMsgPartNames[1] = "b";
    Object[] inMsgPartValues = new Object[2];
    inMsgPartValues[0] = new Integer(2);
    inMsgPartValues[1] = new Integer(10);

    WebServiceMethod wsm = wsp.getMethod("Add");
    Object objRet = wsm.invoke(inMsgPartNames,
                               inMsgPartValues);

    System.err.println("Calling  method Add(" +inMsgPartValues[0] + ","
+
                       inMsgPartValues[1] +")" );
    System.err.println("return = " + objRet);
  }
}

The output of the client execution is as follows:

Wsdl url = http://mssoapinterop.org/asmx/Rpc.asmx?WSDL
operation[0] = [Add,,]
part name = b, type = http://www.w3.org/2001/XMLSchema:int, java type = int
part name = a, type = http://www.w3.org/2001/XMLSchema:int, java type = int
Calling  method Add(2,10)
return = 12

11.2.3 Known Limitations

The following information describes the known limitations of the dynamic invocation API:

  • Supports invoking operations defined in the WSDL document defined by the W3C recommendation XML schema version whose namespace is: http://www.w3.org/2001/XMLSchema

  • Does not support WSDL documents that use the <import> tag to include other WSDL documents.

  • Does not support HTTP, MIME, or any other custom bindings.