FileDocCategorySizeDatePackage
SMTPHandlerChain.javaAPI DocApache James 2.3.111792Fri Jan 12 12:56:26 GMT 2007org.apache.james.smtpserver

SMTPHandlerChain.java

/****************************************************************
 * 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.smtpserver;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;

import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfiguration;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;

/**
  * The SMTPHandlerChain is per service object providing access
  * ConnectHandlers, Commandhandlers and message handlers
  */
public class SMTPHandlerChain extends AbstractLogEnabled implements Configurable, Serviceable {

    private HashMap commandHandlerMap = new HashMap();
    private ArrayList messageHandlers = new ArrayList();
    private ArrayList connectHandlers = new ArrayList();

    private final CommandHandler unknownHandler = new UnknownCmdHandler();
    private ServiceManager serviceManager;

    private final static String[] mandatoryCommands = { "MAIL" , "RCPT", "DATA"};

    public void service(ServiceManager arg0) throws ServiceException {
        serviceManager = arg0;
    }


    /**
     * loads the various handlers from the configuration
     * @param configuration configuration under handlerchain node
     */
    public void configure(Configuration configuration) throws  ConfigurationException {
        addToMap(UnknownCmdHandler.UNKNOWN_COMMAND, unknownHandler);
        if(configuration == null || configuration.getChildren("handler") == null || configuration.getChildren("handler").length == 0) {
            configuration = new DefaultConfiguration("handlerchain");
            Properties cmds = new Properties();
            cmds.setProperty("AUTH",AuthCmdHandler.class.getName());
            cmds.setProperty("DATA",DataCmdHandler.class.getName());
            cmds.setProperty("EHLO",EhloCmdHandler.class.getName());
            cmds.setProperty("EXPN",ExpnCmdHandler.class.getName());
            cmds.setProperty("HELO",HeloCmdHandler.class.getName());
            cmds.setProperty("HELP",HelpCmdHandler.class.getName());
            cmds.setProperty("MAIL",MailCmdHandler.class.getName());
            cmds.setProperty("NOOP",NoopCmdHandler.class.getName());
            cmds.setProperty("QUIT",QuitCmdHandler.class.getName());
            cmds.setProperty("RCPT" ,RcptCmdHandler.class.getName());
            cmds.setProperty("RSET",RsetCmdHandler.class.getName());
            cmds.setProperty("VRFY",VrfyCmdHandler.class.getName());
            cmds.setProperty("Default SendMailHandler",SendMailHandler.class.getName());
            Enumeration e = cmds.keys();
            while (e.hasMoreElements()) {
                String cmdName = (String) e.nextElement();
                String className = cmds.getProperty(cmdName);
                DefaultConfiguration cmdConf = new DefaultConfiguration("handler");
                cmdConf.setAttribute("command",cmdName);
                cmdConf.setAttribute("class",className);
                ((DefaultConfiguration) configuration).addChild(cmdConf);
            }
        }
        if(configuration != null) {
            Configuration[] children = configuration.getChildren("handler");
            if ( children != null ) {
                ClassLoader classLoader = getClass().getClassLoader();
                for ( int i = 0 ; i < children.length ; i++ ) {
                    String className = children[i].getAttribute("class");
                    if(className != null) {
                        //load the handler
                        try {
                            Object handler = classLoader.loadClass(className).newInstance();

                            //enable logging
                            if (handler instanceof LogEnabled) {
                                ((LogEnabled)handler).enableLogging(getLogger());
                            }

                            //servicing the handler
                            ContainerUtil.service(handler,serviceManager);

                            //configure the handler
                            ContainerUtil.configure(handler,children[i]);

                            //if it is a connect handler add it to list of connect handlers
                            if(handler instanceof ConnectHandler) {
                                connectHandlers.add((ConnectHandler)handler);
                                if (getLogger().isInfoEnabled()) {
                                    getLogger().info("Added ConnectHandler: " + className);
                                }
                            }

                            //if it is a command handler add it to the map with key as command name
                            if(handler instanceof CommandHandler) {
                                String commandName = children[i].getAttribute("command");
                                commandName = commandName.toUpperCase(Locale.US);
                                addToMap(commandName, (CommandHandler)handler);
                                if (getLogger().isInfoEnabled()) {
                                    getLogger().info("Added Commandhandler: " + className);
                                }

                            }

                            //if it is a message handler add it to list of message handlers
                            if(handler instanceof MessageHandler) {
                                messageHandlers.add((MessageHandler)handler);
                                if (getLogger().isInfoEnabled()) {
                                    getLogger().info("Added MessageHandler: " + className);
                                }
                            }

                        } catch (ClassNotFoundException ex) {
                           if (getLogger().isErrorEnabled()) {
                               getLogger().error("Failed to add Commandhandler: " + className,ex);
                           }
                           throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
                        } catch (IllegalAccessException ex) {
                           if (getLogger().isErrorEnabled()) {
                               getLogger().error("Failed to add Commandhandler: " + className,ex);
                           }
                           throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
                        } catch (InstantiationException ex) {
                           if (getLogger().isErrorEnabled()) {
                               getLogger().error("Failed to add Commandhandler: " + className,ex);
                           }
                           throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
                        } catch (ServiceException e) {
                            if (getLogger().isErrorEnabled()) {
                                getLogger().error("Failed to service Commandhandler: " + className,e);
                            }
                            throw new ConfigurationException("Failed to add Commandhandler: " + className,e);
                        }
                    }
                }
            }
        }

        //the size must be greater than 1 because we added UnknownCmdHandler to the map
        if(commandHandlerMap.size() < 2) {
            if (getLogger().isErrorEnabled()) {
                getLogger().error("No commandhandlers configured");
            }
            throw new ConfigurationException("No commandhandlers configured");
        } else {
            boolean found = true;
            for (int i = 0; i < mandatoryCommands.length; i++) {
                if(!commandHandlerMap.containsKey(mandatoryCommands[i])) {
                    if (getLogger().isErrorEnabled()) {
                        getLogger().error("No commandhandlers configured for the command:" + mandatoryCommands[i]);
                    }
                    found = false;
                    break;
                }
            }

            if(!found) {
                throw new ConfigurationException("No commandhandlers configured for mandatory commands");
            }
            
            if (messageHandlers.size() == 0) {
                if (getLogger().isErrorEnabled()) {
                    getLogger().error("No messageHandler configured. Check that SendMailHandler is configured in the SMTPHandlerChain");
                }
                throw new ConfigurationException("No messageHandler configured");
            }

        }
    }

