Project

General

Profile

1 1087 tao
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class represent a DBConnection pool. Another user can use the
4
 *    object to initial a connection pool, get db connection or return it.
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jing Tao
8
 *
9
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27
28 5015 daigle
package edu.ucsb.nceas.metacat.database;
29 1087 tao
30
import java.util.Vector;
31
import java.sql.*;
32
33 2663 sgarg
import org.apache.log4j.Logger;
34
35 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
36 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
37
38 1087 tao
/**
39
 * A class represent a DBConnection pool. Another user can use the
40
 * object to initial a connection pool, get db connection or return it.
41
 * This a singleton class, this means only one instance of this class could
42
 * be in the program at one time.
43
 */
44 1092 tao
public class DBConnectionPool implements Runnable
45 1087 tao
{
46 1089 tao
47 1087 tao
  //static attributes
48
  private static DBConnectionPool instance;
49 5168 daigle
  private static Vector<DBConnection> connectionPool;
50 1092 tao
  private static Thread runner;
51 5168 daigle
  private static int _countOfReachMaximum = 0;
52 2663 sgarg
  private static Logger logMetacat = Logger.getLogger(DBConnectionPool.class);
53
54 5168 daigle
  private static int _maxConnNum;
55
  private static int _initConnNum;
56
  private static int _incrConnNum;
57
  private static long _maxAge;
58
  private static long _maxConnTime;
59
  private static int _maxUsageNum;
60
  private static int _connCountWarnLimit;
61
  private static String _dbConnRecyclThrd;
62
  private static long _cyclTimeDbConn;
63 1092 tao
64 4080 daigle
  final static int MAXIMUMCONNECTIONNUMBER;
65
  final static int INITIALCONNECTIONNUMBER;
66
  final static int INCREASECONNECTIONNUMBER;
67
  final static long MAXIMUMAGE;
68
  final static long MAXIMUMCONNECTIONTIME;
69
  final static int MAXIMUMUSAGENUMBER;
70
  final static String DBCONNECTIONRECYCLETHREAD ;
71
  final static long CYCLETIMEOFDBCONNECTION;
72
73
  static {
74 5168 daigle
//		int maxConnNum = 0;
75
//		int initConnNum = 0;
76
//		int incrConnNum = 0;
77
//		long maxAge = 0;
78
//		long maxConnTime = 0;
79
//		int maxUsageNum = 0;
80
//		int connCountWarnLevel = 0;
81
//		String dbConnRecyclThrd = null;
82
//		long cyclTimeDbConn = 0;
83 4080 daigle
84
		try {
85
			// maximum connection number in the connection pool
86 5168 daigle
			_maxConnNum = Integer.parseInt(PropertyService
87 4080 daigle
					.getProperty("database.maximumConnections"));
88 5168 daigle
			_initConnNum = Integer.parseInt(PropertyService
89 4080 daigle
					.getProperty("database.initialConnections"));
90 5168 daigle
			_incrConnNum = Integer.parseInt(PropertyService
91 4080 daigle
					.getProperty("database.incrementConnections"));
92 5168 daigle
			_maxAge = Integer.parseInt(PropertyService
93 4184 daigle
					.getProperty("database.maximumConnectionAge"));
94 5168 daigle
			_maxConnTime = Long.parseLong(PropertyService
95 4080 daigle
					.getProperty("database.maximumConnectionTime"));
96 5168 daigle
			_maxUsageNum = Integer.parseInt(PropertyService
97 4080 daigle
					.getProperty("database.maximumUsageNumber"));
98 5168 daigle
			_connCountWarnLimit = Integer.parseInt(PropertyService
99
					.getProperty("database.connectionCountWarnLimit"));
100
			_dbConnRecyclThrd = PropertyService
101 4080 daigle
					.getProperty("database.runDBConnectionRecycleThread");
102 5168 daigle
			_cyclTimeDbConn = Long.parseLong(PropertyService
103 4080 daigle
					.getProperty("database.cycleTimeOfDBConnection"));
104
		} catch (PropertyNotFoundException pnfe) {
105
			System.err.println("Could not get property in static block: "
106
					+ pnfe.getMessage());
107
		}
108
109 5168 daigle
		MAXIMUMCONNECTIONNUMBER = _maxConnNum;
110
		INITIALCONNECTIONNUMBER = _initConnNum;
111
		INCREASECONNECTIONNUMBER = _incrConnNum;
112
		MAXIMUMAGE = _maxAge;
113
		MAXIMUMCONNECTIONTIME = _maxConnTime;
114
		MAXIMUMUSAGENUMBER = _maxUsageNum;
115
		DBCONNECTIONRECYCLETHREAD  = _dbConnRecyclThrd;
116
		CYCLETIMEOFDBCONNECTION = _cyclTimeDbConn;
117 4080 daigle
	}
118
119
  // the number for trying to check out a connection in the pool in
120
  // getDBConnection method
121 1217 tao
  final static int LIMIT = 2;
122 1089 tao
123
  final static int FREE = 0; //status of a connection
124 5168 daigle
  final static int BUSY = 1; //status of a connection
125 1087 tao
  /**
126
   * Returns the single instance, creating one if it's the
127
   * first time this method is called.
128
   */
129 1092 tao
  public static synchronized DBConnectionPool getInstance()
130 1089 tao
                                 throws SQLException
131 1087 tao
  {
132 2250 jones
    if (instance == null) {
133 1087 tao
      instance = new DBConnectionPool();
134 3078 jones
      Logger log = Logger.getLogger(DBConnectionPool.class);
135 5168 daigle
      log.debug("DBConnectionPool.getInstance - MaximumConnectionNumber: " + MAXIMUMCONNECTIONNUMBER);
136
      log.debug("DBConnectionPool.getInstance - Intial connection number: " + INITIALCONNECTIONNUMBER);
137
      log.debug("DBConnectionPool.getInstance - Increated connection Number: " + INCREASECONNECTIONNUMBER);
138
      log.debug("DBConnectionPool.getInstance - Maximum connection age: " + MAXIMUMAGE);
139
      log.debug("DBConnectionPool.getInstance - Maximum connection time: " + MAXIMUMCONNECTIONTIME);
140
      log.debug("DBConnectionPool.getInstance - Maximum usage count: " + MAXIMUMUSAGENUMBER);
141
      log.debug("DBConnectionPool.getInstance - Running recycle thread or not: " + DBCONNECTIONRECYCLETHREAD);
142
      log.debug("DBConnectionPool.getInstance - Cycle time of recycle: " + CYCLETIMEOFDBCONNECTION);
143 1087 tao
    }
144
    return instance;
145 3078 jones
  }
146 1089 tao
147 1092 tao
148 1089 tao
  /**
149 1087 tao
   * This is a private constructor since it is singleton
150
   */
151
152 1089 tao
  private DBConnectionPool()  throws SQLException
153 1087 tao
  {
154 5168 daigle
    connectionPool = new Vector<DBConnection>();
155 1089 tao
    initialDBConnectionPool();
156 1092 tao
    //running the thread to recycle DBConnection
157 1095 tao
    if (DBCONNECTIONRECYCLETHREAD.equals("on"))
158
    {
159
      runner = new Thread(this);
160
      runner.start();
161
    }
162 1087 tao
  }//DBConnection
163 1092 tao
164
  /**
165
   * Method to get the size of DBConnectionPool
166
   */
167
  public int getSizeOfDBConnectionPool()
168
  {
169
    return connectionPool.size();
170
  }
171 1087 tao
172 1092 tao
173 1087 tao
  /**
174
   * Method to initial a pool of DBConnection objects
175
   */
176 1092 tao
  private void initialDBConnectionPool() throws SQLException
177
  {
178 1087 tao
179
    DBConnection dbConn = null;
180
181 1089 tao
    for ( int i = 0; i < INITIALCONNECTIONNUMBER; i++ )
182 1087 tao
    {
183
      //create a new object of DBConnection
184 1089 tao
      //this DBConnection object has a new connection in it
185
      //it automatically generate the createtime and tag
186 1087 tao
      dbConn = new DBConnection();
187
      //put DBConnection into vetor
188
      connectionPool.add(dbConn);
189
    }
190
191
192 1092 tao
  }//initialDBConnectionPool
193
194
  /**
195
   * Method to get Connection object (Not DBConnection)
196
   */
197
  /*public static Connection getConnection() throws SQLException
198
  {
199
    DBConnection dbConn = null;
200
    //get a DBConnection
201
    dbConn = getDBConnection();
202
    //get connection object in DBConnection object
203
    //The following getConnections method is in DBConnection class
204
    return dbConn.getConnections();
205
  }*/
206
207 1089 tao
208 1095 tao
  /**
209
   * Method to get a DBConnection in connection pool
210
   * 1) try to get a DBConnection from DBConnection pool
211
   * 2) if 1) failed, then check the size of pool. If the size reach the
212
   *    maximum number of connection, throw a exception: couldn't get one
213
   * 3) If the size is less than the maximum number of connectio, create some
214
   *    new connections and recursive get one
215
   * @param methodName, the name of method which will check connection out
216
   */
217
  public static synchronized DBConnection getDBConnection(String methodName)
218
                                                throws SQLException
219
  {
220 2250 jones
    if (instance == null) {
221
      instance = DBConnectionPool.getInstance();
222
    }
223 1095 tao
    DBConnection db = null;
224 1217 tao
    int random = 0; //random number
225
    int index = 0; //index
226
    int size = 0; //size of connection pool
227 5319 jones
//    logMetacat.debug("DBConnectionPool.getDBConnection - Trying to check out connection...");
228 1217 tao
    size = connectionPool.size();
229 5319 jones
//    logMetacat.debug("DBConnectionPool.getDBConnection - size of connection pool: " + size);
230 1217 tao
231
     //try every DBConnection in the pool
232
    //every DBConnection will be try LIMITE times
233
    for (int j=0 ; j<LIMIT; j++)
234
    {
235
       //create a random number as the started index for connection pool
236
      //So that the connection ofindex of 0 wouldn't be a the heaviest user
237
      random = (new Double (Math.random()*100)).intValue();
238
      for (int i=0; i<size; i++)
239 1095 tao
      {
240 1217 tao
        index =(i+random)%size;
241
        db = (DBConnection) connectionPool.elementAt(index);
242 5319 jones
//        logMetacat.debug("DBConnectionPool.getDBConnection - Index: " + index);
243
//        logMetacat.debug("DBConnectionPool.getDBConnection - Tag: " + db.getTag());
244
//        logMetacat.debug("DBConnectionPool.getDBConnection - Status: " + db.getStatus());
245 1095 tao
        //check if the connection is free
246
        if (db.getStatus()==FREE)
247
        {
248
          //If this connection is good, return this DBConnection
249
          if (validateDBConnection(db))
250
          {
251
252
            //set this DBConnection status
253
            db.setStatus(BUSY);
254 1122 tao
            //increase checkout serial number
255
            db.increaseCheckOutSerialNumber(1);
256 1095 tao
            //increase one usageCount
257
            db.increaseUsageCount(1);
258
            //set method name to DBConnection
259
            db.setCheckOutMethodName(methodName);
260 1299 tao
            db.setAutoCommit(true);
261 1095 tao
            //debug message
262 5943 berkley
            logMetacat.debug("DBConnectionPool.getDBConnection - The connection is checked out: " + db.getTag());
263
            logMetacat.debug("DBConnectionPool.getDBConnection - The method for checking is: " + db.getCheckOutMethodName());
264
            logMetacat.debug("DBConnectionPool.getDBConnection - The age is " + db.getAge());
265
            logMetacat.debug("DBConnectionPool.getDBConnection - The usage is " + db.getUsageCount());
266
            logMetacat.debug("DBConnectionPool.getDBConnection - The connection time is: " + db.getConnectionTime());
267
268 5944 berkley
//            System.out.println("DBConnectionPool.getDBConnection - The connection is checked out: " + db.getTag());
269
//            System.out.println("DBConnectionPool.getDBConnection - The method for checking is: " + db.getCheckOutMethodName());
270
//            System.out.println("DBConnectionPool.getDBConnection - The age is " + db.getAge());
271
//            System.out.println("DBConnectionPool.getDBConnection - The usage is " + db.getUsageCount());
272
//            System.out.println("DBConnectionPool.getDBConnection - The connection time is: " + db.getConnectionTime());
273 5943 berkley
274 1095 tao
            //set check out time
275
            db.setCheckOutTime(System.currentTimeMillis());
276 1849 tao
            // set count of reach maximum 0 because it can check out
277 5168 daigle
            _countOfReachMaximum = 0;
278 1095 tao
            return db;
279
          }//if
280
          else//The DBConnection has some problem
281
          {
282
            //close this DBConnection
283
            db.close();
284
            //remove it form connection pool
285 1217 tao
            connectionPool.remove(index);
286 1095 tao
            //insert a new DBConnection to same palace
287
            db = new DBConnection();
288 1217 tao
            connectionPool.insertElementAt(db, index);
289 1095 tao
          }//else
290
        }//if
291
      }//for
292 1217 tao
    }//for
293 1095 tao
294
    //if couldn't get a connection, we should increase DBConnection pool
295
    //if the connection pool size is less than maximum connection number
296 1217 tao
297
    if ( size < MAXIMUMCONNECTIONNUMBER )
298 1095 tao
    {
299 5168 daigle
       if ((size + INCREASECONNECTIONNUMBER) < MAXIMUMCONNECTIONNUMBER)
300 1095 tao
       {
301
         //if we can create INCREASECONNECTIONNUMBER of new DBConnection
302
         //add to connection pool
303 5168 daigle
         for ( int i = 0; i < INCREASECONNECTIONNUMBER; i++)
304 1095 tao
         {
305
           DBConnection dbConn = new DBConnection();
306
           connectionPool.add(dbConn);
307
         }//for
308
       }//if
309
       else
310
       {
311
         //There is no enough room to increase INCREASECONNECTIONNUMBER
312
         //we create new DBCoonection to Maximum connection number
313 1217 tao
         for (int i= size+1; i<= MAXIMUMCONNECTIONNUMBER; i++)
314 1095 tao
         {
315
           DBConnection dbConn = new DBConnection();
316
           connectionPool.add(dbConn);
317
         }//for
318
       }//else
319
320
    }//if
321
    else
322
    {
323 1217 tao
      /*throw new SQLException("The maximum of " +MAXIMUMCONNECTIONNUMBER +
324 1095 tao
                            " open db connections is reached." +
325
                            " New db connection to MetaCat" +
326 1217 tao
                            " cannot be established.");*/
327 5168 daigle
       logMetacat.fatal("DBConnectionPool.getDBConnection - The maximum of " + MAXIMUMCONNECTIONNUMBER +
328
    		" open db connections is reached. New db connection to MetaCat" +
329
       		" cannot be established.");
330
       _countOfReachMaximum ++;
331
       if (_countOfReachMaximum >= 10)
332 1217 tao
       {
333 5168 daigle
         _countOfReachMaximum =0;
334 2663 sgarg
         logMetacat.fatal("finally could not get dbconnection");
335 1849 tao
         return null;
336 1217 tao
       }
337 1849 tao
       else
338 1217 tao
       {
339 1849 tao
         //if couldn't get a connection, sleep 20 seconds and try again.
340
         try
341
         {
342 5168 daigle
           logMetacat.debug("DBConnectionPool.getDBConnection - sleep 5000ms, could not get dbconnection");
343 1849 tao
           Thread.sleep(5000);
344
         }
345
         catch (Exception e)
346
        {
347 5168 daigle
           logMetacat.error("DBConnectionPool.getDBConnection - General exception: " + e.getMessage());
348 1849 tao
        }
349
      }
350 1217 tao
351 1095 tao
352 1089 tao
    }//else
353
354
    //recursive to get new connection
355 1217 tao
    return getDBConnection(methodName);
356 1089 tao
  }//getDBConnection
357 1217 tao
358 1089 tao
  /**
359
   * Method to check if a db connection works fine or not
360
   * Check points include:
361
   * 1. check the usageCount if it is too many
362
   * 2. check the dbconne age if it is too old
363
   * 3. check the connection time if it is too long
364
   * 4. run simple sql query
365
   *
366
   * @param dbConn, the DBConnection object need to check
367
   */
368
  private static boolean validateDBConnection (DBConnection dbConn)
369 5168 daigle
  {
370 1089 tao
    //Check if the DBConnection usageCount if it is too many
371
    if (dbConn.getUsageCount() >= MAXIMUMUSAGENUMBER )
372
    {
373 5168 daigle
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection usageCount is too high: "+
374 2663 sgarg
      dbConn.getUsageCount());
375 1089 tao
      return false;
376
    }
377
378
    //Check if the DBConnection has too much connection time
379
    if (dbConn.getConnectionTime() >= MAXIMUMCONNECTIONTIME)
380
    {
381 5168 daigle
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection has too much connection time: " +
382
    		  dbConn.getConnectionTime());
383 1089 tao
      return false;
384
    }
