FileDocCategorySizeDatePackage
FetchMail.javaAPI DocApache James 2.3.129616Fri Jan 12 12:56:24 GMT 2007org.apache.james.fetchmail

FetchMail

public class FetchMail extends org.apache.avalon.framework.logger.AbstractLogEnabled implements org.apache.avalon.framework.service.Serviceable, org.apache.avalon.cornerstone.services.scheduler.Target, org.apache.avalon.framework.configuration.Configurable

Class FetchMail is an Avalon task that is periodically triggered to fetch mail from a JavaMail Message Store.

The lifecycle of an instance of FetchMail is managed by Avalon. The configure(Configuration) method is invoked to parse and validate Configuration properties. The targetTriggered(String) method is invoked to execute the task.

When triggered, a sorted list of Message Store Accounts to be processed is built. Each Message Store Account is processed by delegating to StoreProcessor.

There are two kinds of Message Store Accounts, static and dynamic. Static accounts are expliciltly declared in the Configuration. Dynamic accounts are built each time the task is executed, one per each user defined to James, using the James user name with a configurable prefix and suffix to define the host user identity and recipient identity for each Account. Dynamic accounts allow FetchMail to fetch mail for all James users without modifying the Configuration parameters or restarting the Avalon server.

To fully understand the operations supported by this task, read the Class documention for each Class in the delegation chain starting with this class' delegate, StoreProcessor.

Creation Date: 24-May-03

Fields Summary
private boolean
fieldFetching
private ParsedConfiguration
fieldConfiguration
The Configuration for this task
private List
fieldParsedDynamicAccountParameters
A List of ParsedDynamicAccountParameters, one for every entry in the configuration.
private List
fieldStaticAccounts
The Static Accounts for this task. These are setup when the task is configured.
private Session
fieldSession
The JavaMail Session for this fetch task.
private Map
fieldDynamicAccounts
The Dynamic Accounts for this task. These are setup each time the fetchtask is run.
private org.apache.james.services.MailServer
fieldServer
The MailServer service
private org.apache.james.services.UsersRepository
fieldLocalUsers
The Local Users repository
Constructors Summary
public FetchMail()
Constructor for POP3mail.

        

            
     
    
        super();
    
Methods Summary
protected java.util.MapcomputeDynamicAccounts()
Computes the dynamicAccounts.

        Map newAccounts =
            new HashMap(
                getLocalUsers().countUsers()
                    * getParsedDynamicAccountParameters().size());
        Map oldAccounts = getDynamicAccountsBasic();
        if (null == oldAccounts)
            oldAccounts = new HashMap(0);

        Iterator parameterIterator =
            getParsedDynamicAccountParameters().iterator();

        // Process each ParsedDynamicParameters
        while (parameterIterator.hasNext())
        {
            Map accounts =
                computeDynamicAccounts(
                    oldAccounts,
                    (ParsedDynamicAccountParameters) parameterIterator.next());
            // Remove accounts from oldAccounts.
            // This avoids an average 2*N increase in heapspace used as the 
            // newAccounts are created. 
            Iterator oldAccountsIterator = oldAccounts.keySet().iterator();
            while (oldAccountsIterator.hasNext())
            {
                if (accounts.containsKey(oldAccountsIterator.next()))
                    oldAccountsIterator.remove();
            }
            // Add this parameter's accounts to newAccounts
            newAccounts.putAll(accounts);
        }
        return newAccounts;
    
protected java.util.MapcomputeDynamicAccounts(java.util.Map oldAccounts, org.apache.james.fetchmail.FetchMail$ParsedDynamicAccountParameters parameters)
Compute the dynamicAccounts for the passed parameters. Accounts for existing users are copied and accounts for new users are created.

