Creating subcommands with commons-cli - java

I'm trying to create a simple argument parser using commons-cli and I can't seem to figure out how to create the following options:
java ... com.my.path.to.MyClass producer
java ... com.my.path.to.MyClass consumer -j 8
The first argument to my program should be either producer or consumer, defining the mode which my program will run in. If it's in consumer mode, I'd like to have a -j argument which defines how many threads to service with.
Here's what I've got so far:
Options options = new Options();
options.addOption("mode", false, "Things.");
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("startup.sh", options);
When I print out these options, the mode parameter shows up as -mode.
In Python's argparse, I'd just do the following:
parser = argparse.ArgumentParser()
parser.add_argument('mode', choices=('producer', 'consumer'), required=True)
parser.print_help()
This does exactly what I'm looking for. How can I do this in commons-cli?

What I've done for things like this is to have separate Options for each class. In your main, check the first argument to decide which list to pass to the parser. FWIW, I don't consider it "hack" solution.

JCommander is the answer. commons-cli doesn't seem to support these options.

picocli is now included in Groovy 2.5.x. It has built-in support for subcommands.

Related

Possible side effects when several CommandLine instance "work" on the same instance of an annotated class?

picoCLI's #-file mechanism is almost what I need, but not exactly. The reason is that I want to control the exact location of additional files parsed -- depending on previous option values.
Example: When called with the options
srcfolder=/a/b optionfile=of.txt, my program should see the additional options read from /a/b/of.txt, but when called with srcfolder=../c optionfile=of.txt, it should see those from ../c/of.txt.
The #-file mechanism can't do that, because it expands ALL the option files (always relative to the current folder, if they're relative) prior to processing ANY option values.
So I'd like to have picoCLI...
process options "from left to right",
recursively parse an option file when it's mentioned in an optionfile option,
and after that continue with the following options.
I might be able to solve this by recursively starting to parse from within the annotated setter method:
...
Config cfg = new Config();
CommandLine cmd = new CommandLine(cfg);
cmd.parseArgs(a);
...
public class Config {
#Option(names="srcfolder")
public void setSrcfolder(String path) {
this.srcfolder=path;
}
#Option(names="optionfile")
public void parseOptionFile(String pathAndName) {
// validate path, do some other housekeeping...
CommandLine cmd = new CommandLine(this /* same Config instance! */ );
cmd.parseArgs(new String[] { "#"+this.srcfolder + pathAndName });
}
...
This way several CommandLine instances would call setter methods on the same Config instance, recursively "interrupting" each other. Now comes the actual question: Is that a problem?
Of course my Config class has state. But do CommandLine instances also have state that might get messed up if other CommandLine instances also modify cfg "in between options"?
Thanks for any insights!
Edited to add: I tried, and I'm getting an UnmatchedArgumentException on the #-file option:
Exception in thread "main" picocli.CommandLine$UnmatchedArgumentException: Unmatched argument at index 0: '#/path/to/configfile'
at picocli.CommandLine$Interpreter.validateConstraints(CommandLine.java:13490)
...
So first I have to get around this: Obviously picoCLI doesn't expand the #-file option unless it's coming directly from the command line.
I did get it to work: several CommandLine instance can indeed work on the same instance of an annotated class, without interfering with each other.
There are some catches and I had to work around a strange picoCLI quirk, but that's not exactly part of an answer to this question, so I explain them in this other question.

how to use "closure-compiler " inside the java

I'm using closure-compiler which is provided by Google. I have JavaScript's in the string variable. need to compress the string using closure-compiler in java
I already tried the code from the following link http://blog.bolinfest.com/2009/11/calling-closure-compiler-from-java.html
This is the code I used "source" variable has the value of the javascript
Compiler compiler = new Compiler();
CompilerOptions options = new CompilerOptions();
// Advanced mode is used here, but additional options could be set, too.
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
compiler.compile(source, options);
return compiler.toSource();
I have error in the following line: compiler.compile(source, options);
Compiler.complier() method does not require 2 parameters but it requires 3 parameters.
Have a look at this link.
You will understand the number and kind of parameters required for the method you are calling.

Pentaho SDK, how to define a text file input

I'm trying to define a Pentaho Kettle (ktr) transformation via code. I would like to add to the transformation a Text File Input Step: http://wiki.pentaho.com/display/EAI/Text+File+Input.
I don't know how to do this (note that I want to achieve the result in a custom Java application, not using the standard Spoon GUI). I think I should use the TextFileInputMeta class, but when I try to define the filename the trasformation doesn't work anymore (it seems empty in Spoon).
This is the code I'm using. I think the third line has something wrong:
PluginRegistry registry = PluginRegistry.getInstance();
TextFileInputMeta fileInMeta = new TextFileInputMeta();
fileInMeta.setFileName(new String[] {myFileName});
String fileInPluginId = registry.getPluginId(StepPluginType.class, fileInMeta);
StepMeta fileInStepMeta = new StepMeta(fileInPluginId, myStepName, fileInMeta);
fileInStepMeta.setDraw(true);
fileInStepMeta.setLocation(100, 200);
transAWMMeta.addStep(fileInStepMeta);
To run a transformation programmatically, you should do the following:
Initialise Kettle
Prepare a TransMeta object
Prepare your steps
Don't forget about Meta and Data objects!
Add them to TransMeta
Create Trans and run it
By default, each transformation germinates a thread per step, so use trans.waitUntilFinished() to force your thread to wait until execution completes
Pick execution's results if necessary
Use this test as example: https://github.com/pentaho/pentaho-kettle/blob/master/test/org/pentaho/di/trans/steps/textfileinput/TextFileInputTests.java
Also, I would recommend you create the transformation manually and to load it from file, if it is acceptable for your circumstances. This will help to avoid lots of boilerplate code. It is quite easy to run transformations in this case, see an example here: https://github.com/pentaho/pentaho-kettle/blob/master/test/org/pentaho/di/TestUtilities.java#L346

JMeter use beanshell variable in HTTP Request

I'm an absolute rookie here (JAVA i mean), spent hours looking for a solution, now i just want to shoot myself.
I want to create a string in the beanshell assertion which is placed right above the HTTP Request.
In the beanshell i wrote:
String docid="abcd";
(in actuality i wish to concatenate a string with some variables)
In HTTP Request, send parameters i add ${docid}.
In BeanShell Assertion description section you can find the following:
vars - JMeterVariables - e.g. vars.get("VAR1"); vars.put("VAR2","value"); vars.putObject("OBJ1",new Object());
props - JMeterProperties (class java.util.Properties) - e.g. props.get("START.HMS"); props.put("PROP1","1234");
So to set jmeter variable in beanshell code (BeanShell Assertion sampler in your case) use the following:
String docid = "abcd";
vars.put("docid",docid);
or simply
vars.put("docid","abcd");
and then you can refer it as ${docid}, as you've done in your HTTP Request.
If you don't know Java well, you can use any of BSF or JSR223 Test elements and then select Javascript language as scripting language
http://jmeter.apache.org/usermanual/component_reference.html#JSR223_Sampler
If you need to pass value from one bean shell sampler to another, you should use variables.
vars.put("a", "something")
In other sampler, you should have something like:
String otherSampler = vars.get("a")
About debugging Shell Samplers - It is not so easy. I suggest to use SampleResult object. How to use it, you can see here Debugging Bean Shell Sampler

Get a specific argument with a firefox add-on

I'm trying to start firefox form a Java program, so far i know how to do that with option as well. But i'm interested in send a specific argument so a javascript add-on could obtain it.
For example, i use the command Runtime.getRuntime().exec("/usr/bin/firefox") to start firefox, my goal is to use something like Runtime.getRuntime().exec("/usr/bin/firefox 12345"), where 12345 is my argument and obtain it via a simple add-on.
Is this possible at all? is there another method/way to pass an argument to an add-on on firefox start?
Thanks in advance.
Start firefox with a url that contains your argument.
Use it as Runtime.getRuntime().exec(new String[] {"/usr/bin/firefox", "12345"})
Can't tell you how to get that argument in your Firefox add-on. Maybe modifying your question if that's what you're mainly asking?
I think your functionality would break the security model of firefox. but there are commands that you can use, http://www.binaryturf.com/lesser-firefox-command-line-options/
In first thank you all for your answers, all of you help me to get this work done. After some more research and thinking of some security issues, i end up using the Java process builder adding an environment variable with the value i want:
//Initiates the process i'm about to start.
ProcessBuilder pb = new ProcessBuilder(args);
//Gets the system environment.
Map<String, String> env = pb.environment();
//Register VAR with value Value as an evironment variable in this process context
env.put("VAR", "Value");
//Stats the process initiated in the 1st line.
pb.start();
So with this i can run an application and have environment variables on it's context, now i just want to access them in my JavaScript add-on, simply with this:
var env = Components.classes["#mozilla.org/process/environment;1"].getService(Components.interfaces.nsiEnvironment);
var X = env.get('VAR');
where X will have the value in the environment variable VAR (previous defined in the Java code);

Categories

Resources