KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > internal > core > FrameworkCommandInterpreter


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.osgi.framework.internal.core;
13
14 import java.io.*;
15 import java.lang.reflect.*;
16 import java.net.URL JavaDoc;
17 import java.util.*;
18 import org.eclipse.osgi.framework.console.CommandInterpreter;
19 import org.eclipse.osgi.framework.console.CommandProvider;
20 import org.eclipse.osgi.util.NLS;
21 import org.osgi.framework.Bundle;
22
23 /**
24  * This class knows how to parse and execute the command line arguments to the FrameworkConsole.
25  * It attempts to pass the command to each registered CommandProvider until it finds one
26  * that knows what to do with it.
27  *
28  * FrameworkCommandInterpreter provides support for the "More" command which allows the operator to configure
29  * the number of lines to display before being prompted to continue.
30  *
31  * FrameworkCommandInterpreter provides several print methods which handle the "More" command.
32  */

33 public class FrameworkCommandInterpreter implements CommandInterpreter {
34     private static final String JavaDoc WS_DELIM = " \t\n\r\f"; //$NON-NLS-1$
35

36     /** The command line in StringTokenizer form */
37     private StringTokenizer tok;
38     /** The active CommandProviders */
39     private Object JavaDoc[] commandProviders;
40     /** The FrameworkConsole */
41     private FrameworkConsole con;
42     /** The stream to send output to */
43     private PrintWriter out;
44
45     /** Strings used to format other strings */
46     private String JavaDoc tab = "\t"; //$NON-NLS-1$
47
private String JavaDoc newline = "\r\n"; //$NON-NLS-1$
48
private boolean firstCommand = true;
49
50     /**
51      * The maximum number of lines to print without user prompt.
52      * 0 means no user prompt is required, the window is scrollable.
53      */

54     protected static int maxLineCount;
55
56     /** The number of lines printed without user prompt.*/
57     protected int currentLineCount;
58
59     /**
60      * The constructor. It turns the cmdline string into a StringTokenizer and remembers
61      * the input parms.
62      */

63     public FrameworkCommandInterpreter(String JavaDoc cmdline, Object JavaDoc[] commandProviders, FrameworkConsole con) {
64         tok = new StringTokenizer(cmdline);
65         this.commandProviders = commandProviders;
66         this.con = con;
67         this.out = con.getWriter();
68     }
69
70     /**
71      Get the next argument in the input.
72      
73      E.g. if the commandline is hello world, the _hello method
74      will get "world" as the first argument.
75      
76      @return A string containing the next argument on the command line
77      */

78     public String JavaDoc nextArgument() {
79         if (tok == null || !tok.hasMoreElements())
80             return null;
81         
82         String JavaDoc arg = tok.nextToken();
83         if (arg.startsWith("\"")) { //$NON-NLS-1$
84
if (arg.endsWith("\"")) { //$NON-NLS-1$
85
if (arg.length() >= 2)
86                     // strip the beginning and ending quotes
87
return arg.substring(1, arg.length() - 1);
88             }
89             String JavaDoc remainingArg = tok.nextToken("\""); //$NON-NLS-1$
90
arg = arg.substring(1) + remainingArg;
91             // skip to next whitespace separated token
92
tok.nextToken(WS_DELIM);
93         } else if (arg.startsWith("'")) { //$NON-NLS-1$ //$NON-NLS-2$
94
if (arg.endsWith("'")) { //$NON-NLS-1$
95
if (arg.length() >= 2)
96                     // strip the beginning and ending quotes
97
return arg.substring(1, arg.length() - 1);
98             }
99             String JavaDoc remainingArg = tok.nextToken("'"); //$NON-NLS-1$
100
arg = arg.substring(1) + remainingArg;
101             // skip to next whitespace separated token
102
tok.nextToken(WS_DELIM);
103         }
104         return arg;
105     }
106
107     /**
108      Execute a command line as if it came from the end user.
109      
110      Searches the list of command providers using introspection until
111      it finds one that contains a matching method. It searches for a method
112      with the name "_cmd" where cmd is the command to execute. For example,
113      for a command of "launch" execute searches for a method called "_launch".
114      
115      @param cmd The name of the command to execute.
116      @return The object returned by the method executed.
117      */

118     public Object JavaDoc execute(String JavaDoc cmd) {
119         if (!firstCommand)
120             return innerExecute(cmd);
121         firstCommand = false;
122         resetLineCount();
123         Object JavaDoc retval = null;
124         // handle "more" command here
125
if (cmd.equalsIgnoreCase("more")) { //$NON-NLS-1$
126
try {
127                 _more();
128             } catch (Exception JavaDoc e) {
129                 printStackTrace(e);
130             }
131             return retval;
132         }
133         // handle "disconnect" command here
134
if (cmd.equalsIgnoreCase("disconnect") && con.getUseSocketStream()) { //$NON-NLS-1$
135
try {
136                 _disconnect();
137             } catch (Exception JavaDoc e) {
138                 printStackTrace(e);
139             }
140             return retval;
141         }
142         Class JavaDoc[] parameterTypes = new Class JavaDoc[] {CommandInterpreter.class};
143         Object JavaDoc[] parameters = new Object JavaDoc[] {this};
144         boolean executed = false;
145         int size = commandProviders.length;
146         for (int i = 0; !executed && (i < size); i++) {
147             try {
148                 Object JavaDoc target = commandProviders[i];
149                 Method method = target.getClass().getMethod("_" + cmd, parameterTypes); //$NON-NLS-1$
150
retval = method.invoke(target, parameters);
151                 executed = true; // stop after the command has been found
152
} catch (NoSuchMethodException JavaDoc ite) {
153                 // keep going - maybe another command provider will be able to execute this command
154
} catch (InvocationTargetException ite) {
155                 executed = true; // don't want to keep trying - we found the method but got an error
156
printStackTrace(ite.getTargetException());
157             } catch (Exception JavaDoc ee) {
158                 executed = true; // don't want to keep trying - we got an error we don't understand
159
printStackTrace(ee);
160             }
161         }
162         // if no command was found to execute, display help for all registered command providers
163
if (!executed) {
164             for (int i = 0; i < size; i++) {
165                 try {
166                     CommandProvider commandProvider = (CommandProvider) commandProviders[i];
167                     out.print(commandProvider.getHelp());
168                     out.flush();
169                 } catch (Exception JavaDoc ee) {
170                     printStackTrace(ee);
171                 }
172             }
173             // call help for the more command provided by this class
174
out.print(getHelp());
175             out.flush();
176         }
177         return retval;
178     }
179
180     private Object JavaDoc innerExecute(String JavaDoc cmd) {
181         if (cmd != null && cmd.length() > 0) {
182             CommandInterpreter intcp = new FrameworkCommandInterpreter(cmd, commandProviders, con);
183             String JavaDoc command = intcp.nextArgument();
184             if (command != null)
185                 return intcp.execute(command);
186         }
187         return null;
188     }
189
190     /**
191      * Answers the number of lines output to the console
192      * window should scroll without user interaction.
193      *
194      * @return The number of lines to scroll.
195      */

196     private int getMaximumLinesToScroll() {
197         return maxLineCount;
198     }
199
200     /**
201      * Sets the number of lines output to the console
202      * window will scroll without user interaction.
203      * <p>
204      * Note that this number does not include the line
205      * for the 'more' prompt itself.
206      * <p>
207      * If the number of lines is 0 then no 'more' prompt
208      * is disabled.
209      *
210      * @param lines the number of lines to scroll
211      */

212     private void setMaximumLinesToScroll(int lines) {
213         if (lines < 0) {
214             throw new IllegalArgumentException JavaDoc(ConsoleMsg.CONSOLE_LINES_TO_SCROLL_NEGATIVE_ERROR);
215         }
216
217         maxLineCount = lines;
218     }
219
220     /**
221      * Resets the line counter for the 'more' prompt.
222      */

223     private void resetLineCount() {
224         currentLineCount = 0;
225     }
226
227     /**
228      * Prints a string to the output medium (appended with newline character).
229      * <p>
230      * This method does not increment the line counter for the 'more' prompt.
231      *
232      * @param o the string to be printed
233      */

234     private void printline(Object JavaDoc o) {
235         print(o + newline);
236     }
237
238     /**
239      * Prints an object to the outputstream
240      *
241      * @param o the object to be printed
242      */

243     public void print(Object JavaDoc o) {
244         synchronized (out) {
245             check4More();
246             out.print(o);
247             out.flush();
248         }
249     }
250
251     /**
252      * Prints a empty line to the outputstream
253      */

254     public void println() {
255         println(""); //$NON-NLS-1$
256
}
257
258     /**
259      * Print a stack trace including nested exceptions.
260      * @param t The offending exception
261      */

262     public void printStackTrace(Throwable JavaDoc t) {
263         t.printStackTrace(out);
264
265         Method[] methods = t.getClass().getMethods();
266
267         int size = methods.length;
268         Class JavaDoc throwable = Throwable JavaDoc.class;
269
270         for (int i = 0; i < size; i++) {
271             Method method = methods[i];
272
273             if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("get") && throwable.isAssignableFrom(method.getReturnType()) && (method.getParameterTypes().length == 0)) { //$NON-NLS-1$
274
try {
275                     Throwable JavaDoc nested = (Throwable JavaDoc) method.invoke(t, null);
276
277                     if ((nested != null) && (nested != t)) {
278                         out.println(ConsoleMsg.CONSOLE_NESTED_EXCEPTION);
279                         printStackTrace(nested);
280                     }
281                 } catch (IllegalAccessException JavaDoc e) {
282                 } catch (InvocationTargetException e) {
283                 }
284             }
285         }
286     }
287
288     /**
289      * Prints an object to the output medium (appended with newline character).
290      * <p>
291      * If running on the target environment, the user is prompted with '--more'
292      * if more than the configured number of lines have been printed without user prompt.
293      * This enables the user of the program to have control over scrolling.
294      * <p>
295      * For this to work properly you should not embed "\n" etc. into the string.
296      *
297      * @param o the object to be printed
298      */

