Kilim 2 Tutorial

0 - Kilim2, what is it for ?

Kilim is a generic open-source configuration framework for Java, which can be used easily with existing applications, frameworks, and systems. It gives your applications the opportunity to be configured :

It is not intrusive at all, and makes no assumption on how your existing code has been developped:

If you are tired of writing boring configuration code right in the middle of your business logic, Kilim might just be the solution.

0-1 - Overview

Kilim 2 enables :
1) the defininition of composable abstractions called Templates, capturing encasulated sub-systems defining :

2) the definition of the mapping of these abstractions to existing code in terms of :

3) the recursive assembly of these bricks, allowing to build complex systems :

1 - Static Definition of Templates

1-1 - Definition of an Abstract Template

All the examples given in this tutorial are implemented in the Kilim2Tutorial distribution available through CVS.
  • All the templates are contained in the kilim directory,
  • All the sources are contained in the src repository,
  • The needed .jar (included the kilim2.jar) can be found in the libs directory,
  • This documentation is in the doc directory.
The build.xml file contains the following ant tasks :
  • compile compiles the examples,
  • run.test runs a test with template quotes/application/Yet Another Composite Inherited, you can try it with another template simply by changing the value of the argument in the build.xml file,
  • run.test.JMX launches a JMX server. To see/configure the component, launch any browser on the following URL http://localhost:8082. It instantiates the template quotes/application/Yet Another Composite Inherited with JMX, you can try it with another template simply by changing the value of the argument in the build.xml file.

Let us define in the Kilim description language (which is an XML dialect) the Channel Template of the publish & subscribe paradigm :

The name attribute of the Template tag defines the name of the template. The templates can belong to a package (like in Java), in this case, the name in the attribute tag must be its fully qualified name, using / as a separator.
In this example, the Template belongs to package quotes, it must be stored in a file contained in a subdirectory quotes of the CLASSPATH.

Then we add in the template body a property tag defining the type, the value and the accessibility of the property name. Available types are :

The different levels of accessibility are

These levels of accessibility will be the same for all the members of the template, with the same semantics.

We can then define two extension slots. They will be used to plug publishers and subscribers into the channel. In this first definition step, we stay at a very abstract level, an do not make any assumption about :

1-2 - Specifying an abstract object mapping for the Template

Now we will define the object interfaces offered and required by the Template. These interfaces will, in the next section, be mapped on one, or many, language objects. The aim of the current step is not to describe the precise mapping of the template yet, but to define, for each interface (we call them ports) :

Ports are used to exchange references on object instances between the template and the rest of the system. The ports defined directly in the template body are used to provide/retrieve references to/from the outside of the template. The ports defined in the slot blocks are used to define how the template exchanges references with another template when it is plugged into it.
The template expects to :

In out example, the template Channel :

The subscriber port has an "any" arity, it means that many subscriber templates can be inserted in the slot, while only one publisher can be inserted in the subscriber slot because port "publisher" has an arity of 1.

This template is still abstract, as, if it is instantiated, no language object will be instantiated.

The template Channel is defined in file kilim/quotes/Channel.kilim.

1-3 - Pinning a template to code

Now time has come to define how this template will be mapped on language objects.
First, we want to preserve the genericity of our abstract template Channel, in order to define, if necessary, different mappings, all of them compliant with the abstract specification.

We will do that by a classical extension mechanism. LocalChannel template extends Channel, this means that it inherits all the properties, slots and ports of Channel.

Let us now precise how the port channel is mapped on code. This mapping will be achieved by a bind block. In this bind we declare that the binding of the port is done by instanciating a new object of class quotes.local.LocalChannel. This instanciation is done by calling the constructor taking a String as parameter. This parameter will be provided by the property name defined in the super template. This is achieved through a reference tag designing the property through is name.

Next step will be to describe what happens when a template is plugged into each slot. When a template instance is plugged into a slot, a binding event is generated by the runtime. This event can trigger a call to any specified method on any given interface, with an arbitrary number of parameter among :
We will now describe what happens when a subscriber is plugged into the channel. The binding event triggers a call to the method addSubscriber() on the instance mapping the port channel, with the object mapping que port subscriber of the plugged component as a parameter.

