How to read "OS variables" from Java (not System.properties) - java

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

Related

How can i set a global variable for Java so that it puts all java applets through a proxy?

I am trying to figure out how to make it so all java applications running on the machine are put through a provided proxy. I am doing this because the application that will be running does not support proxies by default and due to the circumstance i can not just give it command arguments. Below is what I have found so far and I have triied both the _JAVA_OPTIONS, JAVA_TOOL_OPTIONS, and _JPI_VM_OPTIONS. The application I am trying to work with is minecraft.
Prior to this issue I couldnt determine why my proxy application that I have built in C# using Titanium Web Proxy was not picking up on the minecraft traffic, and I have come to the conclusion that it is because it is not using the system's proxy. Here are the commands I have used to try setting the variable that are still not causing the JVM to go through the proxy.
set _JAVA_OPTIONS=-Djava.net.useSystemProxies=true
set _JPI_VM_OPTIONS=-Djava.net.useSystemProxies=true
set JAVA_TOOL_OPTIONS=-Djava.net.useSystemProxies=true
Guess my question is , is this possible?
If you find yourself using the same options over and over before laucing a java process, you can set up a special environment variable to contain your default options and the JVM will pick up the the values.
If the Java process is launch via java.exe then the environment variable is called _JAVA_OPTIONS (see JAVA_TOOL_OPTIONS below for a better option),
e.g. In Windows:
set _JAVA_OPTIONS=-Xms64m -Xmx128m -Dawt.useSystemAAFontSettings=lcd
In Linux:
export _JAVA_OPTIONS='-Xms64m -Xmx128m -Dawt.useSystemAAFontSettings=lcd'
ref : https://docs.oracle.com/javase/8/docs/technotes/guides/2d/flags.html
If the Java process is launch via javaw.exe (Applet) then the environment variable is called
_JPI_VM_OPTIONS.
For example :
_JPI_VM_OPTIONS = -Dsome.property=true
For a Java Web Start process (javaws.exe), the environment variable is called JAVAWS_VM_ARGS.
For example :
JAVAWS_VM_ARGS = -Dsome.property=true
But .. The preferred way is to use an environment called JAVA_TOOL_OPTIONS.
_JAVA_OPTIONS environment variable was ok but was not documented or supported. Since it is not >standardized, other vendors have their own names e.g. IBM_JAVA_OPTIONS. Leading underscore names are >private by convention so it's not a good to standardize the usage of _JAVA_OPTIONS. That's why >JAVA_TOOL_OPTIONS should be the preferred choice.
Maybe this question on the Arqade (another StackExchange site) can help: How can I play Minecraft through a proxy server?;
or, among others on StackOverflow, How do I set the proxy to be used by the JVM
Basically setting JAVA_TOOL_OPTIONS to include -Dhttp.proxyHost=proxyURL -Dhttp.proxyPort=proxyPORT -Dhttps.proxyHost=proxyURL -Dhttps.proxyPort=proxyPORT
(java.net.useSystemProxies should also work... but maybe minecraft (starter) is not respecting these settings - I believe you can set options in the starter as well)

Set default memory limit for all applets

