Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Handling attachments in SOAP

Transferring foreign objects with Apache SOAP 2.2

Joshy Joseph, Software Engineer, IBM Software Group
author
Joshy is a Software Engineer working on the IBM WebSphere Catalog Manager product. His primary programming interests are working with emerging technologies like Web services, the Semantic Web and GRID computing, and using programming models based on UML, AOP, and XP. You can contact him at joshy@us.ibm.com.

Summary:  Web services will require the ability to send more than just text messages between services in a process. Often it will involve complex data types such as language structures, multimedia files, and even other embedded messages. This article takes a look at how the SOAP with Attachments specification can be used to send such information. It provides a programming example of how to handle custom data type mapping and attachments in your SOAP services.

Date:  01 Feb 2002
Level:  Introductory
Also available in:   Korean  Japanese

Activity:  72979 views
Comments:  

Web services has been well received by the industry to solve the complex problems and distributed processes across multiple platforms and systems. Web services achieves this through the use of standard-based protocols like SOAP, WSDL, and UDDI, and through the developments in standards groups. These standards are still evolving and have yet to solidify solutions for all the areas needed. Within these grey areas, you still need to figure out how to transfer custom data types, such as arrays of data structures, between services, as well as how to handle attachments to transfer binary and other complex data files.

In this article, I will explain the current protocol and tools support for handling the custom data encoding and attachments in Web services. I will also present a simple case study that illustrates how you can use the existing tools and standards to create a file upload and download Web services. Before I move on to those topics, let's review how SOAP and WSDL handles data encoding while they work.

SOAP and data types

A SOAP message contains an XML document definition that can be used to exchange structured and typed information between peers in a decentralized, distributed environment. SOAP messages are normally encoded as defined on Section 5 of the SOAP specification. However, there is no restriction on using other encoding schemes such as in XML Schema or RDF as long as it can be understood by the application. For example, the literal encoding method specified in WSDL uses XML Schema encoding. Section 5 of the SOAP specification was created to augment the drawbacks of earlier versions of XML Schema's type system, specifically features needed by SOAP such as arrays and other complex type system. However, a big debate has risen in the industry and amongst the standards working groups on why there needs to be an alternative special encoding scheme when XML Schema has since evolved to support most of the features needed for SOAP.

SOAP message exchange can be modeled as Remote Procedure Calls (RPCs), where there is a well-defined way of message exchange based on well-defined method call signatures (that is, method name and parameters) and its return values/exceptions. SOAP messages can also be viewed as Documents exchanged where the semantics of the data exchanged are known only at the application level (sender or receiver).


WSDL (Web services Definition Language)

WSDL describes a set of SOAP messages and how these messages are exchanged between SOAP processors. This enables companies to describe their services and enables the client to consume the services in a standard way without knowing much on the lower level exchange protocol (binding) like SOAP. This high level abstraction on the service limits the human interaction and enables the automatic generation of proxies for Web services. (These proxies can be static or dynamic). WSDL allows the description of both document-oriented and RPC-oriented messages.

There are two kinds of message encoding available in WSDL: literal and SOAP-encoding. Literal encoding means that the messages will be constructed according to XML Schema. SOAP encoding uses the rules specified by Section 5 of the SOAP specification. Another important concept in WSDL is the message transfer format, where messages can be transferred as Document or RPC parameters. Document transfer format means that the message part is in the body of the message, while RPC means that message parts are just parameters of the call with specific signatures, wrapped in XML elements. These transfer formats confirm to the SOAP semantic of SOAP message exchange.

With these concepts in mind, I can discuss some of the interesting aspects of the SOAP and Web services including the custom type mapping and support for attachments.


Type mapping

The type mappings in SOAP are used to determine how to transfer native language objects by marshalling or reformatting them into XML so that they can be transmitted in the SOAP messages. These type mappings are stored in a mapping registry on the client and server. Most of the toolkits have some predefined translators for primitive types, collections, and sometimes even MIME attachments. In order to transmit custom class objects, you will need to create new serializers and deserializers and to register new type mappings in both client and server. Such type mappings are based on the encodingStyle feature of SOAP.

Each type mapping may normally contain the following information:

  • encodingStyle - a URI describing the encoding style to be used; for example, http://schemas.xmlsoap.org/soap/encoding/
  • Qname for the XML element - a URI given for that specific type definition for example, http://www.w3.org/2001/XMLSchema:int
  • Native language class to be encoded from/decoded to
  • Name of the Native language class to act as the serializer
  • Name of the Native language class to act as the deserializer

