Reflection-based command line processor
7
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)
(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.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");
}
}
}
}
}
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");
}
}
}
}
}





There are currently no comments for this snippet.