nimana – weblog

Using Properties Files in Java Applications (And Autoload)

with 19 comments

Properties files are one of the most frequently used mechanism for storing configuration information for applications. And so is the code to access these properties from the application. This article is intended to demonstrate (source code can be downloaded here) a simple way of configuring and using Properties files in Java applications.

Please note that, the mechanism is not limited to properties files. The approach supports XML configuration files as well.

The steps are defined below and as we move along, we’ll try and explain the rationale for each of the items:
1.    Define System variable for properties file location. Define a system/environment variable that points to the folder, where the properties files will be placed. Finding the properties files through a system/environment variable is straight-forward and helps avoid the classpath issues often found using properties files in webapps. In cases where a system/environment variable cannot be defined, this variable can be passed to the application as an argument. For e.g., java –D APP_PROPS=d:/Properties App

Let’s say the environment variable is called APP_PROPS and it points to D:/Properties. For demonstration, let’s assume there’re two properties files:
a.    app.properties
b.    security.properties

2.    The Properties Store. The properties store (class PropStore), will be used by the application code to fetch properties. For e.g., the following code reads the application title from the app.properties file.

String title = PropStore.getAppProps(“title”);

Let’s get into the code and see how the PropStore will be structured and how do we add new properties.

Structure. The properties store will have a static “Properties” field, for each “properties” file annotated with a custom annotation (PropertiesHolder, defined later). For e.g.,

public class PropStore {
	@PropertiesHolder(file="app.properties", autoLoad=true)
	private static Properties appProps;

	@PropertiesHolder(file="security.properties")
	private static Properties securityProps;

	public static Properties getAppProps() {
		return appProps;
	}
	public static Properties getSecurityProps() {
		return securityProps;
	}
	protected static void setAppProps(Properties appProps) {
		PropStore.appProps = appProps;
	}
	protected static void setSecurityProps(Properties securityProps) {
		PropStore.securityProps = securityProps;
	}
}

For now, assume, the properties appProps and securityProps are magically loaded. So, the following code sippet can be used in the application code to read securityProps:

String appUser = PropStore.getSecurityProps().getProperty("APP_USER");

To add another properties file, all that needs to be done is add a static field, annotate it with PropertiesHolder with the properties file name as the file attribute, and define a public getter.

3.    PropertiesHolder. PropetiesHolder is a custom annotation, that we will use to annotate fields in the PropStore, and set the properties file that field will go against.

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertiesHolder {
	String file();
	boolean autoLoad() default false;
}

4.    Loading Properties. Properties file need to be loaded at application startup since the application code uses the properties files. We’ll load the properties using PropsLoader class as demonstrated below. PropsLoader can then be used by a startup class (a startup servlet in webapps, or a bootstrap class in a desktop application, for e.g.).

Here’s what the PropsLoader does to load the properties files:
i.    Introspect the PropStore to get declared fields.
ii.    Loop on the fields and check if the field is annotated with PropertiesHolder.
iii.    If it is annotated with PropertiesHolder, create a “Properties” object and load the properties file (set with the file attribute of PropertiesHolder).
iv.    Call the appropriate setter, on the PropStore with this “Properties” object.
v.    Please note that if there’s a XML configuration file, another reading mechanism can be provided and a Properties object be built from that.


public class PropsLoader {
	private static final String VAR_NAME = "APP_PROPS";
	//TODO: Better Exception Handling
	public static void load() throws Exception {
		Field[] fields = PropStore.class.getDeclaredFields();
		for(Field field:fields) {
			if( field.isAnnotationPresent(PropertiesHolder.class) ) {
				PropertiesHolder propsHolder = field.getAnnotation(PropertiesHolder.class);
				loadPropsAndWatch( field.getName(), propsHolder );
			}
		}
	}
	//TODO: Better Exception Handling
	private static void loadPropsAndWatch(String fieldName, PropertiesHolder propsHolder) throws Exception {
		String propsFile = System.getProperty(VAR_NAME) + File.separator + propsHolder.file();
		loadProperties(fieldName, propsFile);
		if( propsHolder.autoLoad() ) {
			PropsWatcherTask.watch( fieldName, propsFile, propsHolder );
		}
	}
	//TODO: Better Exception Handling
	protected static void loadProperties(String fieldName, String propsFile)
			throws Exception {
		String setterName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
		Method setter = PropStore.class.getDeclaredMethod(setterName, Properties.class);

		Properties props = new Properties();
		props.load( new FileInputStream(new File(propsFile) ) );

		setter.invoke(null, props);
	}
}

5.    Auto Load. Although, not an absolute essential, sometimes, the properties files need to be auto-loaded in case there’s a change while the application is running.