Most of the existing SOAP toolkits support complex type-mapping based on the SOAP encoding scheme and XML Schema.

Apache SOAP 2.2's custom type mapping support

In order to handle custom type encoding, the new type mappings must be defined both in the server and the client. There are two ways to register type mapping on the server side using the Apache SOAP 2.2 toolkit:

  • Using deployment descriptors.
  • Overriding the default mapping registry with the new type mappings. The new registry must be a subclass of the SOAPMappingRegistry.

There are also two ways to register type mapping on the client side in the Apache toolkit:

  • Creating an instance of SOAPMappingRegistry and adding new types using the mapTypes() method.
  • Creating a subclass of SOAPMappingRegistry with all pre-registered mapping.

In order to help developers, Apache SOAP comes with a Java Bean Serializer/Deserializer class that enables all classes built on JavaBeans technology standards to be serialized or deserialized without writing any custom code. This JavaBeans Serializer/Deserializer class, org.apache.soap.encoding.soapenc.BeanSerializer can be used in the type mapping registry as serializers and deserializers.

Developers can also try creating custom serializers and deserializes created by implementing org.apache.soap.util.xml.Serializer and org.apache.soap.util.xml.Deserializer respectively to do custom handling.

I will explain how this custom encoding can be done in the following example.


SOAP protocol and attachments

Often, you may need to transmit a SOAP message together with attachments of various sorts like images, drawings, xml docs, etc. Such data are often in a particular binary format. The SOAP with Attachments specification details on usage on 'MIME multipart/related' media type and URI schemes for referencing the MIME parts. The support for SOAP attachments is not available in all the Web service toolkits. Microsoft has proposed another attachment solution based on DIME (see Resources).

I will now explain how a SOAP message can be constructed with attachments and how to reference an attachment from a SOAP message.

The SOAP message package

A SOAP message package contains the primary SOAP message in XML format as well as other entities in any data format (for example, gif, jpg, xml, etc.) that are not in defined in the SOAP envelope but are related to the message.

As shown in Figure 1, the SOAP message package is constructed using MIME's Multipart/related media type with each part embedded within a MIME boundary (defined in the Context-Type header). Each MIME part has header information such as Context-Type that specifies the type of the data embedded in this MIME part, Content Transfer-encoding to specify the encoding used for this MIME part, and Content-ID and/or Content-Location as an identifier to refer this content from any where in the MIME package. The root part of the MIME message contains the SOAP envelope with Content-Type set to text/xml.


Figure 1. SOAP message package
SOAP message package

SOAP reference to attachments

Both the SOAP header and body of a SOAP message may refer to other entities in the message package. Based on the SOAP 1.1 encoding rules, SOAP 'href' attribute (see Figure 1) can be used to reference any resource.

Any resource can be referenced using either Content-ID or Content-Location. If you are using Content-ID as the identifier then the schema attribute (for example, href) must use the URL scheme CID (based on rfc 2153) as shown in Figure 1. If Content-Location is used as the identifier then the resolution has to be done based on the rules as specified in the SOAP with Attachments specification, where the resolution based on one of the following:

  • Absolute URI reference - An absolute URL is specified in both Content-Location and 'href' attribute in the SOAP envelope.
  • Relative URI reference - There is a base URL as specified in the Content-Location of the main header of the MIME message and all the relative URLs are referenced using this base URL.
  • Relative but with no base URI - There is no base URL specified in the Content-Location of the main header but using the messages base URL and all the relative URLs are referenced using this base URL.

Normally it is up to the SOAP processor to determine if it needs to resolve the URI. Furthermore, there may be attachments in the message package with no URI reference in SOAP envelope.

HTTP bindings
If HTTP binding is used by SOAP for sending attachments, the HTTP header needs to be modified to include the Content-Type information from the SOAP MIME package header. No other header information from the MIME package header is present in the HTTP header. Apache ignores headers such as Content-Transfer-Encoding and MIME Version information. All the MIME parts including the SOAP envelope part and other attachments, form the HTTP body. On the other hand, in the case of SMTP binding, all the multipart MIME headers would be stored as part of the SMTP headers. Thus, SOAP processors and applications should be aware of these header incompatibilities with different kind of SOAP bindings.

