001: /**
002: * Library name : Primrose - A Java Database Connection Pool.
003: * Published by Ben Keeping, http://primrose.org.uk .
004: * Copyright (C) 2004 Ben Keeping, primrose.org.uk
005: * Email: Use "Contact Us Form" on website
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */package uk.org.primrose.pool.core;
021:
022: import uk.org.primrose.Logger;
023: import uk.org.primrose.Util;
024: import java.sql.*;
025: import java.util.*;
026: import java.io.*;
027:
028: public class PoolData extends PoolConfigImpl {
029:
030: /*
031: * A trivial synch object used by Pool.java
032: */
033: class PoolLock {
034: }
035:
036: /**
037: *
038: * @author sedj
039: * On failover (if defined), then start a thread to monitor the broken
040: * DB to see if it comes back. If it does, the thread stops, and informs the
041: * Pool to cut back from the failover pool to the original pool
042: */
043: class FailoverCutBack extends Thread {
044: public FailoverCutBack(Pool pool, Logger logger) {
045: this .pool = pool;
046: this .logger = logger;
047: }
048:
049: Pool pool = null;
050: Logger logger = null;
051: boolean bKeepRunning = true;
052:
053: public void run() {
054: while (bKeepRunning) {
055: try {
056: Thread.sleep(10000);
057: } catch (InterruptedException ie) {
058: }
059: Connection c = null;
060: Statement s = null;
061: ResultSet rs = null;
062: try {
063: c = Util.getConnection(driverClass, driverURL,
064: user, password);
065: s = c.createStatement();
066: rs = s.executeQuery(onExceptionCheckSQL);
067: logger
068: .info("[FailoverCutBack@"
069: + pool.getPoolName()
070: + "] FailoverCutBack has determined that the original DB is back up ... informing pool to cut back");
071: pool.cutbackFromFailoverPool();
072: bKeepRunning = false;
073: } catch (Throwable t) {
074: } finally {
075: try {
076: if (rs != null)
077: rs.close();
078: } catch (SQLException sqle2) {
079: }
080: try {
081: if (s != null)
082: s.close();
083: } catch (SQLException sqle2) {
084: }
085: try {
086: if (c != null)
087: c.close();
088: } catch (SQLException sqle2) {
089: }
090: }
091: }
092: }
093:
094: public void stopIt() {
095: bKeepRunning = false;
096: }
097: }
098:
099: // Global id for a connection
100: protected long gid = 0L;
101:
102: // Connection status codes
103: public static final int UNKNOWN_STATUS_CODE = -1;
104: public static final int CONNECTION_ACTIVE = 1;
105: public static final int CONNECTION_INACTIVE = 2;
106: public static final int CONNECTION_DUMPED = 3;
107:
108: // Connection behviours
109: public static final int ON_CLOSE_SHOULD_DIE = 4;
110: public static final int ON_CLOSE_SHOULD_REUSE = 5;
111:
112: // A list of connections (and status's etc)
113: Vector<ConnectionHolder> connections = null;
114:
115: // Whether the pool can give out connections
116: boolean poolAccessLocked = false;
117:
118: // Global lock object
119: protected PoolLock lock = null;
120:
121: // The number of waiting threads waiting for a connection
122: protected int numberOfWaitingThreads = 0;
123: protected int totalConnectionsHandedOut = 0;
124:
125: // A monitor on the pool
126: PoolMonitor monitor = null;
127:
128: // The pool's logger
129: protected Logger logger = null;
130:
131: // The pool to failover to (if specified)
132: Pool failoverPoolObj = null;
133: // A thread to monitor if this DB comes back (and cutback)
134: FailoverCutBack failoverCutBackObj = null;
135:
136: // Is the pool shutdown ?
137: boolean bPoolHasBeenShutdown = false;
138:
139: protected void setUpLogger() {
140: logger = new Logger();
141: if (log != null && log.length() > 0) {
142: try {
143: logger.setEmailDetails(emailEvents, adminEmail,
144: smtpMailExchangeServer, poolName);
145: logger.setLogLevel(logLevel);
146: logger.setLogWriter(log);
147: } catch (IOException ioe) {
148: System.out
149: .println("Primrose cannot write to log file : "
150: + log);
151: ioe.printStackTrace();
152: }
153:
154: }
155:
156: }
157:
158: /**
159: * Get the number of waiting threads
160: */
161: public int getNumberOfWaitingThreads() {
162: return numberOfWaitingThreads;
163: }
164:
165: /**
166: * Get the total number of connections handed out by the pool
167: */
168: public int getTotalConnectionsHandedOut() {
169: return totalConnectionsHandedOut;
170: }
171:
172: /**
173: * Get a string representation for the connection status/behaviour
174: */
175: public static String getStringStatus(int i) {
176: if (i == CONNECTION_ACTIVE) {
177: return "CONNECTION_ACTIVE";
178: } else if (i == CONNECTION_INACTIVE) {
179: return "CONNECTION_INACTIVE";
180: } else if (i == CONNECTION_DUMPED) {
181: return "CONNECTION_DUMPED";
182: } else if (i == ON_CLOSE_SHOULD_DIE) {
183: return "ON_CLOSE_SHOULD_DIE";
184: } else if (i == ON_CLOSE_SHOULD_REUSE) {
185: return "ON_CLOSE_SHOULD_REUSE";
186: } else if (i == UNKNOWN_STATUS_CODE) {
187: return "UNKNOWN_STATUS_CODE";
188: }
189:
190: return "UNKNOWN_STATUS_CODE";
191: }
192:
193: /**
194: * Get the current number of free connections
195: */
196: public int numberOfFreeConnections() {
197: logger.verbose("START");
198: int n = 0;
199: for (ConnectionHolder ch : connections) {
200: if (ch.status == CONNECTION_INACTIVE) {
201: logger.verbose("INACTIVE");
202: n++;
203: }
204: }
205: return n;
206: }
207:
208: /**
209: * Get the current number of active connections
210: */
211: public int numberOfActiveConnections() {
212: int n = 0;
213: for (ConnectionHolder ch : connections) {
214: if (ch.status == CONNECTION_ACTIVE) {
215: n++;
216: }
217: }
218: return n;
219: }
220:
221: /**
222: * Sets the default level for connection's isolation transaction level.
223: * This can only be set on startup - not during runtime.
224: */
225: protected void setInternalConnectionTransactionIsolation(
226: String sConnectionTransactionIsolation) {
227: // If not specified in the config file, then use the driver's default
228: if (sConnectionTransactionIsolation == null) {
229: try {
230: Connection c = Util.getConnection(driverClass,
231: driverURL, user, password);
232: // if the connection is null, then it means the db is down or not reachable
233: // so don't go any further.
234: // If this is the case, the when the db comes back up
235: // the transaction isolation level will -1, and the next 'get' on the Pool
236: // will cause this code to be run again to default the level if needs be.
237: if (c == null) {
238: logger
239: .warn("[Pool@"
240: + poolName
241: + "] setConnectionTransactionIsolation() : DB is down/not reachable, and because the pool config variable 'connectionTransactionLevel' is not set, it will be set when the db comes back up and the next call for a connection is made.");
242: iConnectionTransactionIsolation = -1;
243: return;
244: }
245: iConnectionTransactionIsolation = c
246: .getTransactionIsolation();
247: c.close();
248: } catch (Throwable t) {
249:
250: logger.printStackTrace(t);
251: }
252: } else if (sConnectionTransactionIsolation
253: .equalsIgnoreCase("TRANSACTION_NONE")) {
254: iConnectionTransactionIsolation = Connection.TRANSACTION_NONE;
255: } else if (sConnectionTransactionIsolation
256: .equalsIgnoreCase("TRANSACTION_READ_COMMITTED")) {
257: iConnectionTransactionIsolation = Connection.TRANSACTION_READ_COMMITTED;
258: } else if (sConnectionTransactionIsolation
259: .equalsIgnoreCase("TRANSACTION_READ_UNCOMMITTED")) {
260: iConnectionTransactionIsolation = Connection.TRANSACTION_READ_UNCOMMITTED;
261: } else if (sConnectionTransactionIsolation
262: .equalsIgnoreCase("TRANSACTION_REPEATABLE_READ")) {
263: iConnectionTransactionIsolation = Connection.TRANSACTION_REPEATABLE_READ;
264: } else if (sConnectionTransactionIsolation
265: .equalsIgnoreCase("TRANSACTION_SERIALIZABLE")) {
266: iConnectionTransactionIsolation = Connection.TRANSACTION_SERIALIZABLE;
267: // If not recognized, then use the driver's default
268: } else {
269: logger
270: .warn("[Pool@"
271: + poolName
272: + "] setConnectionTransactionIsolation() : Do not recognize transaction level of '"
273: + sConnectionTransactionIsolation
274: + "', using driver default");
275: try {
276: Connection c = Util.getConnection(driverClass,
277: driverURL, user, password);
278: iConnectionTransactionIsolation = c
279: .getTransactionIsolation();
280: c.close();
281: } catch (Throwable t) {
282:
283: logger.printStackTrace(t);
284: }
285: }
286:
287: logger
288: .verbose("[Pool@"
289: + poolName
290: + "] setConnectionTransactionIsolation() : Set connection transaction level to '"
291: + getInternalConnectionTransactionIsolation()
292: + "'");
293:
294: }
295:
296: /**
297: * Gets the default level for connection's isolation transaction level.
298: */
299: protected String getInternalConnectionTransactionIsolation() {
300: return getInternalConnectionTransactionIsolation(iConnectionTransactionIsolation);
301: }
302:
303: /**
304: * Gets the default level for connection's isolation transaction level.
305: */
306: protected String getInternalConnectionTransactionIsolation(int level) {
307: String sLevel = "DRIVER_DEFAULT";
308:
309: switch (level) {
310: case Connection.TRANSACTION_NONE:
311: sLevel = "TRANSACTION_NONE";
312: break;
313: case Connection.TRANSACTION_READ_COMMITTED:
314: sLevel = "TRANSACTION_READ_COMMITTED";
315: break;
316: case Connection.TRANSACTION_READ_UNCOMMITTED:
317: sLevel = "TRANSACTION_READ_UNCOMMITTED";
318: break;
319: case Connection.TRANSACTION_REPEATABLE_READ:
320: sLevel = "TRANSACTION_REPEATABLE_READ";
321: break;
322: case Connection.TRANSACTION_SERIALIZABLE:
323: sLevel = "TRANSACTION_SERIALIZABLE";
324: break;
325: }
326:
327: return sLevel;
328: }
329:
330: }
|