You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by ve...@apache.org on 2009/01/27 14:29:11 UTC

svn commit: r738086 - in /webservices/axis2/trunk/java/modules/saaj: src/org/apache/axis2/saaj/ test-resources/ test/org/apache/axis2/saaj/

Author: veithen
Date: Tue Jan 27 13:29:10 2009
New Revision: 738086

URL: http://svn.apache.org/viewvc?rev=738086&view=rev
Log:
AXIS2-4189: Fixed MessageFactoryImpl#createMessage(MimeHeaders, InputStream) so that it behaves according to the SAAJ specs (and to Sun's reference implementation), i.e.
* creates AttachmentParts for all attachments (SwA and MTOM);
* doesn't substitute xop:Include elements (this behavior can be changed using the new MessageFactoryImpl#setProcessMTOM method);
* correctly populates the MimeHeader objects linked to the SOAPPart and AttachmentParts.
To this end, processing of multipart/related has been moved from SOAPPartImpl to SOAPMessageImpl. This also makes more sense from a design point of view.  

Modified:
    webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/MessageFactoryImpl.java
    webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java
    webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
    webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
    webservices/axis2/trunk/java/modules/saaj/test-resources/message.bin
    webservices/axis2/trunk/java/modules/saaj/test/org/apache/axis2/saaj/MessageFactoryTest.java

Modified: webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/MessageFactoryImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/MessageFactoryImpl.java?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/MessageFactoryImpl.java (original)
+++ webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/MessageFactoryImpl.java Tue Jan 27 13:29:10 2009
@@ -77,6 +77,7 @@
 public class MessageFactoryImpl extends MessageFactory {
 
     protected String soapVersion = SOAPConstants.SOAP_1_1_PROTOCOL;
+    private boolean processMTOM;
 
     /**
      * Creates a new <CODE>SOAPMessage</CODE> object with the default <CODE>SOAPPart</CODE>,
@@ -128,7 +129,7 @@
      */
     public SOAPMessage createMessage(MimeHeaders mimeheaders,
                                      InputStream inputstream) throws IOException, SOAPException {
-        SOAPMessageImpl soapMessage = new SOAPMessageImpl(inputstream, mimeheaders);
+        SOAPMessageImpl soapMessage = new SOAPMessageImpl(inputstream, mimeheaders, processMTOM);
         soapMessage.setSaveRequired();
         return soapMessage;
     }
@@ -136,4 +137,23 @@
     public void setSOAPVersion(String soapVersion) {
         this.soapVersion = soapVersion;
     }
+
+    /**
+     * Specify whether MTOM messages should be processed or parsed literally.
+     * <p>
+     * The way MTOM messages are handled fundamentally differs between Axiom and SAAJ.
+     * While Axiom replaces xop:Include elements by {@link javax.activation.DataHandler} backed
+     * {@link org.apache.axiom.om.OMText} nodes, there is no such requirement in SAAJ. The only
+     * requirement there is that {@link SOAPMessage#getAttachment(javax.xml.soap.SOAPElement)}
+     * returns the relevant {@link javax.xml.soap.AttachmentPart} when applied to an
+     * xop:Include element.
+     * <p>
+     * This method allows to make this SAAJ implementation behave as Axiom, i.e. to substitute
+     * xop:Include elements.
+     * 
+     * @param processMTOM whether xop:Include elements should be substituted
+     */
+    public void setProcessMTOM(boolean processMTOM) {
+        this.processMTOM = processMTOM;
+    }
 }

Modified: webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java (original)
+++ webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java Tue Jan 27 13:29:10 2009
@@ -476,7 +476,7 @@
                     httpInputStream = httpCon.getInputStream();
                 }
 
-                soapMessage = new SOAPMessageImpl(httpInputStream, mimeHeaders);
+                soapMessage = new SOAPMessageImpl(httpInputStream, mimeHeaders, false);
                 httpInputStream.close();
                 httpCon.disconnect();
 

Modified: webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java (original)
+++ webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java Tue Jan 27 13:29:10 2009
@@ -19,7 +19,9 @@
 
 package org.apache.axis2.saaj;
 
+import org.apache.axiom.attachments.Attachments;
 import org.apache.axiom.attachments.ByteArrayDataSource;
+import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.OMOutputFormat;
 import org.apache.axiom.om.impl.MIMEOutputUtils;
 import org.apache.axiom.soap.SOAP11Constants;
@@ -72,7 +74,7 @@
         soapPart = new SOAPPartImpl(this, soapEnvelope);
     }
 
-    public SOAPMessageImpl(InputStream inputstream, javax.xml.soap.MimeHeaders mimeHeaders)
+    public SOAPMessageImpl(InputStream inputstream, MimeHeaders mimeHeaders, boolean processMTOM)
             throws SOAPException {
         String contentType = null;
         String tmpContentType = "";
@@ -83,11 +85,37 @@
                 contentType = SAAJUtil.normalizeContentType(tmpContentType);
             }
         }
-        initCharsetEncodingFromContentType(tmpContentType);
-        if (contentType != null) {
-            soapPart = new SOAPPartImpl(this, inputstream, mimeHeaders);
+        if ("multipart/related".equals(contentType)) {
+            try {
+                Attachments attachments =
+                        new Attachments(inputstream, tmpContentType, false, "", "");
+                
+                // Axiom doesn't give us access to the MIME headers of the individual
+                // parts of the SOAP message package. We need to reconstruct them from
+                // the available information.
+                MimeHeaders soapPartHeaders = new MimeHeaders();
+                soapPartHeaders.addHeader(HTTPConstants.CONTENT_TYPE,
+                        attachments.getSOAPPartContentType());
+                String soapPartContentId = attachments.getSOAPPartContentID();
+                soapPartHeaders.addHeader("Content-ID", "<" + soapPartContentId + ">");
+                
+                soapPart = new SOAPPartImpl(this, attachments.getSOAPPartInputStream(),
+                        soapPartHeaders, processMTOM ? attachments : null);
+                
+                for (String contentId : attachments.getAllContentIDs()) {
+                    if (!contentId.equals(soapPartContentId)) {
+                        AttachmentPart ap =
+                                createAttachmentPart(attachments.getDataHandler(contentId));
+                        ap.setContentId("<" + contentId + ">");
+                        attachmentParts.add(ap);
+                    }
+                }
+            } catch (OMException e) {
+                throw new SOAPException(e);
+            }
         } else {
-            soapPart = new SOAPPartImpl(this, inputstream);
+            initCharsetEncodingFromContentType(tmpContentType);
+            soapPart = new SOAPPartImpl(this, inputstream, mimeHeaders, null);
         }
 
         this.mimeHeaders = (mimeHeaders == null) ?

Modified: webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java (original)
+++ webservices/axis2/trunk/java/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java Tue Jan 27 13:29:10 2009
@@ -29,7 +29,6 @@
 import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
 import org.apache.axiom.soap.impl.dom.soap11.SOAP11Factory;
 import org.apache.axiom.soap.impl.dom.soap12.SOAP12Factory;
-import org.apache.axis2.builder.BuilderUtil;
 import org.apache.axis2.saaj.util.IDGenerator;
 import org.apache.axis2.saaj.util.SAAJUtil;
 import org.apache.axis2.transport.http.HTTPConstants;
@@ -53,6 +52,8 @@
 import org.w3c.dom.Text;
 import org.w3c.dom.UserDataHandler;
 
+import javax.mail.internet.ContentType;
+import javax.mail.internet.ParseException;
 import javax.xml.soap.MimeHeaders;
 import javax.xml.soap.SOAPElement;
 import javax.xml.soap.SOAPEnvelope;
@@ -95,11 +96,26 @@
         envelope.setSOAPPartParent(this);
     }
 
