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 net.sf.sillyexceptions.OutOfTheBlueException;
22 import nl.toolforge.karma.core.KarmaRuntimeException;
23 import org.apache.commons.cli.CommandLineParser;
24 import org.apache.commons.cli.MissingArgumentException;
25 import org.apache.commons.cli.MissingOptionException;
26 import org.apache.commons.cli.Options;
27 import org.apache.commons.cli.ParseException;
28 import org.apache.commons.cli.PosixParser;
29 import org.apache.commons.cli.UnrecognizedOptionException;
30
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.InvocationTargetException;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.TreeMap;
41
42
43
44 /***
45 * This factory is the single resource of Command objects. <code>KarmaRuntimeException</code>s are thrown when
46 * something fails.
47 *
48 * @author W.H. Schraal
49 * @version $Id: CommandFactory.java,v 1.34 2004/11/10 23:53:07 asmedes Exp $
50 */
51 public final class CommandFactory {
52
53
54
55 private static CommandFactory factory = null;
56
57
58
59 private static Set commandNames = null;
60
61 private static Map commandsByName = null;
62 private static Map commandsByAlias = null;
63
64 /***
65 * Only static methods
66 */
67 private CommandFactory() throws CommandLoadException {
68 init();
69 }
70
71 private synchronized void init() throws CommandLoadException {
72
73 CommandDescriptorMap descriptors = CommandLoader.getInstance().load();
74
75 commandsByName = new TreeMap();
76 commandsByAlias = new TreeMap();
77 commandNames = new HashSet();
78
79
80
81
82 for (Iterator i = descriptors.values().iterator(); i.hasNext();) {
83 CommandDescriptor descriptor = (CommandDescriptor) i.next();
84
85 commandsByName.put(descriptor.getName(), descriptor);
86 commandNames.add(descriptor.getName());
87
88 for (Iterator j = descriptor.getAliasList().iterator(); j.hasNext();) {
89 String alias = (String) j.next();
90 commandsByAlias.put(alias, descriptor);
91 commandNames.add(alias);
92 }
93 }
94 }
95
96 /***
97 * Gets the singleton <code>CommandFactory</code>.
98 *
99 * @return The singleton <code>CommandFactory</code> instance.
100 */
101 public static CommandFactory getInstance() throws CommandLoadException {
102 if (factory == null) {
103 factory = new CommandFactory();
104 }
105 return factory;
106 }
107
108 /***
109 * Retrieves the correct <code>Command</code>-instance, by looking up the implementation class through
110 * <code>commandLine</code>.
111 *
112 * @param commandLineString Command arguments (e.g. <code>select-manifest -m karma-1.0</code>).
113 * @return The implementation of a <code>Command</code> object.
114 * @throws CommandException When a correct command could not be constructed. See
115 * {@link CommandException#INVALID_COMMAND}.
116 */
117 public Command getCommand(String commandLineString) throws CommandException {
118
119 String commandName = null;
120 commandLineString = commandLineString.trim();
121
122 if (commandLineString.indexOf(' ') > 0) {
123 commandName = commandLineString.substring(0, commandLineString.indexOf(' '));
124 } else {
125 commandName = commandLineString;
126 }
127
128 char[] chars = commandLineString.substring(commandName.length()).toCharArray();
129
130 List commandOptionsList = new ArrayList();
131
132 int j = 0;
133 String part = null;
134
135 while (j < chars.length) {
136
137
138
139 while (chars[j] == ' ') {
140 j++;
141 }
142
143 part = "";
144 if (chars[j] != '"') {
145
146
147 part += chars[j];
148 j++;
149
150 while ((j < chars.length) && (chars[j] != ' ') && (chars[j] != '\"')) {
151
152
153 part += chars[j];
154 j++;
155 }
156
157 } else if (chars[j] == '"') {
158
159
160
161 part += chars[j];
162 j++;
163
164 while (j < chars.length) {
165
166 if (chars[j] == '"') {
167 if (chars[j-1] != '//') {
168
169
170 j++;
171 break;
172 }
173 }
174
175
176 part += chars[j];
177 j++;
178 }
179
180
181 part += '"';
182 j++;
183 }
184
185 if (part.startsWith("\"") && part.endsWith("\"")) {
186 part = part.substring(1, part.length() - 1).trim();
187 }
188
189 commandOptionsList.add(part);
190 }
191
192 String[] commandOptions = (String[]) commandOptionsList.toArray(new String[commandOptionsList.size()]);
193
194 return getCommand(commandName, commandOptions);
195 }
196
197 public Command getCommand(String commandName, String[] arguments) throws CommandException {
198
199 Command cmd = null;
200
201 if (isCommand(commandName)) {
202
203 CommandDescriptor descriptor = null;
204 try {
205 descriptor = getCommandDescriptor(commandName);
206
207
208
209 Class implementingClass = null;
210 try {
211 implementingClass = Class.forName(descriptor.getClassName());
212 } catch (ClassNotFoundException c) {
213 throw new CommandException(CommandException.NO_IMPLEMENTING_CLASS, new Object[]{descriptor.getClassName()});
214 }
215
216 Constructor defaultConstructor = implementingClass.getConstructor(new Class[]{CommandDescriptor.class});
217 cmd = (Command) defaultConstructor.newInstance(new Object[]{descriptor});
218
219
220
221 CommandLineParser parser = new PosixParser();
222
223 Options parserOptions = descriptor.getOptions();
224
225
226
227
228
229
230 cmd.setCommandLine(parser.parse(parserOptions, arguments));
231
232 } catch (NoSuchMethodException e) {
233 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
234 } catch (SecurityException e) {
235 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
236 } catch (InstantiationException e) {
237 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
238 } catch (IllegalAccessException e) {
239 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
240 } catch (IllegalArgumentException e) {
241 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
242 } catch (InvocationTargetException e) {
243 throw new KarmaRuntimeException(e.getLocalizedMessage(), e);
244 } catch (ParseException e) {
245 if (e instanceof MissingOptionException) {
246 throw new CommandException(e, CommandException.MISSING_OPTION, new Object[]{e.getMessage()});
247 }
248 if (e instanceof UnrecognizedOptionException) {
249 throw new CommandException(e, CommandException.INVALID_OPTION, new Object[]{arguments});
250 }
251 if (e instanceof MissingArgumentException) {
252 throw new CommandException(e, CommandException.MISSING_ARGUMENT, new Object[]{e.getMessage()});
253 }
254 }
255 return cmd;
256 }
257
258
259 throw new CommandException(CommandException.UNKNOWN_COMMAND, new Object[]{commandName});
260 }
261
262 /***
263 * Checks if some string is a command within this context.
264 *
265 * @param name
266 * @return
267 */
268 private boolean isCommand(String name) {
269 return commandNames.contains(name);
270 }
271
272 public Collection getCommands() {
273 return commandsByName.values();
274 }
275
276 /***
277 * Retrieves the correct command descriptor either by name or by alias (whichever is passed as a
278 * parameter). Returns <code>null</code> if the descriptor could not be found.
279 */
280 public CommandDescriptor getCommandDescriptor(String commandId) {
281
282 try {
283 init();
284 } catch (CommandLoadException cle) {
285
286
287 throw new OutOfTheBlueException("Tried to reload the commands, but failed. This is strange because they have been loaded earlier with success");
288 }
289
290 if (commandsByName.containsKey(commandId)) {
291 return (CommandDescriptor) commandsByName.get(commandId);
292 } else {
293 if (commandsByAlias.containsKey(commandId)) {
294 return (CommandDescriptor) commandsByAlias.get(commandId);
295 }
296 }
297 return null;
298 }
299
300 }