How to pass SOAP Attachments with JAX-RPC Web Service

Date: 30-Sept-2003

After reading this how-to document you should be able to:

  • Understand what is a JAX-RPC Web Service
  • Write a JAX-RPC Service that receives and sends SOAP attachments.

Introduction

This document demonstrates how to send SOAP attachments with Document literal JAX-RPC Web Service.

Overview of JAX-RPC Web Services

The Java API for XML-based remote procedure calls (JAX-RPC) provides standard way of building portable and interoperable SOAP based Web Services. It simplifies the process of building Web services that incorporate XML-based RPC. In JAX-RPC, a remote procedure call is represented by an XML-based protocol such as SOAP. The SOAP specification defines envelope structure, encoding rules, and a convention for representing remote procedure calls and responses. These calls and responses are transmitted as SOAP messages over HTTP. Read more on JAX-RPC Web Services here.

The SOAP Attachment

A SOAP message package with attachments is constructed using the MIME multipart/related type. The primary SOAP 1.1 message is carried in the root body part of the multipart/related structure. The primary SOAP 1.1 message may reference additional entities (termed as attachment or MIME parts) in the message package. These entities may contain data in formats other than XML.

Thus the root part of message contains the original message(in the SOAP body) and any attachment goes as referenced MIME parts. The referenced MIME parts must contain either a Content-ID MIME header or a Content-Location MIME header to uniquely identify it. Following is a sample SOAP message with attachment.

   MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
start="<http://img5422a.xml.oracle.com>"
--MIME_boundary--
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <img5422a.xml.img.oracle.com>

<?xml version='1.0' ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
..
<theSignedForm href="cid:img5422a.xml.oracle.com"/>
..
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

--MIME_boundary--
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-ID: <img5422a.xml.oracle.com> --MIME_boundary--

The attached entity is referenced from the SOAP body as a resource referenced by a URI given as the value of an href attribute. While processing the message, all the URI references are converted to absolute references and then absolute references are resolved.

The JAX-RPC runtime maps the MIME types to Java types as follows:

image gif/jpeg type          ==> java.awt.image
text/plain type              ==> java.lang.String
text/xml or application/xml  ==>javax.xml.transform.Source 

Java class javax.activation.DataHandler can be used for content with any MIME type.

Section 7 of the JAX-RPC specification gives more details on SOAP attachments with JAX-RPC.

Software Requirements

  • Oracle Application Server Containers for J2EE 10g or later. You can download the OC4J from Oracle Technology Network. 

  • JDK1.4.x or above This can be downloaded here .

  • Apache Ant v1.5 or later.

  • How To Example Source code zip

Description

The SOAP Attachment

The JAX-RPC services provide Handler mechanism to modify SOAP request and response messages at client and service side. This handler class mechanism can be effectively used to send and receive SOAP attachment from a JAX-RPC Web Service.

The handler class provides access to SOAP message that is being transferred between the client and the service. javax.xml.soap.SOAPMessage class can be used inside the handler to manipulate the SOAP message. A SOAPMessage object consists of a SOAPPart object that contains the actual SOAP XML document (or the envelope) sent in SOAP request. The SOAPEnvelope object can be used to access SOAP body and header.

The javax.xml.soap.AttachmentPart object represents each attachment in the SOAP message. A SOAPMessage object may contain zero, one, or many AttachmentPart objects. The SOAPMessage class provides various methods to manipulate attachments. Some important methods are as follows:

  • createAttachmentPart(): create an empty AttachmentPart object .
  • createAttachmentPart(javax.activation.DataHandler datahandler): Creates an AttachmentPart object and populates it using the given DataHandler object.
  • getAttachments(): Retrieves all the AttachmentPart objects in the SOAPMessage object.
  • addAttachmentPart(AttachmentPart attachmentpart) : Adds the given AttachmentPart object to this SOAPMessage object.
  • countAttachments() : Gets a count of the number of attachments in this message.

The How-To Example

The example with this how to explains how to send and receive attachments with JAX-RPC Web Services.

In the example we start with a WSDL and write the implementation classes after the WSDL has been processed and the necessary service classes and interfaces are generated. Once the generation process is complete the Web Service implementation class can be compiled and included into the Web Service archive (EAR file) to be deployed to OC4J

The client invokes a simple method on Web Service. The SOAP request is intercepted and modified by the client handler class to attach the image file to SOAP message being sent to the Web Service. The Web Service has a handler class tied to it that intercepts the request, reads the attachment sent by the client and sends the SOAP request to the Web Service for further processing. It also intercepts the response from the Web Service and attaches a plain text message to the response. This response message is intercepted by the client handler to read the text attachment sent by the Web Service and then the SOAP response message is received by the client.

The how to uses Oracle's Web Services Assembler tool to generate the service artifacts. The Web Service assembler tool takes as input, an XML config file that describes the service. It uses the definitions in the WSDL file to generate service artifacts like types, interfaces, tie and stub classes, compiles all the classes and produces an Enterprise Archive file that can be deployed to an application server to run the Web Service.

Listing 1 shows the WSDL file that will be used to the generate service artifacts.