-    public SOAPPartImpl(SOAPMessageImpl parentSoapMsg,
-                        InputStream inputStream, javax.xml.soap.MimeHeaders mimeHeaders
-    ) throws SOAPException {
-        String contentType = "";
-        String fullContentTypeStr = "";
+    /**
+     * Construct a SOAP part from the given input stream.
+     * The content type (as provided by the MIME headers) must be SOAP 1.1, SOAP 1.2
+     * or XOP (MTOM). MIME packages (multipart/related) are not supported and should be
+     * parsed using {@link SOAPMessageImpl#SOAPMessageImpl(InputStream, MimeHeaders).
+     * <p>
+     * If the content type is XOP, xop:Include elements will only be replaced if
+     * the <code>attachments</code> parameter is not null.
+     *
+     * @see MessageFactoryImpl#setProcessMTOM(boolean)
+     * 
+     * @param parentSoapMsg the parent SOAP message
+     * @param inputStream the input stream with the content of the SOAP part
+     * @param mimeHeaders the MIME headers
+     * @param attachments the set of attachments to be used to substitute xop:Include elements
+     * @throws SOAPException
+     */
+    public SOAPPartImpl(SOAPMessageImpl parentSoapMsg, InputStream inputStream,
+                        MimeHeaders mimeHeaders, Attachments attachments) throws SOAPException {
+        ContentType contentType = null;
         if (mimeHeaders == null) {
             //TODO : read string from constants
             this.mimeHeaders = new MimeHeaders();
@@ -108,93 +124,78 @@
         } else {
             String contentTypes[] = mimeHeaders.getHeader(HTTPConstants.CONTENT_TYPE);
             if (contentTypes != null && contentTypes.length > 0) {
-                fullContentTypeStr = contentTypes[0];
-                contentType = SAAJUtil.normalizeContentType(fullContentTypeStr);
+                try {
+                    contentType = new ContentType(contentTypes[0]);
+                } catch (ParseException ex) {
+                    throw new SOAPException("Invalid content type '" + contentTypes[0] + "'");
+                }
             }
             this.mimeHeaders = SAAJUtil.copyMimeHeaders(mimeHeaders);
         }
 
         soapMessage = parentSoapMsg;
 
-        String knownEncoding = (String) soapMessage.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
-        XMLStreamReader xmlReader = null;
-      
-        
-        StAXSOAPModelBuilder builder = null;
-
-        if (contentType.indexOf("multipart/related") == 0) {
-            //This contains attachements
-            try {
-                Attachments attachments =
-                        new Attachments(inputStream, fullContentTypeStr, false, "", "");
-
-                String soapEnvelopeNamespaceURI =
-                        BuilderUtil.getEnvelopeNamespace(fullContentTypeStr);
-
-                String charSetEncoding =
-                        BuilderUtil.getCharSetEncoding(attachments.getSOAPPartContentType());
-
-                XMLStreamReader streamReader =
-                        StAXUtils.createXMLStreamReader(BuilderUtil.getReader(
-                                attachments.getSOAPPartInputStream(), charSetEncoding));
-
-                SOAPFactory factory;
-                if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapEnvelopeNamespaceURI)) {
-                    factory = new SOAP11Factory();
-                } else {
-                    factory = new SOAP12Factory();
-                }
-                if (attachments.getAttachmentSpecType().equals(
-                        MTOMConstants.MTOM_TYPE)) {
-                    //Creates the MTOM specific MTOMStAXSOAPModelBuilder
-                    builder = new MTOMStAXSOAPModelBuilder(streamReader,
-                                                           factory,
-                                                           attachments,
-                                                           soapEnvelopeNamespaceURI);
-                } else if (attachments.getAttachmentSpecType().equals(
-                        MTOMConstants.SWA_TYPE)) {
-                    builder = new StAXSOAPModelBuilder(streamReader,
-                                                       factory,
-                                                       soapEnvelopeNamespaceURI);
-                } else if (attachments.getAttachmentSpecType().equals(
-                        MTOMConstants.SWA_TYPE_12)) {
-                    builder = new StAXSOAPModelBuilder(streamReader,
-                                                       factory,
-                                                       soapEnvelopeNamespaceURI);
-                }
-
-            } catch (Exception e) {
-                throw new SOAPException(e);
-            }
+        String charset;
+        boolean isMTOM;
+        String soapEnvelopeNamespaceURI;
+        SOAPFactory soapFactory;
+        if (contentType == null) {
+            charset = null;
+            isMTOM = false;
+            soapFactory = new SOAP11Factory();
+            soapEnvelopeNamespaceURI = null;
         } else {
-            try {
-                XMLStreamReader streamReader = null;
-                
-                if(knownEncoding != null){
-                	streamReader = StAXUtils.createXMLStreamReader(inputStream, knownEncoding);
-                }else{
-                	streamReader = StAXUtils.createXMLStreamReader(inputStream);                	
-                }
-
-                if (HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(contentType)) {
-                    builder = new StAXSOAPModelBuilder(streamReader,
-                                                       new SOAP11Factory(),
-                                                       SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
-
-                } else if (HTTPConstants.MEDIA_TYPE_APPLICATION_SOAP_XML.equals(contentType)) {
-                    builder = new StAXSOAPModelBuilder(streamReader,
-                                                       new SOAP12Factory(),
-                                                       SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
-
+            String baseType = contentType.getBaseType().toLowerCase();
+            String soapContentType;
+            if (baseType.equals(MTOMConstants.MTOM_TYPE)) {
+                isMTOM = true;
+                String typeParam = contentType.getParameter("type");
+                if (typeParam == null) {
+                    throw new SOAPException("Missing 'type' parameter in XOP content type");
                 } else {
-                    builder = new StAXSOAPModelBuilder(streamReader,
-                                                       new SOAP11Factory(),
-                                                       null);
+                    soapContentType = typeParam.toLowerCase();
                 }
-            } catch (XMLStreamException e) {
-                throw new SOAPException(e);
+            } else {
+                isMTOM = false;
+                soapContentType = baseType;
             }
+            
+            if (soapContentType.equals(HTTPConstants.MEDIA_TYPE_TEXT_XML)) {
+                soapEnvelopeNamespaceURI = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
+                soapFactory = new SOAP11Factory();
+            } else if (soapContentType.equals(HTTPConstants.MEDIA_TYPE_APPLICATION_SOAP_XML)) {
+                soapEnvelopeNamespaceURI = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
+                soapFactory = new SOAP12Factory();
+            } else {
+                throw new SOAPException("Unrecognized content type '" + soapContentType + "'");
+            }
+            
+            charset = contentType.getParameter("charset");
+        }
+        
+        XMLStreamReader streamReader;
+        try {
+            if (charset != null) {
+            	streamReader = StAXUtils.createXMLStreamReader(inputStream, charset);
+            } else {
+            	streamReader = StAXUtils.createXMLStreamReader(inputStream);                	
+            }
+        } catch (XMLStreamException e) {
+            throw new SOAPException(e);
         }
+
+        StAXSOAPModelBuilder builder;
+        if (isMTOM && attachments != null) {
+            builder = new MTOMStAXSOAPModelBuilder(streamReader,
+                                                   soapFactory,
+                                                   attachments,
+                                                   soapEnvelopeNamespaceURI);
+        } else {
+            builder = new StAXSOAPModelBuilder(streamReader,
+                                               soapFactory,
+                                               soapEnvelopeNamespaceURI);
+        }
+        
         try {
             org.apache.axiom.soap.SOAPEnvelope soapEnvelope = builder.getSOAPEnvelope();
             envelope = new SOAPEnvelopeImpl(
@@ -207,11 +208,6 @@
         }
     }
 
-    public SOAPPartImpl(SOAPMessageImpl parentSoapMsg,
-                        InputStream inputStream) throws SOAPException {
-        this(parentSoapMsg, inputStream, null);
-    }
-
     /**
      * Obtain the SOAPMessage
      *

Modified: webservices/axis2/trunk/java/modules/saaj/test-resources/message.bin
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/test-resources/message.bin?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/test-resources/message.bin (original)
+++ webservices/axis2/trunk/java/modules/saaj/test-resources/message.bin Tue Jan 27 13:29:10 2009
@@ -1,5 +1,5 @@
 --MIMEBoundaryurn:uuid:F02ECC18873CFB73E211412748909307
-content-type: application/xop+xml; charset=UTF-8; type="text/xml";
+content-type: application/xop+xml; charset=UTF-8; type="text/xml"
 content-transfer-encoding: binary
 content-id: <0....@apache.org>
 

Modified: webservices/axis2/trunk/java/modules/saaj/test/org/apache/axis2/saaj/MessageFactoryTest.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/saaj/test/org/apache/axis2/saaj/MessageFactoryTest.java?rev=738086&r1=738085&r2=738086&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/saaj/test/org/apache/axis2/saaj/MessageFactoryTest.java (original)
+++ webservices/axis2/trunk/java/modules/saaj/test/org/apache/axis2/saaj/MessageFactoryTest.java Tue Jan 27 13:29:10 2009
@@ -24,10 +24,12 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.w3c.dom.Node;
 
 import javax.xml.soap.AttachmentPart;
 import javax.xml.soap.MessageFactory;
 import javax.xml.soap.MimeHeaders;
+import javax.xml.soap.SOAPElement;
 import javax.xml.soap.SOAPMessage;
 import javax.xml.soap.SOAPPart;
 
@@ -142,7 +144,7 @@
         }
     }
 
-    @Validated @Test @Ignore("AXIS2-4189")
+    @Validated @Test
     public void testParseMTOMMessage() throws Exception {
         MimeHeaders headers = new MimeHeaders();
         headers.addHeader("Content-Type",
@@ -159,15 +161,27 @@
         SOAPPart soapPart = message.getSOAPPart();
         assertEquals("<0....@apache.org>",
                 soapPart.getContentId());
+        
+        // Check the xop:Include element. Note that SAAJ doesn't resolve xop:Includes!
+        SOAPElement textElement =
+                (SOAPElement)soapPart.getEnvelope().getElementsByTagName("text").item(0);
+        assertNotNull(textElement);
+        Node xopIncludeNode = textElement.getChildNodes().item(0);
+        assertTrue(xopIncludeNode instanceof SOAPElement);
+        AttachmentPart ap = message.getAttachment((SOAPElement)xopIncludeNode);
+        assertEquals("<1....@apache.org>",
+                ap.getContentId());
+        
+        // Now check the attachments
         Iterator attachments = message.getAttachments();
         assertTrue(attachments.hasNext());
-        AttachmentPart ap = (AttachmentPart)attachments.next();
+        ap = (AttachmentPart)attachments.next();
         assertEquals("<1....@apache.org>",
                 ap.getContentId());
         assertFalse(attachments.hasNext());
     }
 
-    @Validated @Test @Ignore("AXIS2-4189")
+    @Validated @Test
     public void testParseSwAMessage() throws Exception {
         MimeHeaders headers = new MimeHeaders();
         headers.addHeader("Content-Type",