WSDL support to describe Web services with attachments
As shown in the below WSDL document, the binding element's input and/or output elements are extended and are packaged under MIME:multipart-related with different MIME parts, one MIME part for the SOAP body and other attachments. Each MIME part with attachment can specify its content type too.


Listing 1: Extending WSDL bindings for MIME

 <binding name="DocManagementService_Binding"  ... />
  <operation  name="SubmitArrayOfDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/SubmitArrayOfData"/>
    <input>
      <mime:multipartRelated>
          <mime:part>
      		<soap:body
	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	namespace="urn:DocManagement-service"
	parts="SubmitArrayOfDocuments_inType1 SubmitArrayOfDocuments_inType2"
	use="encoded"/>

          </mime:part>
          <mime:part>
            <mime:content part="SubmitArrayOfDocuments_inType3" type="*/*"/>
          </mime:part>
	</mime:multipartRelated>
    </input>
    <output>
      <soap:body
	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	namespace="urn:DocManagement-service" 
	use="encoded"/>
    </output>
  </operation>
</binding>

Apache SOAP 2.2 toolkit support for SOAP with Attachments

Apache SOAP toolkit version 2.2 support SOAP with attachments based on the W3C's SOAP with Attachments Note. Depending on the type of the service and the fine-grain control needed, there are different techniques available in the toolkit to handle the attachments:

  • There are built in serializers/deserializers to handle attachments using javax.activation.Datasource objects and javax.activation.DataHandler objects. This is mainly used for RPC based client-server invocation.
  • To get more fine-grain control on the handling of attachments there are methods (addBodyPart(..), findBodyPart(..), getBodyPart(..),...) available with the client side classes like org.apache.soap.messaging.Message, org.apache.soap.rpc.Call and org.apache.soap.rpc.Response and at the server side SoapContext class. These methods allow to add or retrieve a javax.mail.internet.MimeBodyPart to the SOAP message.

There are a number of issues associated with using SOAP with attachments:

  • The SOAP with Attachments specification is based on 'MIME Multipart/related'. There are discussions in the SOAP community on the use of 'MIME Application/Multiplexed', which binary contents to be interleaved with in the main XML document. This helps applications to scale better by not loading all the data to the memory at once including the attachments.
  • Some of the toolkits supports the SOAP with Attachments specification standard. Apache SOAP 2.2 , WASP are among them.
  • Currently most of the SOAP toolkits didn't support a streaming model for handling huge data coming as either attachments or as messages. This results in scalability and performance issues for the SOAP processors.

Building this example

I built this implementation for the WebSphere Application Server 4.0 environment using the Web Services ToolKit 2.4.2 and Apache SOAP toolkit 2.2. A newer version of the WSTK exists now but this code should be compatible. You can download the ZIP file (DocumentManager.zip) that contains source code, .ear (enterprise application archive), .war (document manager web module) and other files (DD.xml and .wsdl files) and the necessary information to install it (see 'setup.doc'). It also contains a sample client source and class files. (See Resources.)

A simple implementation study

For this implementation study, I will create a Web-based application to enable end-users to upload and download their files from a Web server. This application provides a Web-service based invocation model. This Web service application will enable users to upload any number of files to the server and get references back to those files, as well as download the files they want using these references.

This example will help to explain the custom type mapping, sending multiple attachments and advanced WSDL document constructs to support MIME attachment. It will also help to describe how to send and retrieve custom data as arrays. This simple application could be enhanced into a global Web-based file management application. The example however, does not take into account the more complex issues of security, internationalization, privacy, and performance that would be necessary in a such large scale application.

Service description (WSDL) of the front-end client and back-end server contains information on the services being exposed from the Document manager application. The WSDL bindings have been extended to support the MIME format with MIME type multipart/related. The back-end WSDL file is shown in Listing 2, and front-end in Listing 3.


Listing 2: DocumentManagement-Interface.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="DocumentManagementService_Interface"
  targetNamespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:tns=
"http://www.DocumentManagementService.com/DocumentManagementService_interface"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
  xmlns:types=
"http://www.DocumentManagementService.com/DocumentManagementService_interface/types/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