299     public void println(Object JavaDoc o) {
300         if (o == null) {
301             return;
302         }
303         synchronized (out) {
304             check4More();
305             printline(o);
306             currentLineCount++;
307             currentLineCount += o.toString().length() / 80;
308         }
309     }
310
311     /**
312      * Prints the given dictionary sorted by keys.
313      *
314      * @param dic the dictionary to print
315      * @param title the header to print above the key/value pairs
316      */

317     public void printDictionary(Dictionary dic, String JavaDoc title) {
318         if (dic == null)
319             return;
320
321         int count = dic.size();
322         String JavaDoc[] keys = new String JavaDoc[count];
323         Enumeration keysEnum = dic.keys();
324         int i = 0;
325         while (keysEnum.hasMoreElements()) {
326             keys[i++] = (String JavaDoc) keysEnum.nextElement();
327         }
328         Util.sort(keys);
329
330         if (title != null) {
331             println(title);
332         }
333         for (i = 0; i < count; i++) {
334             println(" " + keys[i] + " = " + dic.get(keys[i])); //$NON-NLS-1$//$NON-NLS-2$
335
}
336         println();
337     }
338
339     /**
340      * Prints the given bundle resource if it exists
341      *
342      * @param bundle the bundle containing the resource
343      * @param resource the resource to print
344      */

