How-To Use MTOM to Exchange Binary Data Using Web Services

First Created: August-2006
Author: Tugdual Grall

 

 

Introduction

MTOM ( Message Transmission and Optimization Mechanism) together with XOP ( XML Binary Optimized Packaging) defines how an XML binary data such as xs:base64Binary can be optimally transmitted over the wire. If you are using a top-down approach (not shown here), the <element name="image" type="base64Binary"/> is mapped to byte[]. In the other way, when you do a bottom up generation of service the byte[] parameters will be mapped in the WSDL as <element name="image" type="base64Binary"/>.

MTOM does not add any particular extension to the WSDL (this is not the case with other Web Services attachments solutions such as SOAP with Attachment (SwA and swaRef) or Direct Internet Message Encapsulation (DIME) ). When MTOM is enabled, on the wire, the base64Binary content will be automatically put in a MIME attachment part in binary form.

OracleAS 10 g R3 (10.1.3.1.0) introduces support of MTOM to exchange binary content. This sample application presents how to use the new MTOM support in OracleAS 10g Web Services.

What are the Prerequisites?

What Should You Know?

  • Some familiarity with the standard J2EE deployment model.
  • Familiarity with the bottom-up development model of OracleAS Web Services.

What are the Software Requirements?

  • OracleAS 10.1.3.1 is installed, available from OTN
  • Sun's JDK 1.4.2_03 or above, available here

What are the Notations?

The following conventions are used throughout the document:
  • %ORACLE_HOME% - The directory you installed OC4J or Oracle Application Server
  • %JAVA_HOME% - The directory where your JDK is installed

How to Build the Application?

Let's take a closer look at the steps involved in creating the web service application from an existing Java class.  These steps have already been performed for this sample but are provided for illustrative purposes.

Exchanging file using a Web Service

In order to exchange files with a web service we will:

1. Create a service interface ( FileExchangeService ) . The service interface represents the functionality and operations we wish to provide to client applications:

public interface FileExchangeService extends Remote {
    public String put(String fileName,byte[] fileContent) throws
            RemoteException, Exception;
    public byte[] get(String fileName) throws
            RemoteException, Exception;
}

You will note that this service interface extends the java.rmi.Remote interface and that all methods throw (at least) the java.rmi.RemoteException exception, a requirement of the JAX-RPC specification.

2.  Create a service implementation.  The implementation class (FileExchangeServiceImpl) implements the service interface (FileExchangeService).

 

As you can see  from the interface, as developer you won't need to manipulate any special Java class to get the content since it will be exchange using simple byte arrays. ( byte[]). In this sample application, you can find an helper class to manipulate the I/O. The  how.to.ws.mtom.util.IOManager contains 2 methods:

  • byte[] getBytesFromFile(String fileLocation) : this method takes a file location (absolute path) and return its content as byte[]
  • File putBytesInFile(String fileLocation, byte[] fileContent) : this method take a file location and the content of a file as byte[] and save it in a file of the file system; and returns the File object.
 
The javadocs for the components above can be found here.

Given the bank implementation and support classes, the service interface, and the service implementation we can proceed with the generation and deployment of a web service.

Enabling MTOM during the generation of the service and the proxy

Assembling the service

OracleAS 10g R3 (10.1.3.1) introduces new parameter to the OracleAS Web Services Ant tasks to enable MTOM when a service is assemble or a proxy is generated. To enable MTOM when generating a proxy or assembling a service (top-down or bottom-up) you just need to add the mtomsupport="true" to the code.  In this how to, the service is generated from the Java class using the following Ant target:

       <oracle:assemble appName="${app.name}"
            serviceName="${app.name}"
            input="${bld.webservice.dir}"
            classpath="${bld.webservice.dir}"
            output="${out.dir}"
            ear="${lib.dir}/${ear.name}.ear"
            >
            <oracle:porttype  interfaceName="how.to.ws.mtom.service.FileExchangeService" className="
how.to.ws.mtom.service .FileExchangeServiceImpl" >
                < oracle:port soapVersion="1.2" uri="mtom-demo" name="mtom-demo-soap12"  mtomsupport="true" />
                < oracle:port soapVersion="1.1" uri="mtom-demo" name="mtom-demo-soap11"  />
            </oracle:porttype>
       </oracle:assemble>
    

In this example, you are exposing the service using two ports:
  • a SOAP 1.2 port named mtom-demo-soap12 where MTOM is enabled
  • a SOAP 1.1 port named mtom-demo-soap11 where MTOM is not enabled (default). Note that even if MTOM is a specification of SOAP 1.2, OracleAS Web Services allows you to enabled MTOM on SOAP 1.2 port.

