001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.smtpserver;
019:
020: import java.util.ArrayList;
021: import java.util.Enumeration;
022: import java.util.List;
023: import java.util.HashMap;
024: import java.util.Locale;
025: import java.util.Properties;
026:
027: import org.apache.avalon.framework.configuration.Configurable;
028: import org.apache.avalon.framework.configuration.Configuration;
029: import org.apache.avalon.framework.configuration.ConfigurationException;
030: import org.apache.avalon.framework.configuration.DefaultConfiguration;
031: import org.apache.avalon.framework.container.ContainerUtil;
032: import org.apache.avalon.framework.logger.AbstractLogEnabled;
033: import org.apache.avalon.framework.logger.LogEnabled;
034: import org.apache.avalon.framework.service.ServiceException;
035: import org.apache.avalon.framework.service.ServiceManager;
036: import org.apache.avalon.framework.service.Serviceable;
037:
038: /**
039: * The SMTPHandlerChain is per service object providing access
040: * ConnectHandlers, Commandhandlers and message handlers
041: */
042: public class SMTPHandlerChain extends AbstractLogEnabled implements
043: Configurable, Serviceable {
044:
045: private HashMap commandHandlerMap = new HashMap();
046: private ArrayList messageHandlers = new ArrayList();
047: private ArrayList connectHandlers = new ArrayList();
048:
049: private final CommandHandler unknownHandler = new UnknownCmdHandler();
050: private ServiceManager serviceManager;
051:
052: private final static String[] mandatoryCommands = { "MAIL", "RCPT",
053: "DATA" };
054:
055: public void service(ServiceManager arg0) throws ServiceException {
056: serviceManager = arg0;
057: }
058:
059: /**
060: * loads the various handlers from the configuration
061: * @param configuration configuration under handlerchain node
062: */
063: public void configure(Configuration configuration)
064: throws ConfigurationException {
065: addToMap(UnknownCmdHandler.UNKNOWN_COMMAND, unknownHandler);
066: if (configuration == null
067: || configuration.getChildren("handler") == null
068: || configuration.getChildren("handler").length == 0) {
069: configuration = new DefaultConfiguration("handlerchain");
070: Properties cmds = new Properties();
071: cmds.setProperty("AUTH", AuthCmdHandler.class.getName());
072: cmds.setProperty("DATA", DataCmdHandler.class.getName());
073: cmds.setProperty("EHLO", EhloCmdHandler.class.getName());
074: cmds.setProperty("EXPN", ExpnCmdHandler.class.getName());
075: cmds.setProperty("HELO", HeloCmdHandler.class.getName());
076: cmds.setProperty("HELP", HelpCmdHandler.class.getName());
077: cmds.setProperty("MAIL", MailCmdHandler.class.getName());
078: cmds.setProperty("NOOP", NoopCmdHandler.class.getName());
079: cmds.setProperty("QUIT", QuitCmdHandler.class.getName());
080: cmds.setProperty("RCPT", RcptCmdHandler.class.getName());
081: cmds.setProperty("RSET", RsetCmdHandler.class.getName());
082: cmds.setProperty("VRFY", VrfyCmdHandler.class.getName());
083: cmds.setProperty("Default SendMailHandler",
084: SendMailHandler.class.getName());
085: Enumeration e = cmds.keys();
086: while (e.hasMoreElements()) {
087: String cmdName = (String) e.nextElement();
088: String className = cmds.getProperty(cmdName);
089: DefaultConfiguration cmdConf = new DefaultConfiguration(
090: "handler");
091: cmdConf.setAttribute("command", cmdName);
092: cmdConf.setAttribute("class", className);
093: ((DefaultConfiguration) configuration)
094: .addChild(cmdConf);
095: }
096: }
097: if (configuration != null) {
098: Configuration[] children = configuration
099: .getChildren("handler");
100: if (children != null) {
101: ClassLoader classLoader = getClass().getClassLoader();
102: for (int i = 0; i < children.length; i++) {
103: String className = children[i]
104: .getAttribute("class");
105: if (className != null) {
106: //load the handler
107: try {
108: Object handler = classLoader.loadClass(
109: className).newInstance();
110:
111: //enable logging
112: if (handler instanceof LogEnabled) {
113: ((LogEnabled) handler)
114: .enableLogging(getLogger());
115: }
116:
117: //servicing the handler
118: ContainerUtil.service(handler,
119: serviceManager);
120:
121: //configure the handler
122: ContainerUtil.configure(handler,
123: children[i]);
124:
125: //if it is a connect handler add it to list of connect handlers
126: if (handler instanceof ConnectHandler) {
127: connectHandlers
128: .add((ConnectHandler) handler);
129: if (getLogger().isInfoEnabled()) {
130: getLogger().info(
131: "Added ConnectHandler: "
132: + className);
133: }
134: }
135:
136: //if it is a command handler add it to the map with key as command name
137: if (handler instanceof CommandHandler) {
138: String commandName = children[i]
139: .getAttribute("command");
140: commandName = commandName
141: .toUpperCase(Locale.US);
142: addToMap(commandName,
143: (CommandHandler) handler);
144: if (getLogger().isInfoEnabled()) {
145: getLogger().info(
146: "Added Commandhandler: "
147: + className);
148: }
149:
150: }
151:
152: //if it is a message handler add it to list of message handlers
153: if (handler instanceof MessageHandler) {
154: messageHandlers
155: .add((MessageHandler) handler);
156: if (getLogger().isInfoEnabled()) {
157: getLogger().info(
158: "Added MessageHandler: "
159: + className);
160: }
161: }
162:
163: } catch (ClassNotFoundException ex) {
164: if (getLogger().isErrorEnabled()) {
165: getLogger().error(
166: "Failed to add Commandhandler: "
167: + className, ex);
168: }
169: throw new ConfigurationException(
170: "Failed to add Commandhandler: "
171: + className, ex);
172: } catch (IllegalAccessException ex) {
173: if (getLogger().isErrorEnabled()) {
174: getLogger().error(
175: "Failed to add Commandhandler: "
176: + className, ex);
177: }
178: throw new ConfigurationException(
179: "Failed to add Commandhandler: "
180: + className, ex);
181: } catch (InstantiationException ex) {
182: if (getLogger().isErrorEnabled()) {
183: getLogger().error(
184: "Failed to add Commandhandler: "
185: + className, ex);
186: }
187: throw new ConfigurationException(
188: "Failed to add Commandhandler: "
189: + className, ex);
190: } catch (ServiceException e) {
191: if (getLogger().isErrorEnabled()) {
192: getLogger().error(
193: "Failed to service Commandhandler: "
194: + className, e);
195: }
196: throw new ConfigurationException(
197: "Failed to add Commandhandler: "
198: + className, e);
199: }
200: }
201: }
202: }
203: }
204:
205: //the size must be greater than 1 because we added UnknownCmdHandler to the map
206: if (commandHandlerMap.size() < 2) {
207: if (getLogger().isErrorEnabled()) {
208: getLogger().error("No commandhandlers configured");
209: }
210: throw new ConfigurationException(
211: "No commandhandlers configured");
212: } else {
213: boolean found = true;
214: for (int i = 0; i < mandatoryCommands.length; i++) {
215: if (!commandHandlerMap
216: .containsKey(mandatoryCommands[i])) {
217: if (getLogger().isErrorEnabled()) {
218: getLogger().error(
219: "No commandhandlers configured for the command:"
220: + mandatoryCommands[i]);
221: }
222: found = false;
223: break;
224: }
225: }
226:
227: if (!found) {
228: throw new ConfigurationException(
229: "No commandhandlers configured for mandatory commands");
230: }
231:
232: if (messageHandlers.size() == 0) {
233: if (getLogger().isErrorEnabled()) {
234: getLogger()
235: .error(
236: "No messageHandler configured. Check that SendMailHandler is configured in the SMTPHandlerChain");
237: }
238: throw new ConfigurationException(
239: "No messageHandler configured");
240: }
241:
242: }
243: }
244:
245: /**
246: * Add it to map (key as command name, value is an array list of commandhandlers)
247: *
248: * @param commandName the command name which will be key
249: * @param cmdHandler The commandhandler object
250: */
251: private void addToMap(String commandName, CommandHandler cmdHandler) {
252: ArrayList handlers = (ArrayList) commandHandlerMap
253: .get(commandName);
254: if (handlers == null) {
255: handlers = new ArrayList();
256: commandHandlerMap.put(commandName, handlers);
257: }
258: handlers.add(cmdHandler);
259: }
260:
261: /**
262: * Returns all the configured commandhandlers for the specified command
263: *
264: * @param commandName the command name which will be key
265: * @return List of commandhandlers
266: */
267: List getCommandHandlers(String command) {
268: if (command == null) {
269: return null;
270: }
271: if (getLogger().isDebugEnabled()) {
272: getLogger().debug(
273: "Lookup command handler for command: " + command);
274: }
275: List handlers = (List) commandHandlerMap.get(command);
276: if (handlers == null) {
277: handlers = (List) commandHandlerMap
278: .get(UnknownCmdHandler.UNKNOWN_COMMAND);
279: }
280:
281: return handlers;
282: }
283:
284: /**
285: * Returns all the configured message handlers
286: *
287: * @return List of message handlers
288: */
289: List getMessageHandlers() {
290: return messageHandlers;
291: }
292:
293: /**
294: * Returns all the configured connect handlers
295: *
296: * @return List of connect handlers
297: */
298: List getConnectHandlers() {
299: return connectHandlers;
300: }
301:
302: }
|