Project

General

Profile

1
/**
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: cjones $'
10
 *     '$Date: 2011-06-07 09:53:46 -0700 (Tue, 07 Jun 2011) $'
11
 * '$Revision: 6124 $'
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
package edu.ucsb.nceas.metacat.database;
29

    
30
import java.util.Vector;
31
import java.sql.*;
32

    
33
import org.apache.log4j.Logger;
34

    
35
import edu.ucsb.nceas.metacat.properties.PropertyService;
36
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
37

    
38
/** 
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
public class DBConnectionPool implements Runnable
45
{
46

    
47
  //static attributes
48
  private static DBConnectionPool instance;
49
  private static Vector<DBConnection> connectionPool;
50
  private static Thread runner;
51
  private static int _countOfReachMaximum = 0;
52
  private static Logger logMetacat = Logger.getLogger(DBConnectionPool.class);
53

    
54
  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
  
64
  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
//		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
		
84
		try {
85
			// maximum connection number in the connection pool
86
			_maxConnNum = Integer.parseInt(PropertyService
87
					.getProperty("database.maximumConnections"));
88
			_initConnNum = Integer.parseInt(PropertyService
89
					.getProperty("database.initialConnections"));
90
			_incrConnNum = Integer.parseInt(PropertyService
91
					.getProperty("database.incrementConnections"));
92
			_maxAge = Integer.parseInt(PropertyService
93
					.getProperty("database.maximumConnectionAge"));
94
			_maxConnTime = Long.parseLong(PropertyService
95
					.getProperty("database.maximumConnectionTime"));
96
			_maxUsageNum = Integer.parseInt(PropertyService
97
					.getProperty("database.maximumUsageNumber"));
98
			_connCountWarnLimit = Integer.parseInt(PropertyService
99
					.getProperty("database.connectionCountWarnLimit"));
100
			_dbConnRecyclThrd = PropertyService
101
					.getProperty("database.runDBConnectionRecycleThread");
102
			_cyclTimeDbConn = Long.parseLong(PropertyService
103
					.getProperty("database.cycleTimeOfDBConnection"));
104
		} catch (PropertyNotFoundException pnfe) {
105
			System.err.println("Could not get property in static block: "
106
					+ pnfe.getMessage());
107
		}
108
		
109
		MAXIMUMCONNECTIONNUMBER = _maxConnNum;
110
		INITIALCONNECTIONNUMBER = _initConnNum;
111
		INCREASECONNECTIONNUMBER = _incrConnNum;
112
		MAXIMUMAGE = _maxAge;
113
		MAXIMUMCONNECTIONTIME = _maxConnTime;
114
		MAXIMUMUSAGENUMBER = _maxUsageNum;
115
		DBCONNECTIONRECYCLETHREAD  = _dbConnRecyclThrd;
116
		CYCLETIMEOFDBCONNECTION = _cyclTimeDbConn;
117
	}
118
  
119
  // the number for trying to check out a connection in the pool in
120
  // getDBConnection method
121
  final static int LIMIT = 2;
122
  
123
  final static int FREE = 0; //status of a connection
124
  final static int BUSY = 1; //status of a connection
125
  /**
126
   * Returns the single instance, creating one if it's the
127
   * first time this method is called.
128
   */
129
  public static synchronized DBConnectionPool getInstance()
130
                                 throws SQLException 
131
  {
132
    if (instance == null) {
133
      instance = new DBConnectionPool();
134
      Logger log = Logger.getLogger(DBConnectionPool.class);
135
      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
    }
144
    return instance;
145
  }
146

    
147

    
148
  /**
149
   * This is a private constructor since it is singleton
150
   */
151
   
152
  private DBConnectionPool()  throws SQLException 
153
  {
154
    connectionPool = new Vector<DBConnection>();
155
    initialDBConnectionPool();
156
    //running the thread to recycle DBConnection
157
    if (DBCONNECTIONRECYCLETHREAD.equals("on"))
158
    {
159
      runner = new Thread(this);
160
      runner.start();
161
    }
162
  }//DBConnection
163

    
164
  /**
165
   * Method to get the size of DBConnectionPool
166
   */
167
  public int getSizeOfDBConnectionPool()
168
  {
169
    return connectionPool.size();
170
  }
171
  
172
  
173
  /**
174
   * Method to initial a pool of DBConnection objects 
175
   */
