You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2017/03/09 19:05:46 UTC

svn commit: r1786217 - in /webservices/axiom/trunk: axiom-api/src/main/java/org/apache/axiom/mime/ axiom-api/src/main/java/org/apache/axiom/mime/impl/ axiom-api/src/main/java/org/apache/axiom/om/ axiom-api/src/main/java/org/apache/axiom/om/impl/ axiom-...

Author: veithen
Date: Thu Mar  9 19:05:46 2017
New Revision: 1786217

URL: http://svn.apache.org/viewvc?rev=1786217&view=rev
Log:
Deprecate MultipartWriter and replace it by a simpler API.

Added:
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBodyWriter.java
      - copied, changed from r1781488, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java
    webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/MultipartBodyWriterTest.java
      - copied, changed from r1786216, webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java
    webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriter.java
      - copied, changed from r1786216, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriter.java
    webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java
      - copied, changed from r1786216, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java
    webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/
      - copied from r1786216, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/axiom/
    webservices/axiom/trunk/axiom-compat/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java
      - copied unchanged from r1781488, webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java
    webservices/axiom/trunk/axiom-compat/src/test/java/org/apache/axiom/mime/impl/axiom/
      - copied from r1786216, webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/impl/axiom/
Removed:
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriter.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/
    webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java
    webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/impl/
Modified:
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/OMOutputFormat.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/impl/OMMultipartWriter.java
    webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/AxiomMultipartWriterFactory.java
    webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java

