EMMA Coverage Report (generated Fri Jun 19 09:16:10 CEST 2009)
[all classes][org.ktc.rbutils.rb]

COVERAGE SUMMARY FOR SOURCE FILE [AbstractUtility.java]

nameclass, %method, %block, %line, %
AbstractUtility.java100% (1/1)93%  (14/15)97%  (352/363)96%  (86/90)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbstractUtility100% (1/1)93%  (14/15)97%  (352/363)96%  (86/90)
usage (): void 0%   (0/1)0%   (0/7)0%   (0/2)
parse (Exception, PrintWriter): void 100% (1/1)88%  (29/33)78%  (7/9)
<static initializer> 100% (1/1)100% (54/54)100% (12/12)
AbstractUtility (): void 100% (1/1)100% (3/3)100% (1/1)
clone (Options): Options 100% (1/1)100% (26/26)100% (7/7)
createLogger (String, String): Logger 100% (1/1)100% (15/15)100% (4/4)
getCommonOptions (): Options 100% (1/1)100% (3/3)100% (1/1)
getExtension (): String 100% (1/1)100% (6/6)100% (1/1)
getFilesToBeProcessed (): List 100% (1/1)100% (41/41)100% (9/9)
getLoggers (): Collection 100% (1/1)100% (60/60)100% (16/16)
getRootDir (): File 100% (1/1)100% (10/10)100% (3/3)
getUniqueDir (String, String): File 100% (1/1)100% (15/15)100% (4/4)
getUniqueOptionValue (String, String, boolean): String 100% (1/1)100% (40/40)100% (10/10)
parseParameters (): void 100% (1/1)100% (14/14)100% (3/3)
usage (PrintWriter): void 100% (1/1)100% (36/36)100% (8/8)

