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 libraries that wrap around Java types.
Let's take the following scenario: you are a Java middleware company and you want to ship a proxy library that allows C++ 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 library? 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 libraries.
Let's start with the classpath. Your Java types will have to be deployed with the native application.
A common application layout would be to to have all your native code modules (shared libraries 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 xmog_jvm_loader
.
You register the hook by calling xmog_jvm_loader::registerConfigurationHook()
, usually from a global
variable's constructor. Global variables are initialized when the library loads, so hook registration takes place at
library load time. The following snippet, which would be part of your proxy library, illustrates this pattern.
#include "xmog_java_client.h" // a class whose only purpose is the registration of a callback hook class config_hook { public: // the constructor registers the hook config_hook() { xmog_jvm_loader::registerConfigurationHook(myConfigHook); } private: // the configuration hook callback static void XMOG_CALLING_CONVENTION myConfigHook(void * pl, int when) { // let's ignore what goes into a hook for now ... } }; // when this object is initialized, the hook is registered static config_hook hooker;
The key here is the declaration of hooker
at file scope. When its constructor is
invoked it will register myConfigHook()
with the Codemesh runtime, which will then
proceed to invoke the callback multiple times.
The first invocation will occur right after the xmog_jvm_loader
instance has been
created. This is the time to configure application defaults that can be overridden by anyone
who has access to the xmog_jvm_loader
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 xmog_jvm_loader
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 xmog_jvm_loader
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 void XMOG_CALLING_CONVENTION myConfigHook(void * pl, int when) { xmog_jvm_loader * pLoader = (xmog_jvm_loader*)pl; if(when == XMOG_AFTER_INITIALIZATION) { // set defaults } else if(when == XMOG_BEFORE_LOADING) { // override or amend user configuration } else if(when == XMOG_AFTER_LOADING) { // check or perform Java application initialization } }
Example
You can find an example in the code generator distribution at examples/cpp/v3/configuration/confighook
.
The readme.html
file in that directory contains a description and the instructions on how to build and
run the example.