/*************************************************************************** * * * CommandFactory.java * * ------------------- * * date : 26. Mai 2003, 18:32 * * copyright : (C) 2004 Distributed and Mobile Systems Group * * Lehrstuhl fuer Praktische Informatik * * Universitaet Bamberg * * http://www.uni-bamberg.de/pi/ * * email : sven.kaffille@uni-bamberg.de * * * * * ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * A copy of the license can be found in the license.txt file supplied * * with this software or at: http://www.gnu.org/copyleft/gpl.html * * * ***************************************************************************/ package de.uniba.wiai.lspi.util.console; import java.util.*; import java.lang.reflect.*; import java.io.PrintStream; import de.uniba.wiai.lspi.util.console.parser.*; /** * Factory responsible to create instances of {@link Command} given the commands * name. The factory must be supplied with a mapping from the commands' names to * the commands' classes, which are subclasses of {@link Command}. The mapping * is provided through a Hashtable containing keys (Strings) representing * command names and values (Strings) representing class names. <br/> <div> For * example: <br/> <CODE> MyClass toCommand = new MyClass(...); <br/> Hashtable * myMapping = new Hashtable(); <br/> myMapping.put("exit", * MyExitCommand.class.getName()); <br/> ... <br/> CommandFactory factory = new * CommandFactory(toCommand, myMapping); <br/> </CODE> <br/> </div> On creation * the factory is provided with one or more Objects, on which the commands will * be executed. Additionally the mapping from command names to command classes * implementing the command must be provided to the <code>CommandFactory</code>. * This factory is used by {@link ConsoleThread}. * * @author sven * @version 1.0.5 */ public class CommandFactory { /** * The Objects given to the Commands to execute commands on. */ protected Object[] toCommand; /** * The mapping from command name to command class name. */ protected Map<String, String> commandMapping; /** * Map containing already instantiated commands. Key: name of command, Value: instance of {@link Command} . */ protected Map<String, Command> instanceMap; /** * The PrintStream to that all {@link Command}s print their outputs. */ protected PrintStream out; /** * Creates a new instance of CommandFactory. * * @param out * The PrintStream, to that all {@link Command}s created by this * factory, print their output to. * @param toCommand * The Objects to execute commands on. * @param commandMapping * The mapping from command name to command class. This must not * be <code>null</code> or have a size of zero! */ public CommandFactory(Object[] toCommand, PrintStream out, Map<String, String> commandMapping) { this.toCommand = new Object[toCommand.length]; System.arraycopy(toCommand, 0, this.toCommand, 0, this.toCommand.length); this.out = out; this.commandMapping = commandMapping; this.instanceMap = new HashMap<String, Command>(); } /** * Add the given {@link Command} <code>cmd</code> to this command factory. * * @param name * The name of the command to add. * @param cmdClass The class name of {@link Command} to add. */ public void addCommand(String name, String cmdClass) { this.commandMapping.put(name, cmdClass); } /** * Get the PrintStream, to that all {@link Command}s created by this * factory, print their output to. * * @return The PrintStream. */ public PrintStream getPrintStream() { return this.out; } /** * Creates the {@link Command} instance corresponding to the given command * name. Therefore the given command line is parsed with help of * {@link CommandParser}, the command name and parameters extracted from * it, the correspondig {@link Command} created and the parameters passed to * the command. Then the command is returned. * * @param commandLine * The command line entered into the console (See * {@link ConsoleThread}). * @throws ConsoleException * Any Exception during creation of command. * @return The instance of the command corresponding to given commandLine. */ public Command createCommand(String commandLine) throws ConsoleException { if (commandLine == null) { throw new IllegalArgumentException("commandLine must not be null!"); } Command com = null; try { String command = CommandParser.parse(commandLine); /* * TODO: check if parser generated with javacc can be made compliant * to Java 5.0 */ Map<String, String> parameters = CommandParser .parseParams(commandLine); /* * Test if there is already an instance of that command, * that can be reused. */ if (this.instanceMap.containsKey(command)) { com = this.instanceMap.get(command); } else { // try to load command String commandClass = this.commandMapping.get(command); if (commandClass == null || commandClass.length() == 0) { throw new ConsoleException("Unknown command: '" + command + "'"); } Class comClass = null; // try { try { comClass = Class.forName(commandClass); } catch (ClassNotFoundException e) { throw new ConsoleException("Unknown command: " + command); } Class[] argtypes = new Class[2]; argtypes[0] = Object[].class; argtypes[1] = java.io.PrintStream.class; Constructor comClassCons = null; try { comClassCons = comClass.getDeclaredConstructor(argtypes); } catch (SecurityException e) { throw new ConsoleException("Unknown command: " + command); } catch (NoSuchMethodException e) { throw new ConsoleException("Unknown command: " + command); } Object[] arg = new Object[2]; arg[0] = this.toCommand; arg[1] = this.out; try { com = (Command) comClassCons.newInstance(arg); } catch (IllegalArgumentException e) { throw new ConsoleException("Unknown command: " + command); } catch (InstantiationException e) { throw new ConsoleException("Unknown command: " + command); } catch (IllegalAccessException e) { throw new ConsoleException("Unknown command: " + command); } catch (InvocationTargetException e) { throw new ConsoleException("Unknown command: " + command); } this.instanceMap.put(command, com); } com.setParameters(parameters); return com; } catch (ParseException e) { throw new ConsoleException( "Command misspelled? Could not parse command."); } } }