How do you parse arguments for a java program? - java

I'm making a Selenium WebDriver java program. I have 25 application and 4 environments. I need to be able to pass something like -app app1 app2 app3 ... appn -env env1 env2 envn
I need to be able to pass either, neither or both arguments. Right now I have it being able to pass one app and one env in that order but I need to be able to do it in either order and with the either neither or both possibility. Here's what I have so far. With this I can either pass no arguments and runs every app for every environment (which is what I want) or I can pick app1 env1 in that order for that specific test.
public static Application chooseAppTest(String[] args)
{
Application application = null;
switch (Application.valueOf(args[0]))
{
case ACCOUNTINVENTORY:
new AccountInventory(Environment.valueOf(args[1]));
AccountInventory.accountInventoryDatabaseTests(testResults);
break;
if (args.length == 0)
{
LogIn.loginTest(testResults);
DatabaseTest.testResults(testResults);
LinkTest.linkTests(testResults);
}
else
{
// First choose application, then choose environment
Application.chooseAppTest(args);
}

I don't think recursion is needed. You can do something like this:
public static void main (String[] args)
{
List<String> apps = new LinkedList<>();
List<String> envs = new LinkedList<>();
List<String> current = null;
// parse arguments
for (String arg : args)
{
if (arg.equals("-app")) current = apps;
else if (arg.equals("-env")) current = envs;
else if (current != null) // add argument
current.add(arg);
}
// parsing finished
Application.doSomethingWith(apps, envs);
}

It is not necessary or advantagious to use recursion. You can read all the arguments into an array and process them from there. Other than that, I'm not sure how you would proceed. With the arguments arranged in this way, how do you know which environment goes with which application?

As Elliott commented, have you looked at Apache Commons CLI? It's a command line parser.

Related

Commons CLI is not honoring my command line setup

Using Apache Commons CLI 1.2 here. I have an executable JAR that needs to take 2 runtime options, fizz and buzz; both are strings that require arguments/values. I would like (if at all possible) my app to be executed like so:
java -jar myapp.jar -fizz "Alrighty, then!" -buzz "Take care now, bye bye then!"
In this case, the value for the fizz option would be "Alrighty, then!", etc.
Here's my code:
public class MyApp {
private Options cmdLineOpts = new Options();
private CommandLineParser cmdLineParser = new GnuParser();
private HelpFormatter helpFormatter = new HelpFormatter();
public static void main(String[] args) {
MyApp myapp = new MyApp();
myapp.processArgs(args);
}
private void processArgs(String[] args) {
Option fizzOpt = OptionBuilder
.withArgName("fizz")
.withLongOpt("fizz")
.hasArg()
.withDescription("The fizz argument.")
.create("fizz");
Option buzzOpt = OptionBuilder
.withArgName("buzz")
.withLongOpt("buzz")
.hasArg()
.withDescription("The buzz argument.")
.create("buzz");
cmdLineOpts.addOption(fizzOpt);
cmdLineOpts.addOption(buzzOpt);
CommandLine cmdLine;
try {
cmdLine = cmdLineParser.parse(cmdLineOpts, args);
// Expecting to get a value of "Alright, then!"
String fizz = cmdLine.getOptionValue("fizz");
System.out.println("Fizz is: " + fizz);
} catch(ParseException parseExc) {
helpFormatter.printHelp("myapp", cmdLineOpts, true);
throw parseExc;
}
}
}
When I run this I get the following output:
Fizz is: null
What do I need to do to my code so that my app can be invoked the way I want it to? Or what's the closest I can get to it?
Bonus points: If someone can explain to me the difference between the OptionBuilder's withArgName(...), withLongOpt(...) and create(...) arguments, as I am passing in the same value for them all like so:
Option fizzOpt = OptionBuilder
.withArgName("fizz")
.withLongOpt("fizz") } Why do I have to pass the same value in 3 times to make this work?!?
.create("fizz");
First the .hasArg() on your OptionBuilder tells it that you expect an argument after the paramter flag.
I got it to work with this command line
--fizz "VicFizz is good for you" -b "VicBuzz is also good for you"
Using the following code - I put this in the constructor
Option fizzOpt = OptionBuilder
.withArgName("Fizz")
.withLongOpt("fizz")
.hasArg()
.withDescription("The Fizz Option")
.create("f");
cmdLineOpts.addOption(fizzOpt);
cmdLineOpts.addOption("b", true, "The Buzz Option");
Breakdown
The option settings are necessary in order to provide more usability on the command line, as well as a nice usage message (see below)
.withArgName("Fizz"): Gives your argument a nice title in the usage
(see below)
.withLongOpt("fizz"): allows for --fizz "VicFizz is good for you"
.create("f"): is the main parameter and allows
command line -f "VicFizz is good for you"
Notice that Option b for
fuzz was constructed much simpler, sacrificing readability during
usage
Usage Message
Personally I love CLI programs that print out a nice usage. You can do this with the HelpFormatter. For example:
private void processArgs(String[] args) {
if (args == null || args.length == ) {
helpFormatter.printHelp("Don't you know how to call the Fizz", cmdLineOpts);
...
This will print something usefull like:
usage: Don't you know how to call the Fizz
-b <arg> The Buzz Option
-f,--fizz <Fizz> The Fizz Option
Notice how a the short option -f, the long option --fizz, and a name <Fizz> is displayed, along with the description.
Hope this helps

How to use R model in java to predict with multiple models?

I have this constructor:
public Revaluator(File model,PrintStream ps) {
modelFile=model;
rsession=Rsession.newInstanceTry(ps, null);
rsession.eval("library(e1071)");
rsession.load(modelFile);
}
i want to load a model and predict with it.
the problem that Rsession.newInstanceTry(ps, null); is always the same session, so if i load another model, like:
Revaluator re1=new Revaluator(new File("model1.RData"),System.out);
Revaluator re2=new Revaluator(new File("model2.RData"),System.out);
Both re1 and re2 using the same model, since the var name is model, so only the last one loaded.
the evaluate function:
public REXP evaluate(Object[] arr){
String expression=String.format("predict(model, c(%s))", J2Rarray(arr));
REXP ans=rsession.eval(expression);
return ans;
}
//J2Rarray just creates a string from the array like "1,2,true,'hello',false"
i need to load about 250 predictors, is there a way to get every instance of Rsession as a new separated R Session?
You haven't pasted all of your code in your question, so before trying the (complicated) way below, please rule out the simple causes and make sure that your fields modelFile and rsession are not declared static :-)
If they are not:
It seems that the way R sessions are created is OS dependent.
On Unix it relies on the multi-session ability of R itself, on Windows it starts with Port 6311 and checks if it is still free. If it's not, then the port is incremented and it checks again, if it's free and so on.
Maybe something goes wrong with checking free ports (which OS are you working on?).
You could try to configure the ports manually and explicitly start different local R servers like this:
Logger simpleLogger = new Logger() {
public void println(String string, Level level) {
if (level == Level.WARNING) {
p.print("! ");
} else if (level == Level.ERROR) {
p.print("!! ");
}
p.println(string);
}
public void close() {
p.close();
}
};
RserverConf serverConf = new RserverConf(null, staticPortCounter++, null, null, null);
Rdaemon server = new Rdaemon(serverConf, this);
server.start(null);
rsession = Rsession.newInstanceTry(serverConf);
If that does not work, please show more code of your Revaluator class and give details about which OS you are running on. Also, there should be several log outputs (at least if the log level is configured accordingly). Please paste the logged messages as well.
Maybe it could also help to get the source code of rsession from Google Code and use a debugger to set a breakpoint in Rsession.begin(). Maybe this can help figuring out what goes wrong.

Using a String in run configurations as an argument and using it in an if-statement

The code below works as long as the argument in the run configuration equals "-output". But when the arguments are empty the compiler throws and ArrayOutOfBoundsException.
The point of this piece of code would eventually be to;
- Perform an action when -output is written in the run configurations arguments
- Perform something else if the arguments are empty or different from -output
I found many problems that looked like this one. But I've been working on a solutions for far to long, so I started a new post. Help is very much appreciated.
...
public static void main(String[] args) {
Version_5 v5 = new Version_5("Test");
{
if(args[0].equals("-output")){
System.out.println("It works");
}
}
}
...
You need to check if you have arguments first, that's all.
if ((args.length > 0) && (args[0].equals("-output")) {
...
You might also consider using an argument-parsing library, of which there are several.
What are the extra brackets for?
As you can see String args[] is an array with a specific size. If you don't pass an argument the size is zero. Before you check what is at args[0] check if args has a size with args.length.
if (args.length>0){
//do something
}
else if (args[0].equals("-output")){
System.out.println("It works");
}

Make parameters available in an application

What is the standard way of storing a command line argument so that it can be accessed when required?
I can see 2 scenarios:
The argument is consumed immediately (A logging level)
The argument is not needed immediately (On failure send email to address X)
With scenario 1 It would seem quite natural to configure it upfront, however when it is a scenario more in the vein of scenario 2 I would prefer to configure that component as and when necessary (IE not up front)
So to phrase the question slightly differently how do I make my configuration options available to my entire application?
You can have a singleton Configuration object, in which all relevant things are stored.
public class Configuration {
private static final Configuration conf = new Configuration();
public static Configuration get() {
return conf;
}
private String failureEmailAddress;
public String getFailureEmailAddress() {
return failureEmailAddress;
}
public void parseCommandLine(String[] args) {
// ...
}
}
You can use something like that (you can store the CommandLine somewhere or use the opions right away):
Options options = createOptions();
CommandLineParser parser = new GnuParser();
CommandLine cmdLine;
int timeoutHumanMove;
try
{
cmdLine = parser.parse(options, args, true);
timeoutHumanMove = getTimeoutOption(cmdLine, "thm", 300);
}
catch(ParseException e)
{
return;
}
private static int getTimeoutOption(CommandLine cmdLine, String opt, int defaultSeconds)
throws ParseException
{
if(cmdLine.hasOption(opt))
{
Number val = (Number)cmdLine.getParsedOptionValue(opt);
return (int)(val.doubleValue() * 1000D);
} else
{
return 1000 * defaultSeconds;
}
}
private static Options createOptions()
{
Options options = new Options();
options.addOption(OptionBuilder.withDescription("print this help and exit").create(OptionBuilder.withLongOpt("help"), 104));
// ...
return options;
}
There is no standard way to store application wide configuration information such as you describe. However, most of the time you store it in a class which is specific to the job (ApplicationContext), and then the instance is passed into the other classes as parameters or in a constructor or something like that. I usually make the ApplicationContext immutable.
Some applications I've come across use a static global context, effectively a global variable. This isn't necessarily a good idea, for the same reason that you should avoid global variables.
However, I would say that you should always verify that the command line options are valid up front. You don't want to do 3 hours of processing and then find out that someone hadn't configured the email address correctly on the command line. This should be a fail-fast situation.
You could store your command args into System properties using System.setProperty() then you can access your properties anywhere via System.getProperty()..

how to get the command line arguments from another class with java

so suppose I have a java package....
it's got the main class with the main method
and then it's got a whole bunch of other classes.....
my question is, is it possible to get the args that was passed into the main method from these other classes that are not part of the main class but in the same package...
No, not portably, there may be some trickery based on the JVM implementation but I've never seen it, and it would be a very bad idea to rely on it even if it existed.
If you want those values elsewhere, the main function needs to make them available somehow.
An easy way to do this (not necessarily the best way) is to simply store away the strings as the first thing in main and provide a means for getting at them:
Scratch2.java:
public class Scratch2 {
// Arguments and accessor for them.
private static String[] savedArgs;
public static String[] getArgs() {
return savedArgs;
}
public static void main(String[] args) {
// Save them away for later.
savedArgs = args;
// Test that other classes can get them.
CmdLineArgs cla = new CmdLineArgs();
cla.printArgs();
}
}
CmdLineArgs.java:
public class CmdLineArgs {
public void printArgs() {
String[] args = Scratch2.getArgs();
System.out.println ("Arg count is [" + args.length + "]");
for (int i = 0; i < args.length; i++) {
System.out.println ("Arg[" + i + "] is [" + args[i] + "]");
}
}
}
And, when run with the arguments a b c, this outputs:
Arg count is [3]
Arg[0] is [a]
Arg[1] is [b]
Arg[2] is [c]
The system-properties on some (?) JRE-implementations provide the system-property "sun.java.command" to get the programm-name and parameters that were used to start the program. Like "myjar.jar param1 param2 ...".
While this value doesn't even belong to the set of properties that are mentioned in the documentation, it is present in both Oracle-JRE v1.8 and OpenJRE v1.8 (tested).
I couldn't find any documentation whether this value is supported by default though (best I could find was the list in the System#getProperties() docs). Any clarification on this would be welcome. Handle with care!!!
If you don't care about OS portability, read /proc/self/cmdline or the equivalent for your OS.
See http://en.wikipedia.org/wiki/Procfs
As paxdiablo said, your main class would have to store these parameters and then either distribute or make available to needed ones. Often a good idea would be to let another class do the parsing of these parameters, and provide an object of this class instead of the raw command line to whoever needs it.
I'm kind of a newb at this, but you should be able to store the string[] args to a private instance variable, then make an accessor method for it.
E.g.,
public class test {
private String[] myArgs = new String[10];
public static void main(String[] args) {
myArgs = args;
}
public String[] getArgs() {
return myArgs;
}
}
Not sure if it will work, but that's the idea.

Categories