mcconnell 2002/08/31 07:48:08
Added: assembly/src/java/org/apache/excalibur/merlin/container
ContainerResource.java
Removed: assembly/src/java/org/apache/excalibur/merlin/container
ContainerService.java
Log:
ContainerService removed in favour of a cleaner object model using a
ContainerResource.
Revision Changes Path
1.1
jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/ContainerResource.java
Index: ContainerResource.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.excalibur.merlin.container;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.context.Context;
import org.apache.excalibur.merlin.assembly.ContainerManager;
import org.apache.excalibur.merlin.model.Profile;
import org.apache.excalibur.merlin.model.Resource;
import org.apache.excalibur.merlin.resource.DefaultResource;
import org.apache.excalibur.merlin.resource.LifestyleHandler;
import org.apache.excalibur.meta.info.ServiceDescriptor;
/**
* A container resource is a resource that manages the execution of a container
* under a seperate thread of control.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
* @version $Revision: 1.1 $ $Date: 2002/08/31 14:48:08 $
*/
public class ContainerResource extends DefaultResource implements Runnable,
Container, Startable, StateListener
{
//==========================================================================
// state
//==========================================================================
/**
* The container type manager to be assigned as the context classloader.
*/
private ContainerManager m_manager;
/**
* The container instance that will by established by the resource.
*/
private Container m_container;
/**
* The thread in which we will run the container.
*/
private Thread m_thread;
/**
* An error causing establishment failure.
*/
private Exception m_error;
/**
* 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 little
* sleep.
*/
private Integer m_action = new Integer( StateEvent.UNKNOWN );
/**
* 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 set of state listeners listening to this container.
*/
private ArrayList m_stateListeners = new ArrayList();
/**
* The set of state listeners listening to this container.
*/
private List m_installable = new LinkedList();
//==========================================================================
// constructor
//==========================================================================
/**
* Create a new container resource instance.
*
* @param the container type manager
* @param profile the resource's profile
* @param context the deployment context
* @param handler the lifestyle handler
*/
public ContainerResource( final ContainerManager manager,
final Profile profile,
final Context context,
final LifestyleHandler handler )
{
super( manager, profile, context, handler );
m_manager = manager;
}
//=======================================================================
// Resource
//=======================================================================
/**
* Return the container resource instance.
*
* @return an instance of the type defined by the profile
* @exception Exception if an access error occurs
*/
public Object access() throws Exception
{
if( m_thread == null )
{
m_thread = new Thread( this, m_manager.getPath() );
m_thread.start();
}
while(( m_state < StateEvent.INITIALIZED ) && ( m_error == null ))
{
sleep();
}
if( m_error != null )
{
throw m_error;
}
return this;
}
/**
* Release the service instance.
* @param instance the instance to release
*/
public void release( Object instance )
{
if( m_state < StateEvent.DISPOSED )
{
m_container.dispose();
while(( m_state < StateEvent.DISPOSED ) && ( m_error == null ))
{
sleep();
}
}
}
//==========================================================================
// Runnable
//==========================================================================
/**
* Starts the thread of execution for the container. This operation is
* invoclved by the container access method and should not be invoked directly
* by a client.
*
* @see #access
* @exception IllegalStateException if this operation has not invoked via access
*/
public void run() throws IllegalStateException
{
if( m_thread == null )
{
final String error = "Use the access method to initiate the thread.";
throw new IllegalStateException( error );
}
try
{
//
// get the initialized container instance and add ourselves
// as a state listener
//
m_container = (Container) super.access();
m_container.addStateListener( this );
m_state = StateEvent.INITIALIZED;
//
// notify any listeners that we are up and running and waiting for
// stage change requests
//
fireStateChange( new StateEvent( this, m_manager.getPath(),
StateEvent.INITIALIZED ) );
//
// 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 )
{
//
// check for any installable profiles
//
synchronized( m_installable )
{
if( m_installable.size() > 0 )
{
if(( m_state == StateEvent.INITIALIZED ) || ( m_state ==
StateEvent.SUSPENDED ))
{
m_container.install( (Profile[]) m_installable.toArray(
new Profile[0] ) );
m_installable.clear();
}
}
}
//
// check for any state change requests
//
synchronized( m_action )
{
if( m_state != m_action.intValue() )
{
switch( m_action.intValue() )
{
case StateEvent.STARTED:
if( m_state == StateEvent.INITIALIZED )
{
m_container.start();
}
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.stop();
}
break;
}
}
}
sleep();
}
}
catch( Throwable e )
{
final String error = "Unexpected error during container execution.";
m_error = new ContainerException( error, e );
}
}
//==========================================================================
// StateListener
//==========================================================================
/**
* Method invoked when the hosted container state changes.
*/
public void stateChanged( StateEvent event )
{
m_state = event.getState();
fireStateChange( new StateEvent( this, event.getName(), m_state ) );
}
//==========================================================================
// Container
//==========================================================================
/**
* Add and assemble the supplied set of profiles.
* @param profiles the profiles to assemble
* @exception Exception is an install error occurs
*/
public void install( Profile[] profiles )
throws Exception
{
synchronized( m_installable )
{
for( int i=0; i<profiles.length; i++ )
{
m_installable.add( profiles[i] );
}
}
}
/**
* Adds a <code>StateListener</code>.
* @param listener the state listener to add
*/
public void addStateListener( StateListener listener )
{
synchronized( m_stateListeners )
{
m_stateListeners.add( listener );
}
}
/**
* Removes a <code>StateListener</code>.
* @param listener the state listener to remove
*/
public void removeStateListener( StateListener listener )
{
synchronized( m_stateListeners )
{
m_stateListeners.remove( listener );
}
}
/**
* Request the startup of the container.
* @exception Exception if an error occurs during the startup phase
*/
public void start() throws Exception
{
synchronized( this )
{
m_action = new Integer( StateEvent.STARTED );
while(( m_state < StateEvent.STARTED ) && ( m_error == null ))
{
sleep();
}
if( m_error != null )
{
throw m_error;
}
}
}
/**
* Suspends the container.
*/
public void suspend()
{
synchronized( this )
{
m_action = new Integer( StateEvent.SUSPENDED );
while(( m_state < StateEvent.SUSPENDED ) && ( m_error == null ))
{
sleep();
}
}
}
/**
* Resumes the container from a suspended state.
*/
public void resume()
{
if( m_state != StateEvent.SUSPENDED )
{
throw new IllegalStateException(
"Container is not suspended.");
}
synchronized( this )
{
m_action = new Integer( StateEvent.STARTED );
while(( m_state == StateEvent.SUSPENDED ) && ( m_error == null ))
{
sleep();
}
}
}
/**
* Request the shutdown of the container.
* @exception Exception if an error occurs during the shutdown phase
*/
public void stop() throws Exception
{
synchronized( this )
{
m_action = new Integer( StateEvent.STOPPED );
while(( m_state < StateEvent.STOPPED ) && ( m_error == null ))
{
sleep();
}
if( m_error != null )
{
throw m_error;
}
}
}
//==========================================================================
// implementation
//==========================================================================
/**
* 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_stateListeners )
{
StateListener[] listeners =
(StateListener[]) m_stateListeners.toArray( new StateListener[0] );
for( int i=0; i<listeners.length; i++ )
{
StateListener listener = listeners[i];
try
{
listener.stateChanged( event );
}
catch( Exception e )
{
m_stateListeners.remove( listener );
final String warning =
"State listener raised on error on notification. Removing
listener: "
+ listener;
if( getLogger().isWarnEnabled() )
{
getLogger().warn( warning );
}
}
}
}
}
/**
* Returns the container instance held by the resource. This operation
* will block until the container instance is fully initialized. A
* client is resposible for subsequent startup of the container.
*
* @return the container
* @exception if an error occurs during container establishment
*/
private Container getContainerInstance() throws Exception
{
while(( m_container == null ) && ( m_error == null ))
{
sleep();
if( m_error != null )
{
throw m_error;
}
}
return m_container;
}
/**
* Internal utility to sleep a bit.
*/
private void sleep()
{
try
{
Thread.currentThread().sleep( 100 );
}
catch( Throwable wakeup )
{
}
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>