385
386
    //Check if the DBConnection is too old
387
    if (dbConn.getAge() >=MAXIMUMAGE)
388
    {
389 5168 daigle
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection is too old: " + dbConn.getAge());
390 1089 tao
      return false;
391
    }
392
393
    //Try to run a simple query
394
    try
395
    {
396
      long startTime=System.currentTimeMillis();
397 1217 tao
      DatabaseMetaData metaData = dbConn.getMetaData();
398 1089 tao
      long stopTime=System.currentTimeMillis();
399
      //increase one usagecount
400
      dbConn.increaseUsageCount(1);
401
      //increase connection time
402
      dbConn.setConnectionTime(stopTime-startTime);
403 1087 tao
404 1089 tao
    }
405
    catch (Exception e)
406
    {
407 5168 daigle
      logMetacat.error("DBConnectionPool.validateDBConnection - General error:" + e.getMessage());
408 1089 tao
      return false;
409
    }
410
411
    return true;
412
413
  }//validateDBConnection()
414
415 1092 tao
  /**
416
   * Method to return a connection to DBConnection pool.
417
   * @param conn, the Connection object need to check in
418
   */
419 1122 tao
  public static synchronized void returnDBConnection(DBConnection conn,
420
                                                              int serialNumber)
421 1092 tao
  {
422
    int index = -1;
423
    DBConnection dbConn = null;
424
425
    index = getIndexOfPoolForConnection(conn);
426
    if ( index ==-1 )
427
    {
428 5319 jones
//      logMetacat.info("DBConnectionPool.returnDBConnection - Couldn't find a DBConnection in the pool" +
429
//    		  " which have same tag to the returned DBConnetion object");
430 1092 tao
      return;
431
432
    }//if
433
    else
434
    {
435 5168 daigle
      //check the parameter - serialNumber which will be keep in calling method
436
      //if it is as same as the object's checkout serial number.
437 1122 tao
      //if it is same return it. If it is not same, maybe the connection already
438 5168 daigle
      // was returned earlier.
439 5319 jones
//      logMetacat.debug("DBConnectionPool.returnDBConnection - serial number in Connection: " +
440
//              conn.getCheckOutSerialNumber());
441
//      logMetacat.debug("DBConnectionPool.returnDBConnection - serial number in local: " + serialNumber);
442 1122 tao
      if (conn.getCheckOutSerialNumber() == serialNumber)
443
      {
444
        dbConn = (DBConnection) connectionPool.elementAt(index);
445
        //set status to free
446
        dbConn.setStatus(FREE);
447
        //count connection time
448
        dbConn.setConnectionTime
449 1092 tao
                          (System.currentTimeMillis()-dbConn.getCheckOutTime());
450 1095 tao
451 1122 tao
        //set check out time to 0
452
        dbConn.setCheckOutTime(0);
453 1217 tao
454 5319 jones
//        logMetacat.debug("DBConnectionPool.returnDBConnection - Connection: " +
455
//        		dbConn.getTag() + " checked in.");
456
//        logMetacat.debug("DBConnectionPool.returnDBConnection - Connection: " +
457
//        		dbConn.getTag() + "'s status: " + dbConn.getStatus());
458 1217 tao
459 1122 tao
      }//if
460 1217 tao
      else
461
      {
462 5319 jones
//        logMetacat.info("DBConnectionPool.returnDBConnection - This DBConnection couldn't return" +
463
//        		dbConn.getTag());
464 1217 tao
      }//else
465 1092 tao
    }//else
466
467
468
  }//returnConnection
