You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by si...@avalon.apache.org on 2003/12/15 15:18:59 UTC

[Apache Avalon Wiki] New: ServiceManagerRelease

   Date: 2003-12-15T06:18:57
   Editor: 81.225.9.144 <>
   Wiki: Apache Avalon Wiki
   Page: ServiceManagerRelease

   Made a wiki page of it all.

New Page:

Few things generate so much controversy as the release() method of 
the Service''''''Manager. Let's take a look at a few of the common comments made (we see these 
periodically):

= try{}finally{release} is a PITA =

Yes it is. It is the price you pay for having a rich set of component 
lifestyles available to you automagically - we need to deal with all 
components as if they have a rich lifestyle, since the lifestyle is not 
exposed to the client (which is a Good Thing).

Note there's several things you can do to make this stuff easier. 
Consider adopting a code convention where you have private members with 
a ms_ (or something, for "My Service") prefix, then an abstract base 
class which implements dispose() and will release all those private 
members, then call super.dispose() as the last method inside your child 
class dispose() (if any):

{{{ public abstract class AbstractServiceDisposer    // UNTESTED CODE SKETCH
     extends AbstractLogEnabled
     implements Disposable, Serviceable
{
   private ServiceManager m_sm;

   public void service( ServiceManager sm )
   {
     m_sm = sm;
   }

   protected ServiceManager getServiceManager()
   {
     return m_sm;
   }

   public void dispose()
   {
     try
     {
       Field[] fields = this.getClass().getDeclaredFields();
       for( int i = 0; i < fields.length; i++ )
       {
         try
         {
           field = fields[i];
           if( field.getName().startsWith("ms_") )
             m_sm.release( field.get(this) );
         }
         catch( IllegalArgumentException iae )
         {
           // won't happen
         }
         catch( IllegalAccessException iace )
         {
           getLogger().warn( "Can't release all my services: " +
             "SecurityManager won't allow me to reflect on myself",
             iace );
         }
       }
     }
     catch( SecurityException se )
     {
        // we need permissions from security manager
        getLogger().warn( "Can't release all my services: " +
          "SecurityManager won't allow me to reflect on myself",
          se );
     }
} }}}

alternative approaches include mixins/AOP/etc. Before you do any of 
this, words of caution:

   http://lsd.student.utwente.nl/jicarilla/TooMuchMagic

= GC magic with finalize() can work =

GC magic is not part of the avalon-framework contract. Why? It can be 
somewhat buggy on obscure JDKs, it's expensive, it's complex, its 
misusing intended use of finalize().

To be on the safe and portable side, don't rely on it being available, 
nor on it to always work perfectly.

= Developers are dumb/lazy =

What you can do is create a framework on top of avalon that makes more 
assumptions about developer laziness that uses mechanisms such as the 
above. You'll want to coerce your dumb developer friends to all use your 
special class though.

= No-one uses it =

Errr...wrong. Service''''''Manager.release() is used in applications all over 
the globe. A notable one is cocoon.

= what about Releaseable, ReleaseRequired, ReleaseUtil? =

Been there, done that, won't work. Marking components as releasable will 
just mean you'll be checking whether they're marked as such, which is 
just as ugly.

= what if we add a method to the service interface? =

A SAXTransformer can't be used after its endDocument() method has been called,
so let's add one method to all services that you can call, and which indicates
that the component can be reclaimed / put in a pool / disposed.

Comment 1: Adding a release() method to the Component interface would be a
double whammy - not only do we bring back the most hated interface in Avalon
from its deprecation, we bring it back in tandem with the most hated method.
Nice.

Comment 2: The code doesn't get that much better. Instead of:

{{{ MyService ms = null;
try {
    ms = lookup(...);
    ...
} finally {
    release(ms);
} }}}

you get:

{{{ MyService ms = null;
try {
    ms = lookup(...);
    ...
} finally {
    if (ms != null) {
        ms.release();
    }
} }}}

which is a step sorta sideways-backward, with an extra null check being required.
(Having that null check encapsulated in a Release''''''Util.release(Object o) is '''not''' a
solution, see above.)

= It boils down to... =

There's a simple choice:

either
  * you restrict yourself to a subset of lifestyles that do not require
    release() semantics (example: Phoenix, PicoContainer);
or
  * you always do the release() semantics, even when they're not really
    required

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