package dmg.util; import dmg.util.command.AcCommandScanner; import org.dcache.util.Args; import org.dcache.util.cli.AnnotatedCommandScanner; /** * Scans a specified object and makes a special set * of methods available for dynamic invocation on * command strings. * * <pre> * method syntax : * 1) public Object ac_<key1>_..._<keyN>(Args args) * 2) public Object ac_<key1>_..._<keyN>_$_n(Args args) * 3) public Object ac_<key1>_..._<keyN>_$_n_m(Args args) * </pre> * The first syntax requires a command string which exactly matches * the specified <code>key1</code> to <code>keyN</code>. * No extra arguments are excepted. * The second syntax allows exactly <code>n</code> extra arguments * following a matching sequence of keys. The third * syntax allows between <code>n</code> and <code>m</code> * extra arguments following a matching sequence of keys. * Each ac_ method may have a corresponding one line help hint * with the following signature. * <pre> * String hh_<key1>_..._<keyN> = "..." ; * </pre> * The assigned string should only present the * additional arguments and shouldn't repeat the command part * itself. * A full help can be made available with the signature * <pre> * String fh_<key1>_..._<keyN> = "..." ; * </pre> * The assigned String should contain a detailed multiline * description of the command. This text is returned * as a result of the <code>help ... </code> command. * Consequently <code>help</code> is a reserved keyword * and can't be used as first key. * <p> * */ public class CommandInterpreter extends org.dcache.util.cli.CommandInterpreter { public CommandInterpreter() { addCommandScanner(new AnnotatedCommandScanner()); addCommandScanner(new AcCommandScanner()); addCommandListener(this); } public CommandInterpreter(Object commandListener) { addCommandScanner(new AnnotatedCommandScanner()); addCommandScanner(new AcCommandScanner()); addCommandListener(commandListener); } /** * Is a convenient method of <code>command(Args args)</code>. * All Exceptions are caught and converted to a meaningful * String except the CommandExitException which allows the * corresponding object to signal a kind * of final state. This method should be overwritten to * customize the behavior on different Exceptions. * This method <strong>never</strong> returns the null * pointer even if the underlying <code>command</code> * method does so. */ public String command(String str) throws CommandExitException { if (str.trim().isEmpty()) { return ""; } try { Object o = command(new Args(str)); if (o == null) { return ""; } return (String) o; } catch (CommandSyntaxException e) { StringBuilder sb = new StringBuilder(); sb.append("Syntax Error : ").append(e.getMessage()).append('\n'); String help = e.getHelpText(); if (help != null) { sb.append("Help : \n"); sb.append(help); } return sb.toString(); } catch (CommandExitException e) { throw e; } catch (CommandThrowableException e) { StringBuilder sb = new StringBuilder(); sb.append(e.getMessage()).append('\n'); Throwable t = e.getTargetException(); sb.append(t.getClass().getName()).append(" : ").append(t.getMessage()).append('\n'); return sb.toString(); } catch (CommandPanicException e) { StringBuilder sb = new StringBuilder(); sb.append("Panic : ").append(e.getMessage()).append('\n'); Throwable t = e.getTargetException(); sb.append(t.getClass().getName()).append(" : ").append(t.getMessage()).append('\n'); return sb.toString(); } catch (CommandException e) { return "??? : " + e; } } }