KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > knowgate > jdc > JDCConnectionPool


1 /*
2   Copyright (C) 2003 Know Gate S.L. All rights reserved.
3                       C/Oņa, 107 1š2 28050 Madrid (Spain)
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   1. Redistributions of source code must retain the above copyright
10      notice, this list of conditions and the following disclaimer.
11
12   2. The end-user documentation included with the redistribution,
13      if any, must include the following acknowledgment:
14      "This product includes software parts from hipergate
15      (http://www.hipergate.org/)."
16      Alternately, this acknowledgment may appear in the software itself,
17      if and wherever such third-party acknowledgments normally appear.
18
19   3. The name hipergate must not be used to endorse or promote products
20      derived from this software without prior written permission.
21      Products derived from this software may not be called hipergate,
22      nor may hipergate appear in their name, without prior written
23      permission.
24
25   This library is distributed in the hope that it will be useful,
26   but WITHOUT ANY WARRANTY; without even the implied warranty of
27   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28
29   You should have received a copy of hipergate License with this code;
30   if not, visit http://www.hipergate.org or mail to info@hipergate.org
31 */

32
33 package com.knowgate.jdc;
34
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.LinkedList JavaDoc;
38 import java.util.ListIterator JavaDoc;
39 import java.util.Set JavaDoc;
40 import java.util.Vector JavaDoc;
41 import java.util.Enumeration JavaDoc;
42 import java.util.Date JavaDoc;
43 import java.util.ConcurrentModificationException JavaDoc;
44
45 import java.sql.DriverManager JavaDoc;
46 import java.sql.Connection JavaDoc;
47 import java.sql.CallableStatement JavaDoc;
48 import java.sql.PreparedStatement JavaDoc;
49 import java.sql.SQLException JavaDoc;
50 import java.sql.Timestamp JavaDoc;
51 import java.sql.Types JavaDoc.*;
52
53 import com.knowgate.debug.DebugFile;
54
55 /**
56  * <p>Connection pool daemon thread</p>
57  * This thread scans a ConnectionPool every given interval calling
58  * ConnectionPool.reapConnections() for closing unused connections.
59  */

60
61 final class ConnectionReaper extends Thread JavaDoc {
62
63    /**
64     * Reference to reaped connection pool
65     */

66     private JDCConnectionPool pool;
67
68     /**
69      * Used to stop the Connection reaper thread
70      */

71     private boolean keepruning;
72
73    /**
74     * Connection Reaper call interval (default = 5 mins)
75     */

76     private long delay=300000l;
77
78     /**
79      * <p>Constructor</p>
80      * @param forpool JDCConnectionPool
81      */

82     ConnectionReaper(JDCConnectionPool forpool) {
83         pool = forpool;
84         keepruning = true;
85         try {
86           checkAccess();
87           setDaemon(true);
88           setPriority(MIN_PRIORITY);
89         } catch (SecurityException JavaDoc ignore) { }
90     }
91
92     /**
93      * Get connection reaper call interval
94      * @return long Number of miliseconds between reaper calls
95      * @since 3.0
96      */

97     public long getDelay() {
98       return delay;
99     }
100
101     /**
102      * <p>Set connection reaper call interval</p>
103      * The default value is 5 minutes
104      * @param lDelay long Number of miliseconds between reaper calls
105      * @throws IllegalArgumentException if lDelay is less than 1000
106      * @since 3.0
107      */

108     public void setDelay(long lDelay) throws IllegalArgumentException JavaDoc {
109       if (lDelay<1000l)
110         throw new IllegalArgumentException JavaDoc("ConnectionReaper delay cannot be smaller than 1000 miliseconds");
111       delay=lDelay;
112     }
113
114     public void halt() {
115       keepruning=false;
116     }
117
118     /**
119      * Reap connections every n-minutes
120      */

121     public void run() {
122         while (keepruning) {
123            try {
124              sleep(delay);
125            } catch( InterruptedException JavaDoc e) { }
126            pool.reapConnections();
127         } // wend
128
} // run
129
} // ConnectionReaper
130

131 // ---------------------------------------------------------
132

133   /**
134    * <p>JDBC Connection Pool</p>
135    * <p>Implementation of a standard JDBC connection pool.</p>
136    * @version 2.2
137    */

