org.eurekastreams.server.service.email.ImapEmailIngester.java Source code

Java tutorial

Introduction

Here is the source code for org.eurekastreams.server.service.email.ImapEmailIngester.java

Source

/*
 * Copyright (c) 2011 Lockheed Martin Corporation
 *
 * Licensed 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.eurekastreams.server.service.email;

import java.util.ArrayList;
import java.util.List;

import javax.mail.FetchProfile;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Store;

import org.apache.commons.lang.StringUtils;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.server.service.actions.strategies.EmailerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Ingests email from a mailbox and processes it.
 */
public class ImapEmailIngester {
    /** Log. */
    private final Logger log = LoggerFactory.getLogger(LogFactory.getClassName());

    /** For getting a connection to the mail server. */
    private final ImapStoreFactory storeFactory;

    /** Does the actual work on each message. */
    private final MessageProcessor messageProcessor;

    /** Name of folder containing messages to process. */
    private final String inputFolderName;

    /** Name of folder to receive messages that failed processing. */
    private final String errorFolderName;

    /** Name of folder to receive messages that were successfully processed. */
    private final String successFolderName;

    /** Name of folder to receive messages that are discarded (no-reply). */
    private final String discardFolderName;

    /** For sending response emails. */
    private final EmailerFactory emailerFactory;

    /**
     * Constructor.
     *
     * @param inStoreFactory
     *            For getting a connection to the mail server.
     * @param inMessageProcessor
     *            Does the actual work on each message.
     * @param inEmailerFactory
     *            For sending response emails.
     * @param inInputFolderName
     *            Name of folder containing messages to process.
     * @param inErrorFolderName
     *            Name of folder to receive messages that failed processing.
     * @param inSuccessFolderName
     *            Name of folder to receive messages that were successfully processed.
     * @param inDiscardFolderName
     *            Name of folder to receive messages that are discarded (no-reply).
     */
    public ImapEmailIngester(final ImapStoreFactory inStoreFactory, final MessageProcessor inMessageProcessor,
            final EmailerFactory inEmailerFactory, final String inInputFolderName, final String inErrorFolderName,
            final String inSuccessFolderName, final String inDiscardFolderName) {
        storeFactory = inStoreFactory;
        messageProcessor = inMessageProcessor;
        emailerFactory = inEmailerFactory;
        inputFolderName = inInputFolderName;
        errorFolderName = inErrorFolderName;
        successFolderName = inSuccessFolderName;
        discardFolderName = inDiscardFolderName;
    }

    /**
     * Ingests email from a mailbox.
     */
    public void execute() {
        // get message store
        Store store;
        try {
            long startTime = System.nanoTime();
            store = storeFactory.getStore();
            log.debug("Connected to mail store in {}ns", System.nanoTime() - startTime);
        } catch (MessagingException ex) {
            log.error("Error getting message store.", ex);
            return;
        }
        try {
            // get folders
            Folder inputFolder = store.getFolder(inputFolderName);
            if (!inputFolder.exists()) {
                log.error("Input folder {} does not exist.", inputFolderName);
                return;
            }
            Folder successFolder = null;
            if (StringUtils.isNotBlank(successFolderName)) {
                successFolder = store.getFolder(successFolderName);
                if (!successFolder.exists()) {
                    log.error("Success folder {} does not exist.", successFolderName);
                    return;
                }
            }
            Folder discardFolder = null;
            if (StringUtils.isNotBlank(discardFolderName)) {
                discardFolder = store.getFolder(discardFolderName);
                if (!discardFolder.exists()) {
                    log.error("Discard folder {} does not exist.", discardFolderName);
                    return;
                }
            }
            Folder errorFolder = null;
            if (StringUtils.isNotBlank(errorFolderName)) {
                errorFolder = store.getFolder(errorFolderName);
                if (!errorFolder.exists()) {
                    log.error("Error folder {} does not exist.", errorFolderName);
                    return;
                }
            }

            inputFolder.open(Folder.READ_WRITE);

            // fetch messages
            // Note: Not preloading CONTENT_INFO. For some reason, preloading the content info (IMAP BODYSTRUCTURE)
            // causes the call to getContent to return empty. (As if there was a bug where getContent saw the cached
            // body structure and thought that the content itself was cached, but I'd think a bug like that would have
            // been found by many people and fixed long ago, so I'm assuming it's something else.)
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.ENVELOPE);
            Message[] msgs = inputFolder.getMessages();
            inputFolder.fetch(msgs, fp);

            log.debug("About to process {} messages", msgs.length);

            // process each message
            if (msgs.length > 0) {
                List<Message> successMessages = new ArrayList<Message>();
                List<Message> errorMessages = new ArrayList<Message>();
                List<Message> discardMessages = new ArrayList<Message>();
                List<Message> responseMessages = new ArrayList<Message>();
                for (int i = 0; i < msgs.length; i++) {
                    Message message = msgs[i];
                    try {
                        boolean processed = messageProcessor.execute(message, responseMessages);
                        (processed ? successMessages : discardMessages).add(message);
                    } catch (Exception ex) {
                        log.error("Failed to process email message.", ex);
                        errorMessages.add(message);
                    }
                }

                // send response messages
                for (Message responseMessage : responseMessages) {
                    emailerFactory.sendMail(responseMessage);
                }

                // move and purge messages
                if (successFolder != null && !successMessages.isEmpty()) {
                    inputFolder.copyMessages(successMessages.toArray(new Message[successMessages.size()]),
                            successFolder);
                }
                if (discardFolder != null && !discardMessages.isEmpty()) {
                    inputFolder.copyMessages(discardMessages.toArray(new Message[discardMessages.size()]),
                            discardFolder);
                }
                if (errorFolder != null && !errorMessages.isEmpty()) {
                    inputFolder.copyMessages(errorMessages.toArray(new Message[errorMessages.size()]), errorFolder);
                }
                for (int i = 0; i < msgs.length; i++) {
                    msgs[i].setFlag(Flag.DELETED, true);
                }

                log.info("{} messages processed:  {} successful, {} discarded, {} failed.", new Object[] {
                        msgs.length, successMessages.size(), discardMessages.size(), errorMessages.size() });
            }

            // close folder
            inputFolder.close(true);
        } catch (MessagingException ex) {
            log.error("Error ingesting email.", ex);
        } catch (Exception ex) {
            log.error("Error ingesting email.", ex);
        } finally {
            // close store
            try {
                store.close();
            } catch (MessagingException ex) {
                log.error("Error closing message store.", ex);
            }
        }
    }
}