Short version
How do I configure the icedtea-plugin package for ubuntu precise in such a way that it executes all applets with a specific memory limit by default? Preferrably using command line tools and no graphical user interface.
Long version
I'm building a kiosk setup using java applets, and would like to increase the default memory limit for all these applets. The kiosk is based on ubuntu linux, using the icedtea-plugin package as a browser plugin. As building the kiosk is automated and headless, I'd rather configure it from the command line if possible.
Here is what I've found out so far:
I'll probably have to specify a -Xmx… command line argument which will be used when starting the java virtual machine for the plugin.
It is possible to pass such arguments using a parameter in the HTML code, i.e.
<param name="java_arguments" value="-Xmx…">.
But that would mean modifying all my HTML files, which I'd rather avoid. And there is a good chance that I'd have to sign my code to make this work, which adds quite a lot of problems in other places of my project.
On my desktop system, using the Oracle VM, there is an application ControlPanel which I can use to set these command line switches. It seems that the configuration gets written to a file ~/.java/deployment/deployment.properties, where it is associated with the key deployment.javaws.jre.0.args.
That key name is not described in the specs for that file. The number 0 seems to refer to one specific JVM, as represented in one row of the table in the control panel. For each JVM, there are several values besides this args value, all sharing a common index number.
According to this wiki section, IcedTea supports a similar file, located at ~/.icedtea/. Not sure whether that means ~/.icedtea/deployment.properties or rather ~/.icedtea/deployment/deployment.properties. IcedTea does not seem to come with a ControlPanel.
As you can see, there are many hints as to how this might work, but so far I haven't seen any definite answer as to what will work. There are still many open questions:
Do I have to create this icedtea deployment file?
Do I have to include a directory named deployment in the path?
Which is the minimal set of keys that I need to specify to make this file work as intended?
Is the args value even supported by OpenJDK, even if it is not described in the corresponding specification?
I guess I could try out all possible combinations to see whether one of them works, but doing so will take considerable time. So I'm asking here, to see if someone has experience in this, and can provide a quiecker answer. If not, I guess I'll answer my own question eventually, once I've tried things the hard way.
as oracle says: http://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-Desktop/html/plugin.html.
following environment variable should be set to add additional arguments to applets:
_JPI_VM_OPTIONS=-Xmx…
Moreover as the reffered site says:
Please note that you need to restart your browser after you set the environment variable. If you are setting this environment variable in the command shell, then you must use the same command shell to launch the browser so that the browser inherits the value of environment variable.
However if you doubt how to set environment variable in ubuntu, following post might be helpful: Make $JAVA_HOME easily changable in Ubuntu
I just had a look at the source code of the icedtea-web plugin. The part of the code which builds the command line seems to have no provision at all for including custom arguments, no matter their origin. So it does not matter which config files, HTML files or environment variables I edit, the code there will build the same command line to call java, disregarding all my whishes.
So if all configuration fails, what remains is hackery. One approach would be to patch the source code of the plugin, and make it include additional words into its command line. For a static addition, i.e. a single size change, this would be fairly easy. A more general fix would include the content of some environment variable, the way Peter's answer suggests. That would mean word-splitting the environment variable in question, and allocating the space for the array of words dynamically. Quite a bit of work at the C level.
As an alternative, one could tackle this at the level of the executed binary. The plugin apparently has the path of the executable hard-coded into it. In my case, this path is /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java. One can rename that binary to java.orig, and put a shell script in its place, with the following content:
#!/bin/bash
for i in "$#"; do
if [[ "${i}" == sun.applet.PluginMain ]]; then
exec "$0.orig" -Xmx512m "$#"
fi
done
exec "$0.orig" "$#"
One consequence of this approach is the fact that ps will no longer print these applets as java but instead as java.orig. Should not be a problem in most cases.

Is it correct for Java system properties to be used to set and get arbitrary program parameters?

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?

How to pass a system property using Wrapper.exe

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 :)

Where to put global application data in Vista?

Where in a Windows (Vista) system should I place data that ought to be readable and writable by everyone, i.e. every user of the computer? Vista's concepts of C:\Users\xxx\AppData\something, C:\Program Files and C:\ProgramData directories and UAC are a bit confusing.
Furthermore, is there any ready solution to determine those locations with Java? I suppose that it requires some interaction with native libraries, since System.getProperties has just user.home and user.dir, neither of which is globally writable.
In vista c:\ProgramData is the place, this replaces what used to be C:\Documents and Settings\AllUsers\AppData in XP.
I'm not sure about the specifics of doing this in java.. but, the ALLUSERSPROFILE environment variable gives you the path if you can get hold of that. You should always use this instead of hard coding the path, because the folder name changes on different internationalized versions of the OS.
If you need to allow users that do not have administrator privileges to modify the global settings then the proper approach is to create an installer for the application and during the install set the permissions on the "Common Application Data" folder such that users area allowed to write to it.
See this post: Where to put common writable application files?
Unless the data is really large, you might want to take a look at the Preferences API; in particular Preferences.systemNodeForPackage. This gives you a platform-independent, system-wide, backend-agnostic storage facility, if that's what you're after.
Furthermore, is there any ready
solution to determine those locations
with Java?
You can check approrpirate environment variables, for instance %PROGRAMDATA%, %PROGRAMFILES% and others.

Categories

Resources