KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > fortress > impl > AbstractContainer


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  *
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.avalon.fortress.impl;
19
20 import org.apache.avalon.excalibur.logger.LoggerManager;
21 import org.apache.avalon.fortress.Container;
22 import org.apache.avalon.fortress.MetaInfoEntry;
23 import org.apache.avalon.fortress.MetaInfoManager;
24 import org.apache.avalon.fortress.impl.extensions.InstrumentableCreator;
25 import org.apache.avalon.fortress.impl.factory.ProxyManager;
26 import org.apache.avalon.fortress.impl.handler.ComponentFactory;
27 import org.apache.avalon.fortress.impl.handler.ComponentHandler;
28 import org.apache.avalon.fortress.impl.handler.LEAwareComponentHandler;
29 import org.apache.avalon.fortress.impl.handler.PrepareHandlerCommand;
30 import org.apache.avalon.fortress.impl.lookup.FortressServiceManager;
31 import org.apache.avalon.fortress.impl.lookup.FortressServiceSelector;
32 import org.apache.avalon.fortress.util.CompositeException;
33 import org.apache.avalon.fortress.util.LifecycleExtensionManager;
34 import org.apache.avalon.fortress.util.dag.CyclicDependencyException;
35 import org.apache.avalon.fortress.util.dag.DirectedAcyclicGraphVerifier;
36 import org.apache.avalon.fortress.util.dag.Vertex;
37 import org.apache.avalon.framework.CascadingException;
38 import org.apache.avalon.framework.activity.Disposable;
39 import org.apache.avalon.framework.activity.Initializable;
40 import org.apache.avalon.framework.configuration.Configuration;
41 import org.apache.avalon.framework.container.ContainerUtil;
42 import org.apache.avalon.framework.context.Context;
43 import org.apache.avalon.framework.context.ContextException;
44 import org.apache.avalon.framework.context.Contextualizable;
45 import org.apache.avalon.framework.logger.AbstractLogEnabled;
46 import org.apache.avalon.framework.logger.Logger;
47 import org.apache.avalon.framework.service.DefaultServiceManager;
48 import org.apache.avalon.framework.service.ServiceException;
49 import org.apache.avalon.framework.service.ServiceManager;
50 import org.apache.avalon.framework.service.Serviceable;
51 import org.apache.commons.collections.BoundedFifoBuffer;
52 import org.apache.commons.collections.StaticBucketMap;
53 import org.apache.excalibur.event.Sink;
54 import org.apache.excalibur.instrument.InstrumentManager;
55 import org.apache.excalibur.instrument.Instrumentable;
56 import org.apache.excalibur.mpool.ObjectFactory;
57 import org.apache.excalibur.mpool.PoolManager;
58
59 import java.util.*;
60
61 /**
62  * This abstract implementation provides basic functionality for building
63  * an implementation of the {@link Container} interface.
64  * It exposes a protected getServiceManager() method so that the
65  * Container's Manager can expose that to the instantiating class.
66  *
67  * @author <a HREF="mailto:dev@avalon.apache.org">The Avalon Team</a>
68  * @version CVS $Revision: 1.41 $ $Date: 2004/02/28 15:16:24 $
69  */

