View Javadoc

1   /*
2    * $Id: RetrieveMessageRequester.java 10961 2008-02-22 19:01:02Z dfeist $
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.transport.email;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.endpoint.EndpointURI;
17  import org.mule.api.endpoint.InboundEndpoint;
18  import org.mule.transport.AbstractMessageRequester;
19  
20  import javax.mail.Flags;
21  import javax.mail.Folder;
22  import javax.mail.Message;
23  import javax.mail.MessagingException;
24  import javax.mail.Store;
25  
26  /**
27   * This dispatcher can only be used to receive message (as opposed to listening for them).
28   * Trying to send or dispatch will throw an UnsupportedOperationException.
29   *
30   * This contains a reference to a mail folder (and also the endpoint and connector, via superclasses)
31   */
32  
33  public class RetrieveMessageRequester extends AbstractMessageRequester
34  {
35      private Folder folder;
36  
37      public RetrieveMessageRequester(InboundEndpoint endpoint)
38      {
39          super(endpoint);
40      }
41  
42      private AbstractRetrieveMailConnector castConnector()
43      {
44          return (AbstractRetrieveMailConnector) getConnector();
45      }
46  
47      protected void doConnect() throws Exception
48      {
49          if (folder == null || !folder.isOpen())
50          {
51  
52              Store store = castConnector().getSessionDetails(endpoint).newStore();
53  
54              EndpointURI uri = endpoint.getEndpointURI();
55              store.connect(uri.getHost(), uri.getPort(), uri.getUser(), uri.getPassword());
56  
57              folder = store.getFolder(castConnector().getMailboxFolder());
58              if (!folder.isOpen())
59              {
60                  try
61                  {
62                      // Depending on Server implementation it's not always
63                      // necessary to open the folder to check it
64                      // Opening folders can be exprensive!
65                      // folder.open(Folder.READ_ONLY);
66                      folder.open(Folder.READ_WRITE);
67                  }
68                  catch (MessagingException e)
69                  {
70                      logger.warn("Failed to open folder: " + folder.getFullName(), e);
71                  }
72              }
73          }
74      }
75  
76      protected void doDisconnect() throws Exception
77      {
78          // close and expunge deleted messages
79          try
80          {
81              if (folder != null)
82              {
83                  try
84                  {
85                      folder.expunge();
86                  }
87                  catch (MessagingException e)
88                  {
89                      if (logger.isDebugEnabled())
90                      {
91                          logger.debug("ignoring exception on expunge: " + e.getMessage());
92                      }
93                  }
94                  if (folder.isOpen())
95                  {
96                      folder.close(true);
97                  }
98              }
99          }
100         catch (Exception e)
101         {
102             logger.error("Failed to close inbox: " + e.getMessage(), e);
103         }
104     }
105 
106     /**
107      * @param event
108      * @throws UnsupportedOperationException
109      */
110     protected void doDispatch(MuleEvent event) throws Exception
111     {
112         throw new UnsupportedOperationException("Cannot dispatch from a Pop3 connection");
113     }
114 
115     /**
116      * @param event
117      * @return
118      * @throws UnsupportedOperationException
119      */
120     protected MuleMessage doSend(MuleEvent event) throws Exception
121     {
122         throw new UnsupportedOperationException("Cannot send from a Pop3 connection");
123     }
124 
125     /**
126      * Make a specific request to the underlying transport. Endpoint can be in the
127      * form of pop3://username:password@pop3.lotsofmail.org
128      *
129      * @param timeout the maximum time the operation should block before returning.
130      *            The call should return immediately if there is data available. If
131      *            no data becomes available before the timeout elapses, null will be
132      *            returned
133      * @return the result of the request wrapped in a MuleMessage object. Null will be
134      *         returned if no data was avaialable
135      * @throws Exception if the call to the underlying protocal causes an exception
136      */
137     protected MuleMessage doRequest(long timeout) throws Exception
138     {
139         long t0 = System.currentTimeMillis();
140         if (timeout < 0)
141         {
142             timeout = Long.MAX_VALUE;
143         }
144 
145         do
146         {
147             if (hasMessages(folder))
148             {
149                 int count = getMessageCount(folder);
150                 if (count > 0)
151                 {
152                     Message message = getNextMessage(folder);
153                     // so we don't get the same message again
154                     flagMessage(folder, message);
155 
156                     return new DefaultMuleMessage(castConnector().getMessageAdapter(message));
157                 }
158                 else if (count == -1)
159                 {
160                     throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
161                         + " as folder is closed");
162                 }
163             }
164 
165             long sleep =
166                 Math.min(castConnector().getCheckFrequency(),
167                     timeout - (System.currentTimeMillis() - t0));
168 
169             if (sleep > 0)
170             {
171                 if (logger.isDebugEnabled())
172                 {
173                     logger.debug("No results, sleeping for " + sleep);
174                 }
175                 Thread.sleep(sleep);
176             }
177             else
178             {
179 
180                 logger.debug("Timeout");
181                 return null;
182             }
183 
184         }
185         while (true);
186     }
187 
188     /**
189      * There seems to be som variation on pop3 implementation so it may be
190      * preferrable to mark messages as seen here and alos overload the getMessages
191      * method to grab only new messages
192      *
193      * @param message
194      * @throws javax.mail.MessagingException
195      */
196     protected void flagMessage(Folder folder, Message message) throws MessagingException
197     {
198         message.setFlag(Flags.Flag.DELETED, true);
199     }
200 
201     protected static Message getNextMessage(Folder folder) throws MessagingException
202     {
203         return folder.getMessage(1);
204     }
205 
206     protected static int getMessageCount(Folder folder) throws MessagingException
207     {
208         return folder.getMessageCount();
209     }
210 
211     /**
212      * Optimised check to se whether to return the message count and retrieve the
213      * messages. Some pop3 implementations differ so an optimised check such as
214      * folder.hasNewMessages() cannot be used
215      *
216      * @param folder
217      * @return
218      * @throws javax.mail.MessagingException
219      */
220     protected static boolean hasMessages(Folder folder) throws MessagingException
221     {
222         return getMessageCount(folder) > 0;
223     }
224 
225     protected void doDispose()
226     {
227         if (null != folder && folder.isOpen())
228         {
229             try
230             {
231 
232                 folder.close(true);
233             }
234             catch (Exception e)
235             {
236                 logger.debug("ignoring exception: " + e.getMessage(), e);
237             }
238         }
239     }
240 
241 }