KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > db > DBTransaction


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64
65 package com.jcorporate.expresso.core.db;
66
67 import com.jcorporate.expresso.core.misc.StringUtil;
68 import org.apache.log4j.Logger;
69
70
71 /**
72  * Generic database transaction object - hides the implementation
73  * details of using jdbc and allows for JDBC message and exceptions to be
74  * handled better than by default.
75  * DBTransaction are also designed to be used in conjunction with connection
76  * pooling, and have special methods to support this.
77  *
78  * @author Yves Henri AMAIZO
79  */

80 public class DBTransaction {
81
82     /**
83      * Constant name for the 'Default' database context
84      */

85     public static final String JavaDoc DEFAULT_DB_CONTEXT_NAME = "default";
86
87     /**
88      * Every connection handled by the pool gets an ID number assigned
89      */

90     private int transactionId = 0;
91
92     /**
93      * last operation
94      */

95     private int lastCommited = 0;
96
97     /**
98      * Description of this connection
99      */

100     private String JavaDoc myDescription = "no description";
101
102     /**
103      * The current data context
104      */

105     private String JavaDoc dbName = DEFAULT_DB_CONTEXT_NAME;
106
107     /**
108      * Is this connection object actually connected to the database yet?
109      */

110     private boolean isConnected = false;
111
112     /**
113      * DB connection pool object
114      */

115     private DBConnectionPool myPool;
116
117     /**
118      * DB connection object
119      */

120     private DBConnection myConnection;
121
122     /**
123      * constant name to help with debugging
124      */

125     private static final String JavaDoc THIS_CLASS = DBTransaction.class.getName() + ".";
126
127     /**
128      * Time that the DBConnection was created.
129      */

130     private long createdTime = System.currentTimeMillis();
131
132     /**
133      * The main Transaction Log
134      */

135     private static Logger transLog = Logger.getLogger("com.jcorporate.expresso.core.db.TRANSACTION");
136
137     /**
138      * The SQL Log Set this category to debug
139      * to see a trace of all sql statements
140      * issued against the main database
141      */

142     private static Logger log = Logger.getLogger(DBTransaction.class);
143
144     /**
145      * Constructor
146      * Create a new connection object
147      *
148      * @param pool The identified transaction pool
149      * connection
150      * @throws DBException If the information provided cannot be used to
151      * create a new connection
152      */

153     public DBTransaction() throws DBException {
154         transactionSetup(DEFAULT_DB_CONTEXT_NAME);
155     }
156
157
158     /**
159      * Constructor
160      * Create a new connection object
161      *
162      * @param pool The identified transaction pool
163      * connection
164      * @throws DBException If the information provided cannot be used to
165      * create a new connection
166      */

167     public DBTransaction(DBConnectionPool pool) throws DBException {
168         myPool = pool;
169         dbName = myPool.getDataContext();
170     }
171
172
173     /**
174      * Constructor
175      * Create a new connection object
176      *
177      * @param transactionDataContext The transaction data context
178      * connection
179      * @throws DBException If the information provided cannot be used to
180      * create a new connection
181      */

182     public DBTransaction(String JavaDoc transactionDataContext) throws DBException {
183         transactionSetup(transactionDataContext);
184     }
185
186
187     /**
188      * Sets up the transaction operation on an identitied DBConnectionPool
189      *
190      * @param transactionDataContext The transaction data context name
191      * for more information on what this paramter means.
192      */

193     private void transactionSetup(String JavaDoc transactionDataContext) throws DBException {
194         String JavaDoc myName = (THIS_CLASS + "transactionSetup()");
195         try {
196             myPool = DBConnectionPool.getInstance(transactionDataContext);
197             dbName = transactionDataContext;
198         } catch (DBException e) {
199             myPool = null;
200             log.error(myName + "DBException : initialize pool for transaction failed!", e);
201         }
202     } /* transactionSetup(String) */
203
204
205     /**
206      * Sets up the transaction operation on an identitied DBConnectionPool
207      *
208      * @param transactionDataContext The transaction data context name
209      * for more information on what this paramter means.
210      */

211     public void startTransaction() throws DBException {
212         startTransaction(true);
213     }
214
215     /**
216      * Sets up the transaction operation on an identitied DBConnectionPool
217      *
218      * @param transactionDataContext The transaction data context name
219      * for more information on what this paramter means.
220      */

221     public void startTransaction(boolean immortal) throws DBException {
222         String JavaDoc myName = (THIS_CLASS + "startTransaction()");
223
224         try {
225             if (!isConnected) {
226                 if (myPool != null) {
227                     myConnection = myPool.getConnection(getDataContext());
228                     myConnection.setImmortal(immortal);
229                     myConnection.setAutoCommit(false);
230                     isConnected = true;
231                     setId(myConnection.getId());
232                     lastCommited = 0;
233                 } else {
234                     return;
235                 }
236             }
237             lastCommited++;
238             if (transLog.isDebugEnabled()) {
239                 transLog.debug(myName + " Transaction " + myConnection.getId() + " Starting:'" +
240                         "' on db '" + getDataContext() + "'");
241             }
242         } catch (DBException e) {
243             log.error(myName + "DBException : initialize transaction failed!", e);
244             if (myConnection != null) {
245                 close();
246             }
247         }
248     } /* transactionSetup(String) */
249
250     /**
251      * Clear all result sets and statements associated with this connection
252      */

253     public void clear() throws DBException {
254         if (myConnection != null) {
255             rollback();
256         }
257     } /* clear() */
258
259
260     /**
261      * Send a COMMIT to the database, closing the current transaction If the
262      * database driver claims it doesn't support transactions, then we skip
263      * this.
264      *
265      * @throws DBException If the commit does not succeed
266      */

267     public void commit() throws DBException {
268         String JavaDoc myName = (THIS_CLASS + "commit()");
269         try {
270 // if (lastCommited == 1) {
271
if (!myConnection.isClosed()) {
272                 myConnection.commit();
273                 if (log.isDebugEnabled()) {
274                     log.debug(myName + " Transaction " + myConnection.getId() + " Commited:'" +
275                             "' on db '" + getDataContext() + "'");
276                 }
277                 close();
278             }
279 // } else {
280
// lastCommited--;
281
// }
282

283         } catch (DBException se) {
284             close();
285             throw new DBException(myName + ":Could not commit (" +
286                     myDescription + ")", se.getMessage());
287         }
288     } /* commit() */
289
290     /**
291      * Clear all result sets and statements associated with this connection
292      */

293     private void close() throws DBException {
294         String JavaDoc myName = (THIS_CLASS + "close()");
295         myConnection.setImmortal(false);
296         if (log.isDebugEnabled()) {
297             log.debug(myName + " Transaction " + myConnection.getId() + " Closed:'" +
298                     "' on db '" + getDataContext() + "'");
299         }
300         myPool.release(myConnection);
301         myConnection = null;
302         myPool = null;
303         setId(0);
304         dbName = "";
305         isConnected = false;
306         lastCommited = -1;
307     } /* close() */
308
309
310     /**
311      * <p/>
312      * Low level function that allows you to retrieve the JDBC connection associated
313      * with this DBConnection. This allows you to do several fancy things that would
314      * not normally happen within Expresso itself such as prepared statements, and
315      * other low level entities. </p>
316      * <p/>
317      * <b>NOTE:</b> Once you grab the connection yourself, you are on your own
318      * as far as the framework is concerned. It doesn't help you to get your
319      * connection back in place. So, for example, if you close the connection manually,
320      * it will mess up the connection pool. Or if you fail to free a prepared statement,
321      * it will register as a resource leak. Be sure to restore your connection to
322      * pristine order before releasing this DBConnection back into the pool.
323      * </p>
324      *
325      * @return a java.sql.Connection JDBC connection.
326      */

327     public DBConnection getTransactionConnection() {
328         if (myConnection == null) {
329             return null;
330         }
331         return myConnection;
332     }
333
334     /**
335      * Returns the text description of this connection. When the connection
336      * is put in use by a client program a description is set, this method
337      * retrieves the description.
338      *
339      * @return String A text description of this database connection's purpose
340      */

341     public String JavaDoc getDescription() {
342         return myDescription;
343     } /* getDescription() */
344
345     /**
346      * When this connection has lost its connection to the server,
347      * tell whether or not it is available to be re-allocated
348      *
349      * @return boolean True if the connection has been lost,
350      * false if it is still usable
351      */

352     public boolean isClosed()
353             throws DBException {
354         String JavaDoc myName = (THIS_CLASS + "isClosed()");
355
356         try {
357             return myConnection.isClosed();
358         } catch (DBException se) {
359             throw new DBException(myName + "isClosed()" + ":Cannot access connection to " +
360                     "database via (driver or JNDI) '" + myConnection.getDBDriver() +
361                     "' and URL '" + myConnection.getDBURL() + "' (" +
362                     myDescription + ")", se.getMessage());
363         }
364     } /* isClosed() */
365
366
367     /**
368      * When this connection has lost its connection to the server,
369      * tell whether or not it is available to be re-allocated
370      *
371      * @return boolean True if the connection has been lost,
372      * false if it is still usable
373      */

374     public boolean isConnected() {
375         return isConnected;
376     } /* boolean() */
377
378
379     /**
380      * Roll back the current transaction, as if it were never requested. If
381      * the JDBC driver claims it doesn't support transactions, then this
382      * method is a NOOP except for touching the connection
383      *
384      * @throws DBException If the rollback encounters an error
385      */

386     public void rollback() throws DBException {
387         String JavaDoc myName = (THIS_CLASS + "rollback()");
388         try {
389             if (!myConnection.isClosed()) {
390                 myConnection.rollback();
391                 if (log.isDebugEnabled()) {
392                     log.debug(myName + " Transaction " + myConnection.getId() + " Rollback:'" +
393                             "' on db '" + getDataContext() + "'");
394                 }
395                 close();
396             }
397         } catch (DBException se) {
398             close();
399             throw new DBException(myName + " Transaction" + ":Could not rollback" + " (" +
400                     myDescription + ")", se.getMessage());
401         }
402     } /* rollback() */
403
404
405     /**
406      * Set a description for this database connection. When status is requested
407      * from the connection pool, this is used to describe the connection.
408      * Any client requesting a connection from the pool should set the
409      * description of the connection as soon as it's returned
410      *
411      * @param newDescription Description of this connection
412      */

413     public void setDescription(String JavaDoc newDescription) {
414         if (newDescription != null) {
415             myDescription = newDescription;
416         }
417
418     } /* setDescription(String) */
419
420     /**
421      * Sets the data context for the connection.
422      *
423      * @param newDBName the datacontext name to use
424      */

425     public void setDataContext(String JavaDoc newDBName) {
426         if (StringUtil.notNull(newDBName).length() == 0) {
427             dbName = DEFAULT_DB_CONTEXT_NAME;
428         } else {
429             dbName = newDBName;
430         }
431     }
432
433     /**
434      * Retrieve the data context name we're associated with
435      *
436      * @return java.lang.String of the current data Context
437      */

438     public String JavaDoc getDataContext() {
439         return dbName;
440     }
441
442     /**
443      * <p>Releases the DBConnection back into the parent DBConnectionPool. Allows
444      * for syntax like:</p>
445      * <code>
446      * <p/>
447      * DBConnection connection = DBConnectionPool.getInstance("default").getConnection(); <br/>
448      * [do stuff]<br />
449      * connection.release(); <br />
450      * </code>
451      * </p>
452      */

453     public void release() throws DBException {
454         String JavaDoc myName = (THIS_CLASS + "release()");
455         if (myConnection != null) {
456             myConnection.setImmortal(false);
457             if (log.isDebugEnabled()) {
458                 log.debug(myName + " Transaction " + myConnection.getId() + " Released:'" +
459                         "' on db '" + getDataContext() + "'");
460             }
461             myPool.release(myConnection);
462             myConnection = null;
463             myPool = null;
464         } else {
465             log.warn(myName + "No parent connection pool defined for this DBConnection");
466         }
467
468     } /* release () */
469
470     /**
471      * @return
472      */

473     public DBConnectionPool getPool() {
474         return myPool;
475     }
476
477     /**
478      * @param pool
479      */

480     public void setPool(DBConnectionPool pool) {
481         myPool = pool;
482     }
483
484     /**
485      * Set EXPRESSO transaction mode for the current DBConnection.
486      * <p/>
487      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
488      *
489      * @since Expresso 5.3
490      */

491     public void setTransactionReadOnlyMode() throws DBException {
492         String JavaDoc myName = (THIS_CLASS + "setTransactionReadOnlyMode()");
493
494         try {
495             myConnection.setTransactionCommittedMode();
496         } catch (DBException se) {
497             throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Committed Mode :'" +
498                     "' on db '" + getDataContext() + "'" + se);
499         }
500     }
501
502     /**
503      * Set EXPRESSO transaction mode for the current DBConnection.
504      * <p/>
505      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
506      *
507      * @since Expresso 5.3
508      */

