newton
Newton
 

Chainlink Demo

Summary

The chainlink demo application provides an introduction to Newton's SCA based component model. The demo runs entirely within a single JVM. The Remote Chainlink Demo extends this to the multi-JVM case.

The aim is to illustrate the full lifecycle of a deployable Newton composite, starting with dynamic resolution of install-time resources, then examining runtime auto-wireup of service dependencies, and finally looking at garbage collection of unused resources after all chainlink components have been removed.

Overview

Chainlink builds a chain out of Newton composites implementing the Link interface. Link has one method, String append(String txt). Implementations append some text to the String they are passed and then forward it on to the next link if there is one, otherwise returning the current value of the String. The demo makes use of two composite types that export services implementing the Link interface. Brace-link composites append their link name in braces, i.e "{name}", whereas Bracket-link composites use brackets, i.e. "[name]". The class structure is illustrated below.

_alt_

At the start of the demo, the Java classes which define the composites and the Link interface they implement are unknown to the Newton container. All are loaded dynamically as the composites are installed.

In Newton, the job of creating composites is delegated to composite specific factory bundles. These supply the code needed to create the composites, and act as factories for turning composite instance descriptors into runtime composite instances.

We will be creating chains that using a mixture of the two link composite types. To avoid class mismatch problems when we wire up the composites we must ensure that they both see the same version of the Link interface through which they connect. This means ensuring that the version of Link each uses is defined by the same ClassLoader. In OSGi this can be achieved by having both factory bundles import the package containing the Link interface from a third bundle, which we'll call the api bundle. See OSGi classloading for more details.

The above differs from the situation in traditional J2EE application servers, where extensibility and dynamic replaceability of components is limited to those implementing one of the fixed set of interfaces pre-defined by the application server, e.g. the Servlet interface. Newton makes use of OSGi's powerful peer classloading model to provide these facilities for arbitrary interfaces.

As well as links in the chain we also make use of a Command line interface (CLI), this has its own factory bundle, and also imports the link interface from the api bundle.

The bundles and their dependencies are illustrated below:

_alt_

Each factory bundle contains a composite template that describes the services the composite provides and the external references it uses. The two link composites provide a service implementing the Link interface and try to connect to references implementing the same interface. The chain will built by dynamically wiring up services and references corresponding to the different Link interfaces. The composite structure defined by the brace-link template is illustrated below. The bracket-link template is essentially the same.

_alt_

Here the component is based on an instance of the ExportingBraceLink class. It provides a service called link, which is obtained by calling the instance's _exportLink() method The multiplicity of (0,1) on the reference means that the composite wants to connect to at most 1 Link interface, but can still function if it can't find any. The wires link the service and reference to the concrete component.

The XML for this template is shown below. See The Newton Component Model for a walkthrough of composite template syntax.

<?xml version="1.0"?>
<composite name="braceLinkTemplate">
    <description>chainlink demo brace link</description>

    <reference name="nextLink" multiplicity="0..1">
        <interface.java interface="org.cauldron.newton.example.chainlink.interfaces.Link"/>
        <binding.osgi/>
    </reference>

    <service name="brace-link-export">
        <interface.java interface="org.cauldron.newton.example.chainlink.interfaces.Link"/>
            <binding.osgi/>
    </service>

    <component name="brace-link">
        <description>A brace decorated chain link</description>
        <property name="linkName" value="Unnamed" type="string"/>
        <service name="link"/>
        <reference name="nextLink"/>
        <implementation.java.callback impl="org.cauldron.newton.example.chainlink.brace.ExportingBraceLink"/>
    </component>

    <wire>
        <source.uri>brace-link/nextLink</source.uri>
        <target.uri>nextLink</target.uri>
    </wire>

    <wire>
        <source.uri>brace-link-export</source.uri>
        <target.uri>brace-link</target.uri>
    </wire>
</composite>

Running the demo

Booting the Newton container

In order to run the demo it is first necessary to start a single Newton container. To do this change to the bin directory and run

//for unix
$ ./container

//for windows
> container.bat

After starting Newton wait for the "Boot complete" message, after which Newton makes a command line available.

