KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > jdbc > TransactionResourceImpl


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

21
22 package org.apache.derby.impl.jdbc;
23
24 import org.apache.derby.jdbc.InternalDriver;
25
26 import org.apache.derby.iapi.services.context.Context;
27 import org.apache.derby.iapi.services.context.ContextService;
28 import org.apache.derby.iapi.services.context.ContextManager;
29 import org.apache.derby.iapi.services.monitor.Monitor;
30 import org.apache.derby.iapi.services.sanity.SanityManager;
31
32 import org.apache.derby.iapi.db.Database;
33 import org.apache.derby.iapi.error.StandardException;
34 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
35 import org.apache.derby.iapi.error.ExceptionSeverity;
36
37 import org.apache.derby.iapi.reference.Attribute;
38 import org.apache.derby.iapi.reference.SQLState;
39 import org.apache.derby.iapi.reference.Property;
40 import org.apache.derby.iapi.util.StringUtil;
41 import org.apache.derby.iapi.util.IdUtil;
42
43 import java.util.Properties JavaDoc;
44 import java.sql.SQLException JavaDoc;
45
46 /**
47  * An instance of a TransactionResourceImpl is a bundle of things that
48  * connects a connection to the database - it is the transaction "context" in
49  * a generic sense. It is also the object of synchronization used by the
50  * connection object to make sure only one thread is accessing the underlying
51  * transaction and context.
52  *
53  * <P>TransactionResourceImpl not only serves as a transaction "context", it
54  * also takes care of: <OL>
55  * <LI>context management: the pushing and popping of the context manager in
56  * and out of the global context service</LI>
57  * <LI>transaction demarcation: all calls to commit/abort/prepare/close a
58  * transaction must route thru the transaction resource.
59  * <LI>error handling</LI>
60  * </OL>
61  *
62  * <P>The only connection that have access to the TransactionResource is the
63  * root connection, all other nested connections (called proxyConnection)
64  * accesses the TransactionResource via the root connection. The root
65  * connection may be a plain EmbedConnection, or a DetachableConnection (in
66  * case of a XATransaction). A nested connection must be a ProxyConnection.
67  * A proxyConnection is not detachable and can itself be a XA connection -
68  * although an XATransaction may start nested local (proxy) connections.
69  *
70  * <P> this is an example of how all the objects in this package relate to each
71  * other. In this example, the connection is nested 3 deep.
72  * DetachableConnection.
73  * <P><PRE>
74  *
75  * lcc cm database jdbcDriver
76  * ^ ^ ^ ^
77  * | | | |
78  * |======================|
79  * | TransactionResource |
80  * |======================|
81  * ^ |
82  * | |
83  * | | |---------------rootConnection----------|
84  * | | | |
85  * | | |- rootConnection-| |
86  * | | | | |
87  * | V V | |
88  *|========================| |=================| |=================|
89  *| EmbedConnection | | EmbedConnection | | EmbedConnection |
90  *| |<-----| |<-----| |
91  *| (DetachableConnection) | | ProxyConnection | | ProxyConnection |
92  *|========================| |=================| |=================|
93  * ^ | ^ ^ ^
94  * | | | | |
95  * ---rootConnection-- | | |
96  * | | |
97  * | | |
98  * |======================| |======================| |======================|
99  * | ConnectionChild | | ConnectionChild | | ConnectionChild |
100  * | | | | | |
101  * | (EmbedStatement) | | (EmbedResultSet) | | (...) |
102  * |======================| |======================| |======================|
103  *
104  * <P>A plain local connection <B>must</B> be attached (doubly linked with) to a
105  * TransactionResource at all times. A detachable connection can be without a
106  * TransactionResource, and a TransactionResource for an XATransaction
107  * (called XATransactionResource) can be without a connection.
108  *
109  *
110  */