345     public void printBundleResource(Bundle bundle, String JavaDoc resource) {
346         URL JavaDoc entry = null;
347         entry = bundle.getEntry(resource);
348         if (entry != null) {
349             try {
350                 println(resource);
351                 InputStream in = entry.openStream();
352                 byte[] buffer = new byte[1024];
353                 int read = 0;
354                 try {
355                     while ((read = in.read(buffer)) != -1)
356                         print(new String JavaDoc(buffer, 0, read));
357                 } finally {
358                     if (in != null) {
359                         try {
360                             in.close();
361                         } catch (IOException e) {
362                         }
363                     }
364                 }
365             } catch (Exception JavaDoc e) {
366                 System.err.println(NLS.bind(ConsoleMsg.CONSOLE_ERROR_READING_RESOURCE, resource));
367             }
368         } else {
369             println(NLS.bind(ConsoleMsg.CONSOLE_RESOURCE_NOT_IN_BUNDLE, resource, bundle.toString()));
370         }
371     }
372
373     /**
374      * Displays the more... prompt if the max line count has been reached
375      * and waits for the operator to hit enter.
376      *
377      */

378     private void check4More() {
379         int max = getMaximumLinesToScroll();
380         if (max > 0) {
381             if (currentLineCount >= max) {
382                 out.print(ConsoleMsg.CONSOLE_MORE);
383                 out.flush();
384                 con.getInput(); // wait for user entry
385
resetLineCount(); //Reset the line counter for the 'more' prompt
386
}
387         }
388     }
389
390     /**
391      Answer a string (may be as many lines as you like) with help
392      texts that explain the command.
393      */