Loading bundles into CDS

The Content Distribution System (CDS) is Newton's distributed repository. At this point the bundles used by the chainlink demo are not present in the CDS, so they must be loaded. Note that this doesn't install anything, it just makes resources available for future installations.

To load the demo bundles run:

> cds scan boot examples/chainlink/build/lib

This loads all of the bundles in demo/build/lib into the boot zone of CDS, extracting metadata and indexing the bundles as they are loaded. Resources in the boot zone are local to the machine on which they are loaded.

Installing Chainlink instances

We now install several Link composites, all of type brace-link. Each composite is instantiated using a composite instance descriptor that identifies its factory bundle and constrains its template. As the first composite of type brace-link is being installed Newton looks up its factory bundle, resolves all of the bundles this depends on, and installs them. The factory bundle itself is then installed and started, after which it serves to convert instance descriptors into runtime composite instances.

To install the composites run the following.

> installer install examples/chainlink/build/etc/chainlink-local-a.composite
> installer install examples/chainlink/build/etc/chainlink-local-b1.composite
> installer install examples/chainlink/build/etc/chainlink-local-c.composite

To see the newly installed bundles enter bundles -i at the Newton console. To get an OSGi level view of the newly installed services enter services -i -l.

The three composite instances constrain the template metadata in different ways:

  • Composite A annotates its exported Link interface with tag=a and filters its imported a Link interface using tag=b
  • Composite B annotates its exported Link interface with tag=b and filters its imported a Link interface using tag=c
  • Composite C annotates its exported Link interface with tag=c and filters its imported a Link interface using tag=d

The instance descriptors for the three components are much the same, as an example here's the instance descriptor XML for component A.

<?xml version="1.0"?>
<composite name="LinkA">

    <bundle.root bundle="chainlink-local-brace-bundle" version="1.0"/>
    <include name="braceLinkTemplate"/>

    <reference name="nextLink">
        <binding.osgi filter="(tag=b)"/>
    </reference>

    <component name="brace-link">
        <description>link A</description>
        <property name="linkName" value="A-link" type="string"/>
    </component>

    <service name="brace-link-export">
        <binding.osgi>
            <attribute name="tag" value="a" type="string"/>
        </binding.osgi>
    </service>

</composite>

The <bundle.root ..> tag identifies the factory bundle for this composite type. The next line imports a composite template from this bundle, and the rest of the document overrides settings in this template. The <binding.osgi ..> elements define the scope of the services and references, and the <property ..> entries are passed to the service class constructor as a map. For more information see The Newton Component Model.

In general services are annotated using a name-value attribute map, and references are filtered using LDAP syntax.

Diagrammatically we have:

_alt_

As the composites are installed Newton examines their external interfaces, attributes and filters, and uses these to organize them into a chain as below

_alt_

Installing the chainlink Command line interface.

At this point the three brace-link composites have been installed and automatically wired up into a chain. In order to make calls on the chain we are going to a install a chainlink CLI composite. This composite has the following structure.

_alt_

To install the CLI type:

> installer install examples/chainlink/build/etc/chainlink-local-cli-a.composite

Once installed it's Link reference looks for a Link service satisfying it's (tag=a) filter. This causes it to bind to Link A. It's ConsoleCommandHandler service is dynamically wired up to a reference exposed by Newton's command line infrastrcuture and used to add a new command group to the Newton command line. To see the new command type:

> help
Available command groups (type 'enter' to enter a group):
system - commands for manipulating systems
storagecds - Commands for manipulating cds storage
sleep - sleeps for a configurable number of milliseconds
session - Session commands built into the console
provisioner - Commands for manipulating the provisioner
obr - OBR commands
logman - Commands for controlling logging within container
logconfig - Configuration commands for the log.
log - Log commands
installer - installs/uninstalls/tracks SCA components in this jvm
indexcds - Commands for manipulating the index service
ifconfig - Tools for managing configuration providers
framework - Framework commands
exec - executes a script from a file or url location
configuration - Configuration commands
chainlink-a - Commands for manipulating chains of Links
cds - Commands for manipulating cds content
binder - Tools for introspecting the binding graph