176
  private void initialDBConnectionPool() throws SQLException 
177
  {
178

    
179
    DBConnection dbConn = null;
180
    
181
    for ( int i = 0; i < INITIALCONNECTIONNUMBER; i++ ) 
182
    {
183
      //create a new object of DBConnection
184
      //this DBConnection object has a new connection in it
185
      //it automatically generate the createtime and tag
186
      dbConn = new DBConnection();
187
      //put DBConnection into vetor
188
      connectionPool.add(dbConn);
189
    }    
190
    
191
  
192
  }//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
 
208
  /**
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
    if (instance == null) {
221
      instance = DBConnectionPool.getInstance();
222
    }
223
    DBConnection db = null;
224
    int random = 0; //random number
225
    int index = 0; //index
226
    int size = 0; //size of connection pool
227
//    logMetacat.debug("DBConnectionPool.getDBConnection - Trying to check out connection...");
228
    size = connectionPool.size();
229
//    logMetacat.debug("DBConnectionPool.getDBConnection - size of connection pool: " + size);
230
    
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
      {
240
        index =(i+random)%size;
241
        db = (DBConnection) connectionPool.elementAt(index);
242
//        logMetacat.debug("DBConnectionPool.getDBConnection - Index: " + index);
243
//        logMetacat.debug("DBConnectionPool.getDBConnection - Tag: " + db.getTag());
244
//        logMetacat.debug("DBConnectionPool.getDBConnection - Status: " + db.getStatus());
245
        //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
            //increase checkout serial number
255
            db.increaseCheckOutSerialNumber(1);
256
            //increase one usageCount
257
            db.increaseUsageCount(1);
258
            //set method name to DBConnection
259
            db.setCheckOutMethodName(methodName);
260
            db.setAutoCommit(true);
261
            //debug message
262
            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
//            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
            
274
            //set check out time
275
            db.setCheckOutTime(System.currentTimeMillis());
276
            // set count of reach maximum 0 because it can check out
277
            _countOfReachMaximum = 0;
278
            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
            connectionPool.remove(index);
286
            //insert a new DBConnection to same palace
287
            db = new DBConnection();
288
            connectionPool.insertElementAt(db, index);
289
          }//else
290
        }//if
291
      }//for
292
    }//for
293
    
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
   
297
    if ( size < MAXIMUMCONNECTIONNUMBER )
298
    {
299
       if ((size + INCREASECONNECTIONNUMBER) < MAXIMUMCONNECTIONNUMBER)
300
       { 
301
         //if we can create INCREASECONNECTIONNUMBER of new DBConnection
302
         //add to connection pool
303
         for ( int i = 0; i < INCREASECONNECTIONNUMBER; i++)
304
         {
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
         for (int i= size+1; i<= MAXIMUMCONNECTIONNUMBER; i++)
314
         {
315
           DBConnection dbConn = new DBConnection();
316
           connectionPool.add(dbConn);
317
         }//for
318
       }//else
319
   
320
    }//if
321
    else
322
    {
323
      /*throw new SQLException("The maximum of " +MAXIMUMCONNECTIONNUMBER + 
324
                            " open db connections is reached." +
325
                            " New db connection to MetaCat" +
326
                            " cannot be established.");*/
327
       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
       {
333
         _countOfReachMaximum =0;
334
         logMetacat.fatal("finally could not get dbconnection");
335
         return null;
336
       }
337
       else
338
       {
339
         //if couldn't get a connection, sleep 20 seconds and try again.
340
         try
341
         {
342
           logMetacat.debug("DBConnectionPool.getDBConnection - sleep 5000ms, could not get dbconnection");
343
           Thread.sleep(5000);
344
         }
345
         catch (Exception e)
346
        {
347
           logMetacat.error("DBConnectionPool.getDBConnection - General exception: " + e.getMessage());
348
        }
349
      }
350
         
351
      
352
    }//else
353
    
354
    //recursive to get new connection    
355
    return getDBConnection(methodName); 
356
  }//getDBConnection
357
 
