Showing posts with label project: Easy Configuration. Show all posts
Showing posts with label project: Easy Configuration. Show all posts

Monday, April 21, 2008

Boring stuff you have to implement: Configuration, part 2

A while ago I wrote a post where I proposed an easy way of specifying the configuration of an application. The idea is basically to define a configuration parameter by annotating a methods with information that describes the parameter. Of course, the value of the parameter is retrieved by calling the annotated method. My previous post contains an example.

To implement this easy-configuration-thingie I use dynamic proxies. If you haven't heard of dynamic proxies you have missed one of Javas powerful facilities for metaprogramming. Under the circumstances (e.g., static type-checking) I think it's pretty easy to use too.

The basic idea behind dynamic proxies is quite simple: let all calls to methods of an interface be delegated to another method. This method is called invoke and is declared in java.lang.reflect.InvocationHandler.

As you may suspect, the invoke method receives the all arguements given to the method defined in the interface (i.e., the method that delegated to invoke). It also receives an arguments that describes which method that was called; this is an java.lang.reflect.Method object, which among other things, contains the method's annotations.

Back to the original topic: configuration. How can all this annotation stuff and proxy fluff be used to define and read configuration?

Well, as the example in my earlier post shows, the interface that defines the configuration is annotated with the name and the type of the configuration parameter. Since the method's annotations are available to the invoke method, invoke can use the parameter name to look up its value (in a hashmap, or similarly) and return it. It's as simple as that!

I've made a simple implementation of this availble here (follow the instructions on Google Code if you wish to check-out the entire Eclipse project).
Note that some more development is needed before this code is useful, since it does not
read any configuration from file (only default values can be read). 

In general, I tend to think that annotations simply are additional arguments to the annotated method (although a bit harder to use than ordinary arguments). This way of looking at annotations is even more suitable when used together with dynamic proxies, I think.

You probably already have thought of this, but there are several other ways of using annotations + dynamic proxies: I've used it to parse binary messages and command line arguments (before I know about JewelCLI), and I guess you can come up with several other examples...

Thursday, April 3, 2008

Boring stuff you have to implement: Configuration, part 1

I don't need to tell you that configuration is a must-have for any application; if it doesn't have any configuration it is either extremely dumb, or it is is extremely smart (i.e., figuring out how to configure itself at runtime).

I don't consider my applications dumb enough to not need configuration, and I don't consider myself smart enough to develop applications that doesn't need configuration. So, where does that leave me? In the realm of not-so-expressive syntaxes with implicit semantics and hardcoded defaults scattered and hidden deep inside the source code, of course. Fasten your seat belts -- configuration hell, here we come!

Ok, to get to the point, this serie of posts will focus on how to abstractly express the configuration needed by a piece of source code within the source code itself (locality is the shit). Details, such as how to read configuration files, are way too boring for me to discuss on my spare time... yeah, really. How to handle a read configuration, on the other hand, that's interesting enough for me.

I guess that you, like me, often see code like this:

/**
 * The configuration of the result/output of the application.
 */
public interface ResultConfiguration {

  /**
   * Get the filename of the file to write the result to.
   * This is configured by the user before startup.
   * If not set, /dev/null is returned.
   */
  String nameOfOutputFile();
}

which is actually quite nice because it's an interface that can be stubbed in tests, and its also quite well documented in a way that is understandable for someone who has not seen the code before.

What's not so very nice is that the description of the configuration is implicitly given in comments. The same is true for the description of the class, and, even worse, for the default value which is likely to change.

Ok, so documenting the configuration is good, but its bad to use comments. How do we get the best of both worlds? We could use java.util.Properties or simething similar, and specify default values in the source; but how fun is that? Not at all. Programmers just want to have fun, as Cyndi sang back in '84. Let's use annotations!

The code above can be expressed as:

@ConfigCategory(
  description = "Controls various aspects of the output.",
  name = "result/output")
public interface ResultConfiguration {


  @ConfigParam(description = "The name of the output file.",
    settable = Settable.BeforeStartUp,
    defaultValue = "/dev/null")
  String nameOfOutputFile();
}


I'll go into details later how to actually use the annotations, right now I'll just say that it involves reflection and dynamic proxies. Or, to paraphrase Fermat, "I have a truly marvellous implementation of this interface which this post is too short to contain." :)