Author: veithen
Date: Wed Jun 15 20:25:14 2011
New Revision: 1136177

URL: http://svn.apache.org/viewvc?rev=1136177&view=rev
Log:
AXIS2-5067: Committed patch provided by Ivan (xuhaihong), with minor changes. 
This implements the saveChanges method and calculates the correct content type 
for a SOAPMessage.
Modified:
    
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
    
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
    
axis/axis2/java/core/trunk/modules/saaj/test/org/apache/axis2/saaj/SOAPMessageTest.java

Modified: 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java?rev=1136177&r1=1136176&r2=1136177&view=diff
==============================================================================
--- 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
 (original)
+++ 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPMessageImpl.java
 Wed Jun 15 20:25:14 2011
@@ -26,9 +26,12 @@ import org.apache.axiom.om.impl.OMMultip
 import org.apache.axiom.soap.SOAPEnvelope;
 import org.apache.axiom.soap.impl.dom.soap11.SOAP11Factory;
 import org.apache.axiom.soap.impl.dom.soap12.SOAP12Factory;
+import org.apache.axiom.util.UIDGenerator;
 import org.apache.axis2.saaj.util.SAAJUtil;
 import org.apache.axis2.transport.http.HTTPConstants;
 
+import javax.mail.internet.ContentType;
+import javax.mail.internet.ParseException;
 import javax.xml.soap.AttachmentPart;
 import javax.xml.soap.MimeHeader;
 import javax.xml.soap.MimeHeaders;
@@ -73,13 +76,13 @@ public class SOAPMessageImpl extends SOA
         String contentType = null;
         String tmpContentType = "";
         if (mimeHeaders != null) {
-            String contentTypes[] = 
mimeHeaders.getHeader(HTTPConstants.CONTENT_TYPE);
+            String contentTypes[] = 
mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
             if (contentTypes != null && contentTypes.length > 0) {
                 tmpContentType = contentTypes[0];
                 contentType = SAAJUtil.normalizeContentType(tmpContentType);
             }
         }
-        if ("multipart/related".equals(contentType)) {
+        if (HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED.equals(contentType)) {
             try {
                 Attachments attachments =
                         new Attachments(inputstream, tmpContentType, false, 
"", "");
@@ -88,7 +91,7 @@ public class SOAPMessageImpl extends SOA
                 // parts of the SOAP message package. We need to reconstruct 
them from
                 // the available information.
                 MimeHeaders soapPartHeaders = new MimeHeaders();
-                soapPartHeaders.addHeader(HTTPConstants.CONTENT_TYPE,
+                soapPartHeaders.addHeader(HTTPConstants.HEADER_CONTENT_TYPE,
                         attachments.getSOAPPartContentType());
                 String soapPartContentId = attachments.getSOAPPartContentID();
                 soapPartHeaders.addHeader("Content-ID", "<" + 
soapPartContentId + ">");
@@ -164,6 +167,7 @@ public class SOAPMessageImpl extends SOA
      */
     public void removeAllAttachments() {
         attachmentParts.clear();
+        saveRequired = true;
     }
 
     /**
@@ -223,7 +227,8 @@ public class SOAPMessageImpl extends SOA
     public void addAttachmentPart(AttachmentPart attachmentPart) {
         if (attachmentPart != null) {
             attachmentParts.add(attachmentPart);
-            mimeHeaders.setHeader(HTTPConstants.CONTENT_TYPE, 
"multipart/related");
+            mimeHeaders.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, 
"multipart/related");
+            saveRequired = true;
         }
     }
 
@@ -267,8 +272,70 @@ public class SOAPMessageImpl extends SOA
      * @throws SOAPException if there was a problem saving changes to this 
message.
      */
     public void saveChanges() throws SOAPException {
+        try {
+            String contentTypeValue = 
getSingleHeaderValue(HTTPConstants.HEADER_CONTENT_TYPE);
+            ContentType contentType = null;
+            if (isEmptyString(contentTypeValue)) {
+                if (attachmentParts.size() > 0) {
+                    contentTypeValue = 
HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED;
+                } else {
+                    contentTypeValue = getBaseType();
+                }
+            }
+            contentType = new ContentType(contentTypeValue);
+            
+            //Use configures the baseType with multipart/related while no 
attachment exists or all the attachments are removed
+            
if(contentType.getBaseType().equals(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED) 
&& attachmentParts.size() == 0) {
+                contentType = new ContentType(getBaseType());
+            }
+           
+            //If it is of multipart/related, initialize those required values 
in the content-type, including boundary etc.
+            if 
(contentType.getBaseType().equals(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED)) {
+                
+                //Configure boundary
+                String boundaryParam = contentType.getParameter("boundary");
+                if (isEmptyString(boundaryParam)) {
+                    contentType.setParameter("boundary", 
UIDGenerator.generateMimeBoundary());
+                }
+
+                //Configure start content id, always get it from soapPart in 
case it is changed
+                String soapPartContentId = soapPart.getContentId();
+                if (isEmptyString(soapPartContentId)) {
+                    soapPartContentId = "<" + UIDGenerator.generateContentId() 
+ ">";
+                    soapPart.setContentId(soapPartContentId);
+                }
+                contentType.setParameter("start", soapPartContentId);
+                
+                //Configure contentId for each attachments
+                for(AttachmentPart attachmentPart : attachmentParts) {
+                    if(isEmptyString(attachmentPart.getContentId())) {
+                        attachmentPart.setContentId("<" + 
UIDGenerator.generateContentId() + ">");
+                    }
+                }
+                
+                //Configure type                
+                contentType.setParameter("type", getBaseType());
+                
+                //Configure charset
+                String soapPartContentTypeValue = 
getSingleHeaderValue(soapPart.getMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE));
+                ContentType soapPartContentType = null;
+                if (isEmptyString(soapPartContentTypeValue)) {
+                    soapPartContentType = new 
ContentType(soapPartContentTypeValue);
+                } else {
+                    soapPartContentType = new ContentType(getBaseType());
+                }                
+                setCharsetParameter(soapPartContentType);
+            } else {
+                //Configure charset
+                setCharsetParameter(contentType);
+            }
+            
+            mimeHeaders.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, 
contentType.toString());
+        } catch (ParseException e) {
+            throw new SOAPException("Invalid Content Type Field in the Mime 
Message", e);
+        }
+
         saveRequired = false;
-        // TODO not sure of the implementation
     }
 
     public void setSaveRequired() {
@@ -299,23 +366,45 @@ public class SOAPMessageImpl extends SOA
      * @throws IOException   if an I/O error occurs
      */
     public void writeTo(OutputStream out) throws SOAPException, IOException {
-        try {
+        try {           
+            saveChanges();
             OMOutputFormat format = new OMOutputFormat();
             String enc = (String)getProperty(CHARACTER_SET_ENCODING);
             format.setCharSetEncoding(enc != null ? enc : 
OMOutputFormat.DEFAULT_CHAR_SET_ENCODING);
             String writeXmlDecl = (String)getProperty(WRITE_XML_DECLARATION);
             if (writeXmlDecl == null || writeXmlDecl.equals("false")) {
-
                 //SAAJ default case doesn't send XML decl
                 format.setIgnoreXMLDeclaration(true);
             }
-
-            SOAPEnvelope envelope = 
((SOAPEnvelopeImpl)soapPart.getEnvelope()).getOMEnvelope();
+            
+            SOAPEnvelope envelope = ((SOAPEnvelopeImpl) 
soapPart.getEnvelope()).getOMEnvelope();
             if (attachmentParts.isEmpty()) {
                 envelope.serialize(out, format);
             } else {
-                
format.setSOAP11(((SOAPEnvelopeImpl)soapPart.getEnvelope()).getOMFactory()
-                        instanceof SOAP11Factory);
+                ContentType contentType = new 
ContentType(getSingleHeaderValue(HTTPConstants.HEADER_CONTENT_TYPE));
+                String boundary = contentType.getParameter("boundary");
+                if(isEmptyString(boundary)) {
+                    boundary = UIDGenerator.generateMimeBoundary();
+                    contentType.setParameter("boundary", boundary);
+                }
+                format.setMimeBoundary(boundary);
+
+                String rootContentId = soapPart.getContentId();
+                if(isEmptyString(rootContentId)) {
+                    rootContentId = "<" + UIDGenerator.generateContentId() + 
">";
+                    soapPart.setContentId(rootContentId);
+                }                
+                contentType.setParameter("start", rootContentId);
+                if ((rootContentId.indexOf("<") > -1) & 
(rootContentId.indexOf(">") > -1)) {
+                    rootContentId = rootContentId.substring(1, 
(rootContentId.length() - 1));
+                }
+                format.setRootContentId(rootContentId);
+
+                format.setSOAP11(((SOAPEnvelopeImpl) 
soapPart.getEnvelope()).getOMFactory() instanceof SOAP11Factory);
+                
+                //Double save the content-type in case anything is updated
+                mimeHeaders.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, 
contentType.toString());
+
                 OMMultipartWriter mpw = new OMMultipartWriter(out, format);
                 OutputStream rootPartOutputStream = mpw.writeRootPart();
                 envelope.serialize(rootPartOutputStream);
@@ -325,7 +414,8 @@ public class SOAPMessageImpl extends SOA
                 }
                 mpw.complete();
             }
-            saveChanges();
+
+            saveRequired = true;
         } catch (Exception e) {
             throw new SOAPException(e);
         }
@@ -453,6 +543,7 @@ public class SOAPMessageImpl extends SOA
         }
         attachmentParts.clear();
         this.attachmentParts = newAttachmentParts;
+        saveRequired = true;
     }
 
     /**
@@ -502,4 +593,45 @@ public class SOAPMessageImpl extends SOA
             }
         }
     }
+    
+    private boolean isEmptyString(String value) {
+        return value == null || value.length() == 0;
+    }
+    
+    private String getSingleHeaderValue(String[] values) {
+        return values != null && values.length > 0 ? values[0] : null;
+    }
+
+    private String getSingleHeaderValue(String name) {
+        String[] values = mimeHeaders.getHeader(name);
+        if (values == null || values.length == 0) {
+            return null;
+        } else {
+            return values[0];
+        }
+    }
+    
+    private String getBaseType() throws SOAPException {
+        boolean isSOAP12 = ((SOAPEnvelopeImpl) 
soapPart.getEnvelope()).getOMFactory() instanceof SOAP12Factory;
+        return isSOAP12 ? HTTPConstants.MEDIA_TYPE_APPLICATION_SOAP_XML : 
HTTPConstants.MEDIA_TYPE_TEXT_XML;
+    }
+    
+    /**
+     * If the charset is configured by CHARACTER_SET_ENCODING, set it in the 
contentPart always. 
+     * If it has already been configured in the contentType, leave it there.
+     * UTF-8 is used as the default value. 
+     * @param contentType
+     * @throws SOAPException
+     */
+    private void setCharsetParameter(ContentType contentType) throws 
SOAPException{
+        String charset = (String)getProperty(CHARACTER_SET_ENCODING); 
+        if (!isEmptyString(charset)) {
+            contentType.setParameter("charset", charset);
+        } else {
+            charset = contentType.getParameter("charset");
+            if(isEmptyString(charset)) {
+                contentType.setParameter("charset", "UTF-8");
+            }
+        }
+    }
 }

Modified: 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java?rev=1136177&r1=1136176&r2=1136177&view=diff
==============================================================================
--- 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
 (original)
+++ 
axis/axis2/java/core/trunk/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java
 Wed Jun 15 20:25:14 2011
@@ -89,7 +89,7 @@ public class SOAPPartImpl extends SOAPPa
                         SOAPEnvelopeImpl soapEnvelope) {
         //setMimeHeader(HTTPConstants.HEADER_CONTENT_ID, 
IDGenerator.generateID());
         //setMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE, "text/xml");
