Oracle® Application Server Web Services Developer's Guide
10g Release 2 (10.1.2) Part No. B14027-01 |
|
Previous |
Next |
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:
SOAP-based Web Services described using WSDL, see Consuming SOAP-Based Web Services Using WSDL.
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.
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
An .ear file (which is a JAR archive containing the J2EE application that can be deployed in OC4J) is located within the destination directory (<destDir>
) you specified in the command line. The .ear file contains the generated EJB, JAR, and XML files for your application, where the application.xml
file located in the /deploy/META-INF
directory for UNIX or the \deploy\META-INF
directory for Windows serves as the EAR manifest file.
An archive JAR file containing your EJB application class files is located within the /deploy
directory for UNIX or the \deploy
directory for Windows. The JAR file includes all EJB application class files and the deployment descriptor file.
A standard J2EE EJB deployment descriptor (ejb-jar.xml
) for the generated bean in the module is located within the /classes/META-INF
directory for UNIX or the \classes\META-INF
directory for Windows. The XML deployment descriptor describes the application components and provides additional information to enable the container to manage the application.
The source code of a set of Java classes that you can use in your Java applications is located within the /src
directory for UNIX or the \src
directory for Windows. The generated JavaBean and EJB Java source code is contained in subdirectories according to their Java package name. An EJB client stub is also generated.
The /classes
directory for UNIX or the \classes
directory for Windows contains the compiled generated classes and additional XML resources used by the generated code.
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 |
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.
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 thewsdl2ejb 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
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
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
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.
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.
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
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.