<api-answers
question-version="1.28"
module="Command Line Parsing API"
author="jtulach@netbeans.org"
>
&api-questions;
<!-- <questionid="arch-overall"when="init"> Describetheoverallarchitecture. <hint> WhatwillbeAPIfor <ahref="http://openide.netbeans.org/tutorial/api-design.html#design.apiandspi"> clientsandwhatsupportAPI</a>? Whatpartswillbepluggable? Howwillplug-insberegistered?Pleaseuse<code><apitype="export"/></code> todescribeyourgeneralAPIs. Ifpossiblepleaseprovide simplediagrams. </hint> </question>
-->
<answer id="arch-overall">
<p>
<api name="SendOptsAPI" category="official" group="java"type="export"url="@TOP@/org/netbeans/api/sendopts/package-summary.html"/>
allows anyone to parse an array of strings - e.g. a command line.
The infrastracture of the module then locates all providers
registered using the
<api name="SendOptsSPI" category="official" group="java"type="export"url="@TOP@/org/netbeans/spi/sendopts/package-summary.html"/>
and distributes the parts of the command line to their handlers.
It is expected that the handlers do not know about each
other and are in fact provided by different modules. The goal of the sendopts
framework
is to get the description of the handlers, apply the gained knowledge to
the actual content of the command line and distribute the parts of the
command line arguments to the designated handlers. Beyond this optimal
state the error handling and help composition is also supported by this
infrastructure.
</p>
</answer>
<!-- <questionid="arch-quality"when="init"> Howwillthe<ahref="http://www.netbeans.org/community/guidelines/q-evangelism.html">quality</a> ofyourcodebetestedand howarefutureregressionsgoingtobeprevented? <hint> Whatkindoftestingdo youwanttouse?Howmuchfunctionality,inwhichareas, shouldbecoveredbythetests? </hint> </question>
-->
<answer id="arch-quality">
<p>
There will be tests to verify consistency with UNIX standard <q>getopts</q> behaviour.
Everytime one reports an error or finds difference between functionality
of this API and functionality of <q>getopts</q> new tests will be created.
</p>
</answer>
<!-- <questionid="arch-usecases"when="init"> <hint> Contentofthisanswerwillbedisplayedaspartofpageat http://www.netbeans.org/download/dev/javadoc/usecases.html Youcanusetags<usecasename="name>regularhtmldescription</usecase> andifyouwanttouseanURLyoucanprefixifwith@TOP@tobegin attherootofyourjavadoc </hint> Describethemain<ahref="http://openide.netbeans.org/tutorial/api-design.html#usecase"> usecases</a>ofthenewAPI.Whowilluseitunder whatcircumstances?Whatkindofcodewouldtypicallyneedtobewritten tousethemodule? </question>
-->
<answer id="arch-usecases">
<usecase id="cli-just-parse" name="Just Parse the Command Line" >
There needs to be a simple API for someone who has an array of strings
and wants to parse them. One does not need to search for providers,
just ask the infrastructure to do the parse and get the result.
<br/>
The correct way to achieve this is to call
<code><a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html">CommandLine</a>.getDefault().process(args)</code>.
</usecase>
<usecase id="cli-own-parse" name="Parse the Command Line with Own Options" >
Since version2.20 one can define own classes with fields and annotate
them with <a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">@Arg</a>
annotation. Those classes can then be passed into a
<a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#create(java.lang.Class...)">
factory method
</a>
that creates new <a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#create(java.lang.Class...)">command line</a>.
One can then process the arguments as many times as needed via the
<a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#process(java.lang.String...)">process</a>
method. Example:
<pre> public final class MyOption implements <a href="@JDK@@JDKMODULE_JAVA_BASE@/java/lang/Runnable.html">Runnable</a> {
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">@Arg</a>(longName="hello") public String name;
public void run() {
System.out.println("Hello " + name + "!");
}
public static void main(String... args) {
<a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html">CommandLine</a> line = <a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#create(java.lang.Class...)">CommandLine.create</a>(MyOption.class);
line.<a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#process(java.lang.String...)">process</a>(args);
}
}
</pre>
<p>
If the above main class is called with parameters <code>--hello World</code> it
will print out <code>Hello World!</code>.
</p>
</usecase>
<usecase id="cli-types-of-options" name="Short and Long options with or without an argument" >
The standard <code>getopts</code> supports short form of options - e.g. a dash
followed with one letter - or long form using two dashes followed with a word.
Moreover the long form is optimized for abbrevations. If there are no
conflicts between multiple options, then one can only use double dash followed
with a prefix of a long option.
<br/>
When using the <a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a>
one can always specify
<code><a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">@Arg</a>(longName="text", shortName='t')</code>.
The <code>longName</code> attribute is required, but if there is supposed to be
no long version of the argument, it can be set to empty string.
<br/>
One can create an <a href="@TOP@org/netbeans/spi/sendopts/Option.html">Option</a>
by calling any of its factory methods
(like
<a href="@TOP@org/netbeans/spi/sendopts/Option.html#withoutArgument(char,java.lang.String)">withoutArgument</a>)
and provider <code>char</code> for the one letter option and/or string for
the long getopts option.
</usecase>
<usecase id="cli-types-args" name="Options with or without an argument" >
There are three types of options. Those without an argument, those with
a required one and those with optional one. Each one can be created
by appropriate factory method in the
<a href="@TOP@org/netbeans/spi/sendopts/Option.html">Option</a> class.
<br/>
When using the <a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a>
one needs to annotate a field of type <code>boolean</code> to create
an option without an argument.
</usecase>
<usecase id="cli-double-dash" name="Support for --" >
The getopts compliant command line parsers support <q>--</q>. If
these characters do appear on the command line, the rest of it is
treated as extra arguments and not processed. The sendopts infrastructure
supports this as well.
</usecase>
<usecase id="cli-multiple-handlers" name="Multiple Independent CLI Handlers" >
The handlers for the options need not know about each other and still
have to be able to process the command line successfully. Any module
which wishes to provide its own options can register its
<a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>
with <a href="@org-openide-util-lookup@/org/openide/util/lookup/ServiceProvider.html">@ServiceProvider</a>
annotation. Alternatively the module can use the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">@Arg</a> annotation
of its fields and it will be registered as well.
</usecase>
<usecase id="cli-extensible-options-set" name="Extensible Options Set" >
<p>
<b>Q:</b> How shall one write an
<a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>
that recognizes set of basic options, however contains one open <q>slot</q>?
The processor wants other modules to provide recognizers for that slot
and wants to communicate with them. For example, by default the processor
recognizes option <code>--channel <name_of_the_channel></code>
which describes a source of data, and stores such data into a <q>sink</q>.
There can be multiple sinks - discard the output, save it to file, show
it on stdout, stream it to network. The processor itself can handle the
copying of data, but does not itself know all the possible <q>sink</q>
types.
</p>
<p>
To implement
<a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>
like this one shall define an additional interface to communicate with
the <q>sink</q> providers:
</p>
<pre>
package my.module; public interface SinkProvider {
/** gets the option (even composite) that this sink needs on command line */ public Option getOption();
/** processes the options and creates a "sink" */ public OutputStream createSink(Env env, Map<Option,String[]> values) throws CommandException;
}
</pre>
<p>
Other modules would then registered implementations of this
interface in the
<code>META-INF/services/my.module.SinkProvider</code> files.
The
<a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>
itself would just look all the implementations up, queried for
the <q>sinks</q>, and then did the copying:
</p>
<pre>
class CopyingProvider extends OptionProvider { public Option getOption() {
List<Option> l = ...;
for (SinkProvider sp : Lookup.getDefault().lookupAll(SinkProvider.class)) {
l.add(sp.getOption());
}
// we need only one provider to be present
Option oneOfSinks = OptionGroups.oneOf(l.toArray(new Option[0]));
// our channel option
Option channel = ...;
// the channel option needs to be present as well as a sink
return OptionGroups.allOf(channel, oneOfSinks);
}
public void process(Env env, Map<Option,String[]> values) throws CommandException {
OutputStream os = null;
for (SinkProvider sp : Lookup.getDefault().lookupAll(SinkProvider.class)) {
if (values.containsKey(sp.getOption())) {
os = sp.createSink(env, values);
break;
}
}
if (os == null) {
throw CommandException.exitCode(2);
}
// process the channel option and
// handle the copying to the sink <code>os</code>
}
}
</pre>
<p>
Another possible approach how to allow sharing of one option between
multiple modules is to expose the option definition and its handling
code as an interface to other modules, and then let the modules
to write their own
<a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>s.
Necessary condition is that each of the processor is uniquely
identified by some additional option, so when the shared option appears
the infrastructure knows which processor to delegate to.
This is demonstrated in the
<a href="https://github.com/apache/netbeans/tree/master/platform/sendopts/test/unit/src/org/netbeans/api/sendopts/SharedOptionTest.java">
SharedOptionTest</a> which
basically does the following:
</p>
<pre>
/** the shared option, part of an interface of some module */ public static final Option SHARED = ...;
/** finds value(s) associated with the SHARED option and
* creates a JPanel based on them */ public static JPanel getSharedPanel(Map<Option,String[]> args) { ... }
</pre>
<p>
Then each module who wishes to reuse the SHARED option and the
factory method that knows how to process their values for their
own processing can just:
</p>
<pre> public static final class ShowDialog extends OptionProcessor {
private static final Option DIALOG = Option.withoutArgument('d', "dialog");
protected Set<Option> getOptions() {
// the following says that this processor should be invoked
// everytime --dialog appears on command line, if the SHARED
// option is there, then this processor wants to consume it
// as well...
return Collections.singleton(Option.allOf(DIALOG, Option.anyOf(SHARED)));
}
protected void process(Env env, Map<Option, String[]> optionValues) throws CommandException {
JPanel p = getSharedPanel(optionvalues);
if (p == null) {
// show empty dialog
} else {
// show some dialog containing the panel p
}
}
}
</pre>
<p>
The other modules are then free to write other processors refering to
<code>SHARED</code>, for example one can write <code>ShowFrame</code>
that does the same, just shows the panel in a frame, etc. The infrastructure
guarantees that the exactly one provider which matches the command
line options is called.
</p>
</usecase>
<usecase id="cli-help" name="Printing Full Help Text" >
Althrough the handlers are provided by independent parties, it must be possible
to generate resonable and consistent help description from all of them,
so for the end user it appears as well formated and easily understandable.
That is why
every option can be associated with a short description providing info
about what it is useful for using
<a href="@TOP@/org/netbeans/spi/sendopts/Option.html#shortDescription(org.netbeans.spi.sendopts.Option,java.lang.String,java.lang.String)">
Option.shortDescription
</a> method. When using the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">@Arg</a> style, there
is an additional <a href="@TOP@/org/netbeans/spi/sendopts/Description.html">@Description</a>
annotation which can be used to declaratively associate a localized display name
and short description with the option.
To get such descriptions for all available options one
can use
<a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html#usage(java.io.PrintWriter)">
CommandLine.getDefault().usage(java.io.PrintWriter)</a>.
</usecase>
<usecase id="cli-errorrecovery" name="Finding and Reporting when Options Are Not Correct" >
In case the command line cannot be processed a clean error for programmatic
consumation and also one that can be shown to the end user of the command
line must be given. This is handled by throwing
<a href="@TOP@org/netbeans/api/sendopts/CommandException.html">CommandException</a>
with appropriate message description and exit code.
</usecase>
<usecase id="cli-extraarguments" name="Processing Extra Command Line Arguments" >
There can be non-option arguments in the command line and they can freely
mix with the option ones. For example the getopts would treat the following
command line arguments as the same:<pre>
--open X.java Y.java Z.txt
X.java Y.java --open Z.txt
</pre> if the option <q>open</q> handles <q>extra arguments</q>.
The sendopts infrastructure must distinquish between them
and pass the non-option ones to the only one handler (active because it
processed an option) that knowns how to
parse them. It is an error if more than one or no handler expresses
an interest in extra arguments and those are given. One can register
such option by using the <code>
<a href="@TOP@org/netbeans/spi/sendopts/Option.html#additionalArguments(char,java.lang.String)">
Option.additionalArgument
</a>
</code> factory method.
<br/>
When using the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a>
one may annotate a field of type <code>String[]</code> which then means
this field should be filled with all additional arguments.
</usecase>
<usecase id="cli-io" name="Handling Input and Output" >
Handler's shall not use the input and output streams directly for their execution, they should
rely on the framework provided ones. This allows NetBeans based application to
transfer the I/O from second started instance to the master one which
is already running. From the client side there is the
<code><a href="@TOP@/org/netbeans/api/sendopts/CommandLine.html">CommandLine</a>.getDefault().parse</code>
methods taking additional arguments like input and output streams.
This gets transfered to providers as an
<a href="@TOP@/org/netbeans/spi/sendopts/Env.html">Env</a>
argument of their methods.
</usecase>
<usecase id="cli-exitcode" name="Returning Exit Code" >
When Handler's get execute (in the order defined by the order of options
on the command line), each of them can either execute successfully, or
fail. If a handler succeeds, next one is executed, if it fails, the
execution is terminated and its return code is returned to the caller.
The error can be notified by creating and throwing
<a href="@TOP@org/netbeans/api/sendopts/CommandException.html">CommandException.exitCode(int errorCode)</a>.
</usecase>
<usecase id="cli-onlyextraarguments" name="Processing Only Extra Command Line Arguments" >
Sometimes it is desirable to process non-option arguments like file names
without providing any option. Handlers can declare interest in such arguments.
It is an error if such non-options are provided and no or more than one
handler is around to handle them. One can create such option by
using <code>
<a href="@TOP@org/netbeans/spi/sendopts/Option.html#defaultArguments()">Option.defaultArguments</a>
</code> factory method. With the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a>
one can annotate a field of type <code>String[]</code> and specify that
it is supposed to be <a href="@TOP@/org/netbeans/spi/sendopts/Arg.html#implicit()">implicit</a>.
</usecase>
<usecase id="cli-lazy-handler-initiliazation" name="Only those processor need to process the options are created" >
For purposes of usage in NetBeans, it is needed to not-initialize those
handlers that are not really needed to process certain command line.
The infrastructure decides which of them are going to be needed and
instantiates only those. This is supported only when using the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a> -
information about these options is recorded in declarative way and the
system can decide without loading the provider classes whether they are
present on the command line or not.
</usecase>
<usecase id="cli-complex-options" name="Complex Option Relations" >
Certain CLI processors may need more than one option before they
can process the input. For example it is necesary to tune the radio
and then also tell what to do with the output. It is unconvenient
to process that as one option with argument(s), that is why one can
use the
<a href="@TOP@org/netbeans/spi/sendopts/OptionGroups.html#allOf(org.netbeans.spi.sendopts.Option...)">
OptionGroups.allOf</a>,
<a href="@TOP@org/netbeans/spi/sendopts/OptionGroups.html#someOf(org.netbeans.spi.sendopts.Option...)">
OptionGroups.someOf</a>, for example like: <pre>
class PP extends OptionProcessor {
private static Option tune = Option.requiredArgument(Option.NO_SHORT_NAME, "tune");
private static Option stream = Option.requiredArgument(Option.NO_SHORT_NAME, "stream");
// XXX handle what is needed here
}
}
</pre>
When the two options are registered and command line like
<q>--tune 91.9 --stream radio1.mp3</q> is being processed, the
<code>PP</code>'s <code>process</code> method is going to get
called with values <q>91.9</q> and <q>radio1.mp3</q>.
<br/>
This kind of grouping is not currently supported with the
<a href="@TOP@/org/netbeans/spi/sendopts/Arg.html">declarative annotation style</a>
registration.
</usecase>
<usecase id="cli-alternative-options" name="Alternative Options" >
Sometimes there may different ways to specify the same option and
just one of them or none of them can be provided at given time.
For example is there is a way to tune the radio with direct frequency
or with name of the station. Just one can be provided and one is needed.
This can be specified by using
<a href="@TOP@org/netbeans/spi/sendopts/OptionGroups.html#oneOf(org.netbeans.spi.sendopts.Option...)">
OptionGroups.oneOf</a> factory methods:
<pre>
Option freq = Option.requiredArgument(Option.NO_SHORT_NAME, "tune");
Option station = Option.requiredArgument(Option.NO_SHORT_NAME, "station");
Option tune = OptionGroups.oneOf(freq, station);
</pre>
The option <code>tune</code> then signals that just one of the station or
freq options can appear and that they both are replaceable.
</usecase>
</answer>
<!-- <questionid="arch-what"when="init"> Whatisthisprojectgoodfor? <hint> Pleaseprovidehereafewlinesdescribingtheproject, whatproblemitshouldsolve,providelinkstodocumentation, specifications,etc. </hint> </question>
-->
<answer id="arch-what">
<p>
GetOpts like infrastructure to parse command line arguments with the cooperative
participation of various modules.
</p>
</answer>
<!-- <questionid="compat-i18n"when="impl"> Isyourmodulecorrectlyinternationalized? <hint> Correctinternationalizationmeansthatitobeysinstructions at<ahref="http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/i18n-branding.html"> NetBeansI18Npages</a>. </hint> </question>
-->
<answer id="compat-i18n">
<p>
XXX no answer for compat-i18n
</p>
</answer>
<answer id="compat-deprecation">
<p>
This module replaces and stabilizes the previous <code>CLIHandler</code>
offered by <code>core/bootstrap</code> module. Modules are now adviced
to depend just on the API exported by this module.
</p>
</answer>
<!-- <questionid="compat-standards"when="init"> Doesthemoduleimplementordefineanystandards?Isthe implementationexactordoesitdeviatesomehow? </question>
-->
<answer id="compat-standards">
<p>
XXX no answer for compat-standards
</p>
</answer>
<!-- <questionid="dep-jre"when="final"> WhichversionofJREdoyouneed(1.2,1.3,1.4,etc.)? <hint> Itisexpectedthatifyourmodulerunson1.xthatitwillrun on1.x+1ifno,statethatplease.Alsodescribeherecaseswhere yourundifferentcodeondifferentversionsofJREandwhy. </hint> </question>
-->
<answer id="dep-jre">
<p>
XXX no answer for dep-jre
</p>
</answer>
<!-- <questionid="dep-jrejdk"when="final"> DoyourequiretheJDKoristheJREenough? </question>
-->
<answer id="dep-jrejdk">
<p>
XXX no answer for dep-jrejdk
</p>
</answer>
<!-- <questionid="dep-nb"when="init"> WhatotherNetBeansprojectsandmodulesdoesthisonedependon? <hint> Ifyouwant,describesuchprojectsasimportedAPIsusing the<code><apiname="identification"type="importorexport"category="stable"url="whereisthedescription"/></code> </hint> </question>
-->
<answer id="dep-nb">
<defaultanswer generate='none' />
<ul>
<li><api type='import' group='java' category='private' name='org.openide.util'url='../org-openide-util/overview-summary.html' >
The sendopts module uses <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html">Lookup</a>
to get list of all registered <a href="@TOP@org/netbeans/spi/sendopts/OptionProcessor.html">OptionProcessor</a>s.
This dependency is critical. If you want to use this API outside of NetBeans,
also include the <code>org-openide-util.jar</code> module.
</api>
</li>
<li><api type='import' group='java' category='private' name='org.netbeans.bootstrap' >
The sendopts module implements and registers the <code>CLIHandler</code> so it can
be called back by the <code>core/bootstrap</code> whenever some one needs
to parse the command line. This dependency is conditional, if the
<code>core/bootstrap</code> module is not present, the whole library
can still be used.
</api>
</li>
</ul>
</answer>
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.