To auto load properties, the PropsWatcherTask:
a.    Schedules itself to run every “x” minutes, and check the last modified time of the properties file to watch.
b.    If the new modified timestamp is newer than the timestamp used to build the task, the properties file is reloaded and the local timestamp set accordingly.


public class PropsWatcherTask extends TimerTask {
	private String propsFile;
	private long lastMod;
	private String fieldName;
	private final static Timer timer = new Timer();
	private static final long INITIAL_DELAY = 1000 * 60 * 5;
	private static final long INTERVAL  = 1000 * 60 * 5;

	private PropsWatcherTask(long lastMod, String fieldName, String propsFileName) {
		this.propsFile = propsFileName;
		this.lastMod = lastMod;
		this.fieldName = fieldName;
	}
	@Override
	public void run() {
		//check last modified time.
		long newModTime = new File(propsFile).lastModified();
		if( newModTime > lastMod ) {
			try {
				PropsLoader.loadProperties(fieldName, propsFile);
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.lastMod = newModTime;
		}
	}
	protected static void watch(String fieldName, String propsFileName, PropertiesHolder propsHolder) {
		File propsFile = new File(propsFileName);
		long lastMod = propsFile.lastModified();
		timer.scheduleAtFixedRate( new PropsWatcherTask( lastMod, fieldName, propsFileName ) , INITIAL_DELAY, INTERVAL );
	}
}

6.    Test. The following simple JUnit can be used to test the PropsLoader for both auto load and otherwise.


public class PropStoreTest {
	@Before
	public void load() {
		try {
			PropsLoader.load();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testProperties() throws Exception{
		Assert.assertEquals("ABC Desktop", PropStore.getAppProps().getProperty("APP_TITLE"));
		Assert.assertEquals("ADMIN", PropStore.getSecurityProps().getProperty("APP_USER"));
	}
	@Test
	public void testAutoLoad() throws Exception {
		write("APP_TITLE=New ABC Desktop");
		synchronized(this) {
			this.wait(45 * 1000);
		}
		Assert.assertEquals("New ABC Desktop", PropStore.getAppProps().getProperty("APP_TITLE"));
		write("APP_TITLE=ABC Desktop");
	}
	private void write(String text) throws Exception {
		PrintWriter pw = new PrintWriter( new FileWriter(System.getProperty("APP_PROPS") + File.separator + "app.properties"));
		pw.print(text);
		pw.close();
	}
	public static junit.framework.Test suite() {
        return new JUnit4TestAdapter(PropStoreTest.class);
    }
}

Note the PropsLoader.load() being called from the load method of PropStoreTest. The PropsLoader.load() call will generally be made from some startup class (like a startup servlet, etc). To run the test, make sure the APP_PROPS variable is passed as a JVM parameter, or is set in the system properties.

Click here to download the source code. Tester.zip contains the Tester folder, which can be directly imported into Eclipse. If you wish to run this with ant, use Tester/build/build.xml. (Please change the value for APP_PROPS on line 9 in build.xml).

(Please note, that most of the modern web based frameworks do have some sort of Properties/configuration framework built in. Also, there’s commons configuration project from Apache that provides a comprehensive support enabling Java applications to read configuration data from variety of sources. This article is intended for applications that do not have such frameworks/facilities available).

Properties files are one of the most frequently used mechanism for storing configuration information for applications. And so is the code to access these properties from the application. This article is intended to demonstrate a simple (Simple to use from the app and easy to maintain) way of configuring and using Properties files in Java applications.

Please note that, the mechanism is not limited to properties files. The approach supports XML configuration files as well.

The steps are defined below and as we move along, we’ll try and explain the rationale for each of the items:

1. Define System variable for properties file location. Define a system/environment variable that points to the folder, where the properties files will be placed. Finding the properties files through a system/environment variable is straight-forward and helps avoid the classpath issues often found using properties files in webapps. In cases where a system/environment variable cannot be defined, this variable can be passed to the application as an argument. For e.g., java –D APP_PROPS=d:/Properties App

Let’s say the environment variable is called APP_PROPS and it points to D:/Properties. For demonstration, let’s assume there’re two properties files:

a. app.properties

b. security.properties

2. The Properties Store. The properties store (class PropStore), will be used by the application code to fetch properties. For e.g., the following code reads the application title from the app.properties file.

String title = PropStore.getAppProps(“title”);

Let’s get into the code and see how the PropStore will be structured and how do we add new properties.

Structure. The properties store will have a static “Properties” field, for each “properties” file annotated with a custom annotation (PropertiesHolder, defined later). For e.g.,

For now, assume, the properties appProps and securityProps are magically loaded. So, the following code sippet can be used in the application code to read securityProps:

String appUser =

PropStore.getSecurityProps().getProperty(“APP_USER”);

To add another properties file, all that needs to be done is add a static field, annotate it with PropertiesHolder with the properties file name as the file attribute, and define a public getter.

3. PropertiesHolder. PropetiesHolder is a custom annotation, that we will use to annotate fields in the PropStore, and set the properties file that field will go against.

4. Loading Properties. Properties file need to be loaded at application startup since the application code uses the properties files. We’ll load the properties using PropsLoader class as demonstrated below. PropsLoader can then be used by a startup class (a startup servlet in webapps, or a bootstrap class in a desktop application, for e.g.).

Here’s what the PropsLoader does to load the properties files:

i. Introspect the PropStore to get declared fields.

ii. Loop on the fields and check if the field is annotated with PropertiesHolder.

iii. If it is annotated with PropertiesHolder, create a “Properties” object and load the properties file (set with the file attribute of PropertiesHolder).

iv. Call the appropriate setter, on the PropStore with this “Properties” object.

v. Please note that if there’s a XML configuration file, another reading mechanism can be provided and a Properties object be built from that.

Below is the code snapshot that loads the properties.

5. Auto Load. Although, not an absolute essential, sometimes, the properties files need to be auto-loaded in case there’s a change while the application is running.

To auto load properties, the PropsWatcherTask:

a. Schedules itself to run every “x” minutes, and check the last modified time of the properties file to watch.

b. If the new modified timestamp is newer than the timestamp used to build the task, the properties file is reloaded and the local timestamp set accordingly.

6. Testing. The following simple JUnit can be used to test the PropsLoader for both auto load and otherwise.

Note the PropsLoader.load() being called from the load method of PropStoreTest. The PropsLoader.load() call will generally be made from some startup class (like a startup servlet, etc). To run the test, make sure the APP_PROPS variable is passed as a JVM parameter, or is set in the system properties.

The code is attached with this article. Tester.zip contains the Tester folder, which can be directly imported into Eclipse. If you wish to run this with ant, use Tester/build/build.xml. (Please change the value for APP_PROPS on line 9 in build.xml).

About these ads

Written by nimana

January 22, 2010 at 8:18 pm

Posted in Tech

Tagged with , , , , ,

19 Responses

Subscribe to comments with RSS.

  1. The main thing that I don’t like with this approach is that you end up tying the name and location of a configuration file to the place where actual properties defined in that file are actually used. That’s a really bad idea and several steps down from what you would get with e.g. Spring.

    Two problems with:
    1) overriding with -D no longer works, a common mechanism used for configuration in production systems or staging configurations.
    2) you hardwired the location of the configuration file as well (i.e. no override possible with an alternative location).