70 public abstract class AbstractContainer
71         extends AbstractLogEnabled
72         implements Contextualizable, Serviceable, Initializable, Disposable, Container
73 {
74     /** The hint map's entry to get the default component type. */
75     public static final String JavaDoc DEFAULT_ENTRY = "*";
76     /** The component map's entry to get a ServiceSelector. */
77     public static final String JavaDoc SELECTOR_ENTRY = "$";
78
79     /** contains the impl's context passed in through contextualize(). */
80     protected Context m_context;
81     /** contains the ServiceManager the impl will use, based on the one passed in through service(). */
82     protected ServiceManager m_serviceManager;
83     /** contains the impl's LoggerManager, which is extracted from m_serviceManager. */
84     protected LoggerManager m_loggerManager;
85     /** contains the impl's PoolManager, which is extracted from m_serviceManager. */
86     protected PoolManager m_poolManager;
87     /** contains the impl's Sink, which is extracted from m_serviceManager. */
88     protected Sink m_commandSink;
89     /** contains the impl's root ClassLoader, which is extracted from m_serviceManager. */
90     protected ClassLoader JavaDoc m_classLoader;
91     /** contains the impl's RoleManager, which is extracted from m_serviceManager. */
92     protected MetaInfoManager m_metaManager;
93     /** contains the impl's InstrumentManager, which is extracted from m_serviceManager. */
94     protected InstrumentManager m_instrumentManager;
95     /** contains the impl's LifecycleExtensionManager, which is extracted from m_serviceManager. */
96     protected LifecycleExtensionManager m_extManager;
97     /**
98      * contains the context that will be passed to the components we will create.
99      * initialized the first time a component handler is created by a call to
100      * provideComponentContext -- override this method to affect the value of this object.
101      */

102     protected Context m_componentContext;
103     /**
104      * Contains entries mapping roles to hint maps, where the hint map contains
105      * mappings from hints to ComponentHandlers.
106      */

107     protected Map m_mapper = new StaticBucketMap();
108     /** Contains an entry for each ComponentHandler */
109     protected List m_components = new ArrayList( 10 );
110
111     protected List m_shutDownOrder;
112
113     private ProxyManager m_proxyManager;
114
115     /**
116      * Allows you to override the ProxyManager used in the container. In order for your proxymanager
117      * to be used, it <b>must</b> be set prior to adding any components.
118      * @param proxyManager
119      */

120     protected void setProxyManager( ProxyManager proxyManager )
121     {
122         if ( null == proxyManager ) throw new NullPointerException JavaDoc("proxyManager");
123         if ( null != m_proxyManager ) throw new IllegalStateException JavaDoc("Can not double-assign the ProxyManager");
124         m_proxyManager = proxyManager;
125     }
126
127     /**
128      * Guarantees that the ProxyManager will be assigned before use. If you do not set the proxy
129      * manager, the AbstractContainer will use the ProxyManager.DISCOVER algorithm.
130      *
131      * @return the ProxyManager.
132      * @throws Exception if there is a problem
133      */

134     protected ProxyManager getProxyManager() throws Exception JavaDoc
135     {
136         if ( null == m_proxyManager )
137         {
138             m_proxyManager = new ProxyManager( ProxyManager.DISCOVER );
139         }
140
141         return m_proxyManager;
142     }
143
144     /**
145      * Pull the manager items from the context so we can use them to set up
146      * the system.
147      *
148      * @avalon.context type="ClassLoader" optional="true"
149      *
150      * @param context the impl context
151      * @throws ContextException if a contexaulization error occurs
152      */

153     public void contextualize( final Context context )
154             throws ContextException
155     {
156         m_context = context;
157         try
158         {
159             m_classLoader = (ClassLoader JavaDoc) context.get( ClassLoader JavaDoc.class.getName() );
160         }
161         catch ( ContextException ce )
162         {
163             m_classLoader = Thread.currentThread().getContextClassLoader();
164         }
165     }
166
167     /**
168      * Root ServiceManager. The Container may choose to have it's
169      * ServiceManager delegate to the root manager, or it may choose to be
170      * entirely self contained.
171      *
172      * @param serviceManager the service manager to apply to the impl
173      * @throws ServiceException is a servicing related error occurs
174      *
175      * @avalon.dependency type="LoggerManager"
176      * @avalon.dependency type="PoolManager"
177      * @avalon.dependency type="InstrumentManager"
178      * @avalon.dependency type="MetaInfoManager"
179      * @avalon.dependency type="LifecycleExtensionManager" optional="true"
180      * @avalon.dependency type="Sink" optional="true"
181      */

182     public void service( final ServiceManager serviceManager )
183             throws ServiceException
184     {
185         // get non-optional services
186

187         m_loggerManager = (LoggerManager) serviceManager.lookup( LoggerManager.ROLE );
188         m_poolManager = (PoolManager) serviceManager.lookup( PoolManager.ROLE );
189         m_instrumentManager = (InstrumentManager) serviceManager.lookup( InstrumentManager.ROLE );
190
191         // get optional services, or a default if the service isn't provided
192

193         setupExtensionManager( serviceManager );
194
195         if ( serviceManager.hasService( Sink.ROLE ) )
196         {
197             m_commandSink = (Sink) serviceManager.lookup( Sink.ROLE );
198         }
199         else
200         {
201             final String JavaDoc message =
202                     "No " + Sink.ROLE + " is given, all " +
203                     "management will be performed synchronously";
204             getLogger().warn( message );
205         }
206
207         m_metaManager = (MetaInfoManager) serviceManager.lookup( MetaInfoManager.ROLE );
208
209         // set up our ServiceManager
210
m_serviceManager = provideServiceManager( serviceManager );
211     }
212
213     /**
214      * Set up the Lifecycle Extension Manager.
215      *
216      * @param serviceManager The serviceManager we are using to determine if the extension manager is being passed.
217      * @throws ServiceException if the ServiceManager does not live up to its contract.
218      */

219     private void setupExtensionManager( final ServiceManager serviceManager ) throws ServiceException
220     {
221         final Logger extLogger = m_loggerManager.getLoggerForCategory( "system.extensions" );
222
223         if ( serviceManager.hasService( LifecycleExtensionManager.ROLE ) )
224         {
225             final LifecycleExtensionManager parent = (LifecycleExtensionManager)
226                     serviceManager.lookup( LifecycleExtensionManager.ROLE );
227
228             if ( extLogger.isDebugEnabled() )
229             {
230                 final String JavaDoc message = "Found the LifecycleExtensionManager, creating a copy.";
231                 extLogger.debug( message );
232             }
233
234             m_extManager = parent.writeableCopy();
235         }
236         else
237         {
238             if ( extLogger.isDebugEnabled() )
239             {
240                 final String JavaDoc message = "No LifecycleExtensionManager found, creating a new one.";
241                 extLogger.debug( message );
242             }
243
244             m_extManager = new LifecycleExtensionManager();
245         }
246
247         /** LifecycleExtensionManager.writeableCopy() does not copy the logger. */
248         m_extManager.enableLogging( extLogger );
249
250         if ( extLogger.isDebugEnabled() )
251         {
252             final String JavaDoc message =
253                     "Adding an InstrumentableCreator to support our InstrumentManager";
254             extLogger.debug( message );
255         }
256
257         /**
258          * We do need a new InstrumentableCreator, as we want strictly our
259          * m_instrumentManager to be engaged. We assume there is no
260          * InstrumentableCreator in the LifecycleExtensionManager passed to us
261          * already. If there is one this is probably a bug. Not testing this currently,
262          * although might test this in the future in order to
263          * throw something like an IllegalArgumentException.
264          */

265         m_extManager.addCreatorExtension( new InstrumentableCreator( m_instrumentManager ) );
266     }
267
268     /**
269      * Add a Component into the impl. This sets the component up for management
270      * by the impl by creating an appropriate {@link ComponentHandler}.
271      *
272      * @param metaData the information needed to construct a ComponentHandler for the component
273      * @throws IllegalArgumentException if the classname defined by the meta data
274      * argument is undefined within the scope of the role manager
275      * @throws Exception if unable to create a Handler for the component
276      */

277     protected void addComponent( final ComponentHandlerMetaData metaData )
278             throws IllegalArgumentException JavaDoc, Exception JavaDoc
279     {
280         // figure out Role
281
final String JavaDoc classname = metaData.getClassname();
282         final MetaInfoEntry metaEntry = m_metaManager.getMetaInfoForClassname( classname );
283         if ( null == metaEntry )
284         {
285             final String JavaDoc message = "No role defined for " + classname;
286             throw new IllegalArgumentException JavaDoc( message );
287         }
288
289         if ( DEFAULT_ENTRY.equals( metaData.getName() ) ||
290                 SELECTOR_ENTRY.equals( metaData.getName() ) )
291         {
292             throw new IllegalArgumentException JavaDoc( "Using a reserved id name" + metaData.getName() );
293         }
294
295         Iterator it = metaEntry.getRoles();
296         // create a handler for the combo of Role+MetaData
297
final ComponentHandler handler =
298                 getComponentHandler( metaEntry, metaData );
299
300         while ( it.hasNext() )
301         {
302             final String JavaDoc role = (String JavaDoc) it.next();
303
304             // put the role into our role mapper. If the role doesn't exist
305
// yet, just stuff it in as DEFAULT_ENTRY. If it does, we create a
306
// ServiceSelector and put that in as SELECTOR_ENTRY.
307
if ( null != role && null != classname && null != handler )
308             {
309                 Map hintMap = (Map) m_mapper.get( role );
310
311                 // Initialize the hintMap if it doesn't exist yet.
312
if ( null == hintMap )
313                 {
314                     hintMap = createHintMap();
315                     hintMap.put( DEFAULT_ENTRY, handler );
316                     hintMap.put( SELECTOR_ENTRY,
317                             new FortressServiceSelector( this, role ) );
318                     m_mapper.put( role, hintMap );
319                 }
320
321                 hintMap.put( metaData.getName(), handler );
322
323                 if ( metaData.getConfiguration().getAttributeAsBoolean( "default", false ) )
324                 {
325                     hintMap.put( DEFAULT_ENTRY, handler );
326                 }
327             }
328         }
329     }
330
331     /**
332      * Get a ComponentHandler with the default constructor for the component class passed in.
333      *
334      * @param metaEntry the description of the Role this handler will be for
335      * @param metaData the information needed to construct a ComponentHandler for the component
336      * @return the component handler
337      * @throws Exception if unable to provide a componenthandler
338      */

339     private ComponentHandler getComponentHandler( final MetaInfoEntry metaEntry,
340                                                   final ComponentHandlerMetaData metaData )
341             throws Exception JavaDoc
342     {
343         // get info from params
344
final ComponentHandler handler;
345         final String JavaDoc classname = metaEntry.getComponentClass().getName();
346         final Configuration configuration = metaData.getConfiguration();
347
348         try
349         {
350             final ObjectFactory factory =
351                     createObjectFactory( classname, configuration );
352
353             // create the appropriate handler instance
354
final ComponentHandler targetHandler =
355                     (ComponentHandler) metaEntry.getHandlerClass().newInstance();
356
357             // do the handler lifecycle
358
ContainerUtil.enableLogging( targetHandler, getLogger() );
359             ContainerUtil.contextualize( targetHandler, m_context );
360             final DefaultServiceManager serviceManager =
361                     new DefaultServiceManager( getServiceManager() );
362             serviceManager.put( ObjectFactory.ROLE, factory );
363             serviceManager.makeReadOnly();
364
365             ContainerUtil.service( targetHandler, serviceManager );
366             ContainerUtil.configure( targetHandler, configuration );
367             ContainerUtil.initialize( targetHandler );
368
369             if ( targetHandler instanceof Instrumentable )
370             {
371                 final Instrumentable instrumentable = (Instrumentable) targetHandler;
372                 final String JavaDoc name = instrumentable.getInstrumentableName();
373                 m_instrumentManager.registerInstrumentable( instrumentable, name );
374             }
375
376             // no other lifecycle stages supported for ComponentHandler;
377
// ComponentHandler is not a "true" avalon component
378

379             handler =
380                     new LEAwareComponentHandler( targetHandler, m_extManager, m_context );
381         }
382         catch ( final Exception JavaDoc e )
383         {
384             // if anything went wrong, the component cannot be worked with
385
// and it cannot be added into the impl, so don't provide
386
// a handler
387
if ( getLogger().isDebugEnabled() )
388             {
389                 final String JavaDoc message =
390                         "Could not create the handler for the '" +
391                         classname + "' component.";
392                 getLogger().debug( message, e );
393             }
394             throw e;
395         }
396
397         if ( getLogger().isDebugEnabled() )
398         {
399             final String JavaDoc message =
400                     "Component " + classname +
401                     " uses handler " + metaEntry.getHandlerClass().getName();
402             getLogger().debug( message );
403         }
404
405         // we're still here, so everything went smooth. Register the handler
406
// and return it
407
final ComponentHandlerEntry entry =
408                 new ComponentHandlerEntry( handler, metaData );
409         m_components.add( entry );
410
411         return handler;
412     }
413
414     /**
415      * Create an objectFactory for specified Object configuration.
416      *
417      * @param classname the classname of object
418      * @param configuration the objests configuration
419      * @return the ObjectFactory
420      * @throws ClassNotFoundException if the specified class does not exist
421      */

422     protected ObjectFactory createObjectFactory( final String JavaDoc classname,
423                                                  final Configuration configuration )
424             throws Exception JavaDoc
425     {
426         if ( m_componentContext == null )
427         {
428             m_componentContext = provideComponentContext( m_context );
429             if ( m_componentContext == null )
430             {
431                 throw new IllegalStateException JavaDoc( "provideComponentContext() has returned null" );
432             }
433         }
434
435         final Class JavaDoc clazz = m_classLoader.loadClass( classname );
436         final ComponentFactory componentFactory =
437                 new ComponentFactory( clazz, configuration,
438                         m_serviceManager, m_componentContext,
439                         m_loggerManager, m_extManager );
440         return getProxyManager().getWrappedObjectFactory( componentFactory );
441     }
442
443     /**
444      * This is the method that the ContainerComponentManager and Selector use
445      * to gain access to the ComponentHandlers and ComponentSelectors. The
446      * actual access of the ComponentHandler is delegated to the Container.
447      *
448      * @param role The role we intend to access a Component for.
449      * @param hint The hint that we use as a qualifier
450      * (note: if null, the default implementation is returned).
451      *
452      * @return Object a reference to the ComponentHandler or
453      * ComponentSelector for the role/hint combo.
454      */

455     public Object JavaDoc get( final String JavaDoc role, final Object JavaDoc hint )
456             throws ServiceException
457     {
458         final Map hintMap = (Map) m_mapper.get( role );
459         Object JavaDoc value;
460
461         if ( null == hintMap )
462         {
463             final String JavaDoc key = getRoleKey( role, hint );
464             final String JavaDoc message = "Component does not exist";
465             throw new ServiceException( key, message );
466         }
467
468         if ( null == hint )
469         {
470             // no hint -> try selector
471
value = hintMap.get( SELECTOR_ENTRY );
472
473             if ( null == value )
474             {
475                 // no selector -> use default
476
value = hintMap.get( DEFAULT_ENTRY );
477             }
478
479             return value;
480         }
481
482         // got a hint -> use it
483
value = hintMap.get( hint );
484
485         if ( null == value )
486         {
487             final String JavaDoc key = getRoleKey( role, hint );
488             final String JavaDoc message = "Component does not exist";
489             throw new ServiceException( key, message );
490         }
491
492         return value;
493     }
494
495     /**
496      * Create the hint map for a role. The map may have to take care for thread-safety.
497      * By default a StaticBucketMap is created, but you may change the implementation
498      * or increment the number of buckets according your needs.
499      *
500      * <div>
501      * <span style="font-weight:strong;text-color: red;">WARNING:</span>
502      * This Map must be threadsafe, so either use the
503      * <code>StaticBucketMap</code> or a synchronized <code>Map</code>.
504      * Otherwise you will experience erratic behavior due to the nature
505      * of the asyncronous component management.
506      * </div>
507      *
508      * @return the hint map implementation
509      */

510     protected Map createHintMap()
511     {
512         return new StaticBucketMap();
513     }
514
515     /**
516      * Get the composite role name based on the specified role and hint.
517      * The default implementation puts a "/" on the end of the rolename
518      * and then adds the string representation of the hint.
519      * This is used <i>for informational display purposes only</i>.
520      *
521      * @param role
522      * @param hint
523      * @return
524      */

525     protected static String JavaDoc getRoleKey( final String JavaDoc role, final Object JavaDoc hint )
526     {
527         return role + "/" + hint;
528     }
529
530     /**
531      * This is the method that the ContainerComponentManager and Selector use
532      * to gain access to the ComponentHandlers and ComponentSelectors. The
533      * actual access of the ComponentHandler is delegated to the Container.
534      *
535      * @param role The role we intend to access a Component for.
536      * @param hint The hint that we use as a qualifier
537      * (note: if null, the default implementation is returned).
538      *
539      * @return true if a reference to the role exists.
540      */

541     public boolean has( final String JavaDoc role, final Object JavaDoc hint )
542     {
543         final Map hintMap = (Map) m_mapper.get( role );
544         boolean hasComponent = false;
545
546         if ( null != hintMap )
547         {
548             hasComponent = true;
549         }
550
551         if ( hasComponent )
552         {
553             if ( null == hint )
554             {
555                 // no hint -> try selector
556
hasComponent = hintMap.containsKey( SELECTOR_ENTRY );
557
558                 if ( !hasComponent )
559                 {
560                     // no hint -> try DEFAULT_ENTRY
561
hasComponent = hintMap.containsKey( DEFAULT_ENTRY );
562                 }
563             }
564             else
565             {
566                 // hint -> find it
567
hasComponent = hintMap.containsKey( hint );
568             }
569         }
570
571         return hasComponent;
572     }
573
574     /**
575      * Initializes the impl and all the components it hosts so that they are ready to be used.
576      * Unless components ask for lazy activation, this is where they are activated.
577      *
578      * @throws CompositeException if one or more components could not be initialized.
579      * The system <i>is</i> running properly so if the missing components are
580      * not vital to operation, it should be possible to recover gracefully
581      */

582     public void initialize()
583             throws CompositeException, Exception JavaDoc
584     {
585         // go over all components
586
final Iterator i = m_components.iterator();
587         final BoundedFifoBuffer buffer = new BoundedFifoBuffer( Math.max( m_components.size(), 1 ) );
588
589         // just to be on the safe side
590
m_extManager.makeReadOnly();
591
592         verifyComponents();
593
594         ComponentHandlerEntry entry;
595         while ( i.hasNext() )
596         {
597             entry = (ComponentHandlerEntry) i.next();
598             try
599             {
600                 final ComponentHandler handler = entry.getHandler();
601
602                 // Depending on the activation policy of the component decide
603
// how to initialize the component. Make sure that we can
604
// perform the specified activation policy, if not modify it.
605
int activation = entry.getMetaData().getActivation();
606                 if ( activation == ComponentHandlerMetaData.ACTIVATION_BACKGROUND )
607                 {
608                     // If a sink is not set then we must change to inline.
609
if ( null == m_commandSink )
610                     {
611                         activation = ComponentHandlerMetaData.ACTIVATION_INLINE;
612                     }
613                 }
614
615                 // We now have an activation policy we can handle.
616
switch ( activation )
617                 {
618                     case ComponentHandlerMetaData.ACTIVATION_BACKGROUND:
619                         // Add a command to initialize the component to the command
620
// sink so it will be initialized asynchronously in the
621
// background.
622
final PrepareHandlerCommand element =
623                                 new PrepareHandlerCommand( handler, getLogger() );
624                         m_commandSink.enqueue( element );
625                         break;
626
627                     case ComponentHandlerMetaData.ACTIVATION_INLINE:
628                         // Initialize the component now.
629
handler.prepareHandler();
630                         break;
631
632                     default: // ComponentHandlerMetaData.ACTIVATION_LAZY
633
if ( getLogger().isDebugEnabled() )
634                         {
635                             final String JavaDoc message = "ComponentHandler (" + handler +
636                                     ") has specified a lazy activation policy, " +
637                                     "initialization deferred until first use";
638                             getLogger().debug( message );
639                         }
640                         break;
641                 }
642             }
643             catch ( final CascadingException e )
644             {
645                 final String JavaDoc cName = entry.getMetaData().getName();
646
647                 if ( getLogger().isWarnEnabled() )
648                 {
649                     final String JavaDoc message = "Could not initialize component " + cName;
650                     getLogger().warn( message, e );
651
652                     final String JavaDoc cause = "Cause for exception";
653                     getLogger().warn( cause, e.getCause() );
654                 }
655                 buffer.add( e );
656             }
657             catch ( final Exception JavaDoc e )
658             {
659                 final String JavaDoc cName = entry.getMetaData().getName();
660
661                 if ( getLogger().isWarnEnabled() )
662                 {
663                     final String JavaDoc message = "Could not initialize component " + cName;
664                     getLogger().warn( message, e );
665                 }
666                 buffer.add( e );
667             }
668             catch ( final LinkageError JavaDoc le )
669             {
670                 final String JavaDoc cName = entry.getMetaData().getName();
671
672                 if ( getLogger().isWarnEnabled() )
673                 {
674                     final String JavaDoc message = "Could not initialize component " + cName;
675                     getLogger().warn( message, le );
676                 }
677                 buffer.add( le );
678             }
679         }
680
681         // if we were unable to activate one or more components,
682
// throw an exception
683
if ( buffer.size() > 0 )
684         {
685             throw new CompositeException( (Exception JavaDoc[]) buffer.toArray( new Exception JavaDoc[0] ),
686                     "unable to instantiate one or more components" );
687         }
688     }
689
690     private void verifyComponents() throws CyclicDependencyException
691     {
692         Map vertexMap = new HashMap();
693         List vertices = new ArrayList( m_components.size() );
694         Iterator it = m_components.iterator();
695
696         while ( it.hasNext() )
697         {
698             ComponentHandlerEntry entry = (ComponentHandlerEntry) it.next();
699             ComponentHandlerMetaData metaData = entry.getMetaData();
700
701             String JavaDoc name = metaData.getName();
702             Vertex v = (Vertex) vertexMap.get( name );
703             if ( v == null )
704             {
705                 v = new Vertex( name, entry.getHandler() );
706                 vertexMap.put( name, v );
707                 vertices.add( v );
708             }
709
710             MetaInfoEntry meta = m_metaManager.getMetaInfoForClassname( metaData.getClassname() );
711
712             Iterator dit = meta.getDependencies().iterator();
713             while ( dit.hasNext() )
714             {
715                 Map deps = (Map) m_mapper.get( dit.next() );
716
717                 /* Ignore for now... It is probably due to a component requiring a Container
718                  * component.... This happens when a required Service is not _directly_ handled
719                  * by this container.
720                  */

721                 if ( null == deps ) continue;
722
723                 Iterator mdit = deps.entrySet().iterator();
724                 while ( mdit.hasNext() )
725                 {
726                     Map.Entry depEntry = (Map.Entry) mdit.next();
727
728                     // If this key is neither the DEFAULT_ENTRY or the SELECTOR_ENTRY then we
729
// want to add a dependency vertex.
730
if ( !( depEntry.getKey().equals( DEFAULT_ENTRY ) ||
731                             depEntry.getKey().equals( SELECTOR_ENTRY ) ) )
732                     {
733                         String JavaDoc dName = depEntry.getKey().toString();
734                         Vertex dv = (Vertex) vertexMap.get( dName );
735                         if ( dv == null )
736                         {
737                             dv = new Vertex( dName, depEntry.getValue() );
738                             vertexMap.put( dName, dv );
739                             vertices.add( dv );
740                         }
741                         v.addDependency( dv );
742                     }
743                 }
744             }
745         }
746
747         DirectedAcyclicGraphVerifier.topologicalSort( vertices );
748
749         if ( getLogger().isDebugEnabled() )
750         {
751             getLogger().debug( "Component initialization order:" );
752             int i = 1;
753             for ( Iterator iter = vertices.iterator(); iter.hasNext(); i++ )
754             {
755                 Vertex v = (Vertex) iter.next();
756                 getLogger().debug( " #" + i + " (" + v.getOrder() + ") : " + v.getName() );
757             }
758         }
759
760         Collections.reverse( vertices );
761
762         m_shutDownOrder = vertices;
763     }
764
765     /**
766      * Disposes of all components and frees resources that they consume.
767      */

768     public void dispose()
769     {
770
771         if ( getLogger().isDebugEnabled() )
772         {
773             getLogger().debug( "Component shutdown order:" );
774             int i = 1;
775             for ( Iterator iter = m_shutDownOrder.iterator(); iter.hasNext(); i++ )
776             {
777                 Vertex v = (Vertex) iter.next();
778                 getLogger().debug( " #" + i + " (" + v.getOrder() + ") : " + v.getName() );
779             }
780         }
781
782         final Iterator i = m_shutDownOrder.iterator();
783         while ( i.hasNext() )
784         {
785             final Vertex entry = (Vertex) i.next();
786             final ComponentHandler handler = (ComponentHandler) entry.getNode();
787
788             if ( getLogger().isDebugEnabled() ) getLogger().debug( "Shutting down: " + handler );
789             ContainerUtil.dispose( handler );
790             if ( getLogger().isDebugEnabled() ) getLogger().debug( "Done." );
791         }
792     }
793
794     /**
795      * Exposes to subclasses the service manager which this impl
796      * uses to manage its child components.
797      * The returned ServiceManager <i>is</i> aware of the services passed
798      * in to <i>this</i> impl, and services that were passed in through
799      * service() are hence available to subclasses.
800      *
801      * @return the service manager that contains the child components.
802      */

803     protected ServiceManager getServiceManager()
804     {
805         return m_serviceManager;
806     }
807
808     /**
809      * Override this method to control creation of the serviceManager
810      * belonging to this container. This serviceManager is passed to
811      * child components as they are being created and is exposed via
812      * the getServiceManager() method.
813      * Invoked from the service() method.
814      *
815      * However even a self-contained container should be careful about
816      * cutting access to parent serviceManager completely, as important
817      * (and required) system services including Sink, LoggerManager,
818      * InstrumentManager, PoolManager and LifecycleExtensionManager
819      * are passed via ServiceManager also. SourceResolver hangs somewhere
820      * in between system and "user space" services.
821      *
822      * It's more or less okay to cut access to them if our child
823      * components do not need them and are not containers themselves,
824      * but if we have containers as our children they will require these
825      * services.
826      */

827     protected ServiceManager provideServiceManager( final ServiceManager parent )
828             throws ServiceException
829     {
830         return new FortressServiceManager( this, parent );
831     }
832
833     /**
834      * Override this method to control what context will be passed to
835      * the components created by this container. Called the first time
836      * a component being created - withing this implementation it is
837      * a part of the configure() stage.
838      * You may derive your context from m_context or create a new one.
839      */

840     protected Context provideComponentContext( final Context parent )
841             throws Exception JavaDoc
842     {
843         /* the default implementation: just use the same as for container itself */
844         return parent;
845     }
846 }
847
Popular Tags