How to easily reconfigure your applications -- while they're running

New JavaWorld column debuts with a look at flexible configuration alternatives for your applications

Welcome to the first installment of the Cool Tools column. Encouraged by the tremendous amount of positive feedback I received from my debut article on object pooling, I've decided to take a stab at this writing gig. Each month, I'll introduce a new useful Java utility. These utilities are basically "tools" I've devised and evolved over the past couple years of my Java programming career. These tools simplify the job of the coder while enhancing the performance and robustness of the application. I hope you'll find them as useful as I have.

This month's topic is global values. These are the values that allow us to change the look or behavior of our applications without changing any code. Global values must be accessible from anywhere, anytime.

At some point, most of us have had to deal with the management of data that has to be accessed from many points within an application, but that doesn't lend itself (on the basis of good design sense) to being passed around from method to method. The most common way to solve this problem is to use either static classes or properties files. Each has unique advantages and drawbacks. After discussing the pros and cons of these techniques, I'll introduce a new tool that combines the best of both worlds.

Static classes

You've probably seen something similar to the following code at least once in your career. It's a simple class that does nothing more than contain a bunch of public static final values. These values control how some part of the application looks or acts. When the application needs to be configured (that is, "branded" for a new vendor), these values are updated accordingly.

    public class GlobalValues 
    {
        public static final String COMPANY_NAME = "TedCo Widgets, Inc.";
        public static final String PRODUCT_NAME = "Cool Tools";
    }

In this dog-eat-dog world of Internet startup companies, I've made it standard procedure to use global variables for product and company names. These change on a whim due to factors like trademark battles and the latest industry buzz words. When your employer decides to change a product name, say from Cool Tools to Super Ultra Hyper Mega Tools, it's nice to only have to change a single line of code.

The advantages of the static class solution are very straightforward. The values are compiled into the code, so access is fast and packaging is simple (no configuration files to worry about). Also, accessing the values is intuitive and clearly understood upon viewing the code. You reference the values via the class name (no instantiation required) and the public static final variable name.

    System.out.println( GlobalValues.COMPANY_NAME );

There are a couple of disadvantages to the static class solution, however, and they aren't so obvious at first glance. When a value changes, you have to recompile the class -- a tad inconvenient, but not too much of a hassle. But what if this class is used to configure a cluster of applications on different machines? You have to distribute the newly recompiled class to all the hosts and make sure they're all in sync. And, you have to restart the applications in order for the changes to take effect.

But is recompilation of the static class all that is necessary? The answer is no! Depending on which brand of compiler you're using, and which optimization flags you pass in, all or some of the values from the static class may be compiled into the dependent classes by value rather than by reference. This has happened to me -- a compiler compiled the value into the referring class rather than a reference. It's incredibly frustrating trying to figure out why the new value isn't propagated. If you're unsure of how your compiler handles public static final values, the safest way to go is to recompile the whole application.

Properties files

After the static class, the next most popular solution is the properties file. Java is even so nice as to provide you with the java.util.Properties class to simplify the use of this technique. Properties files are very similar to Microsoft's Windows INI (initialization) files. In Windows, these files are read by an application when it first starts up. The file contains a series of key-value pairs; one pair per line. The key and value are separated by an equals sign (=), like so:

COMPANY_NAME=TedCo Widgets, Inc. PRODUCT_NAME=Cool Tools

The Properties class extends Hashtable, and you use the standard put() and get() methods to deal with the values. For details on using the Properties class (loading the file and such), please refer to Sun's documentation (see Resources). Your typical code fragment would look like this:

Properties props; // load and initialize the properties (out of the scope of this article) System.out.println( props.get( "COMPANY_NAME" ) );

The advantages of this solution are pretty obvious. The biggest one, of course, is no recompiling! All you have to do is edit the properties file and the next time the application runs, you'll see the changes. If you anticipate frequent changes to the values, properties files are a whole lot more convenient to change than static classes. The disadvantages, however, are numerous.

The first disadvantage is that the coder can change the values by calling the put() method. A quick solution to this is to extend the Properties class yourself and override the put() method to discard any changes -- but then you must also insure that the coder always gets your subclass rather than an actual Properties object.

The second disadvantage is that, even though you don't have to recompile for any changes to the configuration, you must restart the application to force it to load and use the new values. One example of this is if you're using servlets and the Web server caches them.

The third disadvantage relates to support of multiple hosts. As with the static classes, the synchronization of the properties files across each host is something you have to keep track of. Sooner or later, you're going to get one of them out of sync and waste precious hours trying to track down the problem. If you're using a RAID (Redundant Array of Independent Disks) or filesystem mounting (where multiple machines share a single drive), you might be able to avoid this problem.

The last disadvantage is lack of speed. You'll need to implement some sort of caching in your application so you don't hit the disk and reload the properties file each time a value is requested or re-requested. In essence, you will need a static class that points to the Properties object. Oh, the irony.

My solution

Based on the information above, I set out to find a solution that would combine the best of both worlds. My tool would need to have all of the advantages and none of the disadvantages listed above.

Here's my list of goals:

  1. No recompilation is required
  2. Tool must use a single point of reference among multiple hosts
  3. Coders may not, intentionally or inadvertently, change the values
  4. Access speed to values must be fast
  5. No application restart should be required for changes to take effect

Goal 1 immediately eliminates the use of public static final values. Which means I had to use an external source for the data. The obvious choices are a file or database. As you've probably gathered from my prior comments, I don't want to bother myself with the synchronization of configuration files across multiple hosts.