1/*
2 * Copyright  2005-2006 The RbUtils Project
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 *
16 */
17 
18// $Id: AbstractUtility.java,v 1.2 2006/11/18 13:33:38 moishi Exp $
19 
20package org.ktc.rbutils.rb;
21 
22import java.io.File;
23import java.io.FileNotFoundException;
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.Iterator;
29import java.util.LinkedList;
30import java.util.List;
31 
32import org.apache.commons.cli.CommandLine;
33import org.apache.commons.cli.CommandLineParser;
34import org.apache.commons.cli.HelpFormatter;
35import org.apache.commons.cli.MissingArgumentException;
36import org.apache.commons.cli.MissingOptionException;
37import org.apache.commons.cli.Option;
38import org.apache.commons.cli.Options;
39import org.apache.commons.cli.ParseException;
40import org.apache.commons.cli.PosixParser;
41import org.apache.commons.lang.StringUtils;
42import org.ktc.rbutils.api.RbUtilsException;
43import org.ktc.rbutils.api.UnSpecifiedFileException;
44import org.ktc.rbutils.api.audit.Logger;
45import org.ktc.rbutils.api.file.ValidateFile;
46 
47/**
48 * Provides common functionnalities to the command line utilities.
49 * @since RbUtils 0.9.3.3
50 * @version $Revision: 1.2 $
51 * @author moishi
52 */
53public abstract class AbstractUtility implements Utility {
54    /** The options to the command line. */
55    private static final Options COMMON_OPTS = new Options();
56 
57    /** The e option (for properties files extension). */
58    protected static final String OPTION_EXTENSION = "e";
59    /** Error mesage when more than one extension is specified. */
60    protected static final String ERROR_MSG_EXTENSION_NBR = "Must specify at most one extension";
61 
62    /** The f option (for files to be processed). */
63    protected static final String OPTION_FILE = "f";
64 
65    /** The l option (for loggers to be registered). */
66    protected static final String OPTION_LOG = "l";
67    /** Separator used to separate logger type and logging file. */
68    public static final char SEP_LOG_OPTION = ';';
69 
70    /** The r option (for root directory). */
71    protected static final String OPTION_ROOT = "r";
72 
73    /** Error mesage when more than one root directory is specified. */
74    protected static final String ERROR_MSG_ROOT_NBR = "Must specify one "
75        + "and only one root directory";
76 
77    /**
78     * Displayed message for user (to be used by subclasses when error occurs on parameter parsing).
79     */
80    protected static final String MSG_MISSING_REQUIRED_OPTION = "Missing option: ";
81 
82    /**
83     * Name of the RbUtils task of this utility. Subclasses <b>MUST</b> set this field in their
84     * constructor.
85     */
86    protected String taskName;
87    /**
88     * Options of this utility. Subclasses <b>MUST</b> set this field in their constructor.
89     */
90    protected Options options;
91 
92    /**
93     * Internal arguments to be passed to the utility. Subclasses <b>MUST</b> set this field in
94     * their constructor.
95     */
96    protected String[] internalArgs;
97 
98    /** The root directory to be used by this utility. */
99    protected File root;
100 
101    /** Command line of this utility. */
102    protected CommandLine cmdLine;
103 
104    /** Header for required field used when the usage of the utility is displayed. */
105    protected static final String REQUIRED_HEADER = "[required] ";
106    static {
107        final Option rootOption = new Option(OPTION_ROOT, "root", true, REQUIRED_HEADER
108            + "the directory to be traversed for properties source files.");
109        rootOption.setRequired(true);
110        // TODO to be used when the Option clone method will work for this field
111        // rootOption.setArgName("root");
112        COMMON_OPTS.addOption(rootOption);
113 
114        COMMON_OPTS.addOption(OPTION_EXTENSION, "extension", true,
115                              "the extension of the properties source files."
116                                  + " Don't include the dot in the extension."
117                                  + " Defaults to properties.");
118 
119        final String logMsg = "the type of logging: (plain|xml|quiet)."
120            + " Defaults to plain (outputs are displayed in the standard output)."
121            + " To specify a logging file, put a ';' after the type of logging and specified "
122            + "the full path to the logging file. This is required for xml logging.";
123        final Option logOption = new Option(OPTION_LOG, "log", true, logMsg);
124        logOption.setArgs(2);
125        logOption.setValueSeparator(SEP_LOG_OPTION);
126        COMMON_OPTS.addOption(logOption);
127 
128        COMMON_OPTS.addOption(OPTION_FILE, "file", true,
129                              "the relative path from root to a properties file to be processed.");
130    }
131 
132    /**
133     * {@inheritDoc}
134     */
135    public void parseParameters() throws ParseException {
136        final CommandLineParser clp = new PosixParser();
137        cmdLine = clp.parse(options, internalArgs, true);
138    }
139 
140    /**
141     * {@inheritDoc}
142     */
143    public File getRootDir() throws RbUtilsException, FileNotFoundException {
144        final File uniqueDir = getUniqueDir(OPTION_ROOT, ERROR_MSG_ROOT_NBR);
145 
146        root = uniqueDir;
147        return uniqueDir;
148    }
149 
150    /**
151     * Parses the command line options in order to get a directory which must have been specified
152     * only once.
153     * @param optionName the name of the option to be parsed.
154     * @param errorMsg the error message to be used if a RbUtilsException is thrown.
155     * @return the directory.
156     * @throws RbUtilsException if the option is specified more than once.
157     * @throws FileNotFoundException if the directory does not exist in the file system.
158     * @throws org.ktc.rbutils.api.file.NotDirectoryException if the -r value specifies a file in
159     *             the file system instead of a directory.
160     */
161    protected File getUniqueDir(final String optionName, final String errorMsg)
162        throws RbUtilsException, FileNotFoundException
163    {
164        final String rootValue = getUniqueOptionValue(optionName, errorMsg, true);
165        final File internalRoot = new File(rootValue);
166 
167        ValidateFile.isDirectory(internalRoot);
168 
169        return internalRoot;
170    }
171 
172    /**
173     * Parses the command line options in order to get an option value which must have been
174     * specified at most once.
175     * @param optionName the name of the option to be parsed.
176     * @param errorMsg the error message to be used if a RbUtilsException is thrown.
177     * @param isRequired <code>true</code> if the optionName must have been specified.
178     * @return the option value. <code>null</code> if no specified option.
179     * @throws RbUtilsException if the option is specified more than once.
180     */
181    protected String getUniqueOptionValue(final String optionName, final String errorMsg,
182                                          final boolean isRequired) throws RbUtilsException
183    {
184        String value = null;
185        if (!cmdLine.hasOption(optionName)) {
186            if (isRequired) {
187                throw new RbUtilsException(errorMsg);
188            }
189            // if it is not required, we only exit from this method with a null value
190        }
191        else {
192            final String[] optionValues = cmdLine.getOptionValues(optionName);
193            final int optionNbr = optionValues.length;
194            // we only accept one value for the optionName option
195            // TODO this must be done by the parser (set option property)
196            if (optionNbr > 1 || (isRequired && optionNbr == 0)) {
197                throw new RbUtilsException(errorMsg);
198            }
199            value = optionValues[0];
200        }
201        return value;
202    }
203 
204    /**
205     * {@inheritDoc}
206     */
207    public List getFilesToBeProcessed() throws FileNotFoundException {
208        final List files = new LinkedList();
209        if (cmdLine.hasOption(OPTION_FILE)) {
210            final String[] fileValues = cmdLine.getOptionValues(OPTION_FILE);
211            for (int i = 0; i < fileValues.length; i++) {
212                final String relPath = fileValues[i];
213                final File file = new File(root, relPath);
214 
215                ValidateFile.isFile(file);
216                files.add(file);
217            }
218        }
219 
220        return files;
221    }
222 
223    /**
224     * {@inheritDoc}
225     */
226    public String getExtension() throws RbUtilsException {
227        return getUniqueOptionValue(OPTION_EXTENSION, ERROR_MSG_EXTENSION_NBR, false);
228    }
229 
230    /**
231     * {@inheritDoc}
232     */
233    public Collection getLoggers() throws UnSpecifiedFileException, IOException {
234        // TODO improve parsing in order to avoid 2nd arg processing
235        // look in the cli doc or developp another parser
236        final Collection loggers = new ArrayList();
237 
238        if (cmdLine.hasOption(OPTION_LOG)) {
239            // System.out.println("getLoggers");
240            final String[] loggerValues = cmdLine.getOptionValues(OPTION_LOG);
241            final int logNbr = loggerValues.length;
242 
243            // First we check if we have a logger type value
244            // Then, we check if the following value is not a logging type
245            // if not, we take this value which should be a path to a file
246            // Finally, we create a logger with the type and the option file
247            String logType = null;
248            for (int i = 0; i < logNbr; i++) {
249                final String value = loggerValues[i];
250 
251                if (LoggerType.isLoggerTypeValue(value)) {
252                    logType = value;
253                    // System.out.println("\t\t-->found logger type: " + logType);
254                }
255                else {
256                    final String loggingFile = value;
257                    // System.out.println("\t\tfile found: " + loggingFile);
258 
259                    if (logType != null) {
260                        loggers.add(createLogger(logType, loggingFile));
261                        logType = null;
262                    }
263                    else {
264                        // System.out.println("\t\t***skip value");
265                    }
266                }
267            }
268 
269            // The for remaining not registered logger
270            if (logType != null) {
271                // System.out.println("\t\t***Add logger found before exiting method");
272                loggers.add(createLogger(logType, null));
273            }
274 
275        }
276 
277        return loggers;
278    }
279 
280    /**
281     * Creates a Logger.
282     * @param logType the type of the logger to be created.
283     * @param loggingFile the logging file to be used by the Logger. May be <code>null</code>
284     * @return the created Logger.
285     * @throws UnSpecifiedFileException if the Logger to be created requires a logging file and
286     *             loggingFile is <code>null</code>
287     * @throws IOException if an error occurs on file logger initialization.
288     */
289    private Logger createLogger(final String logType, final String loggingFile)
290        throws UnSpecifiedFileException, IOException
291    {
292        // System.out.println("\t\tCreate logger");
293        final LoggerCreator logCreator = new LoggerCreator();
294        logCreator.setOutputFile(loggingFile);
295        logCreator.setLoggerType(logType);
296        return logCreator.createLogger(taskName);
297    }
298 
299    /**
300     * Returns a copy of the common options shared by all RbUtils command line utilities.
301     * @return the common options.
302     */
303    protected static Options getCommonOptions() {
304        return clone(COMMON_OPTS);
305    }
306 
307    /**
308     * Clone an Options instance.
309     * @param options the instance to be cloned.
310     * @return the clone.
311     */
312    protected static Options clone(final Options options) {
313        // Options is not Cloneable so we need to internally clone the instance
314        // TODO is there a problem here because we do not clone optionsGroup
315        final Options internalOptions = new Options();
316 
317        final Collection listOpt = options.getOptions();
318        for (final Iterator iter = listOpt.iterator(); iter.hasNext();) {
319            final Option opt = (Option) iter.next();
320            // TODO Option do not clone all field (argName for instance)
321            internalOptions.addOption((Option) opt.clone());
322        }
323 
324        return internalOptions;
325    }
326 
327    /**
328     * {@inheritDoc}
329     */
330    public final void usage() {
331        usage(new PrintWriter(System.out));
332    }
333 
334    /**
335     * {@inheritDoc}
336     */
337    public final void usage(final PrintWriter pw) {
338        // TODO to be improved
339        // We should maybe extend the CLI library or better understand how it works...
340        final HelpFormatter hf = new HelpFormatter();
341//        final PrintWriter pw = new PrintWriter(pw);
342        final String cmdLineSyntax = "java " + this.getClass().getName();
343        final boolean autoUsage = false;
344        final String header = null;
345        final String footer = null;
346 
347        // hf.defaultSyntaxPrefix = "Parsed command line: ";
348        // final String header = hf.defaultNewLine + "Help";
349 
350        // ***
351        // Act like printhelp with no usage
352        // ***
353        // printOptions(PrintWriter pw, int width, Options options, int leftPad, int descPad)
354        // hf.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, options, HelpFormatter.DEFAULT_LEFT_PAD,
355        // HelpFormatter.DEFAULT_DESC_PAD);
356 
357        hf.printHelp(pw, HelpFormatter.DEFAULT_WIDTH, cmdLineSyntax, header, options,
358                     HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, footer,
359                     autoUsage);
360 
361        // hf.printUsage(pw, hf.defaultWidth, cmdLineSyntax, options);
362        pw.flush();
363    }
364 
365 
366    /**
367     * {@inheritDoc}
368     */
369    public final void parse(final Exception exception, final PrintWriter pw) {
370        final String msgHeader;
371        if (exception instanceof MissingOptionException) {
372            msgHeader = MSG_MISSING_REQUIRED_OPTION;
373        }
374        else if (exception instanceof MissingArgumentException) {
375            msgHeader = StringUtils.EMPTY;
376        }
377        else {
378            exception.printStackTrace();
379            msgHeader = "unknown error: ";
380        }
381        pw.println("Initialization error - " + msgHeader + exception.getMessage());
382        usage(pw);
383    }
384}

[all classes][org.ktc.rbutils.rb]
EMMA 2.0.5312 (C) Vladimir Roubtsov