Author: davsclaus Date: Thu May 14 06:46:07 2009 New Revision: 774657 URL: http://svn.apache.org/viewvc?rev=774657&view=rev Log: MR-173: Added TRACE logging to camel-mail and option for ContentTypeResolver to work around bugs in geronimo mail jar.
Added: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java (with props) camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailContentTypeResolverTest.java - copied, changed from r774627, camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java Modified: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailComponent.java camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSubjectTest.java camel/trunk/components/camel-mail/src/test/resources/log4j.properties Added: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java?rev=774657&view=auto ============================================================================== --- camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java (added) +++ camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java Thu May 14 06:46:07 2009 @@ -0,0 +1,45 @@ +/** + * 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.component.mail; + +/** + * Resolver to determine Content-Type for file attachments. + * <p/> + * Strategy introduced to work around mail providers having problems with this such as geronimo mail jars. + * <p/> + * Note using SUN mail jar have no problem with resolving Content-Type based on file attachments. This resolver + * is thus only needed to work around mail providers having bugs or when you a new mime type is unknown by the + * mail provider allowing you to deterime it. + * + * @version $Revision$ + */ +public interface ContentTypeResolver { + + /** + * Resolves the mime content-type based on the attachment file name. + * <p/> + * Return <tt>null</tt> if you cannot resolve a content type or want to rely on the mail provider + * to resolve it for you. + * <p/> + * The returned value should only be the mime part of the ContentType header, for example: + * <tt>image/jpeg</tt> should be returned. Camel will add the remaining <tt>; name=FILENAME</tt>. + * + * @param fileName the attachment file nane + * @return the Content-Type or <tt>null</tt> to rely on the mail provider + */ + public String resolveContentType(String fileName); +} Propchange: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/ContentTypeResolver.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Modified: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java (original) +++ camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java Thu May 14 06:46:07 2009 @@ -43,6 +43,8 @@ import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.util.CollectionHelper; import org.apache.camel.util.ObjectHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * A Strategy used to convert between a Camel {...@link Exchange} and {...@link Message} to and @@ -52,14 +54,17 @@ */ public class MailBinding { + private static final transient Log LOG = LogFactory.getLog(MailBinding.class); private HeaderFilterStrategy headerFilterStrategy; + private ContentTypeResolver contentTypeResolver; public MailBinding() { headerFilterStrategy = new DefaultHeaderFilterStrategy(); } - public MailBinding(HeaderFilterStrategy headerFilterStrategy) { + public MailBinding(HeaderFilterStrategy headerFilterStrategy, ContentTypeResolver contentTypeResolver) { this.headerFilterStrategy = headerFilterStrategy; + this.contentTypeResolver = contentTypeResolver; } public void populateMailMessage(MailEndpoint endpoint, MimeMessage mimeMessage, Exchange exchange) @@ -152,7 +157,7 @@ } private void setRecipientFromCamelMessage(MimeMessage mimeMessage, Exchange exchange, - org.apache.camel.Message camelMessage) + org.apache.camel.Message camelMessage) throws MessagingException { for (Map.Entry<String, Object> entry : camelMessage.getHeaders().entrySet()) { @@ -208,34 +213,63 @@ multipart.setSubType("mixed"); addBodyToMultipart(camelMessage, configuration, multipart); String partDisposition = configuration.isUseInlineAttachments() ? Part.INLINE : Part.ATTACHMENT; - addAttachmentsToMultipart(camelMessage, multipart, partDisposition); + if (camelMessage.hasAttachments()) { + addAttachmentsToMultipart(camelMessage, multipart, partDisposition); + } return multipart; } protected void addAttachmentsToMultipart(org.apache.camel.Message camelMessage, MimeMultipart multipart, String partDisposition) throws MessagingException { + LOG.trace("Adding attachments +++ start +++"); + int i = 0; for (Map.Entry<String, DataHandler> entry : camelMessage.getAttachments().entrySet()) { String attachmentFilename = entry.getKey(); DataHandler handler = entry.getValue(); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attachment #" + i + ": Disposition: " + partDisposition); + LOG.trace("Attachment #" + i + ": DataHandler: " + handler); + LOG.trace("Attachment #" + i + ": FileName: " + attachmentFilename); + } if (handler != null) { - if (shouldOutputAttachment(camelMessage, attachmentFilename, handler)) { + if (shouldAddAttachment(camelMessage, attachmentFilename, handler)) { // Create another body part BodyPart messageBodyPart = new MimeBodyPart(); // Set the data handler to the attachment messageBodyPart.setDataHandler(handler); if (attachmentFilename.toLowerCase().startsWith("cid:")) { - // add a Content-ID header to the attachment + // add a Content-ID header to the attachment messageBodyPart.addHeader("Content-ID", attachmentFilename.substring(4)); } + // Set the filename messageBodyPart.setFileName(attachmentFilename); + LOG.trace("Attachment #" + i + ": ContentType: " + messageBodyPart.getContentType()); + + if (contentTypeResolver != null) { + String contentType = contentTypeResolver.resolveContentType(attachmentFilename); + LOG.trace("Attachment #" + i + ": Using content type resolver: " + contentTypeResolver + " resolved content type as: " + contentType); + if (contentType != null) { + String value = contentType + "; name=" + attachmentFilename; + messageBodyPart.setHeader("Content-Type", value); + LOG.trace("Attachment #" + i + ": ContentType: " + messageBodyPart.getContentType()); + } + } + // Set Disposition messageBodyPart.setDisposition(partDisposition); // Add part to multipart multipart.addBodyPart(messageBodyPart); + } else { + LOG.trace("shouldAddAttachment: false"); } + } else { + LOG.warn("Cannot add attachment: " + attachmentFilename + " as DataHandler is null"); } + i++; } + LOG.trace("Adding attachments +++ done +++"); } protected void createMultipartAlternativeMessage(MimeMessage mimeMessage, org.apache.camel.Message camelMessage, MailConfiguration configuration) @@ -281,11 +315,10 @@ activeMultipart.addBodyPart(bodyMessage); } - /** - * Strategy to allow filtering of attachments which are put on the Mail message + * Strategy to allow filtering of attachments which are added on the Mail message */ - protected boolean shouldOutputAttachment(org.apache.camel.Message camelMessage, String attachmentFilename, DataHandler handler) { + protected boolean shouldAddAttachment(org.apache.camel.Message camelMessage, String attachmentFilename, DataHandler handler) { return true; } Modified: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailComponent.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailComponent.java?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailComponent.java (original) +++ camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailComponent.java Thu May 14 06:46:07 2009 @@ -33,6 +33,7 @@ */ public class MailComponent extends DefaultComponent { private MailConfiguration configuration; + private ContentTypeResolver contentTypeResolver; public MailComponent() { this.configuration = new MailConfiguration(); @@ -63,6 +64,7 @@ configureAdditionalJavaMailProperties(config, parameters); MailEndpoint endpoint = new MailEndpoint(uri, this, config); + endpoint.setContentTypeResolver(contentTypeResolver); setProperties(endpoint.getConfiguration(), parameters); // sanity check that we know the mail server @@ -112,4 +114,11 @@ return path; } + public ContentTypeResolver getContentTypeResolver() { + return contentTypeResolver; + } + + public void setContentTypeResolver(ContentTypeResolver contentTypeResolver) { + this.contentTypeResolver = contentTypeResolver; + } } Modified: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java (original) +++ camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java Thu May 14 06:46:07 2009 @@ -38,6 +38,7 @@ private MailBinding binding; private MailConfiguration configuration; private HeaderFilterStrategy headerFilterStrategy = new DefaultHeaderFilterStrategy(); + private ContentTypeResolver contentTypeResolver; public MailEndpoint() { } @@ -111,7 +112,7 @@ public MailBinding getBinding() { if (binding == null) { - binding = new MailBinding(headerFilterStrategy); + binding = new MailBinding(headerFilterStrategy, contentTypeResolver); } return binding; } @@ -139,4 +140,11 @@ this.headerFilterStrategy = headerFilterStrategy; } + public ContentTypeResolver getContentTypeResolver() { + return contentTypeResolver; + } + + public void setContentTypeResolver(ContentTypeResolver contentTypeResolver) { + this.contentTypeResolver = contentTypeResolver; + } } Modified: camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java (original) +++ camel/trunk/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailMessage.java Thu May 14 06:46:07 2009 @@ -28,6 +28,8 @@ import org.apache.camel.RuntimeCamelException; import org.apache.camel.impl.DefaultMessage; import org.apache.camel.util.CollectionHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Represents a {...@link org.apache.camel.Message} for working with Mail @@ -35,6 +37,7 @@ * @version $Revision:520964 $ */ public class MailMessage extends DefaultMessage { + private static final transient Log LOG = LogFactory.getLog(MailMessage.class); private Message mailMessage; public MailMessage() { @@ -138,29 +141,46 @@ protected static void extractAttachments(Message message, Map<String, DataHandler> map) throws javax.mail.MessagingException, IOException { + LOG.trace("Extracting attachments +++ start +++"); + Object content = message.getContent(); if (content instanceof Multipart) { extractFromMultipart((Multipart)content, map); + } else if (content != null) { + LOG.trace("No attachments to extract as content is not Multipart: " + content.getClass().getName()); } + + LOG.trace("Extracting attachments +++ done +++"); } protected static void extractFromMultipart(Multipart mp, Map<String, DataHandler> map) throws javax.mail.MessagingException, IOException { for (int i = 0; i < mp.getCount(); i++) { - Part part = mp.getBodyPart(i); + Part part = mp.getBodyPart(i); + LOG.trace("Part #" + i + ": " + part); + if (part.isMimeType("multipart/*")) { + LOG.trace("Part #" + i + ": is mimetype: multipart/*"); extractFromMultipart((Multipart)part.getContent(), map); } else { String disposition = part.getDisposition(); - if (disposition != null) { - if (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE)) { - // only add named attachments - if (part.getFileName() != null) { - // Parts marked with a disposition of Part.ATTACHMENT - // are clearly attachments - CollectionHelper.appendValue(map, part.getFileName(), part.getDataHandler()); - } + if (LOG.isTraceEnabled()) { + LOG.trace("Part #" + i + ": Disposition: " + part.getDisposition()); + LOG.trace("Part #" + i + ": Description: " + part.getDescription()); + LOG.trace("Part #" + i + ": ContentType: " + part.getContentType()); + LOG.trace("Part #" + i + ": FileName: " + part.getFileName()); + LOG.trace("Part #" + i + ": Size: " + part.getSize()); + LOG.trace("Part #" + i + ": LineCount: " + part.getLineCount()); + } + + if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) { + // only add named attachments + String fileName = part.getFileName(); + if (fileName != null) { + LOG.debug("Mail contains file attachment: " + fileName); + // Parts marked with a disposition of Part.ATTACHMENT are clearly attachments + CollectionHelper.appendValue(map, fileName, part.getDataHandler()); } } } Copied: camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailContentTypeResolverTest.java (from r774627, camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java) URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailContentTypeResolverTest.java?p2=camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailContentTypeResolverTest.java&p1=camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java&r1=774627&r2=774657&rev=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailAttachmentTest.java (original) +++ camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailContentTypeResolverTest.java Thu May 14 06:46:07 2009 @@ -17,7 +17,6 @@ package org.apache.camel.component.mail; import java.util.Map; - import javax.activation.DataHandler; import javax.activation.FileDataSource; @@ -32,11 +31,9 @@ /** * Unit test for Camel attachments and Mail attachments. */ -public class MailAttachmentTest extends ContextTestSupport { - - public void testSendAndRecieveMailWithAttachments() throws Exception { - // START SNIPPET: e1 +public class MailContentTypeResolverTest extends ContextTestSupport { + public void testCustomContentTypeResolver() throws Exception { // create an exchange with a normal body and attachment to be produced as email Endpoint endpoint = context.getEndpoint("smtp://ja...@mymailserver.com?password=secret"); @@ -53,8 +50,6 @@ // and let it go (processes the exchange by sending the email) producer.process(exchange); - // END SNIPPET: e1 - // need some time for the mail to arrive on the inbox (consumed and sent to the mock) Thread.sleep(1000); @@ -74,8 +69,8 @@ DataHandler handler = out.getIn().getAttachment("logo.jpeg"); assertNotNull("The logo should be there", handler); - // TODO: content type does not work with geronomi mail jar (its a buggy jar, use SUN mail jar instead) - // assertEquals("image/jpeg; name=logo.jpeg", handler.getContentType()); + // as we use a custom content type resolver the content type should then be fixed and correct + assertEquals("image/jpeg; name=logo.jpeg", handler.getContentType()); producer.stop(); } @@ -83,8 +78,15 @@ protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception { + MailComponent mail = getContext().getComponent("smtp", MailComponent.class); + mail.setContentTypeResolver(new ContentTypeResolver() { + public String resolveContentType(String fileName) { + return "image/jpeg"; + } + }); + from("pop3://ja...@mymailserver.com?password=secret&consumer.delay=1000").to("mock:result"); } }; } -} +} \ No newline at end of file Modified: camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSubjectTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSubjectTest.java?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSubjectTest.java (original) +++ camel/trunk/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSubjectTest.java Thu May 14 06:46:07 2009 @@ -40,6 +40,8 @@ template.sendBody("direct:a", body); mock.assertIsSatisfied(); + + assertFalse("Should not have attachements", mock.getExchanges().get(0).getIn().hasAttachments()); } protected RouteBuilder createRouteBuilder() throws Exception { Modified: camel/trunk/components/camel-mail/src/test/resources/log4j.properties URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-mail/src/test/resources/log4j.properties?rev=774657&r1=774656&r2=774657&view=diff ============================================================================== --- camel/trunk/components/camel-mail/src/test/resources/log4j.properties (original) +++ camel/trunk/components/camel-mail/src/test/resources/log4j.properties Thu May 14 06:46:07 2009 @@ -32,4 +32,4 @@ log4j.appender.file.file=target/camel-mail-test.log # debug logging for Camel -log4j.logger.org.apache.camel.component.mail=DEBUG \ No newline at end of file +log4j.logger.org.apache.camel.component.mail=TRACE \ No newline at end of file