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
 *    Release: @release@
9
 *
10
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
29
package edu.ucsb.nceas.metacat;
30
31
import java.io.*;
32
import java.util.Vector;
33 1089 tao
import java.lang.*;
34 1087 tao
import java.sql.*;
35
import java.util.Stack;
36
import java.util.Hashtable;
37
import java.util.Enumeration;
38
39
/**
40
 * A class represent a DBConnection pool. Another user can use the
41
 * object to initial a connection pool, get db connection or return it.
42
 * This a singleton class, this means only one instance of this class could
43
 * be in the program at one time.
44
 */
45
public class DBConnectionPool
46
{
47 1089 tao
48 1087 tao
  //static attributes
49
  private static DBConnectionPool instance;
50
  private static Vector connectionPool;
51
52 1089 tao
  //maximum connection number in the connection pool
53
  final static int MAXIMUMCONNECTIONNUMBER=
54 1087 tao
                  Integer.parseInt(MetaCatUtil.getOption("maximumConnections"));
55 1089 tao
  //inintila connection number int the connection pool
56
  final static int INITIALCONNECTIONNUMBER=
57 1087 tao
                  Integer.parseInt(MetaCatUtil.getOption("initialConnections"));
58 1089 tao
  //the number to increase connection pool size
59
  final static int INCREASECONNECTIONNUMBER=
60
                Integer.parseInt(MetaCatUtil.getOption("incrementConnections"));
61
  //maximum age for a connection (in milli seconds)
62
  final static long MAXIMUMAGE =
63
                  Long.parseLong(MetaCatUtil.getOption("maximumConnectionAge"));
64
  //maximum connection time for a connection ( in milli second)
65
  final static long MAXIMUMCONNECTIONTIME =
66
                 Long.parseLong(MetaCatUtil.getOption("maximumConnectionTime"));
67
  //maximum number for using a connection.
68
  final static int MAXIMUMUSAGENUMBER =
69
                  Integer.parseInt(MetaCatUtil.getOption("maximumUsageNumber"));
70
71
72
  final static int FREE = 0; //status of a connection
73
  final static int BUSY = 1; //statis of a connection
74 1087 tao
  /**
75
   * Returns the single instance, creating one if it's the
76
   * first time this method is called.
77
   */
78
  static synchronized public DBConnectionPool getInstance()
79 1089 tao
                                 throws SQLException
80 1087 tao
  {
81
    if (instance == null)
82
    {
83
      instance = new DBConnectionPool();
84
    }
85
    return instance;
86
  }//getInstance
87 1089 tao
88
  /**
89
   * Method to get the size of DBConnectionPool
90
   */
91
  public int getSizeOfDBConnectionPool()
92
  {
93
    return connectionPool.size();
94
  }
95 1087 tao
96
  /**
97
   * This is a private constructor since it is singleton
98
   */
99
100 1089 tao
  private DBConnectionPool()  throws SQLException
101 1087 tao
  {
102 1089 tao
103
    initialDBConnectionPool();
104 1087 tao
  }//DBConnection
105
106
  /**
107
   * Method to initial a pool of DBConnection objects
108
   */
109 1089 tao
  private Vector initialDBConnectionPool() throws SQLException
110 1087 tao
 {
111
112
    DBConnection dbConn = null;
113
114 1089 tao
    for ( int i = 0; i < INITIALCONNECTIONNUMBER; i++ )
115 1087 tao
    {
116
      //create a new object of DBConnection
117 1089 tao
      //this DBConnection object has a new connection in it
118
      //it automatically generate the createtime and tag
119 1087 tao
      dbConn = new DBConnection();
120
      //put DBConnection into vetor
121
      connectionPool.add(dbConn);
122
    }
123
124
    return connectionPool;
125
  }
126
127 1089 tao
128
129
130
  /**
131
   * Method to get a DBConnection in connection pool
132
   */
133
  public static DBConnection getDBConnection() throws SQLException
134
  {
135
    DBConnection db = null;
136
    //try every DBConnection in the pool
137
    synchronized(connectionPool)
138
    {
139
      for (int i=0; i<connectionPool.size(); i++)
140
      {
141
        db = (DBConnection) connectionPool.elementAt(i);
142
        //check if the connection is free
143
        if (db.getStatus()==FREE)
144
        {
145
          //If this connection is good, return this DBConnection
146
          if (validateDBConnection(db))
147
          {
148
            //set this DBConnection status
149
            db.setStatus(BUSY);
150
            //set check out time
151
            db.setCheckOutTime(System.currentTimeMillis());
152
            //check it out
153
            return db;
154
          }//if
155
          else//The DBConnection has some problem
156
          {
157
            //close this DBConnection
158
            db.close();
159
            //remove it form connection pool
160
            connectionPool.remove(i);
161
            //insert a new DBConnection to same palace
162
            db = new DBConnection();
163
            connectionPool.insertElementAt(db, i);
164
          }//else
165
        }//if
166
      }//for
167
    }//sychronize
168
169
    //if couldn't get a connection, we should increase DBConnection pool
170
    //if the connection pool size is less than maximum connection number
171
    int poolSize = connectionPool.size();
172
    if ( poolSize < MAXIMUMCONNECTIONNUMBER )
173
    {
174
       if ((poolSize+INCREASECONNECTIONNUMBER) < MAXIMUMCONNECTIONNUMBER)
175
       {
176
         //if we can create INCREASECONNECTIONNUMBER of new DBConnection
177
         //add to connection pool
178
         for ( int i=0; i<INCREASECONNECTIONNUMBER; i++)
179
         {
180
           DBConnection dbConn = new DBConnection();
181
           connectionPool.add(dbConn);
182
         }//for
183
       }//if
184
       else
185
       {
186
         //There is no enough room to increase INCREASECONNECTIONNUMBER
187
         //we create new DBCoonection to Maximum connection number
188
         for (int i= poolSize+1; i<= MAXIMUMCONNECTIONNUMBER; i++)
189
         {
190
           DBConnection dbConn = new DBConnection();
191
           connectionPool.add(dbConn);
192
         }//for
193
       }//else
194
195
    }//if
196
    else
197
    {
198
      throw new SQLException("The maximum of " +MAXIMUMCONNECTIONNUMBER +
199
                            " open db connections is reached." +
200
                            " New db connection to MetaCat" +
201
                            " cannot be established.");
202
    }//else
203
204
    //recursive to get new connection
205
    return getDBConnection();
206
  }//getDBConnection
207 1087 tao
208
209
210 1089 tao
  /**
211
   * Method to check if a db connection works fine or not
212
   * Check points include:
213
   * 1. check the usageCount if it is too many
214
   * 2. check the dbconne age if it is too old
215
   * 3. check the connection time if it is too long
216
   * 4. run simple sql query
217
   *
218
   * @param dbConn, the DBConnection object need to check
219
   */
220
  private static boolean validateDBConnection (DBConnection dbConn)
221
  {
222
    Connection conn = null;
223
224
    //Check if the DBConnection usageCount if it is too many
225
    if (dbConn.getUsageCount() >= MAXIMUMUSAGENUMBER )
226
    {
227
      MetaCatUtil.debugMessage("Connection usageCount is too many: "+
228
      dbConn.getUsageCount(), 50);
229
      return false;
230
    }
231
232
    //Check if the DBConnection has too much connection time
233
    if (dbConn.getConnectionTime() >= MAXIMUMCONNECTIONTIME)
234
    {
235
      MetaCatUtil.debugMessage("Connection has too much connection time: "+
236
      dbConn.getConnectionTime(), 50);
237
      return false;
238
    }
239
240
    //Check if the DBConnection is too old
241
    if (dbConn.getAge() >=MAXIMUMAGE)
242
    {
243
      MetaCatUtil.debugMessage("Connection is too old: "+dbConn.getAge(), 50);
244
      return false;
245
    }
246
247
    //Try to run a simple query
248
    conn = dbConn.getConnection();
249
    try
250
    {
251
      long startTime=System.currentTimeMillis();
252
      conn.getMetaData();
253
      long stopTime=System.currentTimeMillis();
254
      //increase one usagecount
255
      dbConn.increaseUsageCount(1);
256
      //increase connection time
257
      dbConn.setConnectionTime(stopTime-startTime);
258 1087 tao
259 1089 tao
    }
260
    catch (Exception e)
261
    {
262
      MetaCatUtil.debugMessage("Error in validateDBConnection: "
263
                                +e.getMessage(), 30);
264
      return false;
265
    }
266
267
    return true;
268
269
  }//validateDBConnection()
270
271 1087 tao
}//DBConnectionPool