Using System Properties in Java - java

I have a question on using System Properties in Java. Some classes like Authenticator require that we set the system properties regarding Proxy settings and than verify whether the Proxy was valid or not.
My question is should I remove the Set Properties after I am done using it ?
There are other parts of programs that might be using these Properties, this change will autmatically impact thier functionality.
Is there a way, I can set Properties local to a Function (some wrapper class)?
What are the good practises for setting system properties and using them ?

Things that use System.properties should have properties that have a global meaning to the running JVM, so that if, for example, you set a proxy, it should be the relevant proxy across that process.
So therefore there is no need to set them back. In fact, setting them back might make some APIs confused, as they may assume they get back the relevant value at all times, and didn't just cache it when they read it.
Of course if a given API isn't using them that way, then you might have issues, but that would really be an issue with a given API, more than a good practice issue with System properties.
In general, due to threading and synchronization issues, it is probably a good practice to set System properties only at the beginning of the JVM startup (either on the command line or in the main thread before starting other threads) with the expectation that the values remain unchanged for the remainder of the time running the JVM.

This doesn't answer your question about system properties in general, but regarding your specific problem with proxy settings properties, perhaps you can use a ProxySelector to isolate the Test Proxy you mention in the comments here?
You could create a subclass of ProxySelector that you utilize for the test. Make it such that it only applies the test settings when the test URI is attempted. This would isolate it from other requests.
This sort of global proxy setting inflexibility is what initially drove me to use HttpClient for HTTP needs instead of Sun's API.
Edit:
I'm not sure how I ever missed this method, but it is possible to get a URL connection and supply the proxy settings to that connection alone via java.net.Url.openConnection(Proxy)
.

If there is a chance that some other part of your program (or some other webapp in the container, etc) might be affected by "temporary" settings then it is a good idea to remove them.
Best practice would be to try an find some other way to do what you are trying to do. For example, consider creating your own protocol class that overrides a standard one in the area where it figures out what proxy to use.
If you cannot do that, try to structure your code so that the sequence:
change the properties,
do the operation,
restore the properties,
is done in a mutex that respected by anything that might be affected by the properties you are changing. This may be a hard ask though ...

Related

Can SpEL be passed an enviroment variable directly or is a properties file in some form always required?

We build micro services and I am working on a generic way of generating documentation for them. This has created a situation where I need to set a variable which is static across all our services yet has two possible values depending on the environment the service is deployed in. Hence I would like to inject a value based directly on an environment variable rather than through my Application.yml file, and it's various profiles, as I would usually do. Is there any way to do this?
Here is an example of what I imagine this would look like (with a syntax similar to what it would have looked like if it was a regular property in Application.yml):
#Value("#{enviromentProperties['environment'].equals['production'] ? jupiter : mars}")
private String APIGatewayHostname;
Just to be clear we have situations where we deploy several profiles behind the same proxy. Hence we want the hostname reference to be the proxy host so people don't attempt to call the service directly as this is not possible. We only have one proxy per environment regardless which profiles we are running at any given time hence my desire to use an environment variable rather than a property. Also this proxy is not really a part of the design of the services themselves so it seems counter intuitive to store it in multiple profiles in the Application.yml file.
NB: If there are other better ways to accomplish this feel free to let me know :)

Can you use multiple proxies at once in java?

I'm coding my server in java, and through the day, my server has to connect through 5 different proxies at once to other servers and gather data. However, reading about java proxy settings through stackexchange, I see that when you set a proxy, its effect is VM-wide, meaning whatever network activity that .jar was doing, it will do it through a proxy if somewhere a different thread sets a proxy setting within the jar.
I'm currently using this method of setting a proxy, which according to some tests it's actually pretty functional and works fast.
System.getProperties().put( "http.proxyHost", host );
System.getProperties().put( "http.proxyPort", port );
However, I can't really afford having 5 jars doing the same thing with different proxies, I tried it to, it would be a simple solution however I can't afford to use that much ram only for this, as my server is huge.
You need to call each connection with its own proxy settings. The Answer here by NickDk defines how you can call a url with its own proxy settings. You will need to do the same with each of your 5 proxies separately.
here is described the use a library embeded in the JRE, able to handle "proxypac" files in wich any combination of proxies can be defined.
since it is embeded in the JRE, standard ways to configure a Java application with a proxypac file (standard launch optional parameters) might exist, but I am not aware of it.
Howhever the solution described in the link provided should fit your needs since your usage is programatic.

