001: //** Copyright Statement ***************************************************
002: // The JADE Open Framework
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020: package com.salmonllc.sql;
021:
022: import java.util.*;
023: import java.sql.*;
024:
025: /**
026: * This class represents a list of database connections sharing a common specification. It is used by the system to maintain connection pools.
027: */
028: public class DBConnectionList {
029: Stack _unused = new Stack();
030: DBConnection _first, _last;
031: int _max, _count;
032: long _timeOut, _idleTimeOut;
033: String _DBMS, _driver, _databaseURL, _userID, _password, _dbName;
034: Hashtable _connectionParms;
035:
036: DBConnectionList(int max, long timeOut, long idleTimeout,
037: String DBMS, String jdbcDriver, String databaseURL,
038: String userID, String password, String dbName,
039: String connectionParms) {
040: super ();
041: _max = max;
042: _timeOut = timeOut;
043: _idleTimeOut = idleTimeout;
044: _count = 0;
045: _DBMS = DBMS;
046: _driver = jdbcDriver;
047: _databaseURL = databaseURL;
048: _userID = userID;
049: _password = password;
050: _dbName = dbName;
051: setConnectionParms(connectionParms);
052: }
053:
054: DBConnectionList(int max, long timeOut, long idleTimeout,
055: String DBMS, String jdbcDriver, String databaseURL,
056: String userID, String password, String dbName) {
057: this (max, timeOut, idleTimeout, DBMS, jdbcDriver, databaseURL,
058: userID, password, dbName, null);
059: }
060:
061: /**
062: * This method will remove all idle connections from the connection pool.
063: */
064: public synchronized void clearIdleConnections() throws SQLException {
065: int size = _unused.size();
066: Vector v = new Vector(size);
067: for (int i = 0; i < size; i++) {
068: DBConnection conn = (DBConnection) _unused.pop();
069: if (conn.getJDBCConnection().isClosed()) {
070: _count--;
071: } else if (System.currentTimeMillis() > (conn.getLastUsed() + _idleTimeOut)) {
072: try {
073: _count--;
074: conn.getJDBCConnection().close();
075: } catch (Exception e) {
076: }
077: } else {
078: v.addElement(conn);
079: }
080: }
081:
082: for (int i = 0; i < v.size(); i++) {
083: _unused.push(v.elementAt(i));
084: }
085: }
086:
087: Connection createConnection() throws SQLException {
088: try {
089: Properties JDBCParms = null;
090: Hashtable parms = getConnectionParms();
091: Enumeration enum = parms.keys();
092: while (enum.hasMoreElements()) {
093: String st=(String) enum.nextElement();
094: if (st != null && st.startsWith("JDBC-")) {
095: if (JDBCParms == null) {
096: JDBCParms=new Properties();
097: JDBCParms.setProperty("user",_userID);
098: JDBCParms.setProperty("password",_password);
099: }
100: JDBCParms.setProperty(st.substring(5),(String)parms.get(st));
101: }
102: }
103:
104: Class.forName(_driver);
105: Connection connection=null;
106: if (JDBCParms == null)
107: connection = DriverManager.getConnection(_databaseURL, _userID, _password);
108: else
109: connection = DriverManager.getConnection(_databaseURL,JDBCParms);
110: _count++;
111: return connection;
112: } catch (ClassNotFoundException ex) {
113: throw (new java.sql.SQLException(ex.toString()));
114: } catch (SQLException ex) {
115: throw (ex);
116: }
117: }
118:
119: /**
120: * This method was created in VisualAge.
121: */
122: private void dump(String message) {
123: if (getInUseCount() >= (_max - 2)) {
124: System.err.println("---------------------");
125: //System.err.println(message);
126: //System.err.println("first=" + _first);
127: //System.err.println("last=" + _last);
128: //System.err.println("list=");
129: //DBConnection node = _first;
130: //while (node != null)
131: //{
132: //System.err.println(node);
133: //node = node.getNext();
134:
135: //}
136:
137: System.err.println("IdleCount =" + getIdleCount());
138: System.err.println("InUseCount =" + getInUseCount());
139: System.err.println("Wait Time Out =" + _timeOut);
140: System.err.println("Max =" + _max);
141: System.err.println("---------------------");
142: }
143: }
144:
145: /**
146: * This method was created in VisualAge.
147: * @return com.salmonllc.sql.DBConnection
148: */
149: synchronized void freeConnection(DBConnection conn) {
150: if (conn == null)
151: return;
152:
153: if (!conn.getInUse())
154: return;
155:
156: DBConnection next = conn.getNext();
157: DBConnection prior = conn.getPrior();
158:
159: if (next != null)
160: next.setPrior(prior);
161:
162: if (prior != null)
163: prior.setNext(next);
164:
165: if (conn == _last)
166: _last = prior;
167:
168: if (conn == _first)
169: _first = next;
170:
171: conn.setNext(null);
172: conn.setPrior(null);
173:
174: _unused.push(conn);
175:
176: conn.setLastDuration(System.currentTimeMillis()
177: - conn.getLastUsed());
178: conn.setInUse(false);
179:
180: notifyAll();
181: dump("freeConnection:" + conn);
182: }
183:
184: /**
185: * This method was created in VisualAge.
186: * @return com.salmonllc.sql.DBConnection
187: */
188: synchronized DBConnection getConnection() throws SQLException {
189: DBConnection DBConn = null;
190:
191: if (_unused.isEmpty()) {
192: Connection conn = null;
193: if (_count < _max) {
194: conn = createConnection();
195: DBConn = new DBConnection(conn, _DBMS, false, false);
196: DBConn.setDatabaseDriver(_driver);
197: DBConn.setUserName(_userID);
198: DBConn.setPassword(_password);
199: DBConn.setDatabaseUrl(_databaseURL);
200: DBConn.setCreated(System.currentTimeMillis());
201: } else
202: DBConn = waitForConnection();
203: } else {
204: DBConn = getUnused();
205: }
206:
207: if (_first == null)
208: _first = DBConn;
209: if (_last != null)
210: _last.setNext(DBConn);
211:
212: DBConn.setPrior(_last);
213: DBConn.setNext(null);
214: DBConn.setList(this );
215: DBConn.setInUse(true);
216: DBConn.setLastUsed(System.currentTimeMillis());
217:
218: _last = DBConn;
219:
220: dump("getConnection:" + DBConn);
221:
222: return DBConn;
223: }
224:
225: /**
226: * This method returns an enumeration of all the connections maintained in the list.
227: */
228: public Enumeration getConnections() {
229: Vector v = new Vector(_count);
230: for (int i = 0; i < _unused.size(); i++) {
231: v.addElement(_unused.elementAt(i));
232: }
233:
234: DBConnection node = _first;
235: while (node != null) {
236: v.addElement(node);
237: node = node.getNext();
238: }
239:
240: return v.elements();
241: }
242:
243: /**
244: * This method returns the Database URL for the connection pool.
245: */
246: public String getDatabaseURL() {
247: return _databaseURL;
248: }
249:
250: /**
251: * This method returns the Database User for the connection pool.
252: */
253: public String getDatabaseUser() {
254: return _userID;
255: }
256:
257: /**
258: * This method returns the DBMS for the connection pool.
259: */
260: public String getDBMS() {
261: return _DBMS;
262: }
263:
264: /**
265: * This method returns the DB name for the connection pool.
266: */
267: public String getDBName() {
268: return _dbName;
269: }
270:
271: /**
272: * This method returns the Database Driver for the connection pool.
273: */
274: public String getDriver() {
275: return _driver;
276: }
277:
278: /**
279: * This method returns the number of idle connections in the list.
280: */
281: public int getIdleCount() {
282: return _unused.size();
283: }
284:
285: /**
286: * This method returns the number of connections currently in use.
287: */
288: public int getInUseCount() {
289: return _count - _unused.size();
290: }
291:
292: private DBConnection getUnused() throws SQLException {
293: DBConnection conn = (DBConnection) _unused.pop();
294: if (conn.getJDBCConnection().isClosed()) {
295: _count--;
296: conn.setJDBCConnection(createConnection());
297: conn.setCreated(System.currentTimeMillis());
298: }
299: return conn;
300: }
301:
302: void setIdleTimeOut(long time) {
303: _idleTimeOut = time;
304: }
305:
306: void setMax(int max) {
307: _max = max;
308: }
309:
310: void setWaitTimeOut(long time) {
311: _timeOut = time;
312: }
313:
314: private DBConnection waitForConnection() throws SQLException {
315:
316: if (_unused.isEmpty() && _count >= _max) {
317: // dsa 05-29-2001
318: try {
319: com.salmonllc.util.MessageLog.writeDebugMessage(
320: "-------------- waiting for connection---------"
321: + _timeOut, null);
322: wait(_timeOut);
323:
324: if (_unused.isEmpty() && _count >= _max)
325: throw (new SQLException(
326: "Timeout occurred waiting for connection"));
327: } catch (InterruptedException ie) {
328: // go
329: } catch (SQLException se) {
330: // throw it to the caller
331: throw (se);
332:
333: // maybe after we should try to getConnection again
334: } catch (Exception e) {
335: com.salmonllc.util.MessageLog.writeErrorMessage(
336: "waitForConnection", e, this );
337: }
338:
339: }
340:
341: if (_unused.isEmpty()) {
342: Connection conn = createConnection();
343: DBConnection dbc = new DBConnection(conn, _DBMS, false,
344: false);
345: dbc.setDatabaseDriver(_driver);
346: dbc.setUserName(_userID);
347: dbc.setPassword(_password);
348: dbc.setDatabaseUrl(_databaseURL);
349: dbc.setCreated(System.currentTimeMillis());
350: return dbc;
351: } else {
352: return getUnused();
353: }
354:
355: }
356:
357: /**
358: * This method sets parameters for the connection
359: */
360: private void setConnectionParms(String parms) {
361: _connectionParms = DBConnection.parseConnectionParms(parms);
362: }
363:
364: /**
365: * This method returns a connection parameter
366: * @param key
367: * @return
368: */
369: String getConnectionParm(String key) {
370: if (_connectionParms == null)
371: return null;
372: return (String) _connectionParms.get(key);
373: }
374:
375: Hashtable getConnectionParms() {
376: return _connectionParms;
377: }
378: }
|