KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > proxool > AbstractProxyConnection


1 /*
2  * This software is released under a licence similar to the Apache Software Licence.
3  * See org.logicalcobwebs.proxool.package.html for details.
4  * The latest version is available at http://proxool.sourceforge.net
5  */

6 package org.logicalcobwebs.proxool;
7
8 import org.logicalcobwebs.concurrent.WriterPreferenceReadWriteLock;
9 import org.logicalcobwebs.logging.Log;
10 import org.logicalcobwebs.logging.LogFactory;
11
12 import java.sql.Connection JavaDoc;
13 import java.sql.DatabaseMetaData JavaDoc;
14 import java.sql.SQLException JavaDoc;
15 import java.sql.Statement JavaDoc;
16 import java.text.DecimalFormat JavaDoc;
17 import java.util.Date JavaDoc;
18 import java.util.HashSet JavaDoc;
19 import java.util.Set JavaDoc;
20
21 /**
22  * Contains most of the functionality that we require to manipilate the
23  * connection. The subclass of this defines how we delegate to the
24  * real connection.
25  *
26  * @version $Revision: 1.23 $, $Date: 2003/10/30 00:05:49 $
27  * @author bill
28  * @author $Author: billhorsman $ (current maintainer)
29  * @since Proxool 0.7
30  */

