sgoeschl    2005/02/16 03:13:49

  Added:       yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration
                        ReconfigurationService.java
                        ReconfigurationServiceImpl.java
  Log:
  Initial import
  
  Revision  Changes    Path
  1.1                  
jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration/ReconfigurationService.java
  
  Index: ReconfigurationService.java
  ===================================================================
  package org.apache.fulcrum.yaafi.service.reconfiguration;
  
  /*
   * Copyright 2004 Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   *
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  /**
   * Monitors the componentConfiguration.xml and triggers a reconfiguration
   * if the content of the component configuration file  has changed.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Siegfried Goeschl</a>
   */
  
  public interface ReconfigurationService
  {
      // This interface doesn't exposes any other methods
  }
  
  
  1.1                  
jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration/ReconfigurationServiceImpl.java
  
  Index: ReconfigurationServiceImpl.java
  ===================================================================
  package org.apache.fulcrum.yaafi.service.reconfiguration;
  
  /*
   * Copyright 2004 Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   *
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.security.MessageDigest;
  
  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.activity.Suspendable;
  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.configuration.DefaultConfigurationBuilder;
  import org.apache.avalon.framework.configuration.Reconfigurable;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.Serviceable;
  import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator;
  
  
  /**
   * Monitors the componentConfiguration.xml and triggers a reconfiguration
   * if the content of the component configuration file  has changed.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Siegfried Goeschl</a>
   */
  
  public class ReconfigurationServiceImpl
      extends AbstractLogEnabled
      implements ReconfigurationService, Serviceable, Contextualizable, 
