Version 2

    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