<?xml version="1.0" encoding="UTF-8"?>


<definitions name="Attachments" targetNamespace="urn:Foo" xmlns:tns="urn:Foo" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<types/>
<message name="Attachments_sayHello">
<part name="String_1" type="xsd:string"/> </message>
<message name="Attachments_sayHelloResponse">
<part name="result" type="xsd:string"/> </message>
<portType name="AttachmentsIF">
<operation name="sayHello" parameterOrder="String_1">
<input message="tns:Attachments_sayHello"/>
<output message="tns:Attachments_sayHelloResponse"/></operation> </portType>
<binding name="AttachmentsBinding" type="tns:AttachmentsIF">
<operation name="sayHello">
<input>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:Foo"/> </input>
<output>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:Foo"/> </output>
<soap:operation soapAction=""/></operation>
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/> </binding>
<service name="Attachments">
<port name="AttachmentsIFPort" binding="tns:AttachmentsBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>

Listing 1

Listing 2 shows the definition of ClientAttachmentHandler.java class. The handler class implements the javax.xml.rpc.Handler interface. The handleRequest method attaches an image file to the SOAP request and the handleResponse method retrieves the text attachment received in the Web Service response. View complete code here.

public class ClientAttachmentHandler implements Handler
{ .. .. /*
* This method is implementation of handleRequest method in Handler
* interface. It extracts the SOAP message from the request and attaches
* image to it.
*/
Public boolean handleRequest(MessageContext messageContext)
{
//-- If there was an image URL specified, // create an attachment and add it to the message
if (imageURL != null) {
try {
//get SOAPMessageContext
SOAPMessageContext soapContext = (SOAPMessageContext)messageContext; // get SOAP message
SOAPMessage msg = soapContext.getMessage(); // create an attachment using DataHandler class
AttachmentPart att = msg.createAttachmentPart( new DataHandler(new URL(imageURL))); // add attachment to message
msg.addAttachmentPart(att);
} catch (MalformedURLException e) {
System.out.println("Bad URL: " + imageURL);
}
} else {
System.out.println("No attachment URL specified, not"+ "attaching image."); } return true;
} /*
* This method is implementation of handleResponse method in Handler
* interface. It intercepts the SOAP response received from the Web Service
* and displays the contents of text file attached with the message.
*/
Public Boolean handleResponse(MessageContext messageContext)
{ //get SOAPMessageContext
SOAPMessageContext soapContext = (SOAPMessageContext)messageContext;
// get SOAP message
SOAPMessage MSG = soapContext.getMessage(); //-- Get and display the first attachment which should // be a plain text document // get iterator of attachments
Iterator attIter = msg.getAttachments();
if (attIter.hasNext()) {
try {
// get next attachment
AttachmentPart att = (AttachmentPart)attIter.next();
// get the content of attachment
String textDoc = (String)att.getContent();
System.out.println("Response Attachment:");
System.out.println("Received attachment of type "+att.getContentType()+ " from Web Service");
System.out.println("Attachment Content: "+textDoc);
} catch (SOAPException se) {
System.out.println("Error getting attachment:");
se.printStackTrace();
}
} else {
System.out.println("No Attachment found in the response.");
} Return true;
} }

Listing 2

The client handler class is configured in stubs-config.xml file that is used by WSA tool to generate Stub classes to access Web Service. Listing 3 shows the part of stub-config.xml file that defines the client handler class and passes image file name as parameter.

...
...
 <wsdl-port>
<port-name>AttachmentsIFPort</port-name>
<handler>
<handler-name>ServiceAttachmentHandler</handler-name>
<handler-class>oracle.demo.attachments.ClientAttachmentHandler</handler-class> <init-param>
<param-name>ImageURL</param-name>
<param-value>file:data/JohnDoe.jpg</param-value>
</init-param>
</handler>
</wsdl-port> ... ...

Listing 3

Listing 4shows the definition of ServiceAttachmentHandler.java class. The handler class implements javax.xml.rpc.handler.Handler interface. The handleRequest method retrieves the image attachment from the SOAP request coming from the client and the handleResponse method attaches a text message to the Web Service response before sending it to the client. View complete code here.

The Web Service handler class is specified in the service-config.xml file that is used by the WSA tool to generate service artifacts.

Public class ServiceAttachmentHandler implements Handler
{ .. .. /*
* This method is implementation of handleRequest method in Handler
* interface. It extracts the SOAP message and checks if the attachment
* is received correctly.
*/
Public Boolean handleRequest(MessageContext messageContext){ //get SOAPMessageContext
SOAPMessageContext smc = (SOAPMessageContext)messageContext; // get SOAP message
SOAPMessage MSG = smc.getMessage(); // get iterator of attachments
Iterator attIter = msg.getAttachments(); // iterate through attachments
if (attIter.hasNext()) {
while (attIter.hasNext()) {
// get the next attachment
AttachmentPart att = (AttachmentPart)attIter.next(); // check if attachment is received
if (document != null)
document += "\n";
document = "The Web Service received attachment of "+ "type: " + att.getContentType();
System.out.println(document);
} } else {
document = "Did not receive any attachments.";
}

Return true;
}
/*
* This method is implementation of handleResponse method in Handler
* interface. It intercepts the SOAP response received from the Web Service
* an
*/
public Boolean handleResponse(MessageContext messageContext)
{
//get SOAPMessageContext
SOAPMessageContext smc = (SOAPMessageContext)messageContext;
// get SOAP message
SOAPMessage MSG = smc.getMessage();

// create an attachment of plain text type
AttachmentPart att = msg.createAttachmentPart(document,"text/plain");
// attach it to the message
msg.addAttachmentPart(att); return true;
} }

