• No results found

Processing Received Attachments

In document Web Services (Page 62-65)

When a SOAP message containing one or more attachments is received, the SOAPMessageobject will have oneAttachmentPartper attachment. The interpreta-tion placed on these attachments and the way in which they relate to the XML in the body of the message is, of course, application-dependent. In the case of the book image service, as we saw in Example 3-13, each image returned in response to aBookImageRequesthas its own entry in theBookImagesarray that appears in the body of the SOAP message sent by the web service to the client. The array entry is bound to the attachment containing the image data by an href attribute that contains the value of theContent-Id MIME header of the appropriate attachment:

<item href="cid:ID0"/>

To extract all of the images, the book image client loops over all of the elements in the array, extracts thehrefattribute for each, and finds the AttachmentPartthat has the correspondingContent-Id, as shown in Example 3-16.

Example 3-16. Handling attachments in a SOAP message

SOAPBody replyBody = reply.getSOAPPart().getEnvelope( ).getBody( );

if (replyBody.hasFault( )) {

SOAPFault fault = replyBody.getFault( );

throw new SOAPException("Fault when getting book images: " + fault.getFaultString( ) +

", actor is [" + fault.getFaultActor( ) + "]");

}

// The body contains a "BookImages" element with a nested // element for each book title.

SAAJ

As each child element of the array is found, itshrefattribute is obtained. Since this is actually in the formcid:ID0, it is necessary to first strip away the leading cid: to obtain the value that is used for theContent-Id header:

String imageRef = element.getAttributeValue(HREF_ATTRIBUTE);

if (imageRef != null) {

// Get the attachment using the Content-Id, having // first removed the "cid:" prefix

imageRef = imageRef.substring(4);

As noted earlier, the SAAJ API provides twoSOAPMessagemethods that return the attachments for the message:

public Iterator getAttachments( )

public Iterator getAttachments(MimeHeaders headers)

There is no direct way to find a single attachment given a content id string.

Instead, the second getAttachments( ) method provides a general facility that returns all attachments that have a given set of MIME headers. Here, we use it to Iterator iter = replyBody.getChildElements(BOOK_IMAGES_NAME);

if (iter.hasNext( )) {

ArrayList list = new ArrayList( );

MimeHeaders headers = new MimeHeaders( );

SOAPElement bookImages = (SOAPElement)iter.next( );

iter = bookImages.getChildElements( );

while (iter.hasNext( )) {

SOAPElement element = (SOAPElement)iter.next( );

String imageRef = element.getAttributeValue(HREF_ATTRIBUTE);

if (imageRef != null) {

// Get the attachment using the Content-Id, having // first removed the "cid:" prefix

imageRef = imageRef.substring(4);

headers.setHeader("Content-Id", imageRef);

Iterator attachIter = reply.getAttachments(headers);

if (attachIter.hasNext( )) {

AttachmentPart attach = (AttachmentPart)attachIter.next( );

Object content = attach.getContent( );

if (content instanceof Image) { list.add(content);

} } } }

int size = list.size( );

Image[] images = new Image[size];

list.toArray(images);

return images;

} else {

// No BookTitles element was found

throw new SOAPException("No BookImages element in returned message");

}

Example 3-16. Handling attachments in a SOAP message (continued)

locate the correct AttachmentPart by looking for the attachment in which the Content-Id header has the value extracted from the message body:

MimeHeaders headers = new MimeHeaders( );

headers.setHeader("Content-Id", imageRef);

Iterator attachIter = reply.getAttachments(headers);

if (attachIter.hasNext( )) {

AttachmentPart attach = (AttachmentPart)attachIter.next( );

Given the way that this message is constructed, we expect there to be only one AttachmentPart per element in the message body, but this isn’t necessarily the case: it is possible to attach more then one object with the same Content-Id, perhaps to supply the image and an associated sound file containing some marketing information for the book. The two objects would, of course, be distin-guished by the content types, which can be obtained from the AttachmentPart using itsgetContentType( ) method.

Once you have theAttachmentPart, you can get its content using the following method:

public Object getContent( );

The actual type of the returned object is determined by the attachment’s content type and theDataContentHandlers that are installed. In the case of the reference implementation, the mapping from content type to Java object type is as shown in Table 3-3, which means that, in this example, thegetContent( ) method should return ajava.awt.Imagecontaining the image data extracted from the attachment.

Content types for which a DataContentHandler is not found are returned as an InputStreamfrom which the raw byte data can be read. In the case of the refer-ence implementation, for example, a sound file sent with typeaudio/wavor a byte stream of typeapplication/octet-stream is returned in this way.

Another way to extract the data from an attachment is to use theDataHandlerthat is created for each AttachmentPart. Using the DataHandler, you can bypass the DataContentHandlerFactoryand get direct access to the raw attachment data, even if the content type is recognized by the SAAJ implementation that you are using.

Here, for example, is some code that will create anImageobject from any of the image types recognized by the JRE that you are using, even if the SAAJ implemen-tation does not provide aDataContentHandler for it. At the time of this writing, this code works for PNG images as well as those in GIF or JPEG format:

if (attach.getContentType( ).startsWith("image/")) {

javax.activation.DataHandler handler = attach.getDataHandler( );

InputStream is = handler.getInputStream( );

int count = is.available( );

byte[] buffer = new byte[count];

is.read(buffer, 0, count);

Image img = java.awt.Toolkit.getDefaultToolkit( ).createImage(buffer);

}

Notice that we use theavailable( )method ofInputStreamto find out how much data there is in the attachment, even though AttachmentPart has a getSize( ) method. The reason for this is theAttachmentPartmethod always seems to return a number that is larger than the actual size of the data.

SAAJ

In document Web Services (Page 62-65)