openwfe.org.shell.CmdHandler Maven / Gradle / Ivy
/*
* Copyright (c) 2001-2006, Peter Mayne, John Mettraux, OpenWFE.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name of the "OpenWFE" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: CmdHandler.java 2713 2006-06-01 14:38:45Z jmettraux $
*/
package openwfe.org.shell;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This command line handler can parse a String into a command verb and its arguments,
* then execute a method determined by the command verb.
*
* Legal command verbs are determined by providing an Object that implements methods of the form
*
*
* public Boolean do_VERB(String[] args)
*
*
* The CmdHandler constructor will inspect the Object passed to it, find all methods that
* implement command verbs, and use the names of those methods (without the leading "do_")
* as the list of legal command verbs.
*
* The list of verbs is sorted alphabetically. When parsing a command line, abbreviations are
* allowed, with the first verb matching the abbreviation being used. Therefore, entering
* "a" with legal verbs "aa" and "ab" will cause the method do_aa() to be invoked.
*
*
Supoport for help methods is also provided. For a given verb VERB, the command "help VERB"
* will result in the method "public void help_VERB()" being invoked. The command "help" by itself
* will list the legal verbs.
*
*
To make the whole thing even easier, this class also provides a command loop which handles
* user input, parsing, and invoking of work methods. This means that all the input stuff can
* be handled by this class, and the classes that do the real work need only provide the
* do_VERB() (and optionally the help_VERB()) methods.
*
* @author Peter Mayne
*
*/
public class CmdHandler
{
// Invoked methods must return one of these.
//
public final static Boolean DO_NOT_EXIT = new Boolean(false);
public final static Boolean DO_EXIT = new Boolean(true);
// Find all words (containing any character except space and double quote)
// and all character sequences surrounded by double quotes.
//
private final Pattern p = Pattern.compile("[^ \"]+|\".*\"");
private String[] verbs;
// The object supplying the do_VERB(String[]) and optional help_VERB() methods.
//
private final Object commandObject;
// The results of parsing a command line.
//
private String verb = null;
private String[] args = null;
/**
* Create a new CmdHandler that recognises the command verbs in the supplied Object.
*
* @param commands
*/
public CmdHandler(Object o)
{
commandObject = o;
// Find all methods implementing a verb.
//
ArrayList methodList = new ArrayList();
Method[] methods = commandObject.getClass().getDeclaredMethods();
for(int i=0; iCommand verbs may be abbreviated: if the list of verbs is {"exit","quit"}
,
* the input verb "e" will be recognised as "exit". The verb list is scanned from the beginning,
* so a verb list of {"save","set"}
with input verb "s" will be unambiguously recognised
* as "save".
*
* @param line
*/
public void parse(String line)
{
verb = null;
args = null;
Matcher m = p.matcher(line.trim());
if(m.find())
{
// Fetch the command verb.
//
String v = m.group().toLowerCase();
// Do we have a recognised verb?
//
for(int i=0; iFor a verb "VERB", the method "public Boolean do_VERB(String[] args)" will be called,
* where "args" is the getArgs() from the parsed command line. The called method must return
* a Boolean indicating whether the command input should be terminated (such as a "quit" command).
*
* The verb "help" is treated specially. If "help" is specified by itself, the available verbs
* will be displayed. If an argument is given, the corresponding verb will be looked up and the
* method "public void help_VERB()" will be called.
*
* @param o The Object whose do_VERB() or help_VERB() method will be called.
*
* @return A boolean indicating whether the command input loop should be terminated.
*/
public boolean invoke(Object o)
{
boolean exiting = false;
if(getVerb().equals("help"))
{
help(o, getArgs());
return false;
}
String methodName = "do_" + getVerb();
try
{
Method command = o.getClass().getDeclaredMethod(methodName, new Class[] { String[].class });
Boolean b = (Boolean)command.invoke(o, new Object[] { getArgs() });
exiting = b.booleanValue();
}
catch(InvocationTargetException ite)
{
System.out.println("\n" + ite.getCause().toString() + "\n");
}
catch (NoSuchMethodException nsme)
{
System.out.println("Unimplemented command.");
}
catch (Throwable t)
{
t.printStackTrace();
}
return exiting;
}
private void help(Object o, String[] args)
{
if (args.length < 1)
{
System.out.println();
System.out.println("help []");
System.out.println("\nAvailable commands are:");
for (int i = 0; i < verbs.length; i++)
{
System.out.print(verbs[i] + " ");
}
System.out.println();
}
else
{
String cmd = args[0].toLowerCase();
boolean found = false;
for(int i=0; iA typical reader would be supplied by new BufferedReader(new InputStreamReader(System.in))
.
*
* @param prompt The input prompt.
* @param reader Where are we reading input from?
*/
public void commandLoop(String prompt, BufferedReader reader)
{
boolean exiting = false;
while (!exiting)
{
String line;
try
{
do
{
System.out.print(prompt);
line = reader.readLine().trim();
} while(line.length()==0);
}
catch (IOException ioe)
{
break;
}
parse(line);
if(getVerb()!=null)
{
if(invoke(commandObject))
{
break;
}
}
else
{
System.out.println("Unrecognised command.");
}
}
}
}