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 <code>ServiceManager</code> selects <code>Object</code>s based on a
* role. The contract is that all the <code>Object</code>s implement the
* differing roles and there is one <code>Object</code> per role. If you
* need to select on of many <code>Object</code>s that implement the same
* role, then you need to use a <code>ServiceSelector</code>. 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:
*
* <ul>
* <li> InputAdaptor and OutputAdaptor</li>
* <li> Store and Spool</li>
* </ul>
*
* The <code>ServiceManager</code> does not specify the methodology of
* getting the <code>Object</code>, merely the interface used to get it.
* Therefore the <code>ServiceManager</code> 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 <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Pierpaolo Fumagalli</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
*/
public interface ServiceManager
{
/**
* Get the <code>Object</code> associated with the given role. For
* instance, If the <code>ServiceManager</code> had a
* <code>LoggerComponent</code> stored and referenced by role, I would use
* the following call:
* <pre>
* try
* {
* MyComponent log;
* myComponent = (MyComponent) manager.lookup(MyComponent.ROLE);
* }
* catch (...)
* {
* ...
* }
* </pre>
*
* @param name The role name of the <code>Object</code> to retrieve.
* @exception ServiceException if an error occurs
*/
Object lookup( String role )
throws ServiceException;
/**
* Check to see if a <code>Object</code> 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 <code>Object</code> when you are finished with it. This
* allows the <code>ServiceManager</code> 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 <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Pierpaolo Fumagalli</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
*/
public class ServiceException
extends CascadingException
{
/**
* Construct a new <code>ServiceException</code> instance.
*
* @param message the exception message
* @param throwable the throwable
*/
public ServiceException( final String message, final Throwable throwable )
{
super( message, throwable );
}
/**
* Construct a new <code>ServiceException</code> 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.
* <br />
*
* The contract surrounding a <code>Serviceable</code> is that it is a user.
* The <code>Serviceable</code> is able to use <code>Object</code>s managed
* by the <code>ServiceManager</code> it was initialized with. As part
* of the contract with the system, the instantiating entity must call
* the <code>compose</code> method before the <code>Serviceable</code>
* can be considered valid.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Pierpaolo Fumagalli</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
*/
public interface Serviceable
{
/**
* Pass the <code>ServiceManager</code> to the <code>servicable</code>.
* The <code>Servicable</code> implementation should use the specified
* <code>ServiceManager</code> to acquire the components it needs for
* execution.
*
* @param manager The <code>ServiceManager</code> which this
* <code>Servicable</code> 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
* <code>Blocks</code> and <code>BlockListeners</code>. The
* class will run each individual Entry through each lifecycle stage,
* and manage erros in a consistent way.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
*/
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 <code>BlockListener</code> 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 <code>Block</code> through it's startup phase.
* This will involve notification of <code>BlockListener</code>
* 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 <code>Block</code> through it's shutdown phase.
* This will involve notification of <code>BlockListener</code>
* 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 <code>Block</code> 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 <code>ComponentManager</code> object for a
* specific <code>Block</code>. This requires that for
* each dependency a reference to providing <code>Block</code>
* is aaqiured from the Application and placing it in
* <code>ComponentManager</code> 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 <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
*/
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: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>