KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > jdbc > standard > StandardConnectionHandle


1 /*
2  * XAPool: Open Source XA JDBC Pool
3  * Copyright (C) 2003 Objectweb.org
4  * Initial Developer: Lutris Technologies Inc.
5  * Contact: xapool-public@lists.debian-sf.objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20  * USA
21  */

22 package org.enhydra.jdbc.standard;
23
24 import java.sql.CallableStatement JavaDoc;
25 import java.sql.PreparedStatement JavaDoc;
26 import java.sql.SQLException JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.Hashtable JavaDoc;
29 import java.sql.Connection JavaDoc;
30 import org.enhydra.jdbc.core.CoreConnection;
31 import org.enhydra.jdbc.util.LRUCache;
32
33 /**
34  * This is an implementation of java.sql.Connection which simply
35  * delegates almost everything to an underlying physical implemention
36  * of the same interface.
37  *
38  * It relies on a StandardPooledConnection to create it and to supply the
39  * physical connection and a cache of PreparedStatements. This class will
40  * try to re-use PreparedStatements wherever possible and will add to the
41  * cache when totally new PreparedStatements get created.
42  */

43 public class StandardConnectionHandle extends CoreConnection {
44
45     StandardPooledConnection pooledCon;
46     // the pooled connection that created this object
47
protected Hashtable JavaDoc masterPrepStmtCache;
48     // the hashtable of caches, indexed by physical connection
49
int preparedStmtCacheSize; // the size of the connection-specific cache
50
protected LRUCache preparedStatementCache = null;
51     // prepared statements indexed by SQL string
52
public Hashtable JavaDoc inUse; // prepared statements that are currently in use
53
private boolean closed; // set true when this connection has been closed
54
public boolean isReallyUsed = false;
55
56     /**
57      * Constructor.
58      */

59     public StandardConnectionHandle(
60         StandardPooledConnection pooledCon,
61         Hashtable JavaDoc preparedStatementCache,
62         int preparedStmtCacheSize) {
63         super(pooledCon.getPhysicalConnection()); // get the real connection
64
this.pooledCon = pooledCon; // first save parameters
65
masterPrepStmtCache = preparedStatementCache;
66         this.preparedStmtCacheSize = preparedStmtCacheSize;
67         log = pooledCon.dataSource.log;
68         setupPreparedStatementCache();
69         inUse = new Hashtable JavaDoc(10, 0.5f);
70
71         log.debug(
72             "StandardConnectionHandle:new StandardConnectionHandle with "
73                 + preparedStmtCacheSize
74                 + " prepared statement");
75     }
76
77     protected void setupPreparedStatementCache() {
78         log.debug("StandardConnectionHandle:setupPreparedStatementCache start");
79         if (preparedStmtCacheSize == 0) {
80             log.debug(
81                 "StandardConnectionHandle:setupPreparedStatementCache return with 0");
82             preparedStatementCache = null;
83             return;
84         }
85         if (con == null)
86             log.warn("Connection is null");
87         else {
88             preparedStatementCache =
89                 (LRUCache) masterPrepStmtCache.get(con.toString());
90             if (preparedStatementCache == null) {
91                 preparedStatementCache =
92                     new PreparedStatementCache(preparedStmtCacheSize);
93                 preparedStatementCache.setLogger(log);
94                 masterPrepStmtCache.put(con.toString(), preparedStatementCache);
95                 log.debug(
96                     "StandardConnectionHandle:setupPreparedStatementCache "
97                         + "preparedStatementCache.size(lru)='"
98                         + preparedStatementCache.LRUSize()
99                         + "' "
100                         + "preparedStatementCache.size(cache)='"
101                         + preparedStatementCache.cacheSize()
102                         + "' "
103                         + "masterPrepStmtCache.size='"
104                         + masterPrepStmtCache.size()
105                         + "' ");
106             } else preparedStatementCache.setLogger(log);
107         }
108         log.debug("StandardConnectionHandle:setupPreparedStatementCache end");
109     }
110
111     /**
112      * Pre-invokation of the delegation, in case of connection is
113      * closed, we throw an exception
114      */

115     public void preInvoke() throws SQLException JavaDoc {
116         if (closed)
117             throw new SQLException JavaDoc("Connection is closed");
118     }
119
120     /**
121      * Exception management : catch or throw the exception
122      */

123     public void catchInvoke(SQLException JavaDoc e) throws SQLException JavaDoc {
124         //ConnectionEvent event = new ConnectionEvent (pooledCon);// create event associate with the connection
125
//pooledCon.connectionErrorOccurred(event); // ppoled have to be closed
126
throw (e); // throw the exception
127
}
128
129     /**
130      * Closes this StandardConnectionHandle and prevents it
131      * from being reused. It also returns used PreparedStatements
132      * to the PreparedStatement cache and notifies all listeners.
133      */

134     synchronized public void close() throws SQLException JavaDoc {
135         log.debug("StandardConnectionHandle:close");
136         // Note - we don't check to see if already closed. Some servers get confused.
137
closed = true; // connection now closed
138
Enumeration JavaDoc keys = inUse.keys(); // get any prepared statements in use
139
while (keys.hasMoreElements()) { // while more prepared statements used
140
Object JavaDoc key = keys.nextElement(); // get next key
141
returnToCache(key); // return prepared statement to cache
142
}
143         pooledCon.closeEvent(); // notify listeners
144

145                 if (preparedStatementCache != null)
146                 preparedStatementCache.cleanupAll();
147                 if ((preparedStatementCache != null) && (masterPrepStmtCache != null) && (log != null))
148         log.debug(
149             "StandardConnectionHandle:close "
150                 + "preparedStatementCache.size(lru)='"
151                 + preparedStatementCache.LRUSize()
152                 + "' "
153                 + "preparedStatementCache.size(cache)='"
154                 + preparedStatementCache.cacheSize()
155                 + "' "
156                 + "masterPrepStmtCache.size='"
157                 + masterPrepStmtCache.size()
158                 + "' ");
159     }
160
161     /**
162      * Removes a prepared statement from the inUse list
163      * and returns it to the cache.
164      */

165     void returnToCache(Object JavaDoc key, Connection JavaDoc theCon) {
166         Object JavaDoc value = inUse.remove(key);
167         // remove key/value from used statements
168
if (value != null) {
169             LRUCache theCache =
170                 (LRUCache) masterPrepStmtCache.get(theCon.toString());
171             theCache.put(key, value); // place back in cache, ready for re-use
172
}
173     }
174
175     void returnToCache(Object JavaDoc key) {
176         returnToCache(key, con);
177     }
178
179     /**
180      * Checks to see if a prepared statement with the same concurrency
181      * has already been created. If not, then a new prepared statement
182      * is created and added to the cache.
183      *
184      * If a prepared statement is found in the cache then it is removed
185      * from the cache and placed on the "inUse" list. This ensures that
186      * if multiple threads use the same StandardConnectionHandle, or a single
187      * thread does multiple prepares using the same SQL, then DIFFERENT
188      * prepared statements will be returned.
189      */

190     synchronized PreparedStatement JavaDoc checkPreparedCache(
191         String JavaDoc sql,
192         int type,
193         int concurrency,
194         int holdability)
195         throws SQLException JavaDoc {
196         log.debug(
197             "StandardConnectionHandle:checkPreparedCache sql='" + sql + "'");
198         PreparedStatement JavaDoc ret = null; // the return value
199
// NOTE - We include the Connection in the lookup key. This has no
200
// effect here but is needed by StandardXAConnection where the the physical
201
// Connection used can vary over time depending on the global transaction.
202
String JavaDoc lookupKey = sql + type + concurrency;
203         // used to lookup statements
204
if (preparedStatementCache != null) {
205             Object JavaDoc obj = preparedStatementCache.get(lookupKey);
206             // see if there's a PreparedStatement already
207
if (obj != null) { // if there is
208
ret = (PreparedStatement JavaDoc) obj; // use as return value
209
try {
210                     ret.clearParameters(); // make it look like new
211
} catch (SQLException JavaDoc e) {
212                     // Bad statement, so we have to create a new one
213
ret = createPreparedStatement(sql, type, concurrency, holdability);
214                 }
215
216                 preparedStatementCache.remove(lookupKey);
217                 // make sure it cannot be re-used
218
inUse.put(lookupKey, ret);
219                 // make sure it gets reused by later delegates
220
} else { // no PreparedStatement ready
221
ret = createPreparedStatement(sql, type, concurrency, holdability);
222                 inUse.put(lookupKey, ret);
223                 // will get saved in prepared statement cache
224
}
225         } else {
226             ret = createPreparedStatement(sql, type, concurrency, holdability);
227         }
228         // We don't actually give the application a real PreparedStatement. Instead
229
// they get a StandardPreparedStatement that delegates everything except
230
// PreparedStatement.close();
231

232         ret = new StandardPreparedStatement(this, ret, lookupKey);
233         return ret;
234     }
235
236
237     synchronized PreparedStatement JavaDoc checkPreparedCache(
238         String JavaDoc sql,
239         int autogeneratedkeys)
240         throws SQLException JavaDoc {
241         log.debug(
242             "StandardConnectionHandle:checkPreparedCache sql='" + sql + "'");
243         PreparedStatement JavaDoc ret = null; // the return value
244
// NOTE - We include the Connection in the lookup key. This has no
245
// effect here but is needed by StandardXAConnection where the the physical
246
// Connection used can vary over time depending on the global transaction.
247
String JavaDoc lookupKey = sql + autogeneratedkeys;
248         // used to lookup statements
249
if (preparedStatementCache != null) {
250             Object JavaDoc obj = preparedStatementCache.get(lookupKey);
251             // see if there's a PreparedStatement already
252
if (obj != null) { // if there is
253
ret = (PreparedStatement JavaDoc) obj; // use as return value
254
try {
255                     ret.clearParameters(); // make it look like new
256
} catch (SQLException JavaDoc e) {
257                     // Bad statement, so we have to create a new one
258
ret = createPreparedStatement(sql, autogeneratedkeys);
259                 }
260
261                 preparedStatementCache.remove(lookupKey);
262                 // make sure it cannot be re-used
263
inUse.put(lookupKey, ret);
264                 // make sure it gets reused by later delegates
265
} else { // no PreparedStatement ready
266
ret = createPreparedStatement(sql, autogeneratedkeys);
267                 inUse.put(lookupKey, ret);
268                 // will get saved in prepared statement cache
269
}
270         } else {
271             ret = createPreparedStatement(sql, autogeneratedkeys);
272         }
273         // We don't actually give the application a real PreparedStatement. Instead
274
// they get a StandardPreparedStatement that delegates everything except
275
// PreparedStatement.close();
276

277         ret = new StandardPreparedStatement(this, ret, lookupKey);
278         return ret;
279     }
280
281
282
283     protected PreparedStatement JavaDoc createPreparedStatement(
284         String JavaDoc sql,
285         int type,
286         int concurrency,
287         int holdability)
288         throws SQLException JavaDoc {
289         log.debug(
290             "StandardConnectionHandle:createPreparedStatement type ='"
291                 + type
292                 + "'");
293         if (type == 0 && holdability == 0) { // if no type or concurrency specified
294
return con.prepareStatement(sql); // create new prepared statement
295
} else if (holdability == 0) {
296             return con.prepareStatement(sql, type, concurrency);
297             // create new prepared statement
298
} else return con.prepareStatement(sql, type, concurrency, holdability);
299     }
300
301
302     protected PreparedStatement JavaDoc createPreparedStatement(
303         String JavaDoc sql,
304         int autogeneratedkeys)
305         throws SQLException JavaDoc {
306         log.debug(
307             "StandardConnectionHandle:createPreparedStatement autogeneratedkeys ='"
308                 + autogeneratedkeys
309                 + "'");
310         return con.prepareStatement(sql, autogeneratedkeys); // create new prepared statement
311
}
312
313     /**
314      * Creates a PreparedStatement for the given SQL. If possible, the
315      * statement is fetched from the cache.
316      */

317     public PreparedStatement JavaDoc prepareStatement(String JavaDoc sql) throws SQLException JavaDoc {
318         log.debug(
319             "StandardConnectionHandle:prepareStatement sql='" + sql + "'");
320         preInvoke();
321         try {
322             return checkPreparedCache(sql, 0, 0, 0);
323         } catch (SQLException JavaDoc e) {
324             catchInvoke(e);
325         }
326         return null;
327     }
328
329     /**
330      * Creates a PreparedStatement for the given SQL, type and concurrency.
331      * If possible, the statement is fetched from the cache.
332      */

333     public PreparedStatement JavaDoc prepareStatement(
334         String JavaDoc sql,
335         int resultSetType,
336         int resultSetConcurrency)
337         throws SQLException JavaDoc {
338         preInvoke();
339         try {
340             return checkPreparedCache(sql, resultSetType, resultSetConcurrency, 0);
341         } catch (SQLException JavaDoc e) {
342             catchInvoke(e);
343         }
344         return null;
345     }
346
347     public PreparedStatement JavaDoc prepareStatement(
348         String JavaDoc sql,
349         int resultSetType,
350         int resultSetConcurrency,
351         int resultSetHoldability)
352         throws SQLException JavaDoc {
353         preInvoke();
354         try {
355             return checkPreparedCache(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
356         } catch (SQLException JavaDoc e) {
357             catchInvoke(e);
358         }
359         return null;
360     }
361
362     public boolean isClosed() throws SQLException JavaDoc {
363         return closed;
364     }
365
366     public CallableStatement JavaDoc prepareCall(
367         String JavaDoc sql,
368         int resultSetType,
369         int resultSetConcurrency)
370         throws SQLException JavaDoc {
371         preInvoke();
372         try {
373             return con.prepareCall(sql, resultSetType, resultSetConcurrency);
374         } catch (SQLException JavaDoc e) {
375             catchInvoke(e);
376         }
377         return null;
378     }
379 }
380
Popular Tags