Listing 4

Preparing and Running the Example

Extract the soapattachment.zip file. This will create soapattachment directory containing documentation and source code of the how-to.

In the following steps <OC4J> refers to directory where OC4J is installed.

Step a:

Start OC4J from <OC4J>/j2ee/home directory on a command prompt as follows:

java -jar oc4j.jar

Step b:

Navigate to soapattachment, the sample home directory on new command window . Include ANT_HOME/bin in the PATH environment variable. Set the following properties required by the ant build script

  • Set the ORACLE_HOME environment variable to your <OC4J> root directory.
    Example:

    Windows : set ORACLE_HOME=c:\oc4j10g
    Unix    : ORACLE_HOME=/home/oc4j10g 
              export ORACLE_HOME
    
  • Set the J2EE_HOME environment variable to your <OC4J>/j2ee/home directory.
    Example:

    Windows : set J2EE_HOME=c:\oc4j10g\j2ee\home
    UNIX    : J2EE_HOME=/home/oc4j10g/j2ee/home 
    
              export J2EE_HOME
  • Set the JAVA_HOME environment variable to your Java installation directory.
    Example:

    Windows : set JAVA_HOME=c:\j2sdk1.4
    UNIX    : JAVA_HOME=/home/j2sdk1.4
              export JAVA_HOME
Quick Start

Once you have the server configured and running, execute the following command from the prompt in Step b:

>ant

The service artifacts and implementation class will be compiled and placed into a WAR which is then placed into an EAR.

The EAR will be deployed to OC4J. Next the stubs and client will be compiled. Finally the service will be invoked by the client and you should see the output on the stdout of the client.

Step by Step
Step 1:

Generate the service artifacts. Execute the following command:

This step will generate the service artifacts which include interfaces and Tie classes. Examine the service-config.xml file. Notice that the implementation-class-name element is filled in with the implementation class provided by the demo. This class is not compiled yet so WSA will generate the artifacts and use the class name as a place holder. Once the artifacts are generated, the implementation class will have to be compiled and WSA will have to be run again with the same config file.

To generate the service artifacts type: ant gen-service

The source code for the service-artifacts will be placed in the soapattachment/build/src/service directory using the package name oracle.demo.attachments.service. Examine the soapattachment/config/type-mapping.xml file. This file is used to instruct WSA how to map types to package name. A namespace URI is mapped to a specific package name. Notice that this example maps its types to the package oracle.demo.attachments.types. So for service artifacts the types are generated in soapattachment/src/oracle/demo/attachments/types.

Step 2:

Generate the stubs (client artifacts)

This step will generate the stubs for the service. A client application uses a stub to invoke operations on a remote service. Examine the file soapattachment/config/client-config.xml. This is the configuration file that the WebServices Assembler (WSA) tool uses to generate the stubs.

To generate the stubs type: ant gen-stubs

The source for the stubs will be placed in soapattachment/build/src/client.

Step 3:

Update the implementation.

This step will compile the implementation classes and regenerate the EAR file that will now contain both service artifacts and the implementation class. Examine the file AttachmentsImpl.java under soapattachment/src/service/oracle/demo/attachments/service. Notice that the class implements AttachmentsIF which is an interface to the Web Service. Before the first step there were no generated files so compiling this class would have failed. Now that you have already ran the gen-service task you are ready to compile the class and update the EAR.

To update the implementation type: ant update-impl

Step 4:

Deploy the Service

The service is now ready to be deployed. Examine the attachments.ear in the soapattachment/dist directory using WinZip or any zip file browser. It should contain a WAR file named attachments-web.war. This WAR file contains all the service artifacts, implementation classes, as well as the web deployment descriptor (web.xml) .

To deploy this ear to a running instance of oc4j type: ant deploy-demo

After this task is complete you can check your Web Service by typing in the following URL into a Web browser: http://localhost:8888/attachments/attachments

You should be able to invoke some of the methods on this service from the Web browser. Currently, invoking services using the browser is restricted to simple types.

Step 5:

Run the demo.

You are now ready to run the client. Examine the file AttachmentsClient.java in soapattachment/src/client/oracle/demo/attachments directory. Notice that this class uses the stubs to set an endpoint address and to invoke methods on the remote service.

To run the client type: ant run-demo

You should see some sample output on client and server output screens.

To undeploy the Web Service execute the command : ant teardown-demo

Resources

Summary

This how-to document explained how write a JAX-RPC Web Service that sends and receives SOAP messages with attachments.


E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy