: config tutorial (v3)

Lesson 4: Configuration Hooks

Introduction

Configuration hooks are probably the hardest to understand method of configuring your application but they can be invaluable if you ship proxy assemblies that wrap around Java types.

Let's take the following scenario: you are a Java middleware company and you want to ship a proxy type assembly that allows .NET developers to use your Java types with as little configuration as possible. How can you do that?

What if you could bundle the configuration code into your proxy type assembly? Clearly that does not work for everything that might need to be configured, but if you combine configuration hooks with some conventions, you can pretty much create auto-configuring assemblies.

Let's start with the classpath. Your Java types will have to be deployed with the .NET application, otherwise nothing will work. A common application layout would be to to have all your assemblies and executables in a bin directory and all your Java libraries in a sibling lib directory.

Let's continue with the JRE. You could bundle a JRE into your application that resides in a jre directory.

If you can just figure out where you're installed at runtime, you can configure both JVM and classpath relative to that location becuase you know where the JRE and the Java libraries can be found. You can do that explicitly in your application's Main() method but you can also do it from a configuration hook that lives in your proxy type library.

Then you just need to tell your users to follow the prescribed file layout (or whatever policy you decide to use) and everything will work automagically.

How Configuration Hooks Work

A configuration hook is basically a callback that gets invoked multiple times by the JvmLoader. You register the hook by calling JvmLoader.RegisterConfigurationHook() from a method that the JMS Courier runtime will call when your assembly gets loaded into the process. You can make that happen by declaring a public static void Init() method in a class that is annotated with the JuggerNETInit attribute. This is shown in the snippet below.

using Codemesh.JuggerNET;

// a class whose only purpose is the registration of a callback hook
[JuggerNETInit]
public class ConfigHookRegistrar
{
public:

    // the constructor registers the hook
    public static void Init()
    {
        JvmLoader.RegisterConfigurationHook(Configure);
    }

    public static void Configure(IJvmLoader loader, int when)
    {
        // let's ignore what goes into a hook for now
    }
};

The key here is the class annotation with the [JuggerNETInit] attribute. This will cause the runtime to invoke the Init() method when the assembly is loaded into the process. That causes the hook registration to be processed and that in turn causes the registered callback to be invoked multiple times in the application's lifecycle.

The first invocation will occur right after the JvmLoader instance has been created. This is the time to configure application defaults that can be overridden by anyone who has access to the JvmLoader singleton. In particular, whatever defaults you configure here can be overridden from your application's Main() method.

The second invocation will occur right before the JvmLoader tries to load the JVM. This is the time to check whatever configuration might have been done in Main() and to override it or amend it with your own settings. You could for example allow users to set a classpath programmatically and then you just append your jar files to it during this callback.

The third invocation will occur right after the JvmLoader successfully loaded the JVM. This is the time when you can perform some sanity checks to make sure required Java types are available or even call Java code to perform application initialization tasks.

Let's now take a look at what goes into a configuration hook callback (we ignored that in the snippet above). The following snippet contains the skeleton that you would flesh out for your own application. A full example is available as part of the code generator distribution (see location below).

// the configuration hook callback
public static void Config(IJvmLoader loader, int when)
{
    When w = (When)when;
    if(w == When.XMOG_AFTER_INITIALIZATION)
    {
        // set defaults
    }
    else if(when == When.XMOG_BEFORE_LOADING)
    {
        // override or amend user configuration
    }
    else if(when == When.XMOG_AFTER_LOADING)
    {
        // check or perform Java application initialization
    }
}

Example

You can find an example in the code generator distribution at examples/dotnet/v3/configuration/confighook. The readme.html file in that directory contains a description and the instructions on how to build and run the example.