chris@3: /*
chris@3:  *   SONEWS News Server
chris@3:  *   see AUTHORS for the list of contributors
chris@3:  *
chris@3:  *   This program is free software: you can redistribute it and/or modify
chris@3:  *   it under the terms of the GNU General Public License as published by
chris@3:  *   the Free Software Foundation, either version 3 of the License, or
chris@3:  *   (at your option) any later version.
chris@3:  *
chris@3:  *   This program is distributed in the hope that it will be useful,
chris@3:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@3:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
chris@3:  *   GNU General Public License for more details.
chris@3:  *
chris@3:  *   You should have received a copy of the GNU General Public License
chris@3:  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
chris@3:  */
chris@3: 
chris@3: package org.sonews.daemon;
chris@3: 
chris@3: import java.util.HashMap;
chris@3: import java.util.Map;
cli@26: import java.util.Set;
chris@3: import java.util.concurrent.ConcurrentHashMap;
chris@3: import org.sonews.daemon.command.Command;
chris@3: import org.sonews.daemon.command.UnsupportedCommand;
chris@3: import org.sonews.util.Log;
chris@3: import org.sonews.util.io.Resource;
chris@3: 
chris@3: /**
chris@3:  * Selects the correct command processing class.
chris@3:  * @author Christian Lins
cli@21:  * @since sonews/1.0
chris@3:  */
cli@21: public class CommandSelector
chris@3: {
chris@3: 
cli@37: 	private static Map<Thread, CommandSelector> instances = new ConcurrentHashMap<Thread, CommandSelector>();
cli@37: 	private static Map<String, Class<?>> commandClassesMapping = new ConcurrentHashMap<String, Class<?>>();
chris@3: 
cli@37: 	static {
cli@37: 		String[] classes = Resource.getAsString("helpers/commands.list", true).split("\n");
cli@37: 		for (String className : classes) {
cli@37: 			if (className.charAt(0) == '#') {
cli@37: 				// Skip comments
cli@37: 				continue;
cli@37: 			}
cli@10: 
cli@37: 			try {
cli@37: 				addCommandHandler(className);
cli@37: 			} catch (ClassNotFoundException ex) {
cli@37: 				Log.get().warning("Could not load command class: " + ex);
cli@37: 			} catch (InstantiationException ex) {
cli@37: 				Log.get().severe("Could not instantiate command class: " + ex);
cli@37: 			} catch (IllegalAccessException ex) {
cli@37: 				Log.get().severe("Could not access command class: " + ex);
cli@37: 			}
cli@37: 		}
cli@37: 	}
chris@3: 
cli@37: 	public static void addCommandHandler(String className)
cli@37: 		throws ClassNotFoundException, InstantiationException,
cli@37: 		IllegalAccessException
cli@37: 	{
cli@37: 		Class<?> clazz = Class.forName(className);
cli@37: 		Command cmd = (Command) clazz.newInstance();
cli@37: 		String[] cmdStrs = cmd.getSupportedCommandStrings();
cli@37: 		for (String cmdStr : cmdStrs) {
cli@37: 			commandClassesMapping.put(cmdStr, clazz);
cli@37: 		}
cli@37: 	}
cli@21: 
cli@37: 	public static Set<String> getCommandNames()
cli@37: 	{
cli@37: 		return commandClassesMapping.keySet();
cli@37: 	}
cli@26: 
cli@37: 	public static CommandSelector getInstance()
cli@37: 	{
cli@37: 		CommandSelector csel = instances.get(Thread.currentThread());
cli@37: 		if (csel == null) {
cli@37: 			csel = new CommandSelector();
cli@37: 			instances.put(Thread.currentThread(), csel);
cli@37: 		}
cli@37: 		return csel;
cli@37: 	}
cli@37: 	private Map<String, Command> commandMapping = new HashMap<String, Command>();
cli@37: 	private Command unsupportedCmd = new UnsupportedCommand();
cli@21: 
cli@37: 	private CommandSelector()
cli@37: 	{
cli@37: 	}
cli@21: 
cli@37: 	public Command get(String commandName)
cli@37: 	{
cli@37: 		try {
cli@37: 			commandName = commandName.toUpperCase();
cli@37: 			Command cmd = this.commandMapping.get(commandName);
cli@21: 
cli@37: 			if (cmd == null) {
cli@37: 				Class<?> clazz = commandClassesMapping.get(commandName);
cli@37: 				if (clazz == null) {
cli@37: 					cmd = this.unsupportedCmd;
cli@37: 				} else {
cli@37: 					cmd = (Command) clazz.newInstance();
cli@37: 					this.commandMapping.put(commandName, cmd);
cli@37: 				}
cli@37: 			} else if (cmd.isStateful()) {
cli@37: 				cmd = cmd.getClass().newInstance();
cli@37: 			}
chris@3: 
cli@37: 			return cmd;
cli@37: 		} catch (Exception ex) {
cli@37: 			ex.printStackTrace();
cli@37: 			return this.unsupportedCmd;
cli@37: 		}
cli@37: 	}
chris@3: }