358
  /** 
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
  {    
370
    //Check if the DBConnection usageCount if it is too many
371
    if (dbConn.getUsageCount() >= MAXIMUMUSAGENUMBER )
372
    {
373
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection usageCount is too high: "+
374
      dbConn.getUsageCount());
375
      return false;
376
    }
377
    
378
    //Check if the DBConnection has too much connection time
379
    if (dbConn.getConnectionTime() >= MAXIMUMCONNECTIONTIME)
380
    {
381
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection has too much connection time: " +
382
    		  dbConn.getConnectionTime());
383
      return false;
384
    }
385
    
386
    //Check if the DBConnection is too old
387
    if (dbConn.getAge() >=MAXIMUMAGE)
388
    {
389
      logMetacat.debug("DBConnectionPool.validateDBConnection - Connection is too old: " + dbConn.getAge());
390
      return false;
391
    }
392
    
393
    //Try to run a simple query
394
    try
395
    {
396
      long startTime=System.currentTimeMillis();
397
      DatabaseMetaData metaData = dbConn.getMetaData();
398
      long stopTime=System.currentTimeMillis();
399
      //increase one usagecount
400
      dbConn.increaseUsageCount(1);
401
      //increase connection time
402
      dbConn.setConnectionTime(stopTime-startTime);
403
  
404
    }
405
    catch (Exception e)
406
    {
407
      logMetacat.error("DBConnectionPool.validateDBConnection - General error:" + e.getMessage());
408
      return false;
409
    }
410
    
411
    return true;
412
    
413
  }//validateDBConnection()
414
  
415
  /**
416
   * Method to return a connection to DBConnection pool.
417
   * @param conn, the Connection object need to check in
418
   */
419
  public static synchronized void returnDBConnection(DBConnection conn, 
420
                                                              int serialNumber)
421
  {
422
    int index = -1;
423
    DBConnection dbConn = null;
424
  
425
    index = getIndexOfPoolForConnection(conn);
426
    if ( index ==-1 )
427
    {
428
//      logMetacat.info("DBConnectionPool.returnDBConnection - Couldn't find a DBConnection in the pool" + 
429
//    		  " which have same tag to the returned DBConnetion object");
430
      return;
431
                                  
432
    }//if
433
    else
434
    {
435
      //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
      //if it is same return it. If it is not same, maybe the connection already
438
      // was returned earlier.
439
//      logMetacat.debug("DBConnectionPool.returnDBConnection - serial number in Connection: " +
440
//              conn.getCheckOutSerialNumber());
441
//      logMetacat.debug("DBConnectionPool.returnDBConnection - serial number in local: " + serialNumber);
442
      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
                          (System.currentTimeMillis()-dbConn.getCheckOutTime());
450
                          
451
        //set check out time to 0
452
        dbConn.setCheckOutTime(0);
453
        
454
//        logMetacat.debug("DBConnectionPool.returnDBConnection - Connection: " + 
455
//        		dbConn.getTag() + " checked in.");
456
//        logMetacat.debug("DBConnectionPool.returnDBConnection - Connection: " +
457
//        		dbConn.getTag() + "'s status: " + dbConn.getStatus());
458
                                                                       
459
      }//if
460
      else
461
      {
462
//        logMetacat.info("DBConnectionPool.returnDBConnection - This DBConnection couldn't return" +
463
//        		dbConn.getTag());
464
      }//else
465
    }//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
    //if conn is null return -1 too
481
    if (conn==null)
482
    {
483
      return -1;
484
    }
485
    //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
    //shut down the background recycle thread
513
    if (DBCONNECTIONRECYCLETHREAD.equals("on"))
514
    {
515
      runner.interrupt();
516
    }
517
    //close every dbconnection in the pool
518
    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
          logMetacat.error("DBConnectionPool.release - Error in release connection: "
530
                                            +e.getMessage());
531
        }//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
          
552
          //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
          {
557
            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
            
562
          }
563
          
564
          //check the validation of free connection in the pool
565
          if (dbConn.getStatus() == FREE)
566
          {
567
            try
568
            {
569
              //try to print out the warning message for every connection
570
              if (dbConn.getWarningMessage()!=null)
571
              {
572
                logMetacat.warn("DBConnectionPool.run - Warning for connection " +
573
                		dbConn.getTag() + " : " + dbConn.getWarningMessage());
574
              }
575
              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
              //check if it is valiate, if not create new one and replace old one
578
              if (!validateDBConnection(dbConn))
579
              {
580
                System.out.println("DB connection is not valid!  Releasing it.");
581
                logMetacat.debug("DBConnectionPool.run - Recyle: " + dbConn.getTag());
582
                //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
                System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@db connection released: " + dbConn.toString());
590
               }//if
591
            }//try
592
            catch (SQLException e)
593
            {
594
              logMetacat.error("DBConnectionPool.run - SQL error: " + e.getMessage());
595
            }//catch
596
            
597
            System.out.println("number of connections in pool: " + connectionPool.size());
598
            System.out.println("connection pool capacity: " + connectionPool.capacity());
599
            
600
          }//if
