Java - control flow of application with environment variables - java

This is more of a general best practice question regarding environment variables and their uses in Java.
Let's say I have an web application (1) that uses web services to target another application (2). I want in pre-prod environments to keep this link as optional in the flow of the application: if application 2 is down, I want to target a mocked server, that always gives back an answer.
How do I do this the best way?
I was thinking I can use an environment variable like app1.usemockserver = false. When I know that app 2 is down, I can set app1.usemockserver = true, and with an IF in my code I can target the mock server, and not application 2.
Is it something wrong doing it this way? What alternatives could I use?

This one would be difficult using environment variable as JVM will pick up all environment variable that was defined when JVM was launched. Anything chnaging there after wont be picked up.
I would suggest you look at JMX and expose a bean which will set the boolean flag to switch from one environment to the other dynamically within existing JVM.
You could even expose RPC call to JVM to set/reset the boolean flag but i would prefer JMX.
Another way would be to have a load balancer service running on top of your service which will do hearbeat and once it doesn't hears from respective servcie, it switches over to the other.

Based on what SMA answered, I think the best choice would be in fact using JMX.
But, to have something fully automated, that falls back to a mocked web service, JMX could be used in conjuncture with a modified circuit-breaker, like in this framework:
Spring in Practice - kite
So, when the circuit-breaker opens, it could just target the mocked web service.

Related

In AEM how can I get project environment into my sling model

I need to use the environment in my sling model (dev|prod etc, not runmode such as author|publish). How can I inject it into my core model?
Is there any service for this ?
dev|prod etc, not runmode such as author|publish
author and publish are among the fixed run modes but run modes in general can be used to tell dev from prod (or similar kinds of environments) as well.
Usually, when AEM environments need to be told apart, e.g. dev vs prod, it is realised through custom run modes. While AEM as a Cloud Service places some limitations on just how much you can customise, the case you mention is still covered OOTB. Among other things, it can be used to manage environment-specific OSGi config.
An on-premise/hosted deployment gives you even more flexibility. I've always used customized run modes for this kind of purpose.
One thing to note is that it does raise an eyebrow that you need to programmatically check the run mode in a Sling Model. I'm not sure what you're implementing but if a piece of functionality is dependent on the environment, I'd rather handle it via alternative OSGi configuration assigned to a given run mode. I think it's generally easier to add another configuration as a sling:OsgiConfig node when required, as opposed to adjusting conditional logic in a Java class that only recognises a predetermined set of environments.
Provided that you have a set of run modes like this, you could inject SlingSettingsService into your model and read the run modes this way. Or you could write an OSGi service to encapsulate whatever logic you need. Such a service would start up with the configuration relevant to a given environment and you could inject it directly into your Sling model, knowing the values it returns are the ones you need.

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.

Using System Properties in 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 ...

Executing a class in remote jvm

I have a small test class that I want to run on a particular jvm that's already up and running (basically it's an web application running on Tomcat) . The reason I want to do this is I want to execute a small test class (with the main method and all) within that jvm so that I get the same environment (loaded and initialized classes) for my test class.
Is it possible to indicate that ,say through a jvm parameter, that it should not initialize a new vm to execute my class but instead go and execute on the remote vm and show me the result here, on my console. So the local jvm acts as a kind of thin proxy ?
I am not aware in case there are some tools that should make this possible .Also heard somewhere that java 6 jvm comes with an option like this , is that true ?
Please help me.
Thanks,
After reading this question and the answers, I decided to roll my own little utility: remoteJunit
It is lightweight and dynamically loads classes from the client to the server JVM. It uses HTTP for communication.
You might want to take a look at btrace. It allows you to run code in an already started JVM provided you don't change the state of the variables inside that JVM. With this kind of tracing, you might be able solve your problem in a different way. Not by running extra code in form of a new class but by adding safe code to and existing class running inside a JVM.
For instance, you might System.out.println the name of the file when there is a call to File.exists.
You might find JMX useful. Register an MBean in the server process. Invoke it with visualvm (or jconsole). (tutorial) Never tried it myself, mind.
RMI would also do the magic.
http://java.sun.com/javase/6/docs/technotes/guides/rmi/index.html
Make your web application start an RMI registry and register your service
beans there.
Then in other JVM you can run a program that queries the RMI registry
started by your web application for the services you want to verify
and you are done.
I assume "small test class" is basically some debugging code you want to run to monitor your real application, which is deployed remotely on a Tomcat. If this is the case, you should connect your Eclipse debugger remotely to the Tomcat instance, so you can set a breakpoint at interesting locations and then use the Display view of Eclipse to run any arbitrary code you might need to perform advanced debugging code. As java supports Hot Code Replacement using the debug mechanism, you can also change existing code on the remote side with new code at runtime.

Categories

Resources