Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Extend the JDK Classes with Jakarta Commons, Part III : Page 3

Explore Jakarta Commons components that enable you to parse arguments in a command-line application, connect to various file systems at the same time, allow an application to uniformly access configurations loaded from various sources, and pool any object.

Commons Configuration addresses the need for enterprise software to access property files. Using this function lets an application uniformly see the configurations loaded from various sources.

The following are some of the more useful features in this API:

  • Transparent access to configuration properties stored in JNDI, databases, text files, XML files, memory, the System properties, Applets, and Servlet initialization properties
  • Ability to automatically reload the properties based on a reloading strategy that you can customize by writing strategy classes
  • Ability to persist the modified properties back to the storage
  • Ability to access the XML configurations using XPath-like syntax

If the module context in a software application contains a reference to the org.apache.commons.configuration.Configuration instance, the properties that the application needs can easily be made available to all the classes in that module.

The Jakarta site gives a good introduction to this API with a primitive example. Saving the properties back to the storage is supported only for the configuration sources of type files.

The sample application for this API synchs the system time to a remote SNTP (Simple Network Time Protocol) server. It doesn't implement the method that does the actual sync to the time server, but it is a skeleton that works well for demonstrating Commons Configuration. Find the complete source in the package in.co.narayanan.commons.config.

Listing 10 presents the configuration requirements for the application, including the following:

  • syncintervalhours – Integer property to represent the interval between syncs
  • enablesync – Boolean property to turn the synching operation on or off
  • <name> – String array property that represents the name of the SNTP servers to which the tool can connect
  • lastsync – Time stamp string of the last successful sync (This is written at the completion of every sync operation.)

Listing 10. Configuration Files Used for the Application
application.properties syncintervalhours=12 enablesync=true #This property is set after the first run lastsync=<timestamp in milliseconds> sntpservers.xml <servers> <name>server1</name> <name>server2</name> <name>server3</name> </servers>

Listing 11 is an interface that provides access to the application's configuration files using Commons Configuration implementation.

Listing 11. Interface for Accessing the Application Configuration Needs
public interface IConfiguration { void setStringConfig(String nameSpace, String key, String value); String getStringConfig(String nameSpace, String key); String[] getStringArrayConfig(String nameSpace, String key); void setBooleanConfig(String nameSpace, String key, boolean value); boolean getBooleanConfig(String nameSpace, String key); void setIntConfig(String nameSpace, String key, int value); int getIntConfig(String nameSpace, String key); }

The interface isolates the application classes that are accessing all the features in the Commons Configuration API. It provides methods to read and store the properties of type string, integer, Boolean, and string array.

Listing 12 is a code snippet from the ApplicationConfiguration class that implements the interface.

Listing 12. Loading the Properties Using Commons Configuration API
/** * Get the config property value from configuration storage. The * properties are loaded if it is not already loaded for the * given namespace. * * @param nameSpace Name of the configuration group * @param key Unique key within the namespace * @return Sring value of the property. Null if the property is not found * or if the configuration cannot be loaded */ public String getStringConfig(String nameSpace, String key) { Configuration config = getConfiguration(nameSpace); if(config != null) { return config.getString(key); } return null; } private synchronized Configuration getConfiguration(String nameSpace) { Configuration config = configs.get(nameSpace); if(config == null) { try { if("application".equals(nameSpace)) { config = new PropertiesConfiguration("application.properties"); } else if("sntpservers".equals(nameSpace)) { config = new XMLConfiguration(getClass().getResource("sntpservers.xml")); } configs.put(nameSpace, config); } catch (ConfigurationException e) { System.out.println("Unable to load the configuration:" + e.getMessage()); } } return config; }

The highlighted lines indicate that the code lazy loads the properties from the text and XML files when a getter method is called. The Configuration objects are stored in an internal map per nameSpace, which lets the configurations be loaded and stored independently without mixing the properties. If the properties can be mixed and are from different sources, the class org.apache.commons.configuration.CompositeConfiguration can be used. (Find more details here.)

Listing 13 shows how the configuration can be saved back to storage.

Listing 13. Saving the Configuration Back to the Text File
private synchronized void save(Configuration config) { if(config instanceof FileConfiguration) { try { // If reloading strategy is set, then the properties // doesn't get saved ((FileConfiguration)config).save(); } catch (ConfigurationException e) { System.out.println("Config not saved. Error while saving." + e.getMessage()); } } else { System.out.println("Config not saved. Not supported."); } }

Note: I encountered a problem in saving the properties to the text file when the reload strategy was set to the Configuration instance. (Find more about property file usage here.)

Listing 14 shows how the configuration properties are accessed in an application class via the context.

Listing 14. Accessing the Configuration Using the Application Context
void syncTime() { if(shouldSyncNow()) { context.getLogger().log(Level.INFO, "Sync started"); sync(); recordSyncTime(); } else { context.getLogger().log(Level.INFO, "Sync skipped. Time not yet arrived"); } } private boolean shouldSyncNow() { boolean enableSync = context.getConfiguration() .getBooleanConfig("application", "enablesync"); context.getLogger().log(Level.INFO, "enablesync:" + enableSync); if(enableSync) { if(getCurrentTime() > readLastSync() + getInterval()) { return true; } } return false; } /** * Use SNTP API to sync the time. */ private void sync() { String servers[] = context.getConfiguration() .getStringArrayConfig("sntpservers", "name"); for(String server : servers) { context.getLogger().log(Level.INFO, "Time Server:" + server); } // Use the list of server to sync the system time. // sntp API for java can be used here context.getLogger().log(Level.INFO, "Syncing time.."); }

The code obtains a reference to the logger and configuration class to fetch the necessary property. Consider looking at the in.co.narayanan.commons.config.SyncTime class for all the properties' uses.

Listing 15 is the test case class for testing the SyncTime class.

Listing 15. Test Case Class for Verifying the Behavior of the SyncTime Class
public class TestSyncTime extends TestCase { public void testSyncTime() { Logger consoleLogger = Logger.getAnonymousLogger(); ApplicationContext context = new ApplicationContext(); context.setLogger(consoleLogger); context.setConfiguration(new ApplicationConfiguration()); SyncTime sync = new SyncTime(context); sync.syncTime(); sync.syncTime(); } }

The test case class initializes a Java logger and the configuration class, sets them to the application context, and injects the dependency to the SyncTime class.

Commons Configuration enables you to access external properties from various sources. Although useful, it has some room for improvement since enterprise software requires saving properties back to a directory server using JNDI and a database. However, for reading from simple text and XML files, this framework is a good option.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.