509     public void setTransactionDirtyMode() throws DBException {
510         String JavaDoc myName = (THIS_CLASS + "setTransactionDirtyMode()");
511
512         try {
513             myConnection.setTransactionUncommittedMode();
514         } catch (DBException se) {
515             throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Uncommitted Mode :'" +
516                     "' on db '" + getDataContext() + "'" + se);
517         }
518     }
519
520     /**
521      * Set EXPRESSO transaction mode for the current DBConnection.
522      * <p/>
523      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
524      *
525      * @since Expresso 5.3
526      */

527     public void setTransactionRestrictiveMode() throws DBException {
528         String JavaDoc myName = (THIS_CLASS + "setTransactionExclusiveMode()");
529
530         try {
531             myConnection.setTransactionRepeatableMode();
532         } catch (DBException se) {
533             throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Repeatable Mode :'" +
534                     "' on db '" + getDataContext() + "'" + se);
535         }
536     }
537
538     /**
539      * Set EXPRESSO transaction mode for the current DBConnection.
540      * <p/>
541      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
542      *
543      * @since Expresso 5.3
544      */

545     public void setTransactionExclusiveMode() throws DBException {
546         String JavaDoc myName = (THIS_CLASS + "setTransactionExclusiveMode()");
547
548         try {
549             myConnection.setTransactionSerializableMode();
550         } catch (DBException se) {
551             throw new DBException(myName + " Transaction " + myDescription + "." + myConnection.getId() + " Transaction Serialisable Mode :'" +
552                     "' on db '" + getDataContext() + "'" + se);
553         }
554     }
555
556     /**
557      * Get transaction id
558      *
559      * @return int
560      * <p/>
561      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
562      * @since Expresso 5.3
563      */

564     public int getId() {
565         return transactionId;
566     }
567
568     /**
569      * Set transaction id
570      *
571      * @param newTransactionID
572      */

573     private void setId(int newTransactionID) {
574         transactionId = newTransactionID;
575     }
576
577     /**
578      * Get transaction identifier which is myDescription + transactionId
579      *
580      * @return String
581      * <p/>
582      * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
583      * @since Expresso 5.3
584      */

585     public String JavaDoc getTransactionIdentifier() {
586         return myDescription + "." + Integer.toString(transactionId);
587     }
588
589
590 }
591
592 /* DBTransaction */
Popular Tags