    What I actually would love to have is a way to tie a property name to a property (with an annotation) and have whatever the value of that property is in whatever configuration you have bound there at run-time, and optionally even have the property and all the places it is used be run time configurable through an mbean (propertychange events for bonus points).

    The only thing that should be referred in your code is the name of the property.

    So something like:

    String myProperty = “default value”;

    @PropertyValue(name=”com.domain.propertyname”)
    public void setMyProperty() {

    }

    You could even make the property name optional and just use package.classname.propertyname instead.

    Jilles van Gurp

    January 26, 2010 at 7:00 pm

    • Thanks for the inputs Jilles van Gurp.

      Here’re my thoughts about your concerns:
      1) overriding with -D no longer works, a common mechanism used for configuration in production systems or staging configurations.
      Most of the app servers in the market have some standard mechanism for setting JVM parameters. And yes even in production systems. Even if the app server does not give that option, the variable can be set as an environment variable at the OS level.
      2) you hardwired the location of the configuration file as well (i.e. no override possible with an alternative location).
      The location is not hardwired (Its not within the code). Its in the JVM variable (APP_PROPS as in our example).

      As for @PropertyValue, yes, that’s a route we can go.
      If you define the property at the class level (where its used), we’ll need to inject the property. Which can be done but which is more complex then it has to be.

      nimana

      January 26, 2010 at 7:38 pm

  2. I would just use Spring bean configurations. That way you dont ever have to say getProperty(“…”), you just make getters and setters and the config values are set for you. You also get a clean syntax for representing property values that are not primitives (like arrays, maps, and nested objects). You also get a mechanism for referencing other objects by name.

    William Shulman

    January 26, 2010 at 8:14 pm

    • Thanks for the inputs William. This is meant more for applications/frameworks where something like Spring bean configurations is not available or a mechanism to read/configure configuration files does not exist.

      nimana

      January 26, 2010 at 8:55 pm

  3. You would unnecessarily spawn a thread to load a properties file and then shutting the down the server might leave this thread dangling, not always the safest way. Also for something that changes rarely , keeping a thread running and checking every 5 min or even 1 hr is a useless processing.

    A different way that I do in my projects is simply expose a JMX Bean with a method(s) called “refreshProperties()”. You could have the option of either setting the location of properties file at the startup using the -D or simply write a “refreshProperties(String filePathLocation” method. The refresh method would simply do the same thing that you do in your run method.

    I mean for something that changes very infrequently (we almost never change stuff in production) spawning and managing thread and ofcourse the whole check every min is an unnecessary overhead.

    Satish

    January 26, 2010 at 9:18 pm

    • Thanks for the inputs Satish! Yeh, JMX is definitely a nice alternative for the purpose.

      As for your comments on the timer interval (5 minutes), the values used in the example were consciously set low for testing purposes. In real life, if ever you need to reload you’d set that value to a more reasonable value.

      nimana

      January 26, 2010 at 9:45 pm

  4. As you said, its good when we are not using advance framework.

    Thanks for sharing your ideas

    Jhonny

    January 27, 2010 at 12:28 am

  5. JMX & the Preferences API eliminates the need for all of this code.

    Its all built into the JVM already.

    David Seymore

    January 27, 2010 at 3:35 am

    • David, Thanks for the comments! I understand the that the preferences API can be used to store configuration data. However, I feel it would be an overkill for simple apps, both from usage as well as configuration perspective.

      nimana

      January 27, 2010 at 3:49 am

  6. Hi,

    I´ve done something similar in jEmbedded (http://code.google.com/p/jembedded) using a PropertiesService to parse the attributes of annotations/services:

    @Compose
    @AnnotatedPropertiesService(propertiesFile=”service.properties”)
    public abstract PropertiesService getPropertiesService();

    You don´t need to use the getProperty() method as is built in the framework (still you can do it).

    Adolfo Estevez

    January 27, 2010 at 7:20 am

  7. I use a configuration solution that scans the classpath and specified additional directories for multiple configuration files, e.g.
    – configuration.properties
    – configuration_mycomputername.properties
    – configuration_servletcontext.properties
    This allows to have special settings for special environments.

    Naturally it also is possible to do this inside one configuration file, e.g.:
    – jdbcuser=mydev
    – jdbcuser[computername|production01]=myprod

    This mean there is a default jdbcuser, but it is overriden in production. However, datacenter guys do not like their information to be present in configuration files at development time, so that is the reason for the multiple configuration files.

    And you can also use XML instead of properties, because that is easiers for groups of settings.

    tbee

    January 27, 2010 at 8:39 am

  8. Hi nimana,
    I liked your approach. Are you going to publish it?
    I have a suggestion. In many enterprise environment more than one application could be deployed in the same appserver. With your approach of setting the path of the filesystem where properties are stored using a system property there no way to distinguish two different application. A way to workaorund this is to add another attribute to the propertiesHolder annotation, an attribute that would allow you to specify the system property to use.

    raffaele spazzoli

    January 27, 2010 at 9:58 am

    • raffaele spazzoli, the environment variable name is application specific.

      nimana

      January 27, 2010 at 2:13 pm

    • raffaele spazzoli, the environment variable name is application specific.

      nimana

      January 27, 2010 at 2:13 pm

  9. […] This post was mentioned on Twitter by bubbl and linking4u, Aitor Iturriozbeitia. Aitor Iturriozbeitia said: Java – Java – Java http://nimana.wordpress.com/2010/01/22/using-properties-files-in-java-applications-and-autoload/ […]

  10. Using of JMX has issues, e.x. you can’t use Mbean methods for managed servers on Weblogic and it’s hard to synchronize Mbean params on all servers in cluster etc.

    scof

    January 27, 2010 at 2:00 pm

  11. Cool little snippet.

    One design issue though is that you’re using static members of the PropStore class for storing properties. The two problems with this are (1) accessing static members causes hard-coded dependencies that make unit testing harder, and (2) If you have multiple applications running in the same JVM (for example, if you have multiple WAR files loaded in JBoss/Tomcat/Jetty/etc), then this may not work.

    James Kingsbery

    January 27, 2010 at 2:10 pm

  12. How about using JNDI approach? Normally all JEE based applications servers provide this mechanism(i.e. file based URLs thru JNDI name). You have to configure those the way you configure your data source for any JEE based web applications based on your deployment environments

    Rama

    January 27, 2010 at 4:39 pm

    • Rama, use JNDI to do what?

      nimana

      February 19, 2010 at 2:23 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: