KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > excalibur > datasource > cluster > DefaultHashedDataSourceCluster


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.
15  *
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */

19
20 package org.apache.avalon.excalibur.datasource.cluster;
21
22 import java.sql.Connection JavaDoc;
23 import java.sql.SQLException JavaDoc;
24
25 import org.apache.avalon.excalibur.datasource.NoValidConnectionException;
26
27 /**
28  * The DefaultHashedDataSourceCluster requires that the user specify an object or a hashCode
29  * which will be used consistantly select a member DataSource form a cluster for each connection
30  * request. Calls to getConnection() will throw an exception. Components which make use of
31  * this class must call either the getConnectionForHashObject( Object hashObject) or the
32  * getConnectionForHashCode( int hashCode ) methods instead.
33  * <p>
34  * This form of Clustering is useful in cases where data can be reliably accessed in a repeatable
35  * manner. For example a web site's visitor information could be accessed by using a String
36  * containing the visitor's username as a hashObject. This would allow visitor information to be
37  * spread across several database servers.
38  * <p>
39  * The Configuration for a 2 database cluster is like this:
40  *
41  * <pre>
42  * &lt;datasources&gt;
43  * &lt;hashed-cluster name="mydb-cluster" size="2"&gt;
44  * &lt;dbpool index="0"&gt;mydb-0&lt;/dbpool&gt;
45  * &lt;dbpool index="1"&gt;mydb-1&lt;/dbpool&gt;
46  * &lt;/hashed-cluster&gt;
47  * &lt;/datasources&gt;
48  * &lt;cluster-datasources&gt;
49  * &lt;jdbc name="mydb-0"&gt;
50  * &lt;pool-controller min="1" max="10"/&gt;
51  * &lt;auto-commit&gt;true&lt;/auto-commit&gt;
52  * &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
53  * &lt;dburl&gt;jdbc:driver://host0/mydb&lt;/dburl&gt;
54  * &lt;user&gt;username&lt;/user&gt;
55  * &lt;password&gt;password&lt;/password&gt;
56  * &lt;/jdbc&gt;
57  * &lt;jdbc name="mydb-1"&gt;
58  * &lt;pool-controller min="1" max="10"/&gt;
59  * &lt;auto-commit&gt;true&lt;/auto-commit&gt;
60  * &lt;driver&gt;com.database.jdbc.JdbcDriver&lt;/driver&gt;
61  * &lt;dburl&gt;jdbc:driver://host1/mydb&lt;/dburl&gt;
62  * &lt;user&gt;username&lt;/user&gt;
63  * &lt;password&gt;password&lt;/password&gt;
64  * &lt;/jdbc&gt;
65  * &lt;/cluster-datasources&gt;
66  * </pre>
67  *
68  * With the following roles declaration:
69  *
70  * <pre>
71  * &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
72  * shorthand="datasources"
73  * default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
74  * &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
75  * &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
76  * &lt;hint shorthand="hashed-cluster"
77  * class="org.apache.avalon.excalibur.datasource.cluster.DefaultHashedDataSourceCluster"/&gt;
78  * &lt;/role&gt;
79  * &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentClusterSelector"
80  * shorthand="cluster-datasources"
81  * default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
82  * &lt;hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/&gt;
83  * &lt;hint shorthand="j2ee" class="org.apache.avalon.excalibur.datasource.J2eeDataSource"/&gt;
84  * &lt;/role&gt;
85  * </pre>
86  *
87  * A hashed-cluster definition enforces that the configuration specify a size. This size must
88  * equal the number of datasources referenced as being members of the cluster. Any datasource can
89  * be a member of the cluster.
90  * <p>
91  * The hashed-cluster can be obtained in the same manner as a non-clustered datasource. The only
92  * difference is in how it is used. The HashedDataSourceCluster requires that the caller provide
93  * an object or a hashCode to use when requesting a connection.
94  * <p>
95  * The following code demonstrates a change that can be made to database enabled components so that
96  * they will be able to work with both HashedDataSourceCluster DataSources and regular
97  * DataSources.
98  * <p>
99  * old:
100  * <pre>
101  * Connection connection = m_dataSource.getConnection();
102  * </pre>
103  *
104  * new:
105  * <pre>
106  * Connection connection;
107  * if ( m_dataSource instanceof HashedDataSourceCluster )
108  * {
109  * connection = ((HashedDataSourceCluster)m_dataSource).getConnectionForHashObject( hashObject );
110  * }
111  * else
112  * {
113  * connection = m_dataSource.getConnection();
114  * }
115  * </pre>
116  *
117  * @avalon.component
118  * @avalon.service type=org.apache.avalon.excalibur.datasource.DataSourceComponent
119  * @avalon.service type=HashedDataSourceCluster
120  * @x-avalon.info name=hash-db-cluster
121  * @x-avalon.lifestyle type=singleton
122  *
123  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
124  * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:20 $
125  * @since 4.1
126  */