394     public String JavaDoc getHelp() {
395         StringBuffer JavaDoc help = new StringBuffer JavaDoc(256);
396         help.append(newline);
397         help.append(ConsoleMsg.CONSOLE_HELP_CONTROLLING_CONSOLE_HEADING);
398         help.append(newline);
399         help.append(tab);
400         help.append("more - "); //$NON-NLS-1$
401
help.append(ConsoleMsg.CONSOLE_HELP_MORE);
402         if (con.getUseSocketStream()) {
403             help.append(newline);
404             help.append(tab);
405             help.append("disconnect - "); //$NON-NLS-1$
406
help.append(ConsoleMsg.CONSOLE_HELP_DISCONNECT);
407         }
408         return help.toString();
409     }
410
411     /**
412      * Toggles the use of the more prompt for displayed output.
413      *
414      */

415     public void _more() throws Exception JavaDoc {
416         if (confirm(ConsoleMsg.CONSOLE_CONFIRM_MORE, true)) {
417             int lines = prompt(newline + ConsoleMsg.CONSOLE_MORE_ENTER_LINES, 24);
418             setMaximumLinesToScroll(lines);
419         } else {
420             setMaximumLinesToScroll(0);
421         }
422     }
423
424     private void _disconnect() throws Exception JavaDoc {
425         if (confirm(ConsoleMsg.CONSOLE_CONFIRM_DISCONNECT, true)) {
426             con.disconnect();
427         }
428     }
429
430     /**
431      * Prompts the user for confirmation.
432      *
433      * @param string the message to present to the user to confirm
434      * @param defaultAnswer the default result
435      *
436      * @return <code>true</code> if the user confirms; <code>false</code> otherwise.
437      */

438     protected boolean confirm(String JavaDoc string, boolean defaultAnswer) {
439         synchronized (out) {
440             if (string.length() > 0) {
441                 print(string);
442             } else {
443                 print(ConsoleMsg.CONSOLE_CONFIRM);
444             }
445             print(" (" + ConsoleMsg.CONSOLE_CONFIRM_VALUES); //$NON-NLS-1$
446
if (defaultAnswer) {
447                 print(ConsoleMsg.CONSOLE_Y + ") "); //$NON-NLS-1$
448
} else {
449                 print(ConsoleMsg.CONSOLE_N + ") "); //$NON-NLS-1$
450
}
451         }
452         String JavaDoc input = con.getInput();
453         resetLineCount();
454         if (input.length() == 0) {
455             return defaultAnswer;
456         }
457         return input.toLowerCase().charAt(0) == ConsoleMsg.CONSOLE_Y.charAt(0);
458     }
459
460     /**
461      * Prompts the user for input from the input medium providing a default value.
462      *
463      * @param string the message to present to the user
464      * @param defaultAnswer the string to use as a default return value
465      *
466      * @return The user provided string or the defaultAnswer,
467      * if user provided string was empty.
468      */

469     protected String JavaDoc prompt(String JavaDoc string, String JavaDoc defaultAnswer) {
470         if (string.length() > 0) {
471             if (defaultAnswer.length() > 0) {
472                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(256);
473                 buf.append(string);
474                 buf.append(" "); //$NON-NLS-1$
475
buf.append(ConsoleMsg.CONSOLE_PROMPT_DEFAULT);
476                 buf.append("="); //$NON-NLS-1$
477
buf.append(defaultAnswer);
478                 buf.append(") "); //$NON-NLS-1$
479
print(buf.toString());
480             } else {
481                 print(string);
482             }
483         }
484         String JavaDoc input = con.getInput();
485         resetLineCount();
486         if (input.length() > 0) {
487             return input;
488         }
489         return defaultAnswer;
490     }
491
492     /**
493      * Prompts the user for input of a positive integer.
494      *
495      * @param string the message to present to the user
496      * @param defaultAnswer the integer to use as a default return value
497      *
498      * @return The user provided integer or the defaultAnswer,
499      * if user provided an empty input.
500      */

501     protected int prompt(String JavaDoc string, int defaultAnswer) {
502         Integer JavaDoc i = new Integer JavaDoc(defaultAnswer);
503         int answer;
504         for (int j = 0; j < 3; j++) {
505             String JavaDoc s = prompt(string, i.toString());
506             try {
507                 answer = Integer.parseInt(s);
508                 if (answer >= 0) {
509                     return answer;
510                 }
511             } catch (NumberFormatException JavaDoc e) {
512             }
513             println(ConsoleMsg.CONSOLE_INVALID_INPUT);
514         }
515         println(ConsoleMsg.CONSOLE_TOO_MUCH_INVALID_INPUT);
516         return defaultAnswer;
517     }
518 }
519
Popular Tags