// Copyright 2013 Michel Kraemer // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.undercouch.citeproc.tool; import java.beans.IntrospectionException; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import de.undercouch.underline.Command; import de.undercouch.underline.InputReader; import de.undercouch.underline.OptionDesc; import de.undercouch.underline.OptionGroup; import de.undercouch.underline.OptionIntrospector; import de.undercouch.underline.OptionIntrospector.ID; import de.undercouch.underline.OptionParser; import de.undercouch.underline.OptionParserException; /** * A base class for commands from the {@link de.undercouch.citeproc.CSLTool} * @author Michel Kraemer */ public abstract class AbstractCSLToolCommand implements CSLToolCommand { private OptionGroup<ID> options; private boolean displayHelp; /** * @return the command's options */ private OptionGroup<ID> getOptions() { return options; } /** * Specifies if the command's help should be displayed * @param display true if the help should be displayed */ @OptionDesc(longName = "help", shortName = "h", description = "display this help and exit", priority = 9000) public void setDisplayHelp(boolean display) { this.displayHelp = display; } /** * Outputs an error message * @param msg the message */ protected void error(String msg) { System.err.println(CSLToolContext.current().getToolName() + ": " + msg); } /** * @return the classes to inspect for CLI options */ protected Class<?>[] getClassesToIntrospect() { return new Class<?>[] { getClass() }; } /** * @return the commands the parsed CLI values should be injected into */ protected Command[] getObjectsToEvaluate() { return new Command[] { this }; } @Override public int run(String[] args, InputReader in, PrintWriter out) throws OptionParserException, IOException { if (options == null) { try { options = OptionIntrospector.introspect(getClassesToIntrospect()); } catch (IntrospectionException e) { throw new RuntimeException("Could not inspect command", e); } } boolean unknownArgs = OptionIntrospector.hasUnknownArguments( getClassesToIntrospect()); OptionParser.Result<ID> parsedOptions = OptionParser.parse(args, getOptions(), unknownArgs ? OptionIntrospector.DEFAULT_ID : null); try { OptionIntrospector.evaluate(parsedOptions.getValues(), (Object[])getObjectsToEvaluate()); } catch (IllegalAccessException e) { throw new RuntimeException("Could not evaluate options", e); } catch (InvocationTargetException e) { throw new RuntimeException("Could not evaluate options", e); } catch (InstantiationException e) { throw new RuntimeException("Could not evaluate options", e); } if (displayHelp) { usage(); return 0; } if (!checkArguments()) { return 1; } return doRun(parsedOptions.getRemainingArgs(), in, out); } /** * Prints out usage information */ protected void usage() { String footnotes = null; if (!getOptions().getCommands().isEmpty()) { footnotes = "Use `" + CSLToolContext.current().getToolName() + " help <command>' to read about a specific command."; } String name = CSLToolContext.current().getToolName(); String usageName = getUsageName(); if (usageName != null && !usageName.isEmpty()) { name += " " + usageName; } String unknownArguments = OptionIntrospector.getUnknownArgumentName( getClassesToIntrospect()); OptionParser.usage(name, getUsageDescription(), getOptions(), unknownArguments, footnotes, new PrintWriter(System.out, true)); } @Override public abstract String getUsageName(); @Override public abstract String getUsageDescription(); @Override public boolean checkArguments() { //nothing to check by default. subclasses may override return true; } @Override public abstract int doRun(String[] remainingArgs, InputReader in, PrintWriter out) throws OptionParserException, IOException; }