KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > console > text > module > AbstractConsoleModule


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: sequoia@continuent.org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * Initial developer(s): Nicolas Modrzyk.
20  * Contributor(s): Mathieu Peltier.
21  */

22
23 package org.continuent.sequoia.console.text.module;
24
25 import java.io.IOException JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
28 import java.util.Hashtable JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedList JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Properties JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36 import java.util.TreeSet JavaDoc;
37
38 import jline.ArgumentCompletor;
39 import jline.Completor;
40 import jline.FileNameCompletor;
41 import jline.SimpleCompletor;
42
43 import org.continuent.sequoia.common.i18n.ConsoleTranslate;
44 import org.continuent.sequoia.console.text.Console;
45 import org.continuent.sequoia.console.text.commands.ConsoleCommand;
46 import org.continuent.sequoia.console.text.commands.Help;
47 import org.continuent.sequoia.console.text.commands.History;
48 import org.continuent.sequoia.console.text.commands.Quit;
49
50 /**
51  * This class defines a AbstractConsoleModule
52  *
53  * @author <a HREF="mailto:Nicolas.Modrzyk@inria.fr">Nicolas Modrzyk </a>
54  * @author <a HREF="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
55  * @version 1.0
56  */

57 public abstract class AbstractConsoleModule
58 {
59   Console console;
60
61   TreeSet JavaDoc commands;
62
63   boolean quit = false;
64
65   protected Completor consoleCompletor;
66
67   /**
68    * location of the default command lists for the console modules
69    */

70   public static final String JavaDoc DEFAULT_COMMAND_PROPERTIES_FILE = "org/continuent/sequoia/console/text/console.ini";
71
72   /**
73    * Creates a new <code>AbstractConsoleModule.java</code> object
74    *
75    * @param console to refer from
76    */

77   public AbstractConsoleModule(Console console)
78   {
79     this.console = console;
80     this.commands = new TreeSet JavaDoc();
81     commands.add(new Help(this));
82     commands.add(new History(this));
83     commands.add(new Quit(this));
84     if (console.isInteractive())
85       console.printInfo(ConsoleTranslate.get("module.loading",
86           getDescriptionString()));
87     this.loadCommands();
88     this.loadCompletor();
89   }
90
91   /**
92    * Loads the commands for this module
93    */

94   protected final void loadCommands()
95   {
96     commands.clear();
97     String JavaDoc commandClassesAsString = loadCommandsFromProperties(getModuleID());
98     String JavaDoc[] commandClasses = parseCommands(commandClassesAsString);
99     addCommands(commandClasses, commands);
100   }
101
102   /**
103    * Parses a String representing a list of command classes (separated by
104    * commas) and returns an String[] representing the command classes
105    *
106    * @param commandClassesAsString a String representing a list of command
107    * classes (separated by commas)
108    * @return a (eventually empty) String[] where each String represents a
109    * command class
110    */

111   protected String JavaDoc[] parseCommands(String JavaDoc commandClassesAsString)
112   {
113     if (commandClassesAsString == null)
114     {
115       return new String JavaDoc[0];
116     }
117     String JavaDoc[] cmds = commandClassesAsString.split("\\s*,\\s*"); //$NON-NLS-1$
118
return cmds;
119   }
120
121   /**
122    * Add commands to this module. Commands instances are created by reflection
123    * based on the command class names passed in parameter
124    *
125    * @param commandClasses a String[] containing the class names of the command
126    * to instantiate
127    * @param commands Set where the commands are added
128    */

129   protected void addCommands(String JavaDoc[] commandClasses, Set JavaDoc commands)
130   {
131     for (int i = 0; i < commandClasses.length; i++)
132     {
133       String JavaDoc commandClass = commandClasses[i];
134       Class JavaDoc clazz;
135       try
136       {
137         clazz = Class.forName(commandClass);
138         Constructor JavaDoc constructor;
139         try
140         {
141           constructor = clazz.getConstructor(new Class JavaDoc[]{this.getClass()});
142         }
143         catch (NoSuchMethodException JavaDoc e)
144         {
145           constructor = clazz
146               .getConstructor(new Class JavaDoc[]{AbstractConsoleModule.class});
147         }
148         ConsoleCommand command = (ConsoleCommand) constructor
149             .newInstance(new Object JavaDoc[]{this});
150         commands.add(command);
151       }
152       catch (Exception JavaDoc e)
153       {
154         // fail silently: the command won't be added to the commands list
155
}
156     }
157   }
158
159   /**
160    * Extracts the commands from the command properties file as a single
161    * <code>String</code> containing a list of comma-separated command classes.
162    *
163    * @param moduleID module ID used as the key in the properties file
164    * @return a single <code>String</code> containing a list of comma-separated
165    * command classes corresponding to the module identified by
166    */

167   protected String JavaDoc loadCommandsFromProperties(String JavaDoc moduleID)
168   {
169     Properties JavaDoc props = new Properties JavaDoc();
170     try
171     {
172       String JavaDoc propertiesFile = System.getProperty("console.commands",
173           DEFAULT_COMMAND_PROPERTIES_FILE);
174       props.load(ClassLoader.getSystemResourceAsStream(propertiesFile));
175     }
176     catch (IOException JavaDoc e)
177     {
178       // fail silently: no commands will be loaded
179
}
180     String JavaDoc commandClassesAsString = props.getProperty(moduleID, "");
181     return commandClassesAsString;
182   }
183
184   /**
185    * Returns an unique ID which identifies the module. This value is used to
186    * identify the commands to load for this given module.
187    *
188    * @return an unique <code>String</code> which identifies the module
189    */

190   protected abstract String JavaDoc getModuleID();
191
192   /**
193    * Loads the commands for this module
194    */

195   protected void loadCompletor()
196   {
197     List JavaDoc completors = new LinkedList JavaDoc();
198     int size = commands.size();
199     if (size > 0)
200     {
201       TreeSet JavaDoc set = new TreeSet JavaDoc();
202       Iterator JavaDoc it = commands.iterator();
203       while (it.hasNext())
204       {
205         set.add(((ConsoleCommand) it.next()).getCommandName());
206       }
207       completors.add(new SimpleCompletor((String JavaDoc[]) set
208           .toArray(new String JavaDoc[size])));
209     }
210     completors.add(new FileNameCompletor());
211
212     Completor[] completorsArray = (Completor[]) completors
213         .toArray(new Completor[completors.size()]);
214     consoleCompletor = new ArgumentCompletor(completorsArray,
215         new CommandDelimiter());
216   }
217
218   /**
219    * Reload the completor associated with this module. This method must be
220    * called if the list of commands has been dynamically modified.
221    */

222   protected synchronized void reloadCompletor()
223   {
224     console.getConsoleReader().removeCompletor(consoleCompletor);
225     loadCompletor();
226     console.getConsoleReader().addCompletor(consoleCompletor);
227   }
228
229   /**
230    * Text description of this module
231    *
232    * @return <code>String</code> description to display
233    */

234   public abstract String JavaDoc getDescriptionString();
235
236   /**
237    * Display help for this module
238    */

239   public void help()
240   {
241     console.println(ConsoleTranslate.get("module.commands.available",
242         getDescriptionString()));
243     ConsoleCommand command;
244     Iterator JavaDoc it = commands.iterator();
245     while (it.hasNext())
246     {
247       command = (ConsoleCommand) it.next();
248       console.println(command.getCommandName() + " "
249           + command.getCommandParameters());
250       console.println(" " + command.getCommandDescription());
251     }
252   }
253
254   /**
255    * Quit this module
256    */

257   public void quit()
258   {
259     quit = true;
260     console.getConsoleReader().removeCompletor(getCompletor());
261     console.getConsoleReader().addCompletor(
262         console.getControllerModule().getCompletor());
263   }
264
265   /**
266    * Get all the commands for this module
267    *
268    * @return <code>TreeSet</code> of commands (commandName|commandObject)
269    */

270   public TreeSet JavaDoc getCommands()
271   {
272     return commands;
273   }
274
275   /**
276    * Get the prompt string for this module
277    *
278    * @return <code>String</code> to place before prompt
279    */

280   public abstract String JavaDoc getPromptString();
281
282   /**
283    * Handle a serie of commands
284    */

285   public void handlePrompt()
286   {
287
288     if (quit)
289     {
290       if (console.isInteractive())
291         console.printError(ConsoleTranslate.get("module.quitting",
292             getDescriptionString()));
293       return;
294     }
295
296     // login();
297
quit = false;
298     while (!quit)
299     {
300
301       Hashtable JavaDoc hashCommands = getHashCommands();
302       try
303       {
304         String JavaDoc commandLine = console.readLine(getPromptString());
305         if (commandLine == null)
306         {
307           quit();
308           break;
309         }
310         if (commandLine.equals(""))
311           continue;
312
313         handleCommandLine(commandLine, hashCommands);
314
315       }
316       catch (Exception JavaDoc e)
317       {
318         // try to get the cause exception instead of the useless jmx
319
// encapsulating one
320
if (e instanceof UndeclaredThrowableException JavaDoc)
321         {
322           try
323           {
324             e = (Exception JavaDoc) ((UndeclaredThrowableException JavaDoc) e)
325                 .getUndeclaredThrowable();
326           }
327           catch (Throwable JavaDoc ignored)
328           {
329           }
330         }
331         console.printError(ConsoleTranslate.get("module.command.got.error", e
332             .getMessage()), e);
333         if (!console.isInteractive() && console.isExitOnError())
334         {
335           System.exit(1);
336         }
337       }
338     }
339   }
340
341   /**
342    * Get the list of commands as strings for this module
343    *
344    * @return <code>Hashtable</code> list of <code>String</code> objects
345    */

346   public final Hashtable JavaDoc getHashCommands()
347   {
348     Hashtable JavaDoc hashCommands = new Hashtable JavaDoc();
349     ConsoleCommand consoleCommand;
350     Iterator JavaDoc it = commands.iterator();
351     while (it.hasNext())
352     {
353       consoleCommand = (ConsoleCommand) it.next();
354       hashCommands.put(consoleCommand.getCommandName(), consoleCommand);
355     }
356     return hashCommands;
357   }
358
359   /**
360    * Handle module command
361    *
362    * @param commandLine the command line to handle
363    * @param hashCommands the list of commands available for this module
364    * @throws Exception if fails *
365    */

366   public final void handleCommandLine(String JavaDoc commandLine, Hashtable JavaDoc hashCommands)
367       throws Exception JavaDoc
368   {
369     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(commandLine);
370     if (st.hasMoreTokens())
371     {
372       ConsoleCommand command = findConsoleCommand(commandLine, hashCommands);
373       if (command != null)
374       {
375         command.execute(commandLine
376             .substring(command.getCommandName().length()));
377         return;
378       }
379     }
380     throw new Exception JavaDoc(ConsoleTranslate.get("module.command.not.supported",
381         commandLine));
382   }
383
384   /**
385    * Find the <code>ConsoleCommand</code> based on the name of the command
386    * from the <code>commandLine</code> in the <code>hashCommands</code>. If
387    * more than one <code>ConsoleCommand</code>'s command name start the same
388    * way, return the <code>ConsoleCommand</code> with the longest one.
389    *
390    * @param commandLine the command line to handle
391    * @param hashCommands the list of commands available for this module
392    * @return the <code>ConsoleCommand</code> corresponding to the name of the
393    * command from the <code>commandLine</code> or <code>null</code>
394    * if there is no matching
395    */

396   public ConsoleCommand findConsoleCommand(String JavaDoc commandLine,
397       Hashtable JavaDoc hashCommands)
398   {
399     ConsoleCommand foundCommand = null;
400     for (Iterator JavaDoc iter = hashCommands.entrySet().iterator(); iter.hasNext();)
401     {
402       Map.Entry JavaDoc commandEntry = (Map.Entry JavaDoc) iter.next();
403       String JavaDoc commandName = (String JavaDoc) commandEntry.getKey();
404       if (commandLine.startsWith(commandName))
405       {
406         ConsoleCommand command = (ConsoleCommand) commandEntry.getValue();
407         if (foundCommand == null)
408         {
409           foundCommand = command;
410         }
411         if (command.getCommandName().length() > foundCommand.getCommandName()
412             .length())
413         {
414           foundCommand = command;
415         }
416       }
417     }
418     return foundCommand;
419   }
420
421   /**
422    * Handles login in this module
423    *
424    * @param params parameters to use to login in this module
425    * @throws Exception if fails
426    */

427   public abstract void login(String JavaDoc[] params) throws Exception JavaDoc;
428
429   /**
430    * Get access to the console
431    *
432    * @return <code>Console</code> instance
433    */

434   public Console getConsole()
435   {
436     return console;
437   }
438
439   /**
440    * Returns the console completor to use for this module.
441    *
442    * @return <code>Completor</code> object.
443    */

444   public Completor getCompletor()
445   {
446     return consoleCompletor;
447   }
448
449   /**
450    * This class defines a CommandDelimiter used to delimit a command from user
451    * input
452    */

453   class CommandDelimiter extends ArgumentCompletor.AbstractArgumentDelimiter
454   {
455     /**
456      * @see jline.ArgumentCompletor.AbstractArgumentDelimiter#isDelimiterChar(java.lang.String,
457      * int)
458      */

459     public boolean isDelimiterChar(String JavaDoc buffer, int pos)
460     {
461       String JavaDoc tentativeCmd = buffer.substring(0, pos);
462       return isACompleteCommand(tentativeCmd);
463     }
464
465     /**
466      * Test if the String input by the user insofar is a complete command or
467      * not.
468      *
469      * @param input Text input by the user
470      * @return <code>true</code> if the text input by the user is a complete
471      * command name, <code>false</code> else
472      */

473     private boolean isACompleteCommand(String JavaDoc input)
474     {
475       boolean foundCompleteCommand = false;
476       for (Iterator JavaDoc iter = commands.iterator(); iter.hasNext();)
477       {
478         ConsoleCommand command = (ConsoleCommand) iter.next();
479         if (input.equals(command.getCommandName()))
480         {
481           foundCompleteCommand = !otherCommandsStartWith(command
482               .getCommandName());
483         }
484       }
485       return foundCompleteCommand;
486     }
487
488     private boolean otherCommandsStartWith(String JavaDoc commandName)
489     {
490       for (Iterator JavaDoc iter = commands.iterator(); iter.hasNext();)
491       {
492         ConsoleCommand command = (ConsoleCommand) iter.next();
493         if (command.getCommandName().startsWith(commandName)
494             && !command.getCommandName().equals(commandName))
495         {
496           return true;
497         }
498       }
499       return false;
500     }
501   }
502 }
Popular Tags