KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > spi > sendopts > Option


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.spi.sendopts;
21
22 import java.io.File JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.PrintWriter JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.MissingResourceException JavaDoc;
31 import java.util.ResourceBundle JavaDoc;
32 import java.util.logging.Level JavaDoc;
33 import org.netbeans.api.sendopts.CommandException;
34 import org.netbeans.modules.sendopts.OptionImpl;
35 import org.openide.util.Lookup;
36
37 /** Represents possible option that can appear on {@link org.netbeans.api.sendopts.CommandLine}
38  * and contains factory methods to create them.
39  * <p>
40  * An option can have letter short version, long name. It can
41  * accept arguments, one argument or an array of additional arguments.
42  *
43  * @author Jaroslav Tulach
44  */

45 public final class Option {
46     /** character of single command of (char)-1
47      */

48     private final int shortName;
49     /** long name or null */
50     private final String JavaDoc longName;
51     /** implementation of this option */
52     final OptionImpl impl;
53     /** bundle with message*/
54     private final String JavaDoc[] keys;
55     private final String JavaDoc[] bundles;
56
57     /** Constant that represents no short name indicator.
58      */

59     public static final char NO_SHORT_NAME = (char)-1;
60     
61     private static String JavaDoc[] EMPTY = new String JavaDoc[2];
62     
63     /** Use factory method */
64     private Option(char shortName, String JavaDoc longName, int type) {
65         this.shortName = shortName == NO_SHORT_NAME ? -1 : (int)shortName;
66         this.longName = longName;
67         switch (type) {
68             case 0: this.impl = OptionImpl.createNoArg(this); break;
69             case 1: this.impl = OptionImpl.createOneArg(this, false); break;
70             case 2: this.impl = OptionImpl.createOneArg(this, true); break;
71             case 3: this.impl = OptionImpl.createAdd(this, false); break;
72             case 4: this.impl = OptionImpl.createAdd(this, true); break;
73             default: throw new IllegalArgumentException JavaDoc("Type: " + type); // NOI18N
74
}
75         this.keys = EMPTY;
76         this.bundles = EMPTY;
77     }
78
79     /** Complex option */
80     Option(int type, Option[] arr) {
81         this.shortName = -1;
82         this.longName = null;
83         this.impl = OptionImpl.create(this, type, Arrays.asList(arr));
84         this.keys = EMPTY;
85         this.bundles = EMPTY;
86     }
87     
88     /** clone with some description
89      */

90     private Option(Option old, int typeOfDescription, String JavaDoc bundle, String JavaDoc description) {
91         this.shortName = old.shortName;
92         this.longName = old.longName;
93         this.impl = OptionImpl.cloneImpl(old.impl, this, null);
94         this.keys = (String JavaDoc[])old.keys.clone();
95         this.bundles = (String JavaDoc[])old.bundles.clone();
96         
97         this.keys[typeOfDescription] = description;
98         this.bundles[typeOfDescription] = bundle;
99         
100     }
101     
102     /** Programmatic textual representation of the option. Format is subject to change
103      * in future.
104      * @return textual description of the option
105      */

106     public String JavaDoc toString() {
107         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
108         sb.append(getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this))); // NOI18N
109
sb.append('[');
110         sb.append(shortName);
111         sb.append(',');
112         sb.append(longName);
113         sb.append(',');
114         impl.append(sb);
115         sb.append(']');
116         return sb.toString();
117     }
118     
119     /** Options with the same functionality, regardless of their descriptions
120      * {@link Option#shortDescription} and {@link Option#displayName} are always the same.
121      */

122     public boolean equals(Object JavaDoc o) {
123         if (o instanceof Option) {
124             Option option = (Option)o;
125             return impl.root == option.impl.root;
126         }
127         return false;
128     }
129     
130     public int hashCode() {
131         return System.identityHashCode(impl.root);
132     }
133
134     /** Factory method that creates an option without any arguments.
135      * For example to create an option that handles <code>--help</code> or
136      * <code>-h</code> one can create it using:<pre>
137      * Option helpOption = Option.withoutArgument('h', "help");</pre>
138      * and inside of the {@link OptionProcessor} declaring this
139      * option use:<pre>
140      * protected void process(Env env, Map&lt;Option,String[]&gt; values) throws CommandException {
141      * if (values.containsKey(helpOption)) {
142      * printHelp(env.getErrorStream());
143      * }
144      * }</pre>
145      * The <code>values.get(helpOption)</code> is always <code>null</code> to signal
146      * that this options does not have any associated value.
147      *
148      * @param shortName character code or {@link Option#NO_SHORT_NAME}
149      * @param longName long name or null
150      * @return option representing the created definition
151      */

