You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mime4j-dev@james.apache.org by ol...@apache.org on 2014/07/17 10:07:32 UTC

svn commit: r1611278 - in /james/mime4j/trunk: dom/src/main/java/org/apache/james/mime4j/message/ examples/src/main/java/org/apache/james/mime4j/samples/dom/ examples/src/main/java/org/apache/james/mime4j/samples/transform/

Author: olegk
Date: Thu Jul 17 08:07:31 2014
New Revision: 1611278

URL: http://svn.apache.org/r1611278
Log:
Extended new builder classes with methods to create copies of message elements and to parse message from content stream

Modified:
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntityBuilder.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/BodyPartBuilder.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MultipartBuilder.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/SingleBodyBuilder.java
    james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
    james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/transform/TransformMessage.java

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntityBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntityBuilder.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntityBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntityBuilder.java Thu Jul 17 08:07:31 2014
@@ -19,8 +19,6 @@
 
 package org.apache.james.mime4j.message;
 
-import java.io.IOException;
-import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -39,7 +37,6 @@ import org.apache.james.mime4j.dom.field
 import org.apache.james.mime4j.dom.field.FieldName;
 import org.apache.james.mime4j.dom.field.ParsedField;
 import org.apache.james.mime4j.field.Fields;
-import org.apache.james.mime4j.io.InputStreams;
 import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.NameValuePair;
 import org.apache.james.mime4j.util.MimeUtil;