601
        }//for
602
      }//synchronize   
603
      //Thread sleep 
604
      try
605
      {
606
        Thread.sleep(CYCLETIMEOFDBCONNECTION);
607
      }
608
      catch (Exception e)
609
      {
610
        logMetacat.error("DBConnectionPool.run - General error: " + e.getMessage());
611
      }
612
    }//while
613
  }//run
614
  
615
  /**
616
   * Method to get the number of free DBConnection in DBConnection pool
617
   */
618
  private static synchronized int getFreeDBConnectionNumber()
619
  {
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
  	/**
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
  
676
  /**
677
	 * 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
  public static synchronized boolean shrinkConnectionPoolSize() 
682
  {
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
     boolean hasException = false; //to check if has a exception happened
688
     boolean result = false; //result
689
     DBConnection conn = null; // the dbconnection
690
     connectionPoolSize = connectionPool.size();
691
     freeConnectionSize = getFreeDBConnectionNumber();
692
     difference = connectionPoolSize - freeConnectionSize;
693

    
694
     if(freeConnectionSize < connectionPoolSize){
695
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - " + difference + " connection(s) " +
696
                        "being used and connection pool size is " + connectionPoolSize);
697
     } else {
698
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - Connection pool size: " + connectionPoolSize);
699
    	 logMetacat.info("DBConnectionPool.shrinkConnectionPoolSize - Free Connection number: " + freeConnectionSize);
700
     }
701
     
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
       //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
       {
710
        
711
         //get the dbconnection from pool
712
         conn = (DBConnection) connectionPool.elementAt(i);
713
         
714
         try
715
         {
716
           //close conn
717
           conn.close();
718
         }//try
719
         catch (SQLException e)
720
         { 
721
           // set hadException true
722
           hasException = true;
723
           logMetacat.error("DBConnectionPool.shrinkConnectionPoolSize - SQL Exception: " + e.getMessage());
724
         }//catch
725
                                        
726
        //remove it from pool
727
        connectionPool.remove(i);
728
        // because enter the loop, set result true
729
        result = true;
730
       }//for
731
     }//if
732
     
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
  }//shrinkDBConnectionPoolSize
742
   
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
     int usedConnectionCount = 0; // store the difference number between connection size
753
                         // and free connection
754
    
755
     DBConnection conn = null; // the dbconnection
756
     connectionPoolSize = connectionPool.size();
757
     freeConnectionSize = getFreeDBConnectionNumber();
758
     usedConnectionCount = connectionPoolSize - freeConnectionSize;
759

    
760
     printBusyDBConnections(usedConnectionCount);
761
     
762
     if(freeConnectionSize < connectionPoolSize){
763
         logMetacat.info("DBConnectionPool.shrinkDBConnectionPoolSize - " + usedConnectionCount + " connection(s) " +
764
        		 "being used and connection pool size is " + connectionPoolSize);
765
     } else {
766
         logMetacat.debug("DBConnectionPool.shrinkDBConnectionPoolSize - " + 
767
        		 "Connection pool size: " + connectionPoolSize);
768
         logMetacat.debug("DBConnectionPool.shrinkDBConnectionPoolSize - " + 
769
        		 "Free Connection number: " + freeConnectionSize);
770
     }
771
     
772
     //If all connections are free and connection pool size greater than 
773
     //initial value, shrink connection pool size to intital value
774
     if (usedConnectionCount == 0 && connectionPoolSize > INITIALCONNECTIONNUMBER)
775
     {
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
             logMetacat.error("DBConnectionPool.shrinkDBConnectionPoolSize - SQL error: " + e.getMessage());
795
           }//catch
796
        
797
           //remove it from pool
798
           connectionPool.remove(i);
799
         }//if
800
       
801
       }//for
802
     }//if
803
     
804
    
805
  }//shrinkDBConnectionPoolSize
806
   
807
  
808
}//DBConnectionPool
(2-2/4)