Tomcat production / dev environments - java

In PHP development, its possible to determine whether or not the app is running in a production or a development environment from the servers 'environment' variable.
Is there a similar variable available on tomcat servers, or is there a better way of targetting applications for production and development?

Every Tomcat instance we have has an isProduction flag defined in the GlobalNamingResources section of the server.xml file.
server.xml:
<Server ...>
...
<GlobalNamingResources>
<Environment name="isProduction" value="false" type="java.lang.Boolean" override="false" />
</GlobalNamingResources>
<Service name="Catalina">
... etc ...
</Service>
</Server>
This allows the property to be available throughout the app by creating a property in the context.xml that references the resource:
context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context ...>
<ResourceLink name="isProduction" global="isProduction" type="java.lang.Boolean" />
...
</Context>
To fetch the value:
public boolean isProduction() {
Object o;
try {
o = (new InitialContext()).lookup("java:comp/env/isProduction");
} catch (NamingException e) {
o = Boolean.FALSE; // assumes FALSE if the value isn't declared
}
return o == null ? Boolean.FALSE : (Boolean) o;
}

You can't do such thing by default.
In any case, do not rely on the container to determine whenever the app is in the environment X. I'd say that you should do it using one of the following methods (in order of preference):
Use whatever your build tool provides. E.g.: use maven profiles. http://maven.apache.org/guides/introduction/introduction-to-profiles.html
Use a property file for the app with a "mode" property.
Pass a -Dmyproject.mode=XXXX property to the JVM
Use an OS system property
I encourage you to use something like #1. For sure you are using some kind of tool to build your app (Ant, SBT, etc).
Imagine if by mistake somebody reinstall Tomcat, remove the OS properties or similar. Your app might run in prod mode.

You could set up OS environment variables in tomcat startup scripts (run.sh at linux environment, for example) and read them from your program. Also you could setup java environment variables (like this: Passing environment variables to a JVM, in a platform-independent manner).
I personally use different property files for dev/prod/etc and read this variable for property file. Only required property file is deployed.

Related

How do I use Multiple Substitutions in Lookups for Log4J 2 configurations? Is it possible?