Copied: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBodyWriter.java (from r1781488, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBodyWriter.java?p2=webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBodyWriter.java&p1=webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java&r1=1781488&r2=1786217&rev=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBodyWriter.java Thu Mar  9 19:05:46 2017
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.axiom.mime.impl.axiom;
+package org.apache.axiom.mime;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -25,10 +25,9 @@ import java.util.List;
 import javax.activation.DataHandler;
 
 import org.apache.axiom.mime.Header;
-import org.apache.axiom.mime.MultipartWriter;
 import org.apache.axiom.util.base64.Base64EncodingOutputStream;
 
-class MultipartWriterImpl implements MultipartWriter {
+public final class MultipartBodyWriter {
     class PartOutputStream extends OutputStream {
         private final OutputStream parent;
 
@@ -64,7 +63,7 @@ class MultipartWriterImpl implements Mul
     private final String boundary;
     private final byte[] buffer = new byte[256];
 
-    public MultipartWriterImpl(OutputStream out, String boundary) {
+    public MultipartBodyWriter(OutputStream out, String boundary) {
         this.out = out;
         this.boundary = boundary;
     }
@@ -87,7 +86,24 @@ class MultipartWriterImpl implements Mul
         }
     }
     
-    @Override
+    /**
+     * Start writing a MIME part. The methods returns an {@link OutputStream} that the caller can
+     * use to write the content of the MIME part. After writing the content,
+     * {@link OutputStream#close()} must be called to complete the writing of the MIME part.
+     * 
+     * @param contentType
+     *            the value of the <tt>Content-Type</tt> header of the MIME part
+     * @param contentTransferEncoding
+     *            the content transfer encoding to be used (see above); must not be
+     *            <code>null</code>
+     * @param contentID
+     *            the content ID of the MIME part (see above)
+     * @param extraHeaders
+     *            a list of {@link Header} objects with additional headers to write to the MIME part
+     * @return an output stream to write the content of the MIME part
+     * @throws IOException
+     *             if an I/O error occurs when writing to the underlying stream
+     */
     public OutputStream writePart(String contentType, String contentTransferEncoding,
             String contentID, List<Header> extraHeaders) throws IOException {
         OutputStream transferEncoder;
@@ -125,13 +141,22 @@ class MultipartWriterImpl implements Mul
         return new PartOutputStream(transferEncoder);
     }
     
-    @Override
-    public OutputStream writePart(String contentType, String contentTransferEncoding,
-            String contentID) throws IOException {    	
-        return writePart(contentType, contentTransferEncoding, contentID, null);
-    }
-    
-    @Override
+    /**
+     * Write a MIME part. The content is provided by a {@link DataHandler} object, which also
+     * specifies the content type of the part.
+     * 
+     * @param dataHandler
+     *            the content of the MIME part to write
+     * @param contentTransferEncoding
+     *            the content transfer encoding to be used (see above); must not be
+     *            <code>null</code>
+     * @param contentID
+     *            the content ID of the MIME part (see above)
+     * @param extraHeaders
+     *            a list of {@link Header} objects with additional headers to write to the MIME part
+     * @throws IOException
+     *             if an I/O error occurs when writing the part to the underlying stream
+     */
     public void writePart(DataHandler dataHandler, String contentTransferEncoding, String contentID, List<Header> extraHeaders)
             throws IOException {
         OutputStream partOutputStream = writePart(dataHandler.getContentType(), contentTransferEncoding, contentID, extraHeaders);
@@ -139,13 +164,13 @@ class MultipartWriterImpl implements Mul
         partOutputStream.close();
     }
     
-    @Override
-    public void writePart(DataHandler dataHandler, String contentTransferEncoding,
-            String contentID) throws IOException {
-        writePart(dataHandler, contentTransferEncoding, contentID, null);
-    }
-
-    @Override
+    /**
+     * Complete writing of the MIME multipart package. This method does <b>not</b> close the
+     * underlying stream.
+     * 
+     * @throws IOException
+     *             if an I/O error occurs when writing to the underlying stream
+     */
     public void complete() throws IOException {
         writeAscii("--");
         writeAscii(boundary);

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/OMOutputFormat.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/OMOutputFormat.java?rev=1786217&r1=1786216&r2=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/OMOutputFormat.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/OMOutputFormat.java Thu Mar  9 19:05:46 2017
@@ -22,8 +22,6 @@ package org.apache.axiom.om;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.axiom.mime.MultipartWriterFactory;
-import org.apache.axiom.mime.impl.axiom.AxiomMultipartWriterFactory;
 import org.apache.axiom.om.impl.MTOMConstants;
 import org.apache.axiom.om.util.StAXWriterConfiguration;
 import org.apache.axiom.soap.SOAP11Constants;
@@ -72,8 +70,6 @@ public class OMOutputFormat {
     
     private StAXWriterConfiguration writerConfiguration;
     
-    private MultipartWriterFactory multipartWriterFactory;
-
     // The value of this property is a Boolean.  
     // A missing value indicates the default action, which is Boolean.FALSE
     // If Boolean.TRUE, attachments that are "non textual" are written out with 
@@ -129,7 +125,6 @@ public class OMOutputFormat {
         ignoreXMLDeclaration = format.ignoreXMLDeclaration;
         autoCloseWriter = format.autoCloseWriter;
         writerConfiguration = format.writerConfiguration;
-        multipartWriterFactory = format.multipartWriterFactory;
         if (format.map != null) {
             map = new HashMap<String,Object>(format.map);
         }
@@ -477,31 +472,4 @@ public class OMOutputFormat {
     public void setStAXWriterConfiguration(StAXWriterConfiguration writerConfiguration) {
         this.writerConfiguration = writerConfiguration;
     }
-
-    /**
-     * Get the currently configured multipart writer factory.
-     * 
-     * @return the current factory; if none has been set explicitly, an
-     *         {@link AxiomMultipartWriterFactory} instance is returned
-     * 
-     * @deprecated
-     */
-    public MultipartWriterFactory getMultipartWriterFactory() {
-        return multipartWriterFactory == null
-                ? AxiomMultipartWriterFactory.INSTANCE
-                : multipartWriterFactory;
-    }
-
-    /**
-     * Set the multipart writer factory. This factory is used to create MIME packages when MTOM or
-     * SwA is enabled.
-     * 
-     * @param multipartWriterFactory
-     *            the factory
-     * 
-     * @deprecated
-     */
-    public void setMultipartWriterFactory(MultipartWriterFactory multipartWriterFactory) {
-        this.multipartWriterFactory = multipartWriterFactory;
-    }
 }

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/impl/OMMultipartWriter.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/impl/OMMultipartWriter.java?rev=1786217&r1=1786216&r2=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/impl/OMMultipartWriter.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/om/impl/OMMultipartWriter.java Thu Mar  9 19:05:46 2017
@@ -27,7 +27,7 @@ import javax.activation.DataHandler;
 
 import org.apache.axiom.attachments.ConfigurableDataHandler;
 import org.apache.axiom.mime.Header;
-import org.apache.axiom.mime.MultipartWriter;
+import org.apache.axiom.mime.MultipartBodyWriter;
 import org.apache.axiom.om.OMOutputFormat;
 import org.apache.axiom.om.util.CommonUtils;
 import org.apache.axiom.soap.SOAP11Constants;
@@ -35,20 +35,19 @@ import org.apache.axiom.soap.SOAP12Const
 
 /**
  * Writes a MIME multipart package as used by XOP/MTOM and SOAP with Attachments. This class wraps a
- * {@link MultipartWriter}, providing a higher level API. In particular it will configure content
+ * {@link MultipartBodyWriter}, providing a higher level API. In particular it will configure content
  * types and content transfer encodings based on information from an {@link OMOutputFormat} object.
  */
 public class OMMultipartWriter {
     private final OMOutputFormat format;
-    private final MultipartWriter writer;
+    private final MultipartBodyWriter writer;
     private final boolean useCTEBase64;
     private final String rootPartContentType;
     
     public OMMultipartWriter(OutputStream out, OMOutputFormat format) {
         this.format = format;
         
-        writer = format.getMultipartWriterFactory().createMultipartWriter(out,
-                format.getMimeBoundary());
+        writer = new MultipartBodyWriter(out, format.getMimeBoundary());
         
         useCTEBase64 = format != null && Boolean.TRUE.equals(
                 format.getProperty(OMOutputFormat.USE_CTE_BASE64_FOR_NON_TEXTUAL_ATTACHMENTS));
@@ -87,7 +86,7 @@ public class OMMultipartWriter {
 
     /**
      * Start writing the root part of the MIME package. This method delegates to
-     * {@link MultipartWriter#writePart(String, String, String)}, but computes the content type,
+     * {@link MultipartBodyWriter#writePart(String, String, String)}, but computes the content type,
      * content transfer encoding and content ID from the {@link OMOutputFormat}.
      * 
      * @return an output stream to write the content of the MIME part
@@ -95,12 +94,12 @@ public class OMMultipartWriter {
      *             if an I/O error occurs when writing to the underlying stream
      */
     public OutputStream writeRootPart() throws IOException {
-        return writer.writePart(rootPartContentType, "binary", format.getRootContentId());
+        return writer.writePart(rootPartContentType, "binary", format.getRootContentId(), null);
     }
 
     /**
      * Start writing an attachment part of the MIME package. This method delegates to
-     * {@link MultipartWriter#writePart(String, String, String)}, but computes the content transfer
+     * {@link MultipartBodyWriter#writePart(String, String, String)}, but computes the content transfer
      * encoding based on the content type and the {@link OMOutputFormat}.
      * 
      * @param contentType
@@ -112,12 +111,12 @@ public class OMMultipartWriter {
      *             if an I/O error occurs when writing to the underlying stream
      */
     public OutputStream writePart(String contentType, String contentID) throws IOException {
-        return writer.writePart(contentType, getContentTransferEncoding(contentType), contentID);
+        return writer.writePart(contentType, getContentTransferEncoding(contentType), contentID, null);
     }
     
     /**
      * Start writing an attachment part of the MIME package. This method delegates to
-     * {@link MultipartWriter#writePart(String, String, String, List)}, but computes the content
+     * {@link MultipartBodyWriter#writePart(String, String, String, List)}, but computes the content
      * transfer encoding based on the content type and the {@link OMOutputFormat}.
      * 
      * @param contentType
@@ -136,7 +135,7 @@ public class OMMultipartWriter {
     
     /**
      * Write a MIME part. This method delegates to
-     * {@link MultipartWriter#writePart(DataHandler, String, String, List)}, but computes the
+     * {@link MultipartBodyWriter#writePart(DataHandler, String, String, List)}, but computes the
      * appropriate content transfer encoding from the {@link OMOutputFormat}.
      * 
      * @param dataHandler
@@ -161,7 +160,7 @@ public class OMMultipartWriter {
     
     /**
      * Write a MIME part. This method delegates to
-     * {@link MultipartWriter#writePart(DataHandler, String, String)}, but computes the appropriate
+     * {@link MultipartBodyWriter#writePart(DataHandler, String, String)}, but computes the appropriate
      * content transfer encoding from the {@link OMOutputFormat}.
      * 
      * @param dataHandler
@@ -177,7 +176,7 @@ public class OMMultipartWriter {
 
     /**
      * Complete writing of the MIME multipart package. This method delegates to
-     * {@link MultipartWriter#complete()}.
+     * {@link MultipartBodyWriter#complete()}.
      * 
      * @throws IOException
      *             if an I/O error occurs when writing to the underlying stream

Copied: webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/MultipartBodyWriterTest.java (from r1786216, webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/MultipartBodyWriterTest.java?p2=webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/MultipartBodyWriterTest.java&p1=webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java&r1=1786216&r2=1786217&rev=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/AbstractMultipartWriterTest.java (original)
+++ webservices/axiom/trunk/axiom-api/src/test/java/org/apache/axiom/mime/MultipartBodyWriterTest.java Thu Mar  9 19:05:46 2017
@@ -31,20 +31,14 @@ import org.apache.axiom.util.UIDGenerato
 
 import junit.framework.TestCase;
 
-public abstract class AbstractMultipartWriterTest extends TestCase {
-    private final MultipartWriterFactory factory;
-
-    public AbstractMultipartWriterTest(MultipartWriterFactory factory) {
-        this.factory = factory;
-    }
-    
+public class MultipartBodyWriterTest extends TestCase {
     private void test(String contentTransferEncoding) throws Exception {
         Random random = new Random();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        MultipartWriter mpw = factory.createMultipartWriter(baos, UIDGenerator.generateMimeBoundary());
+        MultipartBodyWriter mpw = new MultipartBodyWriter(baos, UIDGenerator.generateMimeBoundary());
         byte[] content = new byte[8192];
         random.nextBytes(content);
-        OutputStream partOutputStream = mpw.writePart("application/octet-stream", contentTransferEncoding, UIDGenerator.generateContentId());
+        OutputStream partOutputStream = mpw.writePart("application/octet-stream", contentTransferEncoding, UIDGenerator.generateContentId(), null);
         partOutputStream.write(content);
         partOutputStream.close();
         mpw.complete();

Copied: webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriter.java (from r1786216, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriter.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriter.java?p2=webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriter.java&p1=webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriter.java&r1=1786216&r2=1786217&rev=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriter.java (original)
+++ webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriter.java Thu Mar  9 19:05:46 2017
@@ -49,6 +49,8 @@ import javax.activation.DataHandler;
  *       It is the responsibility of the implementation to properly format the value
  *       of the <tt>Content-ID</tt> header.</li>
  * </ul>
+ * 
+ * @deprecated Use {@link MultipartBodyWriter} instead.
  */
 public interface MultipartWriter {
     /**

Copied: webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java (from r1786216, webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java?p2=webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java&p1=webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java&r1=1786216&r2=1786217&rev=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java (original)
+++ webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/MultipartWriterFactory.java Thu Mar  9 19:05:46 2017
@@ -23,6 +23,8 @@ import java.io.OutputStream;
 
 /**
  * Factory for {@link MultipartWriter} instances.
+ * 
+ * @deprecated
  */
 public interface MultipartWriterFactory {
     /**

Modified: webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/AxiomMultipartWriterFactory.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/AxiomMultipartWriterFactory.java?rev=1786217&r1=1786216&r2=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/AxiomMultipartWriterFactory.java (original)
+++ webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/AxiomMultipartWriterFactory.java Thu Mar  9 19:05:46 2017
@@ -25,6 +25,8 @@ import org.apache.axiom.mime.MultipartWr
 
 /**
  * Factory for Axiom's own {@link MultipartWriter} implementation.
+ * 
+ * @deprecated
  */
 public class AxiomMultipartWriterFactory implements MultipartWriterFactory {
     public static final MultipartWriterFactory INSTANCE = new AxiomMultipartWriterFactory();

Modified: webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java?rev=1786217&r1=1786216&r2=1786217&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java (original)
+++ webservices/axiom/trunk/axiom-compat/src/main/java/org/apache/axiom/mime/impl/axiom/MultipartWriterImpl.java Thu Mar  9 19:05:46 2017
@@ -25,130 +25,45 @@ import java.util.List;
 import javax.activation.DataHandler;
 
 import org.apache.axiom.mime.Header;
+import org.apache.axiom.mime.MultipartBodyWriter;
 import org.apache.axiom.mime.MultipartWriter;
-import org.apache.axiom.util.base64.Base64EncodingOutputStream;
 
+/**
+ * @deprecated
+ */
 class MultipartWriterImpl implements MultipartWriter {
-    class PartOutputStream extends OutputStream {
-        private final OutputStream parent;
-
-        public PartOutputStream(OutputStream parent) {
-            this.parent = parent;
-        }
-
-        @Override
-        public void write(int b) throws IOException {
-            parent.write(b);
-        }
-
-        @Override
-        public void write(byte[] b, int off, int len) throws IOException {
-            parent.write(b, off, len);
-        }
-
-        @Override
-        public void write(byte[] b) throws IOException {
-            parent.write(b);
-        }
-        
-        @Override
-        public void close() throws IOException {
-            if (parent instanceof Base64EncodingOutputStream) {
-                ((Base64EncodingOutputStream)parent).complete();
-            }
-            writeAscii("\r\n");
-        }
-    }
-    
-    private final OutputStream out;
-    private final String boundary;
-    private final byte[] buffer = new byte[256];
+    private final MultipartBodyWriter writer;
 
     public MultipartWriterImpl(OutputStream out, String boundary) {
-        this.out = out;
-        this.boundary = boundary;
+        writer = new MultipartBodyWriter(out, boundary);
     }
 
-    void writeAscii(String s) throws IOException {
-        int count = 0;
-        for (int i=0, len=s.length(); i<len; i++) {
-            char c = s.charAt(i);
-            if (c >= 128) {
-                throw new IOException("Illegal character '" + c + "'");
-            }
-            buffer[count++] = (byte)c;
-            if (count == buffer.length) {
-                out.write(buffer);
-                count = 0;
-            }
-        }
-        if (count > 0) {
-            out.write(buffer, 0, count);
-        }
-    }
-    
     @Override
     public OutputStream writePart(String contentType, String contentTransferEncoding,
             String contentID, List<Header> extraHeaders) throws IOException {
-        OutputStream transferEncoder;
-        if (contentTransferEncoding.equals("8bit") || contentTransferEncoding.equals("binary")) {
-            transferEncoder = out;
-        } else {
-            // We support no content transfer encodings other than 8bit, binary and base64.
-            transferEncoder = new Base64EncodingOutputStream(out);
-            contentTransferEncoding = "base64";
-        }
-        writeAscii("--");
-        writeAscii(boundary);
-        // TODO: specify if contentType == null is legal and check what to do
-        if (contentType != null) {
-            writeAscii("\r\nContent-Type: ");
-            writeAscii(contentType);
-        }
-        writeAscii("\r\nContent-Transfer-Encoding: ");
-        writeAscii(contentTransferEncoding);
-        // TODO: specify that the content ID may be null
-        if (contentID != null) {
-            writeAscii("\r\nContent-ID: <");
-            writeAscii(contentID);
-            out.write('>');
-        }
-        if (extraHeaders != null) {
-            for (Header header : extraHeaders) {
-                writeAscii("\r\n");
-                writeAscii(header.getName());
-                writeAscii(": ");
-                writeAscii(header.getValue());
-            }
-        }
-        writeAscii("\r\n\r\n");
-        return new PartOutputStream(transferEncoder);
+        return writer.writePart(contentType, contentTransferEncoding, contentID, extraHeaders);
     }
     
     @Override
     public OutputStream writePart(String contentType, String contentTransferEncoding,
             String contentID) throws IOException {    	
-        return writePart(contentType, contentTransferEncoding, contentID, null);
+        return writer.writePart(contentType, contentTransferEncoding, contentID, null);
     }
     
     @Override
     public void writePart(DataHandler dataHandler, String contentTransferEncoding, String contentID, List<Header> extraHeaders)
             throws IOException {
-        OutputStream partOutputStream = writePart(dataHandler.getContentType(), contentTransferEncoding, contentID, extraHeaders);
-        dataHandler.writeTo(partOutputStream);
-        partOutputStream.close();
+        writer.writePart(dataHandler, contentTransferEncoding, contentID, extraHeaders);
     }
     
     @Override
     public void writePart(DataHandler dataHandler, String contentTransferEncoding,
             String contentID) throws IOException {
-        writePart(dataHandler, contentTransferEncoding, contentID, null);
+        writer.writePart(dataHandler, contentTransferEncoding, contentID, null);
     }
 
     @Override
     public void complete() throws IOException {
-        writeAscii("--");
-        writeAscii(boundary);
-        writeAscii("--\r\n");
+        writer.complete();
     }
 }