View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  package org.apache.james.postage.mail;
20  
21  import org.apache.james.postage.PostageRunner;
22  import org.apache.james.postage.PostageRuntimeException;
23  import org.apache.james.postage.classloading.CachedInstanceFactory;
24  import org.apache.james.postage.result.MailProcessingRecord;
25  import org.apache.james.util.io.IOUtil;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import javax.mail.BodyPart;
30  import javax.mail.MessagingException;
31  import javax.mail.internet.MimeMessage;
32  import javax.mail.internet.MimeMultipart;
33  
34  import java.io.ByteArrayOutputStream;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.util.regex.Pattern;
38  
39  /***
40   * helps matching, analysing and validating result mails and sent test mails
41   */
42  public class MailMatchingUtils {
43  
44      private static Log log = LogFactory.getLog(MailMatchingUtils.class);
45  
46      /***
47       * if this mail was created by postage, whatever run - but by startup check
48       */
49      public static boolean isPostageStartupCheckMail(MimeMessage message) {
50          String headerValue = getMailIdHeader(message);
51          return HeaderConstants.JAMES_POSTAGE_STARTUPCHECK_HEADER_ID.equals(headerValue);
52      }
53  
54      /***
55       * if this mail was created by postage, whatever run - but not by startup check
56       */
57      public static boolean isPostageTestMail(MimeMessage message) {
58          return isPostageMail(message) && !isPostageStartupCheckMail(message);
59      }
60  
61      /***
62       * if this mail was created by postage, whatever run - if startup check or live test
63       */
64      public static boolean isPostageMail(MimeMessage message) {
65          return null != getUniqueHeader(message, HeaderConstants.JAMES_POSTAGE_HEADER);
66      }
67  
68      public static boolean isPostageIdHeaderPresent(MimeMessage message) {
69          return null != getMailIdHeader(message);
70      }
71  
72      public static String getMailIdHeader(MimeMessage message) {
73          return getUniqueHeader(message, HeaderConstants.MAIL_ID_HEADER);
74      }
75  
76      /***
77       * if this mail was created by the currently running postage scenario - not by
78       * any of those before.
79       */
80      public static boolean isCurrentRunnerMail(MimeMessage message) {
81          String headerValue = getMailIdHeader(message);
82          return headerValue != null && headerValue.startsWith(PostageRunner.getMessageIdPrefix());
83      }
84  
85      public static boolean matchHeader(MimeMessage message, String header, String valueRegex) {
86          return Pattern.matches(valueRegex, getUniqueHeader(message, header));
87      }
88  
89      public static String getUniqueHeader(MimeMessage message, String header) {
90          String[] idHeaders;
91          try {
92              idHeaders = message.getHeader(header);
93          } catch (MessagingException e) {
94              throw new PostageRuntimeException(e);
95          }
96          if (idHeaders != null && idHeaders.length > 0) {
97              return idHeaders[0]; // there should be exactly one.
98          }
99          return null;
100     }
101 
102     public static boolean isMatchCandidate(MimeMessage message) {
103         try {
104             if (!isPostageIdHeaderPresent(message)) {
105                 if (isPostageMail(message)) {
106                     log.warn(HeaderConstants.MAIL_ID_HEADER + " header is missing from James test mail");
107                 }
108                 else log.info("skipping non-postage mail. remains on server. subject was: " + message.getSubject());
109                 return false;
110             }
111         } catch (MessagingException e) {
112             log.info("failed to get mail subject for logging. remains on server. mails might be corrupt.");
113             return false;
114         }
115         if (MailMatchingUtils.isPostageStartupCheckMail(message)) return false;
116         return true;
117     }
118     
119     public static boolean validateMail(MimeMessage message, MailProcessingRecord mailProcessingRecord) {
120         String classname = getUniqueHeader(message, HeaderConstants.JAMES_POSTAGE_VALIDATORCLASSNAME_HEADER);
121         MailValidator validator = (MailValidator)CachedInstanceFactory.createInstance(classname);
122         if (validator == null) return false;
123         
124         boolean isValid = validator.validate(message, mailProcessingRecord);
125         if (isValid) mailProcessingRecord.setValid();
126         else log.warn("failed to validate mail");
127         
128         return isValid;
129     }
130     
131     public static MimeMultipart convertToMimeMultipart(MimeMessage message) {
132         try {
133             return new MimeMultipart(message.getDataHandler().getDataSource());
134         } catch (MessagingException e) {
135             throw new RuntimeException("could not convert MimeMessage to MimeMultipart", e);
136         }
137     }
138     
139     public static int getMimePartSize(MimeMultipart parts, String mimeType) {
140         if (parts != null) {
141             try {
142                 for (int i = 0; i < parts.getCount(); i++) {
143                     BodyPart bodyPart = parts.getBodyPart(i);
144                     if (bodyPart.getContentType().startsWith(mimeType)) {
145                         try {
146                             Object content = bodyPart.getContent();
147                             if (content instanceof InputStream) {
148                                 ByteArrayOutputStream os = new ByteArrayOutputStream();
149                                 IOUtil.copy(((InputStream) content), os);
150                                 return os.size();
151                             } else if (content instanceof String) {
152                                 return ((String) content).length();
153                             } else {
154                                 throw new IllegalStateException("Unsupported content: "+content.getClass().toString());
155                             }
156                         } catch (IOException e) {
157                             throw new IllegalStateException("Unexpected IOException in getContent()");
158                         }
159                     }
160                 }
161             } catch (MessagingException e) {
162                 log.info("failed to process body parts.", e);
163             }
164         }
165         return 0;
166     }
167 }