31 abstract class AbstractProxyConnection implements ProxyConnectionIF {
32
33     static final int STATUS_FORCE = -1;
34
35     private WriterPreferenceReadWriteLock statusReadWriteLock = new WriterPreferenceReadWriteLock();
36
37     private static final Log LOG = LogFactory.getLog(AbstractProxyConnection.class);
38
39     private Connection JavaDoc connection;
40
41     private String JavaDoc delegateUrl;
42
43     private int mark;
44
45     private String JavaDoc reasonForMark;
46
47     private int status;
48
49     private long id;
50
51     private Date JavaDoc birthDate;
52
53     private long timeLastStartActive;
54
55     private long timeLastStopActive;
56
57     private ConnectionPool connectionPool;
58
59     private String JavaDoc requester;
60
61     private Set JavaDoc openStatements = new HashSet JavaDoc();
62
63     private DecimalFormat JavaDoc idFormat = new DecimalFormat JavaDoc("0000");
64
65     /**
66      * Whether we have invoked a method that requires us to reset
67      */

68     private boolean needToReset = false;
69
70     protected AbstractProxyConnection(Connection JavaDoc connection, long id, String JavaDoc delegateUrl, ConnectionPool connectionPool, int status) throws SQLException JavaDoc {
71         this.connection = connection;
72         this.delegateUrl = delegateUrl;
73         setId(id);
74         this.connectionPool = connectionPool;
75         setBirthTime(System.currentTimeMillis());
76
77         this.status = status;
78         if (status == STATUS_ACTIVE) {
79             setTimeLastStartActive(System.currentTimeMillis());
80         }
81
82         // We only need to call this for the first connection we make. But it returns really
83
// quickly and we don't call it that often so we shouldn't worry.
84
connectionPool.initialiseConnectionResetter(connection);
85
86         if (connection == null) {
87             throw new SQLException JavaDoc("Unable to create new connection");
88         }
89     }
90
91     /**
92      * Whether the underlying connections are equal
93      * @param obj the object (probably another connection) that we
94      * are being compared to
95      * @return whether they are the same
96      */

97     public boolean equals(Object JavaDoc obj) {
98         if (obj != null) {
99             if (obj instanceof ProxyConnection) {
100                 return connection.hashCode() == ((ProxyConnection) obj).getConnection().hashCode();
101             } else if (obj instanceof Connection JavaDoc) {
102                 return connection.hashCode() == obj.hashCode();
103             } else {
104                 return super.equals(obj);
105             }
106         } else {
107             return false;
108         }
109     }
110
111     /**
112      * Whether this connection is available. (When you close the connection
113      * it doesn't really close, it just becomes available for others to use).
114      * @return true if the connection is not active
115      */

116     public boolean isClosed() {
117         return (getStatus() != STATUS_ACTIVE);
118     }
119
120     public DatabaseMetaData JavaDoc getMetaData() throws SQLException JavaDoc {
121         return ProxyFactory.getDatabaseMetaData(connection, this);
122     }
123
124     /**
125      * The subclass should call this to indicate that a change has been made to
126      * the connection that might mean it needs to be reset (like setting autoCommit
127      * to false or something). We don't reset unless this has been called to avoid
128      * the overhead of unnecessary resetting.
129      *
130      * @param needToReset true if the connection might need resetting.
131      */

132     protected void setNeedToReset(boolean needToReset) {
133         this.needToReset = needToReset;
134     }
135
136     /**
137      * The ConnectionPool that was used to create this connection
138      * @return connectionPool
139      */

140     protected ConnectionPool getConnectionPool() {
141         return connectionPool;
142     }
143
144     /**
145      * By calling this we can keep track of any statements that are
146      * left open when this connection is returned to the pool.
147      * @param statement the statement that we have just opened/created.
148      * @see #registerClosedStatement
149      */

150     protected void addOpenStatement(Statement JavaDoc statement) {
151         openStatements.add(statement);
152     }
153
154     /**
155      * @see ProxyConnectionIF#registerClosedStatement
156      */

157     public void registerClosedStatement(Statement JavaDoc statement) {
158         if (openStatements.contains(statement)) {
159             openStatements.remove(statement);
160         } else {
161             connectionPool.getLog().warn(connectionPool.displayStatistics() + " - #" + getId() + " registered a statement as closed which wasn't known to be open.");
162         }
163     }
164
165     /**
166      * Close the connection for real
167      * @throws java.sql.SQLException if anything goes wrong
168      */

169     public void reallyClose() throws SQLException JavaDoc {
170         try {
171             connectionPool.registerRemovedConnection(getStatus());
172             // Clean up the actual connection
173
connection.close();
174         } catch (Throwable JavaDoc t) {
175             connectionPool.getLog().error("#" + idFormat.format(getId()) + " encountered errors during destruction: " + t);
176         }
177
178     }
179
180     /**
181      * @see ProxyConnectionIF#isReallyClosed
182      */

183     public boolean isReallyClosed() throws SQLException JavaDoc {
184         if (connection == null) {
185             return true;
186         } else {
187             return connection.isClosed();
188         }
189     }
190
191     /**
192      * @see ProxyConnectionIF#close
193      */

194     public void close() throws SQLException JavaDoc {
195         try {
196
197             if (isMarkedForExpiry()) {
198                 if (connectionPool.getLog().isDebugEnabled()) {
199                     connectionPool.getLog().debug("Closing connection quickly (without reset) because it's marked for expiry anyway");
200                 }
201             } else {
202                 // Close any open statements, as specified in JDBC
203
Statement JavaDoc[] statements = (Statement JavaDoc[]) openStatements.toArray(new Statement JavaDoc[openStatements.size()]);
204                 for (int j = 0; j < statements.length; j++) {
205                     Statement JavaDoc statement = statements[j];
206                     statement.close();
207                     if (connectionPool.getLog().isDebugEnabled()) {
208                         connectionPool.getLog().debug("Closing statement " + Integer.toHexString(statement.hashCode()) + " automatically");
209                     }
210                 }
211                 openStatements.clear();
212
213                 if (needToReset) {
214                     // This call should be as quick as possible. Should we consider only
215
// calling it if values have changed? The trouble with that is that it
216
// means keeping track when they change and that might be even
217
// slower
218
if (!connectionPool.resetConnection(connection, "#" + getId())) {
219                         connectionPool.removeProxyConnection(this, "it couldn't be reset", true, true);
220                     }
221                     needToReset = false;
222                 }
223             }
224             connectionPool.putConnection(this);
225         } catch (Throwable JavaDoc t) {
226             connectionPool.getLog().error("#" + idFormat.format(getId()) + " encountered errors during closure: ", t);
227         }
228
229     }
230
231     public int getMark() {
232         return mark;
233     }
234
235     public int getStatus() {
236         return status;
237     }
238
239     /**
240      * @see ProxyConnectionIF#setStatus(int)
241      */

242     public boolean setStatus(int newStatus) {
243         return setStatus(STATUS_FORCE, newStatus);
244     }
245
246     /**
247      * @see ProxyConnectionIF#setStatus(int, int)
248      */

249     public boolean setStatus(int oldStatus, int newStatus) {
250         boolean success = false;
251         try {
252             statusReadWriteLock.writeLock().acquire();
253             connectionPool.acquireConnectionStatusWriteLock();
254             if (this.status == oldStatus || oldStatus == STATUS_FORCE) {
255                 connectionPool.changeStatus(this.status, newStatus);
256                 this.status = newStatus;
257                 success = true;
258
259                 if (newStatus == oldStatus) {
260                     LOG.warn("Unexpected attempt to change status from " + oldStatus + " to " + newStatus
261                             + ". Why would you want to do that?");
262                 } else if (newStatus == STATUS_ACTIVE) {
263                     setTimeLastStartActive(System.currentTimeMillis());
264                 } else if (oldStatus == STATUS_ACTIVE) {
265                     setTimeLastStopActive(System.currentTimeMillis());
266                 }
267             }
268         } catch (InterruptedException JavaDoc e) {
269             LOG.error("Unable to acquire write lock for status");
270         } finally {
271             connectionPool.releaseConnectionStatusWriteLock();
272             statusReadWriteLock.writeLock().release();
273         }
274         return success;
275     }
276
277     public long getId() {
278         return id;
279     }
280
281     public void setId(long id) {
282         this.id = id;
283     }
284
285     /**
286      * @see ConnectionInfoIF#getBirthTime
287      */

288     public long getBirthTime() {
289         return birthDate.getTime();
290     }
291
292     /**
293      * @see ConnectionInfoIF#getBirthDate
294      */

295     public Date JavaDoc getBirthDate() {
296         return birthDate;
297     }
298
299     /**
300      * @see ConnectionInfoIF#getAge
301      */

302     public long getAge() {
303         return System.currentTimeMillis() - getBirthTime();
304     }
305
306     /**
307      * @see ConnectionInfoIF#getBirthTime
308      */

309     public void setBirthTime(long birthTime) {
310         birthDate = new Date JavaDoc(birthTime);
311     }
312
313     /**
314      * @see ConnectionInfoIF#getTimeLastStartActive
315      */

316     public long getTimeLastStartActive() {
317         return timeLastStartActive;
318     }
319
320     /**
321      * @see ConnectionInfoIF#getTimeLastStartActive
322      */

323     public void setTimeLastStartActive(long timeLastStartActive) {
324         this.timeLastStartActive = timeLastStartActive;
325         setTimeLastStopActive(0);
326     }
327
328     /**
329      * @see ConnectionInfoIF#getTimeLastStopActive
330      */

331     public long getTimeLastStopActive() {
332         return timeLastStopActive;
333     }
334
335     /**
336      * @see ConnectionInfoIF#getTimeLastStopActive
337      */

338     public void setTimeLastStopActive(long timeLastStopActive) {
339         this.timeLastStopActive = timeLastStopActive;
340     }
341
342     /**
343      * @see ConnectionInfoIF#getRequester
344      */

345     public String JavaDoc getRequester() {
346         return requester;
347     }
348
349     /**
350      * @see ConnectionInfoIF#getRequester
351      */

352     public void setRequester(String JavaDoc requester) {
353         this.requester = requester;
354     }
355
356     /**
357      * @see ProxyConnectionIF#isNull
358      */

359     public boolean isNull() {
360         return getStatus() == STATUS_NULL;
361     }
362
363     /**
364      * @see ProxyConnectionIF#isAvailable
365      */

366     public boolean isAvailable() {
367         return getStatus() == STATUS_AVAILABLE;
368     }
369
370     /**
371      * @see ProxyConnectionIF#isActive
372      */

373     public boolean isActive() {
374         return getStatus() == STATUS_ACTIVE;
375     }
376
377     /**
378      * @see ProxyConnectionIF#isOffline
379      */

380     public boolean isOffline() {
381         return getStatus() == STATUS_OFFLINE;
382     }
383
384     /**
385      * @see ProxyConnectionIF#markForExpiry
386      */

387     public void markForExpiry(String JavaDoc reason) {
388         mark = MARK_FOR_EXPIRY;
389         reasonForMark = reason;
390     }
391
392     /**
393      * @see ProxyConnectionIF#isMarkedForExpiry
394      */

395     public boolean isMarkedForExpiry() {
396         return getMark() == MARK_FOR_EXPIRY;
397     }
398
399     /**
400      * @see ProxyConnectionIF#getReasonForMark
401      */

402     public String JavaDoc getReasonForMark() {
403         return reasonForMark;
404     }
405
406     /**
407      * @see ProxyConnectionIF#getConnection
408      */

409     public Connection JavaDoc getConnection() {
410         return connection;
411     }
412
413     /**
414      * @see Object#toString
415      */

416     public String JavaDoc toString() {
417         return getId() + " is " + ConnectionPool.getStatusDescription(getStatus());
418     }
419
420     /**
421      * @see ConnectionInfoIF#getDelegateUrl
422      */

423     public String JavaDoc getDelegateUrl() {
424         return delegateUrl;
425     }
426
427     /**
428      * @see ConnectionInfoIF#getProxyHashcode
429      */

430     public String JavaDoc getProxyHashcode() {
431         return Integer.toHexString(hashCode());
432     }
433
434     /**
435      * @see ConnectionInfoIF#getDelegateHashcode
436      */

437     public String JavaDoc getDelegateHashcode() {
438         if (connection != null) {
439             return Integer.toHexString(connection.hashCode());
440         } else {
441             return null;
442         }
443     }
444
445     /**
446      * Compares using {@link #getId()}
447      * @param o must be another {@link ConnectionInfoIF} implementation
448      * @return the comparison
449      * @see Comparable#compareTo(Object)
450      */

451     public int compareTo(Object JavaDoc o) {
452         return new Long JavaDoc(((ConnectionInfoIF) o).getId()).compareTo(new Long JavaDoc(getId()));
453     }
454 }
455
456
457 /*
458  Revision history:
459  $Log: AbstractProxyConnection.java,v $
460  Revision 1.23 2003/10/30 00:05:49 billhorsman
461  now implements Comparable (using ID)
462
463  Revision 1.22 2003/08/27 18:19:07 billhorsman
464  whoops
465
466  Revision 1.21 2003/08/27 18:03:20 billhorsman
467  added new getDelegateConnection() method
468
469  Revision 1.20 2003/07/08 22:24:43 billhorsman
470  damn. no need to build the iterator now.
471
472  Revision 1.19 2003/07/08 22:04:22 billhorsman
473  attempt to fix possible ConcurrentModificationException
474  except I can't reproduce it in this environment. It now
475  builds an array before it loops through it and closes
476  each one. The iterator it used before wasn't thread-safe
477  in some environments.
478
479  Revision 1.18 2003/06/18 10:05:25 billhorsman
480  don't bother resetting connections that are marked for expiry
481
482  Revision 1.17 2003/03/11 14:51:47 billhorsman
483  more concurrency fixes relating to snapshots
484
485  Revision 1.16 2003/03/10 23:43:07 billhorsman
486  reapplied checkstyle that i'd inadvertently let
487  IntelliJ change...
488
489  Revision 1.15 2003/03/10 15:26:42 billhorsman
490  refactoringn of concurrency stuff (and some import
491  optimisation)
492
493  Revision 1.14 2003/03/05 18:42:32 billhorsman
494  big refactor of prototyping and house keeping to
495  drastically reduce the number of threads when using
496  many pools
497
498  Revision 1.13 2003/03/03 11:11:56 billhorsman
499  fixed licence
500
501  Revision 1.12 2003/02/26 16:05:52 billhorsman
502  widespread changes caused by refactoring the way we
503  update and redefine pool definitions.
504
505  Revision 1.11 2003/02/13 17:01:27 billhorsman
506  use hex for statement hashcode
507
508  Revision 1.10 2003/02/12 12:30:10 billhorsman
509  checkstyle
510
511  Revision 1.9 2003/02/12 12:28:27 billhorsman
512  added url, proxyHashcode and delegateHashcode to
513  ConnectionInfoIF
514
515  Revision 1.8 2003/02/11 00:30:45 billhorsman
516  fixed equals for jdk1.2
517
518  Revision 1.7 2003/02/07 10:58:22 billhorsman
519  fixed equals method so that connections are actually
520  removed (they were just being marked as status null)
521
522  Revision 1.6 2003/02/06 17:41:04 billhorsman
523  now uses imported logging
524
525  Revision 1.5 2003/01/31 16:53:15 billhorsman
526  checkstyle
527
528  Revision 1.4 2003/01/31 14:33:14 billhorsman
529  fix for DatabaseMetaData
530
531  Revision 1.3 2003/01/31 11:38:57 billhorsman
532  birthDate now stored as Date not long
533
534  Revision 1.2 2003/01/28 11:50:35 billhorsman
535  more verbose debug
536
537  Revision 1.1 2003/01/27 18:26:33 billhorsman
538  refactoring of ProxyConnection and ProxyStatement to
539  make it easier to write JDK 1.2 patch
540
541  */
Popular Tags