Rounding up runtime properties

Runtime properties (java -D options) are useful in a development environment to parameterize properties that varies because of workstation and eclipse workspace setup. For example, I have a number of runtime properties to specifiy the database url and super user credentials for database testing:

test.homestate.postgres.url=jdbc:postgresqltest://localhost:5432/fssample
test.homestate.postgres.connectstring=postgres/xxxxxx@fssample

It becomes problematic when these runtime properties grow and there are multiple runtime environments. For example, in my development environment, I have to maintain the runtime properties for eclipse JDK settings, tomcat JAVA_OPTS, jBoss JAVA_OPTS. Also when there are many of these properties, they become difficult to organize and maintain.

One way around this problem with Java 5 (or greater) is to use the java launcher -javaagent option. This option allows you to intercept the call to static void main() method of you runtime class and one of the many things you could do is to manipulate the runtime environment.

Steps

Here are the steps. Create a jar e.g. FSinstrumentation.jar with a class such as follows:

public class PropertyLoadingInstrumenter {

	public static void premain(String agentArgs, Instrumentation instrumentation) {
		String propertyLocation = System.getProperty("runtime.properties");
		try {
			if (propertyLocation != null) {
				Properties properties = new Properties();
				properties.load(new FileInputStream(propertyLocation));
				Set<Object> keySet = properties.keySet();
				for (Object object : keySet) {
					System.err.println("Setting " + object.toString() + " to " +  properties.getProperty(object.toString()));
					System.setProperty(object.toString(), properties.getProperty(object.toString()));
				}
				/*code to close stream snipped for space*/
			} else {
				System.err.println("No runtime properties");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

Ensure that the jar contains a manifest that points to your instrumenter class:

Manifest-Version: 1.0
Premain-Class: ca.intelliware.fs.instrumentation.PropertyLoadingInstrumenter
Created-By: Intelliware FS

Instrumentation

In eclipse change your JDK VM arguments to use this jar file and if necessary, change your tomcat or jboss bat file to provide similar VM arguments.

-javaagent:${workspace_loc}/path_to/FSinstrumentation.jar -Druntime.properties=e:/runtime.properties

Provide a runtime.properties file that contains all the properties at the location specified.

Running tests in eclipse shows the following in console output at startup:

Setting database to oracle
Setting test.homestate.oracle.url to jdbc:oracletest:thin:@//localhost:1521/fssample
Setting selenium.browser to *firefox
Setting path.oracle.bin to E:/oracle/product/10.2.0/db_2/BIN
Setting test.homestate.oracle.connectstring to "system/xxxxxxx@fssample"
<more snipped>

Conclusion

Now you only have one place (runtime.properties file) to provide all the properties and you can also organize the file with some comments. As you can see from the instrumenter class, you can pass additional arguments to the instrumenter using argentArgs. There are many more things you could do with this mechanism and I suggest exploring the java.lang.instrument.Instrumentation interface.

What other uses can you think of?

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply