EmailLinkedInGoogle+TwitterFacebook

Source code available @
svn checkout https://whiteboardjunkie.googlecode.com/svn/trunk/properties-dynaload properties-dynaload
Browse Source code here

I have written a tool to automatically reload a property file on file change. This tool came very handy when implementing stand alone server applications that cannot resort to a server restart for refreshing properties. The class itself is a simple construct that spawns a LOW_PRIORITY thread to monitor the property file and reload the properties when the file has changed. To address some specific use cases where the system should be notified of such a reloading of properties I have also provided a mechanism to add listeners. In the following sample snippet an instance of AutoRefreshingProperties is instantiated against ‘config/configuration.properties’. We are also adding two listeners who are interested to know of any file changes.

	static final File destFile = new File("target/test-classes/config/configuration.properties");
	static Properties properties = null;
	@BeforeClass
	public static void beforeClass() throws Exception{
		properties = new AutoRefreshingProperties(null,destFile.getAbsolutePath())
					.addListener(new FileChangeAdapter() {
						@Override
						public void notifyFileChanged(Properties properties) {
							System.out.println("LISTENER1 : Properties have changed...");
							System.out.println("my.property1=" + properties.getProperty("my.property1"));
						}
					})
					.addListener(new FileChangeAdapter() {
						@Override
						public void notifyFileChanged(Properties properties) {
							System.out.println("LISTENER2: Properties have changed...");
							System.out.println("my.property1=" + properties.getProperty("my.property1"));
						}
					});
	}

To test whether the gig really works we are then changing the contents of the properties file by copying over another properties file to the same location. From my experience I can relate to this test case very well since there are dozens of instances where restarting a running server is not an option to change a simple property.

		copyNewPropertiesFile("target/test-classes/master-config/configuration1.properties");
		Thread.sleep(4);
		assertEquals("foo1", properties.getProperty("my.property1"));
	}
	private synchronized void copyNewPropertiesFile(String fromPath)throws Exception{
		FileUtils.copyFile(new File(fromPath), destFile);
	}

The resulting output clearly shows that the test passes, the properties have changed and both the notifiers are notified.

/*
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.boni.dynaload.TestDynamicPropertyLoading
LISTENER1 : Properties have changed...
my.property1=foo
LISTENER2: Properties have changed...
my.property1=foo
LISTENER1 : Properties have changed...
my.property1=foo1
LISTENER2: Properties have changed...
my.property1=foo1
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
*/

The source code that did this auto loading is not very complex either. It extends the java.util.Properties and adds a new constructor that accepts an absolute file path as the location of the property file that needs auto loading. This suffices the problem I am trying to solve since it is highly unlikely that one needs to change a property file embedded in a jar file. More often than not a fix folder (say ‘config’) houses the configuration files and this folder is added to the classpath.