<types>
  <xsd:schema targetNamespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface/types/"
   xmlns="http://www.w3.org/2001/XMLSchema/">
    
  <xsd:complexType name="User">
	<xsd:sequence>
		<xsd:element name="userName" type="xsd:string"/>
		<xsd:element name="password" type="xsd:string"/>
	</xsd:sequence>
    </xsd:complexType>

	<xsd:complexType name="DocumentInformation">
	<xsd:sequence>
		<xsd:element name="userDefinedDocName" type="xsd:string"/>
		<xsd:element name="localPathInfo" type="xsd:string"/>
	</xsd:sequence>
    </xsd:complexType>
    
    <xsd:complexType name="ArrayOfDocumentInformation">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element minOccurs="0" maxOccurs="unbounded" 
					name="docInfo" type=" DocumentInformation"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="DocumentInformation[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>


	<xsd:complexType name="DocumentReference">
		<xsd:sequence>
			<xsd:element name="docCreateDateTime" type="xsd:datetime"/>
			<xsd:element name="docRefType" type="xsd:string"/>
			<xsd:element name="serverDocPath" type="xsd:string"/>
			<xsd:element name="localPathInfo" type="xsd:string"/>
			<xsd:element name="userDefinedDocName" type="xsd:string"/>
			<xsd:element name="docRef" type="xsd:string"/>
		</xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="ArrayOfDocumentReference">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element minOccurs="0" maxOccurs="unbounded" 
					name="docRef" 
					type="DocumentReference"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="DocumentReference[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>
    
    <xsd:complexType name="ArrayOfString">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element maxOccurs="unbounded" name="docs" 
					type="xsd:string"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="xsd:string[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>
  </xsd:schema>
</types>

<message name="InSubmitArrayOfDocumentsRequest">
  <part name="SubmitArrayOfDocuments_inType1" type="types:User"/>
  <part name="SubmitArrayOfDocuments_inType2" 
type="types:ArrayOfDocumentInformation"/>
  <part name="SubmitArrayOfDocuments_inType3" 
type="types:ArrayOfString"/>
</message>

<message name="OutSubmitArrayOfDocumentsResponse">
  <part name="SubmitArrayOfDocuments_outType" type=
"types:ArrayOfDocumentReference"/>
</message>


<message name="InFetchDocumentsRequest">
 <part name="FetchDocuments_inType1" type="types:User"/>
  <part name="FetchDocuments_inType2"  type=
"types:ArrayOfDocumentReference"/>
</message>

<message name="OutFetchDocumentsResponse">
<part name=" FetchDocuments_outType1" type="xsd:string"/>
</message>

<message name="InPingDocumentMangerRequest">
 <part name="PingDocumentManger_inType1" type="xsd:string"/>
</message>

<message name="OutPingDocumentMangerResponse">
  <part name="PingDocumentManger_outType1"  type="xsd:string"/>
</message>

<portType  name="DocumentManager_portType">
  <operation  name="SubmitArrayOfDocuments">
    <input message="tns:InSubmitArrayOfDocumentsRequest"/>
    <output message="tns:OutSubmitArrayOfDocumentsResponse"/>
  </operation>
  <operation name="FetchDocuments">
    <input  message="tns:InFetchDocumentsRequest"/>
    <output message="tns:OutFetchDocumentsResponse"/>
  </operation>

  <operation name="PingDocumentManger">
    <input  message="tns:InPingDocumentMangerRequest"/>
    <output message="tns:OutPingDocumentMangerResponse"/>
  </operation>

</portType>

<binding name="DocumentManagementService_Binding_Rpc" type=
"tns:DocumentManager_portType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

   <operation  name="SubmitArrayOfDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/SubmitArrayOfData"/>
    <input>
      <mime:multipartRelated>
          <mime:part>
      		<soap:body 
		encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
		namespace="urn:DocumentManagement-service"
		parts="SubmitArrayOfDocuments_inType1 SubmitArrayOfDocuments_inType2"
		use="encoded"/>

          </mime:part>
          <mime:part>
            <mime:content part="SubmitArrayOfDocuments_inType3" type="text/html"/>
          </mime:part>
	</mime:multipartRelated>
    </input>
    <output>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service"
      use="encoded"/>
    </output>
   </operation>

   <operation name="FetchDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/FetchDocuments"/>
    <input>
     <mime:multipartRelated>
          <mime:part>
        	 <soap:body
          		encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	            namespace="urn:DocManagement-service"
		      parts="FetchDocuments_inType1 FetchDocuments_inType2"
      	      use="encoded"/>
	    </mime:part>
     </mime:multipartRelated>
  </input>
  <output>
       <soap:body 
			encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
			namespace="urn:DocManagement-service" use="encoded"/>
  </output>
