You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by Leo Simons <le...@apache.org> on 2003/04/18 01:34:07 UTC

[merlin] a view of a wizard's laboratory

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 
projects.

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,

cheers,

- Leo



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


Re: [merlin] a view of a wizard's laboratory

Posted by Stephen McConnell <mc...@apache.org>.

Leo Simons wrote:

> A view of a running merlin system
> --------------------------------- 


<snip ASCII art>

There is a better version here:

http://avalon.apache.org/sandbox/merlin/merlin/index.html

> 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. 


Under the current implementation the main conjuration concerns are the 
pool and logging manager.  These will be made configurable.  Engine 
related content in largely configurable under the current model.

> 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 block loading scheme has been refractored since this email.  A lot 
of improvements have been put in place that primarily simply things at 
the implementation level.  You may want to take another look at the 
StandardBlock and StandardBlockLoader classes - I think you will find a 
significant improvement.

>
> 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. 


It's not so complicated.  Basically you have a bunch of stuff to do with 
(a) classloader handling and (b) type/profile/service repositories.  In 
the longer term I figure that the type/profile/service repositories can 
be moved out into a separate service. In the meantime there have been a 
bunch of renaming of things that should make things clearing in terms of 
what's-what.

>
> 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.


Attaching a debugger can be a little scary if you don't know what is 
happening.  Basically Merlin is using Merlin to build and deploy the 
components that make up the system that an instance of Merlin 
represents.  This means that what you see in a debug is the deployment 
by Merlin of appliance instances that build and deploy other appliances 
instances that may build and deploy additional appliances instances - 
which basically reflects the fact that just about anything in the Merlin 
system can be treated as a full Avalon component (lifecycle handler, 
contextization stage, component deployer, deployment factory, etc.).  In 
practice - this means that there is a cycle - the deployment of a 
component - that is totally central to the integrity of the Merlin system.

>
> 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. 


Shutdown order is based on the service/dependency graph. I.e.  if a if 
component X is subject to shutdown, all components (Y) that are 
dependent on X will be shutdown and then same process is applied to Y 
before shutdown of X is initiated.  This means that no component 
consuming a shutdown target is running before the shutdown of X is 
initiated.

>
>
> 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.


Agreed.

There are two area on my hit-list - the lifestyle and the lifecycle 
packages (fortunately both represent implementation details).


>
> 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. 


There are some recent updates to Merlin that move "container" 
requirements to any component.  Placing Fortress into this context today 
is a feasible proposition (without any change to Fortress).


> 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.


Just a note on this - the meta generation needs a little more smarts 
concerning handling of "users" defined declarations.  Initially this 
will include skipping generation if a user-defined variant exists - and 
later on I would like this to validate the user-defined version as well.

> 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. 


There is a lot of flexibility - which begs the question - "is there too 
much"?  In some cases - maybe (in particular I'm thinking about the 
multiple lifecycle strategies.  On the other hand when dealing with 
non-Avalon components - this sort of stuff is basic requirements.  But 
yes - its nested - however - there is a bunch of stuff coming together 
which I hope will (a) document this, and (b) serve as examples, and (c) 
function as operation test cases.


>
> Merlin is a cool project with cool features


Something important happened earlier today concerning "cool" stuff.  
It's basically the completion of the "dynamic components" solution.  
Using block specifications in XML you can now declare in XML new 
components that export services based on the block XML implementation 
directives.  This is the thing I've been aiming towards for ages - the 
ability to declare a component model at the assembly level - and deploy 
it and have it behave like a component to the components that consume 
it.  A demonstration and test case are now available in CVS and the 
documentation on this will be up on the Avalon site ASAP.

Cheers, Steve.

-- 

Stephen J. McConnell
mailto:mcconnell@apache.org
http://www.osm.net

Sent via James running under Merlin as an NT service.



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