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
98 try {
99 Object handler = classLoader.loadClass(className).newInstance();
100
101
102 if (handler instanceof LogEnabled) {
103 ((LogEnabled)handler).enableLogging(getLogger());
104 }
105
106
107 ContainerUtil.service(handler,serviceManager);
108
109
110 ContainerUtil.configure(handler,children[i]);
111
112
113 if(handler instanceof ConnectHandler) {
114 connectHandlers.add((ConnectHandler)handler);
115 if (getLogger().isInfoEnabled()) {
116 getLogger().info("Added ConnectHandler: " + className);
117 }
118 }
119
120
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
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
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 }