avalon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Leo Simons <leosim...@apache.org>
Subject [merlin] a view of a wizard's laboratory
Date Thu, 17 Apr 2003 23:34:07 GMT
A view of a running merlin system

| Merlin CLI (bootstrapping package)                    |
|                                                       |
| +---------------------------------------------------+ |
| | Merlin Kernel                                     | |
| |                                                   | |
| | +-----------------------------------------------+ | |
| | | Merlin root block                             | | |
| | |                                               | | |
| | | +-------------------------------------------+ | | |
| | | | Merlin root container                     | | | |
| | | |                                           | | | |
| | | | +------------------- +------------------+ | | | |
| | | | | Merlin appliance | | Merlin appliance | | | | |
| | | | |                  | |                  | | | | |
| | | | | -------------    | | -------------    | | | | |
| | | | | | Component |    | | | Component |    | | | | |
| | | | | -------------    | | -------------    | | | | |
| | | | +------------------+ +------------------+ | | | |
| | | |                                           | | | |
| | | +-------------------------------------------+ | | |
| | |                                               | | |
| | +-----------------------------------------------+ | |
| |                                                   | |
| +---------------------------------------------------+ |
|                                                       |
                               (a typical simple running merlin system)

What happens on startup
the merlin-cli module use commons-cli to parse its commandline arguments 
and set up the stuff the merlin kernel needs. It bootstraps merlin-core. 
It uses a KernelLoader to create a new Kernel instance.

when DefaultKernelLoader calls initialize() on DefaultKernel, the first 
thing DefaultKernel does is registering a shutdown hook with the 
runtime. It then creates several things it needs for setting up the root 
block (a logger manager, a thread pool, an assembly engine, a block 
loader). Which implementation to use for those things is currently not 
configurable and the methods which create them are private. This is 
different from the phoenix kernel, where you can specify implementations 
in the kernel.xml file. The DefaultKernel then proceeds on to set up and 
initialize the assembly engine and then the root block loader. It 
figures out which block should be its root block, and assembles then 
installs this block into the root block loader. After that, 
DefaultKernel won't do anything till shutdown.

Control transfers to the root block. This is a big ugly class which does 
lots of things when a block is installed, including recursively building 
a graph of all child blocks. Which block is created and what exactly 
needs to be set up for it is declared in a block.xml file whose location 
gets passed in from the command line.

The root block will normally be an instance of DefaultBlock, which will 
manage n appliances (which appliances to manage is configured via more 
xml config). It uses the assembly engine (EngineClassLoader from the 
merlin-assembly package) for actually building and setting up those 
appliances. This is again a huge complicated class which does DAG 
building and walking in proper ordering.

The usual appliances which are set up are DefaultAppliance and/or 
DefaultBlock (yes, you can nest merlin inside itself to arbitrary 
depth), which are again complicated classes to wrap around a component. 
They work together with the assembly engine to dynamically setup and 
manage the component they host.

At some point in time, all graphs will have been traversed, and all 
components will hopefully have been properly set up and initialized. I'm 
not going to go into bigger detail on the assembly and appliance 
internals right now; attaching a debugger and using "go to declaration" 
will get you from place to place easily enough.

What happens on shutdown
When you tell the java runtime to terminate, the shutdown hook of 
DefaultKernel kicks in and calls shutdown() on the kernel, which resuls 
in shutdown of the root block, which resuls in shutdown of the 
containers, appliances, blocks and components created during the above 
phases in reverse order.

A view on this setup
Clearly, it is an order of magnitude more complex than what fortress or 
phoenix does. There is lots of complex, dynamic logic involved in the 
resolution of the multiple (possibly dozens) levels, with implementation 
spread out over several complex default implementations. Coupling 
between component implementations is at some points more tight than one 
would expect from the seperation of spi and implementation; clearly 
merlin needs at least a round or two of refactoring to extend the spi 
interfaces and reduce the coupling between its components.

Fortress is something you might wrap as an implementation of what is a 
"container" in the merlin context, then run inside one of the blocks 
hosted by the root block. Merlin would not typically want to host 
phoenix: it does most of the things phoenix is used for by itself.

The reverse very is possible: DefaultKernel is an avalon component which 
you should be able to run within phoenix without notable issues. Since 
all classes described above are indeed components, you can also embed 
only part of the merlin subsystem as a component inside another 
container, for example you could also choose to bypass DefaultKernel and 
DefaultBlock and host DefaultAppliance directly.

The Merlin metadata attribute system
Is completely seperate from the runtime; you generate xml files (which 
are parsed as avalon configuration objects during startup) from javadoc 
tags. These xml files contain lots of declarations of what the system 
does and assumes, exactly.

An opinion
In my opinion, merlin has too many layers, and the seperation between 
those layers is at some points blurry. While there are some very 
powerful features up this wizard's sleeve, they are hidden nested 
several levels deep into the code.

Digesting the organisation of its internals takes way more time than for 
Fortress (which I "got" nearly completely in an afternoon) or Phoenix 
(which I basically learned in a single night). I am guessing I've also 
misunderstood some things, probably partly due to my dislike of 
scrolling long sourcefiles.

Merlin is a cool project with cool features, but it will take most 
people more time than me (and it took me too long already IMO) to digest 
its internals before being able to get to work on it, and that is a huge 
(by far the biggest, actually) downside of the package.

Cross-container integration options

Merlin's Fortress

Given the nice self-containment of fortress, it is probably relatively 
easy to write a FortressContainer which implements the Container 
interface from merlin by wrapping around the fortress DefaultContainer. 
This would allow rather clean transparent integration between the two 

Fortified Merlin

Similarly, Merlin's DefaultKernel is a proper component which has no 
particularly heavy requirements and can likely be loaded into fortress 
rather easily.

Merlin's Phoenix

You don't want to embed phoenix inside merlin. Generally, you don't want 
to embed phoenix but do things the other way around (my opinion).

Foxy Merlin

DefaultKernel feels threadsafe alright, so you can easily run it as a 
component inside phoenix (possibly best to use a thin wrapper around it).

Merlin's Plexus

Haven't looked at plexus recently, but last time I checked is was pretty 
similar to fortress in scope and usage pattern. I think what I say about 
integration between fortress and merlin applies to integration between 
merlin and plexus as well.

hope this is of use,


- Leo

To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org

View raw message