KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > ejb > cmp3 > transaction > base > TransactionImpl


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2005, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.ejb.cmp3.transaction.base;
23
24 import java.lang.reflect.Proxy JavaDoc;
25 import java.lang.reflect.InvocationHandler JavaDoc;
26 import java.util.Vector JavaDoc;
27 import java.sql.*;
28 import javax.transaction.xa.XAResource JavaDoc;
29 import javax.transaction.*;
30 import oracle.toplink.essentials.exceptions.TransactionException;
31 import oracle.toplink.essentials.internal.ejb.cmp3.base.ExceptionFactory;
32 import oracle.toplink.essentials.internal.ejb.cmp3.jdbc.base.ConnectionProxyHandler;
33 import oracle.toplink.essentials.internal.ejb.cmp3.jdbc.base.DataSourceImpl;
34
35 /**
36  * Implementation of JTA Transaction class. The guts of the tx logic
37  * is contained in this class.
38  *
39  * Currently support is limited to enlisting only a single tx data source
40  */

41 public class TransactionImpl implements Transaction {
42     // Set by client-induced rollback marking
43
boolean markedForRollback;
44
45     // Used to maintain the tx status
46
int status;
47
48     // Collection of Synchronization listeners
49
Vector JavaDoc listeners;
50
51     // The transactional connection we use
52
Connection connection;
53     static Class JavaDoc proxyClass = Proxy.getProxyClass(Connection.class.getClassLoader(), new Class JavaDoc[] { Connection.class });
54
55     // The enlisted data source
56
DataSourceImpl dataSource;
57
58     /***** Static constants *****/
59
60     // Cribbed from java.transaction.Status
61
public static final int STATUS_ACTIVE = 0;
62     public static final int STATUS_MARKED_ROLLBACK = 1;
63     public static final int STATUS_PREPARED = 2;
64     public static final int STATUS_COMMITTED = 3;
65     public static final int STATUS_ROLLEDBACK = 4;
66     public static final int STATUS_UNKNOWN = 5;
67     public static final int STATUS_NO_TRANSACTION = 6;
68     public static final int STATUS_PREPARING = 7;
69     public static final int STATUS_COMMITTING = 8;
70     public static final int STATUS_ROLLING_BACK = 9;
71
72     // Set this to true for debugging of afterCompletion exceptions
73
public static boolean DUMP_AFTER_COMPLETION_ERRORS = true;
74
75     /************************/
76     /***** Internal API *****/
77     /************************/
78     private void debug(String JavaDoc s) {
79         System.out.println(s);
80     }
81
82     /*
83      * Constructor invoked and new instance created on tx begin
84      */

85     public TransactionImpl() {
86         markedForRollback = false;
87         status = STATUS_ACTIVE;
88         listeners = new Vector JavaDoc();
89     }
90
91     /*
92      * Lazily allocate the connection. This will be used
93      * by the data source if in a transaction.
94      */

95     public Connection getConnection(DataSourceImpl ds, String JavaDoc user, String JavaDoc password) throws SQLException {
96         // We don't have a datasource connection yet, so allocate one
97
if (connection == null) {
98             debug("TxImpl - allocating new connection");
99             dataSource = ds;
100             connection = ds.internalGetConnection(user, password);
101             connection.setAutoCommit(false);
102         } else {
103             // We already have a connection. Make sure the data sources are the same.
104
if (ds.getName() != dataSource.getName()) {
105                 throw TransactionException.multipleResourceException();
106             }
107         }
108
109         // return connection;
110
// Allocate and return a proxy for the connection
111
debug("TxImpl - creating connection proxy");
112         Connection proxyConnection = null;
113         try {
114             InvocationHandler JavaDoc handler = new ConnectionProxyHandler(connection);
115             proxyConnection = (Connection)proxyClass.getConstructor(new Class JavaDoc[] { InvocationHandler JavaDoc.class }).newInstance(new Object JavaDoc[] { handler });
116         } catch (Exception JavaDoc ex) {
117             throw TransactionException.internalProxyException(ex);
118         }
119         return proxyConnection;
120     }
121
122     /*
123      * Invoke afterCompletion callbacks.
124      * If DUMP_AFTER_COMPLETION_ERRORS flag is set then dump
125      * the exceptions to System.out, otherwise swallow them.
126      *
127      * NOTE: In either case it will not affect the outcome
128      * of the transaction.
129      */

130     public void invokeAfterCompletion() {
131         // Call all of the afterCompletion callbacks
132
debug("TxImpl - invoking afterCompletion");
133         int i;
134         int j;
135         for (i = 0, j = listeners.size(); i < j; i++) {
136             try {
137                 ((Synchronization)listeners.elementAt(i)).afterCompletion(status);
138             } catch (Throwable JavaDoc t) {
139                 if (DUMP_AFTER_COMPLETION_ERRORS) {
140                     t.printStackTrace(System.out);
141                 }
142             }
143         }
144     }
145
146     /*
147      * Rollback the transaction on the connection.
148      */

149     public void rollbackConnection() throws SQLException {
150         if (connection != null) {
151             debug("TxImpl - rolling back connection");
152             status = STATUS_ROLLING_BACK;
153             connection.rollback();
154             status = STATUS_ROLLEDBACK;
155         }
156     }
157
158     /*
159      * Commit the transaction on the connection.
160      */

161     public void commitConnection() throws SQLException {
162         if (connection != null) {
163             debug("TxImpl - committing connection");
164             status = STATUS_COMMITTING;
165             connection.commit();
166             status = STATUS_COMMITTED;
167         }
168     }
169
170     /*
171      * Clean up after everything is over
172      */

173     public void cleanup() {
174         debug("TxImpl - cleanup");
175         if (connection != null) {
176             try {
177                 connection.close();
178             } catch (Exception JavaDoc ex) {
179             }
180
181             // Ignore
182
connection = null;
183         }
184         status = STATUS_NO_TRANSACTION;
185     }
186
187     /*************************************/
188     /***** Supported Transaction API *****/
189     /*************************************/
190     public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException JavaDoc, IllegalStateException JavaDoc, SystemException {
191         Exception JavaDoc error = null;
192
193         debug("TxImpl - commit");
194         // Make sure we are allowed to proceed
195
switch (status) {
196         case STATUS_ACTIVE:// This is the normal case - do nothing
197
break;
198         case STATUS_MARKED_ROLLBACK: {
199             // Tx was marked for rollback by the user, error
200
error = new ExceptionFactory().txMarkedForRollbackException();
201             break;
202         }
203         default:// Tx in some other state, error
204
throw new ExceptionFactory().invalidStateException(status);
205         }
206
207         // Call beforeCompletion callback.
208
if (error == null) {
209             try {
210                 debug("TxImpl - invoking beforeCompletion");
211                 int i;
212                 int j;
213                 for (i = 0, j = listeners.size(); i < j; i++) {
214                     ((Synchronization)listeners.elementAt(i)).beforeCompletion();
215                 }
216             } catch (Exception JavaDoc ex) {
217                 error = ex;
218                 status = STATUS_ROLLING_BACK;
219                 debug("TxImpl - error in beforeCompletion: " + ex);
220             }
221         }
222
223         // Now if we didn't get any errors then commit the connection
224
if ((error == null) && (status == STATUS_ACTIVE)) {
225             try {
226                 commitConnection();
227             } catch (Exception JavaDoc ex) {
228                 error = ex;
229             }
230         } else {
231             try {
232                 rollbackConnection();
233             } catch (Exception JavaDoc ex) {
234                 error = ex;
235             }
236         }
237
238         // Whether we were successful or not, call afterCompletion and clean up
239
invokeAfterCompletion();
240         cleanup();
241
242         // Throw any error that may have occurred at any point in the commit
243
if (error != null) {
244             throw new ExceptionFactory().newSystemException(error);
245         }
246     }
247
248     public int getStatus() throws SystemException {
249         return status;
250     }
251
252     public void registerSynchronization(Synchronization synchronization) throws RollbackException, IllegalStateException JavaDoc, SystemException {
253         debug("TxImpl - registering sync listener: " + synchronization);
254         listeners.add(synchronization);
255     }
256
257     public void rollback() throws IllegalStateException JavaDoc, SystemException {
258         Exception JavaDoc error = null;
259
260         debug("TxImpl - rollback");
261         try {
262             rollbackConnection();
263         } catch (Exception JavaDoc ex) {
264             error = ex;
265         }
266
267         // Call afterCompletion callback and clean up
268
invokeAfterCompletion();
269         cleanup();
270
271         // Throw any error that may have occurred while rolling back
272
if (error != null) {
273             throw new ExceptionFactory().newSystemException(error);
274         }
275     }
276
277     public void setRollbackOnly() throws IllegalStateException JavaDoc, SystemException {
278         debug("TxImpl - setRollbackOnly");
279         status = STATUS_MARKED_ROLLBACK;
280     }
281
282     /*****************************************/
283     /***** NOT supported Transaction API *****/
284     /*****************************************/
285     public boolean enlistResource(XAResource JavaDoc xaresource) throws RollbackException, IllegalStateException JavaDoc, SystemException {
286         return false;
287     }
288
289     public boolean delistResource(XAResource JavaDoc xaresource, int i) throws IllegalStateException JavaDoc, SystemException {
290         return false;
291     }
292 }
293
Popular Tags