Tuesday, April 8, 2008

Commons Configuration - DatabaseConfiguration Definition

My experience has shown me on MANY occasions the advantages of modifiable properties outside of the source code. Some basic examples are:
  • Simple configuration of application for different environments (dev, test, staging, prod, etc.)
  • Ease of modification of characteristics without requiring rebuild (depending on the way a project is built/assembled, this could include on-the-fly configuration of properties without requiring a restart)
  • Central grouping of properties for the application which can ease support and customization efforts
Over the years, I have come to use the commons-configuration library almost exclusively. It has a great set of features and is very simple to incorporate into code. One of the main advantages that I have found is the ConfigurationFactory, and later the DefaultConfigurationBuilder, both of which allow the declaration of a configuration definition file. Once this file is declared, configuration sources can dynamically be added simply by created the source and defining it in this file.

Having mainly worked with xml and properties files, I recently worked on a project where one of the developers wanted to use the DatabaseConfiguration class and keep the properties in a database table. This aproach has several advantages, such as quick and easy search capability (hello SQL!), centralization of properties and live updates. I figured, "great, since the class exists in commons-configuration I'm sure they added the ability to define the source in the configuration definition file". Alas, I was mistaken. Again. You'd think I'd be getting used to this...

Thankfully, the DefaultConfigurationBuilder is extensible to deal with exactly this situation. Well, more or less. The commons group apparently has the intention to make the configuration definition file easily extensible in the future, but for now this takes a bit of tweaking. So, without further ado...

Extending the commons-configuration configuration definition file to handle DatabaseConfiguration configurations

My intention was to allow the definition of a database configuration in the definition file as follows:

<database jndi="jdbc/dataSourceName" table="CONFIG_TABLE" keyColumn="NAME" valueColumn="VALEUR"/>

In order to allow this definition, we first need to create a bean to handle the definition node:

public class DatabaseConfigDef {

  private String jndi;
  private String table;
  private String keyColumn;
  private String valueColumn;

  public DatabaseConfigDef() {
    super();
  }

  public DatabaseConfigDef(String jndi, String table,
      String keyColumn, String valueColumn) {
    super();
    this.jndi = jndi;
    this.table = table;
    this.keyColumn = keyColumn;
    this.valueColumn = valueColumn;
  }

  // GETTERS AND SETTERS
  .
  .
  .
}

Now we need to implement the ConfigurationProvider for our node:

public class DatabaseConfigurationProvider
    extends ConfigurationProvider {

  public DatabaseConfigurationProvider(String configClassName)
  {
    super(DatabaseConfiguration.class.getName());
  }

  public DatabaseConfigurationProvider(Class configClass) {
    super(DatabaseConfiguration.class);
  }

  public DatabaseConfigurationProvider() {
    super();
  }

  @Override
  public AbstractConfiguration getConfiguration(
      ConfigurationDeclaration decl) throws Exception {

    DatabaseConfigDef def = (DatabaseConfigDef)createBean(
      DatabaseConfigDef.class, decl, null);
    DataSource ds = (DataSource)new InitialContext().lookup(
      def.getJndi());

    return new DatabaseConfiguration(ds, def.getTable(),
      def.getKeyColumn(), def.getValueColumn());
  }
}

And now we need to define this provider when we initialise the config. I usually do this in a helper that is called during the loading of the application (ie. in a startup servlet or the constructor of an ejb):

CombinedConfiguration config = new CombinedConfiguration();

DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();

DefaultConfigurationBuilder.ConfigurationProvider provider = new DatabaseConfigurationProvider();
builder.addConfigurationProvider("database", provider);

builder.setFile(masterConfigFile);
CombinedConfiguration cc = builder.getConfiguration(true);
config.addConfiguration(cc);

And that's it - now our database configuration source is loaded along with the rest of the configuration sources. A couple of things to note:
  • I use the jndi name for a JDBC DataSource in the definition file. Thus, we must be sure that the jndi tree has been initialised before calling the load for our configuration.
  • Since the DatabaseConfiguration constructor uses a DataSource object, if we wanted to avoid using jndi (eg. by specifying the connection parameters for the database in the definition file) we would need to modify our DatabaseConfigurationProvider class to build the DataSource from the connection parameters.

Thursday, March 20, 2008

JAX-WS Custom Properties

After days of searching for ways to set a System property for the endpoint of the JAX-WS web service in order to allow us to configure it on the fly, I finally came across Gerard Davison's blog entry that explains how to do it with those magic JAX-WS Maps. 4 lines of code that solve all of my problems!

http://kingsfleet.blogspot.com/2007/11/changing-endpoint-location-for-jax-ws.html


For more information on the MessageContext properties (the exact list I was looking for):
https://jax-ws.dev.java.net/articles/MessageContext.html

As well, a common problem that I have is setting timeouts for the Web Service calls. While this should be the first result of a Google "JAX-WS timeout" search, I always end up having to run around in circles finding the answer. And, of course, every major server has their own way of doing this. However, in this case (Glassfish v2, JAX-WS 2.1) the answer is as follows:

((BindingProvider)port).getRequestContext().put(
"com.sun.xml.ws.connect.timeout", connectionTimeout);
((BindingProvider)port).getRequestContext().put(
"com.sun.xml.ws.request.timeout", socketTimeout);

Now, why these are not constants in BindingProvider...