View Javadoc

1   /*
2    * $Id: RetrieveMessageReceiver.java 7976 2007-08-21 14:26:13Z dirk.olmes $
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     protected UMOMessage handleUnacceptedFilter(UMOMessage message)
170     {
171         super.handleUnacceptedFilter(message);
172         if (message.getPayload() instanceof Message)
173         {
174             Message msg = (Message) message.getPayload();
175             try
176             {
177                 msg.setFlag(Flags.Flag.DELETED, endpoint.isDeleteUnacceptedMessages());
178             }
179             catch (MessagingException e)
180             {
181                 logger.error("failled to set message deleted: " + e.getMessage(), e);
182             }
183         }
184         return null;
185     }
186 
187     public void messagesRemoved(MessageCountEvent event)
188     {
189         if (logger.isDebugEnabled())
190         {
191             Message messages[] = event.getMessages();
192             for (int i = 0; i < messages.length; i++)
193             {
194                 try
195                 {
196                     logger.debug("Message removed: " + messages[i].getSubject());
197                 }
198                 catch (MessagingException ignore)
199                 {
200                     logger.debug("ignoring exception: " + ignore.getMessage());
201                 }
202             }
203         }
204     }
205 
206     /**
207      * @return the current Mail folder
208      */
209     public Folder getFolder()
210     {
211         return folder;
212     }
213 
214     /**
215      * @param folder
216      */
217     public synchronized void setFolder(Folder folder)
218     {
219         if (folder == null)
220         {
221             throw new IllegalArgumentException("Mail folder cannot be null");
222         }
223         this.folder = folder;
224         synchronized (this.folder)
225         {
226             if (!this.folder.isOpen())
227             {
228                 try
229                 {
230                     this.folder.open(Folder.READ_WRITE);
231                 }
232                 catch (MessagingException e)
233                 {
234                     logger.warn("Failed to open folder: " + folder.getFullName(), e);
235                 }
236             }
237         }
238     }
239 
240     /**
241      * Helper method for testing which stores a copy of the message locally as the
242      * POP3 <p/> message will be deleted from the server
243      * 
244      * @param msg the message to store
245      * @throws IOException If a failure happens writing the message
246      * @throws MessagingException If a failure happens reading the message
247      */
248     protected void storeMessage(Message msg) throws IOException, MessagingException
249     {
250         if (backupEnabled)
251         {
252             String filename = msg.getFileName();
253             if (filename == null)
254             {
255                 Address[] from = msg.getFrom();
256                 if (from != null && from.length > 0)
257                 {
258                     filename = from[0] instanceof InternetAddress
259                     ? ((InternetAddress) from[0]).getAddress()
260                     : from[0].toString();
261                 }
262                 else
263                 {
264                     filename = "(no from address)";
265                 }
266                 filename += "[" + UUID.getUUID() + "]";
267             }
268             filename = FileUtils.prepareWinFilename(filename);
269             filename = backupFolder + filename + ".msg";
270             if (logger.isDebugEnabled())
271             {
272                 logger.debug("Writing message to: " + filename);
273             }
274             File f = FileUtils.createFile(filename);
275             FileOutputStream fos = new FileOutputStream(f);
276             msg.writeTo(fos);
277         }
278     }
279 
280     public synchronized void poll()
281     {
282         try
283         {
284             try
285             {
286                 if (!folder.isOpen())
287                 {
288                     folder.open(Folder.READ_WRITE);
289                 }
290             }
291             catch (Exception e)
292             {
293                 if (logger.isDebugEnabled())
294                 {
295                     logger.debug("ignoring exception: " + e.getMessage());
296                 }
297             }
298 
299             int count = folder.getMessageCount();
300             if (count > 0)
301             {
302                 Message[] messages = folder.getMessages();
303                 MessageCountEvent event = new MessageCountEvent(folder, MessageCountEvent.ADDED, true,
304                     messages);
305                 messagesAdded(event);
306             }
307             else if (count == -1)
308             {
309                 throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
310                     + " as folder is closed");
311             }
312         }
313         catch (MessagingException e)
314         {
315             handleException(e);
316         }
317         finally
318         {
319             try
320             {
321                 folder.close(true); // close and expunge deleted messages
322             }
323             catch (Exception e)
324             {
325                 logger.error("Failed to close pop3  inbox: " + e.getMessage());
326             }
327         }
328     }
329 
330     protected void doDispose()
331     {
332         if (null != folder)
333         {
334             folder.removeMessageCountListener(this);
335             if (folder.isOpen())
336             {
337                 try
338                 {
339 
340                     folder.close(true);
341                 }
342                 catch (Exception e)
343                 {
344                     logger.debug("ignoring exception: " + e.getMessage(), e);
345                 }
346             }
347         }
348     }
349 
350 }