469
470
  /**
471
   * Given a returned DBConnection, try to find the index of DBConnection object
472
   * in dbConnection pool by comparing DBConnection' tag and conn.toString.
473
   * If couldn't find , -1 will be returned.
474
   * @param conn, the connection need to be found
475
   */
476
  private static synchronized int getIndexOfPoolForConnection(DBConnection conn)
477
  {
478
    int index = -1;
479
    String info = null;
480 1217 tao
    //if conn is null return -1 too
481
    if (conn==null)
482
    {
483
      return -1;
484
    }
485 1092 tao
    //get tag of this returned DBConnection
486
    info = conn.getTag();
487
    //if the tag is null or empty, -1 will be returned
488
    if (info==null || info.equals(""))
489
    {
490
      return index;
491
    }
492
    //compare this info to the tag of every DBConnection in the pool
493
    for ( int i=0; i< connectionPool.size(); i++)
494
    {
495
      DBConnection dbConn = (DBConnection) connectionPool.elementAt(i);
496
      if (info.equals(dbConn.getTag()))
497
      {
498
        index = i;
499
        break;
500
      }//if
501
    }//for
502
503
    return index;
504
  }//getIndexOfPoolForConnection
505
506
  /**
507
   * Method to shut down all connections
508
   */
509
  public static void release()