JDK7u21 RMI changes

The Release Notes of JDK7u21 specified the changes related to RMI:
From this release, the RMI property java.rmi.server.useCodebaseOnly is
set to true by default. In previous releases the default value was
false.
This change of default value may cause RMI-based applications to break
unexpectedly. The typical symptom is a stack trace that contains a
java.rmi.UnmarshalException containing a nested
java.lang.ClassNotFoundException.
If these exceptions occur, the preferred way to solve the problem is
to configure all RMI clients and servers to use the same codebase, by
specifying proper values in the java.rmi.server.codebase system
property. This is typically done by adding the -D option to the
command that starts up the application: java
-Djava.rmi.server.codebase=file:////(path-to-remote-classes)/
It also specified in the documentation here that workaround is to set the java.rmi.server.useCodebaseOnly property back to false.
However, even when I explicitly set this property to false, I am getting an exception mentioned above. Any clue here please?
And if I have to solve it by the preferred way described above (by setting the -Djava.rmi.server.codebase=file:////(path-to-remote-classes)/, then which path should I set over here? My workspace/bin?
You have to make sure to set the properties on all JVMs that are using your remote classes. This includes your RMI server, the RMI clients, and the RMI registry. If they are all on the same machine, then you can set java.rmi.server.codebase on them all to a file: URL that points to the location of the classes. If they're not on the same machine, then you could make the classes available using an HTTP server, and then set the codebase property of the remote JVMs (presumably the clients) to use an http: URL that points to where the classes are available. Or you could make the classes available to remote JVMs through some other means, such as copying them, or using a shared filesystem, and then set the codebase property to a file: URL.
Your attempt to apply the workaround of setting java.rmi.server.useCodebaseOnly to false might not be working for a couple reasons: you might not have set it in all of the interacting JVMs, or you might not have set the codebase property to the right value.
Since you're having to go to the trouble of configuring the registry and all the clients, you might as well pursue setting their codebase property to the right URL, instead of pursuing the workaround of setting useCodebaseOnly to false.
You would need to either:
Set it to false at all the JVM(s) which download classes, and ensure that java.rmi.server.codebase is set to something useable at all the JVMs which send objects whose classes may need downloading, or
Leave it alone but make sure that every JVM in the system is started with a java.rmi.server.codebase property that points to a useable codebase for that JVM.
It's a very strange change to make. I don't see any security implications, just a nuisance change that changes semantics at all the codebase recipients. With useCodebaseOnly=true, you have to set java.rmi.server.codebase at the receiving JVMs, where otherwise you only have to set it at the sending JVMs. This isn't clear from the documentation.
I am sorry, I solved it on my own. The problem was wrong number of parameters were being passed to my .ksh file. This caused the problem starting RMI registry.

Centralized Application properties for multiple system

I am looking for a open-source solutions which allow hosting different properties for different applications and allow changes. On any change of properties it should notify or push the change to the application appropriately.
So, instead every application managing the properties in physical file and deploying physically; these properties can be pushed to a single system. User will have GUI to load and change the properties as per right. Should allow push as mentioned.
If you have already similar open source solutions in mind please advice.
Is this something that Puppet can manage for you?
I don't think what you've described (as nice as it would be) will be likely to exist in an app server. If a program is looking for a file, it's either going to load it with a FileReader (or similar), or it will use ClassLoader.getResourceAsStream(). It might be looking for data that is returned in properties, format, XML properties format, or even something completely different like RDF with which to configure itself. Also many programs read their config on start-up and then hold the values in memory, so you would still need to reboot them to get them to change.
To get something like this to work there would need to be a standard for configuration provisioning and live updates. Once that existed the webapp authors and server vendors would each need to add support for the standard.
If you are the one writing the programs to be managed however, then you can write your programs to request configuration from a service, and have a configuration push feature.... there may be packages out there that can speed up adding that to your code, but I get the impression you are looking to manage programs written by others.
Have you considered to use JMX? I think he could be a good starting point to implement your requirements.
MBeans's attributes can store your application's properties, the MBeanServer will allow you to make them available from remotting, JConsole offers you an GUI to update properties values.
You also can write within the MBean some code that notify the corrrespondig application when a user change any properties using the GUI.

How to tell if a system property comes from human operator, not from default?

I have a JAR-packaged standalone application that, when executed, unpacks itself into a temporal directory and spawns a child process within that directory. The reason being some third-party code and configuration assumes data files are found relative to current working directory, and java has no chdir() method, so the only way is to switch the working dir for a child process.
All works fine, except for the system properties. An operator may decide to specify some system properties in the command line, both standard ones and ones related to the third-party configuration:
java -Djava.io.tmpdir=/temp -Dsomething=else -jar foo.jar (parameters)
The system properties available to the parent java process are not by default propagated to child. I should do it myself. And here I get into a roadblock: I have no way to tell which properties are set by operator and which are initialized by default by JVM.
Take that java.io.tmpdir one. If operator has provided it, he has a good reason to do so (perhaps the default location is "disk full"). I have to set it to child process, or it will fail. But how do I know if it came from operator? It may be just the default value.
I may try and set all available system properties to the child process. It takes a long list though and, worse, fails in some environments where the command line length is limited.
The only workaround I've found so far (quite a wicked one) is to spawn another child process first, with no arguments at all, and let it pipe back to the parent all the system properties it has. The values that match those that parent has are defaults. The rest should be passed down to the worker child process.
Does anyone have a better alternative?
Where I work, we had a slowly growing list of system properties that users could apply, and while we did not have the child process to worry about, we did have a different issue: there were simply too many.
Rather than making the user supply system properties via the command line (or, in our case, making the line in the script that launches the application yet another property longer), we added support for loading a .properties file by default.
If you can convince users to put permanent properties there, then start the process of launching the child process, and then loading from the file, you could avoid the headache altogether.
Still, you would likely be presented with debug scenarios where temporary, or one-time properties are desired without modifying the file (not that it's really a big deal). You have a few choices here:
Continue to use the approach you are currently.
Get the user to pass the system properties as command line arguments that you then load into system properties for both the parent and child process.
Say tough, use the file. (Not a terrible thing, but I would be annoyed with that solution as a user)
I don't think there is a good answer to this. But fortunately, most of the standard system properties either can't be overridden, or nobody in their right mind would override.
So the following approaches are probably your best bets:
pass on the subset of the standard properties that you think that it makes sense to pass on,
provide a way to specify the JVM options (including -D options) to be used for child JVMs, or
a combination of the above approaches.
Chosen solution:
I still had to go with a child process that does nothing but passes the parent all the system properties it gets to compare. The only minor issue I stumbled upon was line.separator property which caused my line reading code stumble on extra empty line. That was easy to fix.
Why I accepted none of answers:
Approaches suggested in the answers below are reasonable, but none of them is completely satisfying.
I do not have much power over the users to tell them that Java system properties should be passed via a property file or a special command-line argument. This is awkward and goes against operational practices (special cases are always bad).
I cannot also select a subset of system properties to pass to the child process. System class documentation doesn't tell which ones are OK to overwrite (and common sense replaces no documentation). There is also a facility for end-user to define their own properties, and those I cannot predict neither by name no number.

Categories

Resources