You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2015/11/13 17:32:37 UTC

[1/4] camel git commit: Fixed CS

Repository: camel
Updated Branches:
  refs/heads/camel-2.16.x 59b54c679 -> b2ce0f990
  refs/heads/master 74eda663a -> 7fb7b5641


Fixed CS


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7fb7b564
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7fb7b564
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7fb7b564

Branch: refs/heads/master
Commit: 7fb7b56413a625ea80830b3a930a7182d13a1565
Parents: 86d08e2
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Nov 13 17:34:54 2015 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Nov 13 17:35:02 2015 +0100

----------------------------------------------------------------------
 .../src/main/java/org/apache/camel/builder/DataFormatClause.java  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/7fb7b564/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java b/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
index 689ef1f..c80f45d 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
@@ -20,6 +20,8 @@ import java.nio.charset.Charset;
 import java.util.Map;
 import java.util.zip.Deflater;
 
+import org.w3c.dom.Node;
+
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.dataformat.AvroDataFormat;
@@ -56,7 +58,6 @@ import org.apache.camel.model.dataformat.ZipDataFormat;
 import org.apache.camel.model.dataformat.ZipFileDataFormat;
 import org.apache.camel.util.CollectionStringBuffer;
 import org.apache.camel.util.jsse.KeyStoreParameters;
-import org.w3c.dom.Node;
 
 /**
  * An expression for constructing the different possible {@link org.apache.camel.spi.DataFormat}


[2/4] camel git commit: Fixed CS

Posted by da...@apache.org.
Fixed CS


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/86d08e2b
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/86d08e2b
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/86d08e2b

Branch: refs/heads/master
Commit: 86d08e2b4c762fb4e2753807abf2603d0a09bbe0
Parents: 08aa98f
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Nov 13 17:33:46 2015 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Nov 13 17:35:02 2015 +0100

----------------------------------------------------------------------
 .../dynamicrouter/DynamicRouterConcurrentPOJOTest.java          | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/86d08e2b/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java b/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
index eb6db04..776c801 100644
--- a/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
+++ b/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
@@ -16,7 +16,10 @@
  */
 package org.apache.camel.processor.dynamicrouter;
 
-import org.apache.camel.*;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.DynamicRouter;
+import org.apache.camel.Exchange;
+import org.apache.camel.Header;
 import org.apache.camel.builder.RouteBuilder;
 
 public class DynamicRouterConcurrentPOJOTest extends ContextTestSupport {


[4/4] camel git commit: Fixed CS

Posted by da...@apache.org.
Fixed CS


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/b2ce0f99
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/b2ce0f99
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/b2ce0f99

Branch: refs/heads/camel-2.16.x
Commit: b2ce0f99032fc8b9f26c97370ce8a794006e2135
Parents: 59b54c6
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Nov 13 17:33:46 2015 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Nov 13 17:35:51 2015 +0100

----------------------------------------------------------------------
 .../dynamicrouter/DynamicRouterConcurrentPOJOTest.java          | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b2ce0f99/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java b/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
index eb6db04..776c801 100644
--- a/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
+++ b/camel-core/src/test/java/org/apache/camel/processor/dynamicrouter/DynamicRouterConcurrentPOJOTest.java
@@ -16,7 +16,10 @@
  */
 package org.apache.camel.processor.dynamicrouter;
 
-import org.apache.camel.*;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.DynamicRouter;
+import org.apache.camel.Exchange;
+import org.apache.camel.Header;
 import org.apache.camel.builder.RouteBuilder;
 
 public class DynamicRouterConcurrentPOJOTest extends ContextTestSupport {


[3/4] camel git commit: CAMEL-9283: Data Format for MIME-Multipart. Thanks to Stephan Siano for the patch.

Posted by da...@apache.org.
CAMEL-9283: Data Format for MIME-Multipart. Thanks to Stephan Siano for the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/08aa98f8
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/08aa98f8
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/08aa98f8

Branch: refs/heads/master
Commit: 08aa98f8bc771b7edf2a51978c94835d0cd3624c
Parents: 74eda66
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Nov 13 16:39:58 2015 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Nov 13 17:35:02 2015 +0100

----------------------------------------------------------------------
 .../apache/camel/builder/DataFormatClause.java  |  63 ++++-
 .../model/dataformat/DataFormatsDefinition.java |   1 +
 .../dataformat/MimeMultipartDataFormat.java     | 124 +++++++++
 .../apache/camel/model/dataformat/jaxb.index    |   1 +
 components/camel-mail/pom.xml                   |   5 +-
 .../mime/multipart/MimeMultipartDataFormat.java | 241 ++++++++++++++++
 .../org/apache/camel/dataformat/mime-multipart  |  18 ++
 .../multipart/MimeMultipartDataFormatTest.java  | 275 +++++++++++++++++++
 8 files changed, 724 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java b/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
index 9495f4c..689ef1f 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java
@@ -20,8 +20,6 @@ import java.nio.charset.Charset;
 import java.util.Map;
 import java.util.zip.Deflater;
 
-import org.w3c.dom.Node;
-
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.dataformat.AvroDataFormat;
@@ -41,6 +39,7 @@ import org.apache.camel.model.dataformat.JaxbDataFormat;
 import org.apache.camel.model.dataformat.JibxDataFormat;
 import org.apache.camel.model.dataformat.JsonDataFormat;
 import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.dataformat.MimeMultipartDataFormat;
 import org.apache.camel.model.dataformat.PGPDataFormat;
 import org.apache.camel.model.dataformat.ProtobufDataFormat;
 import org.apache.camel.model.dataformat.RssDataFormat;
@@ -57,6 +56,7 @@ import org.apache.camel.model.dataformat.ZipDataFormat;
 import org.apache.camel.model.dataformat.ZipFileDataFormat;
 import org.apache.camel.util.CollectionStringBuffer;
 import org.apache.camel.util.jsse.KeyStoreParameters;
+import org.w3c.dom.Node;
 
 /**
  * An expression for constructing the different possible {@link org.apache.camel.spi.DataFormat}
@@ -272,6 +272,65 @@ public class DataFormatClause<T extends ProcessorDefinition<?>> {
     }
 
     /**
+     * Uses the MIME Multipart data format
+     */
+    public T mimeMultipart() {
+        MimeMultipartDataFormat mm = new MimeMultipartDataFormat();
+        return dataFormat(mm);
+    }
+
+    /**
+     * Uses the MIME Multipart data format
+     *
+     * @param multipartSubType Specifies the subtype of the MIME Multipart
+     */
+    public T mimeMultipart(String multipartSubType) {
+        MimeMultipartDataFormat mm = new MimeMultipartDataFormat();
+        mm.setMultipartSubType(multipartSubType);
+        return dataFormat(mm);
+    }
+
+    /**
+     * Uses the MIME Multipart data format
+     *
+     * @param multipartSubType           the subtype of the MIME Multipart
+     * @param multipartWithoutAttachment defines whether a message without attachment is also marshaled
+     *                                   into a MIME Multipart (with only one body part).
+     * @param headersInline              define the MIME Multipart headers as part of the message body
+     *                                   or as Camel headers
+     * @param binaryContent              have binary encoding for binary content (true) or use Base-64
+     *                                   encoding for binary content (false)
+     */
+    public T mimeMultipart(String multipartSubType, boolean multipartWithoutAttachment, boolean headersInline,
+                           boolean binaryContent) {
+        MimeMultipartDataFormat mm = new MimeMultipartDataFormat();
+        mm.setMultipartSubType(multipartSubType);
+        mm.setMultipartWithoutAttachment(multipartWithoutAttachment);
+        mm.setHeadersInline(headersInline);
+        mm.setBinaryContent(binaryContent);
+        return dataFormat(mm);
+    }
+
+    /**
+     * Uses the MIME Multipart data format
+     *
+     * @param multipartWithoutAttachment defines whether a message without attachment is also marshaled
+     *                                   into a MIME Multipart (with only one body part).
+     * @param headersInline              define the MIME Multipart headers as part of the message body
+     *                                   or as Camel headers
+     * @param binaryContent              have binary encoding for binary content (true) or use Base-64
+     *                                   encoding for binary content (false)
+     */
+    public T mimeMultipart(boolean multipartWithoutAttachment, boolean headersInline,
+                           boolean binaryContent) {
+        MimeMultipartDataFormat mm = new MimeMultipartDataFormat();
+        mm.setMultipartWithoutAttachment(multipartWithoutAttachment);
+        mm.setHeadersInline(headersInline);
+        mm.setBinaryContent(binaryContent);
+        return dataFormat(mm);
+    }
+
+    /**
      * Uses the PGP data format
      */
     public T pgp(String keyFileName, String keyUserid) {

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/camel-core/src/main/java/org/apache/camel/model/dataformat/DataFormatsDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/dataformat/DataFormatsDefinition.java b/camel-core/src/main/java/org/apache/camel/model/dataformat/DataFormatsDefinition.java
index d0ea53b..bdb8caf 100644
--- a/camel-core/src/main/java/org/apache/camel/model/dataformat/DataFormatsDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/dataformat/DataFormatsDefinition.java
@@ -57,6 +57,7 @@ public class DataFormatsDefinition {
         @XmlElement(required = false, name = "jaxb", type = JaxbDataFormat.class),
         @XmlElement(required = false, name = "jibx", type = JibxDataFormat.class),
         @XmlElement(required = false, name = "json", type = JsonDataFormat.class),
+        @XmlElement(required = false, name = "mimeMultipart", type = MimeMultipartDataFormat.class),
         @XmlElement(required = false, name = "protobuf", type = ProtobufDataFormat.class),
         @XmlElement(required = false, name = "rss", type = RssDataFormat.class),
         @XmlElement(required = false, name = "secureXML", type = XMLSecurityDataFormat.class),

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/camel-core/src/main/java/org/apache/camel/model/dataformat/MimeMultipartDataFormat.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/dataformat/MimeMultipartDataFormat.java b/camel-core/src/main/java/org/apache/camel/model/dataformat/MimeMultipartDataFormat.java
new file mode 100644
index 0000000..7116f39
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/dataformat/MimeMultipartDataFormat.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.model.dataformat;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * MIME Multipart data format
+ */
+@Metadata(label = "dataformat,transformation", title = "MIME Multipart")
+@XmlRootElement(name = "mime-multipart")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class MimeMultipartDataFormat extends DataFormatDefinition {
+
+    @XmlAttribute
+    @Metadata(defaultValue = "mixed")
+    private String multipartSubType = "mixed";
+    @XmlAttribute
+    @Metadata(defaultValue = "false")
+    private Boolean multipartWithoutAttachment;
+    @XmlAttribute
+    @Metadata(defaultValue = "false")
+    private Boolean headersInline;
+    @XmlAttribute
+    @Metadata(defaultValue = "false")
+    private Boolean binaryContent;
+
+    public MimeMultipartDataFormat() {
+        super("mime-multipart");
+    }
+
+    @Override
+    protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
+        if (getMultipartSubType() != null) {
+            setProperty(camelContext, dataFormat, "multipartSubType", getMultipartSubType());
+        }
+        if (getMultipartWithoutAttachment() != null) {
+            setProperty(camelContext, dataFormat, "multipartWithoutAttachment", getMultipartWithoutAttachment());
+        }
+        if (getHeadersInline() != null) {
+            setProperty(camelContext, dataFormat, "headersInline", getHeadersInline());
+        }
+        if (getBinaryContent() != null) {
+            setProperty(camelContext, dataFormat, "binaryContent", getBinaryContent());
+        }
+    }
+
+    public String getMultipartSubType() {
+        return multipartSubType;
+    }
+
+    /**
+     * Specify the subtype of the MIME Multipart.
+     * <p>
+     * Default is "mixed".
+     */
+    public void setMultipartSubType(String multipartSubType) {
+        this.multipartSubType = multipartSubType;
+    }
+
+    public Boolean getMultipartWithoutAttachment() {
+        return multipartWithoutAttachment;
+    }
+
+    /**
+     * Defines whether a message without attachment is also marshaled into a
+     * MIME Multipart (with only one body part).
+     * <p>
+     * Default is "false".
+     */
+    public void setMultipartWithoutAttachment(Boolean multipartWithoutAttachment) {
+        this.multipartWithoutAttachment = multipartWithoutAttachment;
+    }
+
+    public Boolean getHeadersInline() {
+        return headersInline;
+    }
+
+    /**
+     * Defines whether the MIME-Multipart headers are part of the message body
+     * (true) or are set as Camel headers (false).
+     * <p>
+     * Default is "false".
+     */
+    public void setHeadersInline(Boolean headersInline) {
+        this.headersInline = headersInline;
+    }
+
+    public Boolean getBinaryContent() {
+        return binaryContent;
+    }
+
+    /**
+     * Defines whether the content of binary parts in the MIME multipart is
+     * binary (true) or Base-64 encoded (false)
+     * <p>
+     * Default is "false".
+     */
+    public void setBinaryContent(Boolean binaryContent) {
+        this.binaryContent = binaryContent;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/camel-core/src/main/resources/org/apache/camel/model/dataformat/jaxb.index
----------------------------------------------------------------------
diff --git a/camel-core/src/main/resources/org/apache/camel/model/dataformat/jaxb.index b/camel-core/src/main/resources/org/apache/camel/model/dataformat/jaxb.index
index 17a947c..07253ec 100644
--- a/camel-core/src/main/resources/org/apache/camel/model/dataformat/jaxb.index
+++ b/camel-core/src/main/resources/org/apache/camel/model/dataformat/jaxb.index
@@ -32,6 +32,7 @@ JaxbDataFormat
 JibxDataFormat
 JsonDataFormat
 JsonLibrary
+MimeMultipartDataFormat
 ProtobufDataFormat
 RssDataFormat
 SerializationDataFormat

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/components/camel-mail/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-mail/pom.xml b/components/camel-mail/pom.xml
index 5069c05..d5123ce 100644
--- a/components/camel-mail/pom.xml
+++ b/components/camel-mail/pom.xml
@@ -30,7 +30,7 @@
     <description>Camel Mail support</description>
 
     <properties>
-        <camel.osgi.export.pkg>org.apache.camel.component.mail.*</camel.osgi.export.pkg>
+        <camel.osgi.export.pkg>org.apache.camel.component.mail.*,org.apache.camel.dataformat.mime.multipart.*</camel.osgi.export.pkg>
         <camel.osgi.export.service>
           org.apache.camel.spi.ComponentResolver;component=imap,
           org.apache.camel.spi.ComponentResolver;component=imaps,
@@ -38,7 +38,8 @@
           org.apache.camel.spi.ComponentResolver;component=pop3,
           org.apache.camel.spi.ComponentResolver;component=pop3s,
           org.apache.camel.spi.ComponentResolver;component=smtp,
-          org.apache.camel.spi.ComponentResolver;component=smtps
+          org.apache.camel.spi.ComponentResolver;component=smtps,
+          org.apache.camel.spi.DataFormatResolver;dataformat=mime-multipart
         </camel.osgi.export.service>
     </properties>
 

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/components/camel-mail/src/main/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormat.java b/components/camel-mail/src/main/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormat.java
new file mode 100644
index 0000000..7d6cf1c
--- /dev/null
+++ b/components/camel-mail/src/main/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormat.java
@@ -0,0 +1,241 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dataformat.mime.multipart;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.mail.BodyPart;
+import javax.mail.Header;
+import javax.mail.MessagingException;
+import javax.mail.Part;
+import javax.mail.Session;
+import javax.mail.internet.ContentType;
+import javax.mail.internet.InternetHeaders;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimeUtility;
+import javax.mail.internet.ParseException;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.MessageHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MimeMultipartDataFormat implements DataFormat {
+    private static final Logger LOG = LoggerFactory.getLogger(MimeMultipartDataFormat.class);
+    private static final String MIME_VERSION = "MIME-Version";
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+    private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
+    private String multipartSubType = "mixed";
+    private boolean multipartWithoutAttachment;
+    private boolean headersInline;
+    private boolean binaryContent;
+
+    public void setBinaryContent(boolean binaryContent) {
+        this.binaryContent = binaryContent;
+    }
+
+    public void setHeadersInline(boolean headersInline) {
+        this.headersInline = headersInline;
+    }
+
+    public void setMultipartWithoutAttachment(boolean multipartWithoutAttachment) {
+        this.multipartWithoutAttachment = multipartWithoutAttachment;
+    }
+
+    public void setMultipartSubType(String multipartSubType) {
+        this.multipartSubType = multipartSubType;
+    }
+
+    @Override
+    public void marshal(Exchange exchange, Object graph, OutputStream stream)
+            throws NoTypeConversionAvailableException, MessagingException, IOException {
+        if (multipartWithoutAttachment || headersInline || exchange.getIn().hasAttachments()) {
+            ContentType contentType = getContentType(exchange);
+            // remove the Content-Type header. This will be wrong afterwards...
+            exchange.getOut().removeHeader(Exchange.CONTENT_TYPE);
+            byte[] bodyContent = ExchangeHelper.convertToMandatoryType(exchange, byte[].class, graph);
+            Session session = Session.getInstance(System.getProperties());
+            MimeMessage mm = new MimeMessage(session);
+            MimeMultipart mp = new MimeMultipart(multipartSubType);
+            BodyPart part = new MimeBodyPart();
+            writeBodyPart(bodyContent, part, contentType);
+            mp.addBodyPart(part);
+            for (Map.Entry<String, DataHandler> entry : exchange.getIn().getAttachments().entrySet()) {
+                String attachmentFilename = entry.getKey();
+                DataHandler handler = entry.getValue();
+                part = new MimeBodyPart();
+                part.setDataHandler(handler);
+                part.setFileName(MimeUtility.encodeText(attachmentFilename, "UTF-8", null));
+                String ct = handler.getContentType();
+                contentType = new ContentType(ct);
+                part.setHeader(CONTENT_TYPE, ct);
+                if (!contentType.match("text/*") && binaryContent) {
+                    part.setHeader(CONTENT_TRANSFER_ENCODING, "binary");
+                }
+                mp.addBodyPart(part);
+                exchange.getOut().removeAttachment(attachmentFilename);
+            }
+            mm.setContent(mp);
+            mm.saveChanges();
+            Enumeration<?> hl = mm.getAllHeaders();
+            List<String> headers = new ArrayList<String>();
+            if (!headersInline) {
+                while (hl.hasMoreElements()) {
+                    Object ho = hl.nextElement();
+                    if (ho instanceof Header) {
+                        Header h = (Header) ho;
+                        exchange.getOut().setHeader(h.getName(), h.getValue());
+                        headers.add(h.getName());
+                    }
+                }
+                mm.saveChanges();
+            }
+            mm.writeTo(stream, headers.toArray(new String[0]));
+        } else {
+            // keep the original data
+            InputStream is = ExchangeHelper.convertToMandatoryType(exchange, InputStream.class, graph);
+            IOHelper.copyAndCloseInput(is, stream);
+        }
+    }
+
+    private ContentType getContentType(Exchange exchange) throws ParseException {
+        String contentTypeStr = ExchangeHelper.getContentType(exchange);
+        if (contentTypeStr == null) {
+            contentTypeStr = DEFAULT_CONTENT_TYPE;
+        }
+        ContentType contentType = new ContentType(contentTypeStr);
+        String contentEncoding = ExchangeHelper.getContentEncoding(exchange);
+        // add a charset parameter for text subtypes
+        if (contentEncoding != null && contentType.match("text/*")) {
+            contentType.setParameter("charset", MimeUtility.mimeCharset(contentEncoding));
+        }
+        return contentType;
+    }
+
+    private void writeBodyPart(byte[] bodyContent, Part part, ContentType contentType) throws MessagingException {
+        DataSource ds = new ByteArrayDataSource(bodyContent, contentType.toString());
+        part.setDataHandler(new DataHandler(ds));
+        part.setHeader(CONTENT_TYPE, contentType.toString());
+        if (contentType.match("text/*")) {
+            part.setHeader(CONTENT_TRANSFER_ENCODING, "8bit");
+        } else if (binaryContent) {
+            part.setHeader(CONTENT_TRANSFER_ENCODING, "binary");
+        } else {
+            part.setHeader(CONTENT_TRANSFER_ENCODING, "base64");
+        }
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, InputStream stream) throws IOException, MessagingException {
+        MimeBodyPart mimeMessage;
+        String contentType;
+        Message camelMessage;
+        Object content = null;
+        if (headersInline) {
+            mimeMessage = new MimeBodyPart(stream);
+            camelMessage = exchange.getOut();
+            MessageHelper.copyHeaders(exchange.getIn(), camelMessage, true);
+            contentType = mimeMessage.getHeader(CONTENT_TYPE, null);
+        } else {
+            // check if this a multipart at all. Otherwise do nothing
+            contentType = exchange.getIn().getHeader(CONTENT_TYPE, String.class);
+            if (contentType == null) {
+                return stream;
+            }
+            try {
+                ContentType ct = new ContentType(contentType);
+                if (!ct.match("multipart/*")) {
+                    return stream;
+                }
+            } catch (ParseException e) {
+                LOG.warn("Invalid Content-Type " + contentType + " ignored");
+                return stream;
+            }
+            camelMessage = exchange.getOut();
+            MessageHelper.copyHeaders(exchange.getIn(), camelMessage, true);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            IOHelper.copyAndCloseInput(stream, bos);
+            InternetHeaders headers = new InternetHeaders();
+            extractHeader(CONTENT_TYPE, camelMessage, headers);
+            extractHeader(MIME_VERSION, camelMessage, headers);
+            mimeMessage = new MimeBodyPart(headers, bos.toByteArray());
+            bos.close();
+        }
+        DataHandler dh;
+        try {
+            dh = mimeMessage.getDataHandler();
+            if (dh != null) {
+                content = dh.getContent();
+                contentType = dh.getContentType();
+            }
+        } catch (MessagingException e) {
+            LOG.warn("cannot parse message, no unmarshalling done");
+        }
+        if (content instanceof MimeMultipart) {
+            MimeMultipart mp = (MimeMultipart) content;
+            content = mp.getBodyPart(0);
+            for (int i = 1; i < mp.getCount(); i++) {
+                BodyPart bp = mp.getBodyPart(i);
+                camelMessage.addAttachment(MimeUtility.decodeText(bp.getFileName()), bp.getDataHandler());
+            }
+        }
+        if (content instanceof BodyPart) {
+            BodyPart bp = (BodyPart) content;
+            camelMessage.setBody(bp.getInputStream());
+            contentType = bp.getContentType();
+        } else {
+            // Last fallback: I don't see how this can happen, but we do this
+            // just to be safe
+            camelMessage.setBody(content);
+        }
+        if (contentType != null && !DEFAULT_CONTENT_TYPE.equals(contentType)) {
+            camelMessage.setHeader(CONTENT_TYPE, contentType);
+            ContentType ct = new ContentType(contentType);
+            String charset = ct.getParameter("charset");
+            if (charset != null) {
+                camelMessage.setHeader(Exchange.CONTENT_ENCODING, MimeUtility.javaCharset(charset));
+            }
+        }
+        return camelMessage;
+    }
+
+    private void extractHeader(String headerMame, Message camelMessage, InternetHeaders headers) {
+        String h = camelMessage.getHeader(headerMame, String.class);
+        if (h != null) {
+            headers.addHeader(headerMame, h);
+            camelMessage.removeHeader(headerMame);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/components/camel-mail/src/main/resources/META-INF/services/org/apache/camel/dataformat/mime-multipart
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/resources/META-INF/services/org/apache/camel/dataformat/mime-multipart b/components/camel-mail/src/main/resources/META-INF/services/org/apache/camel/dataformat/mime-multipart
new file mode 100644
index 0000000..b8483d2
--- /dev/null
+++ b/components/camel-mail/src/main/resources/META-INF/services/org/apache/camel/dataformat/mime-multipart
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class=org.apache.camel.dataformat.mime.multipart.MimeMultipartDataFormat

http://git-wip-us.apache.org/repos/asf/camel/blob/08aa98f8/components/camel-mail/src/test/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormatTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormatTest.java b/components/camel-mail/src/test/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormatTest.java
new file mode 100644
index 0000000..7dbfe42
--- /dev/null
+++ b/components/camel-mail/src/test/java/org/apache/camel/dataformat/mime/multipart/MimeMultipartDataFormatTest.java
@@ -0,0 +1,275 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dataformat.mime.multipart;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.IOHelper;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsCollectionContaining.hasItem;
+import static org.hamcrest.core.StringStartsWith.startsWith;
+
+public class MimeMultipartDataFormatTest extends CamelTestSupport {
+    private Exchange exchange;
+    private Message in;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        exchange = new DefaultExchange(context);
+        in = exchange.getIn();
+    }
+
+    @Test
+    public void roundtripWithTextAttachments() throws IOException {
+        String attContentType = "text/plain";
+        String attText = "Attachment Text";
+        String attFileName = "Attachment File Name";
+        in.setBody("Body text");
+        in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
+        in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
+        addAttachment(attContentType, attText, attFileName);
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
+        assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertEquals(attText, new String(os.toByteArray()));
+    }
+
+    @Test
+    public void roundtripWithTextAttachmentsHeadersInline() throws IOException {
+        String attContentType = "text/plain";
+        String attText = "Attachment Text";
+        String attFileName = "Attachment File Name";
+        in.setBody("Body text");
+        in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
+        in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
+        addAttachment(attContentType, attText, attFileName);
+        Exchange result = template.send("direct:roundtripinlineheaders", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
+        assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertEquals(attText, new String(os.toByteArray()));
+    }
+
+    @Test
+    public void roundtripWithTextAttachmentsAndSpecialCharacters() throws IOException {
+        String attContentType = "text/plain";
+        String attText = "Attachment Text with special characters: \u00A9";
+        String attFileName = "Attachment File Name with special characters: \u00A9";
+        in.setBody("Body text with special characters: \u00A9");
+        in.setHeader(Exchange.CONTENT_TYPE, "text/plain");
+        in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
+        addAttachment(attContentType, attText, attFileName);
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text with special characters: \u00A9", out.getBody(String.class));
+        assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
+        assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertEquals(attText, new String(os.toByteArray()));
+    }
+
+    @Test
+    public void roundtripWithTextAttachmentsAndBinaryContent() throws IOException {
+        String attContentType = "text/plain";
+        String attText = "Attachment Text";
+        String attFileName = "Attachment File Name";
+        in.setBody("Body text");
+        in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
+        in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
+        addAttachment(attContentType, attText, attFileName);
+        Exchange result = template.send("direct:roundtripbinarycontent", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
+        assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertEquals(attText, new String(os.toByteArray()));
+    }
+
+    @Test
+    public void roundtripWithBinaryAttachments() throws IOException {
+        String attContentType = "application/binary";
+        byte[] attText = {0, 1, 2, 3, 4, 5, 6, 7};
+        String attFileName = "Attachment File Name";
+        in.setBody("Body text");
+        DataSource ds = new ByteArrayDataSource(attText, attContentType);
+        in.addAttachment(attFileName, new DataHandler(ds));
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertArrayEquals(attText, os.toByteArray());
+    }
+
+    @Test
+    public void roundtripWithBinaryAttachmentsAndBinaryContent() throws IOException {
+        String attContentType = "application/binary";
+        byte[] attText = {0, 1, 2, 3, 4, 5, 6, 7};
+        String attFileName = "Attachment File Name";
+        in.setBody("Body text");
+        DataSource ds = new ByteArrayDataSource(attText, attContentType);
+        in.addAttachment(attFileName, new DataHandler(ds));
+        Exchange result = template.send("direct:roundtripbinarycontent", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertTrue(out.hasAttachments());
+        assertEquals(1, out.getAttachmentNames().size());
+        assertThat(out.getAttachmentNames(), hasItem(attFileName));
+        DataHandler dh = out.getAttachment(attFileName);
+        assertNotNull(dh);
+        assertEquals(attContentType, dh.getContentType());
+        InputStream is = dh.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IOHelper.copyAndCloseInput(is, os);
+        assertArrayEquals(attText, os.toByteArray());
+    }
+
+    @Test
+    public void roundtripWithoutAttachments() throws IOException {
+        in.setBody("Body text");
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertFalse(out.hasAttachments());
+    }
+
+    @Test
+    public void roundtripWithoutAttachmentsToMultipart() throws IOException {
+        in.setBody("Body text");
+        Exchange result = template.send("direct:roundtripmultipart", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertFalse(out.hasAttachments());
+    }
+
+    @Test
+    public void roundtripWithoutAttachmentsAndContentType() throws IOException {
+        in.setBody("Body text");
+        in.setHeader("Content-Type", "text/plain");
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertFalse(out.hasAttachments());
+    }
+
+    @Test
+    public void roundtripWithoutAttachmentsAndInvalidContentType() throws IOException {
+        in.setBody("Body text");
+        in.setHeader("Content-Type", "text?plain");
+        Exchange result = template.send("direct:roundtrip", exchange);
+        Message out = result.getOut();
+        assertEquals("Body text", out.getBody(String.class));
+        assertFalse(out.hasAttachments());
+    }
+
+    @Test
+    public void marhsalOnlyMixed() throws IOException {
+        in.setBody("Body text");
+        in.setHeader("Content-Type", "text/plain");
+        addAttachment("application/octet-stream", "foobar", "attachment.bin");
+        Exchange result = template.send("direct:marshalonlymixed", exchange);
+        assertThat(result.getOut().getHeader("Content-Type", String.class), startsWith("multipart/mixed"));
+    }
+
+    @Test
+    public void marhsalOnlyRelated() throws IOException {
+        in.setBody("Body text");
+        in.setHeader("Content-Type", "text/plain");
+        addAttachment("application/octet-stream", "foobar", "attachment.bin");
+        Exchange result = template.send("direct:marshalonlyrelated", exchange);
+        assertThat(result.getOut().getHeader("Content-Type", String.class), startsWith("multipart/related"));
+    }
+
+    private void addAttachment(String attContentType, String attText, String attFileName) throws IOException {
+        DataSource ds = new ByteArrayDataSource(attText, attContentType);
+        in.addAttachment(attFileName, new DataHandler(ds));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:roundtrip").marshal().mimeMultipart().to("log:mime?showHeaders=true").unmarshal().mimeMultipart();
+                from("direct:roundtripmultipart").marshal().mimeMultipart(true, false, false).to("log:mime?showHeaders=true").unmarshal().mimeMultipart();
+                from("direct:roundtripinlineheaders").marshal().mimeMultipart(false, true, false).to("log:mime?showHeaders=true").unmarshal().mimeMultipart(false, true, false);
+                from("direct:roundtripbinarycontent").marshal().mimeMultipart(false, false, true).to("log:mime?showHeaders=true").to("dataformat:mime-multipart:unmarshal");
+                from("direct:marshalonlyrelated").marshal().mimeMultipart("related");
+                from("direct:marshalonlymixed").marshal().mimeMultipart();
+            }
+        };
+    }
+}