510
  {
511
512 5168 daigle
    //shut down the background recycle thread
513 1095 tao
    if (DBCONNECTIONRECYCLETHREAD.equals("on"))
514
    {
515
      runner.interrupt();
516
    }
517 5168 daigle
    //close every dbconnection in the pool
518 1092 tao
    synchronized(connectionPool)
519
    {
520
      for (int i=0;i<connectionPool.size();i++)
521
      {
522
        try
523
        {
524
          DBConnection dbConn= (DBConnection) connectionPool.elementAt(i);
525
          dbConn.close();
526
        }//try
527
        catch (SQLException e)
528
        {
529 5168 daigle
          logMetacat.error("DBConnectionPool.release - Error in release connection: "
530 2663 sgarg
                                            +e.getMessage());
531 1092 tao
        }//catch
532
      }//for
533
    }//synchronized
534
  }//release()
535
536
  /**
537
   * periodically to recycle the connection
538
   */
539
  public void run()
540
  {
541
    DBConnection dbConn = null;
542
    //keep the thread running
543
    while (true)
544
    {
545
      //check every dbconnection in the pool
546
      synchronized(connectionPool)
547
      {
548
        for (int i=0; i<connectionPool.size(); i++)
549
        {
550
          dbConn = (DBConnection) connectionPool.elementAt(i);
551 1095 tao
552 1122 tao
          //if a DBConnection conncectioning time for one check out is greater
553
          //than 30000 milliseconds print it out
554
          if (dbConn.getStatus()==BUSY &&
555
            (System.currentTimeMillis()-dbConn.getCheckOutTime())>=30000)
556 1095 tao
          {
557 5168 daigle
            logMetacat.fatal("DBConnectionPool.run - This DBConnection is checked out for: " +
558
            		(System.currentTimeMillis()-dbConn.getCheckOutTime())/1000 + " secs");
559
            logMetacat.fatal("DBConnectionPool.run - " + dbConn.getTag());
560
            logMetacat.error("DBConnectionPool.run - method: " + dbConn.getCheckOutMethodName());
561 1095 tao
562
          }
563
564
          //check the validation of free connection in the pool
565 1092 tao
          if (dbConn.getStatus() == FREE)
566
          {
567
            try
568
            {
569
              //try to print out the warning message for every connection
570 1122 tao
              if (dbConn.getWarningMessage()!=null)
571
              {
572 5168 daigle
                logMetacat.warn("DBConnectionPool.run - Warning for connection " +
573
                		dbConn.getTag() + " : " + dbConn.getWarningMessage());
574 1122 tao
              }
575 5933 berkley
              logMetacat.info("Checking if the db connection " + dbConn.toString() + " is valid according to metacat.properties parameters.");
576
              System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Checking if the db connection " + dbConn.toString() + " is valid according to metacat.properties parameters.");
577 1092 tao
              //check if it is valiate, if not create new one and replace old one
578
              if (!validateDBConnection(dbConn))
579
              {
580 5933 berkley
                System.out.println("DB connection is not valid!  Releasing it.");
581 5168 daigle
                logMetacat.debug("DBConnectionPool.run - Recyle: " + dbConn.getTag());
582 1092 tao
                //close this DBConnection
583
                dbConn.close();
584
                //remove it form connection pool
585
                connectionPool.remove(i);
586
                //insert a new DBConnection to same palace
587
                dbConn = new DBConnection();
588
                connectionPool.insertElementAt(dbConn, i);
589 5933 berkley
                System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@db connection released: " + dbConn.toString());
590 1122 tao
               }//if
591 1092 tao
            }//try
592
            catch (SQLException e)
593
            {
594 5168 daigle
              logMetacat.error("DBConnectionPool.run - SQL error: " + e.getMessage());
595 1092 tao
            }//catch
596 5933 berkley
597
            System.out.println("number of connections in pool: " + connectionPool.size());
598
            System.out.println("connection pool capacity: " + connectionPool.capacity());
599
600 1092 tao
          }//if
601
        }//for
602
      }//synchronize
603 1095 tao
      //Thread sleep
604 1092 tao
      try
605
      {
606 1095 tao
        Thread.sleep(CYCLETIMEOFDBCONNECTION);
607 1092 tao
      }
608
      catch (Exception e)
609
      {
610 5168 daigle
        logMetacat.error("DBConnectionPool.run - General error: " + e.getMessage());
611 1092 tao
      }
612
    }//while
613
  }//run
