001 /**
002 * Copyright (c) 2010, SIB. All rights reserved.
003 *
004 * SIB (Swiss Institute of Bioinformatics) - http://www.isb-sib.ch Host -
005 * https://sourceforge.net/projects/javaprotlib/
006 *
007 * Redistribution and use in source and binary forms, with or without
008 * modification, are permitted provided that the following conditions are met:
009 * Redistributions of source code must retain the above copyright notice, this
010 * list of conditions and the following disclaimer. Redistributions in binary
011 * form must reproduce the above copyright notice, this list of conditions and
012 * the following disclaimer in the documentation and/or other materials provided
013 * with the distribution. Neither the name of the SIB/GENEBIO nor the names of
014 * its contributors may be used to endorse or promote products derived from this
015 * software without specific prior written permission.
016 *
017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020 * ARE DISCLAIMED. IN NO EVENT SHALL SIB/GENEBIO BE LIABLE FOR ANY DIRECT,
021 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
024 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 */
028 package org.expasy.jpl.commons.app;
029
030
031 import java.io.File;
032 import java.io.FileInputStream;
033 import java.io.IOException;
034 import java.util.Iterator;
035 import java.util.List;
036 import java.util.Properties;
037 import org.apache.commons.cli.CommandLine;
038 import org.apache.commons.cli.CommandLineParser;
039 import org.apache.commons.cli.HelpFormatter;
040 import org.apache.commons.cli.Option;
041 import org.apache.commons.cli.Options;
042 import org.apache.commons.cli.ParseException;
043 import org.apache.commons.cli.PosixParser;
044
045
046 /**
047 * A basic command line parameter handler.
048 *
049 * @author nikitin
050 *
051 * @version 1.0
052 */
053 public abstract class AbstractApplicationParameters {
054
055 /********************* the parameters **************************/
056 protected Properties settings;
057
058 /** the file with all settings */
059 private File configFile;
060
061 /** display settings */
062 private boolean isVerbose;
063
064 /** version */
065 private String version;
066
067 /** author, copyright... */
068 private String header;
069
070 /** usage */
071 protected final HelpFormatter usage = new HelpFormatter();
072
073 /** the command line */
074 private String commandLine;
075
076 private final Class<?> app;
077
078 public AbstractApplicationParameters(final Class<?> app,
079 final String version, String mandatoryParams, final String[] params) {
080
081 this.app = app;
082 this.version = version;
083
084 // the command line
085 this.commandLine = app.getSimpleName() + " " + mandatoryParams;
086
087 // make initialisations
088 init();
089
090 // set the default application settings
091 settings = createBaseSettings();
092 addSettings(settings);
093
094 // define base options like -h, -i, -q and -v
095 Options basicOptions = createBaseOptions();
096
097 // application specific options
098 Options appOptions = createAppOptions();
099
100 // merge basic and app options
101 Options options = mergeOptions(basicOptions, appOptions);
102
103 // update settings given the command line
104 try {
105 parseCommandLine(params, options);
106 } catch (ParseException e) {
107 System.err.println(e.getMessage());
108 usage.printHelp(commandLine, options, true);
109 System.exit(1);
110 }
111 }
112
113 @SuppressWarnings("unchecked")
114 private Options mergeOptions(Options baseOptions, Options appOptions) {
115
116 Options options = new Options();
117
118 Iterator iter1 = baseOptions.getOptions().iterator();
119 while (iter1.hasNext()) {
120 options.addOption((Option) iter1.next());
121 }
122
123 if (appOptions != null) {
124 Iterator iter2 = appOptions.getOptions().iterator();
125 while (iter2.hasNext()) {
126 Option o = (Option) iter2.next();
127 String name = o.getOpt();
128 String lname = o.getLongOpt();
129
130 if (name != null && options.hasOption(name)) {
131 System.err.println("Base option '-" + name
132 + "' already exists in application, please choose "
133 + "another short name option.");
134 System.exit(2);
135 }
136
137 if (lname != null && options.hasOption(lname)) {
138 System.err.println("Base option '--" + name
139 + "' already exists in application, please choose "
140 + "another long name option.");
141 System.exit(2);
142 }
143
144 options.addOption(o);
145 }
146 }
147 return options;
148 }
149
150 private Options createBaseOptions() {
151 Options options = new Options();
152
153 options.addOption("h", "help", false, "print this message.");
154
155 options.addOption("v", "version", false, "print the version info.");
156
157 options.addOption("q", "quiet", false, "quiet mode (verbose off)\n"
158 + "by default: false.");
159
160 options.addOption("i", "setting-file", true,
161 "give a property file with all input settings.");
162
163 return options;
164 }
165
166 public Properties createBaseSettings() {
167 Properties settings = new Properties();
168
169 settings.setProperty("quiet", "false");
170
171 return settings;
172 }
173
174 /**
175 * Parse command line and update the settings.
176 *
177 * @param args the command line app arguments.
178 * @param settings the stored/active app params.
179 * @param options the app options.
180 */
181 @SuppressWarnings("unchecked")
182 private void parseCommandLine(String[] args, Options options)
183 throws ParseException {
184
185 // create the command line parser
186 CommandLineParser parser = null;
187
188 parser = new PosixParser();
189
190 // try {
191 // parse the command line arguments
192 final CommandLine line = parser.parse(options, args);
193
194 /** help */
195 if (line.hasOption("h")) {
196 usage.printHelp(commandLine, options, true);
197 System.exit(0);
198 }
199
200 /** version */
201 if (line.hasOption("v")) {
202 System.out.println(app.getSimpleName() + " v." + version);
203 System.exit(0);
204 }
205
206 /** setting property file */
207 if (line.hasOption("i")) {
208 final String filename = line.getOptionValue("i");
209 configFile = new File(filename);
210
211 if (configFile.exists()) {
212 try {
213 // load a properties file
214 settings.load(new FileInputStream(configFile));
215 } catch (final IOException e) {
216 throw new ParseException(e.getMessage()
217 + ": cannot load properties from " + filename);
218 }
219
220 } else {
221 throw new ParseException(filename
222 + ": no such settings file name");
223 }
224 }
225
226 /** verbose mode ? */
227 if (line.hasOption("quiet")) {
228 settings.setProperty("quiet", "true");
229 }
230
231 // parse the specific app options
232 parseSpecificOptions(options, settings, line);
233
234 // convert non string values to correct types
235 setPropertyValues();
236
237 parseArguments(line.getArgList());
238 }
239
240 /**
241 * This method handles all setting/conversions of parameter values to the
242 * correct type.
243 *
244 * <ol>
245 * <li>all subclassses will have to override this method</li>
246 * <li>do not forget to call super.convertPropertyValues() to correctly
247 * convert the base params</li>
248 * </ol>
249 *
250 * @throws ParseException if convertion failed.
251 */
252 protected void setPropertyValues() throws ParseException {
253 /** verbosity */
254 try {
255 isVerbose = !Boolean.parseBoolean(settings.getProperty("quiet"));
256 } catch (NumberFormatException e) {
257 new ParseException(e.getMessage());
258 }
259 }
260
261 public String getParamInfos() {
262 StringBuilder sb = new StringBuilder();
263
264 if (header != null) {
265 sb.append(header + "\n");
266 }
267
268 if (configFile != null) {
269 sb.append("[Settings extracted from file " + configFile.getName()
270 + "]\n\n");
271 }
272
273 sb.append(getSpecificParamInfos());
274
275 return sb.toString();
276 }
277
278 public abstract void init();
279
280 public abstract void addSettings(Properties settings);
281
282 public abstract String getSpecificParamInfos();
283
284 // TODO: force implementation
285 // public abstract void setHeader(String header);
286
287 /** add the app specific options */
288 public abstract Options createAppOptions();
289
290 public abstract void parseSpecificOptions(Options options,
291 Properties settings, CommandLine line) throws ParseException;
292
293 public abstract void parseArguments(List<String> argList)
294 throws org.apache.commons.cli.ParseException;
295
296 public final String getCommandLine() {
297 return commandLine;
298 }
299
300 /**
301 * @return the version
302 */
303 public final String getVersion() {
304 return version;
305 }
306
307 public final void setHeader(String header) {
308 this.header = header;
309 }
310
311 /**
312 * @return the configFile
313 */
314 public final File getConfigFile() {
315 return configFile;
316 }
317
318 /**
319 * @return the true if verbose
320 */
321 public final boolean isVerbose() {
322 return isVerbose;
323 }
324 }