class AutoRefreshingProperties extends Properties{
	private long LAST_LOADED = System.currentTimeMillis();
	private List listeners = Collections.synchronizedList(new ArrayList());
	public AutoRefreshingProperties(String absolutePathToPriopertiesFile) throws IOException{
		this(null, absolutePathToPriopertiesFile);
	}
	public AutoRefreshingProperties(Properties defaults, String absolutePathToPriopertiesFile) throws IOException{
		super(defaults);
		load(absolutePathToPriopertiesFile);
	}
	public AutoRefreshingProperties removeListener(FileChangeListener listener){
		listeners.remove(listener);
		return this;
	}
	public AutoRefreshingProperties addListener(FileChangeListener listener){
		listeners.add(listener);
		return this;
	}
	public synchronized void load(String absoluteFilePath) throws IOException {
		InputStream is = new FileInputStream(new File(absoluteFilePath));
		this.load(is);
		LAST_LOADED = System.currentTimeMillis();
		keepUpdated(absoluteFilePath);
	}
	abstract class FileWatcher implements Runnable{} 
	private void keepUpdated(final String absoluteFilePath){
		Executors.newSingleThreadExecutor().submit(
				new FileWatcher(){
					@Override
					public void run() {
						try {
							while(true){
								if (new File(absoluteFilePath).lastModified() > LAST_LOADED){
									InputStream is =  new FileInputStream(new File(absoluteFilePath));
									load(is);
									LAST_LOADED = System.currentTimeMillis();
									notifyListeners();
								}
								Thread.yield();
								Thread.sleep(2000);
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
		);
	}
	private void notifyListeners(){
		final Properties properties = new Properties(this);
		for (FileChangeListener aListener : listeners){
			aListener.notifyFileChanged(properties);
		}
	}
}

In the simplest of usage scenarios all you will need to do the auto loading feature is to just create an instance of AutoRefreshingProperties by passing the path to the properties file. The class will take care of monitoring the file and reloading itself on file change. So at any point of tile when the system makes a call to Properties.getProperty(…) it will return the latest value specified in the properties file. As I have shown in the test case the power of this tool can be extended by attaching listeners and taking appropriate reactive actions on property changes.

The feature that I would love to see augmented to such a solution is how a spring bean property configured through PropertyPlaceholderConfigurer can load an refresh the beans on property file changes. In my opinion that solution will not be as trivial as the one I cooked up here. Having said that one can very easily use the notification listener mechanism to do whatever it needs to do on such an event.

JDK7 has a WatchService specificatiion. The b64 release has this interface in place. Such a support from JVM will alleviate a lot of thread management issues that each of us have cooked up for file and directory monitoring.

14 Thoughts on “Auto refreshing properties from property files

  1. This would not be good in a JEE environment where you are not supposed to manage your own threads.

    Also, it’s silly to create a single thread executor and pass it threads. First, you can just pass runnables to executors. Second, you’re only ever passing one runnable to the executor. You should just replace that code with

    new Thread() { .. }.start();

    Look at how Apache commons-configuration does it with their FileChangedReloadingStrategy. Maybe you could just use commons-configuration in your applications when you need this functionality.

    You should also test to see if removing properties from your file results in the property being removed from the AutoRefreshingProperties object.

    • Ken, thanks for the comments.

      Using a thread ExecutorService comes out of habit. I know from a lot of concurrency solution experience that the Executor Service managed threads are much better behaved. Esepecially in this scenario where it is watching a file.

      Which JEE environment do you feel might pose a problem? Most of the JEE app servers provide a mechanism to use a TimerTask kind of construct. I am pretty sure that piggybacking on such mechanism will let us use this class and then a listener to update the properties to the JNDI tree. Do you see any specific challenges in this approach? I agree that spawning this class in an Ejb instance will not be very appropriate because of the lifecycle controls the container has to do and a hanging thread will mess with the life cycle management.

      Using Runnable in place of Thread : I think in general it is a good idea because we can take away some memory over heads. Since Thread is a runnable the currentl implementation is not a bad code though. I think I must have used thread just because I was lazy to create a new Impl :-)

      Thanks for pointing out the Apache commons configuration. I just hate reinventing a wheel. Looks like I just did one. My bad!!

      And finally, since the monitor is a dumb thread that watches for file changes through modification date it works (tested too) when properties are removed from the file.

    • Ken, I have taken your suggestion and replaced the Thread with a Runnable. Makes sense! thanks..

  2. Pingback: Refrescando las propiedades desde un fichero properties » Blog de Ruben Garcia

  3. We have been using the Apache Commons Configuration library in production for several years. Here is a link to their docs (specifically the automatic reloading section)”

    http://commons.apache.org/configuration/userguide/howto_filebased.html#Automatic_Reloading

  4. You should name your thread and the thread should be a daemon.

    Also, Ken is right, you should be passing Runnable object rather than a Thread since it is misleading.

  5. David Seymore on October 16, 2009 at 8:43 am said:

    JMX & Preferences API.

    Everything should be coded to have working defaults, and allow runtime configuration changes.

  6. 1. The ‘synchronize’ keyword does nothing on the thread for the following reason:

    synchronized in the ‘run’ will lock the object itself (which is the anonymous Thread object), nobody else try to get the thread monitor for that object. (thus the public load() method can be executed paralelly.) I suppose you put the synchronized keyword there for this reason. Looping forever in a synchronized section is somewhat unusual.

    2. In the watch thread you loop forever. You should at least add a Thread.yield() or even better some sleep(). Even if it is low prio, it can consume lots of cpu power. And who cares if you reload after 2-300ms only.

    Cheers,

    Tamas

  7. ironclay on October 16, 2009 at 8:08 pm said:

    Actually you need to synchronize access to any of the properties methods when you’re updating the properties object since its not inherently synchronized. I think the lazy reload approach taken by the Apache folks is better if you’re in a development environment whereas your approach is more pro-active and makes more sense in a production environment (why make the caller wait for the properties to be reloaded).

    You should consider implementing a locking mechanism to prevent concurrent access to the properties object. You might want to consider implementing a Proxy to the underlying Properties object.

  8. nice, i wanna try this autorefresh property..

  9. Lukasz on October 28, 2011 at 4:21 pm said:

    You should also add a shut down hook…

  10. http://howtodoinjava.com/2012/10/10/auto-reload-of-configuration-when-any-change-happen/

    This article also try to solve this problem differently. Please review.

Leave a Reply

Post Navigation