614
615 1217 tao
  /**
616
   * Method to get the number of free DBConnection in DBConnection pool
617
   */
618 5168 daigle
  private static synchronized int getFreeDBConnectionNumber()
619 1217 tao
  {
620
    int numberOfFreeDBConnetion = 0; //return number
621
    DBConnection db = null; //single DBconnection
622
    int poolSize = 0; //size of connection pool
623
    //get the size of DBConnection pool
624
    poolSize = connectionPool.size();
625
    //Check every DBConnection in the pool
626
    for ( int i=0; i<poolSize; i++)
627
    {
628
629
      db = (DBConnection) connectionPool.elementAt(i);
630
      //check the status of db. If it is free, count it
631
      if (db.getStatus() == FREE)
632
      {
633
        numberOfFreeDBConnetion++;
634
      }//if
635
    }//for
636
    //return the count result
637
    return numberOfFreeDBConnetion;
638
  }//getFreeDBConnectionNumber
639
640 5168 daigle
  	/**
641
	 * Print a list of busy connections. This method should be called when the
642
	 * used connection count exceeds the _connCountWarnLimit set in
643
	 * metacat.properties.
644
	 *
645
	 * @param usedConnectionCount
646
	 *            the current count of busy connections
647
	 */
648
	private static void printBusyDBConnections(int usedConnectionCount) {
649
		boolean showCountWarning = usedConnectionCount > _connCountWarnLimit;
650
651
		String warnMessage = "";
652
653
		// Check every DBConnection in the pool
654
		for (DBConnection dbConnection : connectionPool) {
655
			// check the status of db. If it is busy, add it to the message
656
			if (dbConnection.getStatus() == BUSY) {
657
				if (showCountWarning) {
658
					warnMessage += "\n   --- Method: " + dbConnection.getCheckOutMethodName() +
659
						" is using: " + dbConnection.getTag() + " for " + dbConnection.getAge() + " ms ";
660
				}
661
662
				if (dbConnection.getConnectionTime() > _maxConnTime) {
663
					logMetacat.warn("DBConnectionPool.printBusyDBConnections - Excessive connection time, method: " +
664
							dbConnection.getCheckOutMethodName() + " is using: " + dbConnection.getTag() +
665
							" for " + dbConnection.getConnectionTime() + " ms ");
666
				}
667
			}// if
668
		}// for
669
670
		if (showCountWarning) {
671
			logMetacat.warn("DBConnectionPool.printBusyDBConnections - " + usedConnectionCount +
672
					" DB connections currently busy because: " + warnMessage);
673
		}
674
	}
