I've an equinox application and I want get some eventual command line parameters that the user can use. How can I get these parameters?
The list of possible arguments are listed in the EclipseLauncher class as constants. If you want, you can get the constants of the class with reflection. System property names are prefixed with "PROP_".
This might work for one version, but not for other. I would not recommend this.
You can get the system properties via System.getProperties() (I guess this was trivial).
If you want to now if the arguments have been passed in Oracle based JVM with the sun.java.command system property. This will not work with other JVM implementations.
Non of the options above are suggested to use in production :). I would be interested in the use-case you want to implement by getting these arguments programmatically.
Related
I just read the excellent 12 Factor App document and it really registered with me. In Chapter 3 Config, the author stresses that:
The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.
I'm wondering what this implies for Java projects.
Typically, when it comes to my Java apps, I think of "env vars" as things that I can read from System.getProperty("blah"). Is this what the author is talking about? I don't think this is, because the author explicitly states "and unlike...or other config mechanisms such as Java System Properties...".
If not, what would be an example of an OS-agnostic "env var" that would satisfy this document's definition of "env var"? How would I read it from inside Java code?
Either way, some process has to first set each env var on the OS, so that the var is set & available by the time the app runs. What processes/methods could do this type of pre-run setup?
Use System.getenv() instead of System.getProperty(). System.getenv() returns value of specified environment variable defined in your OS.
Other, and probably preferable way is to pass selected OS environment variable to your JVM using -D command switch and then retrieve them using System.getProperty(). This way is more cross-platform: you may use the same java code even if specific platform does not support specific variable.
Updating the OS variables is absolutely other task. First, I do not think that you really want to do this. If you still want try to ask another question: probably other solution exists.
There is no cross platform API that does this in JDK and I do not know 3rd party library that dies this too. I personally planned to implement one but did not have time for this so far.
Windows stores variables in registry, so you can add variable to registry. But this does not affect current instance of shell, so your own java process will not see variables that it updated itself. You can however create process and run SET myvar=myvalue. If you want to write to registry you can use any of available libraries. Occasionally I implemented such library too. Its advantage is that it does not run any native code and is very compact. Take a look here.
On Unix you can run myvar=myvalue and if you want other processes to see this variable you have to run export myvar. But it still does not make this variable persisted. If you want this variable to survive OS restart you have to add it to one of the initial scripts (e.g. .bashrc). But this is completely depends on your system, configuration, permissions, shell etc.
Yes, the author is talking about environment variables. You can read environment variables from java code using the following snippet:
System.getenv(env);
See: http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getenv-java.lang.String-
If you want OS agnostic way, you can use JVM arguments and read using
System.getProperties();
For example, if you want a variable called var1 to be passed, use java -Dvar1=true -jar myJar.jar
I have following in my .properties file:
connection1.username=${cloud.db.username}
connection1.password=${cloud.db.password}
I'd like to pass these variables in Run/Debug Configuration
I thought all I need to do is to pass following parameters in JVM command line: -Dcloud.db.username=JOHN -Dcloud.db.password=SECRET.
But in the code call to Properties.getProperty() still returns ${cloud.db.username}.
I'm running it as junit under IntelliJ IDEA.
Passing properties into a jvm using -D puts them into the system properties (accessed via System.getProperties()).
Creating a java.util.Properties from a file in code gives you a completely separate set of properties.
Lots of applications allow you to specify properties via the command line -D option and in a file. To do this they have to implement some sort of fallback mechanism between the two and decide which gets preference.
Also, some applications allow you to define a property as referring to another, they generally do this either by extending or wrapping java.util.Properties.
You're expecting both of these things to work but neither are provided by Java out of the box.
If you want to implement these features, take a look at some open source projects that support them.
I don't fully understand why would you want to do something like that. Why do you need those values in the property file if you are not really using it?
If you want to pass those two parameters as custom command line parameters (-D) then can't you just do:
System.getProperty("cloud.db.username");
System.getProperty("cloud.db.password");
The value for connection1.username will alway be "${cloud.db.username}", java does not replace it with the value of another property or an environment variable.
If you want such a replacement, then you'll have to implement it (iterate through the entire value set of the properties object and replace all values, that match this pattern with the values of the referenced properties)
Trying accessing them via System.getProperty(...) instead
It is possible using -Dproperty=value arguments to set arbitrary system properties (not some fixed set of system properties actually used by the JVM) and a program can get these properties later using System.getProperty("property"). Is it correct to do this?
I haven't found an authoritative answer on this, so that's why I'm asking here. It seems to me that program parameters should be set through command line arguments to the program, not to the JVM. However, perhaps this is an accepted practice that just isn't documented anywhere I've looked so far. I'd like to be sure. Thanks.
I think Java system properties are used to pass values from command line to libraries or plugins inside the execution. It is, that insider component has no direct way to receive the parameter from the main program that's executing it. So it reads it from a "context" that Java system properties are.
If we look at it as layers, command line arguments would be parameters for the inmediate lower layer, and system java properties are context for all the lower layers.
command line: arguments + properties
main program: uses arguments
some library/plugin: uses properties from context
If it's not this way the main program should have to carry all the parameters that user could set to the lower layers and it can be very cumbersome.
I don't like to depend on contextual properties so if I design a program I'd try to pass over all the properties in some non-global way. But it can be very handy some times (and using namespacing it's not probable they collide).
In my opinion this is not "incorrect" and there are programs and libraries that do use their own system properties for configuration.
However, it is probably more practical to put configuration parameters for your software in a configuration file (in whatever format you think is suitable - a .properties file, an XML file, or something else). It is cumbersome, especially if you have many configuration parameters, to have to put all those parameters on the command line with -Dname=value options.
You can use this method to set some of your application settings. I think of settings as a contrast to program arguments. For example. Let's think abount some file converter. It converts file A to B. So files A and B should be command line params. If you converter needs some temporary folder you can make id settable by -Dmy.package.tempfolder=\my\tmp\folder. But there should be a default setting for that and the program should work without this setting.
Think about it as an alternative to .properties file. .properties file will be more convinient of course.
You just have to know what you're doing. If your application is a standalone application, system properties provide an easy to use way to pass named arguments, in any order, to the program, and I don't see anything intrinsically bad in using them.
If your app is a webapp that must be deployed in a app server shared by multiple webapps, then it might not be a good idea, especially if you aren't allowed to change how the server is started, or if you have to deploy multiple versions of the same application.
From http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html:
For example, the following invocation of getProperty looks up the
System property called subliminal.message. This is not a valid system
property, so instead of returning null, this method returns the
default value provided as a second argument: "Buy StayPuft
Marshmallows!"
System.getProperty("subliminal.message",
"Buy StayPuft Marshmallows!");
This implies that properties other than those used by the JVM are "invalid". However, later in the same document, it gives the example of loading a properties file containing the same property setting.
subliminal.message=Buy StayPuft Marshmallows!
It only advises "In general, be careful not to overwrite system properties."
So it seems that this is a supported use of System Properties. It looks like a case of misleading naming. When I hear "System Properties" I think "properties of the JVM" where the JVM is the system. While the properties are used for this, they can also be used for application settings. I think I'll make a mental note to think of this as "System and Application Properties".
Does anyone disagree with this?
Let us assume a Java application, accepting an integer command line argument, say bubu.
Assuming one uses a decent command line parser (and I do - https://github.com/jopt-simple/jopt-simple) plus keeping in mind the -D java switch, these are some of the typical ways to pass this command line parameter:
--bubu 5 (or --bubu=5 or --bubu5)
-Dbubu=5
Where the first one is the program argument and must be handled by the application using some command line parser, whereas the second is the VM argument and is already parsed by java, making it available as Integer.getInteger("bubu")
I am kinda puzzled. What should I use? Using the system property facility:
seems to cost nothing
does not depend on any command line parser library
provides convenient (albeit unexpected) API to obtain the values
As far as I can see, the only cons is that all the command line options have to use the -D flag.
Please, advice.
Thanks.
EDIT
Another pros for the system parameters - "they're usable even when the application is not a stand-alone app starting from a main, but also when the app is a webapp or a unit test." - thanks https://stackoverflow.com/users/571407/jb-nizet
EDIT2
Let me be more focused here. Is there any serious reason (besides esthetics) not to use the system parameters, like always?
EDIT3
OK, I think I get it now. If my code is likely to be loaded by a web application, then there is an issue of a potential name clash, since other web applications hosted by the same web container share the system property space with my code.
Therefore, I have to be prudent and disambiguate my system properties beforehand. So, no more bubu, it is com.shunra.myapp.bubu now. Meaning that instead of a simple
-Dbubu=5
I have
-Dcom.shunra.myapp.bubu=5
which becomes less attractive for a simple command line application.
Another reason is given by Mark Peters, which is pretty good to me.
I'd argue that the advantage Fortyrunner cites is actually the most significant negative for system properties--they are available to anyone who asks for them.
If the flag or option is meant to be a command-line option, it should be available to the layer or module of your code that deals with taking input from the command line, not any code that asks for it.
You can get some destructive coupling from global state, and system properties are no different than any other global state.
That said, if you're just trying to make a quick and dirty CLI program, and separation of concerns and coupling is not a big concern for you, system properties give you an easy method that however leads to (IMO) poor user experience. Some getopt library will give you a lot more support for building a good CLI user experience.
One of the main advantages of system properties is that they are available at any time during the life of you program.
Command line arguments are only available in the main method (unless you persist them).
I feel that there are many things that an average user like me do not need to know. System properties will help the developer of a system preset a number of value that will enable a system to run. For example, when I download GlassFish app server, it always come with many preset parameters that I have no ideas what they're for. I am not very experienced at dealing with server's setting. If you ask me to start GlassFish server with 20 parameters in the command line, I would have to learn what these parameters are for and how much should I set, etc. It's too troublesome.
In brief, when a system gets larger and larger, it may have more and more properties. With system properties preset, users may only need to know what they are when they really need to. For example, I only need to know about GlassFish's -XX:PermSize when I need to increase memory.
How do I pass a property to a Java process, started as a Windows service using Wrapper.exe?
The target code calls:
System.getProperty("ADMIN_USERNAME");
http://wrapper.tanukisoftware.org/doc/english/prop-java-additional-n.html
You can set "additional parameters" that will go to the JVM (as opposed to your main class), and -DADMIN_USERNAME=gandalf should work there.
wrapper.java.additional.1=-Xrs
wrapper.java.additional.2=-Dprop=TRUE
wrapper.java.additional.3=-DADMIN_USERNAME=gandalf
Update: You must start with additional.1 and count up without gaps (This is a convention for shoe-horning lists into Java properties syntax).
You can set certain properties in the wrapper config file, see this link:
http://wrapper.tanukisoftware.org/doc/english/properties.html
I believe you can also configure the wrapper to startup java and pass additional properties using the java "-Dproperty=value" syntax
This is a shot in the dark, but have you considered using JMX to communicate with the service? Or is this overkill for what you need?
Yuval =8-)
#Thilo's answer is correct but I feel I must add that you have to take care for JAVA_OPTS environment variable. Many people/servers tend to use it (e.g: remote debugging) as whatever you put into JAVA_OPTS is passed as JVM arguments to any new JVM. If you have this environment variable set then any wrapper.java.additional.<n> will be ignored. I found that on the hard way :)