I have a situation in which I want Log4J 2 to determine which directory to use for logging. The pseudocode is as follows:
property LOG_DIR = "./logs" // default
if (isDIR(${env:LOG_DIR}) {
LOG_DIR = "${env:LOG_DIR}"
} else if (isDir(${sys:catalina.base}) {
LOG_DIR = "${sys:catalina.base}/logs"
}
The configuration I have for properties (in log4j2.xml) is as follows:
<Configuration status="DEBUG">
<Properties>
<Property name="LOG_DIR">${sys:catalina.base}/logs:-logs</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %t/%c:%L | %m%n</Property>
<Property name="JAVA_HEADER">${java:version} - ${java:os}</Property>
</Properties>
<!-- Other configuration here -->
</configuration>
What I think it should look like:
<!-- Is this permitted? What happens if there's no Catalina Base AND no LOG_DIR env var? -->
<Property name="LOG_DIR">${env:LOG_DIR}:${sys:catalina.base}/logs:-logs</Property>
What I'm not sure on is how to get both ${env:LOG_DIR} and ${sys:catalina.base} options in the LOG_DIR property in configuration (before the default of logs). Is this even possible without a programmatic solution? (I'd like to avoid a programmatic solution as this config will be a template for multiple projects, some of which are libraries in SE applications. I'd like to avoid including a library that is only for configuring Log4J.) As far as I know, there can be only one lookup before the default. I don't know if nesting or chaining is permitted.
Today, I encountered the same problem and i stumbled upon this question. I tried at my own end and i was successfully able to solve the issue and accomplish the desired result.
<Property name="LOG_DIR">${env:LOG_DIR:-${sys:catalina.base:-/logs}}/somexyz.log</Property>
sys: It stands for System environment variable, this is for whole PC or your current user.
env: It is the run time environment variable which you configure in runner in Intellij or similar.
According to log4J2 lookup official site: The general format of Lookup is ${sys:SOME_SYS_PATH:-default_path} or ${env:SOME_ENV_PATH:-default_path}.
Now as per your requirement, You want to see if a file path is
configured in runtime environment or not, if yes then save all logs
event data at that place. If no file is configured in runtime
environment then look for system environment, if path is configured
there then save all logging information there else save all logging
information to a default path i.e /logs.
Use below code and it will work for you.
<Property name="LOG_DIR">${env:LOG_DIR:-${sys:catalina.base:-/logs}}/somexyz.log</Property>
If file path is configured in runtime environment then save it there, else check if path is configured in system environment(PC) and save there , else save it in default path /logs.
The previous answer did point out correctly that a lookup expression can be used as the default value inside another lookup expression. My requirement was to allow the configuration to reside outside of WEB-INF and allow two different locations for that. Luckily, this also works for the web.xml configuration:
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>file:///${sys:myapp.home:-${sys:user.home}}/myapp/log4j2.xml</param-value>
</context-param>
If system property myapp.home is not set, user.home will be used instead. This overrules the default location (WEB-INF/log4j2.xml). If the indicated file doesn't exists, only the search on the classpath is left. So I put a fallback configuration into WEB-INF/classes.

Static ressources: where define context aliases with tomcat

I am looking for a way to access static resources (e.g. video files) from my web app JEE.
In my local environment, I added an aliases attribute in the context of my webapp under the config of my tomcat server in Eclipse. This works verywell.
Doing that my context in Eclipse Tomcat server.xml is:
<Context path="/maWebApp" docBase="path/vers/ma/webApp" aliases="/video=/chemin/sur/mon/PC">
Now I want to do the same thing in my production server. But:
under this server (linux, tomcat7), the file etc/tomcat7/server.xml doesn't contains any "Context" for my webapp. I suppose that the context is created automatically during webApp deployment
if I add a "Context" for my application, in order to define the "aliase" attribute, my server tomcat doesn't restart anymore.
So my question is: where should I define the "aliase" attribute when I use Tomcat7 and when I deploy my application with .war generated from Eclipse.
Important note: I don't want to manage the aliases in the webapp, because the aliases change depending on the server (local dev or prod).
Thank you very much for any advise and best practise,
Have a good day!
Adrien
You should be able to add a context attribute to your server.xml.
https://tomcat.apache.org/tomcat-4.1-doc/config/context.html
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" /> <Listener
className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
/> <Listener
className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"
/>
<Context path="/maWebApp" docBase="path/vers/ma/webApp"
aliases="/video=/chemin/sur/mon/PC" />
</Server>
My tomcat is starting fine with this.
What error do you have when starting it with the "< Context .. />" attribute ?
Take a look over here: https://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context
Defining Context elements in server.xml is discouraged. Instead put context.xml in
$CATALINA_BASE/conf/[enginename]/[hostname]/
enginename will most likely be Catalina, so e.g if your tomcat directory is /opt/tomcat7/ and your hostname is www.mysite.com then put the context in this directory:
/opt/tomcat7/conf/Catalina/www.mysite.com
And rename your context file maWebApp.xml
Update: Unless you need the static resources to be available to your app, and if only you need a virtual directory for visitors to access static resources you do not need the aliases attribute. Create a context in a file named video.xml in the same directory as above:
<Context docBase="/chemin/sur/mon/PC/" path="/video/"></Context>
Static resources will then be available at www.mysite.com/video

How to set environment variables in JBoss

We are developing an application that is deployed in a JBoss.
we would like to define a properties files like this:
URL_DEVELOPMENT.properties = ...
URL_TEST.properties = ...
URL_PRODUCTION.properties = ...
and define an environment variable in the JBoss which contains the information about the execution context
for example --> ENVIRONMENT = DEVELOPMENT
Anyone knows:
How to set environment variables in JBoss.
How to get these variables from an applicacion deployed in JBoss in runtime execution?
The easiest and most straight forward way is to log into jboss web admin:
www.yoururl:9990
Then under configuration, look for system property.
At runtime, it is very easy: System.getProperty(yourPropertyKey) and the good thing is that a change in any of these properties is reflected immediately at runtime.
The other scenario is to open up standalone.xml
<server ...>
<system-properties>
<property name="eclipselink.archive.factory" value="org.jipijapa.eclipselink.JBossArchiveFactoryImpl"/>
</system-properties>
</server>
The other option is to read on jboss cli and configure system properties from there. (Only useful if you want to work with remote jboss and you cannot ssh into the server, and you cannot access the web admin)

How to override spring property param with Tomcat?

I have defined property in Spring application.
#Configuration
public class WebappConfiguration {
#Value("${ext.storage.path}")
private String extDirectoryPath;
public String getExtDirectoryPath() {
return extDirectoryPath;
}
}
Default value for ext.storage.path property is defined in application.properties file.
application.properties
ext.storage.path=/home/user/ext/
When I deploy WAR to tomcat with VM options -Dext.storage.path=/var/webapp-data/, this value is loaded successfully. But I would like to load property values more smarter from context files for every environment.
So I deploy the WAR to ROOT of Tomcat, name of WAR file is ROOT.war and it is exploded to ROOT directory. I created context file on path {CATALINA_BASE}/Catalina/localhost/ROOT.xml with following content.
ROOT.xml
<Context
docBase="/opt/webapp-tomcat/webapps/ROOT.war"
path=""
reloadable="true">
<Parameter name="ext.storage.path" value="file:/var/webapp-data/" override="true"/>
</Context>
Unfortunately, the param is not loaded according to the way, it has default value from application.properties.
EDIT:
After a little investigation, I put the Parameter into main context.xml file of Tomcat and the value is overridden.
<Parameter name="ext.storage.path" value="file:/var/webapp-data/" override="true"/>
The best technique I know of is to put environment-specific stuff into Tomcat's conf/context.xml file.
<Environment name="myApp/extStoragePath" type="java.lang.String" value="/var/data/myapp"/>
This defines a JNDI variable that you lookup in your code with something like this:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
String extStoragePath = (String) envCtx.lookup("myApp/extStoragePath");
You can also use this technique to load complex objects like database datasources etc. It has huge advantages:
The configuration is personal to the environment, not the application
You don't need to mess with Tomcat startup scripts
The same binary will run in DEV, UAT and PROD without modification. This much simplifies the build process.
Also, Spring provides a org.springframework.jndi.JndiObjectFactoryBean which can access JNDI from your spring configuration files.

Set specified system property for web application

I have an JavaEE application which needs some certain system properties configured during the runtime.
During the development phase, we set the properties in the .pom.xml to make it work:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<systemProperties>
<xxx>true</xxx>
</systemProperties>
</configuration>
</plugin>
However I wonder how about if we deploy the application in the production environment?
I have though of set the property during the initialization of the servlet, but it seems that I can not modify the system property once the jvm is runing(from this post):
The JVM memory parameters for a Hotspot Java implementation can only
be set via the command line options when the JVM is launched /
started. Setting them in the system properties either before or after
the JVM is launched will have no effect.
And I have tried to set the properties in the web.xml (here):
<env-entry>
<env-entry-name>xx</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>xx</env-entry-value>
</env-entry>
But it seems like it does not take affect.
Then I wonder how to solve it?
BTW, in the production environment we may run more than one application under a shared tomcat, so we prefer to set the properties under the application context only.
Environmental Entries
The <env-entry> won't make it for you because Environmental Entries are availble through JNDI and not through the System properties facade.
So if you configure some entry as below in your deployment descriptor file:
<env-entry>
<env-entry-name>myProperty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>some-value</env-entry-value>
</env-entry>
Accessing the property in codebase as below will return a null reference:
System.getProperty("myProperty");
Though it should be retrieved with a context lookup as follows:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// Look up for your property "myProperty"
String myPropertyValue = (String) envCtx.lookup("myProperty");
The main advantage is that you will be able to have a property which value will vary from one web application to another. But this way, and as the amount of your deployed artifacts will rise, it will be hard to maintain this and I think, based on my humble experience, it is not advised for production environments.
System Properties
If you are targeting a production environment, I advice using system properties (Your code source should then be updated to follow the style).
Since you are using Tomcat as an Application Server, you have one way that will let you have centric property definition, that is to declare a file named setenv.sh (.bat for Windows OS) where you export all the needed System Propeties, e.g of content it might have:
export CATALINA_OPTS="$CATALINA_OPTS -DmyProperty=some-value"
There is no more additional configuration needed, and this file will be processed by default when launching the JVM instance if present under $CATLINA_HOME/bin or $CATLINA_BASE/bin.
you are confusing web.xml env entry with system environment with java system properties
ask your ee server admin to add those in server definition such as
-Dpropname=true

Categories

Resources