675 1217 tao
676 1219 tao
  /**
677 5168 daigle
	 * Method to decrease dbconnection pool size when all dbconnections are idle
678
	 * If all connections are free and connection pool size greater than initial
679
	 * value, shrink connection pool size to initial value
680
	 */
681 1220 tao
  public static synchronized boolean shrinkConnectionPoolSize()
682 1219 tao
  {
683
     int connectionPoolSize = 0; //store the number of dbconnection pool size
684
     int freeConnectionSize = 0; //store the number of free dbconnection in pool
685
     int difference = 0; // store the difference number between connection size
686
                         // and free connection
687 5168 daigle
     boolean hasException = false; //to check if has a exception happened
688 1220 tao
     boolean result = false; //result
689
     DBConnection conn = null; // the dbconnection
690 1219 tao
     connectionPoolSize = connectionPool.size();
691
     freeConnectionSize = getFreeDBConnectionNumber();
692 2716 sgarg
     difference = connectionPoolSize - freeConnectionSize;
693
694 2714 sgarg
     if(freeConnectionSize < connectionPoolSize){
695 5168 daigle
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - " + difference + " connection(s) " +
696
                        "being used and connection pool size is " + connectionPoolSize);
697 2714 sgarg
     } else {
698 5168 daigle
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - Connection pool size: " + connectionPoolSize);
699
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - Free Connection number: " + freeConnectionSize);
700 2714 sgarg
     }