param
oldAccounts
param
parameters
return
Map - The current Accounts
throws
ConfigurationException

        Map accounts = new HashMap(getLocalUsers().countUsers());
        Iterator usersIterator = getLocalUsers().list();
        while (usersIterator.hasNext())
        {
            String userName = (String) usersIterator.next();
            DynamicAccountKey key =
                new DynamicAccountKey(userName, parameters.getSequenceNumber());
            Account account = (Account) oldAccounts.get(key);
            if (null == account)
            {
                // Create a new DynamicAccount
                account =
                    new DynamicAccount(
                        parameters.getSequenceNumber(),
                        getConfiguration(),
                        userName,
                        parameters.getUserPrefix(),
                        parameters.getUserSuffix(),
                        parameters.getPassword(),
                        parameters.getRecipientPrefix(),
                        parameters.getRecipientSuffix(),
                        parameters.isIgnoreRecipientHeader(),
                        parameters.getCustomRecipientHeader(),
                        getSession());
            }
            accounts.put(key, account);
        }
        return accounts;
    
protected java.util.ListcomputeParsedDynamicAccountParameters()
Computes the ParsedDynamicAccountParameters.

        return new ArrayList();
    
protected javax.mail.SessioncomputeSession()
Answers a new Session.

return
Session

        return Session.getInstance(System.getProperties());
    
protected java.util.ListcomputeStaticAccounts()
Computes the staticAccounts.

        return new ArrayList();
    
public voidconfigure(org.apache.avalon.framework.configuration.Configuration configuration)
Method configure parses and validates the Configuration data and creates a new ParsedConfiguration, an Account for each configured static account and a ParsedDynamicAccountParameters for each dynamic account.

see
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)

        // Set any Session parameters passed in the Configuration
        setSessionParameters(configuration);

        // Create the ParsedConfiguration used in the delegation chain
        ParsedConfiguration parsedConfiguration =
            new ParsedConfiguration(
                configuration,
                getLogger(),
                getServer(),
                getLocalUsers());
        setConfiguration(parsedConfiguration);

        // Setup the Accounts
        Configuration[] allAccounts = configuration.getChildren("accounts");
        if (allAccounts.length < 1)
            throw new ConfigurationException("Missing <accounts> section.");
        if (allAccounts.length > 1)
            throw new ConfigurationException("Too many <accounts> sections, there must be exactly one");
        Configuration accounts = allAccounts[0];

        // Create an Account for every configured account
        Configuration[] accountsChildren = accounts.getChildren();
        if (accountsChildren.length < 1)
            throw new ConfigurationException("Missing <account> section.");

        for (int i = 0; i < accountsChildren.length; i++)
        {
            Configuration accountsChild = accountsChildren[i];

            if ("alllocal".equals(accountsChild.getName()))
            {
                // <allLocal> is dynamic, save the parameters for accounts to
                // be created when the task is triggered
                getParsedDynamicAccountParameters().add(
                    new ParsedDynamicAccountParameters(i, accountsChild));
                continue;
            }

            if ("account".equals(accountsChild.getName()))
            {
                // Create an Account for the named user and
                // add it to the list of static accounts
                getStaticAccounts().add(
                    new Account(
                        i,
                        parsedConfiguration,
                        accountsChild.getAttribute("user"),
                        accountsChild.getAttribute("password"),
                        accountsChild.getAttribute("recipient"),
                        accountsChild.getAttributeAsBoolean(
                            "ignorercpt-header"),
                        accountsChild.getAttribute("customrcpt-header",""),
                        getSession()));
                continue;
            }

            throw new ConfigurationException(
                "Illegal token: <"
                    + accountsChild.getName()
                    + "> in <accounts>");
        }
    
protected ParsedConfigurationgetConfiguration()
Returns the configuration.

return
ParsedConfiguration

        return fieldConfiguration;
    
protected java.util.MapgetDynamicAccounts()
Returns the dynamicAccounts. Initializes if required.

return
Map

        if (null == getDynamicAccountsBasic())
        {
            updateDynamicAccounts();
            return getDynamicAccounts();
        }   
        return fieldDynamicAccounts;
    
