EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.impl.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [TransactionResourceImpl.java]

nameclass, %method, %block, %line, %
TransactionResourceImpl.java100% (1/1)100% (23/23)92%  (301/327)93%  (81.6/88)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TransactionResourceImpl100% (1/1)100% (23/23)92%  (301/327)93%  (81.6/88)
TransactionResourceImpl (InternalDriver, String, Properties): void 100% (1/1)93%  (40/43)91%  (10/11)
cleanupOnError (Throwable): boolean 100% (1/1)92%  (12/13)96%  (1.9/2)
clearContextInError (): void 100% (1/1)100% (9/9)100% (3/3)
clearLcc (): void 100% (1/1)100% (4/4)100% (2/2)
commit (): void 100% (1/1)100% (4/4)100% (2/2)
getContextManager (): ContextManager 100% (1/1)100% (3/3)100% (1/1)
getCsf (): ContextService 100% (1/1)100% (3/3)100% (1/1)
getDBName (): String 100% (1/1)100% (3/3)100% (1/1)
getDatabase (): Database 100% (1/1)100% (3/3)100% (1/1)
getDriver (): InternalDriver 100% (1/1)100% (3/3)100% (1/1)
getLcc (): LanguageConnectionContext 100% (1/1)100% (3/3)100% (1/1)
getUrl (): String 100% (1/1)100% (3/3)100% (1/1)
getUserName (): String 100% (1/1)100% (3/3)100% (1/1)
handleException (Throwable, boolean, boolean): SQLException 100% (1/1)80%  (59/74)80%  (16.9/21)
isActive (): boolean 100% (1/1)100% (15/15)100% (1/1)
isIdle (): boolean 100% (1/1)100% (12/12)100% (1/1)
restoreContextStack (): void 100% (1/1)100% (13/13)100% (4/4)
rollback (): void 100% (1/1)100% (7/7)100% (3/3)
setDatabase (Database): void 100% (1/1)92%  (11/12)97%  (2.9/3)
setupContextStack (): void 100% (1/1)93%  (13/14)97%  (2.9/3)
shutdownDatabaseException (): StandardException 100% (1/1)100% (10/10)100% (3/3)
startTransaction (): void 100% (1/1)100% (14/14)100% (2/2)
wrapInSQLException (SQLException, Throwable): SQLException 100% (1/1)92%  (54/59)95%  (18/19)

