import java.util.Map;
import java.util.HashMap;
import java.io.File;

public class CommandLineProcessor {

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

  protected Map m_optionExtractors = new HashMap();
  protected FileOption m_fileSetter = null;
  protected int m_fileIndex = 0;

  public void registerOption (String optionName, Option handler) {
    addExtractor(optionName, new OptionExtractor(handler));
  }

  public void registerOption (String optionName, StringOption handler) {
    addExtractor(optionName, new StringOptionExtractor(handler));
  }

  public void registerFiles (FileOption handler) {
    m_fileSetter = handler;
  }

  public void registerOption (String optionName, IntOption handler) {
    addExtractor(optionName, new IntOptionExtractor(handler));
  }

  public void execute (String[] args) {
    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(arg);
        } else {
          Extractor extractor = (Extractor) m_optionExtractors.get(optionName);
          if (extractor == null) {
            throw new Exception("Unexpected option '" + optionName + "'");
          }
          argIndex = extractor.execute(optionName, args, argIndex);
        }
      } else {
        setFile(arg);
      }
    }
  }

  protected void setFile (String value) {
    if (m_fileSetter == null) {
      throw new Exception("Unexpected file name: '" + value + "'");
    }
    m_fileSetter.execute(++m_fileIndex, new File(value));
  }

  protected void addExtractor (String optionName, Extractor extractor) {
    if (m_optionExtractors.containsKey(optionName)) {
      throw new Exception("Duplicated option name: '" + optionName + "'");
    }
    m_optionExtractors.put(optionName, extractor);
  }

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

  public interface Option {
    void execute (String option) throws Exception;
  }

  public interface StringOption {
    void execute (String option, String value) throws Exception;
  }

  public interface IntOption {
    void execute (String option, int value) throws Exception;
  }

  public interface FileOption {
    void execute (int fileNo, File value) throws Exception;
  }

  protected abstract class Extractor {

    public abstract int execute (String optionName, String[] args, int argIndex) throws Exception;
   
    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);
    }

  }

  protected class OptionExtractor extends Extractor {
    protected Option m_handler;
    public OptionExtractor (Option handler) {
     m_handler = handler;
    }
    public int execute (String optionName, String[] args, int argIndex) {
      m_handler.execute(optionName);
      return argIndex;
    }
  }

  protected class StringOptionExtractor extends Extractor {
    protected StringOption m_handler;
    public StringOptionExtractor (StringOption handler) {
      m_handler = handler;
    }
    public int execute (String optionName, String[] args, int argIndex) {
      m_handler.execute(optionName, getArg(optionName, args, argIndex, "string value expected"));
      return argIndex + 1;
    }
  }

  protected class IntOptionExtractor extends Extractor {
    protected IntOption m_handler;
    public IntOptionExtractor (IntOption handler) {
      m_handler = handler;
    }
    public int execute (String optionName, String[] args, int argIndex) {
      String textValue = getArg(optionName, args, argIndex, "integer value expected");
      int value;
      try {
        value = Integer.parseInt(textValue);
      } catch (Throwable t) {
        throw newException(optionName, "Invalid int argument");
      }
      m_handler.execute(optionName, value);
      return argIndex + 1;
    }
  }
}
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.registerOption("append", new CommandLineProcessor.Option() {
      public void execute (String option) {
        ftpCopy.appendMode = true;
      }
    });
    clp.registerOption("host", new CommandLineProcessor.StringOption() {
      public void execute (String option, String value) {
        ftpCopy.host = value;
      }
    });
    clp.registerOption("maxSize", new CommandLineProcessor.IntOption() {
      public void execute (String option, int value) {
        ftpCopy.maxFileSize = value;
      }
    });
    clp.registerFiles(new CommandLineProcessor.FileOption() {
      public void execute (int fileNo, File value) {
        if (fileNo > 1) {
          throw new CommandLineProcessor.Exception("Too many files specified. Extra file: '" + value + "'");
        }
        ftpCopy.sourceFile = value;
      }
    });
    clp.execute(args);

    ftpCopy.copy();
  }

  public static class DummyFtpCopyUtility {
    protected boolean appendMode;
    protected String  host;
    protected int     maxFileSize = 0;
    protected File    sourceFile;

    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");
        }
        if (maxFileSize > 0) {
          System.out.println("Max file size: " + maxFileSize);
        }
      }
    }
  }

}
java -cp . Test --host localhost Foobar.txt
java -cp . Test --host localhost Foobar.txt --append
java -cp . Test --host localhost Foobar.txt --append --maxSize 1024
java -cp . Test --host localhost --append --maxSize 1024 -- --Foo--