    /**
     * Add it to map (key as command name, value is an array list of commandhandlers)
     *
     * @param commandName the command name which will be key
     * @param cmdHandler The commandhandler object
     */
    private void addToMap(String commandName, CommandHandler cmdHandler) {
        ArrayList handlers = (ArrayList)commandHandlerMap.get(commandName);
        if(handlers == null) {
            handlers = new ArrayList();
            commandHandlerMap.put(commandName, handlers);
        }
        handlers.add(cmdHandler);
    }

    /**
     * Returns all the configured commandhandlers for the specified command
     *
     * @param commandName the command name which will be key
     * @return List of commandhandlers
     */
    List getCommandHandlers(String command) {
        if (command == null) {
            return null;
        }
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Lookup command handler for command: " + command);
        }
        List handlers =  (List)commandHandlerMap.get(command);
        if(handlers == null) {
            handlers = (List)commandHandlerMap.get(UnknownCmdHandler.UNKNOWN_COMMAND);
        }

        return handlers;
    }

    /**
     * Returns all the configured message handlers
     *
     * @return List of message handlers
     */
    List getMessageHandlers() {
        return messageHandlers;
    }

    /**
     * Returns all the configured connect handlers
     *
     * @return List of connect handlers
     */
    List getConnectHandlers() {
        return connectHandlers;
    }

}