mcconnell 2003/01/08 19:59:39 Modified: merlin kernel.xml merlin/src/java/org/apache/avalon/merlin/block Block.java DefaultBlock.java merlin/src/java/org/apache/avalon/merlin/container Container.java DefaultContainer.java merlin/src/test/org/apache/avalon/playground StandardComponent.xinfo Added: merlin/src/java/org/apache/avalon/merlin/container StateEvent.java StateListener.java Log: Addition of support for per-thread containers. Revision Changes Path 1.12 +1 -1 avalon-sandbox/merlin/kernel.xml Index: kernel.xml =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/kernel.xml,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- kernel.xml 8 Jan 2003 20:57:48 -0000 1.11 +++ kernel.xml 9 Jan 2003 03:59:39 -0000 1.12 @@ -15,7 +15,7 @@ </logging> <categories> - <category name="/sys" priority="DEBUG"/> + <category name="/sys" priority="INFO"/> </categories> <!-- 1.6 +26 -2 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/Block.java Index: Block.java =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/Block.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- Block.java 27 Dec 2002 16:38:54 -0000 1.5 +++ Block.java 9 Jan 2003 03:59:39 -0000 1.6 @@ -62,7 +62,31 @@ * @author <a href="mailto:avalon-dev@jakarta.apache.org">Avalon Development Team</a> * @version $Revision$ $Date$ */ -public interface Block extends Appliance, Container +//public interface Block extends Appliance, Container +public interface Block extends Appliance { static final String AVALON_BLOCK_KEY = "Avalon-Block"; + + /** + * Startup the block and startup all subsidiary blocks. + * @exception Exception if a startup error occurs + */ + void startup() throws Exception; + + /** + * Suspend the block and all subsidiary blocks. + */ + void suspend(); + + /** + * Resume the block and all subsidiary blocks. + */ + void resume(); + + /** + * Shutdown the block. + * @exception Exception if a shutdown error occurs + */ + void shutdown() throws Exception; + } 1.11 +242 -14 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/DefaultBlock.java Index: DefaultBlock.java =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/DefaultBlock.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- DefaultBlock.java 7 Jan 2003 04:24:16 -0000 1.10 +++ DefaultBlock.java 9 Jan 2003 03:59:39 -0000 1.11 @@ -4,8 +4,9 @@ import java.io.File; import java.io.IOException; -import java.util.jar.JarFile; import java.net.URL; +import java.util.List; +import java.util.ArrayList; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.jar.JarFile; @@ -24,6 +25,7 @@ import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.activity.Initializable; +import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.context.ContextException; @@ -33,6 +35,8 @@ import org.apache.avalon.merlin.container.DefaultContainer; import org.apache.avalon.merlin.container.ContainerDescriptor; import org.apache.avalon.merlin.container.Container; +import org.apache.avalon.merlin.container.StateListener; +import org.apache.avalon.merlin.container.StateEvent; import org.apache.avalon.meta.info.Type; import org.apache.avalon.meta.info.builder.XMLTypeCreator; import org.apache.avalon.meta.info.StageDescriptor; @@ -47,11 +51,11 @@ * responsible for the establishment of a containment heirachy that * represents the implemetation model for the block. */ -public class DefaultBlock extends DefaultAppliance implements Block +public class DefaultBlock extends DefaultAppliance implements Block, Runnable, StateListener { - //============================================================== + //------------------------------------------------------------------------------- // static - //============================================================== + //------------------------------------------------------------------------------- public static final Attributes.Name BLOCK_PACKAGE = new Attributes.Name( "Block-Package" ); public static final Attributes.Name OLD_BLOCK_NAME = new Attributes.Name( "Block-Name" ); @@ -84,17 +88,52 @@ } - //============================================================== + //------------------------------------------------------------------------------- // state - //============================================================== + //------------------------------------------------------------------------------- + /** + * The root container instance that this block is managing. + */ private Container m_container; + /** + * Flag holding the assembled state of the block. + */ private boolean m_assembled = false; - //============================================================== + /** + * The thread in which we will run the container. + */ + private Thread m_thread; + + /** + * Flag holding the running state of the block. + */ + private boolean m_running = false; + + /** + * The container is managed as a thread under which the current state + * is recorded in the m_state state member. + */ + private int m_state = StateEvent.UNKNOWN; + + /** + * The thread periodically checks for state change requests enter in + * the m_action state member and attempts to bring the m_state value to + * be equal to the m_action value and once achieved goes off for a + * sleep. + */ + private Integer m_action = new Integer( StateEvent.UNKNOWN ); + + /** + * An error raised by the managed container. + */ + private BlockException m_error; + + //------------------------------------------------------------------------------- // constructor - //============================================================== + //------------------------------------------------------------------------------- public DefaultBlock( EngineClassLoader engine, LifestyleService lifestyle, AssemblyService assembly, @@ -102,11 +141,88 @@ throws ApplianceException { super( engine, lifestyle, assembly, context, system, logger ); + m_thread = new Thread( this, super.getPath() ); + m_thread.setContextClassLoader( engine ); + m_thread.start(); } - //============================================================== - // Block - //============================================================== + //------------------------------------------------------------------------------- + // Runnable + //------------------------------------------------------------------------------- + + /** + * Starts the thread of execution for the block. This operation is + * invoked by the container constructor. + */ + public void run() + { + if( !m_running ) + { + m_running = true; + } + + try + { + + // + // while desired state of the hosted container is something + // other than DISPOSED, check if the desired state is different + // from the current state reported by the container, and if + // so initiate a container state change + // + + while( m_action.intValue() < StateEvent.DISPOSED ) + { + synchronized( m_action ) + { + if( m_state != m_action.intValue() ) + { + switch( m_action.intValue() ) + { + case StateEvent.STARTED: + if( m_state == StateEvent.INITIALIZED ) + { + m_container.startup(); + } + else if( m_state == StateEvent.SUSPENDED ) + { + m_container.resume(); + } + break; + case StateEvent.SUSPENDED: + if( m_state == StateEvent.STARTED ) + { + m_container.suspend(); + } + break; + case StateEvent.STOPPED: + if( ( m_state == StateEvent.STARTED ) + || ( m_state == StateEvent.SUSPENDED ) ) + { + m_container.shutdown(); + } + break; + } + } + } + sleep(); + } + if( m_container instanceof Disposable ) + { + ((Disposable)m_container).dispose(); + } + } + catch( Throwable e ) + { + final String error = "Unexpected error during container execution."; + m_error = new BlockException( error, e ); + terminate(); + } + } + + //------------------------------------------------------------------------------- + // Appliance + //------------------------------------------------------------------------------- /** * Assemble the appliance. The implementation extends the default @@ -135,6 +251,7 @@ { m_assembled = true; m_container = (Container) super.access(); + m_container.addStateListener( this ); m_container.assemble(); } catch( Throwable e ) @@ -151,6 +268,29 @@ */ public void terminate() { + synchronized( this ) + { + if( m_error == null ) + { + m_action = new Integer( StateEvent.DISPOSED ); + while( ( m_state < StateEvent.DISPOSED ) && ( m_error == null ) ) + { + sleep(); + } + } + else + { + if( getLogger().isErrorEnabled() ) + { + getLogger().error( "terminating due to container error", m_error ); + } + if( m_container instanceof Disposable ) + { + ((Disposable)m_container).dispose(); + } + } + } + if( m_container != null ) { release( m_container ); @@ -160,7 +300,7 @@ } //------------------------------------------------------------------------------- - // Container + // Block //------------------------------------------------------------------------------- /** @@ -173,7 +313,56 @@ { throw new IllegalStateException( "assembly" ); } - m_container.startup(); + + synchronized( this ) + { + m_action = new Integer( StateEvent.STARTED ); + while( ( m_state < StateEvent.STARTED ) && ( m_error == null ) ) + { + sleep(); + } + if( m_error != null ) + { + throw m_error; + } + } + } + + /** + * Request for the container to suspend all subsidiary containers + * and all contained components. + */ + public void suspend() + { + synchronized( this ) + { + m_action = new Integer( StateEvent.SUSPENDED ); + while( ( m_state < StateEvent.SUSPENDED ) && ( m_error == null ) ) + { + sleep(); + } + } + } + + /** + * Request for the container to resume all subsidiary containers + * and all contained components. + */ + public void resume() + { + if( m_state != StateEvent.SUSPENDED ) + { + throw new IllegalStateException( "not-suspended." ); + } + + synchronized( this ) + { + m_action = new Integer( StateEvent.STARTED ); + while( ( m_state == StateEvent.SUSPENDED ) && ( m_error == null ) ) + { + sleep(); + } + } } /** @@ -186,6 +375,45 @@ { throw new IllegalStateException( "assembly" ); } - m_container.shutdown(); + synchronized( this ) + { + m_action = new Integer( StateEvent.STOPPED ); + while( ( m_state < StateEvent.STOPPED ) && ( m_error == null ) ) + { + sleep(); + } + if( m_error != null ) + { + throw m_error; + } + } + } + + /** + * Method invoked when a container state changes. + * @param event the state event + */ + public void stateChanged( StateEvent event ) + { + if( getLogger().isDebugEnabled() ) + { + getLogger().debug("state event: [" + event.getState() + "]" ); + } + m_state = event.getState(); + } + + /** + * Internal utility to sleep a bit. + */ + private void sleep() + { + try + { + Thread.currentThread().sleep( 100 ); + } + catch( Throwable wakeup ) + { + // return + } } } 1.4 +25 -1 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/Container.java Index: Container.java =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/Container.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Container.java 27 Dec 2002 16:41:06 -0000 1.3 +++ Container.java 9 Jan 2003 03:59:39 -0000 1.4 @@ -85,10 +85,34 @@ */ void startup() throws Exception; + /** + * Request for the container to suspend all subsidiary containers + * and all contained components. + */ + void suspend(); + + /** + * Request for the container to resume all subsidiary containers + * and all contained components. + */ + void resume(); + /** * Shutdown all subsidiary containers and all components in this container. * @exception Exception if a shutdown error occurs */ void shutdown() throws Exception; + + /** + * Adds a <code>StateListener</code> to the container. + * @param listener the state listener to add + */ + void addStateListener( StateListener listener ); + + /** + * Removes a <code>StateListener</code> from the container. + * @param listener the state listener to remove + */ + void removeStateListener( StateListener listener ); } 1.12 +324 -57 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.java Index: DefaultContainer.java =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- DefaultContainer.java 28 Dec 2002 08:06:43 -0000 1.11 +++ DefaultContainer.java 9 Jan 2003 03:59:39 -0000 1.12 @@ -140,6 +140,17 @@ */ private Configuration m_targets; + /** + * State event listener list. + */ + private List m_listeners = new ArrayList(); + + /** + * The container is managed as a thread under which the current state + * is recorded in the m_state state member. + */ + private int m_state = StateEvent.UNKNOWN; + //============================================================== // Contextualizable //============================================================== @@ -193,7 +204,6 @@ if( getLogger().isDebugEnabled() ) { getLogger().debug( "initialization: " + m_path + " (" + profiles.length + ")" ); - //getLogger().debug( "configuration array:\n" + ConfigurationUtil.list( m_targets ) ); } for( int i=0; i<profiles.length; i++ ) @@ -269,13 +279,199 @@ */ public void assemble() throws AssemblyException { + if( m_state < StateEvent.INITIALIZED ) + { + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "assembly" ); + } + + assembleComponents(); + assembleContainers(); + + m_state = StateEvent.INITIALIZED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.INITIALIZED ) ); + } + } + + /** + * Startup the components in this container and startup all subsidiary + * containers. + * @exception Exception if a startup error occurs + */ + public void startup() throws Exception + { + if( m_state < StateEvent.INITIALIZED ) + { + throw new IllegalStateException( + "Container has not been initialized." ); + } + + if( m_state == StateEvent.STARTED ) + { + return; + } + + if( m_state > StateEvent.STARTED ) + { + throw new IllegalStateException( + "Container has already passed through start phase." ); + } + if( getLogger().isDebugEnabled() ) { - getLogger().debug( "assembly" ); + getLogger().debug( "startup" ); } - - assembleComponents(); - assembleContainers(); + + startupComponents(); + startupContainers(); + + m_state = StateEvent.STARTED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.STARTED ) ); + } + + /** + * Request for the container to suspend all subsidiary containers + * and all contained components. + */ + public void suspend() + { + if( m_state < StateEvent.INITIALIZED ) + { + throw new IllegalStateException( + "Container has not been initialized." ); + } + + if( m_state == StateEvent.SUSPENDED ) + { + return; + } + + if( m_state > StateEvent.STOPPED ) + { + throw new IllegalStateException( + "Container has been stopped." ); + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "container suspension" ); + } + + suspendContainers(); + suspendComponents(); + + getLogger().debug( "container suspension complete" ); + m_state = StateEvent.SUSPENDED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.SUSPENDED ) ); + } + + /** + * Request for the container to resume all subsidiary containers + * and all contained components. + */ + public void resume() + { + if( m_state != StateEvent.SUSPENDED ) + { + throw new IllegalStateException( + "Container is not suspended." ); + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "container resuming" ); + } + + // + // resume subsidiary containers + // + + resumeComponents(); + resumeContainers(); + + getLogger().debug( "container resumption complete" ); + m_state = StateEvent.STARTED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.STARTED ) ); + } + + + /** + * Shutdown all subsidiary containers and all components in this container. + * @exception Exception if a shutdown error occurs + */ + public void shutdown() throws Exception + { + if( m_state < StateEvent.STARTED ) + { + return; + } + + if( m_state == StateEvent.STOPPED ) + { + return; + } + + if( m_state > StateEvent.STOPPED ) + { + throw new IllegalStateException( "Already stopped." ); + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "shutdown" ); + } + + // + // shutdown all of the nested containers before stopping + // the components in this container + // + + shutdownContainers(); + shutdownComponents(); + + m_state = StateEvent.STOPPED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.STOPPED ) ); + } + + /** + * Disposal of the container. + */ + public void dispose() + { + if( m_state == StateEvent.DISPOSED ) + { + return; + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "disposal" ); + } + + disposeContainers(); + disposeComponents(); + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "cleanup" ); + } + + m_state = StateEvent.DISPOSED; + fireStateChange( new StateEvent( this, m_descriptor.getName(), StateEvent.DISPOSED, null ) ); + + m_engine = null; + m_descriptor = null; + m_componentMap.clear(); + m_components.clear(); + m_componentMap = null; + m_components = null; + m_containerMap.clear(); + m_containers.clear(); + m_containerMap = null; + m_containers = null; + m_partition = null; + m_path = null; } /** @@ -308,21 +504,6 @@ } /** - * Startup the components in this container and startup all subsidiary - * containers. - * @exception Exception if a startup error occurs - */ - public void startup() throws Exception - { - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "startup" ); - } - startupComponents(); - startupContainers(); - } - - /** * Startup the components in this container. * @exception Exception if a startup error occurs */ @@ -383,17 +564,75 @@ } /** - * Shutdown all subsidiary containers and all components in this container. - * @exception Exception if a shutdown error occurs + * Startup the components in this container. + * @exception Exception if a startup error occurs */ - public void shutdown() throws Exception + private void suspendComponents() { - if( getLogger().isDebugEnabled() ) + // not implemented - more thinking needed about the + // concepts of deployment strategies + } + + /** + * Startup the containers in this container. + * @exception Exception if a startup error occurs + */ + private void suspendContainers() + { + Iterator iterator = m_containers.iterator(); + while( iterator.hasNext() ) { - getLogger().debug( "shutdown" ); + Appliance appliance = (Appliance) iterator.next(); + Container container = (Container) m_containerMap.get( appliance ); + try + { + container.suspend(); + } + catch( Throwable e ) + { + final String error = + "Could not suspend a subsidiary container: " + + appliance.getName() + + " in container: " + this; + throw new ContainerRuntimeException( error, e ); + } + } + } + + /** + * Startup the components in this container. + * @exception Exception if a startup error occurs + */ + private void resumeComponents() + { + // not implemented - more thinking needed about the + // concepts of deployment strategies + } + + /** + * Startup the containers in this container. + * @exception Exception if a startup error occurs + */ + private void resumeContainers() + { + Iterator iterator = m_containers.iterator(); + while( iterator.hasNext() ) + { + Appliance appliance = (Appliance) iterator.next(); + Container container = (Container) m_containerMap.get( appliance ); + try + { + container.resume(); + } + catch( Throwable e ) + { + final String error = + "Could not resume of a subsidiary container: " + + appliance.getName() + + " in container: " + this; + throw new ContainerRuntimeException( error, e ); + } } - shutdownContainers(); - shutdownComponents(); } /** @@ -454,33 +693,6 @@ } /** - * Disposal of the container. - */ - public void dispose() - { - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "disposal" ); - } - - disposeContainers(); - disposeComponents(); - - m_engine = null; - m_descriptor = null; - m_componentMap.clear(); - m_components.clear(); - m_componentMap = null; - m_components = null; - m_containerMap.clear(); - m_containers.clear(); - m_containerMap = null; - m_containers = null; - m_partition = null; - m_path = null; - } - - /** * Release all of the components in this container. */ private void disposeComponents() @@ -527,9 +739,64 @@ { final String error = "Could not shutdown a subsidiary container: " - + appliance.getName() - + " in container: " + this; + + appliance.getName(); getLogger().warn( error, e ); + } + } + } + + /** + * Adds a <code>StateListener</code>. + * @param listener the state listener to add + */ + public void addStateListener( StateListener listener ) + { + synchronized( m_listeners ) + { + m_listeners.add( listener ); + } + } + + /** + * Removes a <code>StateListener</code>. + * @param listener the state listener to remove + */ + public void removeStateListener( StateListener listener ) + { + synchronized( m_listeners ) + { + m_listeners.remove( listener ); + } + } + + /** + * Notifies all state listeners of a change in the state of the container. + * @param event the state event. + */ + protected void fireStateChange( StateEvent event ) + { + synchronized( m_listeners ) + { + StateListener[] listeners = + (StateListener[])m_listeners.toArray( new StateListener[ 0 ] ); + for( int i = 0; i < listeners.length; i++ ) + { + StateListener listener = listeners[ i ]; + try + { + listener.stateChanged( event ); + } + catch( Exception e ) + { + m_listeners.remove( listener ); + final String warning = + "State listener raised on error on notification. Removing listener: " + + listener; + if( getLogger().isWarnEnabled() ) + { + getLogger().warn( warning ); + } + } } } } 1.1 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/StateEvent.java Index: StateEvent.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software * itself, if and wherever such third-party acknowledgments * normally appear. * * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation" * must not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.avalon.merlin.container; import java.util.EventObject; /** * The <code>StateEvent</code> is an event raised by a component * signally a change in state. * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2003/01/09 03:59:39 $ */ public class StateEvent extends EventObject { //============================================================ // static //============================================================ /** * Static state enumeration value indicating that the state of a container is unknown. */ public static final int UNKNOWN = 0; /** * Static state enumeration value indicating that a container has been initialized, * all of its subsidiary containers have been initialized, and all component profiles * have been assembled. */ public static final int INITIALIZED = 1; /** * Static state enumeration value indicating that a container has completed * lifecycle processing on all components requesting startup establishment. */ public static final int STARTED = 2; /** * Static state enumeration value indicating that a container has been suspended. */ public static final int SUSPENDED = 3; /** * Static state enumeration value indicating that a container has completed * the shutdown of all subsidiary containers and the internal components * have been shutdown. */ public static final int STOPPED = 4; /** * Static state enumeration value indicating that a container and all * subsidiary containers have been disposed of. */ public static final int DISPOSED = 5; //============================================================ // state //============================================================ /** * Container state. */ private final int m_state; /** * Error condition */ private Throwable m_error; /** * The name of the container. */ private String m_name; //============================================================ // constructor //============================================================ /** * Creation of a new StateEvent. * * @param source the source container * @param name the name of the soource container * @param state int value of (@link #INITIALIZED}, [EMAIL PROTECTED] #STARTED}, * [EMAIL PROTECTED] #SUSPENDED}, [EMAIL PROTECTED] #STOPPED} or [EMAIL PROTECTED] #DISPOSED} */ public StateEvent( Object source, String name, int state ) { this( source, name, state, null ); } /** * Creation of a new StateEvent. * * @param source the source container * @param name the name of the soource container * @param state int value of (@link #INITIALIZED}, [EMAIL PROTECTED] #STARTED}, * [EMAIL PROTECTED] #STOPPED} or [EMAIL PROTECTED] #DISPOSED} * @param error an error condition triggering the state change */ public StateEvent( Object source, String name, int state, Throwable error ) { super( source ); m_state = state; m_name = name; m_error = error; } //============================================================ // StateEvent //============================================================ /** * Returns the name of the container raising the event. * @return the container name */ public String getName() { return m_name; } /** * Returns the state that the component has raised inidicating * that the component has completed transitioning to that state. * @return the state */ public int getState() { return m_state; } /** * Returns a throwable causing the state change. This is normally a * null value. If not null, the transition was a result of an error * condition. * @return the error condition */ public Throwable getError() { return m_error; } } 1.1 avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/StateListener.java Index: StateListener.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software * itself, if and wherever such third-party acknowledgments * normally appear. * * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation" * must not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.avalon.merlin.container; /** * A <code>StateListener</code> listens to <code>StateEvent</code> events. * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2003/01/09 03:59:39 $ */ public interface StateListener { /** * Method invoked when a container state changes. * @param event the state event */ void stateChanged( StateEvent event ); } 1.6 +1 -1 avalon-sandbox/merlin/src/test/org/apache/avalon/playground/StandardComponent.xinfo Index: StandardComponent.xinfo =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin/src/test/org/apache/avalon/playground/StandardComponent.xinfo,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- StandardComponent.xinfo 20 Dec 2002 11:58:01 -0000 1.5 +++ StandardComponent.xinfo 9 Jan 2003 03:59:39 -0000 1.6 @@ -29,7 +29,7 @@ <context type="org.apache.avalon.playground.StandardContext"> <attributes> - <attribute key="urn:assembly:lifecycle.context.extension" + <attribute key="urn:assembly:lifecycle.context.strategy" value="org.apache.avalon.playground.Contextualizable"/> </attributes> </context>
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>