Coverage Report - org.mule.transport.email.RetrieveMessageRequester
 
Classes in this File Line Coverage Branch Coverage Complexity
RetrieveMessageRequester
0%
0/90
0%
0/52
0
 
 1  
 /*
 2  
  * $Id: RetrieveMessageRequester.java 20321 2010-11-24 15:21:24Z dfeist $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.api.MuleEvent;
 14  
 import org.mule.api.MuleMessage;
 15  
 import org.mule.api.endpoint.EndpointURI;
 16  
 import org.mule.api.endpoint.InboundEndpoint;
 17  
 import org.mule.transport.AbstractMessageRequester;
 18  
 
 19  
 import com.sun.mail.imap.IMAPMessage;
 20  
 
 21  
 import java.net.URLDecoder;
 22  
 
 23  
 import javax.mail.Flags;
 24  
 import javax.mail.Folder;
 25  
 import javax.mail.Message;
 26  
 import javax.mail.MessagingException;
 27  
 import javax.mail.Store;
 28  
 import javax.mail.internet.MimeMessage;
 29  
 
 30  
 /**
 31  
  * This dispatcher can only be used to receive message (as opposed to listening for them).
 32  
  * Trying to send or dispatch will throw an UnsupportedOperationException.
 33  
  * <p/>
 34  
  * This contains a reference to a mail folder (and also the endpoint and connector, via superclasses)
 35  
  */
 36  
 public class RetrieveMessageRequester extends AbstractMessageRequester
 37  
 {
 38  
     private Folder folder;
 39  
     private Folder moveToFolder;
 40  
 
 41  
     public RetrieveMessageRequester(InboundEndpoint endpoint)
 42  
     {
 43  0
         super(endpoint);
 44  0
     }
 45  
 
 46  
     private AbstractRetrieveMailConnector castConnector()
 47  
     {
 48  0
         return (AbstractRetrieveMailConnector) getConnector();
 49  
     }
 50  
 
 51  
     @Override
 52  
     protected void doConnect() throws Exception
 53  
     {
 54  0
         if (folder == null || !folder.isOpen())
 55  
         {
 56  0
             Store store = castConnector().getSessionDetails(endpoint).newStore();
 57  
 
 58  0
             EndpointURI uri = endpoint.getEndpointURI();
 59  0
             String encoding = endpoint.getEncoding();
 60  0
             String user = (uri.getUser() != null ? URLDecoder.decode(uri.getUser(), encoding) : null);
 61  0
             String pass = (uri.getPassword() != null ? URLDecoder.decode(uri.getPassword(), encoding) : null);
 62  0
             store.connect(uri.getHost(), uri.getPort(), user, pass);
 63  
 
 64  0
             folder = store.getFolder(castConnector().getMailboxFolder());
 65  0
             ensureFolderIsOpen(folder);
 66  
 
 67  0
             if (castConnector().getMoveToFolder() != null)
 68  
             {
 69  0
                 moveToFolder = store.getFolder(castConnector().getMoveToFolder());
 70  0
                 ensureFolderIsOpen(moveToFolder);
 71  
             }
 72  
         }
 73  0
     }
 74  
     
 75  
     protected void ensureFolderIsOpen(Folder fldr)
 76  
     {
 77  0
         if (!fldr.isOpen())
 78  
         {
 79  
             try
 80  
             {
 81  
                 // Depending on Server implementation it's not always
 82  
                 // necessary to open the folder to check it
 83  
                 // Opening folders can be exprensive!
 84  0
                 fldr.open(Folder.READ_WRITE);
 85  
             }
 86  0
             catch (MessagingException e)
 87  
             {
 88  0
                 logger.warn("Failed to open folder: " + fldr.getFullName() + " This is not an exception since some server implementations do not require the folder to be open", e);
 89  0
             }
 90  
         }
 91  0
     }
 92  
 
 93  
     @Override
 94  
     protected void doDisconnect() throws Exception
 95  
     {
 96  
         // close and expunge deleted messages
 97  
         try
 98  
         {
 99  0
             if (folder != null)
 100  
             {
 101  
                 try
 102  
                 {
 103  0
                     folder.expunge();
 104  
                 }
 105  0
                 catch (MessagingException e)
 106  
                 {
 107  0
                     if (logger.isDebugEnabled())
 108  
                     {
 109  0
                         logger.debug("ignoring exception on expunge: " + e.getMessage());
 110  
                     }
 111  0
                 }
 112  0
                 if (folder.isOpen())
 113  
                 {
 114  0
                     folder.close(true);
 115  
                 }
 116  
             }
 117  
         }
 118  0
         catch (Exception e)
 119  
         {
 120  0
             logger.error("Failed to close inbox: " + e.getMessage(), e);
 121  0
         }
 122  
 
 123  
         try
 124  
         {
 125  0
             if (moveToFolder != null)
 126  
             {
 127  0
                 if (moveToFolder.isOpen())
 128  
                 {
 129  0
                     moveToFolder.close(false);
 130  
                 }
 131  
             }
 132  
         }
 133  0
         catch (Exception e)
 134  
         {
 135  0
             logger.error("Failed to close moveToFolder: " + e.getMessage(), e);
 136  0
         }
 137  0
     }
 138  
 
 139  
     /**
 140  
      * @param event
 141  
      * @throws UnsupportedOperationException
 142  
      */
 143  
     protected void doDispatch(MuleEvent event) throws Exception
 144  
     {
 145  0
         throw new UnsupportedOperationException("Cannot dispatch from a POP3/IMAP connection");
 146  
     }
 147  
 
 148  
     /**
 149  
      * @param event
 150  
      * @throws UnsupportedOperationException
 151  
      */
 152  
     protected MuleMessage doSend(MuleEvent event) throws Exception
 153  
     {
 154  0
         throw new UnsupportedOperationException("Cannot send from a POP3/IMAP connection");
 155  
     }
 156  
 
 157  
     /**
 158  
      * Make a specific request to the underlying transport. Endpoint can be in the
 159  
      * form of pop3://username:password@pop3.lotsofmail.org
 160  
      *
 161  
      * @param timeout the maximum time the operation should block before returning.
 162  
      *                The call should return immediately if there is data available. If
 163  
      *                no data becomes available before the timeout elapses, null will be
 164  
      *                returned
 165  
      * @return the result of the request wrapped in a MuleMessage object. Null will be
 166  
      *         returned if no data was avaialable
 167  
      * @throws Exception if the call to the underlying protocal causes an exception
 168  
      */
 169  
     @Override
 170  
     protected MuleMessage doRequest(long timeout) throws Exception
 171  
     {
 172  0
         long t0 = System.currentTimeMillis();
 173  0
         if (timeout < 0)
 174  
         {
 175  0
             timeout = Long.MAX_VALUE;
 176  
         }
 177  
 
 178  
         do
 179  
         {
 180  0
             if (hasMessages())
 181  
             {
 182  0
                 int count = getMessageCount();
 183  0
                 if (count > 0)
 184  
                 {
 185  0
                     Message message = getNextMessage();
 186  0
                     if (message != null)
 187  
                     {
 188  
                         // so we don't get the same message again
 189  0
                         flagMessage(message);
 190  
 
 191  0
                         if (moveToFolder != null)
 192  
                         {
 193  0
                             Message newMessage = message;
 194  
                             //If we're using IMAP we need to cache the message contents so the message is accessible after the
 195  
                             //folder is closed
 196  0
                             if (message instanceof IMAPMessage)
 197  
                             {
 198  
                                 //We need to copy and cache so that the message cna be moved
 199  0
                                 newMessage = new MimeMessage((IMAPMessage) message);
 200  
                             }
 201  0
                             folder.copyMessages(new Message[]{message}, moveToFolder);
 202  0
                             message = newMessage;
 203  
                         }
 204  0
                         return createMuleMessage(message, endpoint.getEncoding());
 205  
                     }
 206  0
                 }
 207  0
                 else if (count == -1)
 208  
                 {
 209  0
                     throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
 210  
                             + " as folder is closed");
 211  
                 }
 212  
             }
 213  
 
 214  0
             long sleep =
 215  
                     Math.min(castConnector().getCheckFrequency(),
 216  
                             timeout - (System.currentTimeMillis() - t0));
 217  
 
 218  0
             if (sleep > 0)
 219  
             {
 220  0
                 if (logger.isDebugEnabled())
 221  
                 {
 222  0
                     logger.debug("No results, sleeping for " + sleep);
 223  
                 }
 224  
                 try
 225  
                 {
 226  0
                     Thread.sleep(sleep);
 227  
                 }
 228  0
                 catch (InterruptedException e)
 229  
                 {
 230  0
                     logger.warn("Thread interrupted while requesting email on: " + endpoint.getEndpointURI().toString());
 231  0
                     return null;
 232  0
                 }
 233  
             }
 234  
             else
 235  
             {
 236  
 
 237  0
                 logger.debug("Timeout");
 238  0
                 return null;
 239  
             }
 240  
 
 241  
         }
 242  0
         while (true);
 243  
     }
 244  
 
 245  
     /**
 246  
      * There seems to be some variation on pop3 implementation so it may be
 247  
      * preferrable to mark messages as seen here and also overload the getMessages
 248  
      * method to grab only new messages
 249  
      */
 250  
     protected void flagMessage(Message message) throws MessagingException
 251  
     {
 252  0
         if (castConnector().isDeleteReadMessages())
 253  
         {
 254  0
             message.setFlag(Flags.Flag.DELETED, true);
 255  
         }
 256  
         else
 257  
         {
 258  0
             message.setFlag(Flags.Flag.SEEN, true);
 259  
         }
 260  0
     }
 261  
 
 262  
     protected Message getNextMessage() throws MessagingException
 263  
     {
 264  0
         if (getMessageCount() > 0)
 265  
         {
 266  0
             Message message = folder.getMessage(1);
 267  0
             if (!message.isExpunged())
 268  
             {
 269  0
                 return message;
 270  
             }
 271  
         }
 272  0
         return null;
 273  
     }
 274  
 
 275  
     protected int getMessageCount() throws MessagingException
 276  
     {
 277  0
         return folder.getMessageCount();
 278  
     }
 279  
 
 280  
     /**
 281  
      * Optimised check to se whether to return the message count and retrieve the
 282  
      * messages. Some pop3 implementations differ so an optimised check such as
 283  
      * folder.hasNewMessages() cannot be used
 284  
      */
 285  
     protected boolean hasMessages() throws MessagingException
 286  
     {
 287  0
         return getMessageCount() > 0;
 288  
     }
 289  
 
 290  
     @Override
 291  
     protected void doDispose()
 292  
     {
 293  0
         if (null != folder && folder.isOpen())
 294  
         {
 295  
             try
 296  
             {
 297  
 
 298  0
                 folder.close(true);
 299  
             }
 300  0
             catch (Exception e)
 301  
             {
 302  0
                 logger.debug("ignoring exception: " + e.getMessage(), e);
 303  0
             }
 304  
         }
 305  0
     }
 306  
 }