1/*
2 
3   Derby - Class org.apache.derby.impl.jdbc.TransactionResourceImpl
4 
5   Copyright 1999, 2004 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.impl.jdbc;
22 
23import org.apache.derby.jdbc.InternalDriver;
24 
25import org.apache.derby.iapi.services.context.Context;
26import org.apache.derby.iapi.services.context.ContextService;
27import org.apache.derby.iapi.services.context.ContextManager;
28import org.apache.derby.iapi.services.monitor.Monitor;
29import org.apache.derby.iapi.services.sanity.SanityManager;
30 
31import org.apache.derby.iapi.db.Database;
32import org.apache.derby.iapi.error.StandardException;
33import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
34import org.apache.derby.iapi.error.ExceptionSeverity;
35 
36import org.apache.derby.iapi.reference.Attribute;
37import org.apache.derby.iapi.reference.SQLState;
38import org.apache.derby.iapi.reference.Property;
39import org.apache.derby.iapi.util.StringUtil;
40import org.apache.derby.iapi.util.IdUtil;
41 
42import java.util.Properties;
43import java.sql.SQLException;
44 
45/** 
46 *        An instance of a TransactionResourceImpl is a bundle of things that
47 *        connects a connection to the database - it is the transaction "context" in
48 *        a generic sense.  It is also the object of synchronization used by the
49 *        connection object to make sure only one thread is accessing the underlying
50 *        transaction and context.
51 *
52 *  <P>TransactionResourceImpl not only serves as a transaction "context", it
53 *        also takes care of: <OL>
54 *        <LI>context management: the pushing and popping of the context manager in
55 *                and out of the global context service</LI>
56 *        <LI>transaction demarcation: all calls to commit/abort/prepare/close a
57 *                transaction must route thru the transaction resource.
58 *        <LI>error handling</LI>
59 *        </OL>
60 *
61 *  <P>The only connection that have access to the TransactionResource is the
62 *  root connection, all other nested connections (called proxyConnection)
63 *  accesses the TransactionResource via the root connection.  The root
64 *  connection may be a plain EmbedConnection, or a DetachableConnection (in
65 *  case of a XATransaction).  A nested connection must be a ProxyConnection.
66 *  A proxyConnection is not detachable and can itself be a XA connection -
67 *  although an XATransaction may start nested local (proxy) connections.
68 *
69 *        <P> this is an example of how all the objects in this package relate to each
70 *                other.  In this example, the connection is nested 3 deep.  
71 *                DetachableConnection.  
72 *        <P><PRE>
73 *
74 *      lcc  cm   database  jdbcDriver
75 *       ^    ^    ^         ^ 
76 *       |    |    |         |
77 *      |======================|
78 *      | TransactionResource  |
79 *      |======================|
80 *             ^  |
81 *             |  |
82 *             |  |      |---------------rootConnection----------|
83 *             |  |      |                                       |
84 *             |  |      |- rootConnection-|                     |
85 *             |  |      |                 |                     |
86 *             |  V      V                 |                     |
87 *|========================|      |=================|      |=================|
88 *|    EmbedConnection     |      | EmbedConnection |      | EmbedConnection |
89 *|                        |<-----|                 |<-----|                 |
90 *| (DetachableConnection) |      | ProxyConnection |      | ProxyConnection |
91 *|========================|      |=================|      |=================|
92 *   ^                 | ^             ^                        ^
93 *   |                 | |             |                        |
94 *   ---rootConnection-- |             |                        |
95 *                       |             |                        |
96 *                       |             |                        |
97 * |======================|  |======================|  |======================|
98 * | ConnectionChild |  | ConnectionChild |  | ConnectionChild |
99 * |                      |  |                      |  |                      |
100 * |  (EmbedStatement)    |  |  (EmbedResultSet)    |  |  (...)               |
101 * |======================|  |======================|  |======================|
102 *
103 * <P>A plain local connection <B>must</B> be attached (doubly linked with) to a
104 * TransactionResource at all times.  A detachable connection can be without a
105 * TransactionResource, and a TransactionResource for an XATransaction
106 * (called  XATransactionResource) can be without a connection.
107 *
108 *
109 */
110public final class TransactionResourceImpl
111{
112        /*
113        ** instance variables set up in the constructor.
114        */
115        // conn is only present if TR is attached to a connection
116        protected ContextManager cm;
117        protected ContextService csf;
118        protected String username;
119 
120        private String dbname;
121        private InternalDriver driver;
122        private String url;
123        private String drdaID;
124 
125        // set these up after constructor, called by EmbedConnection
126        protected Database database;
127        protected LanguageConnectionContext lcc;
128 
129        /*
130         * create a brand new connection for a brand new transaction
131         */
132        TransactionResourceImpl(
133                                                        InternalDriver driver, 
134                                                        String url,
135                                                        Properties info) throws SQLException 
136        {
137                this.driver = driver;
138                csf = driver.getContextServiceFactory();
139                dbname = InternalDriver.getDatabaseName(url, info);
140                this.url = url;
141 
142                // the driver manager will push a user name
143                // into the properties if its getConnection(url, string, string)
144                // interface is used.  Thus, we look there first.
145                // Default to APP.
146                username = IdUtil.getUserNameFromURLProps(info);
147 
148                drdaID = info.getProperty(Attribute.DRDAID_ATTR, null);
149 
150                // make a new context manager for this TransactionResource
151 
152                // note that the Database API requires that the 
153                // getCurrentContextManager call return the context manager
154                // associated with this session.  The JDBC driver assumes
155                // responsibility (for now) for tracking and installing
156                // this context manager for the thread, each time a database
157                // call is made.
158                cm = csf.newContextManager();
159        }
160 
161        /*
162         * Called only in EmbedConnection construtor.
163         * The Local Connection sets up the database in its constructor and sets it
164         * here.
165         */
166        void setDatabase(Database db)
167        {
168                if (SanityManager.DEBUG)
169                        SanityManager.ASSERT(database == null, 
170                                "setting database when it is not null"); 
171 
172                database = db;
173        }
174 
175        /*
176         * Called only in EmbedConnection constructor.  Create a new transaction
177         * by creating a lcc.
178         *
179         * The arguments are not used by this object, it is used by
180         * XATransactionResoruceImpl.  Put them here so that there is only one
181         * routine to start a local connection.
182         */
183        void startTransaction() throws StandardException, SQLException
184        {
185                // setting up local connection
186                lcc = database.setupConnection(cm, username, drdaID, dbname);
187        }
188 
189        /*
190         * Return instance variables to EmbedConnection.  RESOLVE: given time, we
191         * should perhaps stop giving out reference to these things but instead use
192         * the transaction resource itself.
193         */
194        InternalDriver getDriver() {
195                return driver;
196        }
197        ContextService getCsf() {
198                return  csf;
199        }
200 
201        /*
202         * need to be public because it is in the XATransactionResource interface
203         */
204        ContextManager getContextManager() {
205                return  cm;
206        }
207 
208        LanguageConnectionContext getLcc() {
209                return  lcc;
210        }
211        String getDBName() {
212                return  dbname;
213        }
214        String getUrl() {
215                return  url;
216        }
217        Database getDatabase() {
218                return  database;
219        }
220 
221        StandardException shutdownDatabaseException() {
222                StandardException se = StandardException.newException(SQLState.SHUTDOWN_DATABASE, getDBName());
223                se.setReport(StandardException.REPORT_NEVER);
224                return se;
225        }
226 
227        /*
228         * local transaction demarcation - note that global or xa transaction
229         * cannot commit thru the connection, they can only commit thru the
230         * XAResource, which uses the xa_commit or xa_rollback interface as a 
231         * safeguard. 
232         */
233        void commit() throws StandardException
234        {
235                lcc.userCommit();
236        }                
237 
238        void rollback() throws StandardException
239        {
240                // lcc may be null if this is called in close.
241                if (lcc != null)
242                        lcc.userRollback();
243        }
244 
245        /*
246         * context management
247         */
248 
249        /**
250         * An error happens in the constructor, pop the context.
251         */
252        void clearContextInError()
253        {
254                csf.resetCurrentContextManager(cm);
255                cm = null;
256        }
257 
258        /**
259         * Resolve: probably superfluous
260         */
261        void clearLcc()
262        {
263                lcc = null;
264        }
265 
266        final void setupContextStack()
267        {
268                if (SanityManager.DEBUG) {
269                        SanityManager.ASSERT(cm != null, "setting up null context manager stack");
270                }
271 
272                        csf.setCurrentContextManager(cm);
273        }
274 
275        final void restoreContextStack() {
276 
277                if ((csf == null) || (cm == null))
278                        return;
279                csf.resetCurrentContextManager(cm);
280        }
281 
282        /*
283         * exception handling
284         */
285 
286        /*
287         * clean up the error and wrap the real exception in some SQLException.
288         */
289        final SQLException handleException(Throwable thrownException,
290                                                                           boolean autoCommit,        
291                                                                           boolean rollbackOnAutoCommit)
292                        throws SQLException 
293        {
294                try {
295                        if (SanityManager.DEBUG)
296                                SanityManager.ASSERT(thrownException != null);
297 
298                        /*
299                                just pass SQL exceptions right back. We assume that JDBC driver
300                                code has cleaned up sufficiently. Not passing them through would mean
301                                that all cleanupOnError methods would require knowledge of Utils.
302                         */
303                        if (thrownException instanceof SQLException) {
304 
305                                return (SQLException) thrownException;
306 
307                        } 
308 
309                        boolean checkForShutdown = false;
310                        if (thrownException instanceof StandardException)
311                        {
312                                StandardException se = (StandardException) thrownException;
313                                int severity = se.getSeverity();
314                                if (severity <= ExceptionSeverity.STATEMENT_SEVERITY)
315                                {
316                                        /*
317                                        ** If autocommit is on, then do a rollback
318                                        ** to release locks if requested.  We did a stmt 
319                                        ** rollback in the cleanupOnError above, but we still
320                                        ** may hold locks from the stmt.
321                                        */
322                                        if (autoCommit && rollbackOnAutoCommit)
323                                        {
324                                                se.setSeverity(ExceptionSeverity.TRANSACTION_SEVERITY);
325                                        }
326                                } else if (SQLState.CONN_INTERRUPT.equals(se.getMessageId())) {
327                                        // an interrupt closed the connection.
328                                        checkForShutdown = true;
329                                }
330                        }
331                        // if cm is null, we don't have a connection context left,
332                        // it was already removed.  all that's left to cleanup is
333                        // JDBC objects.
334                        if (cm!=null) {
335                                boolean isShutdown = cleanupOnError(thrownException);
336                                if (checkForShutdown && isShutdown) {
337                                        // Change the error message to be a known shutdown.
338                                        thrownException = shutdownDatabaseException();
339                                }
340                        }
341 
342 
343 
344                        return wrapInSQLException((SQLException) null, thrownException);
345 
346                } catch (Throwable t) {
347 
348                        if (cm!=null) { // something to let us cleanup?
349                                cm.cleanupOnError(t);
350                        }
351                        /*
352                           We'd rather throw the Throwable,
353                           but then javac complains...
354                           We assume if we are in this degenerate
355                           case that it is actually a java exception
356                         */
357                        throw wrapInSQLException((SQLException) null, t);
358                        //throw t;
359                }
360 
361        }
362                 
363        public static final SQLException wrapInSQLException(SQLException sqlException, Throwable thrownException) {
364 
365                if (thrownException == null)
366                        return sqlException;
367 
368                SQLException nextSQLException;
369 
370                if (thrownException instanceof SQLException) {
371 
372                        // server side JDBC can end up with a SQLException in the nested stack
373                        nextSQLException = (SQLException) thrownException;
374                }
375                else if (thrownException instanceof StandardException) {
376 
377                        StandardException se = (StandardException) thrownException;
378 
379                        nextSQLException = Util.generateCsSQLException(se);
380 
381                        wrapInSQLException(nextSQLException, se.getNestedException());
382 
383                } else {
384 
385                        nextSQLException = Util.javaException(thrownException);
386 
387                        // special case some java exceptions that have nested exceptions themselves
388                        Throwable nestedByJVM = null;
389                        if (thrownException instanceof ExceptionInInitializerError) {
390                                nestedByJVM = ((ExceptionInInitializerError) thrownException).getException();
391                        } else if (thrownException instanceof java.lang.reflect.InvocationTargetException) {
392                                nestedByJVM = ((java.lang.reflect.InvocationTargetException) thrownException).getTargetException();
393                        }
394 
395                        if (nestedByJVM != null) {
396                                wrapInSQLException(nextSQLException, nestedByJVM);
397                        }
398                        
399                }
400 
401                if (sqlException != null) {
402                        sqlException.setNextException(nextSQLException);
403                }
404 
405                return nextSQLException;
406        }
407 
408        /*
409         * TransactionResource methods
410         */
411 
412        String getUserName() {
413                return  username;
414        }
415 
416        boolean cleanupOnError(Throwable e)
417        {
418                if (SanityManager.DEBUG)
419                        SanityManager.ASSERT(cm != null, "cannot cleanup on error with null context manager");
420 
421                return cm.cleanupOnError(e);
422        }
423 
424        boolean isIdle()
425        {
426                // If no lcc, there is no transaction.
427                return (lcc == null || lcc.getTransactionExecute().isIdle());
428        }
429 
430 
431        /*
432         * class specific methods
433         */
434 
435 
436        /* 
437         * is the underlaying database still active?
438         */
439        boolean isActive()
440        {
441                // database is null at connection open time
442                return (driver.isActive() && ((database == null) || database.isActive()));
443        }
444 
445}
446 
447 

[all classes][org.apache.derby.impl.jdbc]
EMMA 2.0.5312 (C) Vladimir Roubtsov