View Javadoc

    1   /*
    2    * Copyright 2002,2004 The Apache Software Foundation.
    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  package org.apache.commons.jelly.util;
    18
    19  import java.io.File;
    20  import java.io.FileWriter;
    21  import java.net.URL;
    22  import java.util.Arrays;
    23  import java.util.ArrayList;
    24  import java.util.List;
    25  import java.util.Properties;
    26
    27  import org.apache.commons.cli.CommandLine;
    28  import org.apache.commons.cli.Options;
    29  import org.apache.commons.cli.ParseException;
    30  import org.apache.commons.cli.Parser;
    31  import org.apache.commons.cli.HelpFormatter;
    32  import org.apache.commons.jelly.Jelly;
    33  import org.apache.commons.jelly.JellyContext;
    34  import org.apache.commons.jelly.JellyException;
    35  import org.apache.commons.jelly.Script;
    36  import org.apache.commons.jelly.XMLOutput;
    37
    38  /***
    39   * Utility class to parse command line options using CLI.
    40   * Using a separate class allows us to run Jelly without
    41   * CLI in the classpath when the command line interface
    42   * is not in use.
    43   *
    44   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    45   * @author Morgan Delagrange
    46   * @version $Revision: 155420 $
    47   */
    48  public class CommandLineParser {
    49
    50      protected static CommandLineParser _instance = new CommandLineParser();
    51
    52      private Options cmdLineOptions = null;
    53
    54      public static CommandLineParser getInstance() {
    55          return _instance;
    56      }
    57
    58      /***
    59       * Parse out the command line options and configure
    60       * the give Jelly instance.
    61       *
    62       * @param args   options from the command line
    63       * @exception JellyException
    64       *                   if the command line could not be parsed
    65       */
    66      public void invokeCommandLineJelly(String[] args) throws JellyException {
    67          CommandLine cmdLine = null;
    68          try {
    69              cmdLine = parseCommandLineOptions(args);
    70          } catch (ParseException e) {
    71              throw new JellyException(e);
    72          }
    73
    74          // check for -h or -v
    75          if (cmdLine.hasOption("h")) {
    76              new HelpFormatter().printHelp("jelly [scriptFile] [-script scriptFile] [-o outputFile] [-Dsysprop=syspropval] [-awt]",
    77                  cmdLineOptions);
    78              System.exit(1);
    79          }
    80          if (cmdLine.hasOption("v")) {
    81              System.err.println("Jelly " + Jelly.getJellyVersion());
    82              System.err.println(" compiled: " + Jelly.getJellyBuildDate());
    83              System.err.println("");
    84              System.exit(1);
    85          }
    86
    87          // get the -script option. If there isn't one then use args[0]
    88          String scriptFile = null;
    89          if (cmdLine.hasOption("script")) {
    90              scriptFile = cmdLine.getOptionValue("script");
    91          } else {
    92              scriptFile = args[0];
    93          }
    94
    95          // check the -awt option.
    96          boolean runInSwingThread = cmdLine.hasOption("awt") || cmdLine.hasOption("swing");
    97
    98          //
    99          // Use classloader to find file
    100         //
    101         URL url = ClassLoaderUtils.getClassLoader(getClass()).getResource(scriptFile);
    102         // check if the script file exists
    103         if (url == null && !(new File(scriptFile)).exists()) {
    104             throw new JellyException("Script file " + scriptFile + " not found");
    105         }
    106
    107         try {
    108             // extract the -o option for the output file to use
    109             final XMLOutput output = cmdLine.hasOption("o") ?
    110                     XMLOutput.createXMLOutput(new FileWriter(cmdLine.getOptionValue("o"))) :
    111                     XMLOutput.createXMLOutput(System.out);
    112
    113             Jelly jelly = new Jelly();
    114             jelly.setScript(scriptFile);
    115
    116             final Script script = jelly.compileScript();
    117
    118             // add the system properties and the command line arguments
    119             final JellyContext context = jelly.getJellyContext();
    120             context.setVariable("args", args);
    121             context.setVariable("commandLine", cmdLine);
    122             if (runInSwingThread) {
    123                 javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() {
    124                     try {
    125                         script.run(context, output);
    126                     } catch (Exception ex) {
    127                         ex.printStackTrace();
    128                     }
    129             } } ); } else {
    130                 script.run(context, output);
    131             }
    132
    133             // now lets wait for all threads to close
    134             Runtime.getRuntime().addShutdownHook(new Thread() {
    135                     public void run() {
    136                         try {
    137                             output.close();
    138                         }
    139                         catch (Exception e) {
    140                             // ignore errors
    141                         }
    142                     }
    143                 }
    144             );
    145
    146         } catch (Exception e) {
    147             throw new JellyException(e);
    148         }
    149
    150     }
    151
    152     /***
    153      * Parse the command line using CLI. -o and -script are reserved for Jelly.
    154      * -Dsysprop=sysval is support on the command line as well.
    155      */
    156     public CommandLine parseCommandLineOptions(String[] args) throws ParseException {
    157         // create the expected options
    158         cmdLineOptions = new Options();
    159         cmdLineOptions.addOption("o", true, "Output file");
    160         cmdLineOptions.addOption("script", true, "Jelly script to run");
    161         cmdLineOptions.addOption("h","help", false, "Give this help message");
    162         cmdLineOptions.addOption("v","version", false, "prints Jelly's version and exits");
    163         cmdLineOptions.addOption("script", true, "Jelly script to run");
    164         cmdLineOptions.addOption("awt", false, "Wether to run in the AWT thread.");
    165         cmdLineOptions.addOption("swing", false, "Synonym of \"-awt\".");
    166         List builtinOptionNames = Arrays.asList(new String[]{
    167             "-o","-script","-h","--help","-v","--version","-awt","-swing"});
    168
    169         // -D options will be added to the system properties
    170         Properties sysProps = System.getProperties();
    171
    172         // filter the system property setting from the arg list
    173         // before passing it to the CLI parser
    174         ArrayList filteredArgList = new ArrayList();
    175
    176         for (int i=0;i<args.length;i++) {
    177             String arg = args[i];
    178
    179             // if this is a -D property parse it and add it to the system properties.
    180             // -D args will not be copied into the filteredArgList.
    181             if (arg.startsWith("-D") && (arg.length() > 2)) {
    182                 arg = arg.substring(2);
    183                 int ePos = arg.indexOf("=");
    184                 if(ePos==-1 || ePos==0 || ePos==arg.length()-1)
    185                     System.err.println("Invalid system property: \"" + arg + "\".");
    186                 sysProps.setProperty(arg.substring(0,ePos), arg.substring(ePos+1));
    187             } else {
    188                 // add this to the filtered list of arguments
    189                 filteredArgList.add(arg);
    190
    191                 // add additional "-?" options to the options object. if this is not done
    192                 // the only options allowed would be the builtin-ones.
    193                 if (arg.startsWith("-") && arg.length() > 1) {
    194                     if (!(builtinOptionNames.contains(arg))) {
    195                         cmdLineOptions.addOption(arg.substring(1, arg.length()), true, "dynamic option");
    196                     }
    197                 }
    198             }
    199         }
    200
    201         // make the filteredArgList into an array
    202         String[] filterArgs = new String[filteredArgList.size()];
    203         filteredArgList.toArray(filterArgs);
    204
    205         // parse the command line
    206         Parser parser = new org.apache.commons.cli.GnuParser();
    207         return parser.parse(cmdLineOptions, filterArgs);
    208     }
    209
    210 }