701 1219 tao
702
     //If all connections are free and connection pool size greater than
703
     //initial value, shrink connection pool size to intital value
704
     if (difference == 0 && connectionPoolSize > INITIALCONNECTIONNUMBER)
705
     {
706 1220 tao
       //db connection having index from  to connectionpoolsize -1
707
       //intialConnectionnumber should be close and remove from pool
708
       for ( int i=connectionPoolSize-1; i >= INITIALCONNECTIONNUMBER ; i--)
709 1219 tao
       {
710 1220 tao
711 1219 tao
         //get the dbconnection from pool
712
         conn = (DBConnection) connectionPool.elementAt(i);
713
714
         try
715
         {
716 1220 tao
           //close conn
717 1219 tao
           conn.close();
718
         }//try
719
         catch (SQLException e)
720 1220 tao
         {
721 5168 daigle
           // set hadException true
722 1220 tao
           hasException = true;
723 5168 daigle
           logMetacat.error("DBConnectionPool.shrinkConnectionPoolSize - SQL Exception: " + e.getMessage());
724 1219 tao
         }//catch
725 1220 tao
726
        //remove it from pool
727
        connectionPool.remove(i);
728 5168 daigle
        // because enter the loop, set result true
729 1220 tao
        result = true;
730 1219 tao
       }//for
731
     }//if
