Reflection-based command line processor





7
Date Submitted Sat. Oct. 28th, 2006 6:03 PM
Revision 1 of 1
Scripter SCoon
Tags "Command Line" | Java | Reflection
Comments 0 comments
This class uses reflection to locate option setters. Client class must contains methods setFile (to receive file names from the command line) and setOption### (to receive option ###).

(See also adapter-based implementation)
import java.io.File;
import java.lang.reflect.Method;

public class CommandLineProcessor {

  public static final String METHOD_SET_FILE = "setFile";

  public static final String ARG_PREFIX1 = "--";
  public static final String ARG_PREFIX2 = "//";

  protected int m_fileNo = 0;

  public void execute (String[] args, Object client) {
    boolean optionsAllowed = true;
    int argIndex = 0;
    while (argIndex < args.length) {
      String arg = args[argIndex++];
      if (optionsAllowed) {
        if (ARG_PREFIX1.equals(arg) || ARG_PREFIX2.equals(arg)) {
          optionsAllowed = false;
          continue;
        }
        String optionName;
        if (arg.startsWith(ARG_PREFIX1)) {
          optionName = arg.substring(ARG_PREFIX1.length());
        } else if (arg.startsWith(ARG_PREFIX2)) {
          optionName = arg.substring(ARG_PREFIX2.length());
        } else {
          optionName = null;
        }
        if (optionName == null) {
          setFile(client, arg);
        } else {
          argIndex = setOption(client, optionName, args, argIndex);
        }
      } else {
        setFile(client, arg);
      }
    }
  }

  protected void setFile (Object client, String fileName) {
    Method method = getMethod(client, METHOD_SET_FILE, new Class[] { Integer.TYPE, File.class });
    if (method == null) {
      throw new Exception("Client '" + client.getClass().getName() + "' has no method " + METHOD_SET_FILE);
    }
    try {
      method.invoke(client, new Object[] { new Integer(m_fileNo++), new File(fileName) });
    } catch (Throwable t) {
      throw new Exception("Error updating file option", t);
    }
  }

  protected int setOption (Object client, String optionName, String[] args, int argIndex) {
    String methodName = "setOption" + optionName.substring(0,1).toUpperCase() + optionName.substring(1);
    Method method = getMethod(client, methodName, new Class[] { String.class });
    if (method != null) {
      invokeOptionSetter(client, method, new Object[] { getArg(optionName, args, argIndex, "value expected") }, optionName);
      return argIndex+1;
    }
    method = getMethod(client, methodName, new Class[0]);
    if (method != null) {
      invokeOptionSetter(client, method, new Object[0], optionName);
      return argIndex;
    }
    throw new Exception("Unexpected option '" + optionName + "'");
  }

  protected void invokeOptionSetter (Object client, Method method, Object[] args, String optionName) {
    try {
      method.invoke(client, args);
    } catch (Throwable t) {
      throw new Exception("Error updating option '" + optionName + "'", t);
    }
  }

  protected Method getMethod (Object client, String name, Class[] argTypes) {
    Class clazz = client.getClass();
    try {
      return clazz.getMethod(name, argTypes);
    } catch (NoSuchMethodException nsme) {
      return null;
    } catch (Throwable t) {
      throw new Exception("Error accessing method " + name + " of class '" + clazz.getName() + "'", t);
    }
  }

  protected String getArg (String optionName, String[] args, int argIndex, String errorMessage) {
    if (argIndex >= args.length) {
      throw newException(optionName, errorMessage);
    }
    return args[argIndex];
  }
 
  protected Exception newException (String optionName, String errorMessage) {
    return new Exception("Invalid option '" + optionName + "': " + errorMessage);
  }

  public static class Exception extends java.lang.RuntimeException {
    public Exception (String message) {
      super(message);
    }
    public Exception (String message, Throwable nested) {
      super(message,nested);
    }
  }
}
 
import java.io.File;

public class Test {

  public static void main (String[] args) throws Exception {

    final DummyFtpCopyUtility ftpCopy = new DummyFtpCopyUtility();

    CommandLineProcessor clp = new CommandLineProcessor();
    clp.execute(args, ftpCopy);

    ftpCopy.copy();
  }

  public static class DummyFtpCopyUtility {

    protected boolean appendMode;
    protected String  host;
    protected File    sourceFile;

    public void setOptionAppend() {
      appendMode = true;
    }

    public void setOptionHost (String value) {
      host = value;
    }

    public void setFile (int fileNo, File value) {
      if (fileNo > 1) {
        throw new CommandLineProcessor.Exception("Too many files specified. Extra file: '" + value + "'");
      }
      sourceFile = value;
    }
   

    public void copy() {
      if (sourceFile == null || host == null) {
        System.out.println("Host and source file must be specified");
      } else {
        System.out.println("About to copy " + sourceFile + " to " + host);
        if (appendMode) {
          System.out.println("Append mode enabled");
        }
      }
    }
  }

}

Vladislav Zlobin

Comments

There are currently no comments for this snippet.

Voting