View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19   
20  package org.apache.james.fetchmail;
21  
22  import javax.mail.FetchProfile;
23  import javax.mail.Flags;
24  import javax.mail.Folder;
25  import javax.mail.Message;
26  import javax.mail.MessagingException;
27  import javax.mail.internet.MimeMessage;
28  
29  /***
30   * <p>Class <code>FolderProcessor</code> opens a Folder and iterates over all
31   * of the Messages, delegating their processing to 
32   * <code>MessageProcessor</code>.</p>
33   * 
34   * <p>If isRecurse(), all subfolders are fetched recursively.</p>
35   * 
36   * <p>Creation Date: 25-May-03</p>
37   *
38   */
39  public class FolderProcessor extends ProcessorAbstract
40  {
41      /***
42       * The fetched folder
43       */ 
44      private Folder fieldFolder;
45      
46      private Boolean fieldMarkSeenPermanent;
47  
48      /***
49       * Constructor for FolderProcessor.
50       * @param folder The folder to be fetched
51       * @param account The account being processed
52       */
53      protected FolderProcessor(Folder folder, Account account)
54      {
55          super(account);
56          setFolder(folder);
57      }
58      
59      /***
60       * Method process opens a Folder, fetches the Envelopes for all of its 
61       * Messages, creates a <code>MessageProcessor</code> and runs it to process
62       * each message.
63       * 
64       * @see org.apache.james.fetchmail.ProcessorAbstract#process()
65       */
66      public void process() throws MessagingException
67      {
68          int messagesProcessed = 0;
69          int messageCount = 0;
70          try
71          {
72              // open the folder            
73              try
74              {
75                  open();
76              }
77              catch (MessagingException ex)
78              {
79                  getLogger().error(
80                      getFetchTaskName() + " Failed to open folder!");
81                  throw ex;
82              }
83  
84              // Lock the folder while processing each message
85              synchronized (getFolder())
86              {
87                  messageCount = getFolder().getMessageCount();
88                  for (int i = 1; i <= messageCount; i++)
89                  {
90                      MimeMessage message =
91                          (MimeMessage) getFolder().getMessage(i);
92                      if (isFetchAll() || !isSeen(message))
93                      {
94                          try
95                          {
96                              new MessageProcessor(message, getAccount())
97                                  .process();
98                              messagesProcessed++;
99                          }
100                         // Catch and report an exception but don't rethrow it, 
101                         // allowing subsequent messages to be processed.                    
102                         catch (Exception ex)
103                         {
104                             StringBuffer logMessageBuffer =
105                                 new StringBuffer("Exception processing message ID: ");
106                             logMessageBuffer.append(message.getMessageID());
107                             getLogger().error(logMessageBuffer.toString(), ex);
108                         }
109                     }
110                 }
111             }
112         }
113         catch (MessagingException mex)
114         {
115             getLogger().error(
116                 "A MessagingException has terminated fetching messages for this folder",
117                 mex);
118         }
119         finally
120         {
121             // Close the folder
122             try
123             {
124                 close();
125             }
126             catch (MessagingException ex)
127             {
128                 // No-op
129             }
130             StringBuffer logMessageBuffer = new StringBuffer("Processed ");
131             logMessageBuffer.append(messagesProcessed);
132             logMessageBuffer.append(" messages of ");
133             logMessageBuffer.append(messageCount);
134             logMessageBuffer.append(" in folder '");
135             logMessageBuffer.append(getFolder().getName());
136             logMessageBuffer.append("'");
137             getLogger().info(logMessageBuffer.toString());
138         }
139 
140         // Recurse through sub-folders if required
141         try
142         {
143             if (isRecurse())
144                 recurse();
145         }
146         catch (MessagingException mex)
147         {
148             getLogger().error(
149                 "A MessagingException has terminated recursing through sub-folders",
150                 mex);
151         }
152 
153         return;
154     }
155     
156     /***
157      * Method close.
158      * @throws MessagingException
159      */
160     protected void close() throws MessagingException
161     {
162         if (null != getFolder() && getFolder().isOpen())
163             getFolder().close(true);
164     }   
165     
166     /***
167      * Method recurse.
168      * @throws MessagingException
169      */
170     protected void recurse() throws MessagingException
171     {
172         if ((getFolder().getType() & Folder.HOLDS_FOLDERS)
173             == Folder.HOLDS_FOLDERS)
174         {
175             // folder contains subfolders...
176             Folder folders[] = getFolder().list();
177 
178             for (int i = 0; i < folders.length; i++)
179             {
180                 new FolderProcessor(folders[i], getAccount()).process();
181             }
182 
183         }
184     }   
185     
186     /***
187      * Method open.
188      * @throws MessagingException
189      */
190     protected void open() throws MessagingException
191     {
192         int openFlag = Folder.READ_WRITE;
193         
194         if (isOpenReadOnly())
195             openFlag = Folder.READ_ONLY;
196 
197         getFolder().open(openFlag);                 
198     }           
199 
200     /***
201      * Returns the folder.
202      * @return Folder
203      */
204     protected Folder getFolder()
205     {
206         return fieldFolder;
207     }
208     
209     /***
210      * Answer if <code>aMessage</code> has been SEEN.
211      * @param aMessage
212      * @return boolean
213      * @throws MessagingException
214      */
215     protected boolean isSeen(MimeMessage aMessage) throws MessagingException
216     {
217         boolean isSeen = false;
218         if (isMarkSeenPermanent().booleanValue())
219             isSeen = aMessage.isSet(Flags.Flag.SEEN);
220         else
221             isSeen = handleMarkSeenNotPermanent(aMessage);
222         return isSeen;
223     }
224 
225     /***
226      * Answer the result of computing markSeenPermanent.
227      * @return Boolean
228      */
229     protected Boolean computeMarkSeenPermanent()
230     {
231         return new Boolean(
232             getFolder().getPermanentFlags().contains(Flags.Flag.SEEN));
233     }
234 
235     /***
236      * <p>Handler for when the folder does not support the SEEN flag.
237      * The default behaviour implemented here is to answer the value of the
238      * SEEN flag anyway.</p>
239      * 
240      * <p>Subclasses may choose to override this method and implement their own
241      *  solutions.</p>
242      *
243      * @param aMessage
244      * @return boolean 
245      * @throws MessagingException
246      */
247     protected boolean handleMarkSeenNotPermanent(MimeMessage aMessage)
248         throws MessagingException
249     {
250         return aMessage.isSet(Flags.Flag.SEEN);
251     }    
252 
253     /***
254      * Sets the folder.
255      * @param folder The folder to set
256      */
257     protected void setFolder(Folder folder)
258     {
259         fieldFolder = folder;
260     }
261     
262     /***
263      * Returns the isMarkSeenPermanent.
264      * @return Boolean
265      */
266     protected Boolean isMarkSeenPermanent()
267     {
268         Boolean markSeenPermanent = null;
269         if (null == (markSeenPermanent = isMarkSeenPermanentBasic()))
270         {
271             updateMarkSeenPermanent();
272             return isMarkSeenPermanent();
273         }    
274         return markSeenPermanent;
275     }
276     
277     /***
278      * Returns the markSeenPermanent.
279      * @return Boolean
280      */
281     private Boolean isMarkSeenPermanentBasic()
282     {
283         return fieldMarkSeenPermanent;
284     }    
285 
286     /***
287      * Sets the markSeenPermanent.
288      * @param markSeenPermanent The isMarkSeenPermanent to set
289      */
290     protected void setMarkSeenPermanent(Boolean markSeenPermanent)
291     {
292         fieldMarkSeenPermanent = markSeenPermanent;
293     }
294     
295     /***
296      * Updates the markSeenPermanent.
297      */
298     protected void updateMarkSeenPermanent()
299     {
300         setMarkSeenPermanent(computeMarkSeenPermanent());
301     }    
302 
303 }