You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2002/02/04 04:20:55 UTC

cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster AbstractDataSourceCluster.java DefaultHashedDataSourceCluster.java DefaultIndexedDataSourceCluster.java DefaultRoundRobinDataSourceCluster.java HashedDataSourceCluster.java IndexedDataSourceCluster.java RoundRobinDataSourceCluster.java

leif        02/02/03 19:20:55

  Added:       src/scratchpad/org/apache/avalon/excalibur/datasource/cluster
                        AbstractDataSourceCluster.java
                        DefaultHashedDataSourceCluster.java
                        DefaultIndexedDataSourceCluster.java
                        DefaultRoundRobinDataSourceCluster.java
                        HashedDataSourceCluster.java
                        IndexedDataSourceCluster.java
                        RoundRobinDataSourceCluster.java
  Log:
  New DataSource Cluster package.
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/AbstractDataSourceCluster.java
  
  Index: AbstractDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.excalibur.datasource.NoValidConnectionException;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.component.Composable;
  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.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public abstract class AbstractDataSourceCluster
      extends    AbstractLogEnabled
      implements Composable, Configurable, Initializable, Disposable, ThreadSafe
      {
      
      /** ComponentManager which created this component */
      protected ComponentManager    m_manager;
  
      protected int                 m_size;
      private String[]              m_dataSourceNames;
      private ComponentSelector     m_dbSelector;
      private DataSourceComponent[] m_dataSources;
      
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      public AbstractDataSourceCluster()
      {
      }
      
      /*---------------------------------------------------------------
       * AbstractDataSourceCluster Methods
       *-------------------------------------------------------------*/
      /**
       * Returns the number of DataSources in the cluster.
       *
       * @returns size of the cluster.
       */
      public int getClusterSize()
      {
          return m_size;
      }
      
      /**
       * Gets a Connection to a database given an index.
       *
       * @param index Index of the DataSource for which a connection is to be returned.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      public Connection getConnectionForIndex(int index) throws SQLException
      {
          if ( ( index < 0 ) || ( index >= m_size ) )
          {
              throw new NoValidConnectionException(
                  "index must be in the range 0 to " + ( m_size - 1 ) );
          }
          return m_dataSources[index].getConnection();
      }
      
      /*---------------------------------------------------------------
       * Composable Methods
       *-------------------------------------------------------------*/
      /**
       * Called by the Container to tell the component which ComponentManager
       *  is controlling it.
       *
       * @param ComponentManager which curently owns the component.
       */
      public void compose(ComponentManager manager)
      {
          m_manager  = manager;
      }
      
      /*---------------------------------------------------------------
       * Configurable Methods
       *-------------------------------------------------------------*/
      /**
       * Called by the Container to configure the component.
       *
       * @param configuration configuration info used to setup the component.
       *
       * @throws ConfigurationException if there are any problems with the configuration.
       */
      public void configure(Configuration configuration) throws ConfigurationException
      {
          // Get the size
          m_size = configuration.getAttributeAsInteger( "size" );
          if (m_size < 1)
          {
              throw new ConfigurationException( "Invalid value for size attribute." );
          }
          
          // Read in the data source names.
          m_dataSourceNames = new String[m_size];
          Configuration[] dataSourceConfigs = configuration.getChildren( "dbpool" );
          for ( int i = 0; i < dataSourceConfigs.length; i++ )
          {
              int index = dataSourceConfigs[i].getAttributeAsInteger( "index" );
              if ( ( index < 0 ) || ( index >= m_size ) )
              {
                  throw new ConfigurationException( "The dbpool with index=\"" + index + 
                      "\" is invalid.  Index must be in the range 0 to " + ( m_size - 1 ) );
              }
              if ( m_dataSourceNames[index] != null )
              {
                  throw new ConfigurationException( "Only one dbpool with index=\"" + index + 
                      "\" can be defined." );
              }
              m_dataSourceNames[index] = dataSourceConfigs[i].getValue();
          }
          
          // Make sure that all of the dbpools were defined
          for ( int i = 0; i < m_dataSourceNames.length; i++ )
          {
              if ( m_dataSourceNames[i] == null )
              {
                  throw new ConfigurationException( "Expected a dbpool with index=\"" + i + "\"" );
              }
          }
      }
  
      /*---------------------------------------------------------------
       * Initializable Methods
       *-------------------------------------------------------------*/
      /**
       * Called by the Container to initialize the component.
       *
       * @throws Exception if there were any problems durring initialization.
       */
      public void initialize() throws Exception
      {
          // Get references to a data sources
          m_dbSelector =
              (ComponentSelector)m_manager.lookup( DataSourceComponent.ROLE + "ClusterSelector" );
          m_dataSources = new DataSourceComponent[m_size];
          for ( int i = 0; i < m_dataSourceNames.length; i++ )
          {
              m_dataSources[i] = (DataSourceComponent)m_dbSelector.select( m_dataSourceNames[i] );
          }
      }
  
      /*---------------------------------------------------------------
       * Disposable Methods
       *-------------------------------------------------------------*/
      /**
       * Called by the Container to dispose the component.
       */
      public void dispose()
      {
          // Free up the data source
          if ( m_dbSelector != null )
          {
              if ( m_dataSources != null )
              {
                  for ( int i = 0; i < m_dataSources.length; i++ )
                  {
                      if ( m_dataSources[i] != null )
                      {
                          m_dbSelector.release( m_dataSources[i] );
                      }
                  }
  
                  m_dataSources = null;
              }
  
              m_manager.release( m_dbSelector );
  
              m_dbSelector = null;
          }
      }	
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/DefaultHashedDataSourceCluster.java
  
  Index: DefaultHashedDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.NoValidConnectionException;
  
  /**
   * The DefaultHashedDataSourceCluster requires that the user specify an object or a hashCode
   *  which will be used consistantly select a member DataSource form a cluster for each connection
   *  request.  Calls to getConnection() will throw an exception.  Components which make use of
   *  this class must call either the getConnectionForHashObject( Object hashObject) or the
   *  getConnectionForHashCode( int hashCode ) methods instead.
   * <p>
   * This form of Clustering is useful in cases where data can be reliably accessed in a repeatable
   *  manner.  For example a web site's visitor information could be accessed by using a String
   *  containing the visitor's username as a hashObject.  This would allow visitor information to be
   *  spread across several database servers.
   * <p>
   * The Configuration for a 2 database cluster is like this:
   *
   * <pre>
   *   &lt;datasources&gt;
   *     &lt;hashed-cluster name="mydb-cluster" size="2"&gt;
   *       &lt;dbpool index="0"&gt;mydb-0&lt;/dbpool&gt;
   *       &lt;dbpool index="1"&gt;mydb-1&lt;/dbpool&gt;
   *     &lt;/hashed-cluster&gt;
   *   &lt;/datasources&gt;
   *   &lt;cluster-datasources&gt;
   *     &lt;jdbc name="mydb-0"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host0/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *     &lt;jdbc name="mydb-1"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host1/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *   &lt;/cluster-datasources&gt;
   * </pre>
   *
   * With the following roles declaration:
   *
   * <pre>
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
   *     shorthand="datasources"
   *     default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *     &lt;hint shorthand="hashed-cluster"
   *       class="org.apache.avalon.excalibur.datasource.cluster.DefaultHashedDataSourceCluster"/&gt;
   *   &lt;/role&gt;
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentClusterSelector"
   *       shorthand="cluster-datasources"
   *       default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *   &lt;/role&gt;
   * </pre>
   *
   * A hashed-cluster definition enforces that the configuration specify a size.  This size must
   *  equal the number of datasources referenced as being members of the cluster.  Any datasource can
   *  be a member of the cluster.
   * <p>
   * The hashed-cluster can be obtained in the same manner as a non-clustered datasource.  The only
   *  difference is in how it is used.  The HashedDataSourceCluster requires that the caller provide
   *  an object or a hashCode to use when requesting a connection.
   * <p>
   * The following code demonstrates a change that can be made to database enabled components so that
   *  they will be able to work with both HashedDataSourceCluster DataSources and regular
   *  DataSources.
   * <p>
   * old:
   * <pre>
   *   Connection connection = m_dataSource.getConnection();
   * </pre>
   *
   * new:
   * <pre>
   *   Connection connection;
   *   if ( m_dataSource instanceof HashedDataSourceCluster )
   *   {
   *     connection = ((HashedDataSourceCluster)m_dataSource).getConnectionForHashObject( hashObject );
   *   }
   *   else
   *   {
   *     connection = m_dataSource.getConnection();
   *   }
   * </pre>
   *
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public class DefaultHashedDataSourceCluster
      extends AbstractDataSourceCluster
      implements HashedDataSourceCluster
  {
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      public DefaultHashedDataSourceCluster()
      {
      }
      
      /*---------------------------------------------------------------
       * DataSourceComponent Methods
       *-------------------------------------------------------------*/
      /**
       * Not supported in this component.  Will throw a NoValidConnectionException.
       */
      public Connection getConnection() throws SQLException
      {
          throw new NoValidConnectionException(
              "getConnection() should not be called for a " + getClass().getName() + ".  " +
              "Please verify your configuration." );
      }
      
      /*---------------------------------------------------------------
       * HashedDataSourceCluster Methods
       *-------------------------------------------------------------*/
      // public int getClusterSize()
      //   declared in AbstractDataSourceCluster
      
      /**
       * Gets a Connection to a database given a hash object.
       *
       * @param hashObject Object whose hashCode will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      public Connection getConnectionForHashObject( Object hashObject ) throws SQLException
      {
          return getConnectionForIndex( getIndexForHashObject( hashObject ) );
      }
      
      /**
       * Gets a Connection to a database given a hash code.
       *
       * @param hashCode HashCode which will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      public Connection getConnectionForHashCode( int hashCode ) throws SQLException
      {
          return getConnectionForIndex( getIndexForHashCode( hashCode ) );
      }
      
      // public Connection getConnectionForIndex( int index ) throws SQLException
      //   declared in AbstractDataSourceCluster
      
      /**
       * Gets the index which will be resolved for a given hashCode.  This can be used
       *  by user code to optimize the use of DataSource Clusters.
       * <p>
       * Subclasses can override this method to get different behavior.
       * <p>
       * By default the index = getIndexForHashCode( hashObject.hashCode() )
       *
       * @param hashObject Object whose hashCode will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       */
      public int getIndexForHashObject( Object hashObject ) {
          return getIndexForHashCode( hashObject.hashCode() );
      }
      
      /**
       * Gets the index which will be resolved for a given hashCode.  This can be used
       *  by user code to optimize the use of DataSource Clusters.
       * <p>
       * Subclasses can override this method to get different behavior.
       * <p>
       * By default the index = hashCode % getClusterSize()
       *
       * @param hashCode HashCode which will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       */
      public int getIndexForHashCode( int hashCode ) {
          return hashCode % getClusterSize();
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/DefaultIndexedDataSourceCluster.java
  
  Index: DefaultIndexedDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.excalibur.datasource.NoValidConnectionException;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.component.Composable;
  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.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * The DefaultIndexedDataSourceCluster requires that the user implement their own method of
   *  selecting which DataSource in the cluster to use for each connection request.  Calls to
   *  getConnection() will throw an exception.  Components which make use of this class must call
   *  the getConnectionForIndex(int index) method instead.
   * <p>
   * The Configuration for a 2 database cluster is like this:
   *
   * <pre>
   *   &lt;datasources&gt;
   *     &lt;indexed-cluster name="mydb-cluster" size="2"&gt;
   *       &lt;dbpool index="0"&gt;mydb-0&lt;/dbpool&gt;
   *       &lt;dbpool index="1"&gt;mydb-1&lt;/dbpool&gt;
   *     &lt;/indexed-cluster&gt;
   *   &lt;/datasources&gt;
   *   &lt;cluster-datasources&gt;
   *     &lt;jdbc name="mydb-0"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host0/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *     &lt;jdbc name="mydb-1"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host1/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *   &lt;/cluster-datasources&gt;
   * </pre>
   *
   * With the following roles declaration:
   *
   * <pre>
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
   *     shorthand="datasources"
   *     default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *     &lt;hint shorthand="indexed-cluster"
   *       class="org.apache.avalon.excalibur.datasource.cluster.DefaultIndexedDataSourceCluster"/&gt;
   *   &lt;/role&gt;
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentClusterSelector"
   *       shorthand="cluster-datasources"
   *       default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *   &lt;/role&gt;
   * </pre>
   *
   * An indexed-cluster definition enforces that the configuration specify a size.  This size must
   *  equal the number of datasources referenced as being members of the cluster.  Any datasource can
   *  be a member of the cluster.
   * <p>
   * The indexed-cluster can be obtained in the same manner as a non-clustered datasource.  The only
   *  difference is in how it is used.  The IndexedDataSourceCluster requires that the caller specify
   *  the index of the cluster member to use when requesting a connection.
   * <p>
   * The following code demonstrates a change that can be made to database enabled components so that
   *  they will be able to work with both IndexedDataSourceCluster DataSources and regular
   *  DataSources.
   * <p>
   * old:
   * <pre>
   *   Connection connection = m_dataSource.getConnection();
   * </pre>
   *
   * new:
   * <pre>
   *   Connection connection;
   *   if ( m_dataSource instanceof IndexedDataSourceCluster )
   *   {
   *     connection = ((IndexedDataSourceCluster)m_dataSource).getConnectionForIndex( index );
   *   }
   *   else
   *   {
   *     connection = m_dataSource.getConnection();
   *   }
   * </pre>
   *
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public class DefaultIndexedDataSourceCluster
      extends  AbstractDataSourceCluster
      implements IndexedDataSourceCluster
      {
      
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      public DefaultIndexedDataSourceCluster()
      {
      }
      
      /*---------------------------------------------------------------
       * DataSourceComponent Methods
       *-------------------------------------------------------------*/
      /**
       * Not supported in this component.  Will throw a NoValidConnectionException.
       */
      public Connection getConnection() throws SQLException
      {
          throw new NoValidConnectionException(
              "getConnection() should not be called for a " + getClass().getName() + ".  " +
              "Please verify your configuration." );
      }
      
      /*---------------------------------------------------------------
       * IndexedDataSourceCluster Methods
       *-------------------------------------------------------------*/
      // public int getClusterSize()
      //   declared in AbstractDataSourceCluster
      
      // public Connection getConnectionForIndex( int index ) throws SQLException
      //   declared in AbstractDataSourceCluster
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/DefaultRoundRobinDataSourceCluster.java
  
  Index: DefaultRoundRobinDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.excalibur.datasource.NoValidConnectionException;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.component.Composable;
  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.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * The DefaultRoundRobinDataSourceCluster allows the user to specify a cluster of DataSources
   *  which all act as one.  The Cluster works by cycling through its member DataSources returning
   *  a connection from a different one with each call to getConnection().
   * <p>
   * This form of Clustering has the benefit that it can be used by components without requiring
   *  any changes.  But care must be taken as to the kind of data written or read from the database.
   *  Wich this clustering method, there is no control over which DataSource will provide a
   *  connection for any given call.
   * <p>
   * Round Robin Clusters are useful in cases where lots of read-only data needs to be accessed and
   *  multiple copies of the data can be stored on different database servers to balance load.
   * <p>
   * The Configuration for a 2 database cluster is like this:
   *
   * <pre>
   *   &lt;datasources&gt;
   *     &lt;roundrobin-cluster name="mydb-cluster" size="2"&gt;
   *       &lt;dbpool index="0"&gt;mydb-0&lt;/dbpool&gt;
   *       &lt;dbpool index="1"&gt;mydb-1&lt;/dbpool&gt;
   *     &lt;/roundrobin-cluster&gt;
   *   &lt;/datasources&gt;
   *   &lt;cluster-datasources&gt;
   *     &lt;jdbc name="mydb-0"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host0/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *     &lt;jdbc name="mydb-1"&gt;
   *       &lt;pool-controller min="1" max="10"/&gt;
   *       &lt;auto-commit&gt;true&lt;/auto-commit&gt;
   *       &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
   *       &lt;dburl&gt;jdbc:driver://host1/mydb&lt;/dburl&gt;
   *       &lt;user&gt;username&lt;/user&gt;
   *       &lt;password&gt;password&lt;/password&gt;
   *     &lt;/jdbc&gt;
   *   &lt;/cluster-datasources&gt;
   * </pre>
   *
   * With the following roles declaration:
   *
   * <pre>
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
   *       shorthand="datasources"
   *       default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *     &lt;hint shorthand="roundrobin-cluster"
   *         class="org.apache.avalon.excalibur.datasource.cluster.DefaultRoundRobinDataSourceCluster"/&gt;
   *   &lt;/role&gt;
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentClusterSelector"
   *       shorthand="cluster-datasources"
   *       default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
   *     &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
   *   &lt;/role&gt;
   * </pre>
   *
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public class DefaultRoundRobinDataSourceCluster
      extends  AbstractDataSourceCluster
      implements RoundRobinDataSourceCluster
      {
          private Object m_semaphore = new Object();
          private int m_nextIndex;
      
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      public DefaultRoundRobinDataSourceCluster()
      {
      }
      
      /*---------------------------------------------------------------
       * DataSourceComponent Methods
       *-------------------------------------------------------------*/
      /**
       * Returns a Connection to one of the Cluster's member DataSources.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      public Connection getConnection() throws SQLException
      {
          int index;
          synchronized(m_semaphore)
          {
              index = m_nextIndex;
              if ( ( ++m_nextIndex ) >= m_size )
              {
                  m_nextIndex = 0;
              }
          }
          
          return getConnectionForIndex( index );
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/HashedDataSourceCluster.java
  
  Index: HashedDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  
  /**
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public interface HashedDataSourceCluster
      extends DataSourceComponent
  {
      /**
       * The name of the role for convenience
       */
      String ROLE = "org.apache.avalon.excalibur.datasource.cluster.HashedDataSourceCluster";
      
      /**
       * Returns the number of DataSources in the cluster.
       *
       * @returns size of the cluster.
       */
      int getClusterSize();
      
      /**
       * Gets a Connection to a database given a hash object.
       *
       * @param hashObject Object whose hashCode will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      Connection getConnectionForHashObject( Object hashObject ) throws SQLException;
      
      /**
       * Gets a Connection to a database given a hash code.
       *
       * @param hashCode HashCode which will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      Connection getConnectionForHashCode( int hashCode ) throws SQLException;
      
      /**
       * Gets a Connection to a database given an index.
       *
       * @param index Index of the DataSource for which a connection is to be returned.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      Connection getConnectionForIndex( int index ) throws SQLException;
      
      /**
       * Gets the index which will be resolved for a given hashCode.  This can be used
       *  by user code to optimize the use of DataSource Clusters.
       *
       * @param hashObject Object whose hashCode will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       */
      int getIndexForHashObject( Object hashObject );
      
      /**
       * Gets the index which will be resolved for a given hashCode.  This can be used
       *  by user code to optimize the use of DataSource Clusters.
       *
       * @param hashCode HashCode which will be used to select which of the Clusted
       *        DataSources will be provide a Connection.
       */
      int getIndexForHashCode( int hashCode );
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/IndexedDataSourceCluster.java
  
  Index: IndexedDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  
  /**
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public interface IndexedDataSourceCluster
      extends DataSourceComponent
  {
      /**
       * The name of the role for convenience
       */
      String ROLE = "com.silveregg.util.datasource.cluster.IndexedDataSourceCluster";
  
      /**
       * Returns the number of DataSources in the cluster.
       *
       * @returns size of the cluster.
       */
      int getClusterSize();
      
      /**
       * Gets a Connection to a database given an index.
       *
       * @param index Index of the DataSource for which a connection is to be returned.
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader or when the index is not valid.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      Connection getConnectionForIndex( int index ) throws SQLException;
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/cluster/RoundRobinDataSourceCluster.java
  
  Index: RoundRobinDataSourceCluster.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.excalibur.datasource.cluster;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  
  /**
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/02/04 03:20:54 $
   * @since 4.1
   */
  public interface RoundRobinDataSourceCluster
      extends DataSourceComponent
  {
      /**
       * The name of the role for convenience
       */
      String ROLE = "org.apache.avalon.excalibur.datasource.cluster.RoundRobinDataSourceCluster";
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>