KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > component > jdbcpool > ConnectionManager


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: ConnectionManager.java 1022 2006-08-04 11:02:28Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.component.jdbcpool;
27
28 import java.io.PrintWriter JavaDoc;
29 import java.io.Serializable JavaDoc;
30 import java.sql.Connection JavaDoc;
31 import java.sql.DriverManager JavaDoc;
32 import java.sql.SQLException JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.LinkedList JavaDoc;
36 import java.util.Map JavaDoc;
37 import java.util.TreeSet JavaDoc;
38
39 import javax.naming.NamingException JavaDoc;
40 import javax.naming.Reference JavaDoc;
41 import javax.naming.Referenceable JavaDoc;
42 import javax.naming.StringRefAddr JavaDoc;
43 import javax.sql.ConnectionEvent JavaDoc;
44 import javax.sql.ConnectionEventListener JavaDoc;
45 import javax.sql.DataSource JavaDoc;
46 import javax.sql.XAConnection JavaDoc;
47 import javax.sql.XADataSource JavaDoc;
48 import javax.transaction.RollbackException JavaDoc;
49 import javax.transaction.SystemException JavaDoc;
50 import javax.transaction.Transaction JavaDoc;
51 import javax.transaction.TransactionManager JavaDoc;
52 import javax.transaction.xa.XAResource JavaDoc;
53
54 import org.objectweb.easybeans.log.JLog;
55 import org.objectweb.easybeans.log.JLogFactory;
56
57 /**
58  * DataSource implementation. Manage a pool of connections.
59  * @author Philippe Durieux
60  * @author Florent Benoit
61  */

