org.apache.james.fetchmail.FolderProcessor Maven / Gradle / Ivy
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.fetchmail;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* Class FolderProcessor
opens a Folder and iterates over all of
* the Messages, delegating their processing to MessageProcessor
.
*
*
*
* If isRecurse(), all subfolders are fetched recursively.
*
*/
public class FolderProcessor extends ProcessorAbstract {
private static final Logger LOGGER = LoggerFactory.getLogger(FolderProcessor.class);
/**
* The fetched folder
*/
private Folder fieldFolder;
private Boolean fieldMarkSeenPermanent;
/**
* Constructor for FolderProcessor.
*
* @param folder
* The folder to be fetched
* @param account
* The account being processed
*/
protected FolderProcessor(Folder folder, Account account) {
super(account);
setFolder(folder);
}
/**
* Method process opens a Folder, fetches the Envelopes for all of its
* Messages, creates a MessageProcessor
and runs it to process
* each message.
*/
@Override
public void process() throws MessagingException {
int messagesProcessed = 0;
int messageCount = 0;
try {
// open the folder
try {
open();
} catch (MessagingException ex) {
LOGGER.error("{} Failed to open folder!", getFetchTaskName());
throw ex;
}
// Lock the folder while processing each message
synchronized (getFolder()) {
messageCount = getFolder().getMessageCount();
for (int i = 1; i <= messageCount; i++) {
MimeMessage message = (MimeMessage) getFolder().getMessage(i);
if (isFetchAll() || !isSeen(message)) {
try {
new MessageProcessor(message, getAccount()).process();
messagesProcessed++;
} catch (Exception ex) {
// Catch and report an exception but don't rethrow it,
// allowing subsequent messages to be processed.
LOGGER.error("Exception processing message ID: {}", message.getMessageID(), ex);
}
}
}
}
} catch (MessagingException mex) {
LOGGER.error("A MessagingException has terminated fetching messages for this folder", mex);
} finally {
// Close the folder
try {
close();
} catch (MessagingException ex) {
// No-op
}
LOGGER.info("Processed {} messages of {} in folder '{}'", messagesProcessed, messageCount, getFolder().getName());
}
// Recurse through sub-folders if required
try {
if (isRecurse()) {
recurse();
}
} catch (MessagingException mex) {
LOGGER.error("A MessagingException has terminated recursing through sub-folders", mex);
}
}
/**
* Method close.
*
* @throws MessagingException
*/
protected void close() throws MessagingException {
if (null != getFolder() && getFolder().isOpen()) {
getFolder().close(true);
}
}
/**
* Method recurse.
*
* @throws MessagingException
*/
protected void recurse() throws MessagingException {
if ((getFolder().getType() & Folder.HOLDS_FOLDERS) == Folder.HOLDS_FOLDERS) {
// folder contains subfolders...
Folder[] folders = getFolder().list();
for (Folder folder : folders) {
new FolderProcessor(folder, getAccount()).process();
}
}
}
/**
* Method open.
*
* @throws MessagingException
*/
protected void open() throws MessagingException {
int openFlag = Folder.READ_WRITE;
if (isOpenReadOnly()) {
openFlag = Folder.READ_ONLY;
}
getFolder().open(openFlag);
}
/**
* Returns the folder.
*
* @return Folder
*/
protected Folder getFolder() {
return fieldFolder;
}
/**
* Answer if aMessage
has been SEEN.
*
* @param aMessage
* @return boolean
* @throws MessagingException
*/
protected boolean isSeen(MimeMessage aMessage) throws MessagingException {
boolean isSeen;
if (isMarkSeenPermanent()) {
isSeen = aMessage.isSet(Flags.Flag.SEEN);
} else {
isSeen = handleMarkSeenNotPermanent(aMessage);
}
return isSeen;
}
/**
* Answer the result of computing markSeenPermanent.
*
* @return Boolean
*/
protected Boolean computeMarkSeenPermanent() {
return getFolder().getPermanentFlags().contains(Flags.Flag.SEEN);
}
/**
*
* Handler for when the folder does not support the SEEN flag. The default
* behaviour implemented here is to answer the value of the SEEN flag
* anyway.
*
*
*
* Subclasses may choose to override this method and implement their own
* solutions.
*
*
* @param aMessage
* @return boolean
* @throws MessagingException
*/
protected boolean handleMarkSeenNotPermanent(MimeMessage aMessage) throws MessagingException {
return aMessage.isSet(Flags.Flag.SEEN);
}
/**
* Sets the folder.
*
* @param folder
* The folder to set
*/
protected void setFolder(Folder folder) {
fieldFolder = folder;
}
/**
* Returns the isMarkSeenPermanent.
*
* @return Boolean
*/
protected Boolean isMarkSeenPermanent() {
Boolean markSeenPermanent;
if (null == (markSeenPermanent = isMarkSeenPermanentBasic())) {
updateMarkSeenPermanent();
return isMarkSeenPermanent();
}
return markSeenPermanent;
}
/**
* Returns the markSeenPermanent.
*
* @return Boolean
*/
private Boolean isMarkSeenPermanentBasic() {
return fieldMarkSeenPermanent;
}
/**
* Sets the markSeenPermanent.
*
* @param markSeenPermanent
* The isMarkSeenPermanent to set
*/
protected void setMarkSeenPermanent(Boolean markSeenPermanent) {
fieldMarkSeenPermanent = markSeenPermanent;
}
/**
* Updates the markSeenPermanent.
*/
protected void updateMarkSeenPermanent() {
setMarkSeenPermanent(computeMarkSeenPermanent());
}
}