Monday, April 20, 2009

Reconciling Apache Commons Configuration with JBoss 5

There are many ways to configure a JavaEE application. Among the available solutions are DBMS tables, JNDI, JMX MBeans and even plain old files in a variety of formats. While we have used most of the above in various occasions, I find that plain files resonate with all types of sysadmins, when no other administrative interface is available. For such scenarios, Apache Commons Configuration is undoubtedly the best tool for the job. Recently, I came across an undocumented incompatibility when using Commons Configuration with JBoss 5 and I thought I should describe our solution for the benefit of others.

Usually we are storing our configuration files in the standard place for JBoss, which is JBOSS_HOME/server/default/conf, for the default server configuration. This has the disadvantage that is not as easy to remember as /etc in UNIX/Linux or \Program Files and \Windows in Windows systems, but it has the important advantage of being specified as a relative path in our code, making it more cross-platform without cluttering it with platform-specific if/else path resolution checks.

Commons Configuration can reload the configuration files automatically when changed in the file system, which helps prolong the server uptime. However JBoss 5 has introduced the concept of a virtual file system that caches all file system accesses performed through the context class loaders using relative paths. Unfortunately this generates resource URLs in the form vfsfile:foo.properties that Commons Configuration does not know how to deal with. Fixing this requires extending FileChangedReloadingStrategy, like we do in gss. Alternatively, one could patch Commons Configuration with the following change and use the standard FileChangedReloadingStrategy unchanged:


Index: FileChangedReloadingStrategy.java
===================================================================
--- FileChangedReloadingStrategy.java (revision 764760)
+++ FileChangedReloadingStrategy.java (working copy)
@@ -46,6 +46,9 @@
/** Constant for the jar URL protocol.*/
private static final String JAR_PROTOCOL = "jar";

+ /** Constant for the JBoss MC VFSFile URL protocol.*/
+ private static final String VFSFILE_PROTOCOL = "vfsfile";
+
/** Constant for the default refresh delay.*/
private static final int DEFAULT_REFRESH_DELAY = 5000;

@@ -161,7 +164,8 @@

/**
* Helper method for transforming a URL into a file object. This method
- * handles file: and jar: URLs.
+ * handles file: and jar: URLs, as well as JBoss VFS-specific vfsfile:
+ * URLs.
*
* @param url the URL to be converted
* @return the resulting file or null
@@ -181,6 +185,18 @@
return null;
}
}
+ else if (VFSFILE_PROTOCOL.equals(url.getProtocol()))
+ {
+ String path = url.getPath();
+ try
+ {
+ return ConfigurationUtils.fileFromURL(new URL("file:" + path));
+ }
+ catch (MalformedURLException mex)
+ {
+ return null;
+ }
+ }
else
{
return ConfigurationUtils.fileFromURL(url);


Neither of these solutions covers the case of storing configuration files in zip or jar containers, but since it is something I haven't found a use for yet, I can't test a fix for it. If anyone is interested in such a use case, I'd advise extending FileChangedReloadingStrategy, combining the logic in jar: and vfsfile: URL handling.

No comments:

Creative Commons License Unless otherwise expressly stated, all original material in this weblog is licensed under a Creative Commons Attribution 3.0 License.