private java.util.MapgetDynamicAccountsBasic()
Returns the dynamicAccounts.

return
Map

        return fieldDynamicAccounts;
    
protected org.apache.james.services.UsersRepositorygetLocalUsers()
Returns the localUsers.

return
UsersRepository

    return fieldLocalUsers;
protected java.util.ListgetParsedDynamicAccountParameters()
Returns the ParsedDynamicAccountParameters.

return
List

        if (null == getParsedDynamicAccountParametersBasic())
        {
            updateParsedDynamicAccountParameters();
            return getParsedDynamicAccountParameters();
        }   
        return fieldParsedDynamicAccountParameters;
    
private java.util.ListgetParsedDynamicAccountParametersBasic()
Returns the ParsedDynamicAccountParameters.

return
List

        return fieldParsedDynamicAccountParameters;
    
protected org.apache.james.services.MailServergetServer()
Returns the server.

return
MailServer

        return fieldServer;
    
protected javax.mail.SessiongetSession()
Returns the session, lazily initialized if required.

return
Session

        Session session = null;
        if (null == (session = getSessionBasic()))
        {
            updateSession();
            return getSession();
        }    
        return session;
    
private javax.mail.SessiongetSessionBasic()
Returns the session.

return
Session

        return fieldSession;
    
protected java.util.ListgetStaticAccounts()
Returns the accounts. Initializes if required.

return
List

        if (null == getStaticAccountsBasic())
        {
            updateStaticAccounts();
            return getStaticAccounts();
        }   
        return fieldStaticAccounts;
    
private java.util.ListgetStaticAccountsBasic()
Returns the staticAccounts.

return
List

        return fieldStaticAccounts;
    
protected booleanisFetching()
Returns the fetching.

return
boolean

        return fieldFetching;
    
protected voidresetDynamicAccounts()
Resets the dynamicAccounts.

        setDynamicAccounts(null);
    
public voidservice(org.apache.avalon.framework.service.ServiceManager manager)

see
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)

        try
        {
            setServer((MailServer) manager.lookup(MailServer.ROLE));
        }
        catch (ClassCastException cce)
        {
            StringBuffer errorBuffer =
                new StringBuffer(128).append("Component ").append(
                    MailServer.ROLE).append(
                    "does not implement the required interface.");
            throw new ServiceException("", errorBuffer.toString());
        }

        UsersRepository usersRepository =
            (UsersRepository) manager.lookup(UsersRepository.ROLE);
        setLocalUsers(usersRepository);
    
protected voidsetConfiguration(ParsedConfiguration configuration)
Sets the configuration.

param
configuration The configuration to set

        fieldConfiguration = configuration;
    
protected voidsetDynamicAccounts(java.util.Map dynamicAccounts)
Sets the dynamicAccounts.

param
dynamicAccounts The dynamicAccounts to set

        fieldDynamicAccounts = dynamicAccounts;
    
protected voidsetFetching(boolean fetching)
Sets the fetching.

param
fetching The fetching to set

        fieldFetching = fetching;
    
protected voidsetLocalUsers(org.apache.james.services.UsersRepository localUsers)
Sets the localUsers.

param
localUsers The localUsers to set

    fieldLocalUsers = localUsers;
protected voidsetParsedDynamicAccountParameters(java.util.List parsedDynamicAccountParameters)
Sets the ParsedDynamicAccountParameters.

param
ParsedDynamicAccountParameters The ParsedDynamicAccountParametersto set

        fieldParsedDynamicAccountParameters = parsedDynamicAccountParameters;
    
protected voidsetServer(org.apache.james.services.MailServer server)
Sets the server.

param
server The server to set

    fieldServer = server;
protected voidsetSession(javax.mail.Session session)
Sets the session.

param
session The session to set

        fieldSession = session;
    
protected voidsetSessionParameters(org.apache.avalon.framework.configuration.Configuration configuration)
Propogate any Session parameters in the configuration to the Session.

