All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.avalon.excalibur.datasource.cluster.DefaultHashedDataSourceCluster Maven / Gradle / Ivy

/* 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

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.
 * 

* 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. *

* The Configuration for a 2 database cluster is like this: * *

 *   <datasources>
 *     <hashed-cluster name="mydb-cluster" size="2">
 *       <dbpool index="0">mydb-0</dbpool>
 *       <dbpool index="1">mydb-1</dbpool>
 *     </hashed-cluster>
 *   </datasources>
 *   <cluster-datasources>
 *     <jdbc name="mydb-0">
 *       <pool-controller min="1" max="10"/>
 *       <auto-commit>true</auto-commit>
 *       <driver>com.database.jdbc.JdbcDriver</driver>
 *       <dburl>jdbc:driver://host0/mydb</dburl>
 *       <user>username</user>
 *       <password>password</password>
 *     </jdbc>
 *     <jdbc name="mydb-1">
 *       <pool-controller min="1" max="10"/>
 *       <auto-commit>true</auto-commit>
 *       <driver>com.database.jdbc.JdbcDriver</driver>
 *       <dburl>jdbc:driver://host1/mydb</dburl>
 *       <user>username</user>
 *       <password>password</password>
 *     </jdbc>
 *   </cluster-datasources>
 * 
* * With the following roles declaration: * *
 *   <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
 *     shorthand="datasources"
 *     default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector">
 *     <hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/>
 *     <hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/>
 *     <hint shorthand="hashed-cluster"
 *       class="org.apache.avalon.excalibur.datasource.cluster.DefaultHashedDataSourceCluster"/>
 *   </role>
 *   <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentClusterSelector"
 *       shorthand="cluster-datasources"
 *       default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector">
 *     <hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/>
 *     <hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/>
 *   </role>
 * 
* * 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. *

* 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. *

* 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. *

* old: *

 *   Connection connection = m_dataSource.getConnection();
 * 
* * new: *
 *   Connection connection;
 *   if ( m_dataSource instanceof HashedDataSourceCluster )
 *   {
 *     connection = ((HashedDataSourceCluster)m_dataSource).getConnectionForHashObject( hashObject );
 *   }
 *   else
 *   {
 *     connection = m_dataSource.getConnection();
 *   }
 * 
* * @avalon.component * @avalon.service type=org.apache.avalon.excalibur.datasource.DataSourceComponent * @avalon.service type=HashedDataSourceCluster * @x-avalon.info name=hash-db-cluster * @x-avalon.lifestyle type=singleton * * @author Avalon Development Team * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:20 $ * @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 NoValidConnectionException 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 NoValidConnectionException 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. *

* Subclasses can override this method to get different behavior. *

* 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. *

* Subclasses can override this method to get different behavior. *

* 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 ) { // DEVELOPER WARNING: // If you change the way the hashCode is calculated, you WILL BREAK // things for existing users, so please do so only after much thought. // Hash code may be negative, Make them all positive by using the unsigned int value. long lHashCode = ( (long)hashCode ) & 0xffffffffL; return (int)( lHashCode % getClusterSize() ); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy