public boolean prepareDelegate( Object subject, CommandSession session, List<Object> params, CommandArguments args) throws Exception { args.subject = subject; // Introspect for (Class type = subject.getClass(); type != null; type = type.getSuperclass()) { for (Field field : type.getDeclaredFields()) { Option option = field.getAnnotation(Option.class); if (option != null) { args.options.put(option, field); } Argument argument = field.getAnnotation(Argument.class); if (argument != null) { if (Argument.DEFAULT.equals(argument.name())) { final Argument delegate = argument; final String name = field.getName(); argument = new Argument() { public String name() { return name; } public String description() { return delegate.description(); } public boolean required() { return delegate.required(); } public int index() { return delegate.index(); } public boolean multiValued() { return delegate.multiValued(); } public String valueToShowInHelp() { return delegate.valueToShowInHelp(); } public Class<? extends Annotation> annotationType() { return delegate.annotationType(); } }; } args.arguments.put(argument, field); int index = argument.index(); while (args.orderedArguments.size() <= index) { args.orderedArguments.add(null); } if (args.orderedArguments.get(index) != null) { throw new IllegalArgumentException("Duplicate argument index: " + index); } args.orderedArguments.set(index, argument); } } } // Check indexes are correct for (int i = 0; i < args.orderedArguments.size(); i++) { if (args.orderedArguments.get(i) == null) { throw new IllegalArgumentException("Missing argument for index: " + i); } } // Populate Map<Option, Object> optionValues = new TreeMap<Option, Object>(CommandArguments.OPTION_COMPARATOR); Map<Argument, Object> argumentValues = new HashMap<Argument, Object>(); boolean processOptions = true; int argIndex = 0; for (Iterator<Object> it = params.iterator(); it.hasNext(); ) { Object param = it.next(); // Check for help if (HELP.name().equals(param) || Arrays.asList(HELP.aliases()).contains(param)) { printUsageDelegate(session, subject, args.options, args.arguments, System.out); return false; } if (processOptions && param instanceof String && ((String) param).startsWith("-")) { boolean isKeyValuePair = ((String) param).indexOf('=') != -1; String name; Object value = null; if (isKeyValuePair) { name = ((String) param).substring(0, ((String) param).indexOf('=')); value = ((String) param).substring(((String) param).indexOf('=') + 1); } else { name = (String) param; } Option option = null; for (Option opt : args.options.keySet()) { if (name.equals(opt.name()) || Arrays.asList(opt.aliases()).contains(name)) { option = opt; break; } } if (option == null) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" undefined option ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(param) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .fg(Ansi.Color.DEFAULT) .toString(), "Undefined option: " + param); } Field field = args.options.get(option); if (value == null && (field.getType() == boolean.class || field.getType() == Boolean.class)) { value = Boolean.TRUE; } if (value == null && it.hasNext()) { value = it.next(); } if (value == null) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" missing value for option ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(param) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .fg(Ansi.Color.DEFAULT) .toString(), "Missing value for option: " + param); } if (option.multiValued()) { List<Object> l = (List<Object>) optionValues.get(option); if (l == null) { l = new ArrayList<Object>(); optionValues.put(option, l); } l.add(value); } else { optionValues.put(option, value); } } else { processOptions = false; if (argIndex >= args.orderedArguments.size()) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(": too many arguments specified") .fg(Ansi.Color.DEFAULT) .toString(), "Too many arguments specified"); } Argument argument = args.orderedArguments.get(argIndex); if (!argument.multiValued()) { argIndex++; } if (argument.multiValued()) { List<Object> l = (List<Object>) argumentValues.get(argument); if (l == null) { l = new ArrayList<Object>(); argumentValues.put(argument, l); } l.add(param); } else { argumentValues.put(argument, param); } } } // Check required arguments / options for (Option option : args.options.keySet()) { if (option.required() && optionValues.get(option) == null) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(": option ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(option.name()) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" is required") .fg(Ansi.Color.DEFAULT) .toString(), "Option " + option.name() + " is required"); } } for (Argument argument : args.arguments.keySet()) { if (argument.required() && argumentValues.get(argument) == null) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(": argument ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(argument.name()) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" is required") .fg(Ansi.Color.DEFAULT) .toString(), "Argument " + argument.name() + " is required"); } } // Convert and inject values for (Map.Entry<Option, Object> entry : optionValues.entrySet()) { Field field = args.options.get(entry.getKey()); Object value; try { value = convert(subject, entry.getValue(), field.getGenericType()); } catch (Exception e) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(": unable to convert option ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(entry.getKey().name()) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" with value '") .a(entry.getValue()) .a("' to type ") .a(new GenericType(field.getGenericType()).toString()) .fg(Ansi.Color.DEFAULT) .toString(), "Unable to convert option " + entry.getKey().name() + " with value '" + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(), e); } field.setAccessible(true); field.set(subject, value); } for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) { Field field = args.arguments.get(entry.getKey()); Object value; try { value = convert(subject, entry.getValue(), field.getGenericType()); } catch (Exception e) { throw new CommandException( Ansi.ansi() .fg(Ansi.Color.RED) .a("Error executing command ") .a(scope) .a(":") .a(Ansi.Attribute.INTENSITY_BOLD) .a(name) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(": unable to convert argument ") .a(Ansi.Attribute.INTENSITY_BOLD) .a(entry.getKey().name()) .a(Ansi.Attribute.INTENSITY_BOLD_OFF) .a(" with value '") .a(entry.getValue()) .a("' to type ") .a(new GenericType(field.getGenericType()).toString()) .fg(Ansi.Color.DEFAULT) .toString(), "Unable to convert argument " + entry.getKey().name() + " with value '" + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(), e); } field.setAccessible(true); field.set(subject, value); } return true; }