param
configuration The configuration containing the parameters
throws
ConfigurationException

        Configuration javaMailProperties =
            configuration.getChild("javaMailProperties", false);
        if (null != javaMailProperties)
        {
            Properties properties = getSession().getProperties();
            Configuration[] allProperties =
                javaMailProperties.getChildren("property");
            for (int i = 0; i < allProperties.length; i++)
            {
                properties.setProperty(
                    allProperties[i].getAttribute("name"),
                    allProperties[i].getAttribute("value"));
                if (getLogger().isDebugEnabled())
                {
                    StringBuffer messageBuffer =
                        new StringBuffer("Set property name: ");
                    messageBuffer.append(allProperties[i].getAttribute("name"));
                    messageBuffer.append(" to: ");
                    messageBuffer.append(
                        allProperties[i].getAttribute("value"));
                    getLogger().debug(messageBuffer.toString());
                }
            }
        }
    
protected voidsetStaticAccounts(java.util.List accounts)
Sets the accounts.

param
accounts The accounts to set

        fieldStaticAccounts = accounts;
    
public voidtargetTriggered(java.lang.String arg0)
Method target triggered fetches mail for each configured account.

see
org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)

        // if we are already fetching then just return
        if (isFetching())
        {
            getLogger().info(
                "Triggered fetch cancelled. A fetch is already in progress.");
            return;
        }

        // Enter Fetching State
        try
        {
            setFetching(true);
            getLogger().info("Fetcher starting fetches");

            // if debugging, list the JavaMail property key/value pairs
            // for this Session
            if (getLogger().isDebugEnabled())
            {
                getLogger().debug("Session properties:");
                Properties properties = getSession().getProperties();
                Enumeration e = properties.keys();
                while (e.hasMoreElements())
                {
                    String key = (String) e.nextElement();
                    String val = (String) properties.get(key);
                    if (val.length() > 40)
                    {
                        val = val.substring(0, 37) + "...";
                    }
                    getLogger().debug(key + "=" + val);

                }
            }

            // Update the dynamic accounts,
            // merge with the static accounts and
            // sort the accounts so they are in the order
            // they were entered in config.xml
            updateDynamicAccounts();
            ArrayList mergedAccounts =
                new ArrayList(
                    getDynamicAccounts().size() + getStaticAccounts().size());
            mergedAccounts.addAll(getDynamicAccounts().values());
            mergedAccounts.addAll(getStaticAccounts());
            Collections.sort(mergedAccounts);

            StringBuffer logMessage = new StringBuffer(64);
            logMessage.append("Processing ");
            logMessage.append(getStaticAccounts().size());
            logMessage.append(" static accounts and ");
            logMessage.append(getDynamicAccounts().size());
            logMessage.append(" dynamic accounts.");
            getLogger().info(logMessage.toString());

            // Fetch each account
            Iterator accounts = mergedAccounts.iterator();
            while (accounts.hasNext())
            {
                try
                {
                    new StoreProcessor((Account) accounts.next()).process();
                }
                catch (MessagingException ex)
                {
                    getLogger().error(
                        "A MessagingException has terminated processing of this Account",
                        ex);
                }
            }
        }
        catch (Exception ex)
        {
            getLogger().error("An Exception has terminated this fetch.", ex);
        }
        finally
        {
            getLogger().info("Fetcher completed fetches");

            // Exit Fetching State
            setFetching(false);
        }
    
protected voidupdateDynamicAccounts()
Updates the dynamicAccounts.

        setDynamicAccounts(computeDynamicAccounts());
    
protected voidupdateParsedDynamicAccountParameters()
Updates the ParsedDynamicAccountParameters.

        setParsedDynamicAccountParameters(computeParsedDynamicAccountParameters());
    
protected voidupdateSession()
Updates the current Session.

        setSession(computeSession());
    
protected voidupdateStaticAccounts()
Updates the staticAccounts.

        setStaticAccounts(computeStaticAccounts());