What happens with the publisher port is quite different. Here, the event that triggers the call to the method setChannel() is the binding of the port channel itself. This means that as soon as the LocalChannel instance will be created, the method will be called. This will work only if the plug of the publisher into the channel has been done prior to the instanciation of the template.

The template LocalChannel is defined in file kilim/quotes/local/LocalChannel.kilim.

1-4 - Assembling Components

Let us now build a template by simply assembling existing templates. For example we want to build a template representing a sub-system with one channel, one publisher plugged into it, and one subscriber.

The tag instance allows us tu create an instance of a given template. The attributes will define :

In the instance block we can override existing properties in order to change their default value. Here the property name, the default value of which was "Default Channel", is replaced by "USD Channel".

Now we will specify which template instance (we will call these "components" from now on) is plugged in which slot of the channel. To do that, we use the tag plug. Its attributes reference :

In this example we want to make this template ready to be assembled with others, with a view to building a global console displaying the quotations of different currencies. To achieve this goal, we create an external port, named console which makes the port console of an inner component available from the outside. It is thus ready to be plugged, in turn, in an other higher level template, like in the following example :

Many assembly examples are available in the distribution, all of them in the kilim/quotes/application directory :
  • JPY Example.kilim is the example detailed in the preceding paragraph,
  • USD Example.kilim is nearly the same, but with USD currency,
  • JPY and USD Example.kilim shows how to build higher level templates by assembling the two preceding templates,
  • the others toy with the existing templates, assembling and re-assembling them recursively, and shows different ways of achieving the same purpose.

1-5 - Creating a component from Java code

Now we can try to instantiate one of the components we have previously specified via .kilim files.

The API to do so is extremely straightforward :

Of course, due to the lack of genericity in Java, we then have to cast this reference into a javax.swing.JFrame reference in order to make it visible.

In order to correctly instantiate and configure the console interface, all required objects will be instantiated and configured lazily, according to the .kilim specification.

The Launcher's code can be found in src/test/

2 - Dynamic Reconfiguration

2-1 - Reconfiguration API

Now we have an instantiated component running (e.g. a Channel), mapped on instantiated language objects. Kilim 2.0 gives us the possibility of, to some extent, to reconfigure the Component once instantiated. In order to do that the only thing we need is have kept, in some way, a reference on the Component we want to modify. Here are the different modifications we can make on a component :

Modify the value of a property

This can be achieved in two easy steps :

This changes the value of the ComponentProperty, but not the state of the underlying language object.

This is not a drawback, this is a feature ! In fact, we probably want to change the value of many properties before we actually change the state of the real objects (for example we change the value of property A and B, and then trigger a unique call to the setAandB(A,B) of the language object)). The moment when we want the changes to take effect on the objects must then be explicit, and this is precisely what we explain in the next paragraph.

Update the state of the underlying language object

Another question that rises when it comes to change a property's value is :

What happens when I change the value of a property which is used to configure the state of many language object, through different methods

The answer is quite simple : you will have to call explicitly the method update() on all the ComponentInterfaces that are likely to be concerned by the property's modification.

Plugging and unplugging components

This is as simple as it gets :

In this case, nothing more needs to be done, as the semantics of insertion is intrinsicly atomic.

The unplug is done exactly in the same way. This code snippet sums up the whole thing.

2-2 - Reconfiguration through JMX

The Java Management Extensions (JMX) technology represents a universal, open technology for management, and monitoring that can be deployed wherever management and monitoring are needed. In Kilim, JMX is used to :

Specifying what is monitorable/visible/configurable in an existing Component

Making an existing component monitorable through JMX can easily be achieved in a few simple steps :

See template kilim/quotes/application/Yet Another Composite Inherited with JMX.kilim for more details.

Launching the JMX server, registering the Component

Now take the usual steps to launch you JMX server and your adaptors (a complete example is given in the test.LauncherJMX class).

The only thing you have to do to make your Kilim Component visible through any JMX console is to register it on the server. This can be achieved simply by :

And this is it. Your component is now visible, with all its exported properties and slots. You can now, through any JMX compliant console, do all the operations listed in the previous section (Reconfiguration API) without a line of Java, simply by clicking.

The LauncherJMX's code can be found in src/test/