</operation>

  <operation name="PingDocumentManger">
    <soap:operation soapAction=
"http://www.DocumentManagementService.com/PingDocumentManger"/>
    <input>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service"
          use="encoded"/>
    </input>
    <output>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service" use="encoded"/>
    </output>
  </operation>
</binding>
</definitions>

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="DocManagementServiceDefinition" 
	xmlns="http://schemas.xmlsoap.org/wsdl/" 
	xmlns:interface=
	http://www.DocumentManagementService.com/DocumentManagementService_interface" 
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	targetNamespace=
	"http://www.DocManagementService.com/DocManagementService" >

<import location=
"http://joshyjjp:4040/DocumentManager/DocumentManager-Interface.wsdl" 
namespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface" />

<service name="DocManagementService">
  <documentation>Document Management Web Service: 
This service will allow user to manage their documents 
</documentation>
  <port binding=
"interface:DocumentManagementService_Binding_Rpc" 
name="DocManagementService_RPC">
    <soap:address location=
"http://joshyjjp:4040/dmsoap/servlet/rpcrouter"/>
  </port>
  <port binding="interface:DocumentManagementService_Binding_Message"
name="DocManagementService_Message">
    <soap:address location=
"http://joshyjjp:4040/dmsoap/servlet/messagerouter"/>
  </port>

</service>
</definitions>

The back-end service implementation

The back-end service implementation (shown in Listing 4) is handled in the class DocumentManagementImpl with the public accessible service methods like SubmitArrayOfDocuments and FetchDocuments. Here SubmitArrayOfDocuments, service is an RPC-based SOAP service method with parameters including SOAPContext (to handle attachments), User (user information) and an array of DocumentInfo (attached documents submitted to the server). The FetchDocuments method is an RPC-based service with both user information and document reference object as parameters. The document reference object contains information (docRefId) on the document already submitted and saved in the server.


Listing 4: DocumentManagementImpl class

// apache soap
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.util.xml.XMLParserUtils;
import org.apache.soap.encoding.SOAPMappingRegistry;

// MIME
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;

// java
import java.io.*;
import java.util.*;

public class DocumentManagementImpl implements DocumentManagement{
	
/* 
	Submit an array of documents to the Document Manger; Attached data has to 
	be retrieved from the SOAPContext.
	Once the attached data is retrieved it will be saved to the disk at 
	the server and a document reference will	be returned to the user.
	*/
public DocumentReference[] SubmitArrayOfDocuments
(SOAPContext requestContext, User user, DocumentInfo[] localDocInfo) 
throws Exception{
	
	DocumentReference [] refArray = null;
		try{
			// get the document information 
			int docCount = localDocInfo.length;
			if(docCount >0){
				// get attachment count
				int attachmentCount = requestContext.getCount();

// there docCount docs to be saved and if successful there will be 
// that many document reference 
// for the client
			refArray = new DocumentReference[docCount]; 
				
MimeBodyPart mbp = null;
				// Get root part
    				MimeBodyPart rootPart = requestContext.getRootPart();

				// Detach Attachments if present
	   for (int i = 0; i < requestContext.getCount(); i++){
			      // Get next attachment
      	mbp = (MimeBodyPart)requestContext.getBodyPart(i);
	     	if (!(mbp.equals(rootPart))){ 
			// the root element is the soap envelope
      		String type = mbp.getContentType();
    		String Id = mbp.getContentID();
    		String cntType = mbp.getContentType();
String location = mbp.getHeader
(org.apache.soap.Constants.HEADER_CONTENT_LOCATION, null);
		String name = mbp.getFileName();
			Object content = mbp.getContent();
			String classType = content.getClass().getName();
	
			if (mbp.isMimeType("text/*")){
				System.out.println("The MIME data is in text format");
		}else{
				System.out.println("The MIME data is in binary format");
			}
			// save each attachment to the file system
			DocumentReference dofRef = 
			saveDocument(user,localDocInfo[i-1],content);
		refArray[i-1]= dofRef; // set the return document reference
		 }
	}
}		
    		}catch(Exception e){
			System.out.println
			("There is an exception "+ e.toString());
			throw e;
    		}
		return refArray;
	   }
/* Get all the documents that already saved in the server with the respective 
document reference number. All the documents should be send back 
to the user as attachments. */
public  void FetchDocuments (DocumentReference[] docRef){
.............................................................................................
}

private synchronized DocumentReference saveDocument(User user, DocumentInfo 
userDefinedDocName, Object content){
	// save the document in the server and return a reference to the user.
..............................................................................
}	
}