This brings me directly to Goal 2. What better way to provide a "central" point of reference than a database? (I'll get to the table design in a moment.)

Goal 3 basically means I have to provide a get() mechanism without a put().

Goal 4 is another supporting argument for the database. Pulling data out of the database is going to be much faster than getting it from a flat file. And with some fancy caching (to be explained) the access time for values is more than acceptable.

Goal 5 is the icing on the cake. This is the part of the solution I am most proud of. In addition to the standard name and value attributes of our data, I have added a volatility value. The volatility value defines whether the value can change, and

how often it's likely to do so. This allows me to do really cool things, like toggle debugging output dynamically while an application is running.

The database

Before I jump into the source code, we need to establish the foundation for the storage and retrieval of the global values: the database. Each value will be stored in a simple database table called GLOBAL_VALUES.

Column Name Column Type ----------- ----------- NAME CHAR(32) VALUE CHAR(128) EXPIRE INT

The first two columns are pretty self-explanatory. The NAME column will store the name of the value, like "COMPANY_NAME". The VALUE column likewise will store the value, a la "TedCo Widgets Inc."

The EXPIRE column is the bread and butter of the tool. Its value will define, in milliseconds, the volatility of the data. If the EXPIRE value is set to zero, the value is loaded once from the database (if or when it is requested by the application), and cached for the life of the process.

If the EXPIRE value is greater than zero, the value will be taken from the database, cached, and timestamped. The next time the value is requested, the timestamp will be checked. If the value is older than its EXPIRE value, it will be reloaded from the database. This is the power of dynamic configuration. (Finally, the basis for the article title is revealed!)

The code

The code is very simple. The only tricky stuff is caching and keeping track of the volatile data.

The first thing we'll need is a cache. I'll introduce some handy caching tools in a future installment of this column, but for now a simple hashtable will have to do.

private static Hashtable cache;

Since all the methods for our utility will be static, no constructor is called. Thus, we must initialize our cache and load our JDBC driver in a static block.

static { cache = new Hashtable( 15, 5 ); // load your JDBC driver }

I'm going to jump ahead for a moment. The hashtable offers us a simple key-value pair storage mechanism, but it doesn't leave any room for the expiration value for each piece of data. Therefore, I devised an inner class to store both the value and the expiration together. The name of the data will be used as the key for the hashtable; the inner class will be stored as the value.

The inner class does one more thing for us: it keeps track of the data's age. When you instantiate a new copy, the constructor gets the current system time in milliseconds and stores it internally. It then uses that time to check for expiration each time the value of the data is requested.

Here's the inner class in its entirety:

static class Value { private long time; private String value; private long expire; Value( String value, long expire ) { this.value = value; this.expire = expire; time = System.currentTimeMillis(); } String getValue() { return value; } boolean hasExpired() { if( expire != 0 ) { if( ( System.currentTimeMillis() - time ) > expire ) { return true; } } return false; } }

Notice that the class is declared as static. As I explained above, this tool never actually gets instantiated, so all methods and attributes (including inner classes) have to be declared as static.

Now that we've laid the foundation for the tool, we can implement the guts. We only need to add two more methods. The first is a private method that actually loads the data from the database and encapsulates it into an instance of the inner class helper. Simple enough:

private static Value load( String name ) { Value value = null; try { Connection conn = DriverManager.getConnection( "your database" ); String sql = "SELECT VALUE, EXPIRE FROM GLOBAL_VALUES WHERE NAME = '?'"; PreparedStatement prep = conn.prepareStatement( sql ); prep.setString( 1, name ); ResultSet rset = prep.executeQuery(); if( rset.next() ) { String val = rset.getString( "VALUE" ); long exp = rset.getInt( "EXPIRE" ); value = new Value( val, exp ); } rset.close(); prep.close(); conn.close(); } catch( SQLException e ) { } return( value ); }

The next, and final, method is the one and only method the outside world is allowed to call: get(). This method first checks to see if we have the value cached. If it's in the cache, the method then checks to see if the value has expired. If the value isn't in the cache, or if it has expired, get() reloads it from the database and puts it into the cache. Finally, it returns that value to the process requesting it.

public static synchronized String get( String name ) { Value value = (Value) cache.get( name ); if( ( value == null ) || ( value.hasExpired() ) ) { value = load( name ); cache.put( name, value ); } return( value.getValue() ); }

Notice that the method is synchronized. This is done to avoid a race condition with the cache. Even though the hashtable itself is thread safe (all of the access methods are synchronized), the logic surrounding our use of it (extracting the data, checking the expiration, and so on) isn't inherently atomic. This could result in undesirable behavior in the case that two processes requested the same piece of data simultaneously.

Conclusion

There are many ways to deal with global values in your code. Each has its own unique advantages and disadvantages. I have argued the case for static classes and property files and offered up a third hybrid solution for your programming enjoyment. Comments, criticisms, and especially design-improvement suggestions are always welcome. Feel free to send me e-mail, using the link in my bio below.

Thomas E. Davis is a Sun Certified Java programmer. He has been designing and implementing large-scale, multiuser distributed applications in Java for over two years.

Learn more about this topic

  • Sun's javadoc on hashtables http://java.sun.com/products/jdk/1.1/docs/api/java.util.Hashtable.html
  • Sun's tutorial on JDBC http://java.sun.com/docs/books/tutorial/jdbc/index.html
  • Sun's tutorial on inner classes http://java.sun.com/docs/books/tutorial/java/more/innerclasses.html