Generating the client

Using the same approach you can generate a Web Services proxy to consume this service, using the following Ant target:

        <oracle:genProxy wsdl="http://${oracleas.host}:${oracleas.http.port}/${app.name}/
mtom-demo ?wsdl"
            output="${src.cli.dir}"
            packageName="how.to.ws.mtom.client.proxy"
            >
            < oracle:port name="
mtom-demo -soap12"  mtomsupport="true" />
            < oracle:port name="
mtom-demo -soap11"  />
            <classpath>
                <pathelement path="${bld.cli.dir}"/>
                <pathelement location="${OC4J_HOME}/webservices/lib/wsa.jar"/>
            </classpath>
        </oracle:genProxy>

In this case, you are creating a Web Service proxy that can invoke the two ports of the service. In the example, the SOAP 1.2 port named mtom-demo-soap12 is MTOM enabled. In this case all the requests will be send out as MTOM encoded when relevant content exist. (base64Binary).

It is also possible to programmatically override the MTOM support in a Web Service stub using the following code.
(Note: we do not show this feature in the how to, but it is indicated for information purpose.)
       ((OracleStub)myPort.getPort())._setProperty(ClientConstants.MTOM_SUPPORT, true) ;


How to Run the Sample

In this sample we will create a banking web service that wraps and delegates its functionality to an underlying bank object.

Examining the How-To Distribution

The How-To zip file should contain the following:

How to distribution

Setting Up the Application

Please check to make sure that the following properties are configured correctly in the ant-oracle.properties file located in the root of the sample's distribution (NOTE:  Some of these properties will default to the values of corresponding environment variables as noted below.  If you have these variables setup in your environment you may not have to alter the values in the file).  If necessary, modify these variable to the proper values for you environment:
  • oracle.home - the root directory of oracle installation.  Defaults to ORACLE_HOME environment variable.
  • java.home -  the root directory of JDK installation.  Defaults to JAVA_HOME environment variable.
  • oracleas.host - the hostname of the platform on which the OC4J instance is running.  Defaults to localhost.
  • oracleas.http.port - the port on which the OC4J HTTP listener is listening.  Defaults to 8888.
  • oracleas.admin.port  - the port on which the OC4J administration processor is listening.  Defaults to 23791.
  • oracleas.admin.user - the name of the OC4J administrator.  Defaults to " oc4jadmin".
  • oracleas.admin.password - the password for the OC4J administrator.  Defaults to " welcome".
  • oracleas.binding.module - the name of the HTTP web site to which the deployed application is bound.  Defaults to " default-web-site".
In addition, please make sure that the ant command associated with the OC4J ant distribution is in your execution path ( %ORACLE_HOME%/ant/bin).

Configuring the Environment for a Managed OracleAS Instance

If you are running a managed version of the Oracle Application Server 10 g, you are using OPMN, you must change the following values to match your configuration:
  • oracleas.http.port - the port on which the Oracle HTTP Server (OHS) is listening.
  • oracleas.admin.port  - The OPMN request port, as specified in opmn.xml, the default value is 6003.  You can also check the OPMN request port using the following command: %ORACLE_HOME%/opmn/bin/opmnctl status -port
  • oracleas.admin.user - the name of the OC4J administrator.  Defaults to " oc4jadmin".
  • oracleas.deployer.uri - the URI to use to do the different administration operation (deployment, undeployment). The file contains different URI depending of the topology of your application: stand alone OC4J, Managed Single Node or Managed Cluster. You just need to un-comment the URI that matches your topology.
  • oracleas.oc4j.instance - This is the managed OC4J instance where the application will be deployed or undeployed.

In addition, please make sure that the ant command associated with the OC4J ant distribution is in your execution path ( %ORACLE_HOME%/ant/bin).

Running an OC4J Instance

Start an OracleAS 10 g (10.1.3.1) instance as follows:
  • Stand Alone Installation: %ORACLE_HOME%/bin/oc4j start
    Note that the oc4j command expects the JAVA_HOME environment variable to point to a full JDK installation.

  • OracleAS Managed Installation: %ORACLE_HOME%/opmn/bin/opmnctl startall

Generating, Compiling and Deploying the Application

To generate, compile, and deploy the components of this application simply type the following command from a command prompt in the root directory of the sample:
  • ant

Executing the default "all" target of the supplied build.xml file performs the following steps:

  • Compiles all the web service source files (service interfaces and implementations) located in src/service subdirectories.
  • Generates the WSDL file and associated artifacts (JAX-RPC mapping file, etc.).  The generation is performed utilizing the assemble ant task:
       <oracle:assemble appName="${app.name}"
            serviceName="${app.name}"
            input="${bld.webservice.dir}"
            classpath="${bld.webservice.dir}"
            output="${out.dir}"
            ear="${lib.dir}/${ear.name}.ear"
            >
            <oracle:porttype  interfaceName="how.to.ws.mtom.service.FileExchangeService" className="