Configurable, Initializable, Runnable, Startable, Disposable
  {    
      /** the interval between two checks in ms */
      private int interval;
      
      /** the location of the componentConfiguration file */
      private String location;
          
      /** helper for locating the component configuration */
      private InputStreamLocator locator;
      
      /** shall the worker thread terminate immediately */
      private boolean terminateNow;
      
      /** the worker thread polling the componentConfiguraton */
      private Thread workerThread;
      
      /** the ServiceManager to use */
      private ServiceManager serviceManager;
      
      /////////////////////////////////////////////////////////////////////////
      // Avalon Service Lifecycle Implementation
      /////////////////////////////////////////////////////////////////////////
  
      /**
       * Constructor
       */
      public ReconfigurationServiceImpl()
      {
          // nothing to do
      }
  
      /**
       * @see 
org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
       */
      public void service(ServiceManager manager) throws ServiceException
      {
          this.serviceManager = manager;
      }
      
      /**
       * @see 
org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
       */
      public void contextualize(Context context) throws ContextException
      {
          this.locator  = new InputStreamLocator( (File) 
context.get("urn:avalon:home") );
      }
      
      /**
       * @see 
org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
       */
      public void configure(Configuration configuration) throws 
ConfigurationException
      {
          this.interval = Math.max( 
configuration.getAttributeAsInteger("interval",5000), 1000 );
          this.location = configuration.getChild("location").getValue();
      }
      
      /**
       * @see org.apache.avalon.framework.activity.Initializable#initialize()
       */
      public void initialize() throws Exception
      {
          // ensure that we actually find our target
          
          if( this.locate() == null )
          {
              String msg = "The component configuration was not found : " + 
this.location;
              this.getLogger().error(msg);
              throw new IllegalArgumentException(msg);
          }
          else
          {
              String msg = "Checking " + this.location + " every " + 
this.interval + " ms";
              this.getLogger().debug( msg );            
          }
          
          // request a SHA-1 to make sure that it is supported
          
          MessageDigest.getInstance( "SHA1" );
                  
          // check that the ServiceManager inplements Reconfigurable
          
          if( (this.serviceManager instanceof Reconfigurable) == false )
          {
              String msg = "The ServiceManager instance does not implement 
Reconfigurable?!";
              throw new IllegalArgumentException( msg );
          }
          
          // create the worker thread polling the target
          
          this.workerThread = new Thread( this, "ReconfigurationService" );
      }
  
      /**
       * @see org.apache.avalon.framework.activity.Startable#start()
       */
      public void start() throws Exception
      {
          this.workerThread.start();
      }
      
      /**
       * @see org.apache.avalon.framework.activity.Startable#stop()
       */
      public void stop() throws Exception
      {
          this.terminateNow = true;
          this.workerThread.interrupt();
          this.workerThread.join( 10000 );
      }
      
      /**
       * @see org.apache.avalon.framework.activity.Disposable#dispose()
       */
      public void dispose()
      {
          this.locator = null;
        this.workerThread = null;
        this.serviceManager = null;
      }
      
      /////////////////////////////////////////////////////////////////////////
      // Service interface implementation
      /////////////////////////////////////////////////////////////////////////
  
      /**
       * @see java.lang.Runnable#run()
       */
      public void run()
      {
          byte[] lastDigest = null;
          byte[] currDigest = null;
          InputStream is = null;
          boolean isFirstInvocation = true;
          
          while( this.terminateNow == false )
          {
              try
              {
                  // get a grip on our file 
                  
                  is = this.locate();
  
                  if( is == null )
                  {
                      String msg = "Unable to find the component configuration";
                      this.getLogger().warn(msg);
                      continue;
                  }
                  
                  // calculate a SHA-1 digest
                  
                  currDigest = this.getDigest(is);
                  is.close();
                  is = null;
               
                  if( isFirstInvocation == true )
                  { 
                      isFirstInvocation = false;
                      this.getLogger().debug( "Storing SHA-1 digest of 
componentConfiguration" );
                      lastDigest = currDigest;
                  }
                  else
                  {
                      this.getLogger().debug( "Checking the 
componentConfiguration to detect changes ..." );    
                        if( equals( lastDigest, currDigest ) == false )
                        {
                            this.getLogger().debug( "The componentConfiguration 
has changed" );
                            lastDigest = currDigest;
                            this.reconfigure();
                        }
                        Thread.sleep( this.interval );
                  }
              }
              catch( InterruptedException e )
              {
                  continue;
              }
              catch(Exception e)
              {
                  String msg = "The ReconfigurationService had a problem";
                  this.getLogger().error(msg,e);
                  continue;
              }
              finally
              {
                  if( is != null )
                  {
                      try
                      {
                          is.close();
                      }
                      catch (Exception e)
                      {
                          String msg = "Can't close the InputStream during 
error recovery";
                          this.getLogger().error(msg,e);
                      }
                  }
              }
          }
          
          return;
      }    
      
      /////////////////////////////////////////////////////////////////////////
      // Service implementation
      /////////////////////////////////////////////////////////////////////////
  
      private void reconfigure() throws Exception
      {
          InputStream is = this.locate();
          DefaultConfigurationBuilder builder = new 
DefaultConfigurationBuilder();
          Configuration configuration = builder.build(is);
          is.close();
          is = null;
        
          this.getLogger().warn( "Starting to reconfigure the container" );
          
          if( this.serviceManager instanceof Suspendable)
          {
              this.getLogger().info( "Calling suspend() of the container" );
              ((Suspendable) this.serviceManager).suspend();
          }
  
          if( this.serviceManager instanceof Reconfigurable)
          {
              this.getLogger().info( "Calling reconfigure() of the container" );
              ((Reconfigurable) this.serviceManager).reconfigure(configuration);
          }
  
          if( this.serviceManager instanceof Suspendable)
          {
              this.getLogger().info( "Calling resume() of the container" );
              ((Suspendable) this.serviceManager).resume();
          }
          
          this.getLogger().info( "Reconfiguring the container was successful" );
      }
      
      /**
       * Creates an InputStream  
       */
      private InputStream locate() throws IOException
      {
          return this.locator.locate(this.location);
      }
      
      /**
       * Pumps the input stream to the output stream.
       *
       * @param is the source input stream
       * @param os the target output stream
       * @throws IOException the copying failed
       */
      private static void copy( InputStream is, OutputStream os )
          throws IOException
      {
          byte[] buf = new byte[1024];
          int n = 0;
          int total = 0;
  
          while ((n = is.read(buf)) > 0)
          {
              os.write(buf, 0, n);
              total += n;
          }
  
          is.close();
          
          os.flush();
          os.close();
      }    
      
      /** 
       * Creates a message digest 
       */
      private byte[] getDigest( InputStream is )
        throws Exception
      {
          byte[] result = null;
          byte[] content = null;
  
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          copy( is, baos );
          content = baos.toByteArray();
          baos.close();        
          
          MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
          sha1.update( content );
          result = sha1.digest();
  
          return result;
      }
   
      /**
       * Compares two byte[] for equality
       */
      private static boolean equals(byte[] lhs, byte[] rhs)
      {
          if( lhs == rhs )
          {
              return true;
          }
          else if( lhs.length != rhs.length )
          {
              return false;
          }
          else
          {
              for( int i=0; i<lhs.length; i++ )
              {
                  if( lhs[i] != rhs[i] )
                  {
                      return false;
                  }
              }
          }
          
          return true;
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to