I use the SOAPContext request object to get the attachment information as shown in the service code. This SOAPContext object contains the body parts, which is an array of MIME parts with the root part containing the SOAP envelope. You can extract a number of information from the MIME body part including the content id, content type, and location.

The custom type mapping registry is set up using the deployment descriptor as shown in Deployment Descriptor.xml file (see the isd:mapping section). SOAP server loads the type mapping information and the necessary serialization and de-serialization classes and does the necessary marshalling and un-marshalling of the types to the custom Java technology classes like User, DocumentInfo, etc.

Document based methods can be added to provide fine-grain control on attachment. This is done by creating MIME attachments by using SOAPContext 'reponse' object, which is a parameter to 'document' based method calls. This SOAPContext object contains the body parts, which is an array of MIME parts with the root part containing the SOAP envelope.

The control information (user name, uploaded file information, and file reference id) is stored in server using an XML document (DocumentManger.xml).

The client service implementation

The client code creates type mapping information in the SOAPMappingRegistry to marshall and unmarshall Java technology classes like User, DocumentInfo, and DocumentReference and binds it with the request object as shown in the following:

	// set the SOAP mapping registry
      BeanSerializer beanSer = new BeanSerializer(); 
	// java bean based standard serializer
	SOAPMappingRegistry smr = new SOAPMappingRegistry();
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName
	("urn:xml-docmanger-webservice", "user"),User.class, beanSer, beanSer);	
	
// set the mapping registry
	request.setSoapMappingRegistry(smr);

It uses the bean serializer class (BeanSerializer) for serialization and deserialization of the classes like User, which follows the JavaBean design pattern.

	Attachments are created using DataSource, DataHandler 
	and MimeBodyPart classes and bind to the request object as show below, 
	// Now create attachments and add to the request
DataSource ds = new ByteArrayDataSource(new File("Compile.bat"), null); 

In the above example the file Compile.bat is sent as the attachment.

     
DataHandler dh = new DataHandler(ds);
      MimeBodyPart mbp = new MimeBodyPart();
      mbp.setDataHandler(dh);
      // Add the attachment to the service request
      request.addAttachment(mbp);

An implementation of the client is show in Listing 5. The code is mostly self-descriptive.


Listing 5: Document client code

	// Service Implementation URL
     	String wsdlSvcImplURL = Util.formatURL(WSTKConstants.SERVER_HOSTNAME,
                                      WSTKConstants.SERVER_PORT,
                                      svcImplUrl);
     	 // get the WSDL document
	WSDLDocument wsdlDoc = new WSDLDocument(new URL(wsdlSvcImplURL));

    	// Get the service proxy you will use to invoke service based on the WSDL document
    	ServiceProxy serviceProxy = ServiceProxyFactory.getServiceProxy
(serviceName,portName,wsdlDoc);

      	// SubmitArrayOfDocuments RPC based operation expects 2 input arguments
      	Object oArgs = new Object[2];
	
	// the parameters are 
	// 1. user information
	User user = new User (userName,userPassword);
	
	// 2. an array of submited document information
	DocumentInfo[] docInfo = new DocumentInfo[1];
	docInfo[0] = new DocumentInfo("compile.bat","d:\\data");

	// Setting up the type mapping registry to handle custom java objects
	// setup the serializers; 
	BeanSerializer beanSer = new BeanSerializer(); 
	// java bean based standard serializer
	// set the soap mapping registry
	SOAPMappingRegistry smr = new SOAPMappingRegistry();
	// input parameters
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
            	new QName("urn:xml-docmanger-webservice", "user"),
            User.class, beanSer, beanSer);
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
            	new QName("urn:xml-docmanger-webservice", "documentinfo"),
            DocumentInfo.class, beanSer, beanSer);
	// output parameters
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
                       new QName("urn:xml-docmanger-webservice", "documentreference"),
                      DocumentReference.class, beanSer, beanSer);

 // Set input arguments
	 oArgs[0] = user;
	 oArgs[1] = docInfo;

	// Set up the request
    	SoapServiceRequest request = new SoapServiceRequest 
