001: /*
002: * Distributed as part of c3p0 v.0.9.1.2
003: *
004: * Copyright (C) 2005 Machinery For Change, Inc.
005: *
006: * Author: Steve Waldman <swaldman@mchange.com>
007: *
008: * This library is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU Lesser General Public License version 2.1, as
010: * published by the Free Software Foundation.
011: *
012: * This software 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
015: * GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this software; see the file LICENSE. If not, write to the
019: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package com.mchange.v2.c3p0.test;
024:
025: import java.beans.PropertyChangeEvent;
026: import java.beans.PropertyChangeListener;
027: import java.io.File;
028: import java.io.IOException;
029: import java.io.ObjectInputStream;
030: import java.io.ObjectOutputStream;
031: import java.io.PrintWriter;
032: import java.util.Properties;
033: import java.sql.Connection;
034: import java.sql.Driver;
035: import java.sql.DriverManager;
036: import java.sql.SQLException;
037: import javax.sql.DataSource;
038: import com.mchange.v2.sql.SqlUtils;
039: import com.mchange.v2.log.MLevel;
040: import com.mchange.v2.log.MLog;
041: import com.mchange.v2.log.MLogger;
042: import com.mchange.v2.c3p0.cfg.C3P0Config;
043: import com.mchange.v2.c3p0.impl.DriverManagerDataSourceBase;
044:
045: // this is a copy-paste hack job to do a quick simulation of how c3p0 responds when
046: // getConnection() freezes but does not fail.
047: public final class FreezableDriverManagerDataSource extends
048: DriverManagerDataSourceBase implements DataSource {
049: final static MLogger logger = MLog
050: .getLogger(FreezableDriverManagerDataSource.class);
051:
052: final static File FREEZE_FILE = new File("/tmp/c3p0_freeze_file");
053:
054: //MT: protected by this' lock
055: Driver driver;
056:
057: //MT: protected by this' lock
058: boolean driver_class_loaded = false;
059:
060: public FreezableDriverManagerDataSource() {
061: this (true);
062: }
063:
064: public FreezableDriverManagerDataSource(boolean autoregister) {
065: super (autoregister);
066:
067: setUpPropertyListeners();
068:
069: String user = C3P0Config.initializeStringPropertyVar("user",
070: null);
071: String password = C3P0Config.initializeStringPropertyVar(
072: "password", null);
073:
074: if (user != null)
075: this .setUser(user);
076:
077: if (password != null)
078: this .setPassword(password);
079: }
080:
081: private void waitNoFreezeFile() throws SQLException {
082: try {
083: while (true) {
084: if (!FREEZE_FILE.exists())
085: break;
086: Thread.sleep(1000);
087: }
088: } catch (InterruptedException e) {
089: logger.log(MLevel.WARNING,
090: "Frozen cxn acquire interrupted.", e);
091: throw new SQLException(e.toString());
092: }
093: }
094:
095: private void setUpPropertyListeners() {
096: PropertyChangeListener driverClassListener = new PropertyChangeListener() {
097: public void propertyChange(PropertyChangeEvent evt) {
098: Object val = evt.getNewValue();
099: if ("driverClass".equals(evt.getPropertyName()))
100: setDriverClassLoaded(false);
101: }
102: };
103: this .addPropertyChangeListener(driverClassListener);
104: }
105:
106: private synchronized boolean isDriverClassLoaded() {
107: return driver_class_loaded;
108: }
109:
110: private synchronized void setDriverClassLoaded(boolean dcl) {
111: this .driver_class_loaded = dcl;
112: }
113:
114: private void ensureDriverLoaded() throws SQLException {
115: try {
116: if (!isDriverClassLoaded()) {
117: if (driverClass != null)
118: Class.forName(driverClass);
119: setDriverClassLoaded(true);
120: }
121: } catch (ClassNotFoundException e) {
122: if (logger.isLoggable(MLevel.WARNING))
123: logger.log(MLevel.WARNING,
124: "Could not load driverClass " + driverClass, e);
125: }
126: }
127:
128: // should NOT be sync'ed -- driver() is sync'ed and that's enough
129: // sync'ing the method creates the danger that one freeze on connect
130: // blocks access to the entire DataSource
131:
132: public Connection getConnection() throws SQLException {
133: ensureDriverLoaded();
134:
135: waitNoFreezeFile();
136:
137: Connection out = driver().connect(jdbcUrl, properties);
138: if (out == null)
139: throw new SQLException("Apparently, jdbc URL '" + jdbcUrl
140: + "' is not valid for the underlying " + "driver ["
141: + driver() + "].");
142: return out;
143: }
144:
145: // should NOT be sync'ed -- driver() is sync'ed and that's enough
146: // sync'ing the method creates the danger that one freeze on connect
147: // blocks access to the entire DataSource
148:
149: public Connection getConnection(String username, String password)
150: throws SQLException {
151: ensureDriverLoaded();
152:
153: waitNoFreezeFile();
154:
155: Connection out = driver().connect(jdbcUrl,
156: overrideProps(username, password));
157: if (out == null)
158: throw new SQLException("Apparently, jdbc URL '" + jdbcUrl
159: + "' is not valid for the underlying " + "driver ["
160: + driver() + "].");
161: return out;
162: }
163:
164: public PrintWriter getLogWriter() throws SQLException {
165: return DriverManager.getLogWriter();
166: }
167:
168: public void setLogWriter(PrintWriter out) throws SQLException {
169: DriverManager.setLogWriter(out);
170: }
171:
172: public int getLoginTimeout() throws SQLException {
173: return DriverManager.getLoginTimeout();
174: }
175:
176: public void setLoginTimeout(int seconds) throws SQLException {
177: DriverManager.setLoginTimeout(seconds);
178: }
179:
180: //overrides
181: public synchronized void setJdbcUrl(String jdbcUrl) {
182: //System.err.println( "setJdbcUrl( " + jdbcUrl + " )");
183: //new Exception("DEBUG STACK TRACE").printStackTrace();
184: super .setJdbcUrl(jdbcUrl);
185: clearDriver();
186: }
187:
188: //"virtual properties"
189: public synchronized void setUser(String user) {
190: String oldUser = this .getUser();
191: if (!eqOrBothNull(user, oldUser)) {
192: if (user != null)
193: properties.put(SqlUtils.DRIVER_MANAGER_USER_PROPERTY,
194: user);
195: else
196: properties
197: .remove(SqlUtils.DRIVER_MANAGER_USER_PROPERTY);
198:
199: pcs.firePropertyChange("user", oldUser, user);
200: }
201: }
202:
203: public synchronized String getUser() {
204: // System.err.println("getUser() -- DriverManagerDataSource@" + System.identityHashCode( this ) +
205: // " using Properties@" + System.identityHashCode( properties ));
206: // new Exception("STACK TRACE DUMP").printStackTrace();
207: return properties
208: .getProperty(SqlUtils.DRIVER_MANAGER_USER_PROPERTY);
209: }
210:
211: public synchronized void setPassword(String password) {
212: String oldPass = this .getPassword();
213: if (!eqOrBothNull(password, oldPass)) {
214: if (password != null)
215: properties.put(
216: SqlUtils.DRIVER_MANAGER_PASSWORD_PROPERTY,
217: password);
218: else
219: properties
220: .remove(SqlUtils.DRIVER_MANAGER_PASSWORD_PROPERTY);
221:
222: pcs.firePropertyChange("password", oldPass, password);
223: }
224: }
225:
226: public synchronized String getPassword() {
227: return properties
228: .getProperty(SqlUtils.DRIVER_MANAGER_PASSWORD_PROPERTY);
229: }
230:
231: private final Properties overrideProps(String user, String password) {
232: Properties overriding = (Properties) properties.clone(); //we are relying on a defensive clone in our base class!!!
233:
234: if (user != null)
235: overriding.put(SqlUtils.DRIVER_MANAGER_USER_PROPERTY, user);
236: else
237: overriding.remove(SqlUtils.DRIVER_MANAGER_USER_PROPERTY);
238:
239: if (password != null)
240: overriding.put(SqlUtils.DRIVER_MANAGER_PASSWORD_PROPERTY,
241: password);
242: else
243: overriding
244: .remove(SqlUtils.DRIVER_MANAGER_PASSWORD_PROPERTY);
245:
246: return overriding;
247: }
248:
249: private synchronized Driver driver() throws SQLException {
250: //System.err.println( "driver() <-- " + this );
251: if (driver == null)
252: driver = DriverManager.getDriver(jdbcUrl);
253: return driver;
254: }
255:
256: private synchronized void clearDriver() {
257: driver = null;
258: }
259:
260: private static boolean eqOrBothNull(Object a, Object b) {
261: return (a == b || (a != null && a.equals(b)));
262: }
263:
264: // serialization stuff -- set up bound/constrained property event handlers on deserialization
265: private static final long serialVersionUID = 1;
266: private static final short VERSION = 0x0001;
267:
268: private void writeObject(ObjectOutputStream oos) throws IOException {
269: oos.writeShort(VERSION);
270: }
271:
272: private void readObject(ObjectInputStream ois) throws IOException,
273: ClassNotFoundException {
274: short version = ois.readShort();
275: switch (version) {
276: case VERSION:
277: setUpPropertyListeners();
278: break;
279: default:
280: throw new IOException("Unsupported Serialized Version: "
281: + version);
282: }
283: }
284: }
|