how.to.ws.mtom.service. .FileExchangeServiceImpl" >
                <oracle:port soapVersion="1.1" uri="mtom-demo" name="mtom-demo-soap11"  />
                <oracle:port soapVersion="1.2" uri="mtom-demo" name="mtom-demo-soap12"  mtomsupport="true" />
            </oracle:porttype>
       </oracle:assemble>
    


        The output of this task is a J2EE application module (ear file) that contains the various files required for the deployment of the File Exchange service.
  • Deploys the application module.  The .ear file generated in the previous step is now deployed to the server using the ant deploy ant task:
            <oracle:deploy moduleType="ear"
            host="${oc4j.host}"
            port="${oc4j.admin.port}"
            userId="${oc4j.admin.user}"
            password="${oc4j.admin.password}"
            file="${lib.dir}/${app.name}.ear"
            deploymentName="${app.name}"
            logFile="deploy-ear.log"/>

          In addition, in order for the service to be accessible via the Oracle Application Server's web tier it must be bound to an web site:
       
        <oracle:bindWebApp deploymentName="${app.name}"
            host="${oc4j.host}"
            port="${oc4j.admin.port}"
            userId="${oc4j.admin.user}"
            password="${oc4j.admin.password}"
            webModule="${web.name}"
            webSiteName="${oc4j.binding.module}"
            contextRoot="/${app.name}"/>
  • Creates the client proxy source files.  Once the service is deployed and available the client proxy can be generated from the available WSDL file (you can actually view the generated WSDL file of the service by pointing a browser to the location http://<OC4J host>:<OC4J http port>/ mtom-demo / mtom-demo ?wsdl).   The genProxy ant task is utilized for this purpose:
        <oracle:genProxy wsdl="http://${oracleas.host}:${oracleas.http.port}/${app.name}/ mtom-demo ?wsdl"
            output="${src.cli.dir}"
            packageName="how.to.ws.mtom.client.proxy"
            >
            < oracle:port name="
mtom-demo -soap12"  mtomsupport="true" />
            < oracle:port name="
mtom-demo -soap11"  />
            <classpath>
                <pathelement path="${bld.cli.dir}"/>
                <pathelement location="${OC4J_HOME}/webservices/lib/wsa.jar"/>
            </classpath>
        </oracle:genProxy>

  • Compiles the client application and associated proxy files.  The proxy files generated in the previous step and the client application utilizing the proxy for remote communication are compiled and placed in the build/mtom-demo/mtom-demo-client directory.

Running the Application

Now that the web service is deployed and the client is generated and compiled we are ready to execute the application.  From a command prompt in the root directory of the sample simply type:

  • ant run

This command executes the client application that performs the following operations and message exchanges (the message exchange figures below were captured by the JDeveloper 10g Http Analyzer and are provided to illustrate the underlying message exchanges performed during the execution of the remote service invocations):

  • Send a file using the put operation:

Send file using the put operation

You can notice the following:
  • the content type is multipart/related and the type is application/xop+xml
  • the file content is sent as binary content as part of the MIME message, and reference using XOP in the input parameter of the operation
      <ns0:fileContent>
       <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:337b22511ce545dc9182f6c6ab9f1ffe"/>
     </ns0:fileContent>
  • Receive file from the server using the get operation
Receive file from the server

The response like the request in the previous call use XOP to encode the message.

The generated output from the "run" target should be as follows:

run:
     [java] Calling service using:
     [java]     URL:http://127.0.0.1:8888/how-to-ws-mtom/mtom-demo
     [java]     File:./etc/bmw-oracle-racing.jpg
     [java] Put file done : File Saved: /tmp/file-uploaded-server.jpg
     [java] ----- get the file -----
     [java] File received and saves : /tmp/file-downloaded-client.jpg
     [java]  --- End ---

BUILD SUCCESSFUL

Summary

This how-to provided a detailed look at how to exchange binary content using MTOM encoding.
  • Creating the service interface and implementation
  • Generating the  the required service artifacts (most importantly, the WSDL file describing the service) using the correct parameters to force MTOM encoding
  • Deploying the service to the Oracle Application Server.
  • Generating the client proxy code based on the service WSDL file.
  • Writing a client application the leverages the client proxies to interact with the deployed service.
Left Curve
Popular Downloads
Right Curve
Untitled Document