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.ArrayList;
23  import java.util.Properties;
24  import java.util.StringTokenizer;
25  
26  import org.apache.commons.cli.CommandLine;
27  import org.apache.commons.cli.GnuParser;
28  import org.apache.commons.cli.Options;
29  import org.apache.commons.cli.Parser;
30  import org.apache.commons.cli.ParseException;
31  
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: 1.7 $
47   */
48  public class CommandLineParser {
49  
50      protected static CommandLineParser _instance = new CommandLineParser();
51  
52      public static CommandLineParser getInstance() {
53          return _instance;
54      }
55  
56      /***
57       * Parse out the command line options and configure
58       * the give Jelly instance.
59       *
60       * @param args   options from the command line
61       * @exception JellyException
62       *                   if the command line could not be parsed
63       */
64      public void invokeCommandLineJelly(String[] args) throws JellyException {
65          CommandLine cmdLine = null;
66          try {
67              cmdLine = parseCommandLineOptions(args);
68          } catch (ParseException e) {
69              throw new JellyException(e);
70          }
71  
72          // get the -script option. If there isn't one then use args[0]
73          String scriptFile = null;
74          if (cmdLine.hasOption("script")) {
75              scriptFile = cmdLine.getOptionValue("script");
76          } else {
77              scriptFile = args[0];
78          }
79  
80          //
81          // Use classloader to find file
82          //
83          URL url = ClassLoaderUtils.getClassLoader(getClass()).getResource(scriptFile);
84          // check if the script file exists
85          if (url == null && !(new File(scriptFile)).exists()) {
86              throw new JellyException("Script file " + scriptFile + " not found");
87          }
88  
89          try {
90              // extract the -o option for the output file to use
91              final XMLOutput output = cmdLine.hasOption("o") ?
92                      XMLOutput.createXMLOutput(new FileWriter(cmdLine.getOptionValue("o"))) :
93                      XMLOutput.createXMLOutput(System.out);
94  
95              Jelly jelly = new Jelly();
96              jelly.setScript(scriptFile);
97  
98              Script script = jelly.compileScript();
99  
100             // add the system properties and the command line arguments
101             JellyContext context = jelly.getJellyContext();
102             context.setVariable("args", args);
103             context.setVariable("commandLine", cmdLine);
104             script.run(context, output);
105 
106             // now lets wait for all threads to close
107             Runtime.getRuntime().addShutdownHook(new Thread() {
108                     public void run() {
109                         try {
110                             output.close();
111                         }
112                         catch (Exception e) {
113                             // ignore errors
114                         }
115                     }
116                 }
117             );
118 
119         } catch (Exception e) {
120             throw new JellyException(e);
121         }
122 
123     }
124 
125     /***
126      * Parse the command line using CLI. -o and -script are reserved for Jelly.
127      * -Dsysprop=sysval is support on the command line as well.
128      */
129     public CommandLine parseCommandLineOptions(String[] args) throws ParseException {
130         // create the expected options
131         Options cmdLineOptions = new Options();
132         cmdLineOptions.addOption("o", true, "Output file");
133         cmdLineOptions.addOption("script", true, "Jelly script to run");
134 
135         // -D options will be added to the system properties
136         Properties sysProps = System.getProperties();
137 
138         // filter the system property setting from the arg list
139         // before passing it to the CLI parser
140         ArrayList filteredArgList = new ArrayList();
141 
142         for (int i=0;i<args.length;i++) {
143             String arg = args[i];
144 
145             // if this is a -D property parse it and add it to the system properties.
146             // -D args will not be copied into the filteredArgList.
147             if (arg.startsWith("-D") && (arg.length() > 2)) {
148                 arg = arg.substring(2);
149                 StringTokenizer toks = new StringTokenizer(arg, "=");
150 
151                 if (toks.countTokens() == 2) {
152                     // add the tokens to the system properties
153                     sysProps.setProperty(toks.nextToken(), toks.nextToken());
154                 } else {
155                     System.err.println("Invalid system property: " + arg);
156                 }
157 
158             } else {
159                 // add this to the filtered list of arguments
160                 filteredArgList.add(arg);
161 
162                 // add additional "-?" options to the options object. if this is not done
163                 // the only options allowed would be "-o" and "-script".
164                 if (arg.startsWith("-") && arg.length() > 1) {
165                     if (!(arg.equals("-o") && arg.equals("-script"))) {
166                         cmdLineOptions.addOption(arg.substring(1, arg.length()), true, "dynamic option");
167                     }
168                 }
169             }
170         }
171 
172         // make the filteredArgList into an array
173         String[] filterArgs = new String[filteredArgList.size()];
174         filteredArgList.toArray(filterArgs);
175 
176         // parse the command line
177         Parser parser = new GnuParser();
178         return parser.parse(cmdLineOptions, filterArgs);
179     }
180 
181 }