Working with Attachments
Part of the SAAJ-1.2 specification is how to add MIME attachments to
to a SOAP message. The following MIME types are supported
MIME Type | Java Type |
image/gif | java.awt.Image |
image/jpeg | java.awt.Image |
text/plain | java.lang.String |
multipart/ | javax.mail.internet.MimeMultipart |
text/xml | javax.xml.transform.Source |
application/xml | javax.xml.transform.Source |
The SOAP message will be transported as a MIME multipart message with the SOAP envelope being the first MIME part.
Part of the JBoss webservice testsuite is a service endpoint interface that exposes six methods that deal with attachements. There is no need to have an java.lang.Object parameter that takes the MIME part, you might as well
use the propper target type.
public interface Attachment extends Remote { /** Service endpoint method for image/gif */ String sendMimeImageGIF(String message, Object mimepart) throws RemoteException; ... }
The WSDL that defines the service uses elements from the mime namespace xmlns:mime='http://schemas.xmlsoap.org/wsdl/mime/'. Also note that the actual message part
that takes the attachment part use xsd:hexBinary.
This is because we use Object for the mimepart parameter in the SEI.
Here is a sample WSDL
<definitions ... xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"> <types></types> <message name="Attachment_sendMimeImageGIF"> <part name="message" type="xsd:string"></part> <part name="mimepart" type="xsd:hexBinary"></part> </message> <message name="Attachment_sendMimeImageGIFResponse"> <part name="response" type="xsd:string"></part> </message> ... <portType name="Attachment"> <operation name="sendMimeImageGIF"> <input message="tns:Attachment_sendMimeImageGIF"/> <output message="tns:Attachment_sendMimeImageGIFResponse"></output> </operation> ... </portType> <binding name="AttachmentBinding" type="tns:Attachment"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding> <operation name="sendMimeImageGIF"> <soap:operation soapAction=""></soap:operation> <input> <mime:multipartRelated> <mime:part> <soap:body part="message" use="literal" namespace="http://org.jboss.webservice/attachment"></soap:body> </mime:part> <mime:part> <mime:content part="mimepart" type="image/gif"></mime:content> </mime:part> </mime:multipartRelated> </input> <output> <soap:body use="literal" namespace="http://org.jboss.webservice/attachment"></soap:body> </output> </operation> ... </binding> <service name="Attachment"> <port name="AttachmentPort" binding="tns:AttachmentBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL"></soap:address> </port> </service> </definitions>
You endpoint bean may access the attachment parts using the standard SAAJ API.
ServletEndpointContext context = (ServletEndpointContext)ctxWhichIsSetIn_ServiceLifecycle_init; SOAPMessageContext msgContext = (SOAPMessageContext)context.getMessageContext(); SOAPMessage soapMessage = msgContext.getMessage(); Iterator attachments = soapMessage.getAttachments(); if (attachments.hasNext()) { AttachmentPart ap = (AttachmentPart)attachments.next(); String contentType = ap.getContentType(); if (expContentType.equals("multipart/*")) { MimeMultipart mmp = (MimeMultipart)ap.getContent(); int mmpCount = mmp.getCount(); for (int i = 0; i < mmpCount; i++) { BodyPart bp = mmp.getBodyPart(i); String bpct = bp.getContentType(); Object bpc = bp.getContent(); ... } } else if (expContentType.equals("image/gif")) { Image image = (Image)ap.getContent(); ... } else { ... } }
Sending an Attachment from a DII client
To send an image, we can use the standard DII API and make use of the Java activation framework.
From the JavaDoc for DataHandler:
+The DataHandler class provides a consistent interface to data available in many different sources and formats.
It manages simple stream to string conversions and related operations using DataContentHandlers.+
ServiceFactory factory = ServiceFactory.newInstance(); Service service = factory.createService(SERVICE_NAME); Call call = service.createCall(PORT_NAME, new QName(NS_URI, rpcMethodName)); call.addParameter("message", Constants.XSD_STRING, ParameterMode.IN); call.addParameter("mimepart", Constants.MIME_IMAGE, ParameterMode.IN); call.setReturnType(Constants.XSD_STRING); call.setTargetEndpointAddress("http://" + getServerHost() + ":8080/ws4ee-attachment"); URL url = new File("resources/webservice/attachment/attach.gif").toURL(); String message = "Some text message"; String value = (String)call.invoke(new Object[]{message, new DataHandler(url)}); System.out.println(value);
You can also build the SOAP multipart message manually using the SAAJ API, which we will see next.
Building a SOAP multipart message using SAAJ
Using the SAAJ API directly, you can also construct a MIME multipart message and send it on the wire without using
an JAX-RPC client.
MessageFactory mf = MessageFactory.newInstance(); // Create a soap message from the message factory. SOAPMessage msg = mf.createMessage(); // Message creation takes care of creating the SOAPPart // a required part of the message as per the SOAP 1.1 spec. SOAPPart sp = msg.getSOAPPart(); // Retrieve the envelope from the soap part to start building the soap message. SOAPEnvelope envelope = sp.getEnvelope(); // Create a soap body from the envelope. SOAPBody bdy = envelope.getBody(); // Add a soap body element SOAPBodyElement sbe = bdy.addBodyElement(envelope.createName(rpcMethodName, NS_PREFIX, NS_URI)); // Add a some child elements sbe.addChildElement(envelope.createName("message")).addTextNode("Some text message"); sbe.addChildElement(envelope.createName("mimepart")).addAttribute(envelope.createName("href"), CID_MIMEPART); AttachmentPart ap = msg.createAttachmentPart(new DataHandler(url)); ap.setContentType("image/gif"); ap.setContentId(CID_MIMEPART); // Add the attachments to the message. msg.addAttachmentPart(ap); SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance(); SOAPConnection con = conFactory.createConnection(); SOAPMessage resMessage = con.call(msg, new URL("http://" + getServerHost() + ":8080/ws4ee-attachment"));
Most conveniently, you might want to lookup the preconfigured JAX-RPC Service from JNDI and use it directly with
Java method call semantics.
Using a WS4EE client
There is no special propriatary attachment handling needed. All plain vanilla WS4EE.
InitialContext iniCtx = getInitialContext(); Service service = (Service)iniCtx.lookup("java:comp/env/service/AttachmentService"); Attachment port = (Attachment)service.getPort(Attachment.class); URL url = new File("resources/webservice/attachment/attach.gif").toURL(); String value = port.sendMimeImageGIF("Some text message", new DataHandler(url));
Running the Attachment testcases
Use the source distribution or checkout from CVS, then build and run jboss
cvs co -r Branch_4_0 jboss-4.x cd jboss-4.x build/build.sh
Now build the testsuite and run one of the attachment testcase
cd testsuite ant ant -Dtest=org.jboss.test.webservice.attachment.AttachmentProxyTestCase one-test Buildfile: build.xml Overriding previous definition of reference to xdoclet.task.classpath one-test: [junit] Running org.jboss.test.webservice.attachment.AttachmentProxyTestCase [junit] Tests run: 7, Failures: 0, Errors: 0, Time elapsed: 10.25 sec
Comments