Return-Path: Delivered-To: apmail-jakarta-avalon-cvs-archive@apache.org Received: (qmail 38796 invoked from network); 10 Feb 2002 05:39:56 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 10 Feb 2002 05:39:56 -0000 Received: (qmail 11280 invoked by uid 97); 10 Feb 2002 05:40:08 -0000 Delivered-To: qmlist-jakarta-archive-avalon-cvs@jakarta.apache.org Received: (qmail 11225 invoked by uid 97); 10 Feb 2002 05:40:07 -0000 Mailing-List: contact avalon-cvs-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Avalon CVS List" Reply-To: "Avalon Developers List" Delivered-To: mailing list avalon-cvs@jakarta.apache.org Received: (qmail 11214 invoked from network); 10 Feb 2002 05:40:07 -0000 Date: 10 Feb 2002 05:39:54 -0000 Message-ID: <20020210053954.98161.qmail@icarus.apache.org> From: mcconnell@apache.org To: jakarta-avalon-cvs@apache.org Subject: cvs commit: jakarta-avalon/src/proposal/service ServiceManager.java ServiceException.java Serviceable.java LifecycleHelper.java DefaultServiceManager.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N mcconnell 02/02/09 21:39:54 Added: src/proposal/service ServiceManager.java ServiceException.java Serviceable.java LifecycleHelper.java DefaultServiceManager.java Log: proposal for ComponentManager/Composable replacement Revision Changes Path 1.1 jakarta-avalon/src/proposal/service/ServiceManager.java Index: ServiceManager.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.framework.service; /** * A ServiceManager selects Objects based on a * role. The contract is that all the Objects implement the * differing roles and there is one Object per role. If you * need to select on of many Objects that implement the same * role, then you need to use a ServiceSelector. Roles are * usually the full interface name. * * A role is better understood by the analogy of a play. There are many * different roles in a script. Any actor or actress can play any given part * and you get the same results (phrases said, movements made, etc.). The exact * nuances of the performance is different. * * Below is a list of things that might be considered the different roles: * *
    *
  • InputAdaptor and OutputAdaptor
  • *
  • Store and Spool
  • *
* * The ServiceManager does not specify the methodology of * getting the Object, merely the interface used to get it. * Therefore the ServiceManager can be implemented with a * factory pattern, an object pool, or a simple Hashtable. * * @see org.apache.avalon.framework.service.Serviceable * @see org.apache.avalon.framework.service.ServiceSelector * * @author Federico Barbieri * @author Stefano Mazzocchi * @author Pierpaolo Fumagalli * @author Berin Loritsch * @author Stephen McConnell */ public interface ServiceManager { /** * Get the Object associated with the given role. For * instance, If the ServiceManager had a * LoggerComponent stored and referenced by role, I would use * the following call: *
       * try
       * {
       *     MyComponent log;
       *     myComponent = (MyComponent) manager.lookup(MyComponent.ROLE);
       * }
       * catch (...)
       * {
       *     ...
       * }
       * 
* * @param name The role name of the Object to retrieve. * @exception ServiceException if an error occurs */ Object lookup( String role ) throws ServiceException; /** * Check to see if a Object exists for a role. * * @param role a string identifying the role to check. * @return True if the object exists, False if it does not. */ boolean hasService( String role ); /** * Return the Object when you are finished with it. This * allows the ServiceManager to handle the End-Of-Life Lifecycle * events associated with the Object. Please note, that no Exceptions * should be thrown at this point. This is to allow easy use of the * ServiceManager system without having to trap Exceptions on a release. * * @param object The Object we are releasing. */ void release( Object object ); } 1.1 jakarta-avalon/src/proposal/service/ServiceException.java Index: ServiceException.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.framework.service; import org.apache.avalon.framework.CascadingException; /** * The exception thrown to indicate a problem with service. * It is usually thrown by ServiceManager or ServiceSelector. * * @author Peter Donald * @author Pierpaolo Fumagalli * @author Federico Barbieri * @author Stefano Mazzocchi * @author Stephen McConnell */ public class ServiceException extends CascadingException { /** * Construct a new ServiceException instance. * * @param message the exception message * @param throwable the throwable */ public ServiceException( final String message, final Throwable throwable ) { super( message, throwable ); } /** * Construct a new ServiceException instance. * * @param message the exception message */ public ServiceException( final String message ) { super( message, null ); } } 1.1 jakarta-avalon/src/proposal/service/Serviceable.java Index: Serviceable.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.framework.service; /** * A servicable is a class that need to connect to software components using * a "role" abstraction, thus not depending on particular implementations * but on behavioral interfaces. *
* * The contract surrounding a Serviceable is that it is a user. * The Serviceable is able to use Objects managed * by the ServiceManager it was initialized with. As part * of the contract with the system, the instantiating entity must call * the compose method before the Serviceable * can be considered valid. * * @author Federico Barbieri * @author Pierpaolo Fumagalli * @author Stefano Mazzocchi * @author Berin Loritsch * @author Stephen McConnell */ public interface Serviceable { /** * Pass the ServiceManager to the servicable. * The Servicable implementation should use the specified * ServiceManager to acquire the components it needs for * execution. * * @param manager The ServiceManager which this * Servicable uses. */ void service( ServiceManager manager ) throws ServiceException; } 1.1 jakarta-avalon/src/proposal/service/LifecycleHelper.java Index: LifecycleHelper.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.phoenix.components.application; import org.apache.avalon.excalibur.container.State; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.CascadingException; import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.activity.Startable; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.component.Composable; import org.apache.avalon.framework.component.DefaultComponentManager; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.avalon.framework.service.DefaultServiceManager; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.logger.LogEnabled; import org.apache.avalon.framework.logger.LogKitLogger; import org.apache.avalon.framework.logger.Loggable; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.parameters.Parameterizable; import org.apache.avalon.framework.parameters.ParameterException; import org.apache.avalon.phoenix.Block; import org.apache.avalon.phoenix.BlockContext; import org.apache.avalon.phoenix.BlockEvent; import org.apache.avalon.phoenix.BlockListener; import org.apache.avalon.phoenix.ApplicationListener; import org.apache.avalon.phoenix.ApplicationEvent; import org.apache.avalon.phoenix.interfaces.Application; import org.apache.avalon.phoenix.interfaces.ApplicationContext; import org.apache.avalon.phoenix.metadata.BlockListenerMetaData; import org.apache.avalon.phoenix.metadata.BlockMetaData; import org.apache.avalon.phoenix.metadata.DependencyMetaData; import org.apache.avalon.phoenix.metainfo.ServiceDescriptor; /** * This is a class to help an Application manage lifecycle of * Blocks and BlockListeners. The * class will run each individual Entry through each lifecycle stage, * and manage erros in a consistent way. * * @author Peter Donald */ class LifecycleHelper extends AbstractLogEnabled { private static final Resources REZ = ResourceManager.getPackageResources( LifecycleHelper.class ); //Constants to designate stages private final static int STAGE_CREATE = 0; private final static int STAGE_LOGGER = 1; private final static int STAGE_CONTEXT = 2; private final static int STAGE_COMPOSE = 3; private final static int STAGE_CONFIG = 4; private final static int STAGE_PARAMETER = 5; private final static int STAGE_INIT = 6; private final static int STAGE_START = 7; private final static int STAGE_STOP = 8; private final static int STAGE_DISPOSE = 9; private final static int STAGE_DESTROY = 10; //Constants to designate type of component private final static int TYPE_BLOCK = 0; private final static int TYPE_LISTENER = 1; ///Frame in which block executes private ApplicationContext m_context; /** * The Application which this phase is associated with. * Required to build a ComponentManager. */ private Application m_application; /** * Object to support notification of BlockListeners. */ private BlockListenerSupport m_blockListenerSupport = new BlockListenerSupport(); /** * Object to support notification of ApplicationListeners. */ private ApplicationListenerSupport m_applicationListenerSupport = new ApplicationListenerSupport(); /** * Construct helper object for specified application, * in specified frame. * * @param application the Application that this object is helper to * @param context the ApplicationContext in which this helper operates */ protected LifecycleHelper( final Application application, final ApplicationContext context ) { m_application = application; m_context = context; } /** * Method to run a BlockListener through it's startup phase. * This will involve creation of BlockListener object and configuration of * object if appropriate. * * @param metaData the BlockListenerMetaData * @exception Exception if an error occurs when listener passes * through a specific lifecycle stage */ public void startupListener( final BlockListenerMetaData metaData ) throws Exception { final String name = metaData.getName(); final ClassLoader classLoader = m_context.getClassLoader(); final Class clazz = classLoader.loadClass( metaData.getClassname() ); final BlockListener listener = (BlockListener)clazz.newInstance(); if( listener instanceof LogEnabled ) { final Logger logger = new LogKitLogger( m_context.getLogger( name ) ); ( (LogEnabled)listener ).enableLogging( logger ); } if( listener instanceof Configurable ) { final Configuration configuration = getConfiguration( name, TYPE_LISTENER ); ( (Configurable)listener ).configure( configuration ); } // As ApplicationListners are BlockListeners then this is applicable for all m_blockListenerSupport.addBlockListener( listener ); // However onky ApplicationListners can avail of block events. if (listener instanceof ApplicationListener) { m_applicationListenerSupport.addApplicationListener( (ApplicationListener) listener ); } } public void applicationStarting(ApplicationEvent appEvent) throws Exception { m_applicationListenerSupport.applicationStarting(appEvent); } public void applicationStarted() { m_applicationListenerSupport.applicationStarted(); } public void applicationStopping() { m_applicationListenerSupport.applicationStopping(); } public void applicationStopped() { m_applicationListenerSupport.applicationStopped(); } public void applicationFailure(Exception causeOfFailure) { m_applicationListenerSupport.applicationFailure(causeOfFailure); } /** * Method to run a Block through it's startup phase. * This will involve notification of BlockListener * objects, creation of the Block/Block Proxy object, calling the startup * Avalon Lifecycle methods and updating State property of BlockEntry. * Errors that occur during shutdown will be logged appropriately and * cause exceptions with useful messages to be raised. * * @param entry the entry containing Block * @exception Exception if an error occurs when block passes * through a specific lifecycle stage */ public void startup( final BlockEntry entry ) throws Exception { final BlockMetaData metaData = entry.getMetaData(); final String name = metaData.getName(); //The number of stage currently at //(Used in constructing error messages) int stage = 0; try { //Creation stage stage = STAGE_CREATE; notice( name, stage ); final Block block = createBlock( metaData ); //LogEnabled stage stage = STAGE_LOGGER; if( block instanceof Loggable ) { notice( name, stage ); ( (Loggable)block ).setLogger( m_context.getLogger( name ) ); } else if( block instanceof LogEnabled ) { notice( name, stage ); final Logger logger = new LogKitLogger( m_context.getLogger( name ) ); ( (LogEnabled)block ).enableLogging( logger ); } //Contextualize stage stage = STAGE_CONTEXT; if( block instanceof Contextualizable ) { notice( name, stage ); final BlockContext context = createBlockContext( name ); ( (Contextualizable)block ).contextualize( context ); } //Composition stage stage = STAGE_COMPOSE; if( block instanceof Composable ) { notice( name, stage ); final ComponentManager componentManager = createComponentManager( metaData ); ( (Composable)block ).compose( componentManager ); } else if( block instanceof Serviceable ) { notice( name, stage ); final ServiceManager manager = createServiceManager( metaData ); ( (Serviceable)block ).service( manager ); } //Configuring stage stage = STAGE_CONFIG; if( block instanceof Configurable ) { notice( name, stage ); final Configuration configuration = getConfiguration( name, TYPE_BLOCK ); ( (Configurable)block ).configure( configuration ); } //Parameterizing stage stage = STAGE_PARAMETER; if( block instanceof Parameterizable ) { notice( name, stage ); final Parameters parameters = Parameters.fromConfiguration( getConfiguration( name, TYPE_BLOCK ) ); parameters.makeReadOnly(); ( (Parameterizable)block ).parameterize( parameters ); } //Initialize stage stage = STAGE_INIT; if( block instanceof Initializable ) { notice( name, stage ); ( (Initializable)block ).initialize(); } //Start stage stage = STAGE_START; if( block instanceof Startable ) { notice( name, stage ); ( (Startable)block ).start(); } entry.setState( State.STARTED ); entry.setBlock( block ); exportBlock( metaData, block ); final Block proxy = entry.getProxy(); final BlockEvent event = new BlockEvent( name, proxy, metaData.getBlockInfo() ); m_blockListenerSupport.blockAdded( event ); } catch( final Throwable t ) { entry.setState( State.FAILED ); fail( name, stage, t ); } } /** * Method to run a Block through it's shutdown phase. * This will involve notification of BlockListener * objects, invalidating the proxy object, calling the shutdown * Avalon Lifecycle methods and updating State property of BlockEntry. * Errors that occur during shutdown will be logged appropraitely. * * @param entry the entry containing Block */ public void shutdown( final BlockEntry entry ) { final BlockMetaData metaData = entry.getMetaData(); final String name = metaData.getName(); final BlockEvent event = new BlockEvent( name, entry.getProxy(), metaData.getBlockInfo() ); m_blockListenerSupport.blockRemoved( event ); final Block block = entry.getBlock(); //Remove block from Management system unexportBlock( metaData, block ); //Invalidate entry. This will invalidate //and null out Proxy object aswell as nulling out //block property entry.invalidate(); //Stoppable stage if( block instanceof Startable ) { notice( name, STAGE_STOP ); try { entry.setState( State.STOPPING ); ( (Startable)block ).stop(); entry.setState( State.STOPPED ); } catch( final Throwable t ) { entry.setState( State.FAILED ); safeFail( name, STAGE_STOP, t ); } } //Disposable stage if( block instanceof Disposable ) { notice( name, STAGE_DISPOSE ); try { entry.setState( State.DESTROYING ); ( (Disposable)block ).dispose(); } catch( final Throwable t ) { entry.setState( State.FAILED ); safeFail( name, STAGE_DISPOSE, t ); } } notice( name, STAGE_DESTROY ); entry.setState( State.DESTROYED ); } /** * Export the services of block, declared to be management * services, into management system. */ private void exportBlock( final BlockMetaData metaData, final Block block ) throws CascadingException { final ServiceDescriptor[] services = metaData.getBlockInfo().getManagementAccessPoints(); final String name = metaData.getName(); final ClassLoader classLoader = block.getClass().getClassLoader(); for( int i = 0; i < services.length; i++ ) { final ServiceDescriptor service = services[ i ]; try { final Class clazz = classLoader.loadClass( service.getName() ); m_context.exportObject( name, clazz, block ); } catch( final Exception e ) { final String reason = e.toString(); final String message = REZ.getString( "export.error", name, service.getName(), reason ); getLogger().error( message ); throw new CascadingException( message, e ); } } } /** * Unxport the services of block, declared to be management * services, into management system. */ private void unexportBlock( final BlockMetaData metaData, final Block block ) { final ServiceDescriptor[] services = metaData.getBlockInfo().getManagementAccessPoints(); final String name = metaData.getName(); final ClassLoader classLoader = block.getClass().getClassLoader(); for( int i = 0; i < services.length; i++ ) { final ServiceDescriptor service = services[ i ]; try { final Class clazz = classLoader.loadClass( service.getName() ); m_context.unexportObject( name, clazz ); } catch( final Exception e ) { final String reason = e.toString(); final String message = REZ.getString( "unexport.error", name, service.getName(), reason ); getLogger().error( message ); } } } /** * Utility method to create a Block object * from specified BlockMetaData. * * @param metaData the BlockMetaData * @return the newly created Block object * @exception Exception if an error occurs */ private Block createBlock( final BlockMetaData metaData ) throws Exception { final ClassLoader classLoader = m_context.getClassLoader(); final Class clazz = classLoader.loadClass( metaData.getClassname() ); return (Block)clazz.newInstance(); } /** * Create a BlockContext object for Block with specified name. * * @param name the name of Block * @return the created BlockContext */ private BlockContext createBlockContext( final String name ) { final DefaultBlockContext context = new DefaultBlockContext( name, m_context ); setupLogger( context ); return context; } /** * Retrieve a configuration for specified component. * If the configuration is missing then a exception * is raised with an appropraite error message. * * @param name the name of component * @return the Configuration object * @exception ConfigurationException if an error occurs */ private Configuration getConfiguration( final String name, final int type ) throws ConfigurationException { try { return m_context.getConfiguration( name ); } catch( final ConfigurationException ce ) { //Note that this shouldn't ever happen once we //create a Config validator final String message = REZ.getString( "missing-configuration", new Integer( type ), name ); throw new ConfigurationException( message, ce ); } } /** * Create a ComponentManager object for a * specific Block. This requires that for * each dependency a reference to providing Block * is aaqiured from the Application and placing it in * ComponentManager under the correct name. * * @param metaData the BlockMetaData representing block * @return the created ComponentManager */ private ComponentManager createComponentManager( final BlockMetaData metaData ) { final DefaultComponentManager componentManager = new DefaultComponentManager(); final DependencyMetaData[] roles = metaData.getDependencies(); for( int i = 0; i < roles.length; i++ ) { final DependencyMetaData role = roles[ i ]; final Block dependency = m_application.getBlock( role.getName() ); componentManager.put( role.getRole(), dependency ); } return componentManager; } private ServiceManager createServiceManager( final BlockMetaData metaData ) { final DefaultServiceManager manager = new DefaultServiceManager(); final DependencyMetaData[] roles = metaData.getDependencies(); for( int i = 0; i < roles.length; i++ ) { final DependencyMetaData role = roles[ i ]; final Block dependency = m_application.getBlock( role.getName() ); manager.put( role.getRole(), dependency ); } return manager; } /** * Utility method to report that a lifecycle stage is about to be processed. * * @param name the name of block that caused failure * @param stage the stage */ private void notice( final String name, final int stage ) { if( getLogger().isDebugEnabled() ) { final String message = REZ.getString( "lifecycle-stage.notice", name, new Integer( stage ) ); getLogger().debug( message ); } } /** * Utility method to report that there was an error processing * specified lifecycle stage. * * @param name the name of block that caused failure * @param stage the stage * @param t the exception thrown */ private void safeFail( final String name, final int stage, final Throwable t ) { //final String reason = t.getMessage(); final String reason = t.toString(); final String message = REZ.getString( "lifecycle-fail.error", name, new Integer( stage ), reason ); getLogger().error( message ); } /** * Utility method to report that there was an error processing * specified lifecycle stage. It will also rethrow an exception * with a better error message. * * @param name the name of block that caused failure * @param stage the stage * @param t the exception thrown * @exception Exception containing error */ private void fail( final String name, final int stage, final Throwable t ) throws Exception { //final String reason = t.getMessage(); final String reason = t.toString(); final String message = REZ.getString( "lifecycle-fail.error", name, new Integer( stage ), reason ); getLogger().error( message ); throw new CascadingException( message, t ); } } 1.1 jakarta-avalon/src/proposal/service/DefaultServiceManager.java Index: DefaultServiceManager.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.framework.service; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * This class is a static implementation of a ServiceManager. Allow ineritance * and extension so you can generate a tree of ServiceManager each defining * Object scope. * * @author Federico Barbieri * @author Peter Donald * @author Stephen McConnell */ public class DefaultServiceManager implements ServiceManager { private final HashMap m_components = new HashMap(); private final ServiceManager m_parent; private boolean m_readOnly; /** * Construct ServiceManager with no parent. * */ public DefaultServiceManager() { this( null ); } /** * Construct ServiceManager with specified parent. * * @param parent the ServiceManager parent */ public DefaultServiceManager( final ServiceManager parent ) { m_parent = parent; } /** * Retrieve Object by role from ServiceManager. * * @param role the role * @return the Object * @exception ServiceException if an error occurs */ public Object lookup( final String role ) throws ServiceException { final Object component = m_components.get( role ); if( null != component ) { return component; } else if( null != m_parent ) { return m_parent.lookup( role ); } else { throw new ServiceException( "Unable to provide implementation for " + role ); } } public boolean hasService( final String role ) { boolean componentExists = false; try { this.release(this.lookup(role)); componentExists = true; } catch (Throwable t) { // Ignore all throwables--we want a yes or no answer. } return componentExists; } /** * Place Component into ComponentManager. * * @param role the components role * @param component the component */ public void put( final String role, final Object object ) { checkWriteable(); m_components.put( role, object ); } /** * Release component. * * @param component the component */ public void release( final Object component ) { // if the ServiceManager handled pooling, it would be // returned to the pool here. } /** * Build a human readable representation of ComponentManager2. * * @return the description of ComponentManager2 */ public String toString() { final StringBuffer buffer = new StringBuffer(); final Iterator components = m_components.keySet().iterator(); buffer.append( "Services:" ); while( components.hasNext() ) { buffer.append( "[" ); buffer.append( components.next() ); buffer.append( "]" ); } return buffer.toString(); } /** * Helper method for subclasses to retrieve parent. * * @return the parent ServiceManager */ protected final ServiceManager getParent() { return m_parent; } /** * Helper method for subclasses to retrieve component map. * * @return the component map */ protected final Map getComponentMap() { return m_components; } public void makeReadOnly() { m_readOnly = true; } protected final void checkWriteable() throws IllegalStateException { if( m_readOnly ) { throw new IllegalStateException( "ServiceManager is read only and can not be modified" ); } } } -- To unsubscribe, e-mail: For additional commands, e-mail: