> From: Stephen McConnell [mailto:[EMAIL PROTECTED]] 
> 
> The latest Merlin news is the completion of pluggable lifecycle 
> extensions. 


Now that I have had time to read the message in its entirety, here
are some observations:


> The extension framework is fully incorporated in the 
> component model - 
> components can declare a dependency on a lifecycle extension provider 
> via a <phase> declaration in the component type model.  For example:
> 
>    <component-info>
>       <component>
>         <name>my-component</name>
>       </component>
> 
>       <phases>
>         <phase>
>           <reference 
> type="org.apache.excalibur.playground.Exploitable" 
> version="1.0"/>
>         </phase>
>         <phase>
>           <reference 
> type="org.apache.excalibur.playground.Demonstratable"/>
>         </phase>
>       </phases>
> 
>    </componenent-info>
> 
> Declaration of a <phase/> is similar to the declaration of a service 
> dependency in that phase providers are managed by the Merlin 
> container 
> as dependencies of the target component.  In the above example, two 
> lifecycle extension dependencies are being declare.  The type 
> attribute 
> declares the lifecycle interface implemented by the component 
> - its up 
> to the container to resolve an appropriate lifecycle extension to 
> provide this to the target component when handling component 
> instantiation.


We can reduce the verbosity of the <component-info/> declaration by
merging the <reference/> element with the <phase/> and <extension/>
elements.  In essence, we are changing this:

<phases>
  <phase>
    <reference type="com.mycom.foobar.Demonstratable" version="1.0"/>
  </phase>
  <phase>
    <reference type="com.mycom.foobar.Exploitable"/>
  </phase>
</phases>

to this:

<phases>
  <phase reftype="com.mycom.foobar.Demonstratable" version="1.0"/>
  <phase reftype="com.mycom.foobar.Exploitable"/>
</phases>

And similarly with the extensions

<extension stage="ALL"
           type="com.mycom.foobar.Demonstratable"
           version="1.0">
  <name>demonstrate</name>
  <attributes>
    <attribute key="status" value="experimental"/>
  </attributes>
</extension>


At least from an XML point of view, it simplifies what someone has
to type.


> Lifecycle handlers are declared as extension of the "classic" 
> component 
> type definition.  Here is an example of a lifecycle handler.  It 
> publishes its ability to handle a phase via an <extension/> element.  
> The container is responsible for locating extension providers 
> based on 
> the matching of the <phase> type attribute with an 
> <extension><reference/> type attribute.  Selection of an extension 
> handler is identical to the selection of a service dependency.  This 
> means that multiple candidate extensions can exist within a singe 
> classloader scope.


Honestly, I'm not sure if I like this.  I prefer lifecycle extension
handlers being treated distinctly as such.  Maybe it would be better
if it had its own markup like this:

<extension-info>
  <!-- Declare everything else the same -->
</extension-info>



> Other important points are that a extension provider can 
> declare its own 
> phase dependencies and also classic service dependencies.  
> Merlin will 
> take care of the ordering of component establishment based on 
> the phase 
> and service dependencies that the component publishes. 
> 
> Extension providers must implement the following interface:
> 
>     org.apache.excalibur.merlin.assembly.resource.Extension
> 
> The interface declares the operation "extend( int stage, 
> Object object, 
> Context context ) which will be invoked by the Merlin 
> container during 
> the appropriate stages.  Merlin defines a number of stages 
> that can be 
> associated with an extension provider.  Merlin will only 
> invoke extend 
> if the provider declares that it supports the particular stage.
> 
> Standard stages include the following:
> 
>    CREATE    invoked immediately before initialization
>    ACCESS    invoked immediate before lookup
>    RELEASE   invoked immediately before release
>    DESTROY   invoked immediately before dispose
>    INNER     equivalent to ACCESS + RELEASE
>    OUTER     equivalinet to CREATE + DESTROY
>    ALL       equivalent to INNER + OUTER


:/

I kind of like Marcus' solution a bit better.  We have simple
methods that have a specific meaning.  If a lifecycle event happens
on more than one type of use (create/destroy/access/release),
the implementor has the freedom to use OO principles more clearly
by encapsulating the common elements in a separate method.

More often then not, we are not processing the same method even
if we are processing the same interface.  Take for instance the
following:

interface PersistantConfigurable
{
    void configure(Configuration conf);

    Configuration saveConfiguration();
}


Which is more clear?

Marcus solution:
------------------------------------------------------------------------
--

class PersistantConfigurableHandler extends AbstractExtension
{
     void create( Object component, Context context )
     throws Exception
     {
         if ( component instanceof PersistantConfigurable )
         {
             ((PersistantConfigurable) component)
                 .configure( (Configuration) context.get(
"configuration" ) );
         }
     }

     void destroy( Object component, Context context )
     throws Exception
     {
         if ( component instanceof PersistantConfigurable )
         {
             Configuration config = ((PersistantConfigurable) component)
                 .saveConfiguration();

             // perform config persistence here.
         }
     }
}

-----------------------------------------------------------------

Your solution:

-----------------------------------------------------------------

class PersistantConfigurableHandler implements LifecycleExtension
{
     void stage( int stage, Object component, Context context )
     throws Exception
     {
         if ( component instanceof PersistantConfigurable )
         {
             switch(stage)
             {
                 case CREATE:
                     ((PersistantConfigurable) component)
                         .configure( (Configuration) context.get(
"configuration" ) );
                     break;

                 case DESTROY:
                     Configuration config = ((PersistantConfigurable)
component)
                         .saveConfiguration();

                     // perform config persistence here.
                     break;
             }
         }
     }
}

---------------------------------------------------------------


I like having separate and distinct methods that do one thing, and
do not change behavior based on a value passed in.

The stage(...) solution gets much more complicated when you have more
than one interface you are supporting.


> Demonstration of extension declaration and phase declaration 
> is included 
> in the org.apache.excalibur.playground package (see 
> assembly/demo) - in 
> particular, the DemoManager, ExpliotationManager (both examples of 
> extension providers), and SimpleComponent - a multi-phase 
> phase consumer.


I will check your example to see if I completely missed what
I think you were saying here, but I don't think I'm that far
off.


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to