The command group we've just added is chainlink-a (third from bottom).

We can now use this command to make calls on the chain. When we do this each link appends its name in braces to the string it is passed until the end of the chain is reached. This is then returned along the chain to the original caller. Invoke the chain as follows:

> chainlink-a chain
chain: cli->{A-link}->{B1-link}->{C-link} [end of chain]

Dynamically rewiring the chain.

So far we've gone from a blank container to a wired up set of brace-link composites. We will now dynamically swap out the middle link, replacing it with a bracket-link composite.

First lets install the B2 composite. Since composite A's Link reference is already satisfied by the Link service provided by composite B1, composite B2's Link service is initially unused.

> installer install examples/chainlink/build/etc/chainlink-local-b2.composite

You can run chainlink-a chain again to verify that the chain hasn't changed. You can check that the bracket link bundle has loaded using bundles -i and that the new composite's Link interface has been exported using services -i -l

We now uninstall the B1 composite

> installer uninstall examples/chainlink/build/etc/chainlink-local-b1.composite

When B1 is removed, Newton realizes that composite A's Link reference is no longer satisfied, identifies the Link service on B2 as a suitable replacement and dynamically rewires the chain as we can see by running:

> chainlink-a chain
chain: cli->{A-link}->[B2-link]->{C-link} [end of chain]

Note that this time the name "B2-Link" is in brackets rather than braces.

Uninstalling chainlink & bundle garbage collection

Before uninstalling the chain take a look at the installed bundles by running:

> bundles -i
   id  level/state name
   --------------------
   ... (first 71 omitted) ...
   
   72  1/active    org.cauldron.newton.provisioner.service   
   73  1/active    org.cauldron.newton.provisioner.client
   74  1/resolved  com.sun.jmx.remote.optional   
   75  1/active    org.cauldron.newton.management.server
   76  1/active    org.cauldron.newton.management.monitor   
   77  1/active    org.cauldron.newton.boot.control
   78  1/resolved  chainlink-api-bundle    
   79  1/active    chainlink-local-brace-bundle
   80  1/active    chainlink-local-bracket-bundle   
   81  1/active    chainlink-local-cli-bundle
    

Bundles 78 to 81 are the ones that have been installed to support the chainlink composites.

Next uninstall all of the chainlink composites:

> installer uninstall examples/chainlink/build/etc/chainlink-local-a.composite
> installer uninstall examples/chainlink/build/etc/chainlink-local-b2.composite
> installer uninstall examples/chainlink/build/etc/chainlink-local-c.composite
> installer uninstall examples/chainlink/build/etc/chainlink-local-cli-a.composite

The components are now uninstalled. Shortly after this the bundle garbage collection mechanism, which runs on a bckground thread, will notice that the chainlink bundles are unused and remove them. You can speed this up by running

>installer gc

which will schedule a garbage collection sweep in the next 10 seconds. After this you can check that all unused bundles have been removed:

> bundles -i
   id  level/state name
   --------------------
   ... (first 71 omitted) ...
   
   72  1/active    org.cauldron.newton.provisioner.service   
   73  1/active    org.cauldron.newton.provisioner.client
   74  1/resolved  com.sun.jmx.remote.optional   
   75  1/active    org.cauldron.newton.management.server
   76  1/active    org.cauldron.newton.management.monitor   
   77  1/active    org.cauldron.newton.boot.control
   

At this point we are right back where we started, and have a blank container that knows nothing about chainlink or any of its classes. (Note that the chainlink bundles are still available in CDS, but these can easily be removed too, see CDS, although in a production system the contents of the distributed CDS would typically be long lived.)

Further exercises

  1. Observe the dependency and garbage collection code operating by installing/uninstalling composite instances in different orders.
  2. Using a combination of multiplicities, tags and filters it should be possible to create any number of chainlink configurations. Note some configurations may require modifications to the simple command line or link code if they specify circular dependencies (Newton copes well with circular dependencies, but individual applications may not)

Follow on Demos

  1. The Remote Chainlink Demo extends the current example to the multi JVM case