Java tutorial
/* Karma core - Core of the Karma application Copyright (C) 2004 Toolforge <www.toolforge.nl> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.toolforge.karma.core.cmd; import nl.toolforge.karma.core.cmd.digester.CommandDescriptorCreationFactory; import nl.toolforge.karma.core.cmd.digester.OptionDescriptorCreationFactory; import org.apache.commons.cli.Options; import org.apache.commons.digester.Digester; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.SAXException; import java.io.IOException; import java.net.URL; import java.util.Enumeration; /** * <p>Loads command-descriptors from an <code>XML</code>-file. The default filename * is <code>commands.xml</code>, which should be available in the classpath. It should have been shipped with * the Karma Core release jar-file. * <p/> * * @author W.M. Oosterom * @author D.A. Smedes * @version $Id$ */ public final class CommandLoader { //TODO the xml instance should be checked by a DTD or XML Schema document. private static Log logger = LogFactory.getLog(CommandLoader.class); /** * Default filename for the command descriptor file */ public static final String DEFAULT_COMMANDS_BASEDIR = "commands"; /** File name for core commands. */ public static final String CORE_COMMANDS_FILE = "core-commands.xml"; /** Directory where plugins are located. */ public static final String COMMAND_PLUGINS_DIR = "plugins"; /** File name for plugin commands definitions. */ public static final String PLUGIN_COMMANDS_FILE = "commands.xml"; private CommandLoader() { } private static CommandLoader instance = null; /** * Gets the singleton instance of the <code>CommandLoader</code>. * * @return The singleton instance of the <code>CommandLoader</code>. */ public static CommandLoader getInstance() { if (instance == null) { instance = new CommandLoader(); } return instance; } /** * Loads command xml files from a predefined base directory. The base directory is determined by * {@link DEFAULT_COMMANDS_BASEDIR}, relative to the runtime classpath. Core commands are considered to be in * <code>core-commands.xml</code>. The rest of the commands are located in plugin directories on the classpath. * * @return The full set of commands for Karma. * @throws CommandLoadException */ CommandDescriptorMap load() throws CommandLoadException { // Load the core commands // CommandDescriptorMap uniqueCommands = loadCoreCommands(); // Load the plugin commands // Enumeration enumeration = null; try { String commands = DEFAULT_COMMANDS_BASEDIR + "/" + COMMAND_PLUGINS_DIR + "/" + PLUGIN_COMMANDS_FILE; enumeration = this.getClass().getClassLoader().getResources(commands); } catch (IOException ioe) { throw new CommandLoadException(ioe, CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[] { PLUGIN_COMMANDS_FILE }); } while (enumeration.hasMoreElements()) { CommandDescriptorMap map = (CommandDescriptorMap) load((URL) enumeration.nextElement()); // for (Iterator i = map.keySet().iterator(); i.hasNext();) { // // CommandDescriptor descriptor = map.get((String) i.next()); // // for (Iterator j = descriptor.getAliasList().iterator(); j.hasNext();) { // String alias = (String) j.next(); // if (uniqueCommands.keySet().contains(alias)) { // throw new CommandLoadException(CommandLoadException.DUPLICATE_COMMAND, new Object[]{alias}); // } // } // // At this point, we have not found a duplicate. // // // uniqueCommands.add(descriptor); // } uniqueCommands.addAll(map); } return uniqueCommands; } /** * <p>Loads the <code>xml</code> file containing command descriptors. * * @param resource The resource url to a command <code>xml</code> file. Use * {@link #load} to use the default settings. * @return A <code>List</code> of {@link CommandDescriptor} instances. * * @throws CommandLoadException */ CommandDescriptorMap load(URL resource) throws CommandLoadException { try { return (CommandDescriptorMap) getCommandDigester().parse(resource.openStream()); } catch (IOException e) { logger.error(e); throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[] { PLUGIN_COMMANDS_FILE }); } catch (SAXException e) { logger.error(e); throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[] { PLUGIN_COMMANDS_FILE }); } } /** * Loads commands from the Karma default <code>commands.xml</code> file. * * @throws CommandLoadException */ private CommandDescriptorMap loadCoreCommands() throws CommandLoadException { try { String defaultCommands = DEFAULT_COMMANDS_BASEDIR + "/" + CORE_COMMANDS_FILE; CommandDescriptorMap cds = (CommandDescriptorMap) getCommandDigester() .parse(this.getClass().getClassLoader().getResourceAsStream(defaultCommands)); return cds; } catch (IOException e) { logger.error(e); throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_DEFAULT_COMMANDS, new Object[] { CORE_COMMANDS_FILE }); } catch (SAXException e) { logger.error(e); throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_DEFAULT_COMMANDS, new Object[] { CORE_COMMANDS_FILE }); } } private Digester getCommandDigester() { Digester digester = new Digester(); digester.addObjectCreate("commands", CommandDescriptorMap.class); digester.addFactoryCreate("*/command", CommandDescriptorCreationFactory.class); digester.addCallMethod("*/command/description", "setDescription", 0); digester.addCallMethod("*/command/classname", "setClassName", 0); digester.addCallMethod("*/command/help", "setHelp", 0); digester.addObjectCreate("*/command/options", Options.class); digester.addFactoryCreate("*/command/options/option", OptionDescriptorCreationFactory.class); digester.addCallMethod("*/command/options/option/arg", "setArgName", 0); digester.addSetNext("*/command/options/option", "addOption"); digester.addSetNext("*/command/options", "addOptions"); // Adds an Option to the command. digester.addSetNext("*/command", "add"); // Adds a CommandDescriptor instance to the set. return digester; } }