732 1220 tao
733
     //if hasException is true ( there at least once exception happend)
734
     // the result should be false
735
     if (hasException)
736
     {
737
       result =false;
738
     }//if
739
     // return result
740
     return result;
741 1219 tao
  }//shrinkDBConnectionPoolSize
742 1220 tao
743
    /**
744
   * Method to decrease dbconnection pool size when all dbconnections are idle
745
   * If all connections are free and connection pool size greater than
746
   * initial value, shrink connection pool size to intital value
747
   */
748
  public static synchronized void shrinkDBConnectionPoolSize()
749
  {
750
     int connectionPoolSize = 0; //store the number of dbconnection pool size
751
     int freeConnectionSize = 0; //store the number of free dbconnection in pool
752 5168 daigle
     int usedConnectionCount = 0; // store the difference number between connection size
753 1220 tao
                         // and free connection
754
755
     DBConnection conn = null; // the dbconnection
756
     connectionPoolSize = connectionPool.size();
757
     freeConnectionSize = getFreeDBConnectionNumber();
758 5168 daigle
     usedConnectionCount = connectionPoolSize - freeConnectionSize;
759 2716 sgarg
760 5168 daigle
     printBusyDBConnections(usedConnectionCount);
761
762 2716 sgarg
     if(freeConnectionSize < connectionPoolSize){
763 5168 daigle
         logMetacat.info("DBConnectionPool.shrinkDBConnectionPoolSize - " + usedConnectionCount + " connection(s) " +
764
        		 "being used and connection pool size is " + connectionPoolSize);
765 2716 sgarg
     } else {
766 5168 daigle
         logMetacat.debug("DBConnectionPool.shrinkDBConnectionPoolSize - " +
767
        		 "Connection pool size: " + connectionPoolSize);
768
         logMetacat.debug("DBConnectionPool.shrinkDBConnectionPoolSize - " +
769
        		 "Free Connection number: " + freeConnectionSize);
770 2716 sgarg
     }
771 1219 tao
772 1220 tao
     //If all connections are free and connection pool size greater than
773
     //initial value, shrink connection pool size to intital value
774 5168 daigle
     if (usedConnectionCount == 0 && connectionPoolSize > INITIALCONNECTIONNUMBER)
775 1220 tao
     {
776
       //db connection having index from  to connectionpoolsize -1
777
       //intialConnectionnumber should be close and remove from pool
778
       for ( int i=connectionPoolSize-1; i >= INITIALCONNECTIONNUMBER ; i--)
779
       {
780
781
         //get the dbconnection from pool
782
         conn = (DBConnection) connectionPool.elementAt(i);
783
         //make sure again the DBConnection status is free
784
         if (conn.getStatus()==FREE)
785
         {
786
           try
787
           {
788
             //close conn
789
             conn.close();
790
           }//try
791
           catch (SQLException e)
792
           {
793
794 5168 daigle
             logMetacat.error("DBConnectionPool.shrinkDBConnectionPoolSize - SQL error: " + e.getMessage());
795 1220 tao
           }//catch
796
797
           //remove it from pool
798
           connectionPool.remove(i);
799
         }//if
800
801
       }//for
802
     }//if
803
804
805
  }//shrinkDBConnectionPoolSize
806 1219 tao
807
808 1087 tao
}//DBConnectionPool