KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > transaction > jta > WebLogicJtaTransactionManager


1 /*
2  * Copyright 2002-2007 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.transaction.jta;
18
19 import java.io.Serializable JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22
23 import javax.transaction.InvalidTransactionException JavaDoc;
24 import javax.transaction.NotSupportedException JavaDoc;
25 import javax.transaction.SystemException JavaDoc;
26 import javax.transaction.Transaction JavaDoc;
27 import javax.transaction.TransactionManager JavaDoc;
28 import javax.transaction.UserTransaction JavaDoc;
29
30 import org.springframework.transaction.TransactionDefinition;
31 import org.springframework.transaction.TransactionSystemException;
32
33 /**
34  * Special {@link JtaTransactionManager} variant for BEA WebLogic (7.0, 8.1 and higher).
35  * Supports the full power of Spring's transaction definitions on WebLogic's
36  * transaction coordinator, <i>beyond standard JTA</i>: transaction names,
37  * per-transaction isolation levels, and proper resuming of transactions in all cases.
38  *
39  * <p>Uses WebLogic's special <code>begin(name)</code> method to start a JTA transaction,
40  * in order to make <b>Spring-driven transactions visible in WebLogic's transaction
41  * monitor</b>. In case of Spring's declarative transactions, the exposed name will
42  * (by default) be the fully-qualified class name + "." + method name.
43  *
44  * <p>Supports a <b>per-transaction isolation level</b> through WebLogic's corresponding
45  * JTA transaction property "ISOLATION LEVEL". This will apply the specified isolation
46  * level (e.g. ISOLATION_SERIALIZABLE) to all JDBC Connections that participate in the
47  * given transaction.
48  *
49  * <p>Invokes WebLogic's special <code>forceResume</code> method if standard JTA resume
50  * failed, to <b>also resume if the target transaction was marked rollback-only</b>.
51  * If you're not relying on this feature of transaction suspension in the first
52  * place, Spring's standard JtaTransactionManager will behave properly too.
53  *
54  * <p>Automatically detects WebLogic Server 7.0 or 8.1+ and adapts accordingly.
55  * Usage on a WebLogic client is also supported, although with restricted
56  * functionality: transaction names cannot be applied there.
57  *
58  * <p>By default, the JTA UserTransaction and TransactionManager handles are
59  * fetched directly from WebLogic's <code>TransactionHelper</code> (on 8.1+)
60  * or <code>TxHelper</code> (on 7.0). This can be overridden by specifying
61  * "userTransaction"/"userTransactionName" and "transactionManager"/"transactionManagerName",
62  * passing in existing handles or specifying corresponding JNDI locations to look up.
63  *
64  * @author Juergen Hoeller
65  * @since 1.1
66  * @see org.springframework.transaction.TransactionDefinition#getName
67  * @see org.springframework.transaction.TransactionDefinition#getIsolationLevel
68  * @see weblogic.transaction.UserTransaction#begin(String)
69  * @see weblogic.transaction.Transaction#setProperty
70  * @see weblogic.transaction.TransactionManager#forceResume
71  * @see weblogic.transaction.TransactionHelper
72  * @see weblogic.transaction.TxHelper
73  */

