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]>

Reply via email to