View Javadoc
1   package org.argeo.cli;
2   
3   import java.io.StringWriter;
4   import java.util.ArrayList;
5   import java.util.Arrays;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.TreeMap;
10  import java.util.function.Function;
11  
12  import org.apache.commons.cli.CommandLine;
13  import org.apache.commons.cli.CommandLineParser;
14  import org.apache.commons.cli.DefaultParser;
15  import org.apache.commons.cli.Options;
16  import org.apache.commons.cli.ParseException;
17  
18  /** Base class for a CLI managing sub commands. */
19  public abstract class CommandsCli implements DescribedCommand<Object> {
20  	public final static String HELP = "help";
21  
22  	private final String commandName;
23  	private Map<String, Function<List<String>, ?>> commands = new TreeMap<>();
24  
25  	protected final Options options = new Options();
26  
27  	public CommandsCli(String commandName) {
28  		this.commandName = commandName;
29  	}
30  
31  	@Override
32  	public Object apply(List<String> args) {
33  		String cmd = null;
34  		List<String> newArgs = new ArrayList<>();
35  		try {
36  			CommandLineParser clParser = new DefaultParser();
37  			CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true);
38  			List<String> leftOvers = commonCl.getArgList();
39  			for (String arg : leftOvers) {
40  				if (!arg.startsWith("-") && cmd == null) {
41  					cmd = arg;
42  				} else {
43  					newArgs.add(arg);
44  				}
45  			}
46  		} catch (ParseException e) {
47  			CommandArgsException cae = new CommandArgsException(e);
48  			throw cae;
49  		}
50  
51  		Function<List<String>, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand();
52  		if (function == null)
53  			throw new IllegalArgumentException("Uknown command " + cmd);
54  		try {
55  			return function.apply(newArgs).toString();
56  		} catch (CommandArgsException e) {
57  			if (e.getCommandName() == null) {
58  				e.setCommandName(cmd);
59  				e.setCommandsCli(this);
60  			}
61  			throw e;
62  		} catch (IllegalArgumentException e) {
63  			CommandArgsException cae = new CommandArgsException(e);
64  			cae.setCommandName(cmd);
65  			throw cae;
66  		}
67  	}
68  
69  	@Override
70  	public Options getOptions() {
71  		return options;
72  	}
73  
74  	protected void addCommand(String cmd, Function<List<String>, ?> function) {
75  		commands.put(cmd, function);
76  
77  	}
78  
79  	@Override
80  	public String getUsage() {
81  		return "[command]";
82  	}
83  
84  	protected void addCommandsCli(CommandsCli commandsCli) {
85  		addCommand(commandsCli.getCommandName(), commandsCli);
86  		commandsCli.addCommand(HELP, new HelpCommand(this, commandsCli));
87  	}
88  
89  	public String getCommandName() {
90  		return commandName;
91  	}
92  
93  	public Set<String> getSubCommands() {
94  		return commands.keySet();
95  	}
96  
97  	public Function<List<String>, ?> getCommand(String command) {
98  		return commands.get(command);
99  	}
100 
101 	public HelpCommand getHelpCommand() {
102 		return (HelpCommand) getCommand(HELP);
103 	}
104 
105 	public Function<List<String>, String> getDefaultCommand() {
106 		return getHelpCommand();
107 	}
108 
109 	/** In order to implement quickly a main method. */
110 	public static void mainImpl(CommandsCli cli, String[] args) {
111 		try {
112 			cli.addCommand(CommandsCli.HELP, new HelpCommand(null, cli));
113 			Object output = cli.apply(Arrays.asList(args));
114 			System.out.println(output);
115 			System.exit(0);
116 		} catch (CommandArgsException e) {
117 			System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage());
118 			if (e.getCommandName() != null) {
119 				StringWriter out = new StringWriter();
120 				HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out);
121 				System.err.println(out.toString());
122 			} else {
123 				e.printStackTrace();
124 			}
125 			System.exit(1);
126 		} catch (Exception e) {
127 			e.printStackTrace();
128 			System.exit(1);
129 		}
130 	}
131 }