@@ -51,8 +48,6 @@ abstract class AbstractEntityBuilder {
 
     private Body body;
 
-    private BodyFactory bodyFactory;
-
     AbstractEntityBuilder() {
         this.fields = new LinkedList<Field>();
         this.fieldMap = new HashMap<String, List<Field>>();
@@ -189,6 +184,15 @@ abstract class AbstractEntityBuilder {
         return this;
     }
 
+    /**
+     * Clears all fields.
+     */
+    public AbstractEntityBuilder clearFields() {
+        fields.clear();
+        fieldMap.clear();
+        return this;
+    }
+
     @SuppressWarnings("unchecked")
     <F extends ParsedField> F obtainField(String fieldName) {
         return (F) getField(fieldName);
@@ -454,59 +458,6 @@ abstract class AbstractEntityBuilder {
     }
 
     /**
-     * Sets {@link org.apache.james.mime4j.message.BodyFactory} that will be
-     * used to generate message body.
-     *
-     * @param bodyFactory body factory.
-     */
-    public AbstractEntityBuilder use(final BodyFactory bodyFactory) {
-        this.bodyFactory = bodyFactory;
-        return this;
-    }
-
-    /**
-     * Sets text of this message with the charset.
-     *
-     * @param text
-     *            the text.
-     * @param charset
-     *            the charset of the text.
-     */
-    public AbstractEntityBuilder setBody(String text, Charset charset) throws IOException {
-        return setBody(text, null, charset);
-    }
-
-    /**
-     * Sets text of this message with the given MIME subtype and charset.
-     *
-     * @param text
-     *            the text.
-     * @param charset
-     *            the charset of the text.
-     * @param subtype
-     *            the text subtype (e.g. &quot;plain&quot;, &quot;html&quot; or
-     *            &quot;xml&quot;).
-     */
-    public AbstractEntityBuilder setBody(String text, String subtype, Charset charset) throws IOException {
-        if (subtype != null) {
-            if (charset != null) {
-                setField(Fields.contentType("text/" + subtype, new NameValuePair("charset", charset.name())));
-            } else {
-                setField(Fields.contentType("text/" + subtype));
-            }
-        }
-        TextBody textBody;
-        if (bodyFactory != null) {
-            textBody = bodyFactory.textBody(
-                    InputStreams.create(text, charset),
-                    charset != null ? charset.name() : null);
-        } else {
-            textBody = BasicBodyFactory.INSTANCE.textBody(text, charset);
-        }
-        return setBody(textBody);
-    }
-
-    /**
      * Returns message body.
      *
      * @return the message body.

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/BodyPartBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/BodyPartBuilder.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/BodyPartBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/BodyPartBuilder.java Thu Jul 17 08:07:31 2014
@@ -23,8 +23,11 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.Date;
 
+import org.apache.james.mime4j.dom.BinaryBody;
 import org.apache.james.mime4j.dom.Body;
-import org.apache.james.mime4j.dom.Header;
+import org.apache.james.mime4j.dom.TextBody;
+import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.io.InputStreams;
 import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.NameValuePair;
 
@@ -33,10 +36,23 @@ import org.apache.james.mime4j.stream.Na
  */
 public class BodyPartBuilder extends AbstractEntityBuilder {
 
+    private BodyFactory bodyFactory;
+
     public static BodyPartBuilder create() {
         return new BodyPartBuilder();
     }
 
+    /**
+     * Sets {@link org.apache.james.mime4j.message.BodyFactory} that will be
+     * used to generate message body.
+     *
+     * @param bodyFactory body factory.
+     */
+    public BodyPartBuilder use(BodyFactory bodyFactory) {
+        this.bodyFactory = bodyFactory;
+        return this;
+    }
+
     @Override
     public BodyPartBuilder setField(Field field) {
         super.setField(field);
@@ -102,22 +118,68 @@ public class BodyPartBuilder extends Abs
         return this;
     }
 
-    @Override
-    public BodyPartBuilder use(final BodyFactory bodyFactory) {
-        super.use(bodyFactory);
-        return this;
-    }
-
-    @Override
+    /**
+     * Sets text of this message with the charset.
+     *
+     * @param text
+     *            the text.
+     * @param charset
+     *            the charset of the text.
+     */
     public BodyPartBuilder setBody(String text, Charset charset) throws IOException {
-        super.setBody(text, charset);
-        return this;
+        return setBody(text, null, charset);
     }
 
-    @Override
+    /**
+     * Sets text of this message with the given MIME subtype and charset.
+     *
+     * @param text
+     *            the text.
+     * @param charset
+     *            the charset of the text.
+     * @param subtype
+     *            the text subtype (e.g. &quot;plain&quot;, &quot;html&quot; or
+     *            &quot;xml&quot;).
+     */
     public BodyPartBuilder setBody(String text, String subtype, Charset charset) throws IOException {
-        super.setBody(text, subtype, charset);
-        return this;
+        if (subtype != null) {
+            if (charset != null) {
+                setField(Fields.contentType("text/" + subtype, new NameValuePair("charset", charset.name())));
+            } else {
+                setField(Fields.contentType("text/" + subtype));
+            }
+        }
+        TextBody textBody;
+        if (bodyFactory != null) {
+            textBody = bodyFactory.textBody(
+                    InputStreams.create(text, charset),
+                    charset != null ? charset.name() : null);
+        } else {
+            textBody = BasicBodyFactory.INSTANCE.textBody(text, charset);
+        }
+        return setBody(textBody);
+    }
+
+    /**
+     * Sets binary content of this message with the given MIME type.
+     *
+     * @param body
+     *            the body.
+     * @param mimeType
+     *            the MIME media type of the specified body
+     *            (&quot;type/subtype&quot;).
+     */
+    public BodyPartBuilder setBody(byte[] bin, String mimeType) throws IOException {
+        if (mimeType != null) {
+            setField(Fields.contentType(mimeType));
+        }
+        BinaryBody binBody;
+        if (bodyFactory != null) {
+            binBody = bodyFactory.binaryBody(InputStreams.create(bin));
+        } else {
+            binBody = BasicBodyFactory.INSTANCE.binaryBody(bin);
+        }
+        return setBody(binBody);
     }
 
     public BodyPart build() {

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java Thu Jul 17 08:07:31 2014
@@ -20,6 +20,7 @@
 package org.apache.james.mime4j.message;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,9 +30,17 @@ import java.util.Date;
 import java.util.List;
 import java.util.TimeZone;
 
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.BinaryBody;
 import org.apache.james.mime4j.dom.Body;
+import org.apache.james.mime4j.dom.FieldParser;
 import org.apache.james.mime4j.dom.Header;
 import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.dom.Multipart;
+import org.apache.james.mime4j.dom.SingleBody;
+import org.apache.james.mime4j.dom.TextBody;
 import org.apache.james.mime4j.dom.address.Address;
 import org.apache.james.mime4j.dom.address.AddressList;
 import org.apache.james.mime4j.dom.address.Mailbox;
@@ -43,9 +52,15 @@ import org.apache.james.mime4j.dom.field
 import org.apache.james.mime4j.dom.field.MailboxListField;
 import org.apache.james.mime4j.dom.field.ParseException;
 import org.apache.james.mime4j.dom.field.UnstructuredField;
+import org.apache.james.mime4j.field.DefaultFieldParser;
 import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.field.LenientFieldParser;
 import org.apache.james.mime4j.field.address.AddressBuilder;
+import org.apache.james.mime4j.io.InputStreams;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
 import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.stream.MimeConfig;
 import org.apache.james.mime4j.stream.NameValuePair;
 
 /**
@@ -53,10 +68,112 @@ import org.apache.james.mime4j.stream.Na
  */
 public class MessageBuilder extends AbstractEntityBuilder {
 
+    private MimeConfig config;
+    private DecodeMonitor monitor;
+    private BodyDescriptorBuilder bodyDescBuilder;
+    private FieldParser<?> fieldParser;
+    private BodyFactory bodyFactory;
+    private boolean flatMode;
+    private boolean rawContent;
+
     public static MessageBuilder create() {
         return new MessageBuilder();
     }
 
+    public static MessageBuilder createCopy(Message other) {
+        return new MessageBuilder().copy(other);
+    }
+
+    public static MessageBuilder read(final InputStream is) throws IOException {
+        return new MessageBuilder().parse(is);
+    }
+
+    /**
+     * Sets MIME configuration.
+     *
+     * @param config the configuration.
+     */
+    public MessageBuilder use(MimeConfig config) {
+        this.config = config;
+        return this;
+    }
+
+    /**
+     * Sets {@link org.apache.james.mime4j.codec.DecodeMonitor} that will be
+     * used to handle malformed data when executing {@link #parse(java.io.InputStream)}.
+     *
+     * @param monitor the decoder monitor.
+     */
+    public MessageBuilder use(DecodeMonitor monitor) {
+        this.monitor = monitor;
+        return this;
+    }
+
+    /**
+     * Sets {@link org.apache.james.mime4j.stream.BodyDescriptorBuilder} that will be
+     * used to generate body descriptors when executing {@link #parse(java.io.InputStream)}.
+     *
+     * @param bodyDescBuilder the body descriptor builder.
+     */
+    public MessageBuilder use(BodyDescriptorBuilder bodyDescBuilder) {
+        this.bodyDescBuilder = bodyDescBuilder;
+        return this;
+    }
+
+    /**
+     * Sets {@link org.apache.james.mime4j.dom.FieldParser} that will be
+     * used to generate parse message fields when executing {@link #parse(java.io.InputStream)}.
+     *
+     * @param fieldParser the field parser.
+     */
+    public MessageBuilder use(FieldParser<?> fieldParser) {
+        this.fieldParser = fieldParser;
+        return this;
+    }
+
+    /**
+     * Sets {@link org.apache.james.mime4j.message.BodyFactory} that will be
+     * used to generate message body.
+     *
+     * @param bodyFactory the body factory.
+     */
+    public MessageBuilder use(BodyFactory bodyFactory) {
+        this.bodyFactory = bodyFactory;
+        return this;
+    }
+
+    /**
+     * Enables flat parsing mode for {@link #parse(java.io.InputStream)} operation.
+     */
+    public MessageBuilder enableFlatMode() {
+        this.flatMode = true;
+        return this;
+    }
+
+    /**
+     * Disables flat parsing mode for {@link #parse(java.io.InputStream)} operation.
+     */
+    public MessageBuilder disableFlatMode() {
+        this.flatMode = false;
+        return this;
+    }
+
+    /**
+     * Enables automatic content decoding for {@link #parse(java.io.InputStream)} operation.
+     */
+    public MessageBuilder enableContentDecoding() {
+        this.rawContent = false;
+        return this;
+    }
+
+    /**
+     * Enables disable content decoding for {@link #parse(java.io.InputStream)} operation.
+     */
+    public MessageBuilder disableContentDecoding() {
+        this.rawContent = true;
+        return this;
+    }
+
     @Override
     public MessageBuilder setField(Field field) {
         super.setField(field);
@@ -76,6 +193,12 @@ public class MessageBuilder extends Abst
     }
 
     @Override
+    public AbstractEntityBuilder clearFields() {
+        super.clearFields();
+        return this;
+    }
+
+    @Override
     public MessageBuilder setContentTransferEncoding(String contentTransferEncoding) {
         super.setContentTransferEncoding(contentTransferEncoding);
         return this;
@@ -118,22 +241,68 @@ public class MessageBuilder extends Abst
         return this;
     }
 
-    @Override
-    public MessageBuilder use(final BodyFactory bodyFactory) {
-        super.use(bodyFactory);
-        return this;
-    }
-
-    @Override
+    /**
+     * Sets text of this message with the charset.
+     *
+     * @param text
+     *            the text.
+     * @param charset
+     *            the charset of the text.
+     */
     public MessageBuilder setBody(String text, Charset charset) throws IOException {
-        super.setBody(text, charset);
-        return this;
+        return setBody(text, null, charset);
     }
 
-    @Override
+    /**
+     * Sets text of this message with the given MIME subtype and charset.
+     *
+     * @param text
+     *            the text.
+     * @param charset
+     *            the charset of the text.
+     * @param subtype
+     *            the text subtype (e.g. &quot;plain&quot;, &quot;html&quot; or
+     *            &quot;xml&quot;).
+     */
     public MessageBuilder setBody(String text, String subtype, Charset charset) throws IOException {
-        super.setBody(text, subtype, charset);
-        return this;
+        if (subtype != null) {
+            if (charset != null) {
+                setField(Fields.contentType("text/" + subtype, new NameValuePair("charset", charset.name())));
+            } else {
+                setField(Fields.contentType("text/" + subtype));
+            }
+        }
+        TextBody textBody;
+        if (bodyFactory != null) {
+            textBody = bodyFactory.textBody(
+                    InputStreams.create(text, charset),
+                    charset != null ? charset.name() : null);
+        } else {
+            textBody = BasicBodyFactory.INSTANCE.textBody(text, charset);
+        }
+        return setBody(textBody);
+    }
+
+    /**
+     * Sets binary content of this message with the given MIME type.
+     *
+     * @param body
+     *            the body.
+     * @param mimeType
+     *            the MIME media type of the specified body
+     *            (&quot;type/subtype&quot;).
+     */
+    public MessageBuilder setBody(byte[] bin, String mimeType) throws IOException {
+        if (mimeType != null) {
+            setField(Fields.contentType(mimeType));
+        }
+        BinaryBody binBody;
+        if (bodyFactory != null) {
+            binBody = bodyFactory.binaryBody(InputStreams.create(bin));
+        } else {
+            binBody = BasicBodyFactory.INSTANCE.binaryBody(bin);
+        }
+        return setBody(binBody);
     }
 
     /**
@@ -676,9 +845,65 @@ public class MessageBuilder extends Abst
         return this;
     }
 
+    public MessageBuilder copy(Message other) {
+        if (other == null) {
+            return this;
+        }
+        clearFields();
+        final Header otherHeader = other.getHeader();
+        if (otherHeader != null) {
+            final List<Field> otherFields = otherHeader.getFields();
+            for (Field field: otherFields) {
+                addField(field);
+            }
+        }
+        Body body = null;
+        Body otherBody = other.getBody();
+        if (otherBody instanceof Message) {
+            body = MessageBuilder.createCopy((Message) otherBody).build();
+        } else if (otherBody instanceof Multipart) {
+            body = MultipartBuilder.createCopy((Multipart) otherBody).build();
+        } else if (otherBody instanceof SingleBody) {
+            body = ((SingleBody) otherBody).copy();
+        }
+        setBody(body);
+        return this;
+    }
+
+    public MessageBuilder parse(final InputStream is) throws IOException {
+        MimeConfig currentConfig = config != null ? config : MimeConfig.DEFAULT;
+        boolean strict = currentConfig.isStrictParsing();
+        DecodeMonitor currentMonitor = monitor != null ? monitor : strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT;
+        BodyDescriptorBuilder currentBodyDescBuilder = bodyDescBuilder != null ? bodyDescBuilder :
+                new DefaultBodyDescriptorBuilder(null, fieldParser != null ? fieldParser :
+                        strict ? DefaultFieldParser.getParser() : LenientFieldParser.getParser(), currentMonitor);
+        BodyFactory currentBodyFactory = bodyFactory != null ? bodyFactory : new BasicBodyFactory();
+        MimeStreamParser parser = new MimeStreamParser(currentConfig, currentMonitor, currentBodyDescBuilder);
+
+        Message message = new MessageImpl();
+        parser.setContentHandler(new EntityBuilder(message, currentBodyFactory));
+        parser.setContentDecoding(!rawContent);
+        if (flatMode) {
+            parser.setFlat();
+        }
+        try {
+            parser.parse(is);
+        } catch (MimeException e) {
+            throw new MimeIOException(e);
+        }
+        clearFields();
+        final List<Field> fields = message.getHeader().getFields();
+        for (Field field: fields) {
+            addField(field);
+        }
+        setBody(message.getBody());
+        return this;
+    }
+
     public Message build() {
         MessageImpl message = new MessageImpl();
-        Header header = message.getHeader();
+        HeaderImpl header = new HeaderImpl();
+        message.setHeader(header);
         if (!containsField(FieldName.MIME_VERSION)) {
             header.setField(Fields.version("1.0"));
         }

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MultipartBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MultipartBuilder.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MultipartBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MultipartBuilder.java Thu Jul 17 08:07:31 2014
@@ -19,12 +19,22 @@
 
 package org.apache.james.mime4j.message;
 
+import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.james.mime4j.Charsets;
+import org.apache.james.mime4j.dom.Body;
 import org.apache.james.mime4j.dom.Entity;
+import org.apache.james.mime4j.dom.Header;
+import org.apache.james.mime4j.dom.Message;
 import org.apache.james.mime4j.dom.Multipart;
+import org.apache.james.mime4j.dom.SingleBody;
+import org.apache.james.mime4j.dom.TextBody;
+import org.apache.james.mime4j.io.InputStreams;
+import org.apache.james.mime4j.stream.Field;
 
 /**
  * {@link org.apache.james.mime4j.dom.Multipart} builder.
@@ -36,10 +46,16 @@ public class MultipartBuilder {
     private String preamble;
     private String epilogue;
 
+    private BodyFactory bodyFactory;
+
     public static MultipartBuilder create(String subType) {
         return new MultipartBuilder().setSubType(subType);
     }
 
+    public static MultipartBuilder createCopy(Multipart other) {
+        return new MultipartBuilder().copy(other);
+    }
+
     public static MultipartBuilder create() {
         return new MultipartBuilder();
     }
@@ -48,6 +64,11 @@ public class MultipartBuilder {
         this.bodyParts = new LinkedList<Entity>();
     }
 
+    public MultipartBuilder use(final BodyFactory bodyFactory) {
+        this.bodyFactory = bodyFactory;
+        return this;
+    }
+
     /**
      * Gets the multipart sub-type. E.g. <code>alternative</code> (the
      * default) or <code>parallel</code>. See RFC 2045 for common sub-types
@@ -194,6 +215,53 @@ public class MultipartBuilder {
         return this;
     }
 
+    public MultipartBuilder addTextPart(String text, Charset charset) throws IOException {
+        Charset cs = charset != null ? charset : Charsets.ISO_8859_1;
+        TextBody body = bodyFactory != null ? bodyFactory.textBody(
+                InputStreams.create(text, cs), cs.name()) : BasicBodyFactory.INSTANCE.textBody(text, cs);
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setText(body);
+        bodyPart.setContentTransferEncoding("quoted-printable");
+
+        return addBodyPart(bodyPart);
+    }
+
+    public MultipartBuilder copy(Multipart other) {
+        if (other == null) {
+            return this;
+        }
+        subType = other.getSubType();
+        bodyParts.clear();
+        final List<Entity> otherParts = other.getBodyParts();
+        for (Entity otherPart: otherParts) {
+            BodyPart bodyPart = new BodyPart();
+            Header otherHeader = otherPart.getHeader();
+            if (otherHeader != null) {
+                HeaderImpl header = new HeaderImpl();
+                for (Field otherField : otherHeader.getFields()) {
+                    header.addField(otherField);
+                }
+                bodyPart.setHeader(header);
+            }
+            final Body otherBody = otherPart.getBody();
+            if (otherBody != null) {
+                Body body = null;
+                if (otherBody instanceof Message) {
+                    body = MessageBuilder.createCopy((Message) otherBody).build();
+                } else if (otherBody instanceof Multipart) {
+                    body = MultipartBuilder.createCopy((Multipart) otherBody).build();
+                } else if (otherBody instanceof SingleBody) {
+                    body = ((SingleBody) otherBody).copy();
+                }
+                bodyPart.setBody(body);
+            }
+            bodyParts.add(bodyPart);
+        }
+        preamble = other.getPreamble();
+        epilogue = other.getEpilogue();
+        return this;
+    }
+
     public Multipart build() {
         MultipartImpl multipart = new MultipartImpl(subType);
         for (Entity part : bodyParts) {

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/SingleBodyBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/SingleBodyBuilder.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/SingleBodyBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/SingleBodyBuilder.java Thu Jul 17 08:07:31 2014
@@ -22,13 +22,17 @@ package org.apache.james.mime4j.message;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
 
 import org.apache.james.mime4j.Charsets;
 import org.apache.james.mime4j.dom.BinaryBody;
 import org.apache.james.mime4j.dom.SingleBody;
 import org.apache.james.mime4j.dom.TextBody;
 import org.apache.james.mime4j.io.InputStreams;
+import org.apache.james.mime4j.util.CharsetUtil;
 import org.apache.james.mime4j.util.ContentUtil;
 
 /**
@@ -40,12 +44,16 @@ public class SingleBodyBuilder {
         return new SingleBodyBuilder();
     }
 
-    private BodyFactory bodyFactory;
+    public static SingleBodyBuilder createCopy(final SingleBody other) throws IOException {
+        return new SingleBodyBuilder().copy(other);
+    }
 
     private String text;
     private byte[] bin;
     private Charset charset;
 
+    private BodyFactory bodyFactory;
+
     SingleBodyBuilder() {
         super();
     }
@@ -84,6 +92,26 @@ public class SingleBodyBuilder {
         return this;
     }
 
+    public SingleBodyBuilder copy(final SingleBody other) throws IOException {
+        if (other == null) {
+            return this;
+        }
+        if (other instanceof TextBody) {
+            String charsetName = ((TextBody) other).getMimeCharset();
+            if (charsetName != null) {
+                try {
+                    this.charset = Charset.forName(charsetName);
+                } catch (IllegalCharsetNameException ex) {
+                    throw new UnsupportedEncodingException(charsetName);
+                } catch (UnsupportedCharsetException ex) {
+                    throw new UnsupportedEncodingException(charsetName);
+                }
+            }
+        }
+        this.bin = ContentUtil.buffer(other.getInputStream());
+        return this;
+    }
+
     public TextBody buildText() throws IOException {
         Charset cs = this.charset != null ? this.charset : Charsets.DEFAULT_CHARSET;
         if (this.bodyFactory != null) {

Modified: james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java (original)
+++ james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java Thu Jul 17 08:07:31 2014
@@ -61,21 +61,23 @@ public class MultipartMessage {
                 .generateMessageId(InetAddress.getLocalHost().getCanonicalHostName())
         // 3) set a multipart body
                 .setBody(MultipartBuilder.create("mixed")
-                        // a multipart may have a preamble
+                        .use(bodyFactory)
+                                // a multipart may have a preamble
                         .setPreamble("This is a multi-part message in MIME format.")
-                        // first part is text/plain
+                                // first part is text/plain
                         .addBodyPart(BodyPartBuilder.create()
                                 .use(bodyFactory)
                                 .setBody("Why so serious?", Charsets.UTF_8)
                                 .setContentTransferEncoding("quoted-printable")
                                 .build())
-                        // second part is image/png (image is created on the fly)
+                                // second part is image/png (image is created on the fly)
                         .addBodyPart(BodyPartBuilder.create()
+                                .use(bodyFactory)
                                 .setBody(createImageBody(bodyFactory, renderSampleImage()))
                                 .setContentType("image/png")
                                 .setContentTransferEncoding("base64")
-                        // Specify a filename in the Content-Disposition header (implicitly sets
-                        // the disposition type to "attachment")
+                                        // Specify a filename in the Content-Disposition header (implicitly sets
+                                        // the disposition type to "attachment")
                                 .setContentDisposition("attachment", "smiley.png")
                                 .build())
                         .build())

Modified: james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/transform/TransformMessage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/transform/TransformMessage.java?rev=1611278&r1=1611277&r2=1611278&view=diff
==============================================================================
--- james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/transform/TransformMessage.java (original)
+++ james/mime4j/trunk/examples/src/main/java/org/apache/james/mime4j/samples/transform/TransformMessage.java Thu Jul 17 08:07:31 2014
@@ -19,26 +19,21 @@
 
 package org.apache.james.mime4j.samples.transform;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.Date;
 import java.util.Random;
 
-import org.apache.james.mime4j.dom.Body;
+import org.apache.james.mime4j.Charsets;
+import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.dom.Entity;
 import org.apache.james.mime4j.dom.Message;
-import org.apache.james.mime4j.dom.MessageBuilder;
 import org.apache.james.mime4j.dom.MessageWriter;
 import org.apache.james.mime4j.dom.Multipart;
-import org.apache.james.mime4j.dom.TextBody;
-import org.apache.james.mime4j.dom.field.ParseException;
-import org.apache.james.mime4j.field.address.AddressBuilder;
 import org.apache.james.mime4j.message.BodyPart;
-import org.apache.james.mime4j.message.MessageImpl;
-import org.apache.james.mime4j.message.DefaultMessageBuilder;
+import org.apache.james.mime4j.message.BodyPartBuilder;
 import org.apache.james.mime4j.message.DefaultMessageWriter;
-import org.apache.james.mime4j.message.MultipartImpl;
-import org.apache.james.mime4j.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.message.MessageBuilder;
+import org.apache.james.mime4j.message.MultipartBuilder;
 import org.apache.james.mime4j.storage.StorageBodyFactory;
 import org.apache.james.mime4j.storage.StorageProvider;
 import org.apache.james.mime4j.storage.TempFileStorageProvider;
@@ -56,59 +51,50 @@ public class TransformMessage {
         // Explicitly set a strategy for storing body parts. Usually not
         // necessary; for most applications the default setting is appropriate.
         StorageProvider storageProvider = new TempFileStorageProvider();
-        DefaultStorageProvider.setInstance(storageProvider);
+        StorageBodyFactory bodyFactory = new StorageBodyFactory(storageProvider, DecodeMonitor.SILENT);
 
         // Create a template message. It would be possible to load a message
         // from an input stream but for this example a message object is created
         // from scratch for demonstration purposes.
-        Message template = createTemplate();
+        Message template = MessageBuilder.create()
+                .setBody(MultipartBuilder.create("mixed")
+                        .addBodyPart(BodyPartBuilder.create()
+                                .use(bodyFactory)
+                                .setBody("This is the first part of the template..", Charsets.UTF_8)
+                                .setContentTransferEncoding("quoted-printable")
+                                .build())
+                        .addBodyPart(BodyPartBuilder.create()
+                                .use(bodyFactory)
+                                .setBody(createRandomBinary(200), "application/octet-stream")
+                                .setContentTransferEncoding("base64")
+                                .build())
+                        .addBodyPart(BodyPartBuilder.create()
+                                .use(bodyFactory)
+                                .setBody(createRandomBinary(300), "application/octet-stream")
+                                .setContentTransferEncoding("base64")
+                                .build())
+                        .build())
+                .setSubject("Template message")
+                .build();
 
         // Create a new message by transforming the template.
-        Message transformed = transform(template);
-
-        MessageWriter writer = new DefaultMessageWriter();
-
-        // Print transformed message.
-        System.out.println("\n\nTransformed message:\n--------------------\n");
-        writer.writeMessage(transformed, System.out);
-
-        // Messages should be disposed of when they are no longer needed.
-        // Disposing of a message also disposes of all child elements (e.g. body
-        // parts) of the message.
-        transformed.dispose();
-
-        // Print original message to illustrate that it was not affected by the
-        // transformation.
-        System.out.println("\n\nOriginal template:\n------------------\n");
-        writer.writeMessage(template, System.out);
-
-        // Original message is no longer needed.
-        template.dispose();
-
-        // At this point all temporary files have been deleted because all
-        // messages and body parts have been disposed of properly.
-    }
-
-    /**
-     * Copies the given message and makes some arbitrary changes to the copy.
-     * @throws ParseException on bad arguments
-     */
-    private static Message transform(Message original) throws IOException, ParseException {
         // Create a copy of the template. The copy can be modified without
         // affecting the original.
-        MessageBuilder builder = new DefaultMessageBuilder();
-        Message message = builder.newMessage(original);
-
+        final MessageBuilder messageBuilder = MessageBuilder.createCopy(template);
         // In this example we know we have a multipart message. Use
         // Message#isMultipart() if uncertain.
-        Multipart multipart = (Multipart) message.getBody();
+        Multipart multipart = (Multipart) messageBuilder.getBody();
 
         // Insert a new text/plain body part after every body part of the
         // template.
         final int count = multipart.getCount();
         for (int i = 0; i < count; i++) {
             String text = "Text inserted after part " + (i + 1);
-            BodyPart bodyPart = createTextPart(text);
+            BodyPart bodyPart = BodyPartBuilder.create()
+                    .use(bodyFactory)
+                    .setBody(text, Charsets.UTF_8)
+                    .setContentTransferEncoding("quoted-printable")
+                    .build();
             multipart.addBodyPart(bodyPart, 2 * i + 1);
         }
 
@@ -121,67 +107,41 @@ public class TransformMessage {
         removed.dispose();
 
         // Set some headers on the transformed message
-        message.createMessageId(HOSTNAME);
-        message.setSubject("Transformed message");
-        message.setDate(new Date());
-        message.setFrom(AddressBuilder.DEFAULT.parseMailbox("John Doe <jd...@machine.example>"));
+        messageBuilder.generateMessageId(HOSTNAME);
+        messageBuilder.setSubject("Transformed message");
+        messageBuilder.setDate(new Date());
+        messageBuilder.setFrom("John Doe <jd...@machine.example>");
 
-        return message;
-    }
-
-    /**
-     * Creates a multipart/mixed message that consists of three parts (one text,
-     * two binary).
-     */
-    private static Message createTemplate() throws IOException {
-        Multipart multipart = new MultipartImpl("mixed");
-
-        BodyPart part1 = createTextPart("This is the first part of the template..");
-        multipart.addBodyPart(part1);
+        Message transformed = messageBuilder.build();
 
-        BodyPart part2 = createRandomBinaryPart(200);
-        multipart.addBodyPart(part2);
-
-        BodyPart part3 = createRandomBinaryPart(300);
-        multipart.addBodyPart(part3);
+        MessageWriter writer = new DefaultMessageWriter();
 
-        MessageImpl message = new MessageImpl();
-        message.setMultipart(multipart);
+        // Print transformed message.
+        System.out.println("\n\nTransformed message:\n--------------------\n");
+        writer.writeMessage(transformed, System.out);
 
-        message.setSubject("Template message");
+        // Messages should be disposed of when they are no longer needed.
+        // Disposing of a message also disposes of all child elements (e.g. body
+        // parts) of the message.
+        transformed.dispose();
 
-        return message;
-    }
+        // Print original message to illustrate that it was not affected by the
+        // transformation.
+        System.out.println("\n\nOriginal template:\n------------------\n");
+        writer.writeMessage(template, System.out);
 
-    /**
-     * Creates a text part from the specified string.
-     */
-    private static BodyPart createTextPart(String text) {
-        TextBody body = new StorageBodyFactory().textBody(text, "UTF-8");
-
-        BodyPart bodyPart = new BodyPart();
-        bodyPart.setText(body);
-        bodyPart.setContentTransferEncoding("quoted-printable");
+        // Original message is no longer needed.
+        template.dispose();
 
-        return bodyPart;
+        // At this point all temporary files have been deleted because all
+        // messages and body parts have been disposed of properly.
     }
 
-    /**
-     * Creates a binary part with random content.
-     */
-    private static BodyPart createRandomBinaryPart(int numberOfBytes)
+    private static byte[] createRandomBinary(int numberOfBytes)
             throws IOException {
         byte[] data = new byte[numberOfBytes];
         new Random().nextBytes(data);
-
-        Body body = new StorageBodyFactory()
-                .binaryBody(new ByteArrayInputStream(data));
-
-        BodyPart bodyPart = new BodyPart();
-        bodyPart.setBody(body, "application/octet-stream");
-        bodyPart.setContentTransferEncoding("base64");
-
-        return bodyPart;
+        return data;
     }
 
 }