-        this.mimeHeaders = parentSoapMsg.getMimeHeaders();
+        this.mimeHeaders = 
SAAJUtil.copyMimeHeaders(parentSoapMsg.getMimeHeaders());
         soapMessage = parentSoapMsg;
         envelope = soapEnvelope;
         document = soapEnvelope.getOwnerDocument();
@@ -122,7 +122,7 @@ public class SOAPPartImpl extends SOAPPa
             this.mimeHeaders.addHeader("Content-ID", IDGenerator.generateID());
             this.mimeHeaders.addHeader("content-type", 
HTTPConstants.MEDIA_TYPE_APPLICATION_SOAP_XML);
         } else {
-            String contentTypes[] = 
mimeHeaders.getHeader(HTTPConstants.CONTENT_TYPE);
+            String contentTypes[] = 
mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
             if (contentTypes != null && contentTypes.length > 0) {
                 try {
                     contentType = new ContentType(contentTypes[0]);

Modified: 
axis/axis2/java/core/trunk/modules/saaj/test/org/apache/axis2/saaj/SOAPMessageTest.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/saaj/test/org/apache/axis2/saaj/SOAPMessageTest.java?rev=1136177&r1=1136176&r2=1136177&view=diff
==============================================================================
--- 
axis/axis2/java/core/trunk/modules/saaj/test/org/apache/axis2/saaj/SOAPMessageTest.java
 (original)
+++ 
axis/axis2/java/core/trunk/modules/saaj/test/org/apache/axis2/saaj/SOAPMessageTest.java
 Wed Jun 15 20:25:14 2011
@@ -21,11 +21,13 @@ package org.apache.axis2.saaj;
 
 import junit.framework.Assert;
 import org.apache.axis2.saaj.util.SAAJDataSource;
+import org.apache.axis2.transport.http.HTTPConstants;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import javax.activation.DataHandler;
+import javax.mail.internet.ContentType;
 import javax.xml.namespace.QName;
 import javax.xml.soap.AttachmentPart;
 import javax.xml.soap.MessageFactory;
@@ -45,6 +47,8 @@ import javax.xml.soap.SOAPMessage;
 import javax.xml.soap.SOAPPart;
 import javax.xml.transform.stream.StreamSource;
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
@@ -187,8 +191,7 @@ public class SOAPMessageTest extends Ass
         }
     }
 
-    // TODO: check why this fails with Sun's SAAJ implementation
-    @Test
+    @Validated @Test
     public void testGetContent() {
         try {
             MessageFactory fac = 
MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
@@ -201,7 +204,7 @@ public class SOAPMessageTest extends Ass
             AttachmentPart ap;
 
             InputStream inputStream = TestUtils.getTestFile("attach.xml");
-            ap = msg.createAttachmentPart(inputStream, "text/xml");
+            ap = msg.createAttachmentPart(new StreamSource(inputStream), 
"text/xml");
             DataHandler dh =
                     new DataHandler(new SAAJDataSource(inputStream, 1000, 
"text/xml", true));
 
@@ -229,6 +232,67 @@ public class SOAPMessageTest extends Ass
         }
     }
 
+    @Validated @Test
+    public void testContentTypeGeneration() throws Exception{        
+        MessageFactory fac = MessageFactory.newInstance();
+        SOAPMessage msg = fac.createMessage();
+        InputStream inputStream = TestUtils.getTestFile("attach.xml");
+        AttachmentPart ap = msg.createAttachmentPart(new 
StreamSource(inputStream), "text/xml");        
+        msg.addAttachmentPart(ap);
+        msg.saveChanges();
+        
assertNotNull(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
        
+        String contentTypeValue = 
msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0];
+        ContentType contentType = new ContentType(contentTypeValue);
+        assertNotNull("boundary parameter should exist in the content-type 
header", contentType.getParameter("boundary"));
+        //start parameter is not checked, due to it is optional parameter, and 
seems RI will not add this value
+        //assertNotNull("start parameter should exist in the content-type 
header", contentType.getParameter("start"));
+        assertNotNull("type parameter should exist in the content-type 
header", contentType.getParameter("type"));
+        assertEquals(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED, 
contentType.getBaseType());        
+    }
+
+    @Validated @Test
+    public void testCreateMessageWithMimeHeaders() throws Exception{
+        MessageFactory fac = MessageFactory.newInstance();
+        SOAPMessage msg = fac.createMessage();               
+        InputStream inputStream = TestUtils.getTestFile("attach.xml");
+        AttachmentPart ap = msg.createAttachmentPart(new 
StreamSource(inputStream), "text/xml");        
+        msg.addAttachmentPart(ap);
+        msg.saveChanges();
+        ContentType contentType = new 
ContentType(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0]);
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        msg.writeTo(out);
+        SOAPMessage msg2 = fac.createMessage(msg.getMimeHeaders(), new 
ByteArrayInputStream(out.toByteArray()));
+        msg2.saveChanges();
+        ContentType contentType2 = new 
ContentType(msg2.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0]);
+
+        assertEquals(contentType.getBaseType(), contentType2.getBaseType());
+        assertEquals(contentType.getParameter("boundary"), 
contentType2.getParameter("boundary"));
+        assertEquals(contentType.getParameter("type"), 
contentType2.getParameter("type"));
+        //start parameter is not checked, due to it is an optional parameter, 
and seems RI will not add this value
+        //assertEquals(contentType.getParameter("start"), 
contentType2.getParameter("start"));
+    }
+    
+    @Validated @Test
+    public void testContentTypeUpdateWithAttachmentChanges() throws Exception{
+        MessageFactory fac = MessageFactory.newInstance();
+        SOAPMessage msg = fac.createMessage();               
+        InputStream inputStream = TestUtils.getTestFile("attach.xml");
+        AttachmentPart ap = msg.createAttachmentPart(new 
StreamSource(inputStream), "text/xml");        
+        msg.addAttachmentPart(ap);
+        msg.saveChanges();
+        
+        
assertNotNull(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
+        ContentType contentType = new 
ContentType(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0]);
        
+        assertEquals(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED, 
contentType.getBaseType());
+        
+        msg.removeAllAttachments();
+        msg.saveChanges();
+
+        
assertNotNull(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
+        contentType = new 
ContentType(msg.getMimeHeaders().getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0]);
        
+        assertEquals("text/xml", contentType.getBaseType());
+    }
 
     private StringBuffer copyToBuffer(InputStream inputStream) {
         if (inputStream == null) {


Reply via email to