152     public static Option withoutArgument(char shortName, String JavaDoc longName) {
153         return new Option(shortName, longName, 0);
154     }
155
156     /** Factory method for option that may, but does not need to have an argument.
157      * For example to have option that increments by one or by specified number
158      * one could write:<pre>
159      * Option incrementOption = Option.optionalArgument('i', "increment");</pre>
160      * and inside of the {@link OptionProcessor} declaring this
161      * option use:<pre>
162      * public void process(Env env, Map&lt;Option,String[]&gt; values) throws CommandException {
163      * if (values.containsKey(incrementOption)) {
164      * String[] inc = values.get(incrementOption);
165      * int increment = inc == null ? 1 : Integer.parseInt(inc[0]);
166      * // do what is necessary
167      * }
168      * }</pre>
169      * The <code>values</code> map always contains the <code>incrementOption</code>
170      * if it appeared on the command line. If it had associated value, then
171      * the <code>map.get(incrementOption)</code> returns array of length one,
172      * with item on position 0 being the value of the option. However if the
173      * option appeared without argument, then the value associated with the
174      * option is <code>null</code>.
175      * <p>
176      * If registered into to system using {@link OptionProcessor} then users could
177      * use command lines like <code>-i=5</code> or <code>--increment=5</code> to
178      * increase the value by five or just <code>-i</code> and <code>--increment</code>
179      * to increment by default - e.g. one.
180      *
181      * @param shortName the character to be used as a shortname or {@link Option#NO_SHORT_NAME}
182      * @param longName the long name or null
183      */

184     public static Option optionalArgument(char shortName, String JavaDoc longName) {
185         return new Option(shortName, longName, 1);
186     }
187
188     /** Factory method for option has to be followed by one argument.
189      * For example to have option that opens a file
190      * one could write:<pre>
191      * Option openOption = Option.optionalArgument('o', "open");</pre>
192      * and inside of the {@link OptionProcessor} declaring this
193      * option use:<pre>
194      * public void process(Env env, Map&lt;Option,String[]&gt; values) throws CommandException {
195      * if (values.containsKey(openOption)) {
196      * String fileName = values.get(openOption)[0];
197      * File file = new File({@link Env#getCurrentDirectory}, fileName);
198      * // do what is necessary
199      * }
200      * }</pre>
201      * The <code>values</code> map always contains the <code>openOption</code>
202      * if it appeared on the command line. Its value is then always string
203      * array of length one and its 0 element contains the argument for the
204      * option.
205      * <p>
206      * If registered into to system using {@link OptionProcessor} then users could
207      * use command lines like <code>-oX.java</code> or <code>--open Y.java</code> to
208      * invoke the open functionality.
209      *
210      * @param shortName the character to be used as a shortname or {@link Option#NO_SHORT_NAME}
211      * @param longName the long name or null
212      */

213     public static Option requiredArgument(char shortName, String JavaDoc longName) {
214         return new Option(shortName, longName, 2);
215     }
216
217     /** Creates an option that can accept <q>additional arguments</q>.
218      * For example to have option that opens few files
219      * one could write:<pre>
220      * Option openOption = Option.additionalArguments('o', "open");</pre>
221      * and inside of the {@link OptionProcessor} declaring this
222      * option use:<pre>
223      * public void process(Env env, Map&lt;Option,String[]&gt; values) throws CommandException {
224      * if (values.containsKey(openOption)) {
225      * for (fileName : values.get(openOption)) {
226      * File file = new File({@link Env#getCurrentDirectory}, fileName);
227      * // do what is necessary
228      * }
229      * }
230      * }</pre>
231      * The <code>values</code> map always contains the <code>openOption</code>
232      * if it appeared on the command line. Its value is then always string
233      * array of arbitrary length containing all elements on the command line
234      * that were not recognised as options (or their arguments).
235      * For example line <pre>
236      * X.java -o Y.java Z.txt</pre>
237      * will invoke the {@link OptionProcessor} with
238      * <code>{ "X.java", "Y.java", "Z.txt" }</code>.
239      * <p>
240      * Obviously only one such {@link Option#additionalArguments} can be
241      * used at once on a command line. If there was not only the <q>open</q>
242      * but also <q>edit</q> option
243      * taking the additional arguments,
244      * then command line like: <pre>
245      * --edit X.java --open Y.java Z.txt</pre>
246      * would be rejected.
247      *
248      * @param shortName the character to be used as a shortname or {@link Option#NO_SHORT_NAME}
249      * @param longName the long name or null
250      */

251     public static Option additionalArguments(char shortName, String JavaDoc longName) {
252         return new Option(shortName, longName, 3);
253     }
254     /** Creates a default option that accepts <q>additional arguments</q>
255      * not claimed by any other option.
256      * For example to have option that opens few files
257      * one could write:<pre>
258      * Option openOption = Option.defaultArguments();</pre>
259      * and inside of the {@link OptionProcessor} declaring this
260      * option use:<pre>
261      * public void process(Env env, Map&lt;Option,String[]&gt; values) throws CommandException {
262      * if (values.containsKey(openOption)) {
263      * for (fileName : values.get(openOption)) {
264      * File file = new File({@link Env#getCurrentDirectory}, fileName);
265      * // do what is necessary
266      * }
267      * }
268      * }</pre>
269      * The <code>values</code> map always contains the <code>openOption</code>
270      * if there were some arguments on the command line that were not parsed
271      * by any other option. Its value is then always string
272      * array of arbitrary length containing all elements on the command line
273      * that were not recognised as options (or their arguments).
274      * For example line <pre>
275      * X.java Y.java Z.txt</pre>
276      * will invoke the {@link OptionProcessor} with
277      * <code>{ "X.java", "Y.java", "Z.txt" }</code>.
278      * <p>
279      * Obviously only one such {@link Option#defaultArguments} can defined.
280      * If there are two, then an error is reported when one tries to parse
281      * any command line with arguments not claimed by any other option.
282      * That is why it is always good idea to not define just {@link Option#defaultArguments}
283      * option, but also appropriate {@link Option#additionalArguments} one:<pre>
284      * Option openOption1 = Option.defaultArguments();
285      * Option openOption2 = Option.additionalArguments('o', "open");</pre>
286      * and handle both of them in the {@link OptionProcessor}. Then if the
287      * command line: <pre>
288      * X.java Y.java Z.txt</pre> is rejected due to ambiguities one can use <pre>
289      * X.java Y.java --open Z.txt</pre> to invoke the same functionality.
290      */

291     public static Option defaultArguments() {
292         return new Option(NO_SHORT_NAME, null, 4);
293     }
294
295     /** Associates a name with given option. By default
296      * the option display name is generated by the infrastructure from the
297      * short and long name plus generic description of options arguments, this
298      * method allows to completely replace the default behaviour.
299      *
300      * @param option the option to add description for
301      * @param bundleName name of a bundle to create
302      * @param key the bundle key to get the message from
303      * @return option with same behaviour as the old one plus with associated display name
304      */

305     public static Option displayName(Option option, String JavaDoc bundleName, String JavaDoc key) {
306         return new Option(option, 0, bundleName, key);
307     }
308     
309     /** Associates a short textual description with given option. This message
310      * is going to be printed during {@link org.netbeans.api.sendopts.CommandLine#usage} next to the
311      * option name. Usually should be one liner comment.
312      *
313      * @param option the option to add description for
314      * @param bundleName name of a bundle to create
315      * @param key the bundle key to get the message from
316      * @return option with same behaviour as the old one plus with associated short description message
317      */

318     public static Option shortDescription(Option option, String JavaDoc bundleName, String JavaDoc key) {
319         return new Option(option, 1, bundleName, key);
320     }
321     
322     
323     static {
324         OptionImpl.Trampoline.DEFAULT = new OptionImpl.Trampoline() {
325             public OptionImpl impl(Option o) {
326                 return o.impl;
327             }
328             public Env create(InputStream JavaDoc is, OutputStream JavaDoc os, OutputStream JavaDoc err, File JavaDoc currentDir) {
329                 return new Env(is, os, err, currentDir);
330             }
331
332             public void usage(PrintWriter JavaDoc w, Option o, int max) {
333                 if (o.keys[1] != null) {
334                     w.print(key(o.bundles[1], o.keys[1], Locale.getDefault()));
335                 }
336             }
337             public Option[] getOptions(OptionProcessor p) {
338                 return p.getOptions().toArray(new Option[0]);
339             }
340             public void process(OptionProcessor provider, Env env, Map JavaDoc<Option,String JavaDoc[]> options) throws CommandException {
341                 provider.process(env, Collections.unmodifiableMap(options));
342             }
343             public String JavaDoc getLongName(Option o) {
344                 return o.longName;
345             }
346             public int getShortName(Option o) {
347                 return o.shortName;
348             }
349             public String JavaDoc getDisplayName(Option o, Locale JavaDoc l) {
350                 return key(o.bundles[0], o.keys[0], l);
351             }
352             private String JavaDoc key(String JavaDoc bundle, String JavaDoc key, Locale JavaDoc l) {
353                 if (key == null) {
354                     return null;
355                 }
356                 ClassLoader JavaDoc loader = Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
357                 if (loader == null) {
358                     loader = Thread.currentThread().getContextClassLoader();
359                 }
360                 if (loader == null) {
361                     loader = getClass().getClassLoader();
362                 }
363                 try {
364                     ResourceBundle JavaDoc b = ResourceBundle.getBundle(bundle, l, loader);
365                     return b.getString(key);
366                 } catch (MissingResourceException JavaDoc ex) {
367                     OptionImpl.LOG.log(Level.WARNING, null, ex);
368                     return key;
369                 }
370                 
371             }
372         };
373     }
374 }
375
Popular Tags