View Javadoc

1   /************************************************************************
2    * Copyright (c) 1999-2006 The Apache Software Foundation.             *
3    * All rights reserved.                                                *
4    * ------------------------------------------------------------------- *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you *
6    * may not use this file except in compliance with the License. You    *
7    * may obtain a copy of the License at:                                *
8    *                                                                     *
9    *     http://www.apache.org/licenses/LICENSE-2.0                      *
10   *                                                                     *
11   * Unless required by applicable law or agreed to in writing, software *
12   * distributed under the License is distributed on an "AS IS" BASIS,   *
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
14   * implied.  See the License for the specific language governing       *
15   * permissions and limitations under the License.                      *
16   ***********************************************************************/
17  
18  package org.apache.james.smtpserver;
19  
20  import java.util.ArrayList;
21  import java.util.Enumeration;
22  import java.util.List;
23  import java.util.HashMap;
24  import java.util.Locale;
25  import java.util.Properties;
26  
27  import org.apache.avalon.framework.configuration.Configurable;
28  import org.apache.avalon.framework.configuration.Configuration;
29  import org.apache.avalon.framework.configuration.ConfigurationException;
30  import org.apache.avalon.framework.configuration.DefaultConfiguration;
31  import org.apache.avalon.framework.container.ContainerUtil;
32  import org.apache.avalon.framework.logger.AbstractLogEnabled;
33  import org.apache.avalon.framework.logger.LogEnabled;
34  import org.apache.avalon.framework.service.ServiceException;
35  import org.apache.avalon.framework.service.ServiceManager;
36  import org.apache.avalon.framework.service.Serviceable;
37  
38  /***
39    * The SMTPHandlerChain is per service object providing access
40    * ConnectHandlers, Commandhandlers and message handlers
41    */
42  public class SMTPHandlerChain extends AbstractLogEnabled implements Configurable, Serviceable {
43  
44      private HashMap commandHandlerMap = new HashMap();
45      private ArrayList messageHandlers = new ArrayList();
46      private ArrayList connectHandlers = new ArrayList();
47  
48      private final CommandHandler unknownHandler = new UnknownCmdHandler();
49      private ServiceManager serviceManager;
50  
51      private final static String[] mandatoryCommands = { "MAIL" , "RCPT", "DATA"};
52  
53      public void service(ServiceManager arg0) throws ServiceException {
54          serviceManager = arg0;
55      }
56  
57  
58      /***
59       * loads the various handlers from the configuration
60       * @param configuration configuration under handlerchain node
61       */
62      public void configure(Configuration configuration) throws  ConfigurationException {
63          addToMap(UnknownCmdHandler.UNKNOWN_COMMAND, unknownHandler);
64          if(configuration == null || configuration.getChildren("handler") == null || configuration.getChildren("handler").length == 0) {
65              configuration = new DefaultConfiguration("handlerchain");
66              Properties cmds = new Properties();
67              cmds.setProperty("AUTH",AuthCmdHandler.class.getName());
68              cmds.setProperty("DATA",DataCmdHandler.class.getName());
69              cmds.setProperty("EHLO",EhloCmdHandler.class.getName());
70              cmds.setProperty("EXPN",ExpnCmdHandler.class.getName());
71              cmds.setProperty("HELO",HeloCmdHandler.class.getName());
72              cmds.setProperty("HELP",HelpCmdHandler.class.getName());
73              cmds.setProperty("MAIL",MailCmdHandler.class.getName());
74              cmds.setProperty("NOOP",NoopCmdHandler.class.getName());
75              cmds.setProperty("QUIT",QuitCmdHandler.class.getName());
76              cmds.setProperty("RCPT" ,RcptCmdHandler.class.getName());
77              cmds.setProperty("RSET",RsetCmdHandler.class.getName());
78              cmds.setProperty("VRFY",VrfyCmdHandler.class.getName());
79              cmds.setProperty("Default SendMailHandler",SendMailHandler.class.getName());
80              Enumeration e = cmds.keys();
81              while (e.hasMoreElements()) {
82                  String cmdName = (String) e.nextElement();
83                  String className = cmds.getProperty(cmdName);
84                  DefaultConfiguration cmdConf = new DefaultConfiguration("handler");
85                  cmdConf.setAttribute("command",cmdName);
86                  cmdConf.setAttribute("class",className);
87                  ((DefaultConfiguration) configuration).addChild(cmdConf);
88              }
89          }
90          if(configuration != null) {
91              Configuration[] children = configuration.getChildren("handler");
92              if ( children != null ) {
93                  ClassLoader classLoader = getClass().getClassLoader();
94                  for ( int i = 0 ; i < children.length ; i++ ) {
95                      String className = children[i].getAttribute("class");
96                      if(className != null) {
97                          //load the handler
98                          try {
99                              Object handler = classLoader.loadClass(className).newInstance();
100 
101                             //enable logging
102                             if (handler instanceof LogEnabled) {
103                                 ((LogEnabled)handler).enableLogging(getLogger());
104                             }
105 
106                             //servicing the handler
107                             ContainerUtil.service(handler,serviceManager);
108 
109                             //configure the handler
110                             ContainerUtil.configure(handler,children[i]);
111 
112                             //if it is a connect handler add it to list of connect handlers
113                             if(handler instanceof ConnectHandler) {
114                                 connectHandlers.add((ConnectHandler)handler);
115                                 if (getLogger().isInfoEnabled()) {
116                                     getLogger().info("Added ConnectHandler: " + className);
117                                 }
118                             }
119 
120                             //if it is a command handler add it to the map with key as command name
121                             if(handler instanceof CommandHandler) {
122                                 String commandName = children[i].getAttribute("command");
123                                 commandName = commandName.toUpperCase(Locale.US);
124                                 addToMap(commandName, (CommandHandler)handler);
125                                 if (getLogger().isInfoEnabled()) {
126                                     getLogger().info("Added Commandhandler: " + className);
127                                 }
128 
129                             }
130 
131                             //if it is a message handler add it to list of message handlers
132                             if(handler instanceof MessageHandler) {
133                                 messageHandlers.add((MessageHandler)handler);
134                                 if (getLogger().isInfoEnabled()) {
135                                     getLogger().info("Added MessageHandler: " + className);
136                                 }
137                             }
138 
139                         } catch (ClassNotFoundException ex) {
140                            if (getLogger().isErrorEnabled()) {
141                                getLogger().error("Failed to add Commandhandler: " + className,ex);
142                            }
143                            throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
144                         } catch (IllegalAccessException ex) {
145                            if (getLogger().isErrorEnabled()) {
146                                getLogger().error("Failed to add Commandhandler: " + className,ex);
147                            }
148                            throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
149                         } catch (InstantiationException ex) {
150                            if (getLogger().isErrorEnabled()) {
151                                getLogger().error("Failed to add Commandhandler: " + className,ex);
152                            }
153                            throw new ConfigurationException("Failed to add Commandhandler: " + className,ex);
154                         } catch (ServiceException e) {
155                             if (getLogger().isErrorEnabled()) {
156                                 getLogger().error("Failed to service Commandhandler: " + className,e);
157                             }
158                             throw new ConfigurationException("Failed to add Commandhandler: " + className,e);
159                         }
160                     }
161                 }
162             }
163         }
164 
165         //the size must be greater than 1 because we added UnknownCmdHandler to the map
166         if(commandHandlerMap.size() < 2) {
167             if (getLogger().isErrorEnabled()) {
168                 getLogger().error("No commandhandlers configured");
169             }
170             throw new ConfigurationException("No commandhandlers configured");
171         } else {
172             boolean found = true;
173             for (int i = 0; i < mandatoryCommands.length; i++) {
174                 if(!commandHandlerMap.containsKey(mandatoryCommands[i])) {
175                     if (getLogger().isErrorEnabled()) {
176                         getLogger().error("No commandhandlers configured for the command:" + mandatoryCommands[i]);
177                     }
178                     found = false;
179                     break;
180                 }
181             }
182 
183             if(!found) {
184                 throw new ConfigurationException("No commandhandlers configured for mandatory commands");
185             }
186             
187             if (messageHandlers.size() == 0) {
188                 if (getLogger().isErrorEnabled()) {
189                     getLogger().error("No messageHandler configured. Check that SendMailHandler is configured in the SMTPHandlerChain");
190                 }
191                 throw new ConfigurationException("No messageHandler configured");
192             }
193 
194         }
195     }
196 
197     /***
198      * Add it to map (key as command name, value is an array list of commandhandlers)
199      *
200      * @param commandName the command name which will be key
201      * @param cmdHandler The commandhandler object
202      */
203     private void addToMap(String commandName, CommandHandler cmdHandler) {
204         ArrayList handlers = (ArrayList)commandHandlerMap.get(commandName);
205         if(handlers == null) {
206             handlers = new ArrayList();
207             commandHandlerMap.put(commandName, handlers);
208         }
209         handlers.add(cmdHandler);
210     }
211 
212     /***
213      * Returns all the configured commandhandlers for the specified command
214      *
215      * @param commandName the command name which will be key
216      * @return List of commandhandlers
217      */
218     List getCommandHandlers(String command) {
219         if (command == null) {
220             return null;
221         }
222         if (getLogger().isDebugEnabled()) {
223             getLogger().debug("Lookup command handler for command: " + command);
224         }
225         List handlers =  (List)commandHandlerMap.get(command);
226         if(handlers == null) {
227             handlers = (List)commandHandlerMap.get(UnknownCmdHandler.UNKNOWN_COMMAND);
228         }
229 
230         return handlers;
231     }
232 
233     /***
234      * Returns all the configured message handlers
235      *
236      * @return List of message handlers
237      */
238     List getMessageHandlers() {
239         return messageHandlers;
240     }
241 
242     /***
243      * Returns all the configured connect handlers
244      *
245      * @return List of connect handlers
246      */
247     List getConnectHandlers() {
248         return connectHandlers;
249     }
250 
251 }