127 public class DefaultHashedDataSourceCluster
128     extends AbstractDataSourceCluster
129     implements HashedDataSourceCluster
130 {
131     /*---------------------------------------------------------------
132      * Constructors
133      *-------------------------------------------------------------*/

134     public DefaultHashedDataSourceCluster()
135     {
136     }
137
138     /*---------------------------------------------------------------
139      * DataSourceComponent Methods
140      *-------------------------------------------------------------*/

141     /**
142      * Not supported in this component. Will throw a NoValidConnectionException.
143      */

144     public Connection JavaDoc getConnection() throws SQLException JavaDoc
145     {
146         throw new NoValidConnectionException(
147             "getConnection() should not be called for a " + getClass().getName() + ". " +
148             "Please verify your configuration." );
149     }
150
151     /*---------------------------------------------------------------
152      * HashedDataSourceCluster Methods
153      *-------------------------------------------------------------*/

154     // public int getClusterSize()
155
// declared in AbstractDataSourceCluster
156

157     /**
158      * Gets a Connection to a database given a hash object.
159      *
160      * @param hashObject Object whose hashCode will be used to select which of the Clusted
161      * DataSources will be provide a Connection.
162      *
163      * @throws NoValidConnectionException when there is no valid Connection wrapper
164      * available in the classloader or when the index is not valid.
165      *
166      * @throws NoValidConnectionException when there are no more available
167      * Connections in the pool.
168      */

169     public Connection JavaDoc getConnectionForHashObject( Object JavaDoc hashObject ) throws SQLException JavaDoc
170     {
171         return getConnectionForIndex( getIndexForHashObject( hashObject ) );
172     }
173
174     /**
175      * Gets a Connection to a database given a hash code.
176      *
177      * @param hashCode HashCode which will be used to select which of the Clusted
178      * DataSources will be provide a Connection.
179      *
180      * @throws NoValidConnectionException when there is no valid Connection wrapper
181      * available in the classloader or when the index is not valid.
182      *
183      * @throws NoValidConnectionException when there are no more available
184      * Connections in the pool.
185      */

186     public Connection JavaDoc getConnectionForHashCode( int hashCode ) throws SQLException JavaDoc
187     {
188         return getConnectionForIndex( getIndexForHashCode( hashCode ) );
189     }
190
191     // public Connection getConnectionForIndex( int index ) throws SQLException
192
// declared in AbstractDataSourceCluster
193

194     /**
195      * Gets the index which will be resolved for a given hashCode. This can be used
196      * by user code to optimize the use of DataSource Clusters.
197      * <p>
198      * Subclasses can override this method to get different behavior.
199      * <p>
200      * By default the index = getIndexForHashCode( hashObject.hashCode() )
201      *
202      * @param hashObject Object whose hashCode will be used to select which of the Clusted
203      * DataSources will be provide a Connection.
204      */

205     public int getIndexForHashObject( Object JavaDoc hashObject )
206     {
207         return getIndexForHashCode( hashObject.hashCode() );
208     }
209
210     /**
211      * Gets the index which will be resolved for a given hashCode. This can be used
212      * by user code to optimize the use of DataSource Clusters.
213      * <p>
214      * Subclasses can override this method to get different behavior.
215      * <p>
216      * By default the index = hashCode % getClusterSize()
217      *
218      * @param hashCode HashCode which will be used to select which of the Clusted
219      * DataSources will be provide a Connection.
220      */

221     public int getIndexForHashCode( int hashCode )
222     {
223         // DEVELOPER WARNING:
224
// If you change the way the hashCode is calculated, you WILL BREAK
225
// things for existing users, so please do so only after much thought.
226

227         // Hash code may be negative, Make them all positive by using the unsigned int value.
228
long lHashCode = ( (long)hashCode ) & 0xffffffffL;
229
230         return (int)( lHashCode % getClusterSize() );
231     }
232 }
233
234
Popular Tags