CAMEL-9880: Header Support for Attachments in Camel 2.18
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/50d6d4fb Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/50d6d4fb Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/50d6d4fb Branch: refs/heads/master Commit: 50d6d4fb98660df1351d7779a1fb2f8f13d4e1ac Parents: 00b5913 Author: Stephan Siano <stephan.si...@sap.com> Authored: Mon Jul 18 14:55:08 2016 +0200 Committer: Stephan Siano <stephan.si...@sap.com> Committed: Tue Jul 19 12:23:44 2016 +0200 ---------------------------------------------------------------------- .../main/java/org/apache/camel/Attachment.java | 83 +++++++++++ .../org/apache/camel/AttachmentObjects.java | 35 +++++ .../main/java/org/apache/camel/Attachments.java | 5 +- .../src/main/java/org/apache/camel/Message.java | 30 ++++ .../apache/camel/builder/ExpressionBuilder.java | 36 +++++ .../camel/builder/ExpressionClauseSupport.java | 2 +- .../apache/camel/component/bean/BeanInfo.java | 5 +- .../camel/converter/AttachmentConverter.java | 43 ++++++ .../apache/camel/impl/DefaultAttachment.java | 125 +++++++++++++++++ .../org/apache/camel/impl/DefaultMessage.java | 74 +++++++--- .../org/apache/camel/impl/MessageSupport.java | 6 +- .../converter/CorePackageScanClassResolver.java | 2 + .../org/apache/camel/processor/Splitter.java | 2 +- .../org/apache/camel/util/AttachmentMap.java | 140 +++++++++++++++++++ .../apache/camel/BodyAndHeaderConvertTest.java | 5 +- .../camel/builder/ExpressionClauseTest.java | 6 +- .../bean/BeanMethodWithExchangeTest.java | 9 +- .../bean/BeanWithAttachmentAnnotationTest.java | 44 +++++- .../apache/camel/impl/DefaultMessageTest.java | 4 +- ...essageWithAttachmentRedeliveryIssueTest.java | 3 +- .../apache/camel/processor/PipelineTest.java | 3 + .../camel/component/cxf/DefaultCxfBinding.java | 34 ++++- .../component/cxf/jaxrs/SimpleCxfRsBinding.java | 25 +++- .../component/cxf/DefaultCxfBindingTest.java | 21 ++- .../apache/camel/component/jcr/JcrMessage.java | 2 +- .../component/jetty9/AttachmentHttpBinding.java | 11 +- .../jetty/MultiPartFormOkHttpTest.java | 1 + .../apache/camel/component/jms/JmsMessage.java | 2 +- .../camel/component/mail/MailBinding.java | 35 +++-- .../camel/component/mail/MailMessage.java | 3 +- .../apache/camel/component/mail/MailUtils.java | 1 + .../mail/SplitAttachmentsExpression.java | 8 +- .../mime/multipart/MimeMultipartDataFormat.java | 26 +++- .../component/mail/MailAttachmentTest.java | 13 +- .../multipart/MimeMultipartDataFormatTest.java | 45 +++++- .../src/test/resources/multipart-related.txt | 2 + .../processor/AnalyticsApiProcessor.java | 2 +- .../internal/processor/BulkApiProcessor.java | 2 +- .../internal/processor/JsonRestProcessor.java | 2 +- .../internal/processor/XmlRestProcessor.java | 2 +- .../org/apache/camel/scala/RichMessage.scala | 9 ++ .../apache/camel/scala/dsl/PipelineTest.scala | 2 + .../servlet/AttachmentHttpBinding.java | 11 +- .../camel/component/sjms/SjmsMessage.java | 2 +- 44 files changed, 829 insertions(+), 94 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/Attachment.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Attachment.java b/camel-core/src/main/java/org/apache/camel/Attachment.java new file mode 100644 index 0000000..6cdc0e4 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/Attachment.java @@ -0,0 +1,83 @@ +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.activation.DataHandler; + +/** + * Represents an attachment as part of a {@link Message}. + */ +public interface Attachment { + /** + * Return a DataHandler for the content within this attachment. + * + * @return DataHandler for the content + */ + DataHandler getDataHandler(); + + /** + * Get all the headers for this header name. Returns null if no headers for + * this header name are available. + * + * @param headerName he name of this header + * @return a comma separated list of all header values + */ + String getHeader(String headerName); + + /** + * Get all the headers for this header name. Returns null if no headers for + * this header name are available. + * + * @param headerName he name of this header + * @return a list of all header values + */ + List<String> getHeaderAsList(String name); + + /** + * Get all header names for this attachment. + * + * @return a collection of all header names + */ + Collection<String> getHeaderNames(); + + /** + * Set the value for this headerName. Replaces all existing header values + * with this new value. + * + * @param headerName the name of this header + * @param headerValue the value for this header + */ + void setHeader(String headerName, String headerValue); + + /** + * Add this value to the existing values for this headerName. + * + * @param headerName the name of this header + * @param headerValue the value for this header + */ + void addHeader(String headerName, String headerValue); + + /** + * Remove all headers with this name. + * + * @param headerName the name of this header + */ + void removeHeader(String headerName); +} http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/AttachmentObjects.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/AttachmentObjects.java b/camel-core/src/main/java/org/apache/camel/AttachmentObjects.java new file mode 100644 index 0000000..58d376f --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/AttachmentObjects.java @@ -0,0 +1,35 @@ +/** + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a parameter as being Map of attachments as {@link Attachment} objects + * of an inbound {@link Message} + * + * @version + */ +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Target({ElementType.PARAMETER }) +public @interface AttachmentObjects { +} http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/Attachments.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Attachments.java b/camel-core/src/main/java/org/apache/camel/Attachments.java index df363ea..d400534 100644 --- a/camel-core/src/main/java/org/apache/camel/Attachments.java +++ b/camel-core/src/main/java/org/apache/camel/Attachments.java @@ -23,9 +23,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Marks a parameter as being Map of attachments of an inbound {@link Message} + * Marks a parameter as being Map of attachments as + * {@link javax.activation.DataHandler} objects of an inbound {@link Message} * - * @version + * @version */ @Retention(RetentionPolicy.RUNTIME) @Documented http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/Message.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Message.java b/camel-core/src/main/java/org/apache/camel/Message.java index dd576a8..7efb34c 100644 --- a/camel-core/src/main/java/org/apache/camel/Message.java +++ b/camel-core/src/main/java/org/apache/camel/Message.java @@ -256,6 +256,14 @@ public interface Message { DataHandler getAttachment(String id); /** + * Returns the attachment specified by the id + * + * @param id the id under which the attachment is stored + * @return the attachment or <tt>null</tt> + */ + Attachment getAttachmentObject(String id); + + /** * Returns a set of attachment names of the message * * @return a set of attachment names @@ -278,6 +286,14 @@ public interface Message { void addAttachment(String id, DataHandler content); /** + * Adds an attachment to the message using the id + * + * @param id the id to store the attachment under + * @param content the attachment + */ + void addAttachmentObject(String id, Attachment content); + + /** * Returns all attachments of the message * * @return the attachments in a map or <tt>null</tt> @@ -285,6 +301,13 @@ public interface Message { Map<String, DataHandler> getAttachments(); /** + * Returns all attachments of the message + * + * @return the attachments in a map or <tt>null</tt> + */ + Map<String, Attachment> getAttachmentObjects(); + + /** * Set all the attachments associated with this message * * @param attachments the attachments @@ -292,6 +315,13 @@ public interface Message { void setAttachments(Map<String, DataHandler> attachments); /** + * Set all the attachments associated with this message + * + * @param attachments the attachments + */ + void setAttachmentObjects(Map<String, Attachment> attachments); + + /** * Returns whether this message has attachments. * * @return <tt>true</tt> if this message has any attachments. http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java index 3200990..b6069ea 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java +++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java @@ -80,6 +80,42 @@ public final class ExpressionBuilder { private ExpressionBuilder() { } + /** + * Returns an expression for the inbound message attachments + * + * @return an expression object which will return the inbound message attachments + */ + public static Expression attachmentObjectsExpression() { + return new ExpressionAdapter() { + public Object evaluate(Exchange exchange) { + return exchange.getIn().getAttachmentObjects(); + } + + @Override + public String toString() { + return "attachmentObjects"; + } + }; + } + + /** + * Returns an expression for the inbound message attachments + * + * @return an expression object which will return the inbound message attachments + */ + public static Expression attachmentObjectValuesExpression() { + return new ExpressionAdapter() { + public Object evaluate(Exchange exchange) { + return exchange.getIn().getAttachmentObjects().values(); + } + + @Override + public String toString() { + return "attachmentObjects"; + } + }; + } + /** * Returns an expression for the inbound message attachments * http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java index 0ef21b8..9e1224c 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java +++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java @@ -171,7 +171,7 @@ public class ExpressionClauseSupport<T> { * An expression of the inbound message attachments */ public T attachments() { - return expression(ExpressionBuilder.attachmentValuesExpression()); + return expression(ExpressionBuilder.attachmentObjectValuesExpression()); } /** http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java b/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java index 3e23332..5a3a0ef 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.camel.AttachmentObjects; import org.apache.camel.Attachments; import org.apache.camel.Body; import org.apache.camel.CamelContext; @@ -946,7 +947,9 @@ public class BeanInfo { private Expression createParameterUnmarshalExpressionForAnnotation(Class<?> clazz, Method method, Class<?> parameterType, Annotation annotation) { - if (annotation instanceof Attachments) { + if (annotation instanceof AttachmentObjects) { + return ExpressionBuilder.attachmentObjectsExpression(); + } else if (annotation instanceof Attachments) { return ExpressionBuilder.attachmentsExpression(); } else if (annotation instanceof Property) { Property propertyAnnotation = (Property)annotation; http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/converter/AttachmentConverter.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/converter/AttachmentConverter.java b/camel-core/src/main/java/org/apache/camel/converter/AttachmentConverter.java new file mode 100644 index 0000000..5e032d5 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/converter/AttachmentConverter.java @@ -0,0 +1,43 @@ +/** + * 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.converter; + +import javax.activation.DataHandler; + +import org.apache.camel.Attachment; +import org.apache.camel.Converter; + +/** + * Some useful converters for {@link Attachment} + * to a {@link DataHandler} + * + * @version + */ +@Converter +public final class AttachmentConverter { + + /** + * Utility classes should not have a public constructor. + */ + private AttachmentConverter() { + } + + @Converter + public static DataHandler toDataHandler(final Attachment attachment) { + return attachment.getDataHandler(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/impl/DefaultAttachment.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultAttachment.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultAttachment.java new file mode 100644 index 0000000..dbb87af --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultAttachment.java @@ -0,0 +1,125 @@ +/** + * 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.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import javax.activation.DataHandler; +import javax.activation.DataSource; + +import org.apache.camel.Attachment; +import org.apache.camel.util.CollectionHelper; + +public class DefaultAttachment implements Attachment { + private Map<String, Object> headers = null; + private DataHandler dataHandler; + + public DefaultAttachment(DataHandler dh) { + dataHandler = dh; + } + + public DefaultAttachment(DataSource ds) { + dataHandler = new DataHandler(ds); + } + + @Override + public DataHandler getDataHandler() { + return dataHandler; + } + + @Override + public String getHeader(String name) { + if (headers != null) { + Object headerObject = headers.get(name); + if (headerObject instanceof String) { + return (String)headerObject; + } else if (headerObject instanceof Collection<?>) { + return CollectionHelper.collectionAsCommaDelimitedString((Collection<?>)headerObject); + } + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public List<String> getHeaderAsList(String name) { + if (headers != null) { + Object headerObject = headers.get(name); + if (headerObject instanceof List<?>) { + return (List<String>)headerObject; + } else if (headerObject instanceof String) { + return Collections.singletonList((String)headerObject); + } + } + return null; + } + + @Override + public void addHeader(String headerName, String headerValue) { + if (headers == null) { + headers = createHeaders(); + } + CollectionHelper.appendValue(headers, headerName, headerValue); + } + + @Override + public void setHeader(String headerName, String headerValue) { + if (headers == null) { + headers = createHeaders(); + } + headers.put(headerName, headerValue); + } + + @Override + public void removeHeader(String headerName) { + if (headers != null) { + headers.remove(headerName); + } + } + + @Override + public Collection<String> getHeaderNames() { + if (headers == null) { + headers = createHeaders(); + } + return headers.keySet(); + } + + public void clearHeaders() { + headers = null; + } + + private Map<String, Object> createHeaders() { + return new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER); + } + + public boolean equals(Object other) { + if (other instanceof Attachment) { + DataHandler otherDh = ((Attachment)other).getDataHandler(); + return dataHandler.equals(otherDh); + } + return false; + } + + public int hashCode() { + return (dataHandler.hashCode()); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/impl/DefaultMessage.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultMessage.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultMessage.java index 0ed2841..848586a 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultMessage.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultMessage.java @@ -22,7 +22,9 @@ import java.util.Map; import java.util.Set; import javax.activation.DataHandler; +import org.apache.camel.Attachment; import org.apache.camel.Exchange; +import org.apache.camel.util.AttachmentMap; import org.apache.camel.util.CaseInsensitiveMap; import org.apache.camel.util.EndpointHelper; @@ -40,6 +42,7 @@ public class DefaultMessage extends MessageSupport { private boolean fault; private Map<String, Object> headers; private Map<String, DataHandler> attachments; + private Map<String, Attachment> attachmentObjects; public boolean isFault() { return fault; @@ -199,14 +202,14 @@ public class DefaultMessage extends MessageSupport { } /** - * A factory method to lazily create the attachments to make it easy to + * A factory method to lazily create the attachmentObjects to make it easy to * create efficient Message implementations which only construct and * populate the Map on demand * * @return return a newly constructed Map */ - protected Map<String, DataHandler> createAttachments() { - Map<String, DataHandler> map = new LinkedHashMap<String, DataHandler>(); + protected Map<String, Attachment> createAttachments() { + Map<String, Attachment> map = new LinkedHashMap<String, Attachment>(); populateInitialAttachments(map); return map; } @@ -222,12 +225,12 @@ public class DefaultMessage extends MessageSupport { } /** - * A strategy method populate the initial set of attachments on an inbound + * A strategy method populate the initial set of attachmentObjects on an inbound * message from an underlying binding * * @param map is the empty attachment map to populate */ - protected void populateInitialAttachments(Map<String, DataHandler> map) { + protected void populateInitialAttachments(Map<String, Attachment> map) { // do nothing by default } @@ -247,45 +250,82 @@ public class DefaultMessage extends MessageSupport { } public void addAttachment(String id, DataHandler content) { - if (attachments == null) { - attachments = createAttachments(); + addAttachmentObject(id, new DefaultAttachment(content)); + } + + public void addAttachmentObject(String id, Attachment content) { + if (attachmentObjects == null) { + attachmentObjects = createAttachments(); } - attachments.put(id, content); + attachmentObjects.put(id, content); } public DataHandler getAttachment(String id) { - return getAttachments().get(id); + Attachment att = getAttachmentObject(id); + if (att == null) { + return null; + } else { + return att.getDataHandler(); + } + } + + @Override + public Attachment getAttachmentObject(String id) { + return getAttachmentObjects().get(id); } public Set<String> getAttachmentNames() { - if (attachments == null) { - attachments = createAttachments(); + if (attachmentObjects == null) { + attachmentObjects = createAttachments(); } - return attachments.keySet(); + return attachmentObjects.keySet(); } public void removeAttachment(String id) { - if (attachments != null && attachments.containsKey(id)) { - attachments.remove(id); + if (attachmentObjects != null && attachmentObjects.containsKey(id)) { + attachmentObjects.remove(id); } } public Map<String, DataHandler> getAttachments() { if (attachments == null) { - attachments = createAttachments(); + attachments = new AttachmentMap(getAttachmentObjects()); } return attachments; } + public Map<String, Attachment> getAttachmentObjects() { + if (attachmentObjects == null) { + attachmentObjects = createAttachments(); + } + return attachmentObjects; + } + public void setAttachments(Map<String, DataHandler> attachments) { - this.attachments = attachments; + if (attachments == null) { + this.attachmentObjects = null; + } else if (attachments instanceof AttachmentMap) { + // this way setAttachments(getAttachments()) will tunnel attachment headers + this.attachmentObjects = ((AttachmentMap)attachments).getOriginalMap(); + } else { + this.attachmentObjects = new LinkedHashMap<String, Attachment>(); + for (Map.Entry<String, DataHandler> entry : attachments.entrySet()) { + this.attachmentObjects.put(entry.getKey(), new DefaultAttachment(entry.getValue())); + } + } + this.attachments = null; + } + + public void setAttachmentObjects(Map<String, Attachment> attachments) { + this.attachmentObjects = attachments; + this.attachments = null; } public boolean hasAttachments() { // optimized to avoid calling createAttachments as that creates a new empty map // that we 99% do not need (only camel-mail supports attachments), and we have // then ensure camel-mail always creates attachments to remedy for this - return this.attachments != null && this.attachments.size() > 0; + return this.attachmentObjects != null && this.attachmentObjects.size() > 0; } /** http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/impl/MessageSupport.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/MessageSupport.java b/camel-core/src/main/java/org/apache/camel/impl/MessageSupport.java index 029c0bf..2d4955e 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/MessageSupport.java +++ b/camel-core/src/main/java/org/apache/camel/impl/MessageSupport.java @@ -173,17 +173,17 @@ public abstract class MessageSupport implements Message { // the attachments may be the same instance if the end user has made some mistake // and set the OUT message with the same attachment instance of the IN message etc boolean sameAttachments = false; - if (hasAttachments() && that.hasAttachments() && getAttachments() == that.getAttachments()) { + if (hasAttachments() && that.hasAttachments() && getAttachmentObjects() == that.getAttachmentObjects()) { sameAttachments = true; } if (!sameAttachments) { if (hasAttachments()) { // okay its safe to clear the attachments - getAttachments().clear(); + getAttachmentObjects().clear(); } if (that.hasAttachments()) { - getAttachments().putAll(that.getAttachments()); + getAttachmentObjects().putAll(that.getAttachmentObjects()); } } } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java b/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java index dfa008e..ed11fa9 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java +++ b/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java @@ -23,6 +23,7 @@ import java.util.Set; import org.apache.camel.component.bean.BeanConverter; import org.apache.camel.component.file.GenericFileConverter; +import org.apache.camel.converter.AttachmentConverter; import org.apache.camel.converter.CamelConverter; import org.apache.camel.converter.CollectionConverter; import org.apache.camel.converter.DateTimeConverter; @@ -75,6 +76,7 @@ public class CorePackageScanClassResolver implements PackageScanClassResolver { converters.add(BeanConverter.class); converters.add(GenericFileConverter.class); converters.add(DurationConverter.class); + converters.add(AttachmentConverter.class); } @Override http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/processor/Splitter.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/processor/Splitter.java b/camel-core/src/main/java/org/apache/camel/processor/Splitter.java index fba3f71..ba3be2e 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/Splitter.java +++ b/camel-core/src/main/java/org/apache/camel/processor/Splitter.java @@ -284,7 +284,7 @@ public class Splitter extends MulticastProcessor implements AsyncProcessor, Trac private static Exchange copyExchangeNoAttachments(Exchange exchange, boolean preserveExchangeId) { Exchange answer = ExchangeHelper.createCopy(exchange, preserveExchangeId); // we do not want attachments for the splitted sub-messages - answer.getIn().setAttachments(null); + answer.getIn().setAttachmentObjects(null); // we do not want to copy the message history for splitted sub-messages answer.getProperties().remove(Exchange.MESSAGE_HISTORY); return answer; http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/main/java/org/apache/camel/util/AttachmentMap.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/util/AttachmentMap.java b/camel-core/src/main/java/org/apache/camel/util/AttachmentMap.java new file mode 100644 index 0000000..1f33546 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/util/AttachmentMap.java @@ -0,0 +1,140 @@ +/** + * 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.util; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.activation.DataHandler; + +import org.apache.camel.Attachment; +import org.apache.camel.impl.DefaultAttachment; + +/** + * The AttachmentMap class provides a transparent Map<String, DataHandler> + * interface for a Map<String, Attachment> + */ +public class AttachmentMap extends AbstractMap<String, DataHandler> { + private Map<String, Attachment> map; + + public AttachmentMap(Map<String, Attachment> backingMap) { + this.map = backingMap; + } + + @Override + public DataHandler put(String key, DataHandler value) { + Attachment old = map.put(key, new DefaultAttachment(value)); + if (old == null) { + return null; + } else { + return old.getDataHandler(); + } + } + + @Override + public Set<Map.Entry<String, DataHandler>> entrySet() { + return new AttachmentEntrySet(map.entrySet()); + } + + public Map<String, Attachment> getOriginalMap() { + return map; + } + + private static class AttachmentEntrySet extends AbstractSet<Map.Entry<String, DataHandler>> { + private Set<Map.Entry<String, Attachment>> set; + + public AttachmentEntrySet(Set<Map.Entry<String, Attachment>> set) { + this.set = set; + } + + @Override + public int size() { + return set.size(); + } + + @Override + public Iterator<Map.Entry<String, DataHandler>> iterator() { + return new AttachmentEntrySetIterator(set.iterator()); + } + } + + private static class AttachmentEntrySetIterator implements Iterator<Map.Entry<String, DataHandler>> { + private Iterator<Map.Entry<String, Attachment>> iter; + + public AttachmentEntrySetIterator(Iterator<Map.Entry<String, Attachment>> origIterator) { + iter = origIterator; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public Map.Entry<String, DataHandler> next() { + return new AttachmentEntry(iter.next()); + } + + public void remove() { + iter.remove(); + } + } + + private static class AttachmentEntry implements Map.Entry<String, DataHandler> { + private Map.Entry<String, Attachment> entry; + + public AttachmentEntry(Map.Entry<String, Attachment> backingEntry) { + this.entry = backingEntry; + } + + @Override + public String getKey() { + return entry.getKey(); + } + + @Override + public DataHandler getValue() { + Attachment value = entry.getValue(); + if (value != null) + return value.getDataHandler(); + return null; + } + + @Override + public DataHandler setValue(DataHandler value) { + Attachment oldValue = entry.setValue(new DefaultAttachment(value)); + if (oldValue != null) + return oldValue.getDataHandler(); + return null; + } + + // two AttachmentEntry objects are equal if the backing entries are + // equal + public boolean equals(Object o) { + if (o instanceof AttachmentEntry && entry.equals(((AttachmentEntry)o).entry)) + return true; + return false; + } + + public int hashCode() { + return entry.hashCode(); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/BodyAndHeaderConvertTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/BodyAndHeaderConvertTest.java b/camel-core/src/test/java/org/apache/camel/BodyAndHeaderConvertTest.java index 73db6ad..af67e04 100644 --- a/camel-core/src/test/java/org/apache/camel/BodyAndHeaderConvertTest.java +++ b/camel-core/src/test/java/org/apache/camel/BodyAndHeaderConvertTest.java @@ -26,6 +26,7 @@ import org.w3c.dom.Element; import junit.framework.TestCase; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.impl.DefaultExchange; @@ -55,6 +56,8 @@ public class BodyAndHeaderConvertTest extends TestCase { public void testConversionOfMessageAttachments() throws Exception { DataHandler handler = exchange.getIn().getAttachment("att"); assertNotNull("attachment got lost", handler); + Attachment attachment = exchange.getIn().getAttachmentObject("att"); + assertNotNull("attachment got lost", attachment); } @Override @@ -65,6 +68,6 @@ public class BodyAndHeaderConvertTest extends TestCase { Message message = exchange.getIn(); message.setBody("<hello>world!</hello>"); message.setHeader("bar", 567); - message.addAttachment("att", new DataHandler(new URLDataSource(new URL("http://camel.apache.org/message.html")))); + message.addAttachmentObject("att", new DefaultAttachment(new URLDataSource(new URL("http://camel.apache.org/message.html")))); } } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/builder/ExpressionClauseTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/builder/ExpressionClauseTest.java b/camel-core/src/test/java/org/apache/camel/builder/ExpressionClauseTest.java index f45aabe..f053177 100644 --- a/camel-core/src/test/java/org/apache/camel/builder/ExpressionClauseTest.java +++ b/camel-core/src/test/java/org/apache/camel/builder/ExpressionClauseTest.java @@ -22,11 +22,13 @@ import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; +import org.apache.camel.Attachment; import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.Processor; import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.DefaultAttachment; /** * @version @@ -53,13 +55,13 @@ public class ExpressionClauseTest extends ContextTestSupport { public void process(Exchange exchange) throws Exception { Message m = exchange.getIn(); m.setBody("Hello World"); - m.addAttachment("log4j", new DataHandler(new FileDataSource("src/test/resources/log4j.properties"))); + m.addAttachmentObject("log4j", new DefaultAttachment(new FileDataSource("src/test/resources/log4j.properties"))); m.addAttachment("jndi-example", new DataHandler(new FileDataSource("src/test/resources/jndi-example.properties"))); } }); assertMockEndpointsSatisfied(); - Map<String, DataHandler> attachments = mock.getExchanges().get(0).getIn().getAttachments(); + Map<String, Attachment> attachments = mock.getExchanges().get(0).getIn().getAttachmentObjects(); assertTrue(attachments == null || attachments.size() == 0); } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java b/camel-core/src/test/java/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java index 01e022e..9afe828 100644 --- a/camel-core/src/test/java/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java +++ b/camel-core/src/test/java/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java @@ -20,11 +20,13 @@ import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.naming.Context; +import org.apache.camel.Attachment; import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.util.jndi.JndiContext; public class BeanMethodWithExchangeTest extends ContextTestSupport { @@ -39,7 +41,9 @@ public class BeanMethodWithExchangeTest extends ContextTestSupport { }); - assertTrue(result.getOut().getAttachments().containsKey("attachment2")); + assertTrue(result.getOut().getAttachmentObjects().containsKey("attachment2")); + assertTrue(result.getOut().getAttachments().containsKey("attachment1")); + assertEquals("attachmentValue1", result.getOut().getAttachmentObjects().get("attachment1").getHeader("attachmentHeader1")); assertFalse(result.getOut().getAttachments().containsKey("attachment")); } @@ -60,6 +64,9 @@ public class BeanMethodWithExchangeTest extends ContextTestSupport { public static class AttachmentProcessor { public void doSomething(Exchange exchange) { + Attachment att = new DefaultAttachment(new FileDataSource("src/test/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java")); + att.addHeader("attachmentHeader1", "attachmentValue1"); + exchange.getOut().addAttachmentObject("attachment1", att); exchange.getOut().addAttachment("attachment2", new DataHandler(new FileDataSource("src/test/org/apache/camel/component/bean/BeanMethodWithExchangeTest.java"))); } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java b/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java index 3eea300..5f43bc4 100644 --- a/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java +++ b/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java @@ -22,6 +22,8 @@ import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.naming.Context; +import org.apache.camel.Attachment; +import org.apache.camel.AttachmentObjects; import org.apache.camel.Attachments; import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; @@ -30,10 +32,28 @@ import org.apache.camel.Message; import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.util.jndi.JndiContext; public class BeanWithAttachmentAnnotationTest extends ContextTestSupport { + public void testBeanWithOldAnnotationAndExchangeTest() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("attachment"); + + template.send("direct:inOld", new Processor() { + + public void process(Exchange exchange) throws Exception { + exchange.setPattern(ExchangePattern.InOut); + Message m = exchange.getIn(); + m.addAttachmentObject("attachment", new DefaultAttachment(new FileDataSource("src/test/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java"))); + } + + }); + + mock.assertIsSatisfied(); + } + public void testBeanWithAnnotationAndExchangeTest() throws Exception { MockEndpoint mock = getMockEndpoint("mock:result"); mock.expectedBodiesReceived("attachment"); @@ -43,7 +63,7 @@ public class BeanWithAttachmentAnnotationTest extends ContextTestSupport { public void process(Exchange exchange) throws Exception { exchange.setPattern(ExchangePattern.InOut); Message m = exchange.getIn(); - m.addAttachment("attachment", new DataHandler(new FileDataSource("src/test/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java"))); + m.addAttachmentObject("attachment", new DefaultAttachment(new FileDataSource("src/test/org/apache/camel/component/bean/BeanWithAttachmentAnnotationTest.java"))); } }); @@ -53,6 +73,7 @@ public class BeanWithAttachmentAnnotationTest extends ContextTestSupport { protected Context createJndiContext() throws Exception { JndiContext answer = new JndiContext(); + answer.bind("processorOld", new AttachmentProcessorOld()); answer.bind("processor", new AttachmentProcessor()); return answer; } @@ -61,11 +82,12 @@ public class BeanWithAttachmentAnnotationTest extends ContextTestSupport { return new RouteBuilder() { public void configure() throws Exception { from("direct:in").to("bean:processor").to("mock:result"); + from("direct:inOld").to("bean:processorOld").to("mock:result"); } }; } - public static class AttachmentProcessor { + public static class AttachmentProcessorOld { // START SNIPPET: e1 public String doSomething(@Attachments Map<String, DataHandler> attachments) { assertNotNull(attachments); @@ -80,4 +102,22 @@ public class BeanWithAttachmentAnnotationTest extends ContextTestSupport { } // END SNIPPET: e1 } + + public static class AttachmentProcessor { + // START SNIPPET: e2 + public String doSomething(@AttachmentObjects Map<String, Attachment> attachments) { + assertNotNull(attachments); + assertEquals("The attache size is wrong", 1, attachments.size()); + String key = attachments.keySet().iterator().next(); + assertNotNull(key); + assertNotNull(attachments.get(key)); + Attachment attachment = attachments.get(key); + assertNotNull(attachment); + DataHandler handler = attachment.getDataHandler(); + assertNotNull(handler); + assertTrue("The data source should be a instance of FileDataSource", handler.getDataSource() instanceof FileDataSource); + return key; + } + // END SNIPPET: e2 + } } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/impl/DefaultMessageTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/impl/DefaultMessageTest.java b/camel-core/src/test/java/org/apache/camel/impl/DefaultMessageTest.java index 59b4cdc..f8073d2 100644 --- a/camel-core/src/test/java/org/apache/camel/impl/DefaultMessageTest.java +++ b/camel-core/src/test/java/org/apache/camel/impl/DefaultMessageTest.java @@ -18,8 +18,8 @@ package org.apache.camel.impl; import java.util.LinkedHashMap; import java.util.Map; -import javax.activation.DataHandler; +import org.apache.camel.Attachment; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -31,7 +31,7 @@ public class DefaultMessageTest { public void testAttachmentsAreSorted() { DefaultMessage message = new DefaultMessage(); - Map<String, DataHandler> attachments = message.createAttachments(); + Map<String, Attachment> attachments = message.createAttachments(); assertThat(attachments, instanceOf(LinkedHashMap.class)); } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/issues/MessageWithAttachmentRedeliveryIssueTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/issues/MessageWithAttachmentRedeliveryIssueTest.java b/camel-core/src/test/java/org/apache/camel/issues/MessageWithAttachmentRedeliveryIssueTest.java index a264a9c..8156d8e 100644 --- a/camel-core/src/test/java/org/apache/camel/issues/MessageWithAttachmentRedeliveryIssueTest.java +++ b/camel-core/src/test/java/org/apache/camel/issues/MessageWithAttachmentRedeliveryIssueTest.java @@ -25,6 +25,7 @@ import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultAttachment; /** * @@ -39,7 +40,7 @@ public class MessageWithAttachmentRedeliveryIssueTest extends ContextTestSupport public void process(Exchange exchange) throws Exception { exchange.getIn().setBody("Hello World"); exchange.getIn().addAttachment("message1.xml", new DataHandler(new FileDataSource(new File("src/test/data/message1.xml")))); - exchange.getIn().addAttachment("message2.xml", new DataHandler(new FileDataSource(new File("src/test/data/message2.xml")))); + exchange.getIn().addAttachmentObject("message2.xml", new DefaultAttachment(new FileDataSource(new File("src/test/data/message2.xml")))); } }); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/camel-core/src/test/java/org/apache/camel/processor/PipelineTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/processor/PipelineTest.java b/camel-core/src/test/java/org/apache/camel/processor/PipelineTest.java index db58d81..aa92a5d 100644 --- a/camel-core/src/test/java/org/apache/camel/processor/PipelineTest.java +++ b/camel-core/src/test/java/org/apache/camel/processor/PipelineTest.java @@ -132,9 +132,11 @@ public class PipelineTest extends ContextTestSupport { }); // there is always breadcrumb header assertEquals("There should have no message header", 1, exchange.getOut().getHeaders().size()); + assertEquals("There should have no attachments", 0, exchange.getOut().getAttachmentObjects().size()); assertEquals("There should have no attachments", 0, exchange.getOut().getAttachments().size()); assertEquals("Get a wrong message body", "test", exchange.getOut().getBody()); assertNull(exchange.getOut().getHeader("test")); + assertNull(exchange.getOut().getAttachmentObject("test1.xml")); assertNull(exchange.getOut().getAttachment("test1.xml")); } @@ -184,6 +186,7 @@ public class PipelineTest extends ContextTestSupport { .process(new Processor() { public void process(Exchange exchange) throws Exception { exchange.getOut().copyFrom(exchange.getIn()); + assertNotNull("The test attachment should not be null", exchange.getOut().getAttachmentObject("test1.xml")); assertNotNull("The test attachment should not be null", exchange.getOut().getAttachment("test1.xml")); assertNotNull("The test header should not be null", exchange.getOut().getHeader("test")); exchange.getOut().removeAttachment("test1.xml"); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java index aad23d5..bbad18a 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java @@ -30,7 +30,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import javax.activation.DataHandler; import javax.security.auth.Subject; import javax.xml.XMLConstants; import javax.xml.namespace.QName; @@ -47,6 +46,7 @@ import org.apache.camel.ExchangePattern; import org.apache.camel.component.cxf.common.message.CxfConstants; import org.apache.camel.component.cxf.util.CxfUtils; import org.apache.camel.component.cxf.util.ReaderInputStream; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; import org.apache.camel.util.ExchangeHelper; @@ -129,11 +129,16 @@ public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware // we should avoid adding the attachments if the data format is CXFMESSAGE, as the message stream // already has the attachment information if (!DataFormat.CXF_MESSAGE.equals(dataFormat)) { - for (Map.Entry<String, DataHandler> entry : camelExchange.getIn().getAttachments().entrySet()) { + for (Map.Entry<String, org.apache.camel.Attachment> entry : camelExchange.getIn().getAttachmentObjects().entrySet()) { if (attachments == null) { attachments = new HashSet<Attachment>(); } - AttachmentImpl attachment = new AttachmentImpl(entry.getKey(), entry.getValue()); + AttachmentImpl attachment = new AttachmentImpl(entry.getKey()); + org.apache.camel.Attachment camelAttachment = entry.getValue(); + attachment.setDataHandler(camelAttachment.getDataHandler()); + for (String name : camelAttachment.getHeaderNames()) { + attachment.setHeader(name, camelAttachment.getHeader(name)); + } attachment.setXOP(isXop); attachments.add(attachment); } @@ -187,10 +192,20 @@ public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware if (cxfMessage.getAttachments() != null) { // propagate attachments for (Attachment attachment : cxfMessage.getAttachments()) { - camelExchange.getOut().addAttachment(attachment.getId(), attachment.getDataHandler()); + camelExchange.getOut().addAttachmentObject(attachment.getId(), createCamelAttachment(attachment)); } } } + + private DefaultAttachment createCamelAttachment(Attachment attachment) { + DefaultAttachment camelAttachment = new DefaultAttachment(attachment.getDataHandler()); + Iterator<String> headers = attachment.getHeaderNames(); + while (headers.hasNext()) { + String name = headers.next(); + camelAttachment.addHeader(name, attachment.getHeader(name)); + } + return camelAttachment; + } /** * This method is called by {@link CxfConsumer}. @@ -289,7 +304,7 @@ public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware if (cxfMessage.getAttachments() != null && !camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class).equals(DataFormat.POJO)) { for (Attachment attachment : cxfMessage.getAttachments()) { - camelExchange.getIn().addAttachment(attachment.getId(), attachment.getDataHandler()); + camelExchange.getIn().addAttachmentObject(attachment.getId(), createCamelAttachment(attachment)); } } } @@ -387,11 +402,16 @@ public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware Set<Attachment> attachments = null; boolean isXop = Boolean.valueOf(camelExchange.getProperty(Message.MTOM_ENABLED, String.class)); - for (Map.Entry<String, DataHandler> entry : camelExchange.getOut().getAttachments().entrySet()) { + for (Map.Entry<String, org.apache.camel.Attachment> entry : camelExchange.getOut().getAttachmentObjects().entrySet()) { if (attachments == null) { attachments = new HashSet<Attachment>(); } - AttachmentImpl attachment = new AttachmentImpl(entry.getKey(), entry.getValue()); + AttachmentImpl attachment = new AttachmentImpl(entry.getKey()); + org.apache.camel.Attachment camelAttachment = entry.getValue(); + attachment.setDataHandler(camelAttachment.getDataHandler()); + for (String name : camelAttachment.getHeaderNames()) { + attachment.setHeader(name, camelAttachment.getHeader(name)); + } attachment.setXOP(isXop); attachments.add(attachment); } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/SimpleCxfRsBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/SimpleCxfRsBinding.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/SimpleCxfRsBinding.java index a1a12be..566f9f6 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/SimpleCxfRsBinding.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/SimpleCxfRsBinding.java @@ -43,6 +43,7 @@ import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import org.apache.camel.Message; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.InputStreamDataSource; @@ -279,21 +280,31 @@ public class SimpleCxfRsBinding extends DefaultCxfRsBinding { } private void transferBinaryMultipartParameter(Object toMap, String parameterName, String multipartType, Message in) { - DataHandler dh = null; + org.apache.camel.Attachment dh = null; if (toMap instanceof Attachment) { - dh = ((Attachment) toMap).getDataHandler(); + dh = createCamelAttachment((Attachment) toMap); } else if (toMap instanceof DataSource) { - dh = new DataHandler((DataSource) toMap); + dh = new DefaultAttachment((DataSource) toMap); } else if (toMap instanceof DataHandler) { - dh = (DataHandler) toMap; + dh = new DefaultAttachment((DataHandler) toMap); } else if (toMap instanceof InputStream) { - dh = new DataHandler(new InputStreamDataSource((InputStream) toMap, multipartType == null ? "application/octet-stream" : multipartType)); + dh = new DefaultAttachment(new InputStreamDataSource((InputStream) toMap, multipartType == null ? "application/octet-stream" : multipartType)); } if (dh != null) { - in.addAttachment(parameterName, dh); + in.addAttachmentObject(parameterName, dh); } } - + + private DefaultAttachment createCamelAttachment(Attachment attachment) { + DefaultAttachment camelAttachment = new DefaultAttachment(attachment.getDataHandler()); + for (String name : attachment.getHeaders().keySet()) { + for(String value : attachment.getHeaderAsList(name)) { + camelAttachment.addHeader(name, value); + } + } + return camelAttachment; + } + protected static class MethodSpec { private boolean multipart; private int numberParameters; http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/DefaultCxfBindingTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/DefaultCxfBindingTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/DefaultCxfBindingTest.java index c82050a..a700832 100644 --- a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/DefaultCxfBindingTest.java +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/DefaultCxfBindingTest.java @@ -159,6 +159,7 @@ public class DefaultCxfBindingTest extends Assert { exchange.getIn().setHeader("MyFruitHeader", "peach"); exchange.getIn().setHeader("MyBrewHeader", Arrays.asList("cappuccino", "espresso")); exchange.getIn().addAttachment("att-1", new DataHandler(new FileDataSource("pom.xml"))); + exchange.getIn().getAttachmentObject("att-1").setHeader("attachment-header", "value 1"); cxfBinding.populateCxfRequestFromExchange(cxfExchange, exchange, requestContext); @@ -181,6 +182,7 @@ public class DefaultCxfBindingTest extends Assert { assertNotNull(attachments.size() == 1); Attachment att = attachments.iterator().next(); assertEquals("att-1", att.getId()); + assertEquals("value 1", att.getHeader("attachment-header")); } @Test @@ -200,7 +202,9 @@ public class DefaultCxfBindingTest extends Assert { cxfExchange.setInMessage(cxfMessage); Set<Attachment> attachments = new HashSet<Attachment>(); - attachments.add(new AttachmentImpl("att-1", new DataHandler(new FileDataSource("pom.xml")))); + AttachmentImpl attachment = new AttachmentImpl("att-1", new DataHandler(new FileDataSource("pom.xml"))); + attachment.setHeader("additional-header", "value 1"); + attachments.add(attachment); cxfMessage.setAttachments(attachments); cxfBinding.populateExchangeFromCxfResponse(exchange, cxfExchange, responseContext); @@ -209,9 +213,10 @@ public class DefaultCxfBindingTest extends Assert { assertNotNull(camelHeaders); assertEquals(responseContext, camelHeaders.get(Client.RESPONSE_CONTEXT)); - Map<String, DataHandler> camelAttachments = exchange.getOut().getAttachments(); + Map<String, org.apache.camel.Attachment> camelAttachments = exchange.getOut().getAttachmentObjects(); assertNotNull(camelAttachments); assertNotNull(camelAttachments.get("att-1")); + assertEquals("value 1", camelAttachments.get("att-1").getHeader("additional-header")); } @Test @@ -249,6 +254,7 @@ public class DefaultCxfBindingTest extends Assert { exchange.getOut().setHeader("soapAction", "urn:hello:world"); exchange.getOut().setHeader("MyFruitHeader", "peach"); exchange.getOut().addAttachment("att-1", new DataHandler(new FileDataSource("pom.xml"))); + exchange.getOut().getAttachmentObject("att-1").setHeader("attachment-header", "value 1"); IMocksControl control = EasyMock.createNiceControl(); @@ -281,6 +287,7 @@ public class DefaultCxfBindingTest extends Assert { assertNotNull(attachments.size() == 1); Attachment att = attachments.iterator().next(); assertEquals("att-1", att.getId()); + assertEquals("value 1", att.getHeader("attachment-header")); } @Test @@ -300,7 +307,9 @@ public class DefaultCxfBindingTest extends Assert { cxfMessage.put(org.apache.cxf.message.Message.PROTOCOL_HEADERS, headers); Set<Attachment> attachments = new HashSet<Attachment>(); - attachments.add(new AttachmentImpl("att-1", new DataHandler(new FileDataSource("pom.xml")))); + AttachmentImpl attachment = new AttachmentImpl("att-1", new DataHandler(new FileDataSource("pom.xml"))); + attachment.setHeader("attachment-header", "value 1"); + attachments.add(attachment); cxfMessage.setAttachments(attachments); cxfExchange.setInMessage(cxfMessage); @@ -315,11 +324,11 @@ public class DefaultCxfBindingTest extends Assert { assertEquals("241", camelHeaders.get("content-length")); assertEquals("peach", camelHeaders.get("MyFruitHeader")); assertEquals(Arrays.asList("cappuccino", "espresso"), camelHeaders.get("MyBrewHeader")); - - Map<String, DataHandler> camelAttachments = exchange.getIn().getAttachments(); + + Map<String, org.apache.camel.Attachment> camelAttachments = exchange.getIn().getAttachmentObjects(); assertNotNull(camelAttachments); assertNotNull(camelAttachments.get("att-1")); - + assertEquals("value 1", camelAttachments.get("att-1").getHeader("attachment-header")); } @Test http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrMessage.java ---------------------------------------------------------------------- diff --git a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrMessage.java b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrMessage.java index 7e2dd44..0cf02ac 100644 --- a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrMessage.java +++ b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrMessage.java @@ -77,7 +77,7 @@ public class JcrMessage extends DefaultMessage { getAttachments().clear(); if (that.hasAttachments()) { - getAttachments().putAll(that.getAttachments()); + getAttachmentObjects().putAll(that.getAttachmentObjects()); } } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-jetty9/src/main/java/org/apache/camel/component/jetty9/AttachmentHttpBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-jetty9/src/main/java/org/apache/camel/component/jetty9/AttachmentHttpBinding.java b/components/camel-jetty9/src/main/java/org/apache/camel/component/jetty9/AttachmentHttpBinding.java index 1b7bca1..293dd70 100644 --- a/components/camel-jetty9/src/main/java/org/apache/camel/component/jetty9/AttachmentHttpBinding.java +++ b/components/camel-jetty9/src/main/java/org/apache/camel/component/jetty9/AttachmentHttpBinding.java @@ -20,14 +20,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; -import javax.activation.DataHandler; import javax.activation.DataSource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; +import org.apache.camel.Attachment; import org.apache.camel.RuntimeCamelException; import org.apache.camel.http.common.DefaultHttpBinding; import org.apache.camel.http.common.HttpMessage; +import org.apache.camel.impl.DefaultAttachment; import org.eclipse.jetty.util.MultiPartInputStreamParser; /** @@ -50,7 +51,13 @@ final class AttachmentHttpBinding extends DefaultHttpBinding { parts = parser.getParts(); for (Part part : parts) { DataSource ds = new PartDataSource(part); - message.addAttachment(part.getName(), new DataHandler(ds)); + Attachment attachment = new DefaultAttachment(ds); + for (String headerName : part.getHeaderNames()) { + for (String headerValue : part.getHeaders(headerName)) { + attachment.addHeader(headerName, headerValue); + } + } + message.addAttachmentObject(part.getName(), attachment); } } catch (Exception e) { throw new RuntimeCamelException("Cannot populate attachments", e); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/MultiPartFormOkHttpTest.java ---------------------------------------------------------------------- diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/MultiPartFormOkHttpTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/MultiPartFormOkHttpTest.java index 1221cc9..fb02542 100644 --- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/MultiPartFormOkHttpTest.java +++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/MultiPartFormOkHttpTest.java @@ -62,6 +62,7 @@ public class MultiPartFormOkHttpTest extends BaseJettyTest { InputStream is = exchange.getIn().getAttachment("test").getInputStream(); assertNotNull(is); + assertEquals("form-data; name=\"test\"", exchange.getIn().getAttachmentObject("test").getHeader("content-disposition")); String data = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, is); assertNotNull("Should have data", data); assertEquals("some data here", data); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java ---------------------------------------------------------------------- diff --git a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java index fc307fb..0408ff7 100644 --- a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java +++ b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java @@ -102,7 +102,7 @@ public class JmsMessage extends DefaultMessage { getAttachments().clear(); if (that.hasAttachments()) { - getAttachments().putAll(that.getAttachments()); + getAttachmentObjects().putAll(that.getAttachmentObjects()); } } http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java index 79f4066..0596d61 100644 --- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java +++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java @@ -42,9 +42,11 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.mail.util.ByteArrayDataSource; +import org.apache.camel.Attachment; import org.apache.camel.Exchange; import org.apache.camel.RuntimeCamelException; import org.apache.camel.converter.ObjectConverter; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.impl.DefaultHeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.util.CollectionHelper; @@ -283,7 +285,7 @@ public class MailBinding { * @param message the mail message with attachments * @param map the map to add found attachments (attachmentFilename is the key) */ - public void extractAttachmentsFromMail(Message message, Map<String, DataHandler> map) + public void extractAttachmentsFromMail(Message message, Map<String, Attachment> map) throws MessagingException, IOException { LOG.trace("Extracting attachments +++ start +++"); @@ -298,7 +300,7 @@ public class MailBinding { LOG.trace("Extracting attachments +++ done +++"); } - protected void extractAttachmentsFromMultipart(Multipart mp, Map<String, DataHandler> map) + protected void extractAttachmentsFromMultipart(Multipart mp, Map<String, Attachment> map) throws MessagingException, IOException { for (int i = 0; i < mp.getCount(); i++) { @@ -326,7 +328,14 @@ public class MailBinding { LOG.debug("Mail contains file attachment: {}", fileName); if (!map.containsKey(fileName)) { // Parts marked with a disposition of Part.ATTACHMENT are clearly attachments - map.put(fileName, part.getDataHandler()); + DefaultAttachment camelAttachment = new DefaultAttachment(part.getDataHandler()); + @SuppressWarnings("unchecked") + Enumeration<Header> headers = part.getAllHeaders(); + while (headers.hasMoreElements()) { + Header header = headers.nextElement(); + camelAttachment.addHeader(header.getName(), header.getValue()); + } + map.put(fileName, camelAttachment); } else { LOG.warn("Cannot extract duplicate file attachment: {}.", fileName); } @@ -457,21 +466,29 @@ public class MailBinding { AttachmentsContentTransferEncodingResolver encodingResolver, Exchange exchange) throws MessagingException { LOG.trace("Adding attachments +++ start +++"); int i = 0; - for (Map.Entry<String, DataHandler> entry : exchange.getIn().getAttachments().entrySet()) { + for (Map.Entry<String, Attachment> entry : exchange.getIn().getAttachmentObjects().entrySet()) { String attachmentFilename = entry.getKey(); - DataHandler handler = entry.getValue(); + Attachment attachment = entry.getValue(); if (LOG.isTraceEnabled()) { LOG.trace("Attachment #{}: Disposition: {}", i, partDisposition); - LOG.trace("Attachment #{}: DataHandler: {}", i, handler); + LOG.trace("Attachment #{}: DataHandler: {}", i, attachment.getDataHandler()); LOG.trace("Attachment #{}: FileName: {}", i, attachmentFilename); } - if (handler != null) { - if (shouldAddAttachment(exchange, attachmentFilename, handler)) { + if (attachment != null) { + if (shouldAddAttachment(exchange, attachmentFilename, attachment.getDataHandler())) { // Create another body part BodyPart messageBodyPart = new MimeBodyPart(); // Set the data handler to the attachment - messageBodyPart.setDataHandler(handler); + messageBodyPart.setDataHandler(attachment.getDataHandler()); + + // Set headers to the attachment + for (String headerName : attachment.getHeaderNames()) { + List<String> values = attachment.getHeaderAsList(headerName); + for (String value : values) { + messageBodyPart.setHeader(headerName, value); + } + } if (attachmentFilename.toLowerCase().startsWith("cid:")) { // add a Content-ID header to the attachment http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java ---------------------------------------------------------------------- diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java index 949b0aa..5e0615b 100644 --- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java +++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java @@ -21,6 +21,7 @@ import javax.activation.DataHandler; import javax.mail.Message; import javax.mail.MessagingException; +import org.apache.camel.Attachment; import org.apache.camel.RuntimeCamelException; import org.apache.camel.impl.DefaultMessage; import org.apache.camel.util.ExchangeHelper; @@ -120,7 +121,7 @@ public class MailMessage extends DefaultMessage { } @Override - protected void populateInitialAttachments(Map<String, DataHandler> map) { + protected void populateInitialAttachments(Map<String, Attachment> map) { if (mailMessage != null) { try { MailBinding binding = ExchangeHelper.getBinding(getExchange(), MailBinding.class); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailUtils.java ---------------------------------------------------------------------- diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailUtils.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailUtils.java index 49b7cd0..dc4084e 100644 --- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailUtils.java +++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailUtils.java @@ -18,6 +18,7 @@ package org.apache.camel.component.mail; import java.text.DateFormat; import java.util.Date; + import javax.mail.Address; import javax.mail.Message; import javax.mail.MessagingException; http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-mail/src/main/java/org/apache/camel/component/mail/SplitAttachmentsExpression.java ---------------------------------------------------------------------- diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/SplitAttachmentsExpression.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/SplitAttachmentsExpression.java index 708428e..ca5aae5 100644 --- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/SplitAttachmentsExpression.java +++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/SplitAttachmentsExpression.java @@ -21,8 +21,8 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.activation.DataHandler; +import org.apache.camel.Attachment; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.RuntimeCamelException; @@ -78,7 +78,7 @@ public class SplitAttachmentsExpression extends ExpressionAdapter { try { List<Message> answer = new ArrayList<Message>(); Message inMessage = exchange.getIn(); - for (Map.Entry<String, DataHandler> entry : inMessage.getAttachments().entrySet()) { + for (Map.Entry<String, Attachment> entry : inMessage.getAttachmentObjects().entrySet()) { Message attachmentMessage; if (extractAttachments) { attachmentMessage = extractAttachment(inMessage, entry.getKey()); @@ -97,9 +97,9 @@ public class SplitAttachmentsExpression extends ExpressionAdapter { } } - private Message splitAttachment(Message inMessage, String attachmentName, DataHandler attachmentHandler) { + private Message splitAttachment(Message inMessage, String attachmentName, Attachment attachmentHandler) { final Message copy = inMessage.copy(); - Map<String, DataHandler> attachments = copy.getAttachments(); + Map<String, Attachment> attachments = copy.getAttachmentObjects(); attachments.clear(); attachments.put(attachmentName, attachmentHandler); copy.setHeader(HEADER_NAME, attachmentName); http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/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 index 86e5f35..0af87fb 100644 --- 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 @@ -44,9 +44,11 @@ import javax.mail.internet.MimeUtility; import javax.mail.internet.ParseException; import javax.mail.util.ByteArrayDataSource; +import org.apache.camel.Attachment; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.NoTypeConversionAvailableException; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.spi.DataFormat; import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.IOHelper; @@ -101,18 +103,25 @@ public class MimeMultipartDataFormat implements DataFormat { BodyPart part = new MimeBodyPart(); writeBodyPart(bodyContent, part, contentType); mp.addBodyPart(part); - for (Map.Entry<String, DataHandler> entry : exchange.getIn().getAttachments().entrySet()) { + for (Map.Entry<String, Attachment> entry : exchange.getIn().getAttachmentObjects().entrySet()) { String attachmentFilename = entry.getKey(); - DataHandler handler = entry.getValue(); + Attachment attachment = entry.getValue(); part = new MimeBodyPart(); - part.setDataHandler(handler); + part.setDataHandler(attachment.getDataHandler()); part.setFileName(MimeUtility.encodeText(attachmentFilename, "UTF-8", null)); - String ct = handler.getContentType(); + String ct = attachment.getDataHandler().getContentType(); contentType = new ContentType(ct); part.setHeader(CONTENT_TYPE, ct); if (!contentType.match("text/*") && binaryContent) { part.setHeader(CONTENT_TRANSFER_ENCODING, "binary"); } + // Set headers to the attachment + for (String headerName : attachment.getHeaderNames()) { + List<String> values = attachment.getHeaderAsList(headerName); + for (String value : values) { + part.setHeader(headerName, value); + } + } mp.addBodyPart(part); exchange.getOut().removeAttachment(attachmentFilename); } @@ -238,7 +247,14 @@ public class MimeMultipartDataFormat implements DataFormat { content = mp.getBodyPart(0); for (int i = 1; i < mp.getCount(); i++) { BodyPart bp = mp.getBodyPart(i); - camelMessage.addAttachment(getAttachmentKey(bp), bp.getDataHandler()); + DefaultAttachment camelAttachment = new DefaultAttachment(bp.getDataHandler()); + @SuppressWarnings("unchecked") + Enumeration<Header> headers = bp.getAllHeaders(); + while (headers.hasMoreElements()) { + Header header = headers.nextElement(); + camelAttachment.addHeader(header.getName(), header.getValue()); + } + camelMessage.addAttachmentObject(getAttachmentKey(bp), camelAttachment); } } if (content instanceof BodyPart) { http://git-wip-us.apache.org/repos/asf/camel/blob/50d6d4fb/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java ---------------------------------------------------------------------- diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java index e9ae035..fce729e 100644 --- a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java +++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java @@ -21,12 +21,14 @@ import java.util.Map; import javax.activation.DataHandler; import javax.activation.FileDataSource; +import org.apache.camel.Attachment; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.Producer; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.test.junit4.CamelTestSupport; import org.junit.Test; import org.jvnet.mock_javamail.Mailbox; @@ -50,7 +52,9 @@ public class MailAttachmentTest extends CamelTestSupport { Exchange exchange = endpoint.createExchange(); Message in = exchange.getIn(); in.setBody("Hello World"); - in.addAttachment("logo.jpeg", new DataHandler(new FileDataSource("src/test/data/logo.jpeg"))); + DefaultAttachment att = new DefaultAttachment(new FileDataSource("src/test/data/logo.jpeg")); + att.addHeader("Content-Description", "some sample content"); + in.addAttachmentObject("logo.jpeg", att); // create a producer that can produce the exchange (= send the mail) Producer producer = endpoint.createProducer(); @@ -73,11 +77,12 @@ public class MailAttachmentTest extends CamelTestSupport { assertEquals("Hello World", out.getIn().getBody(String.class)); // attachment - Map<String, DataHandler> attachments = out.getIn().getAttachments(); + Map<String, Attachment> attachments = out.getIn().getAttachmentObjects(); assertNotNull("Should have attachments", attachments); assertEquals(1, attachments.size()); - DataHandler handler = out.getIn().getAttachment("logo.jpeg"); + Attachment attachment = out.getIn().getAttachmentObject("logo.jpeg"); + DataHandler handler = attachment.getDataHandler(); assertNotNull("The logo should be there", handler); // content type should match @@ -87,6 +92,8 @@ public class MailAttachmentTest extends CamelTestSupport { assertEquals("Handler name should be the file name", "logo.jpeg", handler.getName()); + assertEquals("some sample content", attachment.getHeader("content-description")); + producer.stop(); }