KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jdbc > datasource > lookup > IsolationLevelDataSourceRouter


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.jdbc.datasource.lookup;
18
19 import org.springframework.core.Constants;
20 import org.springframework.transaction.TransactionDefinition;
21 import org.springframework.transaction.support.DefaultTransactionDefinition;
22 import org.springframework.transaction.support.TransactionSynchronizationManager;
23
24 /**
25  * DataSource that routes to one of various target DataSources based on the
26  * current transaction isolation level. The target DataSources need to be
27  * configured with the isolation level name as key, as defined on the
28  * {@link org.springframework.transaction.TransactionDefinition TransactionDefinition interface}.
29  *
30  * <p>This is particularly useful in combination with JTA transaction management
31  * (typically through Spring's {@link org.springframework.transaction.jta.JtaTransactionManager}).
32  * Standard JTA does not support transaction-specific isolation levels. Some JTA
33  * providers support isolation levels as a vendor-specific extension (e.g. WebLogic),
34  * which is the preferred way of addressing this. As alternative (e.g. on WebSphere),
35  * the target database can be represented through multiple JNDI DataSources, each
36  * configured with a different isolation level (for the entire DataSource).
37  * The present DataSource router allows to transparently switch to the
38  * appropriate DataSource based on the current transaction's isolation level.
39  *
40  * <p>The configuration can for example look like this, assuming that the target
41  * DataSources are defined as individual Spring beans with names
42  * "myRepeatableReadDataSource", "mySerializableDataSource" and "myDefaultDataSource":
43  *
44  * <pre>
45  * &lt;bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter"&gt;
46  * &lt;property name="targetDataSources"&gt;
47  * &lt;map&gt;
48  * &lt;entry key="ISOLATION_REPEATABLE_READ" value-ref="myRepeatableReadDataSource"/&gt;
49  * &lt;entry key="ISOLATION_SERIALIZABLE" value-ref="mySerializableDataSource"/&gt;
50  * &lt;/map&gt;
51  * &lt;/property&gt;
52  * &lt;property name="defaultTargetDataSource" ref="myDefaultDataSource"/&gt;
53  * &lt;/bean&gt;</pre>
54  *
55  * Alternatively, the keyed values can also be data source names, to be resolved
56  * through a {@link #setDataSourceLookup DataSourceLookup}: by default, JNDI
57  * names for a standard JNDI lookup. This allows for a single concise definition
58  * without the need for separate DataSource bean definitions.
59  *
60  * <pre>
61  * &lt;bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter"&gt;
62  * &lt;property name="targetDataSources"&gt;
63  * &lt;map&gt;
64  * &lt;entry key="ISOLATION_REPEATABLE_READ" value="java:comp/env/jdbc/myrrds"/&gt;
65  * &lt;entry key="ISOLATION_SERIALIZABLE" value="java:comp/env/jdbc/myserds"/&gt;
66  * &lt;/map&gt;
67  * &lt;/property&gt;
68  * &lt;property name="defaultTargetDataSource" value="java:comp/env/jdbc/mydefds"/&gt;
69  * &lt;/bean&gt;</pre>
70  *
71  * Note: If you are using this router in combination with Spring's
72  * {@link org.springframework.transaction.jta.JtaTransactionManager},
73  * don't forget to switch the "allowCustomIsolationLevels" flag to "true".
74  * (By default, JtaTransactionManager will only accept a default isolation level
75  * because of the lack of isolation level support in standard JTA itself.)
76  *
77  * <pre>
78  * &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"&gt;
79  * &lt;property name="allowCustomIsolationLevels" value="true"/&gt;
80  * &lt;/bean&gt;</pre>
81  *
82  * @author Juergen Hoeller
83  * @since 2.0.1
84  * @see #setTargetDataSources
85  * @see #setDefaultTargetDataSource
86  * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED
87  * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED
88  * @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ
89  * @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE
90  * @see org.springframework.transaction.jta.JtaTransactionManager
91  */

92 public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource {
93
94     /** Constants instance for TransactionDefinition */
95     private static final Constants constants = new Constants(TransactionDefinition.class);
96
97
98     /**
99      * Supports Integer values for the isolation level constants
100      * as well as isolation level names as defined on the
101      * {@link org.springframework.transaction.TransactionDefinition TransactionDefinition interface}.
102      */

103     protected Object JavaDoc resolveSpecifiedLookupKey(Object JavaDoc lookupKey) {
104         if (lookupKey instanceof Integer JavaDoc) {
105             return (Integer JavaDoc) lookupKey;
106         }
107         else if (lookupKey instanceof String JavaDoc) {
108             String JavaDoc constantName = (String JavaDoc) lookupKey;
109             if (constantName == null || !constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {
110                 throw new IllegalArgumentException JavaDoc("Only isolation constants allowed");
111             }
112             return constants.asNumber(constantName);
113         }
114         else {
115             throw new IllegalArgumentException JavaDoc(
116                     "Invalid lookup key - needs to be isolation level Integer or isolation level name String: " + lookupKey);
117         }
118     }
119
120     protected Object JavaDoc determineCurrentLookupKey() {
121         return TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
122     }
123
124 }
125
Popular Tags