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