1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package nl.toolforge.karma.core.cmd;
20
21 import nl.toolforge.karma.core.cmd.digester.CommandDescriptorCreationFactory;
22 import nl.toolforge.karma.core.cmd.digester.OptionDescriptorCreationFactory;
23 import org.apache.commons.cli.Options;
24 import org.apache.commons.digester.Digester;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.xml.sax.SAXException;
28
29 import java.io.IOException;
30 import java.net.URL;
31 import java.util.Enumeration;
32
33 /***
34 * <p>Loads command-descriptors from an <code>XML</code>-file. The default filename
35 * is <code>commands.xml</code>, which should be available in the classpath. It should have been shipped with
36 * the Karma Core release jar-file.
37 * <p/>
38 *
39 * @author W.M. Oosterom
40 * @author D.A. Smedes
41 * @version $Id: CommandLoader.java,v 1.33 2004/11/10 23:53:08 asmedes Exp $
42 */
43 public final class CommandLoader {
44
45
46
47 private static Log logger = LogFactory.getLog(CommandLoader.class);
48 /***
49 * Default filename for the command descriptor file
50 */
51 public static final String DEFAULT_COMMANDS_BASEDIR = "commands";
52
53 /*** File name for core commands. */
54 public static final String CORE_COMMANDS_FILE = "core-commands.xml";
55
56 /*** Directory where plugins are located. */
57 public static final String COMMAND_PLUGINS_DIR = "plugins";
58
59 /*** File name for plugin commands definitions. */
60 public static final String PLUGIN_COMMANDS_FILE = "commands.xml";
61
62 private CommandLoader() {
63 }
64
65 private static CommandLoader instance = null;
66
67 /***
68 * Gets the singleton instance of the <code>CommandLoader</code>.
69 *
70 * @return The singleton instance of the <code>CommandLoader</code>.
71 */
72 public static CommandLoader getInstance() {
73 if (instance == null) {
74 instance = new CommandLoader();
75 }
76 return instance;
77 }
78
79 /***
80 * Loads command xml files from a predefined base directory. The base directory is determined by
81 * {@link DEFAULT_COMMANDS_BASEDIR}, relative to the runtime classpath. Core commands are considered to be in
82 * <code>core-commands.xml</code>. The rest of the commands are located in plugin directories on the classpath.
83 *
84 * @return The full set of commands for Karma.
85 * @throws CommandLoadException
86 */
87 CommandDescriptorMap load() throws CommandLoadException {
88
89
90
91 CommandDescriptorMap uniqueCommands = loadCoreCommands();
92
93
94
95 Enumeration enum = null;
96 try {
97 String commands = DEFAULT_COMMANDS_BASEDIR + "/" + COMMAND_PLUGINS_DIR + "/" + PLUGIN_COMMANDS_FILE;
98 enum = this.getClass().getClassLoader().getResources(commands);
99 } catch (IOException ioe) {
100 throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[]{PLUGIN_COMMANDS_FILE});
101 }
102
103 while (enum.hasMoreElements()) {
104
105 CommandDescriptorMap map = (CommandDescriptorMap) load((URL) enum.nextElement());
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 uniqueCommands.addAll(map);
123 }
124
125 return uniqueCommands;
126 }
127
128 /***
129 * <p>Loads the <code>xml</code> file containing command descriptors.
130 *
131 * @param resource The resource url to a command <code>xml</code> file. Use
132 * {@link #load} to use the default settings.
133 * @return A <code>List</code> of {@link CommandDescriptor} instances.
134 *
135 * @throws CommandLoadException
136 */
137 CommandDescriptorMap load(URL resource) throws CommandLoadException {
138
139 try {
140 return (CommandDescriptorMap) getCommandDigester().parse(resource.openStream());
141 } catch (IOException e) {
142 logger.error(e);
143 throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[]{PLUGIN_COMMANDS_FILE});
144 } catch (SAXException e) {
145 logger.error(e);
146 throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_PLUGIN_COMMANDS_FILE, new Object[]{PLUGIN_COMMANDS_FILE});
147 }
148 }
149
150 /***
151 * Loads commands from the Karma default <code>commands.xml</code> file.
152 *
153 * @throws CommandLoadException
154 */
155 private CommandDescriptorMap loadCoreCommands() throws CommandLoadException {
156
157 try {
158 String defaultCommands = DEFAULT_COMMANDS_BASEDIR + "/" + CORE_COMMANDS_FILE;
159
160 CommandDescriptorMap cds = (CommandDescriptorMap) getCommandDigester().parse(this.getClass().getClassLoader().getResourceAsStream(defaultCommands));
161
162 return cds;
163 } catch (IOException e) {
164 logger.error(e);
165 throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_DEFAULT_COMMANDS, new Object[]{CORE_COMMANDS_FILE});
166 } catch (SAXException e) {
167 logger.error(e);
168 throw new CommandLoadException(CommandLoadException.LOAD_FAILURE_FOR_DEFAULT_COMMANDS, new Object[]{CORE_COMMANDS_FILE});
169 }
170 }
171
172 private Digester getCommandDigester() {
173
174 Digester digester = new Digester();
175
176 digester.addObjectCreate("commands", CommandDescriptorMap.class);
177
178 digester.addFactoryCreate("*/command", CommandDescriptorCreationFactory.class);
179 digester.addCallMethod("*/command/description", "setDescription", 0);
180 digester.addCallMethod("*/command/classname", "setClassName", 0);
181 digester.addCallMethod("*/command/help", "setHelp", 0);
182
183 digester.addObjectCreate("*/command/options", Options.class);
184
185 digester.addFactoryCreate("*/command/options/option", OptionDescriptorCreationFactory.class);
186 digester.addCallMethod("*/command/options/option/arg", "setArgName", 0);
187 digester.addSetNext("*/command/options/option", "addOption");
188
189 digester.addSetNext("*/command/options", "addOptions");
190
191 digester.addSetNext("*/command", "add");
192
193 return digester;
194 }
195 }