74 public class WebLogicJtaTransactionManager extends JtaTransactionManager {
75
76     private static final String JavaDoc USER_TRANSACTION_CLASS_NAME = "weblogic.transaction.UserTransaction";
77
78     private static final String JavaDoc CLIENT_TRANSACTION_MANAGER_CLASS_NAME = "weblogic.transaction.ClientTransactionManager";
79
80     private static final String JavaDoc TRANSACTION_MANAGER_CLASS_NAME = "weblogic.transaction.TransactionManager";
81
82     private static final String JavaDoc TRANSACTION_CLASS_NAME = "weblogic.transaction.Transaction";
83
84     private static final String JavaDoc TRANSACTION_HELPER_CLASS_NAME = "weblogic.transaction.TransactionHelper";
85
86     private static final String JavaDoc TX_HELPER_CLASS_NAME = "weblogic.transaction.TxHelper";
87
88     private static final String JavaDoc ISOLATION_LEVEL_KEY = "ISOLATION LEVEL";
89
90
91     private boolean weblogicUserTransactionAvailable;
92
93     private Method JavaDoc beginWithNameMethod;
94
95     private Method JavaDoc beginWithNameAndTimeoutMethod;
96
97     private boolean weblogicTransactionManagerAvailable;
98
99     private Method JavaDoc forceResumeMethod;
100
101     private Method JavaDoc setPropertyMethod;
102
103     private Class JavaDoc transactionHelperClass;
104
105     private Object JavaDoc transactionHelper;
106
107
108     public void afterPropertiesSet() throws TransactionSystemException {
109         super.afterPropertiesSet();
110         loadWebLogicTransactionClasses();
111     }
112
113     protected UserTransaction JavaDoc retrieveUserTransaction() throws TransactionSystemException {
114         loadWebLogicTransactionHelperClass();
115         try {
116             logger.debug("Retrieving JTA UserTransaction from WebLogic TransactionHelper/TxHelper");
117             Method JavaDoc getUserTransactionMethod =
118                     this.transactionHelperClass.getMethod("getUserTransaction", new Class JavaDoc[0]);
119             return (UserTransaction JavaDoc) getUserTransactionMethod.invoke(this.transactionHelper, new Object JavaDoc[0]);
120         }
121         catch (InvocationTargetException JavaDoc ex) {
122             throw new TransactionSystemException(
123                     "WebLogic's TransactionHelper/TxHelper.getUserTransaction() method failed", ex.getTargetException());
124         }
125         catch (Exception JavaDoc ex) {
126             throw new TransactionSystemException(
127                     "Could not invoke WebLogic's TransactionHelper/TxHelper.getUserTransaction() method", ex);
128         }
129     }
130
131     protected TransactionManager JavaDoc retrieveTransactionManager() throws TransactionSystemException {
132         loadWebLogicTransactionHelperClass();
133         try {
134             logger.debug("Retrieving JTA TransactionManager from WebLogic TransactionHelper/TxHelper");
135             Method JavaDoc getTransactionManagerMethod =
136                     this.transactionHelperClass.getMethod("getTransactionManager", new Class JavaDoc[0]);
137             return (TransactionManager JavaDoc) getTransactionManagerMethod.invoke(this.transactionHelper, new Object JavaDoc[0]);
138         }
139         catch (InvocationTargetException JavaDoc ex) {
140             throw new TransactionSystemException(
141                     "WebLogic's TransactionHelper/TxHelper.getTransactionManager() method failed", ex.getTargetException());
142         }
143         catch (Exception JavaDoc ex) {
144             throw new TransactionSystemException(
145                     "Could not invoke WebLogic's TransactionHelper/TxHelper.getTransactionManager() method", ex);
146         }
147     }
148
149
150     private void loadWebLogicTransactionHelperClass() throws TransactionSystemException {
151         if (this.transactionHelperClass == null) {
152             try {
153                 try {
154                     this.transactionHelperClass =
155                             getClass().getClassLoader().loadClass(TRANSACTION_HELPER_CLASS_NAME);
156                     Method JavaDoc getTransactionHelperMethod =
157                             this.transactionHelperClass.getMethod("getTransactionHelper", new Class JavaDoc[0]);
158                     this.transactionHelper = getTransactionHelperMethod.invoke(null, new Object JavaDoc[0]);
159                     logger.debug("WebLogic 8.1+ TransactionHelper found");
160                 }
161                 catch (ClassNotFoundException JavaDoc ex) {
162                     this.transactionHelperClass =
163                             getClass().getClassLoader().loadClass(TX_HELPER_CLASS_NAME);
164                     logger.debug("WebLogic 7.0 TxHelper found");
165                 }
166             }
167             catch (InvocationTargetException JavaDoc ex) {
168                 throw new TransactionSystemException(
169                         "WebLogic's TransactionHelper.getTransactionHelper() method failed", ex.getTargetException());
170             }
171             catch (Exception JavaDoc ex) {
172                 throw new TransactionSystemException(
173                         "Could not initialize WebLogicJtaTransactionManager because WebLogic API classes are not available",
174                         ex);
175             }
176         }
177     }
178
179     private void loadWebLogicTransactionClasses() throws TransactionSystemException {
180         try {
181             Class JavaDoc userTransactionClass =
182                 getClass().getClassLoader().loadClass(USER_TRANSACTION_CLASS_NAME);
183             this.weblogicUserTransactionAvailable =
184                     userTransactionClass.isInstance(getUserTransaction());
185             if (this.weblogicUserTransactionAvailable) {
186                 this.beginWithNameMethod =
187                         userTransactionClass.getMethod("begin", new Class JavaDoc[] {String JavaDoc.class});
188                 this.beginWithNameAndTimeoutMethod =
189                         userTransactionClass.getMethod("begin", new Class JavaDoc[] {String JavaDoc.class, int.class});
190                 logger.info("Support for WebLogic transaction names available");
191             }
192             else {
193                 logger.info("Support for WebLogic transaction names not available");
194             }
195
196             Class JavaDoc transactionManagerClass = null;
197             try {
198                 // Try WebLogic 8.1 ClientTransactionManager interface.
199
transactionManagerClass =
200                         getClass().getClassLoader().loadClass(CLIENT_TRANSACTION_MANAGER_CLASS_NAME);
201                 logger.debug("WebLogic 8.1+ ClientTransactionManager found");
202             }
203             catch (ClassNotFoundException JavaDoc ex) {
204                 // Fall back to WebLogic TransactionManager interface.
205
transactionManagerClass =
206                         getClass().getClassLoader().loadClass(TRANSACTION_MANAGER_CLASS_NAME);
207                 logger.debug("WebLogic 7.0 TransactionManager found");
208             }
209
210             this.weblogicTransactionManagerAvailable =
211                     transactionManagerClass.isInstance(getTransactionManager());
212             if (this.weblogicTransactionManagerAvailable) {
213                 Class JavaDoc transactionClass = getClass().getClassLoader().loadClass(TRANSACTION_CLASS_NAME);
214                 this.forceResumeMethod =
215                         transactionManagerClass.getMethod("forceResume", new Class JavaDoc[] {Transaction JavaDoc.class});
216                 this.setPropertyMethod =
217                         transactionClass.getMethod("setProperty", new Class JavaDoc[] {String JavaDoc.class, Serializable JavaDoc.class});
218                 logger.debug("Support for WebLogic forceResume available");
219             }
220             else {
221                 logger.warn("Support for WebLogic forceResume not available");
222             }
223         }
224         catch (Exception JavaDoc ex) {
225             throw new TransactionSystemException(
226                     "Could not initialize WebLogicJtaTransactionManager because WebLogic API classes are not available",
227                 ex);
228         }
229     }
230
231
232     protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition definition)
233             throws NotSupportedException JavaDoc, SystemException JavaDoc {
234
235         int timeout = determineTimeout(definition);
236
237         // Apply transaction name (if any) to WebLogic transaction.
238
if (this.weblogicUserTransactionAvailable && definition.getName() != null) {
239             try {
240                 if (timeout > TransactionDefinition.TIMEOUT_DEFAULT) {
241                     /*
242                     weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
243                     wut.begin(definition.getName(), timeout);
244                     */

245                     this.beginWithNameAndTimeoutMethod.invoke(txObject.getUserTransaction(),
246                             new Object JavaDoc[] {definition.getName(), new Integer JavaDoc(timeout)});
247                 }
248                 else {
249                     /*
250                     weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
251                     wut.begin(definition.getName());
252                     */

253                     this.beginWithNameMethod.invoke(txObject.getUserTransaction(),
254                             new Object JavaDoc[] {definition.getName()});
255                 }
256             }
257             catch (InvocationTargetException JavaDoc ex) {
258                 throw new TransactionSystemException(
259                         "WebLogic's UserTransaction.begin() method failed", ex.getTargetException());
260             }
261             catch (Exception JavaDoc ex) {
262                 throw new TransactionSystemException(
263                         "Could not invoke WebLogic's UserTransaction.begin() method", ex);
264             }
265         }
266         else {
267             // No WebLogic UserTransaction available or no transaction name specified
268
// -> standard JTA begin call.
269
applyTimeout(txObject, timeout);
270             txObject.getUserTransaction().begin();
271         }
272
273         // Specify isolation level, if any, through corresponding WebLogic transaction property.
274
if (this.weblogicTransactionManagerAvailable) {
275             if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
276                 try {
277                     Transaction JavaDoc tx = getTransactionManager().getTransaction();
278                     Integer JavaDoc isolationLevel = new Integer JavaDoc(definition.getIsolationLevel());
279                     /*
280                     weblogic.transaction.Transaction wtx = (weblogic.transaction.Transaction) tx;
281                     wtx.setProperty(ISOLATION_LEVEL_KEY, isolationLevel);
282                     */

283                     this.setPropertyMethod.invoke(tx, new Object JavaDoc[] {ISOLATION_LEVEL_KEY, isolationLevel});
284                 }
285                 catch (InvocationTargetException JavaDoc ex) {
286                     throw new TransactionSystemException(
287                             "WebLogic's Transaction.setProperty(String, Serializable) method failed", ex.getTargetException());
288                 }
289                 catch (Exception JavaDoc ex) {
290                     throw new TransactionSystemException(
291                             "Could not invoke WebLogic's Transaction.setProperty(String, Serializable) method", ex);
292                 }
293             }
294         }
295         else {
296             applyIsolationLevel(txObject, definition.getIsolationLevel());
297         }
298     }
299
300     protected void doJtaResume(JtaTransactionObject txObject, Object JavaDoc suspendedTransaction)
301             throws InvalidTransactionException JavaDoc, SystemException JavaDoc {
302
303         try {
304             getTransactionManager().resume((Transaction JavaDoc) suspendedTransaction);
305         }
306         catch (InvalidTransactionException JavaDoc ex) {
307             if (!this.weblogicTransactionManagerAvailable) {
308                 throw ex;
309             }
310
311             if (logger.isDebugEnabled()) {
312                 logger.debug("Standard JTA resume threw InvalidTransactionException: " + ex.getMessage() +
313                     " - trying WebLogic JTA forceResume");
314             }
315             /*
316             weblogic.transaction.TransactionManager wtm =
317                     (weblogic.transaction.TransactionManager) getTransactionManager();
318             wtm.forceResume(suspendedTransaction);
319             */

320             try {
321                 this.forceResumeMethod.invoke(getTransactionManager(), new Object JavaDoc[] {suspendedTransaction});
322             }
323             catch (InvocationTargetException JavaDoc ex2) {
324                 throw new TransactionSystemException(
325                         "WebLogic's TransactionManager.forceResume(Transaction) method failed", ex2.getTargetException());
326             }
327             catch (Exception JavaDoc ex2) {
328                 throw new TransactionSystemException(
329                         "Could not access WebLogic's TransactionManager.forceResume(Transaction) method", ex2);
330             }
331         }
332     }
333
334 }
335
Popular Tags