138
139 public final class JDCConnectionPool {
140
141    private Object JavaDoc binding;
142    private Vector JavaDoc connections;
143    private int openconns;
144    private HashMap JavaDoc callers;
145    private String JavaDoc url, user, password;
146    private ConnectionReaper reaper;
147    private LinkedList JavaDoc errorlog;
148
149    /**
150     * Staled connection threshold (10 minutes)
151     * The maximum time that any SQL single statement may last.
152     */

153    private long timeout=600000l;
154
155    /**
156     * Soft limit for maximum open connections
157     */

158    private int poolsize = 32;
159
160    /**
161     * Hard absolute limit for maximum open connections
162     */

163    private int hardlimit = 100;
164
165    // ---------------------------------------------------------
166

167    /**
168     * Constructor
169     * By default, maximum pool size is set to 32,
170     * maximum opened connections is 100,
171     * login timeout is 20 seconds,
172     * connection timeout is 5 minutes.
173     * @param url JDBC URL string
174     * @param user Database user
175     * @param password Password for user
176     */

177
178    public JDCConnectionPool(String JavaDoc url, String JavaDoc user, String JavaDoc password) {
179
180      binding = null;
181
182       if (null==url)
183         throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url cannot be null");
184
185       if (url.length()==0)
186         throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url value not set");
187
188       this.url = url;
189       this.user = user;
190       this.password = password;
191       this.openconns = 0;
192
193       DriverManager.setLoginTimeout(20); // default login timeout = 20 seconds
194

195       connections = new Vector JavaDoc(poolsize<=hardlimit ? poolsize : hardlimit);
196       reaper = new ConnectionReaper(this);
197       reaper.start();
198
199       if (DebugFile.trace) callers = new HashMap JavaDoc(1023);
200
201       errorlog = new LinkedList JavaDoc();
202     }
203
204    // ---------------------------------------------------------
205

206    /**
207     * <p>Constructor</p>
208     * This method sets a default login timeout of 20 seconds
209     * @param bind DBBind owner of the connection pool (may be <b>null</b>)
210     * @param url JDBC URL string
211     * @param user Database user
212     * @param password Password for user
213     * @param maxpoolsize Maximum pool size
214     * @param maxconnections Maximum opened connections
215     * @param connectiontimeout Maximum time that a
216     * @param logintimeout Maximum time, in seconds, to wait for connection
217     * @since v2.2
218     */

219
220    public JDCConnectionPool(Object JavaDoc bind, String JavaDoc url, String JavaDoc user, String JavaDoc password,
221                             int maxpoolsize, int maxconnections,
222                             int logintimeout, long connectiontimeout) {
223
224       binding = bind;
225
226       if (null==url)
227         throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url cannot be null");
228
229       if (url.length()==0)
230         throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url value not set");
231
232       if (maxpoolsize<1)
233         throw new IllegalArgumentException JavaDoc("maxpoolsize must be greater than or equal to 1");
234
235       if (maxconnections<1)
236         throw new IllegalArgumentException JavaDoc("maxpoolsize must be greater than or equal to 1");
237
238       if (maxpoolsize>maxconnections)
239         throw new IllegalArgumentException JavaDoc("maxpoolsize must be less than or equal to maxconnections");
240
241       this.url = url;
242       this.user = user;
243       this.password = password;
244       this.openconns = 0;
245       this.poolsize = maxpoolsize;
246       this.hardlimit = maxconnections;
247       this.timeout = connectiontimeout;
248
249       DriverManager.setLoginTimeout(logintimeout);
250
251       connections = new Vector JavaDoc(poolsize<=hardlimit ? poolsize : hardlimit);
252       reaper = new ConnectionReaper(this);
253       reaper.start();
254
255       if (DebugFile.trace) callers = new HashMap JavaDoc(1023);
256
257       errorlog = new LinkedList JavaDoc();
258    }
259
260    /**
261     * <p>Constructor</p>
262     * This method sets a default login timeout of 20 seconds
263     * @param bind DBBind owner of the connection pool (may be <b>null</b>)
264     * @param url JDBC URL string
265     * @param user Database user
266     * @param password Password for user
267     * @param maxpoolsize Maximum pool size
268     * @param maxconnections Maximum opened connections
269     * @param logintimeout Maximum time, in seconds, to wait for connection
270     * @since v2.2
271     */

272
273    public JDCConnectionPool(Object JavaDoc bind, String JavaDoc url, String JavaDoc user, String JavaDoc password,
274                             int maxpoolsize, int maxconnections,
275                             int logintimeout) {
276      this(bind,url,user,password,maxpoolsize,maxconnections,logintimeout,60000l);
277    }
278
279    // ---------------------------------------------------------
280

281    /**
282     * <p>Constructor</p>
283     * This method sets a default login timeout of 20 seconds
284     * @param bind DBBind owner of the connection pool (may be <b>null</b>)
285     * @param url JDBC URL string
286     * @param user Database user
287     * @param password Password for user
288     * @param maxpoolsize Maximum pool size (Default 32)
289     * @param maxconnections Maximum opened connections (Default 100)
290     */

291    public JDCConnectionPool(Object JavaDoc bind, String JavaDoc url, String JavaDoc user, String JavaDoc password,
292                             int maxpoolsize, int maxconnections) {
293      this(bind,url,user,password,maxpoolsize,maxconnections,20);
294    }
295
296    // ---------------------------------------------------------
297

298    /**
299     * <p>Constructor</p>
300     * @param url JDBC URL string
301     * @param user Database user
302     * @param password Password for user
303     * @param maxpoolsize Maximum pool size (Default 32)
304     * @param maxconnections Maximum opened connections (Default 100)
305     * @param logintimeout Maximum time, in seconds, to wait for connection
306     * @since v2.2
307     */

308
309    public JDCConnectionPool(String JavaDoc url, String JavaDoc user, String JavaDoc password,
310                             int maxpoolsize, int maxconnections,
311                             int logintimeout) {
312
313      binding = null;
314
315      if (null==url)
316        throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url cannot be null");
317
318      if (url.length()==0)
319        throw new IllegalArgumentException JavaDoc("JDCConnectionPool : url value not set");
320
321      if (maxpoolsize<1)
322        throw new IllegalArgumentException JavaDoc("maxpoolsize must be greater than or equal to 1");
323
324      if (maxconnections<1)
325        throw new IllegalArgumentException JavaDoc("maxpoolsize must be greater than or equal to 1");
326
327      if (maxpoolsize>maxconnections)
328        throw new IllegalArgumentException JavaDoc("maxpoolsize must be less than or equal to maxconnections");
329
330      this.url = url;
331      this.user = user;
332      this.password = password;
333      this.openconns = 0;
334      this.poolsize = maxpoolsize;
335      this.hardlimit = maxconnections;
336
337      DriverManager.setLoginTimeout(logintimeout);
338
339      connections = new Vector JavaDoc(poolsize);
340      reaper = new ConnectionReaper(this);
341      reaper.start();
342
343      if (DebugFile.trace) callers = new HashMap JavaDoc(1023);
344
345      errorlog = new LinkedList JavaDoc();
346    }
347
348    // ---------------------------------------------------------
349

350    /**
351     * <p>Constructor</p>
352     * This method sets a default login timeout of 20 seconds
353     * @param url JDBC URL string
354     * @param user Database user
355     * @param password Password for user
356     * @param maxpoolsize Maximum pool size (Default 32)
357     * @param maxconnections Maximum opened connections (Default 100)
358     */

359
360    // ---------------------------------------------------------
361

362    public JDCConnectionPool(String JavaDoc url, String JavaDoc user, String JavaDoc password, int maxpoolsize, int maxconnections) {
363      this(url,user,password,maxpoolsize,maxconnections,20);
364    }
365
366    // ---------------------------------------------------------
367

368    private synchronized void modifyMap (String JavaDoc sCaller, int iAction)
369      throws NullPointerException JavaDoc {
370
371      if (null==callers) callers = new HashMap JavaDoc(1023);
372
373      if (callers.containsKey(sCaller)) {
374        Integer JavaDoc iRefCount = new Integer JavaDoc(((Integer JavaDoc) callers.get(sCaller)).intValue()+iAction);
375        callers.remove(sCaller);
376        callers.put(sCaller, iRefCount);
377        DebugFile.writeln(" " + sCaller + " reference count is " + iRefCount.toString());
378      }
379      else {
380        if (1==iAction) {
381          callers.put(sCaller, new Integer JavaDoc(1));
382          DebugFile.writeln(" " + sCaller + " reference count is 1");
383        }
384        else {
385          DebugFile.writeln(" ERROR: JDCConnectionPool get/close connection mismatch for " + sCaller);
386        }
387      }
388    } // modifyMap
389

390    // ---------------------------------------------------------
391

392    /**
393     * Close all connections and stop connection reaper
394     */

395    public void close() {
396       if (DebugFile.trace) {
397         DebugFile.writeln("Begin ConnectionPool.close()");
398         DebugFile.incIdent();
399       }
400
401      reaper.halt();
402
403      closeConnections();
404
405      if (DebugFile.trace) {
406        DebugFile.decIdent();
407        DebugFile.writeln("End ConnectionPool.close()");
408      }
409    } // close
410

411    // ---------------------------------------------------------
412

413    /**
414     * <p>Get prefered open connections limit</p>
415     * <p>Additional connections beyond PoolSize may be opened but they
416     * will closed inmediately after use and not pooled.<br>The default value is 32.</p>
417     * @return open connections soft limit
418     */

419    public int getPoolSize() {
420      return poolsize;
421    }
422
423    // ---------------------------------------------------------
424

425    /**
426     * <p>Set prefered open connections limit</p>
427     * <p>Additional connections beyond PoolSize may be opened but they
428     * will closed inmediately after use and not pooled.<br>The default value is 32.<br>
429     * Connections not being used can only be in the pool for a maximum of five minutes.<br>
430     * After a connection is not used for over 5 minutes it will be closed so the actual
431     * pool size will eventually go down to zero after a period of inactivity.</p>
432     * @param iPoolSize Maximum pooled connections
433     */

434
435    public void setPoolSize(int iPoolSize) {
436
437      if (iPoolSize>hardlimit)
438        throw new IllegalArgumentException JavaDoc("prefered pool size must be less than or equal to max pool size ");
439
440      reapConnections();
441      poolsize = iPoolSize;
442    }
443
444    // ---------------------------------------------------------
445

446    /**
447     * <p>Set maximum concurrent open connections limit</p>
448     * The default value is 100.<br>
449     * If iMaxConnections is set to zero then the connection pool is effectively
450     * turned off and no pooling occurs.
451     * @param iMaxConnections Absolute maximum for opened connections
452     */

453    public void setMaxPoolSize(int iMaxConnections) {
454
455      if (iMaxConnections==0) {
456        reapConnections();
457        poolsize = hardlimit = 0;
458      } else {
459        if (iMaxConnections<poolsize)
460          throw new IllegalArgumentException JavaDoc("max pool size must be greater than or equal to prefered pool size ");
461
462        reapConnections();
463        hardlimit = iMaxConnections;
464      }
465    }
466
467    // ---------------------------------------------------------
468

469    /**
470     * <p>Absolute maximum allowed for concurrent opened connections.</p>
471     * The default value is 100.
472     */

473    public int getMaxPoolSize() {
474      return hardlimit;
475    }
476
477    /**
478     * <p>Get staled connection threshold</p>
479     * The default value is 600000ms (10 mins.)<br>
480     * This implies that all database operations done using connections
481     * obtained from the pool must be completed before 10 minutes or else
482     * they can be closed by the connection reaper before their normal finish.
483     * @return The maximum amount of time in miliseconds that a JDCConnection
484     * can be opened and not used before considering it staled.
485     */

486    public long getTimeout() {
487      return timeout;
488    }
489
490    // ---------------------------------------------------------
491

492    /**
493     * <p>Set staled connection threshold</p>
494     * @param miliseconds The maximum amount of time in miliseconds that a JDCConnection
495     * can be opened and not used before considering it staled.<BR>
496     * Default value is 600000ms (10 mins.) Minimum value is 1000.
497     * @throws IllegalArgumentException If miliseconds<1000
498     */

499
500    public void setTimeout(long miliseconds)
501      throws IllegalArgumentException JavaDoc {
502
503      if (miliseconds<1000l)
504        throw new IllegalArgumentException JavaDoc("Connection timeout must be at least 1000 miliseconds");
505
506      timeout = miliseconds;
507    }
508
509    /**
510     * Delay betwwen connection reaper executions
511     * @return long Number of miliseconds
512     * @since 3.0
513     */

514    public long getReaperDaemonDelay() {
515      return reaper.getDelay();
516    }
517
518    /**
519     * Set delay betwwen connection reaper executions (default value is 5 mins)
520     * @param lDelayMs long Miliseconds
521     * @throws IllegalArgumentException if lDelayMs is less than 1000
522     * @since 3.0
523     */

524    public void setReaperDaemonDelay(long lDelayMs) throws IllegalArgumentException JavaDoc {
525      reaper.setDelay(lDelayMs);
526    }
527
528    // ---------------------------------------------------------
529

530    /**
531     * Close and remove one connection from the pool
532     * @param conn Connection to close
533     */

534
535    private synchronized void removeConnection(JDCConnection conn) {
536      boolean bClosed;
537      String JavaDoc sCaller = "";
538
539        try {
540          if (DebugFile.trace) logConnection (conn, "removeConnection", "RDBC", null);
541
542          sCaller = conn.getName();
543          if (!conn.isClosed()) conn.getConnection().close();
544          conn.expireLease();
545          if (DebugFile.trace && (null!=sCaller)) modifyMap(sCaller,-1);
546          bClosed = true;
547        }
548        catch (SQLException JavaDoc e) {
549          bClosed = false;
550
551          if (errorlog.size()>100) errorlog.removeFirst();
552          errorlog.addLast(new Date JavaDoc().toString() + " " + sCaller + " Connection.close() " + e.getMessage());
553
554          if (DebugFile.trace) DebugFile.writeln("SQLException at JDCConnectionPool.removeConnection() : " + e.getMessage());
555        }
556
557        if (bClosed) {
558          if (DebugFile.trace) DebugFile.writeln("connections.removeElement(" + String.valueOf(openconns) + ")");
559          connections.removeElement(conn);
560          openconns--;
561        }
562    } // removeConnection()
563

564    // ---------------------------------------------------------
565

566    /**
567     * Called from the connection reaper daemon thread every n-minutes for maintaining the pool clean
568     */

569
570    synchronized void reapConnections() {
571
572       if (DebugFile.trace) {
573         DebugFile.writeln("Begin JDCConnectionPool.reapConnections()");
574         DebugFile.incIdent();
575       }
576
577       long stale = System.currentTimeMillis() - timeout;
578       Enumeration JavaDoc connlist = connections.elements();
579       JDCConnection conn;
580
581       while((connlist != null) && (connlist.hasMoreElements())) {
582           conn = (JDCConnection) connlist.nextElement();
583
584           // Remove each connection that is not in use or
585
// is stalled for more than maximun usage timeout (default 10 mins)
586
if (!conn.inUse())
587             removeConnection(conn);
588           else if (stale>conn.getLastUse()) {
589             if (DebugFile.trace) DebugFile.writeln("Connection "+conn.getName()+" was staled since "+new Date JavaDoc(conn.getLastUse()).toString());
590             if (errorlog.size()>100) errorlog.removeFirst();
591             errorlog.addLast(new Date JavaDoc().toString()+" Connection "+conn.getName()+" was staled since "+new Date JavaDoc(conn.getLastUse()).toString());
592             removeConnection(conn);
593           }
594       } // wend
595

596       if (DebugFile.trace) {
597         DebugFile.decIdent();
598         DebugFile.writeln("End JDCConnectionPool.reapConnections() : " + new Date JavaDoc().toString());
599       }
600    } // reapConnections()
601

602    // ---------------------------------------------------------
603

604    /**
605     * Close all connections from the pool regardless of their current state
606     */

607
608    public void closeConnections() {
609
610      Enumeration JavaDoc connlist;
611
612      if (DebugFile.trace) {
613        DebugFile.writeln("Begin JDCConnectionPool.closeConnections()");
614        DebugFile.incIdent();
615      }
616
617       connlist = connections.elements();
618
619       if (connlist != null) {
620         while (connlist.hasMoreElements()) {
621           removeConnection ((JDCConnection) connlist.nextElement());
622         } // wend
623
} // fi ()
624

625       if (DebugFile.trace) callers.clear();
626
627       connections.clear();
628
629       if (DebugFile.trace) {
630         DebugFile.decIdent();
631         DebugFile.writeln("End JDCConnectionPool.closeConnections() : " + String.valueOf(openconns));
632       }
633
634       openconns = 0;
635    } // closeConnections()
636

637    // ---------------------------------------------------------
638

639    /**
640     * Close connections from the pool not used for a longer time
641     * @return Count of staled connections closed
642     */

643
644    public int closeStaledConnections() {
645
646      JDCConnection conn;
647      Enumeration JavaDoc connlist;
648
649      if (DebugFile.trace) {
650        DebugFile.writeln("Begin JDCConnectionPool.closeStaledConnections()");
651        DebugFile.incIdent();
652      }
653
654      int staled = 0;
655      final long stale = System.currentTimeMillis() - timeout;
656
657      connlist = connections.elements();
658
659       if (connlist != null) {
660         while (connlist.hasMoreElements()) {
661           conn = (JDCConnection) connlist.nextElement();
662           if (stale>conn.getLastUse()) {
663             staled++;
664             removeConnection (conn);
665           }
666         } // wend
667
} // fi ()
668

669       if (DebugFile.trace) {
670         DebugFile.decIdent();
671         DebugFile.writeln("End JDCConnectionPool.closeStaledConnections() : " + String.valueOf(staled));
672       }
673
674       return staled;
675    } // closeStaledConnections()
676

677    // ---------------------------------------------------------
678

679    private static void logConnection(JDCConnection conn, String JavaDoc sName, String JavaDoc cOpCode, String JavaDoc sParams) {
680
681      PreparedStatement JavaDoc oStmt = null;
682      JDCConnection oLogConn = null;
683
684      if (DebugFile.trace) {
685        com.knowgate.dataobjs.DBAudit.log(JDCConnection.IdClass, cOpCode, "", sName, "", 0, "", sParams, "");
686      }
687
688    } // logConnection
689

690    // ---------------------------------------------------------
691

692    /**
693     * Get an array with references to all pooled connections
694     */

695    public synchronized JDCConnection[] getAllConnections() {
696      int iConnections = connections.size();
697      JDCConnection[] aConnections = new JDCConnection[iConnections];
698
699      for (int c=0; c<iConnections; c++)
700        aConnections[c] = (JDCConnection) connections.get(c);
701
702      return aConnections;
703    } // getAllConnections
704

705    // ---------------------------------------------------------
706

707    /**
708     * Get the DBbind object owner of this conenction pool
709     * @return DBBind instance or <b>null</b> if this connection pool has no owner
710     */

711    public Object JavaDoc getDatabaseBinding() {
712      return binding;
713    }
714
715    // ---------------------------------------------------------
716

717    /**
718     * Get a connection from the pool
719     * @param sCaller This is just an information parameter used for open/closed
720     * mismatch tracking and other benchmarking and statistical purposes.
721     * @return Opened JDCConnection
722     * @throws SQLException If getMaxPoolSize() opened connections is reached an
723     * SQLException with SQLState="08004" will be raised upon calling getConnection().<br>
724     * <b>Microsoft SQL Server</b>: Connection reuse requires that SelectMethod=cursor was
725     * specified at connection string.
726     */

727
728    public synchronized JDCConnection getConnection(String JavaDoc sCaller) throws SQLException JavaDoc {
729
730        int i, s;
731        JDCConnection j;
732        Connection JavaDoc c;
733
734        if (DebugFile.trace) {
735          DebugFile.writeln("Begin JDCConnectionPool.getConnection(" + (sCaller!=null ? sCaller : "") + ")");
736          DebugFile.incIdent();
737        }
738
739        if (hardlimit==0) {
740          // If hardlimit==0 Then connection pool is turned off so return a connection
741
// directly from the DriverManager
742

743          c = DriverManager.getConnection(url, user, password);
744          j = new JDCConnection(c,null);
745        } else {
746
747          j = null;
748
749          s = connections.size();
750          for (i = 0; i < s; i++) {
751            j = (JDCConnection) connections.elementAt(i);
752            if (j.lease(sCaller)) {
753              if (DebugFile.trace) {
754                DebugFile.writeln(" JDCConnectionPool hit for (" + url + ", ...) on pooled connection #" + String.valueOf(i));
755                if (sCaller!=null) logConnection (j, sCaller, "ODBC", "hit");
756              }
757              break;
758            }
759            else
760              j = null;
761          } // endfor
762

763          if (null==j) {
764            if (openconns==hardlimit) {
765              if (DebugFile.trace) DebugFile.decIdent();
766              throw new SQLException JavaDoc ("Maximum number of " + String.valueOf(hardlimit) + " concurrent connections exceeded","08004");
767            }
768
769            if (DebugFile.trace) DebugFile.writeln(" DriverManager.getConnection(" + url + ", ...)");
770
771            c = DriverManager.getConnection(url, user, password);
772
773            if (null!=c) {
774              j = new JDCConnection(c, this);
775              j.lease(sCaller);
776
777              if (DebugFile.trace) {
778                DebugFile.writeln(" JDCConnectionPool miss for (" + url + ", ...)");
779                if (sCaller!=null) logConnection (j, sCaller, "ODBC", "miss");
780              }
781
782              connections.addElement(j);
783              c = null;
784            }
785            else {
786              if (DebugFile.trace) DebugFile.writeln("JDCConnectionPool.getConnection() DriverManager.getConnection() returned null value");
787              j = null;
788            }
789
790            if (null!=j) openconns++;
791          } // endif (null==j)
792

793          if (DebugFile.trace ) {
794            if (sCaller!=null) modifyMap(sCaller, 1);
795          } // DebugFile()
796
} // fi (hardlimit==0)
797

798        if (DebugFile.trace ) {
799          DebugFile.decIdent();
800          DebugFile.writeln("End JDCConnectionPool.getConnection()");
801        } // DebugFile()
802

803        return j;
804   } // getConnection()
805

806   // ---------------------------------------------------------
807

808   /**
809    * Get conenction for a server process identifier
810    * @param sPId String Operating system process identifier at server side
811    * @return JDCConnection or <b>null</b> if no connection for such pid was found
812    * @throws SQLException
813    * @since 2.2
814    */

815   public JDCConnection getConnectionForPId(String JavaDoc sPId) throws SQLException JavaDoc {
816     String JavaDoc pid;
817     JDCConnection conn;
818     Enumeration JavaDoc connlist = connections.elements();
819     if (connlist != null) {
820       while(connlist.hasMoreElements()) {
821         conn = (JDCConnection) connlist.nextElement();
822         try {
823           pid = conn.pid();
824         } catch (Exception JavaDoc ignore) { pid=null; }
825         if (sPId.equals(pid))
826           return conn;
827       } // wend
828
} // fi ()
829
return null;
830   } // getConnectionForPId
831

832   // ---------------------------------------------------------
833

834   /**
835    * Return a connection to the pool
836    * @param conn JDCConnection returned to the pool
837    */

838
839    public synchronized void returnConnection(JDCConnection conn) {
840      if (DebugFile.trace) DebugFile.writeln("JDCConnectionPool.returnConnection([JDCConnection])");
841      conn.expireLease();
842    } // returnConnection()
843

844   // ---------------------------------------------------------
845

846   /**
847    * Return a connection to the pool
848    * @param conn JDCConnection returned to the pool
849    * @param sCaller Must be the same String passed as parameter at getConnection()
850    */

851
852    public synchronized void returnConnection(JDCConnection conn, String JavaDoc sCaller) {
853
854       if (DebugFile.trace) {
855         DebugFile.writeln("JDCConnectionPool.returnConnection([JDCConnection], "+sCaller+")");
856         if (sCaller!=null)
857           logConnection (conn, sCaller, "CDBC", null);
858       }
859
860       if (DebugFile.trace) DebugFile.writeln("JDCConnection.expireLease()");
861
862       conn.expireLease();
863
864       if (DebugFile.trace && (null!=sCaller)) modifyMap(sCaller, -1);
865    }
866
867   // ---------------------------------------------------------
868

869   /**
870    * @return Actual connection pool size
871    */

872
873    public synchronized int size() {
874      return openconns;
875    }
876
877    /**
878     * Get information of current activity at database to which this pool is connected
879     * @return JDCActivityInfo
880     * @throws SQLException
881     * @since 3.0
882     */

883    public JDCActivityInfo getActivityInfo() throws SQLException JavaDoc {
884     JDCActivityInfo oInfo;
885     try { oInfo = new JDCActivityInfo(this);
886     } catch (Exception JavaDoc xcpt) {
887       throw new SQLException JavaDoc (xcpt.getMessage());
888     }
889     return oInfo;
890   }
891
892   // ---------------------------------------------------------
893

894   /**
895    * Human readable usage statistics
896    * @return Connection pool usage statistics string
897    * @throws ConcurrentModificationException If pool is modified while iterating
898    * throught connection collection
899    */

900    public String JavaDoc dumpStatistics()
901      throws ConcurrentModificationException JavaDoc {
902      String JavaDoc sDump;
903      String JavaDoc sPId;
904      Object JavaDoc sKey;
905      Object JavaDoc iVal;
906      int iConnOrdinal, iStaled;
907      long stale = System.currentTimeMillis() - timeout;
908
909      if (DebugFile.trace) {
910        DebugFile.writeln("Begin JDCConnectionPool.dumpStatistics()");
911        DebugFile.incIdent();
912      }
913
914      Enumeration JavaDoc connlist = connections.elements();
915      JDCConnection conn;
916
917      sDump = "Maximum Pool Size=" + String.valueOf(poolsize) + "\n";
918      sDump += "Maximum Connections=" + String.valueOf(hardlimit) + "\n";
919      sDump += "Connection Timeout=" + String.valueOf(timeout) + " ms\n";
920      sDump += "Reaper Daemon Delay=" + String.valueOf(getReaperDaemonDelay()) + " ms\n";
921      sDump += "\n";
922
923      iStaled = iConnOrdinal = 0;
924
925      if (connlist != null) {
926        while (connlist.hasMoreElements()) {
927          conn = (JDCConnection) connlist.nextElement();
928
929          if (stale>conn.getLastUse()) iStaled++;
930
931          try {
932            sPId = conn.pid();
933          } catch (Exception JavaDoc ignore) { sPId=null; }
934
935          sDump += "#" + String.valueOf(++iConnOrdinal) + (conn.inUse() ? " in use, " : " vacant, ") + (stale>conn.getLastUse() ? " staled," : " ready,") + (conn.validate() ? "validate=yes" : " validate=no") + ", last use=" + new Date JavaDoc(conn.getLastUse()).toString() + ", caller=" + conn.getName() + (sPId==null ? "" : " pid="+sPId) + "\n";
936        }
937      } // fi ()
938

939      sDump += "\n";
940
941      if (DebugFile.trace) {
942        Iterator JavaDoc oCallersIterator = callers.keySet().iterator();
943
944        while (oCallersIterator.hasNext()) {
945          sKey = oCallersIterator.next();
946          iVal = callers.get(sKey);
947          sDump += sKey + " , " + iVal.toString() + " named open connections\n";
948        }
949        sDump += "\n\n";
950      } // fi (DebugFile.trace)
951

952      sDump += String.valueOf(iStaled) + " staled connections\n";
953
954      sDump += "Actual pool size " + String.valueOf(size()) + "\n\n";
955
956      try {
957        JDCProcessInfo[] oPinfo = getActivityInfo().processesInfo();
958        if (oPinfo!=null) {
959          sDump += "Activity information:\n";
960          for (int p=0; p<oPinfo.length; p++) {
961            sDump += "user "+oPinfo[p].getUserName()+" running process "+oPinfo[p].getProcessId();
962            conn = getConnectionForPId(oPinfo[p].getProcessId());
963            if (conn!=null) {
964              sDump += " on connection "+conn.getName();
965            }
966            if (oPinfo[p].getQueryText().length()>0) {
967              sDump += " for query "+oPinfo[p].getQueryText();
968            }
969            if (oPinfo[p].getQueryStart()!=null) {
970              sDump += " since "+oPinfo[p].getQueryStart().toString();
971            }
972            sDump += "\n";
973          } // next
974
}
975      } catch (Exception JavaDoc xcpt) {
976        sDump += xcpt.getClass().getName()+" trying to get activity information "+xcpt.getMessage()+"\n";
977      }
978
979      sDump += "\n";
980
981      if (errorlog.size()>0) {
982        sDump += "Fatal error log:\n";
983        ListIterator JavaDoc oErrIterator = errorlog.listIterator();
984        while (oErrIterator.hasNext()) sDump += oErrIterator.next()+"\n";
985      } // fi
986

987      if (DebugFile.trace) {
988        DebugFile.decIdent();
989        DebugFile.writeln("End JDCConnectionPool.dumpStatistics()");
990      }
991
992      return sDump;
993    } // dumpStatistics
994

995 } // JDCConnectionPool
996
Popular Tags