("SubmitArrayOfDocuments", oArgs);
	// set the mapping registry
	request.setSoapMappingRegistry(smr);

	// Now create attachments and add to the request
            DataSource ds = new ByteArrayDataSource(new File("Compile.bat"), null);
      	DataHandler dh = new DataHandler(ds);
	MimeBodyPart mbp = new MimeBodyPart();
	mbp.setDataHandler(dh);
      	mbp.setFileName("Compile.bat");
	mbp.setHeader
	(org.apache.soap.Constants.HEADER_CONTENT_LOCATION, "Attachment-1");

      	// Add the attachment to the service request
	request.addAttachment(mbp);
    	// Invoke the operation
    	ServiceResponse sr = serviceProxy.invoke(request);

	// Pull the soap response object from the results
    	Response response = (Response) sr.getOneResult(1);
	// If the call to the service failed, then display error information
	if (response.generatedFault()){
      		handleFault(response);
	} else {
      	// Get return value
	      Parameter parameter = response.getReturnValue();
	      // Display results
	      	System.out.println("Message returned from service provider: \n");
		retRef = (DocumentReference[])parameter.getValue();
		for(int i=0;i<retRef.length;i++){
			System.out.println("Document reference id = "+retRef[i].getDocRef());
     		}
       }
	
	// Now fetch the documents uploaded to the server by using the document references
........................................................................	
	// Pull the soap response object from the results
    	response = (Response) sr.getOneResult(1);
	// If the call to the service failed, then display error information
	if (response.generatedFault()){
          handleFault(response);
      }else{
      		// Get return value
	      int attachCount = sr.getAttachmentCount();
      		// Display results
     	 	System.out.println("Number of attachments = " +attachCount);
       }
    }

Finally the service deployment descriptor is show in Listing 6.


Listing 6: Deployment descriptor for document management service

<root>
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" 
id="urn:DocumentManagement-service" checkMustUnderstands="false">
  <isd:provider type="java" scope="Application" 
methods="PingDocumentManger SubmitArrayOfDocuments FetchDocuments">
    <isd:java class="DocumentManagementImpl" static="false"/>
  </isd:provider>
 <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
  <isd:mappings>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:user"
             javaType="User"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:documentreference"
             javaType="DocumentReference"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:documentinfo"
             javaType="DocumentInfo"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
  </isd:mappings>    

</isd:service>
</root>


Future trends

The XML Protocol committee initiated work to define a set of new software practices or usage scenarios. This includes multiple asynchronous messaging, caching, routing, and the streaming of huge data. It may take some time for the standardization but you can expect SOAP processors coming to the market with these new features including data streaming capabilities, rather than just block transfers using direct attachments. The BEEP (Blocks Extensible Exchange Protocol) is a new protocol that supports multi channels over a single TCP connection, which can be used for such asynchronous and streaming types of data communication.

Direct Internet Message Encapsulation (DIME) is another lightweight, binary message format that can be used to encapsulate one or more application-defined payloads of arbitrary type and size into a single message construct. DIME has strengths in two areas. The sender should do either pre-computation of the size of the payload or "chunks" the payload into records of fixed size. This helps server applications to compute the memory requirements in advance and hence increased performance. The ability to specify new media types using URI mechanism may allow receiving applications to load handlers for new media types. However, this still primarily a Microsoft-defined specification.

Apache AXIS, the latest version of Apache SOAP, is currently in alpha stage but by taking a close look into AXIS toolkit sources and samples and IBM's WSTK 3.0 toolkit provides some insights into the changes that are coming to SOAP with attachments implementation in AXIS. In the case of RPC-based service methods, the attachments are passed to the service as Axis DataHandlers but in the case of Document-based service methods, it expects a MessageContext object as parameter which contains the Message and Attachments objects which in turn contains attachments and SOAP data as 'Parts'.


Resources

About the author

author

Joshy is a Software Engineer working on the IBM WebSphere Catalog Manager product. His primary programming interests are working with emerging technologies like Web services, the Semantic Web and GRID computing, and using programming models based on UML, AOP, and XP. You can contact him at joshy@us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=11642
ArticleTitle=Handling attachments in SOAP
publish-date=02012002
author1-email=joshy@us.ibm.com
author1-email-cc=