111 public final class TransactionResourceImpl
112 {
113     /*
114     ** instance variables set up in the constructor.
115     */

116     // conn is only present if TR is attached to a connection
117
protected ContextManager cm;
118     protected ContextService csf;
119     protected String JavaDoc username;
120
121     private String JavaDoc dbname;
122     private InternalDriver driver;
123     private String JavaDoc url;
124     private String JavaDoc drdaID;
125
126     // set these up after constructor, called by EmbedConnection
127
protected Database database;
128     protected LanguageConnectionContext lcc;
129
130     /*
131      * create a brand new connection for a brand new transaction
132      */

133     TransactionResourceImpl(
134                             InternalDriver driver,
135                             String JavaDoc url,
136                             Properties JavaDoc info) throws SQLException JavaDoc
137     {
138         this.driver = driver;
139         csf = driver.getContextServiceFactory();
140         dbname = InternalDriver.getDatabaseName(url, info);
141         this.url = url;
142
143         // the driver manager will push a user name
144
// into the properties if its getConnection(url, string, string)
145
// interface is used. Thus, we look there first.
146
// Default to APP.
147
username = IdUtil.getUserNameFromURLProps(info);
148
149         drdaID = info.getProperty(Attribute.DRDAID_ATTR, null);
150
151         // make a new context manager for this TransactionResource
152

153         // note that the Database API requires that the
154
// getCurrentContextManager call return the context manager
155
// associated with this session. The JDBC driver assumes
156
// responsibility (for now) for tracking and installing
157
// this context manager for the thread, each time a database
158
// call is made.
159
cm = csf.newContextManager();
160     }
161
162     /*
163      * Called only in EmbedConnection construtor.
164      * The Local Connection sets up the database in its constructor and sets it
165      * here.
166      */

167     void setDatabase(Database db)
168     {
169         if (SanityManager.DEBUG)
170             SanityManager.ASSERT(database == null,
171                 "setting database when it is not null");
172
173         database = db;
174     }
175
176     /*
177      * Called only in EmbedConnection constructor. Create a new transaction
178      * by creating a lcc.
179      *
180      * The arguments are not used by this object, it is used by
181      * XATransactionResoruceImpl. Put them here so that there is only one
182      * routine to start a local connection.
183      */

184     void startTransaction() throws StandardException, SQLException JavaDoc
185     {
186         // setting up local connection
187
lcc = database.setupConnection(cm, username, drdaID, dbname);
188     }
189
190     /*
191      * Return instance variables to EmbedConnection. RESOLVE: given time, we
192      * should perhaps stop giving out reference to these things but instead use
193      * the transaction resource itself.
194      */

195     InternalDriver getDriver() {
196         return driver;
197     }
198     ContextService getCsf() {
199         return csf;
200     }
201
202     /*
203      * need to be public because it is in the XATransactionResource interface
204      */

205     ContextManager getContextManager() {
206         return cm;
207     }
208
209     LanguageConnectionContext getLcc() {
210         return lcc;
211     }
212     String JavaDoc getDBName() {
213         return dbname;
214     }
215     String JavaDoc getUrl() {
216         return url;
217     }
218     Database getDatabase() {
219         return database;
220     }
221
222     StandardException shutdownDatabaseException() {
223         StandardException se = StandardException.newException(SQLState.SHUTDOWN_DATABASE, getDBName());
224         se.setReport(StandardException.REPORT_NEVER);
225         return se;
226     }
227
228     /*
229      * local transaction demarcation - note that global or xa transaction
230      * cannot commit thru the connection, they can only commit thru the
231      * XAResource, which uses the xa_commit or xa_rollback interface as a
232      * safeguard.
233      */

234     void commit() throws StandardException
235     {
236         lcc.userCommit();
237     }
238
239     void rollback() throws StandardException
240     {
241         // lcc may be null if this is called in close.
242
if (lcc != null)
243             lcc.userRollback();
244     }
245
246     /*
247      * context management
248      */

249
250     /**
251      * An error happens in the constructor, pop the context.
252      */

253     void clearContextInError()
254     {
255         csf.resetCurrentContextManager(cm);
256         cm = null;
257     }
258
259     /**
260      * Resolve: probably superfluous
261      */

262     void clearLcc()
263     {
264         lcc = null;
265     }
266
267     final void setupContextStack()
268     {
269         if (SanityManager.DEBUG) {
270             SanityManager.ASSERT(cm != null, "setting up null context manager stack");
271         }
272
273             csf.setCurrentContextManager(cm);
274     }
275
276     final void restoreContextStack() {
277
278         if ((csf == null) || (cm == null))
279             return;
280         csf.resetCurrentContextManager(cm);
281     }
282
283     /*
284      * exception handling
285      */

286
287     /*
288      * clean up the error and wrap the real exception in some SQLException.
289      */

290     final SQLException JavaDoc handleException(Throwable JavaDoc thrownException,
291                                        boolean autoCommit,
292                                        boolean rollbackOnAutoCommit)
293             throws SQLException JavaDoc
294     {
295         try {
296             if (SanityManager.DEBUG)
297                 SanityManager.ASSERT(thrownException != null);
298
299             /*
300                 just pass SQL exceptions right back. We assume that JDBC driver
301                 code has cleaned up sufficiently. Not passing them through would mean
302                 that all cleanupOnError methods would require knowledge of Utils.
303              */

304             if (thrownException instanceof SQLException JavaDoc) {
305
306                 return (SQLException JavaDoc) thrownException;
307
308             }
309
310             boolean checkForShutdown = false;
311             if (thrownException instanceof StandardException)
312             {
313                 StandardException se = (StandardException) thrownException;
314                 int severity = se.getSeverity();
315                 if (severity <= ExceptionSeverity.STATEMENT_SEVERITY)
316                 {
317                     /*
318                     ** If autocommit is on, then do a rollback
319                     ** to release locks if requested. We did a stmt
320                     ** rollback in the cleanupOnError above, but we still
321                     ** may hold locks from the stmt.
322                     */

323                     if (autoCommit && rollbackOnAutoCommit)
324                     {
325                         se.setSeverity(ExceptionSeverity.TRANSACTION_SEVERITY);
326                     }
327                 } else if (SQLState.CONN_INTERRUPT.equals(se.getMessageId())) {
328                     // an interrupt closed the connection.
329
checkForShutdown = true;
330                 }
331             }
332             // if cm is null, we don't have a connection context left,
333
// it was already removed. all that's left to cleanup is
334
// JDBC objects.
335
if (cm!=null) {
336                 boolean isShutdown = cleanupOnError(thrownException);
337                 if (checkForShutdown && isShutdown) {
338                     // Change the error message to be a known shutdown.
339
thrownException = shutdownDatabaseException();
340                 }
341             }
342
343
344
345             return wrapInSQLException((SQLException JavaDoc) null, thrownException);
346
347         } catch (Throwable JavaDoc t) {
348
349             if (cm!=null) { // something to let us cleanup?
350
cm.cleanupOnError(t);
351             }
352             /*
353                We'd rather throw the Throwable,
354                but then javac complains...
355                We assume if we are in this degenerate
356                case that it is actually a java exception
357              */

358             throw wrapInSQLException((SQLException JavaDoc) null, t);
359             //throw t;
360
}
361
362     }
363          
364     public static final SQLException JavaDoc wrapInSQLException(SQLException JavaDoc sqlException, Throwable JavaDoc thrownException) {
365
366         if (thrownException == null)
367             return sqlException;
368
369         SQLException JavaDoc nextSQLException;
370
371         if (thrownException instanceof SQLException JavaDoc) {
372
373             // server side JDBC can end up with a SQLException in the nested stack
374
nextSQLException = (SQLException JavaDoc) thrownException;
375         }
376         else if (thrownException instanceof StandardException) {
377
378             StandardException se = (StandardException) thrownException;
379
380             nextSQLException = Util.generateCsSQLException(se);
381
382             wrapInSQLException(nextSQLException, se.getNestedException());
383
384         } else {
385
386             nextSQLException = Util.javaException(thrownException);
387
388             // special case some java exceptions that have nested exceptions themselves
389
Throwable JavaDoc nestedByJVM = null;
390             if (thrownException instanceof ExceptionInInitializerError JavaDoc) {
391                 nestedByJVM = ((ExceptionInInitializerError JavaDoc) thrownException).getException();
392             } else if (thrownException instanceof java.lang.reflect.InvocationTargetException JavaDoc) {
393                 nestedByJVM = ((java.lang.reflect.InvocationTargetException JavaDoc) thrownException).getTargetException();
394             }
395
396             if (nestedByJVM != null) {
397                 wrapInSQLException(nextSQLException, nestedByJVM);
398             }
399             
400         }
401
402         if (sqlException != null) {
403             sqlException.setNextException(nextSQLException);
404         }
405
406         return nextSQLException;
407     }
408
409     /*
410      * TransactionResource methods
411      */

412
413     String JavaDoc getUserName() {
414         return username;
415     }
416
417     boolean cleanupOnError(Throwable JavaDoc e)
418     {
419         if (SanityManager.DEBUG)
420             SanityManager.ASSERT(cm != null, "cannot cleanup on error with null context manager");
421
422         return cm.cleanupOnError(e);
423     }
424
425     boolean isIdle()
426     {
427         // If no lcc, there is no transaction.
428
return (lcc == null || lcc.getTransactionExecute().isIdle());
429     }
430
431
432     /*
433      * class specific methods
434      */

435
436
437     /*
438      * is the underlaying database still active?
439      */

440     boolean isActive()
441     {
442         // database is null at connection open time
443
return (driver.isActive() && ((database == null) || database.isActive()));
444     }
445
446 }
447
448
449
Popular Tags