View Javadoc

1   /*
2    * $Id: RetrieveMessageReceiver.java 10330 2008-01-15 15:32:02Z holger $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.providers.email;
12  
13  import org.mule.MuleManager;
14  import org.mule.impl.MuleMessage;
15  import org.mule.providers.AbstractPollingMessageReceiver;
16  import org.mule.providers.email.i18n.EmailMessages;
17  import org.mule.umo.UMOComponent;
18  import org.mule.umo.UMOException;
19  import org.mule.umo.UMOMessage;
20  import org.mule.umo.endpoint.UMOEndpoint;
21  import org.mule.umo.lifecycle.InitialisationException;
22  import org.mule.umo.lifecycle.Startable;
23  import org.mule.umo.lifecycle.Stoppable;
24  import org.mule.umo.provider.ReceiveException;
25  import org.mule.umo.provider.UMOConnector;
26  import org.mule.umo.routing.RoutingException;
27  import org.mule.util.FileUtils;
28  import org.mule.util.StringUtils;
29  import org.mule.util.UUID;
30  
31  import java.io.File;
32  import java.io.FileOutputStream;
33  import java.io.IOException;
34  
35  import javax.mail.Address;
36  import javax.mail.Flags;
37  import javax.mail.Folder;
38  import javax.mail.Message;
39  import javax.mail.MessagingException;
40  import javax.mail.Store;
41  import javax.mail.event.MessageCountEvent;
42  import javax.mail.event.MessageCountListener;
43  import javax.mail.internet.InternetAddress;
44  import javax.mail.internet.MimeMessage;
45  
46  /**
47   * Poll a mailbox for messages, remove the messages and route them as events into Mule.
48   *
49   * This contains a reference to a mail folder (and also the endpoint and connector, via superclasses)
50   */
51  
52  public class RetrieveMessageReceiver extends AbstractPollingMessageReceiver
53      implements MessageCountListener, Startable, Stoppable
54  {
55      private Folder folder = null;
56      private boolean backupEnabled;
57      private String backupFolder = null;
58  
59      public RetrieveMessageReceiver(UMOConnector connector,
60                                     UMOComponent component,
61                                     UMOEndpoint endpoint,
62                                     long checkFrequency,
63                                     boolean backupEnabled,
64                                     String backupFolder)
65      throws InitialisationException
66      {
67          super(connector, component, endpoint);
68          this.backupFolder = backupFolder;
69          this.backupEnabled = backupEnabled;
70          this.setFrequency(checkFrequency);
71      }
72  
73      private AbstractRetrieveMailConnector castConnector()
74      {
75          return (AbstractRetrieveMailConnector) getConnector();
76      }
77  
78      protected void doConnect() throws Exception
79      {
80          SessionDetails session = castConnector().getSessionDetails(endpoint);
81  
82          Store store = session.newStore();
83          store.connect();
84          folder = store.getFolder(castConnector().getMailboxFolder());
85  
86          // set default value if empty/null
87          if (StringUtils.isEmpty(backupFolder))
88          {
89              this.backupFolder = 
90                  MuleManager.getConfiguration().getWorkingDirectory() + "/mail/" + folder.getName();
91          }
92  
93          if (backupFolder != null && !this.backupFolder.endsWith(File.separator))
94          {
95              this.backupFolder += File.separator;
96          }
97      }
98  
99      protected void doDisconnect() throws Exception
100     {
101         // nothing to do here
102     }
103 
104     protected void doStop()
105     {
106         if (folder != null)
107         {
108             folder.removeMessageCountListener(this);
109         }
110     }
111 
112     protected void doStart() throws UMOException
113     {
114         super.doStart();
115         folder.addMessageCountListener(this);
116     }
117 
118     public void messagesAdded(MessageCountEvent event)
119     {
120         Message messages[] = event.getMessages();
121         if (messages != null)
122         {
123             UMOMessage message = null;
124             for (int i = 0; i < messages.length; i++)
125             {
126                 try
127                 {
128                     if (!messages[i].getFlags().contains(Flags.Flag.DELETED))
129                     {
130                         MimeMessage mimeMessage = new MimeMessage((MimeMessage) messages[i]);
131                         storeMessage(mimeMessage);
132                         message = new MuleMessage(castConnector().getMessageAdapter(mimeMessage));
133 
134                         if (castConnector().isDeleteReadMessages())
135                         {
136                             // Mark as deleted
137                             messages[i].setFlag(Flags.Flag.DELETED, true);
138                         }
139                         else
140                         {
141                             messages[i].setFlag(Flags.Flag.SEEN, true);
142                         }
143                         routeMessage(message, endpoint.isSynchronous());
144                     }
145                 }
146                 catch (UMOException e)
147                 {
148                     handleException(e);
149                 }
150                 catch (Exception e)
151                 {
152                     Exception forwarded;
153 
154                     if (message != null)
155                     {
156                         forwarded = new RoutingException(EmailMessages.routingError(), message, endpoint, e);
157                     }
158                     else
159                     {
160                         forwarded = new ReceiveException(endpoint, -1, e);
161                     }
162 
163                     handleException(forwarded);
164                 }
165             }
166         }
167     }
168 
169     // @Override
170     protected UMOMessage handleUnacceptedFilter(UMOMessage message)
171     {
172         super.handleUnacceptedFilter(message);
173         if (message.getPayload() instanceof Message)
174         {
175             Message msg = (Message) message.getPayload();
176             try
177             {
178                 msg.setFlag(Flags.Flag.DELETED, endpoint.isDeleteUnacceptedMessages());
179             }
180             catch (MessagingException e)
181             {
182                 logger.error("failed to set message deleted: " + e.getMessage(), e);
183             }
184         }
185         return message;
186     }
187 
188     public void messagesRemoved(MessageCountEvent event)
189     {
190         if (logger.isDebugEnabled())
191         {
192             Message messages[] = event.getMessages();
193             for (int i = 0; i < messages.length; i++)
194             {
195                 try
196                 {
197                     logger.debug("Message removed: " + messages[i].getSubject());
198                 }
199                 catch (MessagingException ignore)
200                 {
201                     logger.debug("ignoring exception: " + ignore.getMessage());
202                 }
203             }
204         }
205     }
206 
207     /**
208      * @return the current Mail folder
209      */
210     public Folder getFolder()
211     {
212         return folder;
213     }
214 
215     /**
216      * @param folder
217      */
218     public synchronized void setFolder(Folder folder)
219     {
220         if (folder == null)
221         {
222             throw new IllegalArgumentException("Mail folder cannot be null");
223         }
224         this.folder = folder;
225         synchronized (this.folder)
226         {
227             if (!this.folder.isOpen())
228             {
229                 try
230                 {
231                     this.folder.open(Folder.READ_WRITE);
232                 }
233                 catch (MessagingException e)
234                 {
235                     logger.warn("Failed to open folder: " + folder.getFullName(), e);
236                 }
237             }
238         }
239     }
240 
241     /**
242      * Helper method for testing which stores a copy of the message locally as the
243      * POP3 <p/> message will be deleted from the server
244      * 
245      * @param msg the message to store
246      * @throws IOException If a failure happens writing the message
247      * @throws MessagingException If a failure happens reading the message
248      */
249     protected void storeMessage(Message msg) throws IOException, MessagingException
250     {
251         if (backupEnabled)
252         {
253             String filename = msg.getFileName();
254             if (filename == null)
255             {
256                 Address[] from = msg.getFrom();
257                 if (from != null && from.length > 0)
258                 {
259                     filename = from[0] instanceof InternetAddress
260                     ? ((InternetAddress) from[0]).getAddress()
261                     : from[0].toString();
262                 }
263                 else
264                 {
265                     filename = "(no from address)";
266                 }
267                 filename += "[" + UUID.getUUID() + "]";
268             }
269             filename = FileUtils.prepareWinFilename(filename);
270             filename = backupFolder + filename + ".msg";
271             if (logger.isDebugEnabled())
272             {
273                 logger.debug("Writing message to: " + filename);
274             }
275             File f = FileUtils.createFile(filename);
276             FileOutputStream fos = new FileOutputStream(f);
277             msg.writeTo(fos);
278         }
279     }
280 
281     public synchronized void poll()
282     {
283         try
284         {
285             try
286             {
287                 if (!folder.isOpen())
288                 {
289                     folder.open(Folder.READ_WRITE);
290                 }
291             }
292             catch (Exception e)
293             {
294                 if (logger.isDebugEnabled())
295                 {
296                     logger.debug("ignoring exception: " + e.getMessage());
297                 }
298             }
299 
300             int count = folder.getMessageCount();
301             if (count > 0)
302             {
303                 Message[] messages = folder.getMessages();
304                 MessageCountEvent event = new MessageCountEvent(folder, MessageCountEvent.ADDED, true,
305                     messages);
306                 messagesAdded(event);
307             }
308             else if (count == -1)
309             {
310                 throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
311                     + " as folder is closed");
312             }
313         }
314         catch (MessagingException e)
315         {
316             handleException(e);
317         }
318         finally
319         {
320             try
321             {
322                 folder.close(true); // close and expunge deleted messages
323             }
324             catch (Exception e)
325             {
326                 logger.error("Failed to close pop3  inbox: " + e.getMessage());
327             }
328         }
329     }
330 
331     protected void doDispose()
332     {
333         if (null != folder)
334         {
335             folder.removeMessageCountListener(this);
336             if (folder.isOpen())
337             {
338                 try
339                 {
340 
341                     folder.close(true);
342                 }
343                 catch (Exception e)
344                 {
345                     logger.debug("ignoring exception: " + e.getMessage(), e);
346                 }
347             }
348         }
349     }
350 
351 }