001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.dbcp;
019:
020: import java.io.PrintWriter;
021: import java.sql.CallableStatement;
022: import java.sql.Connection;
023: import java.sql.DatabaseMetaData;
024: import java.sql.PreparedStatement;
025: import java.sql.SQLException;
026: import java.sql.SQLWarning;
027: import java.sql.Statement;
028: import java.util.Map;
029: import java.util.NoSuchElementException;
030:
031: import javax.sql.DataSource;
032:
033: import org.apache.commons.pool.ObjectPool;
034:
035: /**
036: * A simple {@link DataSource} implementation that obtains
037: * {@link Connection}s from the specified {@link ObjectPool}.
038: *
039: * @author Rodney Waldhoff
040: * @author Glenn L. Nielsen
041: * @author James House
042: * @author Dirk Verbeeck
043: * @version $Revision: 479137 $ $Date: 2006-11-25 08:51:48 -0700 (Sat, 25 Nov 2006) $
044: */
045: public class PoolingDataSource implements DataSource {
046:
047: /** Controls access to the underlying connection */
048: private boolean accessToUnderlyingConnectionAllowed = false;
049:
050: public PoolingDataSource() {
051: this (null);
052: }
053:
054: public PoolingDataSource(ObjectPool pool) {
055: _pool = pool;
056: }
057:
058: public void setPool(ObjectPool pool) throws IllegalStateException,
059: NullPointerException {
060: if (null != _pool) {
061: throw new IllegalStateException("Pool already set");
062: } else if (null == pool) {
063: throw new NullPointerException("Pool must not be null.");
064: } else {
065: _pool = pool;
066: }
067: }
068:
069: /**
070: * Returns the value of the accessToUnderlyingConnectionAllowed property.
071: *
072: * @return true if access to the underlying is allowed, false otherwise.
073: */
074: public boolean isAccessToUnderlyingConnectionAllowed() {
075: return this .accessToUnderlyingConnectionAllowed;
076: }
077:
078: /**
079: * Sets the value of the accessToUnderlyingConnectionAllowed property.
080: * It controls if the PoolGuard allows access to the underlying connection.
081: * (Default: false)
082: *
083: * @param allow Access to the underlying connection is granted when true.
084: */
085: public void setAccessToUnderlyingConnectionAllowed(boolean allow) {
086: this .accessToUnderlyingConnectionAllowed = allow;
087: }
088:
089: //--- DataSource methods -----------------------------------------
090:
091: /**
092: * Return a {@link java.sql.Connection} from my pool,
093: * according to the contract specified by {@link ObjectPool#borrowObject}.
094: */
095: public Connection getConnection() throws SQLException {
096: try {
097: Connection conn = (Connection) (_pool.borrowObject());
098: if (conn != null) {
099: conn = new PoolGuardConnectionWrapper(conn);
100: }
101: return conn;
102: } catch (SQLException e) {
103: throw e;
104: } catch (NoSuchElementException e) {
105: throw new SQLNestedException(
106: "Cannot get a connection, pool error "
107: + e.getMessage(), e);
108: } catch (RuntimeException e) {
109: throw e;
110: } catch (Exception e) {
111: throw new SQLNestedException(
112: "Cannot get a connection, general error", e);
113: }
114: }
115:
116: /**
117: * Throws {@link UnsupportedOperationException}
118: * @throws UnsupportedOperationException
119: */
120: public Connection getConnection(String uname, String passwd)
121: throws SQLException {
122: throw new UnsupportedOperationException();
123: }
124:
125: /**
126: * Returns my log writer.
127: * @return my log writer
128: * @see DataSource#getLogWriter
129: */
130: public PrintWriter getLogWriter() {
131: return _logWriter;
132: }
133:
134: /**
135: * Throws {@link UnsupportedOperationException}.
136: * @throws UnsupportedOperationException As this
137: * implementation does not support this feature.
138: */
139: public int getLoginTimeout() {
140: throw new UnsupportedOperationException(
141: "Login timeout is not supported.");
142: }
143:
144: /**
145: * Throws {@link UnsupportedOperationException}.
146: * @throws UnsupportedOperationException As this
147: * implementation does not support this feature.
148: */
149: public void setLoginTimeout(int seconds) {
150: throw new UnsupportedOperationException(
151: "Login timeout is not supported.");
152: }
153:
154: /**
155: * Sets my log writer.
156: * @see DataSource#setLogWriter
157: */
158: public void setLogWriter(PrintWriter out) {
159: _logWriter = out;
160: }
161:
162: /** My log writer. */
163: protected PrintWriter _logWriter = null;
164:
165: protected ObjectPool _pool = null;
166:
167: /**
168: * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a
169: * closed connection cannot be used anymore.
170: */
171: private class PoolGuardConnectionWrapper extends
172: DelegatingConnection {
173:
174: private Connection delegate;
175:
176: PoolGuardConnectionWrapper(Connection delegate) {
177: super (delegate);
178: this .delegate = delegate;
179: }
180:
181: protected void checkOpen() throws SQLException {
182: if (delegate == null) {
183: throw new SQLException("Connection is closed.");
184: }
185: }
186:
187: public void close() throws SQLException {
188: checkOpen();
189: this .delegate.close();
190: this .delegate = null;
191: super .setDelegate(null);
192: }
193:
194: public boolean isClosed() throws SQLException {
195: if (delegate == null) {
196: return true;
197: }
198: return delegate.isClosed();
199: }
200:
201: public void clearWarnings() throws SQLException {
202: checkOpen();
203: delegate.clearWarnings();
204: }
205:
206: public void commit() throws SQLException {
207: checkOpen();
208: delegate.commit();
209: }
210:
211: public Statement createStatement() throws SQLException {
212: checkOpen();
213: return delegate.createStatement();
214: }
215:
216: public Statement createStatement(int resultSetType,
217: int resultSetConcurrency) throws SQLException {
218: checkOpen();
219: return delegate.createStatement(resultSetType,
220: resultSetConcurrency);
221: }
222:
223: public boolean innermostDelegateEquals(Connection c) {
224: Connection innerCon = super .getInnermostDelegate();
225: if (innerCon == null) {
226: return c == null;
227: } else {
228: return innerCon.equals(c);
229: }
230: }
231:
232: public boolean getAutoCommit() throws SQLException {
233: checkOpen();
234: return delegate.getAutoCommit();
235: }
236:
237: public String getCatalog() throws SQLException {
238: checkOpen();
239: return delegate.getCatalog();
240: }
241:
242: public DatabaseMetaData getMetaData() throws SQLException {
243: checkOpen();
244: return delegate.getMetaData();
245: }
246:
247: public int getTransactionIsolation() throws SQLException {
248: checkOpen();
249: return delegate.getTransactionIsolation();
250: }
251:
252: public Map getTypeMap() throws SQLException {
253: checkOpen();
254: return delegate.getTypeMap();
255: }
256:
257: public SQLWarning getWarnings() throws SQLException {
258: checkOpen();
259: return delegate.getWarnings();
260: }
261:
262: public int hashCode() {
263: if (delegate == null) {
264: return 0;
265: }
266: return delegate.hashCode();
267: }
268:
269: public boolean equals(Object obj) {
270: if (obj == null) {
271: return false;
272: }
273: if (obj == this ) {
274: return true;
275: }
276: // Use superclass accessor to skip access test
277: Connection delegate = super .getInnermostDelegate();
278: if (delegate == null) {
279: return false;
280: }
281: if (obj instanceof DelegatingConnection) {
282: DelegatingConnection c = (DelegatingConnection) obj;
283: return c.innermostDelegateEquals(delegate);
284: } else {
285: return delegate.equals(obj);
286: }
287: }
288:
289: public boolean isReadOnly() throws SQLException {
290: checkOpen();
291: return delegate.isReadOnly();
292: }
293:
294: public String nativeSQL(String sql) throws SQLException {
295: checkOpen();
296: return delegate.nativeSQL(sql);
297: }
298:
299: public CallableStatement prepareCall(String sql)
300: throws SQLException {
301: checkOpen();
302: return delegate.prepareCall(sql);
303: }
304:
305: public CallableStatement prepareCall(String sql,
306: int resultSetType, int resultSetConcurrency)
307: throws SQLException {
308: checkOpen();
309: return delegate.prepareCall(sql, resultSetType,
310: resultSetConcurrency);
311: }
312:
313: public PreparedStatement prepareStatement(String sql)
314: throws SQLException {
315: checkOpen();
316: return delegate.prepareStatement(sql);
317: }
318:
319: public PreparedStatement prepareStatement(String sql,
320: int resultSetType, int resultSetConcurrency)
321: throws SQLException {
322: checkOpen();
323: return delegate.prepareStatement(sql, resultSetType,
324: resultSetConcurrency);
325: }
326:
327: public void rollback() throws SQLException {
328: checkOpen();
329: delegate.rollback();
330: }
331:
332: public void setAutoCommit(boolean autoCommit)
333: throws SQLException {
334: checkOpen();
335: delegate.setAutoCommit(autoCommit);
336: }
337:
338: public void setCatalog(String catalog) throws SQLException {
339: checkOpen();
340: delegate.setCatalog(catalog);
341: }
342:
343: public void setReadOnly(boolean readOnly) throws SQLException {
344: checkOpen();
345: delegate.setReadOnly(readOnly);
346: }
347:
348: public void setTransactionIsolation(int level)
349: throws SQLException {
350: checkOpen();
351: delegate.setTransactionIsolation(level);
352: }
353:
354: public void setTypeMap(Map map) throws SQLException {
355: checkOpen();
356: delegate.setTypeMap(map);
357: }
358:
359: public String toString() {
360: if (delegate == null) {
361: return null;
362: }
363: return delegate.toString();
364: }
365:
366: // ------------------- JDBC 3.0 -----------------------------------------
367: // Will be commented by the build process on a JDBC 2.0 system
368:
369: /* JDBC_3_ANT_KEY_BEGIN */
370:
371: public int getHoldability() throws SQLException {
372: checkOpen();
373: return delegate.getHoldability();
374: }
375:
376: public void setHoldability(int holdability) throws SQLException {
377: checkOpen();
378: delegate.setHoldability(holdability);
379: }
380:
381: public java.sql.Savepoint setSavepoint() throws SQLException {
382: checkOpen();
383: return delegate.setSavepoint();
384: }
385:
386: public java.sql.Savepoint setSavepoint(String name)
387: throws SQLException {
388: checkOpen();
389: return delegate.setSavepoint(name);
390: }
391:
392: public void releaseSavepoint(java.sql.Savepoint savepoint)
393: throws SQLException {
394: checkOpen();
395: delegate.releaseSavepoint(savepoint);
396: }
397:
398: public void rollback(java.sql.Savepoint savepoint)
399: throws SQLException {
400: checkOpen();
401: delegate.rollback(savepoint);
402: }
403:
404: public Statement createStatement(int resultSetType,
405: int resultSetConcurrency, int resultSetHoldability)
406: throws SQLException {
407: checkOpen();
408: return delegate.createStatement(resultSetType,
409: resultSetConcurrency, resultSetHoldability);
410: }
411:
412: public CallableStatement prepareCall(String sql,
413: int resultSetType, int resultSetConcurrency,
414: int resultSetHoldability) throws SQLException {
415: checkOpen();
416: return delegate.prepareCall(sql, resultSetType,
417: resultSetConcurrency, resultSetHoldability);
418: }
419:
420: public PreparedStatement prepareStatement(String sql,
421: int autoGeneratedKeys) throws SQLException {
422: checkOpen();
423: return delegate.prepareStatement(sql, autoGeneratedKeys);
424: }
425:
426: public PreparedStatement prepareStatement(String sql,
427: int resultSetType, int resultSetConcurrency,
428: int resultSetHoldability) throws SQLException {
429: checkOpen();
430: return delegate.prepareStatement(sql, resultSetType,
431: resultSetConcurrency, resultSetHoldability);
432: }
433:
434: public PreparedStatement prepareStatement(String sql,
435: int[] columnIndexes) throws SQLException {
436: checkOpen();
437: return delegate.prepareStatement(sql, columnIndexes);
438: }
439:
440: public PreparedStatement prepareStatement(String sql,
441: String[] columnNames) throws SQLException {
442: checkOpen();
443: return delegate.prepareStatement(sql, columnNames);
444: }
445:
446: /* JDBC_3_ANT_KEY_END */
447:
448: /**
449: * @see org.apache.commons.dbcp.DelegatingConnection#getDelegate()
450: */
451: public Connection getDelegate() {
452: if (isAccessToUnderlyingConnectionAllowed()) {
453: return super .getDelegate();
454: } else {
455: return null;
456: }
457: }
458:
459: /**
460: * @see org.apache.commons.dbcp.DelegatingConnection#getInnermostDelegate()
461: */
462: public Connection getInnermostDelegate() {
463: if (isAccessToUnderlyingConnectionAllowed()) {
464: return super.getInnermostDelegate();
465: } else {
466: return null;
467: }
468: }
469: }
470: }
|