62 public class ConnectionManager implements DataSource JavaDoc, XADataSource JavaDoc, Referenceable JavaDoc, Serializable JavaDoc, ConnectionEventListener JavaDoc {
63
64     /**
65      * uid for Serializable class.
66      */

67     private static final long serialVersionUID = -7159546694962248547L;
68
69     /**
70      * Logger.
71      */

72     private JLog logger = JLogFactory.getLog(ConnectionManager.class);
73
74     /**
75      * Milliseconds.
76      */

77     private static final long MILLI = 1000L;
78
79     /**
80      * One minute in milliseconds.
81      */

82     private static final long ONE_MIN_MILLI = 60L * MILLI;
83
84     /**
85      * Default timeout.
86      */

87     private static final int DEFAULT_TIMEOUT = 60;
88
89     /**
90      * Default timeout for waiters (10s).
91      */

92     private static final long WAITER_TIMEOUT = 10 * MILLI;
93
94     /**
95      * Max waiters (by default).
96      */

97     private static final int DEFAULT_MAX_WAITERS = 1000;
98
99     /**
100      * Default prepare statement.
101      */

102     private static final int DEFAULT_PSTMT = 12;
103
104     /**
105      * Default sampling period.
106      */

107     private static final int DEFAULT_SAMPLING = 60;
108
109
110     /**
111      * List of all datasources.
112      */

113     private static Map JavaDoc<String JavaDoc, ConnectionManager> cmList = new HashMap JavaDoc<String JavaDoc, ConnectionManager>();
114
115     /**
116      * Transaction manager.
117      */

118     private TransactionManager JavaDoc tm = null;
119
120     /**
121      * List of JManagedConnection not currently used. This avoids closing and
122      * reopening physical connections. We try to keep a minimum of minConPool
123      * elements here.
124      */

125     private TreeSet JavaDoc<JManagedConnection> freeList = new TreeSet JavaDoc<JManagedConnection>();
126
127     /**
128      * Total list of JManagedConnection physically opened.
129      */

130     private LinkedList JavaDoc<JManagedConnection> mcList = new LinkedList JavaDoc<JManagedConnection>();
131
132     /**
133      * This HashMap gives the JManagedConnection from its transaction Requests
134      * with same tx get always the same connection.
135      */

136     private Map JavaDoc<Transaction JavaDoc, JManagedConnection> tx2mc = new HashMap JavaDoc<Transaction JavaDoc, JManagedConnection>();
137
138     /**
139      * Login timeout (DataSource impl).
140      */

141     private int loginTimeout = DEFAULT_TIMEOUT;
142
143     /**
144      * PrintWriter used logging (DataSource impl).
145      */

146     private PrintWriter JavaDoc log = null;
147
148     /**
149      * Constructor for Factory.
150      */

151     public ConnectionManager() {
152
153     }
154
155     /**
156      * Gets the ConnectionManager matching the DataSource name.
157      * @param dsname datasource name.
158      * @return a connection manager impl.
159      */

160     public static ConnectionManager getConnectionManager(final String JavaDoc dsname) {
161         ConnectionManager cm = cmList.get(dsname);
162         return cm;
163     }
164
165     /**
166      * Datasource name.
167      */

168     private String JavaDoc dSName = null;
169
170     /**
171      * @return Jndi name of the datasource
172      */

173     public String JavaDoc getDSName() {
174         return dSName;
175     }
176
177     /**
178      * @param s Jndi name for the datasource
179      */

180     public void setDSName(final String JavaDoc s) {
181         dSName = s;
182         // Add it to the list
183
cmList.put(s, this);
184     }
185
186     /**
187      * @serial datasource name
188      */

189     private String JavaDoc dataSourceName;
190
191     /**
192      * Gets the name of the datasource.
193      * @return the name of the datasource
194      */

195     public String JavaDoc getDatasourceName() {
196         return dataSourceName;
197     }
198
199     /**
200      * Sets the name of the datasource.
201      * @param dataSourceName the name of the datasource
202      */

203     public void setDatasourceName(final String JavaDoc dataSourceName) {
204         this.dataSourceName = dataSourceName;
205     }
206
207     /**
208      * url for database.
209      */

210     private String JavaDoc url = null;
211
212     /**
213      * @return the url used to get the connection.
214      */

215     public String JavaDoc getUrl() {
216         return url;
217     }
218
219     /**
220      * Sets the url to get connections.
221      * @param url the url for JDBC connections.
222      */

223     public void setUrl(final String JavaDoc url) {
224         this.url = url;
225     }
226
227     /**
228      * JDBC driver Class.
229      */

230     private String JavaDoc className = null;
231
232     /**
233      * @return the JDBC driver class name.
234      */

235     public String JavaDoc getClassName() {
236         return className;
237     }
238
239     /**
240      * Sets the driver class for JDBC.
241      * @param className the name of the JDBC driver
242      * @throws ClassNotFoundException if driver is not found
243      */

244     public void setClassName(final String JavaDoc className) throws ClassNotFoundException JavaDoc {
245         this.className = className;
246
247         // Loads standard JDBC driver and keeps it loaded (via driverClass)
248
logger.debug("Load JDBC driver {0}", className);
249         try {
250             Class.forName(className);
251         } catch (java.lang.ClassNotFoundException JavaDoc e) {
252             logger.error("Cannot load JDBC driver", e);
253             throw e;
254         }
255     }
256
257     /**
258      * default user.
259      */

260     private String JavaDoc userName = null;
261
262     /**
263      * @return the user used for getting connections.
264      */

265     public String JavaDoc getUserName() {
266         return userName;
267     }
268
269     /**
270      * Sets the user for getting connections.
271      * @param userName the name of the user.
272      */

273     public void setUserName(final String JavaDoc userName) {
274         this.userName = userName;
275     }
276
277     /**
278      * default passwd.
279      */

280     private String JavaDoc password = null;
281
282     /**
283      * @return the password used for connections.
284      */

285     public String JavaDoc getPassword() {
286         return password;
287     }
288
289     /**
290      * Sets the password used to get connections.
291      * @param password the password value.
292      */

293     public void setPassword(final String JavaDoc password) {
294         this.password = password;
295     }
296
297     /**
298      * Isolation level for JDBC.
299      */

300     private int isolationLevel = -1;
301
302     /**
303      * Isolation level (but String format).
304      */

305     private String JavaDoc isolationStr = null;
306
307     /**
308      * Sets the transaction isolation level of the connections.
309      * @param level the level of isolation.
310      */

311     public void setTransactionIsolation(final String JavaDoc level) {
312         if (level.equals("serializable")) {
313             isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
314         } else if (level.equals("none")) {
315             isolationLevel = Connection.TRANSACTION_NONE;
316         } else if (level.equals("read_committed")) {
317             isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
318         } else if (level.equals("read_uncommitted")) {
319             isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
320         } else if (level.equals("repeatable_read")) {
321             isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
322         } else {
323             isolationStr = "default";
324             return;
325         }
326         isolationStr = level;
327     }
328
329     /**
330      * Gets the transaction isolation level.
331      * @return transaction isolation level.
332      */

333     public String JavaDoc getTransactionIsolation() {
334         return isolationStr;
335     }
336
337     /**
338      * count max waiters during current period.
339      */

340     private int waiterCount = 0;
341
342     /**
343      * count max waiting time during current period.
344      */

345     private long waitingTime = 0;
346
347     /**
348      * count max busy connection during current period.
349      */

350     private int busyMax = 0;
351
352     /**
353      * count min busy connection during current period.
354      */

355     private int busyMin = 0;
356
357     /**
358      * High Value for no limit for the connection pool.
359      */

360     private static final int NO_LIMIT = 99999;
361
362     /**
363      * Nb of milliseconds in a day.
364      */

365     private static final long ONE_DAY = 1440L * 60L * 1000L;
366
367     /**
368      * max number of remove at once in the freelist We avoid removing too much
369      * mcs at once for perf reasons.
370      */

371     private static final int MAX_REMOVE_FREELIST = 10;
372
373     /**
374      * minimum size of the connection pool.
375      */

376     private int poolMin = 0;
377
378     /**
379      * @return min pool size.
380      */

381     public int getPoolMin() {
382         return poolMin;
383     }
384
385     /**
386      * @param min minimum connection pool size to be set.
387      */

388     public synchronized void setPoolMin(final int min) {
389         if (poolMin != min) {
390             poolMin = min;
391             adjust();
392         }
393     }
394
395     /**
396      * maximum size of the connection pool. default value is "NO LIMIT".
397      */

398     private int poolMax = NO_LIMIT;
399
400     /**
401      * @return actual max pool size
402      */

403     public int getPoolMax() {
404         return poolMax;
405     }
406
407     /**
408      * @param max max pool size. -1 means "no limit".
409      */

410     public synchronized void setPoolMax(final int max) {
411         if (poolMax != max) {
412             if (max < 0 || max > NO_LIMIT) {
413                 if (currentWaiters > 0) {
414                     notify();
415                 }
416                 poolMax = NO_LIMIT;
417             } else {
418                 if (currentWaiters > 0 && poolMax < max) {
419                     notify();
420                 }
421                 poolMax = max;
422                 adjust();
423             }
424         }
425     }
426
427     /**
428      * Max age of a Connection in milliseconds. When the time is elapsed, the
429      * connection will be closed. This avoids keeping connections open too long
430      * for nothing.
431      */

432     private long maxAge = ONE_DAY;
433
434     /**
435      * Same value in mns.
436      */

437     private int maxAgeMn;
438
439     /**
440      * @return max age for connections (in mm).
441      */

442     public int getMaxAge() {
443         return maxAgeMn;
444     }
445
446     /**
447      * @return max age for connections (in millisec).
448      */

449     public long getMaxAgeMilli() {
450         return maxAge;
451     }
452
453     /**
454      * @param mn max age of connection in minutes.
455      */

456     public void setMaxAge(final int mn) {
457         maxAgeMn = mn;
458         // set times in milliseconds
459
maxAge = mn * ONE_MIN_MILLI;
460     }
461
462     /**
463      * max open time for a connection, in millisec.
464      */

465     private long maxOpenTime = ONE_DAY;
466
467     /**
468      * Same value in mn.
469      */

470     private int maxOpenTimeMn;
471
472     /**
473      * @return max age for connections (in mns).
474      */

475     public int getMaxOpenTime() {
476         return maxOpenTimeMn;
477     }
478
479     /**
480      * @return max age for connections (in millisecs).
481      */

482     public long getMaxOpenTimeMilli() {
483         return maxOpenTime;
484     }
485
486     /**
487      * @param mn max time of open connection in minutes.
488      */

489     public void setMaxOpenTime(final int mn) {
490         maxOpenTimeMn = mn;
491         // set times in milliseconds
492
maxOpenTime = mn * ONE_MIN_MILLI;
493     }
494
495     /**
496      * max nb of milliseconds to wait for a connection when pool is empty.
497      */

498     private long waiterTimeout = WAITER_TIMEOUT;
499
500     /**
501      * @return waiter timeout in seconds.
502      */

503     public int getMaxWaitTime() {
504         return (int) (waiterTimeout / MILLI);
505     }
506
507     /**
508      * @param sec max time to wait for a connection, in seconds.
509      */

510     public void setMaxWaitTime(final int sec) {
511         waiterTimeout = sec * MILLI;
512     }
513
514     /**
515      * max nb of waiters allowed to wait for a Connection.
516      */

517     private int maxWaiters = DEFAULT_MAX_WAITERS;
518
519     /**
520      * @return max nb of waiters
521      */

522     public int getMaxWaiters() {
523         return maxWaiters;
524     }
525
526     /**
527      * @param nb max nb of waiters
528      */

529     public void setMaxWaiters(final int nb) {
530         maxWaiters = nb;
531     }
532
533     /**
534      * sampling period in sec.
535      */

536     private int samplingPeriod = DEFAULT_SAMPLING; // default sampling period
537

538     /**
539      * @return sampling period in sec.
540      */

541     public int getSamplingPeriod() {
542         return samplingPeriod;
543     }
544
545     /**
546      * @param sec sampling period in sec.
547      */

548     public void setSamplingPeriod(final int sec) {
549         if (sec > 0) {
550             samplingPeriod = sec;
551         }
552     }
553
554     /**
555      * Level of checking on connections when got from the pool. this avoids
556      * reusing bad connections because too old, for example when database was
557      * restarted... 0 = no checking 1 = check that still physically opened. 2 =
558      * try a null statement.
559      */

560     private int checkLevel = 0; // default = 0
561

562     /**
563      * @return connection checking level
564      */

565     public int getCheckLevel() {
566         return checkLevel;
567     }
568
569     /**
570      * @param level jdbc connection checking level (0, 1, or 2)
571      */

572     public void setCheckLevel(final int level) {
573         checkLevel = level;
574     }
575
576     /**
577      * PreparedStatement pool size per managed connection.
578      */

579     private int pstmtMax = DEFAULT_PSTMT;
580
581     /**
582      * @return PreparedStatement cache size.
583      */

584     public int getPstmtMax() {
585         return pstmtMax;
586     }
587
588     /**
589      * @param nb PreparedStatement cache size.
590      */

591     public void setPstmtMax(final int nb) {
592         pstmtMax = nb;
593         // Set the value in each connection.
594
for (Iterator JavaDoc i = mcList.iterator(); i.hasNext();) {
595             JManagedConnection mc = (JManagedConnection) i.next();
596             mc.setPstmtMax(pstmtMax);
597         }
598     }
599
600     /**
601      * test statement used when checkLevel = 2.
602      */

603     private String JavaDoc testStatement;
604
605     /**
606      * @return test statement used when checkLevel = 2.
607      */

608     public String JavaDoc getTestStatement() {
609         return testStatement;
610     }
611
612     /**
613      * @param s test statement
614      */

615     public void setTestStatement(final String JavaDoc s) {
616         testStatement = s;
617     }
618
619     /**
620      * Configure the Connection pool. Called by the Container at init.
621      * Configuration can be set in datasource.properties files.
622      * @param connchecklevel JDBC connection checking level
623      * @param connmaxage JDBC connection maximum age
624      * @param maxopentime JDBC connection maximum open time
625      * @param connteststmt SQL query for test statement
626      * @param pstmtmax prepare statement pool size per managed connection
627      * @param minconpool Min size for the connection pool
628      * @param maxconpool Max size for the connection pool
629      * @param maxwaittime Max time to wait for a connection (in seconds)
630      * @param maxwaiters Max nb of waiters for a connection
631      * @param samplingperiod sampling period in sec.
632      */

633     @SuppressWarnings JavaDoc("boxing")
634     public void poolConfigure(final String JavaDoc connchecklevel, final String JavaDoc connmaxage, final String JavaDoc maxopentime,
635             final String JavaDoc connteststmt, final String JavaDoc pstmtmax, final String JavaDoc minconpool, final String JavaDoc maxconpool,
636             final String JavaDoc maxwaittime, final String JavaDoc maxwaiters, final String JavaDoc samplingperiod) {
637
638         // Configure pool
639
setCheckLevel((new Integer JavaDoc(connchecklevel)).intValue());
640         // set con max age BEFORE min/max pool size.
641
setMaxAge((new Integer JavaDoc(connmaxage)).intValue());
642         setMaxOpenTime((new Integer JavaDoc(maxopentime)).intValue());
643         setTestStatement(connteststmt);
644         setPstmtMax((new Integer JavaDoc(pstmtmax)).intValue());
645         setPoolMin((new Integer JavaDoc(minconpool)).intValue());
646         setPoolMax((new Integer JavaDoc(maxconpool)).intValue());
647         setMaxWaitTime((new Integer JavaDoc(maxwaittime)).intValue());
648         setMaxWaiters((new Integer JavaDoc(maxwaiters)).intValue());
649         setSamplingPeriod((new Integer JavaDoc(samplingperiod)).intValue());
650         if (logger.isDebugEnabled()) {
651             logger.debug("ConnectionManager configured with:");
652             logger.debug(" jdbcConnCheckLevel = {0}", connchecklevel);
653             logger.debug(" jdbcConnMaxAge = {0}", connmaxage);
654             logger.debug(" jdbcMaxOpenTime = {0}", maxopentime);
655             logger.debug(" jdbcTestStmt = {0}", connteststmt);
656             logger.debug(" jdbcPstmtMax = {0}", pstmtmax);
657             logger.debug(" minConPool = {0}", getPoolMin());
658             logger.debug(" maxConPool = {0}", getPoolMax());
659             logger.debug(" maxWaitTime = {0}", getMaxWaitTime());
660             logger.debug(" maxWaiters = {0}", getMaxWaiters());
661             logger.debug(" samplingPeriod = {0}", getSamplingPeriod());
662         }
663     }
664
665     /**
666      * maximum nb of busy connections in last sampling period.
667      */

668     private int busyMaxRecent = 0;
669
670     /**
671      * @return maximum nb of busy connections in last sampling period.
672      */

673     public int getBusyMaxRecent() {
674         return busyMaxRecent;
675     }
676
677     /**
678      * minimum nb of busy connections in last sampling period.
679      */

680     private int busyMinRecent = 0;
681
682     /**
683      * @return minimum nb of busy connections in last sampling period.
684      */

685     public int getBusyMinRecent() {
686         return busyMinRecent;
687     }
688
689     /**
690      * nb of threads waiting for a Connection.
691      */

692     private int currentWaiters = 0;
693
694     /**
695      * @return current number of connection waiters.
696      */

697     public int getCurrentWaiters() {
698         return currentWaiters;
699     }
700
701     /**
702      * total number of opened physical connections since the datasource
703      * creation.
704      */

705     private int openedCount = 0;
706
707     /**
708      * @return int number of physical jdbc connection opened.
709      */

710     public int getOpenedCount() {
711         return openedCount;
712     }
713
714     /**
715      * total nb of physical connection failures.
716      */

717     private int connectionFailures = 0;
718
719     /**
720      * @return int number of xa connection failures on open.
721      */

722     public int getConnectionFailures() {
723         return connectionFailures;
724     }
725
726     /**
727      * total nb of connection leaks. A connection leak occurs when the caller
728      * never issues a close method on the connection.
729      */

730     private int connectionLeaks = 0;
731
732     /**
733      * @return int number of connection leaks.
734      */

735     public int getConnectionLeaks() {
736         return connectionLeaks;
737     }
738
739     /**
740      * total number of opened connections since the datasource creation.
741      */

742     private int servedOpen = 0;
743
744     /**
745      * @return int number of xa connection served.
746      */

747     public int getServedOpen() {
748         return servedOpen;
749     }
750
751     /**
752      * total nb of open connection failures because waiter overflow.
753      */

754     private int rejectedFull = 0;
755
756     /**
757      * @return int number of open calls that were rejected due to waiter
758      * overflow.
759      */

760     public int getRejectedFull() {
761         return rejectedFull;
762     }
763
764     /**
765      * total nb of open connection failures because timeout.
766      */

767     private int rejectedTimeout = 0;
768
769     /**
770      * @return int number of open calls that were rejected by timeout.
771      */

772     public int getRejectedTimeout() {
773         return rejectedTimeout;
774     }
775
776     /**
777      * total nb of open connection failures for any other reason.
778      */

779     private int rejectedOther = 0;
780
781     /**
782      * @return int number of open calls that were rejected.
783      */

784     public int getRejectedOther() {
785         return rejectedOther;
786     }
787
788     /**
789      * @return int number of open calls that were rejected.
790      */

791     public int getRejectedOpen() {
792         return rejectedFull + rejectedTimeout + rejectedOther;
793     }
794
795     /**
796      * maximum nb of waiters since datasource creation.
797      */

798     private int waitersHigh = 0;
799
800     /**
801      * @return maximum nb of waiters since the datasource creation.
802      */

803     public int getWaitersHigh() {
804         return waitersHigh;
805     }
806
807     /**
808      * maximum nb of waiters in last sampling period.
809      */

810     private int waitersHighRecent = 0;
811
812     /**
813      * @return maximum nb of waiters in last sampling period.
814      */

815     public int getWaitersHighRecent() {
816         return waitersHighRecent;
817     }
818
819     /**
820      * total nb of waiters since datasource creation.
821      */

822     private int totalWaiterCount = 0;
823
824     /**
825      * @return total nb of waiters since the datasource creation.
826      */

827     public int getWaiterCount() {
828         return totalWaiterCount;
829     }
830
831     /**
832      * total waiting time in milliseconds.
833      */

834     private long totalWaitingTime = 0;
835
836     /**
837      * @return total waiting time since the datasource creation.
838      */

839     public long getWaitingTime() {
840         return totalWaitingTime;
841     }
842
843     /**
844      * max waiting time in milliseconds.
845      */

846     private long waitingHigh = 0;
847
848     /**
849      * @return max waiting time since the datasource creation.
850      */

851     public long getWaitingHigh() {
852         return waitingHigh;
853     }
854
855     /**
856      * max waiting time in milliseconds in last sampling period.
857      */

858     private long waitingHighRecent = 0;
859
860     /**
861      * @return max waiting time in last sampling period.
862      */

863     public long getWaitingHighRecent() {
864         return waitingHighRecent;
865     }
866
867     /**
868      * {@inheritDoc}
869      */

870     public int getLoginTimeout() throws SQLException JavaDoc {
871         return loginTimeout;
872     }
873
874     /**
875      * {@inheritDoc}
876      */

877     public void setLoginTimeout(final int seconds) throws SQLException JavaDoc {
878         loginTimeout = seconds;
879     }
880
881     /**
882      * {@inheritDoc}
883      */

884     public PrintWriter JavaDoc getLogWriter() throws SQLException JavaDoc {
885         return log;
886     }
887
888     /**
889      * {@inheritDoc}
890      */

891     public void setLogWriter(final PrintWriter JavaDoc out) throws SQLException JavaDoc {
892         log = out;
893     }
894
895     /**
896      * {@inheritDoc}
897      */

898     public Connection JavaDoc getConnection() throws SQLException JavaDoc {
899         return getConnection(userName, password);
900     }
901
902     /**
903      * Attempts to establish a connection with the data source that this
904      * DataSource object represents. - comes from the javax.sql.DataSource
905      * interface
906      * @param username - the database user on whose behalf the connection is
907      * being made
908      * @param password - the user's password
909      * @return a connection to the data source
910      * @throws SQLException - if a database access error occurs
911      */

912     public Connection JavaDoc getConnection(final String JavaDoc username, final String JavaDoc password) throws SQLException JavaDoc {
913         JManagedConnection mc = null;
914
915         // Get the current Transaction
916
Transaction JavaDoc tx = null;
917         try {
918             tx = tm.getTransaction();
919         } catch (NullPointerException JavaDoc n) {
920             // current is null: we are not in EasyBeans Server.
921
logger.error("ConnectionManager: should not be used outside a EasyBeans Server");
922         } catch (SystemException JavaDoc e) {
923             logger.error("ConnectionManager: getTransaction failed", e);
924         }
925         logger.debug("Tx = {0}", tx);
926
927         // Get a JManagedConnection in the pool for this user
928
mc = openConnection(username, tx);
929         Connection JavaDoc ret = mc.getConnection();
930
931         // Enlist XAResource if we are actually in a transaction
932
if (tx != null) {
933             if (mc.getOpenCount() == 1) { // Only if first/only thread
934
try {
935                     logger.debug("enlist XAResource on {0}", tx);
936                     tx.enlistResource(mc.getXAResource());
937                     ret.setAutoCommit(false);
938                 } catch (RollbackException JavaDoc e) {
939                     // Although tx has been marked to be rolled back,
940
// XAResource has been correctly enlisted.
941
logger.warn("XAResource enlisted, but tx is marked rollback", e);
942                 } catch (IllegalStateException JavaDoc e) {
943                     // In case tx is committed, no need to register resource!
944
ret.setAutoCommit(true);
945                 } catch (Exception JavaDoc e) {
946                     logger.error("Cannot enlist XAResource", e);
947                     logger.error("Connection will not be enlisted in a transaction");
948                     // should return connection in the pool XXX
949
throw new SQLException JavaDoc("Cannot enlist XAResource");
950                 }
951             }
952         } else {
953             ret.setAutoCommit(true); // in case we do not start a Tx
954
}
955
956         // return a Connection object
957
return ret;
958     }
959
960     /**
961      * Attempts to establish a physical database connection that can be
962      * used in a distributed transaction.
963      *
964      * @return an <code>XAConnection</code> object, which represents a
965      * physical connection to a data source, that can be used in
966      * a distributed transaction
967      * @exception SQLException if a database access error occurs
968      */

969     public XAConnection JavaDoc getXAConnection() throws SQLException JavaDoc {
970         return getXAConnection(userName, password);
971     }
972
973     /**
974      * Attempts to establish a physical database connection, using the given
975      * user name and password. The connection that is returned is one that can
976      * be used in a distributed transaction - comes from the
977      * javax.sql.XADataSource interface
978      * @param user - the database user on whose behalf the connection is being
979      * made
980      * @param passwd - the user's password
981      * @return an XAConnection object, which represents a physical connection to
982      * a data source, that can be used in a distributed transaction
983      * @throws SQLException - if a database access error occurs
984      */

985     @SuppressWarnings JavaDoc("boxing")
986     public XAConnection JavaDoc getXAConnection(final String JavaDoc user, final String JavaDoc passwd) throws SQLException JavaDoc {
987         // Create the actual connection in the std driver
988
Connection JavaDoc conn = null;
989         try {
990             if (user.length() == 0) {
991                 conn = DriverManager.getConnection(url);
992                 logger.debug(" * New Connection on {0}", url);
993             } else {
994                 // Accept password of zero length.
995
conn = DriverManager.getConnection(url, user, passwd);
996                 logger.debug(" * New Connection on {0} for user {1}", url, user);
997             }
998         } catch (SQLException JavaDoc e) {
999             logger.error("Could not get Connection on {0}", url, e);
1000            throw new SQLException JavaDoc("Could not get Connection on url : " + url + " for user : " + user + " inner exception"
1001                    + e.getMessage());
1002        }
1003
1004        // Attempt to set the transaction isolation level
1005
// Depending on the underlaying database, this may not succeed.
1006
if (isolationLevel != -1) {
1007            try {
1008                logger.debug("set transaction isolation to {0}", isolationLevel);
1009                conn.setTransactionIsolation(isolationLevel);
1010            } catch (SQLException JavaDoc e) {
1011                String JavaDoc ilstr = "?";
1012                switch (isolationLevel) {
1013                    case Connection.TRANSACTION_SERIALIZABLE:
1014                        ilstr = "SERIALIZABLE";
1015                        break;
1016                    case Connection.TRANSACTION_NONE:
1017                        ilstr = "NONE";
1018                        break;
1019                    case Connection.TRANSACTION_READ_COMMITTED:
1020                        ilstr = "READ_COMMITTED";
1021                        break;
1022                    case Connection.TRANSACTION_READ_UNCOMMITTED:
1023                        ilstr = "READ_UNCOMMITTED";
1024                        break;
1025                    case Connection.TRANSACTION_REPEATABLE_READ:
1026                        ilstr = "REPEATABLE_READ";
1027                        break;
1028                    default:
1029                        throw new SQLException JavaDoc("Invalid isolation level '" + ilstr + "'.");
1030                }
1031                logger.error("Cannot set transaction isolation to {0} for this DataSource url {1}", ilstr, url, e);
1032                isolationLevel = -1;
1033            }
1034        }
1035
1036        // Create the JManagedConnection object
1037
JManagedConnection mc = new JManagedConnection(conn, this);
1038
1039        // return the XAConnection
1040
return mc;
1041    }
1042
1043    // -----------------------------------------------------------------
1044
// Referenceable Implementation
1045
// -----------------------------------------------------------------
1046

1047    /**
1048     * Retrieves the Reference of this object. Used at binding time by JNDI to
1049     * build a reference on this object.
1050     * @return The non-null Reference of this object.
1051     * @exception NamingException If a naming exception was encountered while
1052     * retrieving the reference.
1053     */

1054    public Reference JavaDoc getReference() throws NamingException JavaDoc {
1055
1056        Reference JavaDoc ref = new Reference JavaDoc(this.getClass().getName(), DataSourceFactory.class.getName(), null);
1057        // These values are used by ObjectFactory (see DataSourceFactory.java)
1058
ref.add(new StringRefAddr JavaDoc("datasource.name", getDSName()));
1059        ref.add(new StringRefAddr JavaDoc("datasource.url", getUrl()));
1060        ref.add(new StringRefAddr JavaDoc("datasource.classname", getClassName()));
1061        ref.add(new StringRefAddr JavaDoc("datasource.username", getUserName()));
1062        ref.add(new StringRefAddr JavaDoc("datasource.password", getPassword()));
1063        ref.add(new StringRefAddr JavaDoc("datasource.isolationlevel", getTransactionIsolation()));
1064        Integer JavaDoc checklevel = new Integer JavaDoc(getCheckLevel());
1065        ref.add(new StringRefAddr JavaDoc("connchecklevel", checklevel.toString()));
1066        Integer JavaDoc maxage = new Integer JavaDoc(getMaxAge());
1067        ref.add(new StringRefAddr JavaDoc("connmaxage", maxage.toString()));
1068        Integer JavaDoc maxopentime = new Integer JavaDoc(getMaxOpenTime());
1069        ref.add(new StringRefAddr JavaDoc("maxopentime", maxopentime.toString()));
1070        ref.add(new StringRefAddr JavaDoc("connteststmt", getTestStatement()));
1071        Integer JavaDoc pstmtmax = new Integer JavaDoc(getPstmtMax());
1072        ref.add(new StringRefAddr JavaDoc("pstmtmax", pstmtmax.toString()));
1073        Integer JavaDoc minpool = new Integer JavaDoc(getPoolMin());
1074        ref.add(new StringRefAddr JavaDoc("minconpool", minpool.toString()));
1075        Integer JavaDoc maxpool = new Integer JavaDoc(getPoolMax());
1076        ref.add(new StringRefAddr JavaDoc("maxconpool", maxpool.toString()));
1077        Integer JavaDoc maxwaittime = new Integer JavaDoc(getMaxWaitTime());
1078        ref.add(new StringRefAddr JavaDoc("maxwaittime", maxwaittime.toString()));
1079        Integer JavaDoc maxwaiters = new Integer JavaDoc(getMaxWaiters());
1080        ref.add(new StringRefAddr JavaDoc("maxwaiters", maxwaiters.toString()));
1081        Integer JavaDoc samplingperiod = new Integer JavaDoc(getSamplingPeriod());
1082        ref.add(new StringRefAddr JavaDoc("samplingperiod", samplingperiod.toString()));
1083        return ref;
1084    }
1085
1086    /**
1087     * Notifies this <code>ConnectionEventListener</code> that
1088     * the application has called the method <code>close</code> on its
1089     * representation of a pooled connection.
1090     *
1091     * @param event an event object describing the source of
1092     * the event
1093     */

1094    public void connectionClosed(final ConnectionEvent JavaDoc event) {
1095        JManagedConnection mc = (JManagedConnection) event.getSource();
1096        closeConnection(mc, XAResource.TMSUCCESS);
1097    }
1098
1099    /**
1100     * Notifies this <code>ConnectionEventListener</code> that
1101     * a fatal error has occurred and the pooled connection can
1102     * no longer be used. The driver makes this notification just
1103     * before it throws the application the <code>SQLException</code>
1104     * contained in the given <code>ConnectionEvent</code> object.
1105     *
1106     * @param event an event object describing the source of
1107     * the event and containing the <code>SQLException</code> that the
1108     * driver is about to throw
1109     */

1110    @SuppressWarnings JavaDoc("boxing")
1111    public void connectionErrorOccurred(final ConnectionEvent JavaDoc event) {
1112
1113        JManagedConnection mc = (JManagedConnection) event.getSource();
1114        logger.debug("mc= {0}", mc.getIdentifier());
1115
1116        // remove it from the list of open connections for this thread
1117
// only if it was opened outside a tx.
1118
closeConnection(mc, XAResource.TMFAIL);
1119    }
1120
1121    /**
1122     * @return int number of xa connection
1123     */

1124    public int getCurrentOpened() {
1125        return mcList.size();
1126    }
1127
1128    /**
1129     * @return int number of busy xa connection.
1130     */

1131    public int getCurrentBusy() {
1132        return mcList.size() - freeList.size();
1133    }
1134
1135    /**
1136     * compute current min/max busyConnections.
1137     */

1138    public void recomputeBusy() {
1139        int busy = getCurrentBusy();
1140        if (busyMax < busy) {
1141            busyMax = busy;
1142        }
1143        if (busyMin > busy) {
1144            busyMin = busy;
1145        }
1146    }
1147
1148    /**
1149     * @return int number of xa connection reserved for tx.
1150     */

1151    public int getCurrentInTx() {
1152        return tx2mc.size();
1153    }
1154
1155    /**
1156     * make samples with some monitoring values.
1157     */

1158    public synchronized void sampling() {
1159        waitingHighRecent = waitingTime;
1160        if (waitingHigh < waitingTime) {
1161            waitingHigh = waitingTime;
1162        }
1163        waitingTime = 0;
1164
1165        waitersHighRecent = waiterCount;
1166        if (waitersHigh < waiterCount) {
1167            waitersHigh = waiterCount;
1168        }
1169        waiterCount = 0;
1170
1171        busyMaxRecent = busyMax;
1172        busyMax = getCurrentBusy();
1173        busyMinRecent = busyMin;
1174        busyMin = getCurrentBusy();
1175    }
1176
1177    /**
1178     * Adjust the pool size, according to poolMax and poolMin values. Also
1179     * remove old connections in the freeList.
1180     */

1181    @SuppressWarnings JavaDoc("boxing")
1182    public synchronized void adjust() {
1183        logger.debug(dSName);
1184
1185        // Remove max aged elements in freelist
1186
// - Not more than MAX_REMOVE_FREELIST
1187
// - Don't reduce pool size less than poolMin
1188
int count = mcList.size() - poolMin;
1189        // In case count is null, a new connection will be
1190
// recreated just after
1191
if (count >= 0) {
1192            if (count > MAX_REMOVE_FREELIST) {
1193                count = MAX_REMOVE_FREELIST;
1194            }
1195            for (Iterator JavaDoc i = freeList.iterator(); i.hasNext();) {
1196                JManagedConnection mc = (JManagedConnection) i.next();
1197                if (mc.isAged()) {
1198                    logger.debug("remove a timed out connection");
1199                    i.remove();
1200                    destroyItem(mc);
1201                    count--;
1202                    if (count <= 0) {
1203                        break;
1204                    }
1205                }
1206            }
1207        }
1208        recomputeBusy();
1209
1210        // Close (physically) connections lost (opened for too long time)
1211
for (Iterator JavaDoc i = mcList.iterator(); i.hasNext();) {
1212            JManagedConnection mc = (JManagedConnection) i.next();
1213            if (mc.inactive()) {
1214                if (logger.isWarnEnabled()) {
1215                    logger.warn("close a timed out open connection {0}", mc.getIdentifier());
1216                }
1217                i.remove();
1218                // destroy mc
1219
mc.remove();
1220                connectionLeaks++;
1221                // Notify 1 thread waiting for a Connection.
1222
if (currentWaiters > 0) {
1223                    notify();
1224                }
1225            }
1226        }
1227
1228        // Shrink the pool in case of max pool size
1229
// This occurs when max pool size has been reduced by admin console.
1230
if (poolMax != NO_LIMIT) {
1231            while (freeList.size() > poolMin && mcList.size() > poolMax) {
1232                JManagedConnection mc = freeList.first();
1233                freeList.remove(mc);
1234                destroyItem(mc);
1235            }
1236        }
1237        recomputeBusy();
1238
1239        // Recreate more Connections while poolMin is not reached
1240
while (mcList.size() < poolMin) {
1241            JManagedConnection mc = null;
1242            try {
1243                mc = (JManagedConnection) getXAConnection();
1244                openedCount++;
1245            } catch (SQLException JavaDoc e) {
1246                throw new IllegalStateException JavaDoc("Could not create " + poolMin + " mcs in the pool : ", e);
1247            }
1248            // tx = null. Assumes maxage already configured.
1249
freeList.add(mc);
1250            mcList.add(mc);
1251            mc.addConnectionEventListener(this);
1252        }
1253    }
1254
1255    /**
1256     * Lookup connection in the pool for this user/tx.
1257     * @param user user name
1258     * @param tx Transaction the connection is involved
1259     * @return a free JManagedConnection (never null)
1260     * @throws SQLException Cannot open a connection because the pool's max size
1261     * is reached
1262     */

1263    @SuppressWarnings JavaDoc("boxing")
1264    public synchronized JManagedConnection openConnection(final String JavaDoc user, final Transaction JavaDoc tx) throws SQLException JavaDoc {
1265        JManagedConnection mc = null;
1266        // If a Connection exists already for this tx, just return it.
1267
// If no transaction, never reuse a connection already used.
1268
if (tx != null) {
1269            mc = tx2mc.get(tx);
1270            if (mc != null) {
1271                logger.debug("Reuse a Connection for same tx");
1272                mc.hold();
1273                servedOpen++;
1274                return mc;
1275            }
1276        }
1277        // Loop until a valid mc is found
1278
long timetowait = waiterTimeout;
1279        long starttime = 0;
1280        while (mc == null) {
1281            // try to find an mc in the free list
1282
if (freeList.isEmpty()) {
1283                // In case we have reached the maximum limit of the pool,
1284
// we must wait until a connection is released.
1285
if (mcList.size() >= poolMax) {
1286                    boolean stoplooping = true;
1287                    // If a timeout has been specified, wait, unless maxWaiters
1288
// is reached.
1289
if (timetowait > 0) {
1290                        if (currentWaiters < maxWaiters) {
1291                            currentWaiters++;
1292                            // Store the maximum concurrent waiters
1293
if (waiterCount < currentWaiters) {
1294                                waiterCount = currentWaiters;
1295                            }
1296                            if (starttime == 0) {
1297                                starttime = System.currentTimeMillis();
1298                                logger.debug("Wait for a free Connection, {0}", mcList.size());
1299                            }
1300                            try {
1301                                wait(timetowait);
1302                            } catch (InterruptedException JavaDoc ign) {
1303                                logger.warn("Interrupted");
1304                            } finally {
1305                                currentWaiters--;
1306                            }
1307                            long stoptime = System.currentTimeMillis();
1308                            long stillwaited = stoptime - starttime;
1309                            timetowait = waiterTimeout - stillwaited;
1310                            stoplooping = (timetowait <= 0);
1311                            if (stoplooping) {
1312                                // We have been waked up by the timeout.
1313
totalWaiterCount++;
1314                                totalWaitingTime += stillwaited;
1315                                if (waitingTime < stillwaited) {
1316                                    waitingTime = stillwaited;
1317                                }
1318                            } else {
1319                                if (!freeList.isEmpty() || mcList.size() < poolMax) {
1320                                    // We have been notified by a connection
1321
// released.
1322
logger.debug("Notified after {0}", stillwaited);
1323                                    totalWaiterCount++;
1324                                    totalWaitingTime += stillwaited;
1325                                    if (waitingTime < stillwaited) {
1326                                        waitingTime = stillwaited;
1327                                    }
1328                                }
1329                                continue;
1330                            }
1331                        }
1332                    }
1333                    if (stoplooping && freeList.isEmpty() && mcList.size() >= poolMax) {
1334                        if (starttime > 0) {
1335                            rejectedTimeout++;
1336                            logger.warn("Cannot create a Connection - timeout");
1337                        } else {
1338                            rejectedFull++;
1339                            logger.warn("Cannot create a Connection");
1340                        }
1341                        throw new SQLException JavaDoc("No more connections in " + getDatasourceName());
1342                    }
1343                    continue;
1344                }
1345                logger.debug("empty free list: Create a new Connection");
1346                try {
1347                    // create a new XA Connection
1348
mc = (JManagedConnection) getXAConnection();
1349                    openedCount++;
1350                } catch (SQLException JavaDoc e) {
1351                    connectionFailures++;
1352                    rejectedOther++;
1353                    logger.warn("Cannot create new Connection for tx", e);
1354                    throw e;
1355                }
1356                // Register the connection manager as a ConnectionEventListener
1357
mc.addConnectionEventListener(this);
1358                mcList.add(mc);
1359            } else {
1360                mc = freeList.last();
1361                freeList.remove(mc);
1362                // Check the connection before reusing it
1363
if (checkLevel > 0) {
1364                    try {
1365                        JConnection conn = (JConnection) mc.getConnection();
1366                        if (conn.isPhysicallyClosed()) {
1367                            logger.warn("The JDBC connection has been closed!");
1368                            destroyItem(mc);
1369                            starttime = 0;
1370                            mc = null;
1371                            continue;
1372                        }
1373                        if (checkLevel > 1) {
1374                            java.sql.Statement JavaDoc stmt = conn.createStatement();
1375                            stmt.execute(testStatement);
1376                            stmt.close();
1377                        }
1378                    } catch (Exception JavaDoc e) {
1379                        logger.error("DataSource " + getDatasourceName() + " error: removing invalid mc", e);
1380                        destroyItem(mc);
1381                        starttime = 0;
1382                        mc = null;
1383                        continue;
1384                    }
1385                }
1386            }
1387        }
1388        recomputeBusy();
1389        mc.setTx(tx);
1390        if (tx == null) {
1391            logger.debug("Got a Connection - no TX: ");
1392        } else {
1393            logger.debug("Got a Connection for TX: ");
1394            // register synchronization
1395
try {
1396                tx.registerSynchronization(mc);
1397                tx2mc.put(tx, mc); // only if registerSynchronization was OK.
1398
} catch (javax.transaction.RollbackException JavaDoc e) {
1399                // / optimization is probably possible at this point
1400
logger.warn("DataSource " + getDatasourceName() + " error: Pool mc registered, but tx is rollback only", e);
1401            } catch (javax.transaction.SystemException JavaDoc e) {
1402                logger.error("DataSource " + getDatasourceName() + " error in pool: system exception from transaction manager ",
1403                        e);
1404            } catch (IllegalStateException JavaDoc e) {
1405                // In case transaction has already committed, do as if no tx.
1406
logger.warn("Got a Connection - committed TX: ", e);
1407                mc.setTx(null);
1408            }
1409        }
1410        mc.hold();
1411        servedOpen++;
1412        return mc;
1413    }
1414
1415    /**
1416     * The transaction has committed (or rolled back). We can return its
1417     * connections to the pool of available connections.
1418     * @param tx the non null transaction
1419     */

1420    public synchronized void freeConnections(final Transaction JavaDoc tx) {
1421        logger.debug("free connection for Tx = " + tx);
1422        JManagedConnection mc = tx2mc.remove(tx);
1423        if (mc == null) {
1424            logger.error("pool: no connection found to free for Tx = " + tx);
1425            return;
1426        }
1427        mc.setTx(null);
1428        if (mc.isOpen()) {
1429            // Connection not yet closed (but committed).
1430
logger.debug("Connection not closed by caller");
1431            return;
1432        }
1433        freeItem(mc);
1434    }
1435
1436    /**
1437     * Close all connections in the pool, when server is shut down.
1438     */

1439    public synchronized void closeAllConnection() {
1440        // Close physically all connections
1441
Iterator JavaDoc it = mcList.iterator();
1442        try {
1443            while (it.hasNext()) {
1444                JManagedConnection mc = (JManagedConnection) it.next();
1445                mc.close();
1446            }
1447        } catch (java.sql.SQLException JavaDoc e) {
1448            logger.error("Error while closing a Connection:", e);
1449        }
1450    }
1451
1452    // -----------------------------------------------------------------------
1453
// private methods
1454
// -----------------------------------------------------------------------
1455

1456    /**
1457     * Mark a specific Connection in the pool as closed. If it is no longer
1458     * associated to a Tx, we can free it.
1459     * @param mc XAConnection being closed
1460     * @param flag TMSUCCESS (normal close) or TMFAIL (error) or null if error.
1461     * @return false if has not be closed (still in use)
1462     */

1463    private boolean closeConnection(final JManagedConnection mc, final int flag) {
1464        // The connection will be available only if not associated
1465
// to a transaction. Else, it will be reusable only for the
1466
// same transaction.
1467
if (!mc.release()) {
1468            return false;
1469        }
1470        if (mc.getTx() != null) {
1471            logger.debug("keep connection for same tx");
1472        } else {
1473            freeItem(mc);
1474        }
1475
1476        // delist Resource if in transaction
1477
Transaction JavaDoc tx = null;
1478        try {
1479            tx = tm.getTransaction();
1480        } catch (NullPointerException JavaDoc n) {
1481            // current is null: we are not in EasyBeans Server.
1482
logger.error("Pool: should not be used outside a EasyBeans Server", n);
1483        } catch (SystemException JavaDoc e) {
1484            logger.error("Pool: getTransaction failed:", e);
1485        }
1486        if (tx != null && mc.isClosed()) {
1487            try {
1488                tx.delistResource(mc.getXAResource(), flag);
1489            } catch (Exception JavaDoc e) {
1490                logger.error("Pool: Exception while delisting resource:", e);
1491            }
1492        }
1493        return true;
1494    }
1495
1496    /**
1497     * Free item and return it in the free list.
1498     * @param item The item to be freed
1499     */

1500    @SuppressWarnings JavaDoc("boxing")
1501    private synchronized void freeItem(final JManagedConnection item) {
1502        // Add it to the free list
1503
// Even if maxage is reached, because we avoids going under min pool
1504
// size.
1505
// PoolKeeper will manage aged connections.
1506
freeList.add(item);
1507        if (logger.isDebugEnabled()) {
1508            logger.debug("item added to freeList: " + item.getIdentifier());
1509        }
1510
1511        // Notify 1 thread waiting for a Connection.
1512
if (currentWaiters > 0) {
1513            notify();
1514        }
1515        recomputeBusy();
1516    }
1517
1518    /**
1519     * Destroy an mc because connection closed or error occured.
1520     * @param mc The mc to be destroyed
1521     */

1522    private synchronized void destroyItem(final JManagedConnection mc) {
1523        mcList.remove(mc);
1524        mc.remove();
1525        // Notify 1 thread waiting for a Connection.
1526
if (currentWaiters > 0) {
1527            notify();
1528        }
1529        recomputeBusy();
1530    }
1531
1532    /**
1533     * Check on a connection the test statement.
1534     * @param testStatement the statement to use for test
1535     * @return the test statement if the test succeeded, an error message
1536     * otherwise
1537     * @throws SQLException If an error occured when trying to test (not due to
1538     * the test itself, but to other preliminary or post operation).
1539     */

1540    public String JavaDoc checkConnection(final String JavaDoc testStatement) throws SQLException JavaDoc {
1541        String JavaDoc noError = testStatement;
1542        JManagedConnection mc = null;
1543        boolean jmcCreated = false;
1544        if (!freeList.isEmpty()) {
1545            // find a connection to test in the freeList
1546
Iterator JavaDoc it = freeList.iterator();
1547            while (it.hasNext()) {
1548                mc = (JManagedConnection) it.next();
1549                try {
1550                    JConnection conn = (JConnection) mc.getConnection();
1551                    if (!conn.isPhysicallyClosed()) {
1552                        // ok, we found a connection we can use to test
1553
logger.debug("Use a free JManagedConnection to test with " + testStatement);
1554                        break;
1555                    }
1556                    mc = null;
1557                } catch (SQLException JavaDoc e) {
1558                    // Can't use this connection to test
1559
mc = null;
1560                }
1561            }
1562        }
1563        if (mc == null) {
1564            // try to create mc Connection
1565
logger.debug("Create a JManagedConnection to test with " + testStatement);
1566            Connection JavaDoc conn = null;
1567            try {
1568                conn = DriverManager.getConnection(url, userName, password);
1569            } catch (SQLException JavaDoc e) {
1570                logger.error("Could not get Connection on " + url + ":", e);
1571            }
1572            mc = new JManagedConnection(conn, this);
1573            jmcCreated = true;
1574        }
1575        if (mc != null) {
1576            // Do the test on a the free connection or the created connection
1577
JConnection conn = (JConnection) mc.getConnection();
1578            java.sql.Statement JavaDoc stmt = conn.createStatement();
1579            try {
1580                stmt.execute(testStatement);
1581            } catch (SQLException JavaDoc e) {
1582                // The test fails
1583
return e.getMessage();
1584            }
1585            stmt.close();
1586            if (jmcCreated) {
1587                mc.close();
1588            }
1589        }
1590        return noError;
1591    }
1592
1593    /**
1594     * Sets the transaction managed used by the connections.
1595     * @param tm the transaction manager.
1596     */

1597    protected void setTm(final TransactionManager JavaDoc tm) {
1598        this.tm = tm;
1599    }
1600
1601}
1602
Popular Tags