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: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $ 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, NullPointerException { 059 if(null != _pool) { 060 throw new IllegalStateException("Pool already set"); 061 } else if(null == pool) { 062 throw new NullPointerException("Pool must not be null."); 063 } else { 064 _pool = pool; 065 } 066 } 067 068 /** 069 * Returns the value of the accessToUnderlyingConnectionAllowed property. 070 * 071 * @return true if access to the underlying is allowed, false otherwise. 072 */ 073 public boolean isAccessToUnderlyingConnectionAllowed() { 074 return this.accessToUnderlyingConnectionAllowed; 075 } 076 077 /** 078 * Sets the value of the accessToUnderlyingConnectionAllowed property. 079 * It controls if the PoolGuard allows access to the underlying connection. 080 * (Default: false) 081 * 082 * @param allow Access to the underlying connection is granted when true. 083 */ 084 public void setAccessToUnderlyingConnectionAllowed(boolean allow) { 085 this.accessToUnderlyingConnectionAllowed = allow; 086 } 087 088 /* JDBC_4_ANT_KEY_BEGIN */ 089 public boolean isWrapperFor(Class<?> iface) throws SQLException { 090 return false; 091 } 092 093 public <T> T unwrap(Class<T> iface) throws SQLException { 094 throw new SQLException("PoolingDataSource is not a wrapper."); 095 } 096 /* JDBC_4_ANT_KEY_END */ 097 098 //--- DataSource methods ----------------------------------------- 099 100 /** 101 * Return a {@link java.sql.Connection} from my pool, 102 * according to the contract specified by {@link ObjectPool#borrowObject}. 103 */ 104 public Connection getConnection() throws SQLException { 105 try { 106 Connection conn = (Connection)(_pool.borrowObject()); 107 if (conn != null) { 108 conn = new PoolGuardConnectionWrapper(conn); 109 } 110 return conn; 111 } catch(SQLException e) { 112 throw e; 113 } catch(NoSuchElementException e) { 114 throw new SQLNestedException("Cannot get a connection, pool error " + e.getMessage(), e); 115 } catch(RuntimeException e) { 116 throw e; 117 } catch(Exception e) { 118 throw new SQLNestedException("Cannot get a connection, general error", e); 119 } 120 } 121 122 /** 123 * Throws {@link UnsupportedOperationException} 124 * @throws UnsupportedOperationException 125 */ 126 public Connection getConnection(String uname, String passwd) throws SQLException { 127 throw new UnsupportedOperationException(); 128 } 129 130 /** 131 * Returns my log writer. 132 * @return my log writer 133 * @see DataSource#getLogWriter 134 */ 135 public PrintWriter getLogWriter() { 136 return _logWriter; 137 } 138 139 /** 140 * Throws {@link UnsupportedOperationException}. 141 * @throws UnsupportedOperationException As this 142 * implementation does not support this feature. 143 */ 144 public int getLoginTimeout() { 145 throw new UnsupportedOperationException("Login timeout is not supported."); 146 } 147 148 /** 149 * Throws {@link UnsupportedOperationException}. 150 * @throws UnsupportedOperationException As this 151 * implementation does not support this feature. 152 */ 153 public void setLoginTimeout(int seconds) { 154 throw new UnsupportedOperationException("Login timeout is not supported."); 155 } 156 157 /** 158 * Sets my log writer. 159 * @see DataSource#setLogWriter 160 */ 161 public void setLogWriter(PrintWriter out) { 162 _logWriter = out; 163 } 164 165 /** My log writer. */ 166 protected PrintWriter _logWriter = null; 167 168 protected ObjectPool _pool = null; 169 170 /** 171 * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a 172 * closed connection cannot be used anymore. 173 */ 174 private class PoolGuardConnectionWrapper extends DelegatingConnection { 175 176 private Connection delegate; 177 178 PoolGuardConnectionWrapper(Connection delegate) { 179 super(delegate); 180 this.delegate = delegate; 181 } 182 183 protected void checkOpen() throws SQLException { 184 if(delegate == null) { 185 throw new SQLException("Connection is closed."); 186 } 187 } 188 189 public void close() throws SQLException { 190 if (delegate != null) { 191 this.delegate.close(); 192 this.delegate = null; 193 super.setDelegate(null); 194 } 195 } 196 197 public boolean isClosed() throws SQLException { 198 if (delegate == null) { 199 return true; 200 } 201 return delegate.isClosed(); 202 } 203 204 public void clearWarnings() throws SQLException { 205 checkOpen(); 206 delegate.clearWarnings(); 207 } 208 209 public void commit() throws SQLException { 210 checkOpen(); 211 delegate.commit(); 212 } 213 214 public Statement createStatement() throws SQLException { 215 checkOpen(); 216 return new DelegatingStatement(this, delegate.createStatement()); 217 } 218 219 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { 220 checkOpen(); 221 return new DelegatingStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency)); 222 } 223 224 public boolean innermostDelegateEquals(Connection c) { 225 Connection innerCon = super.getInnermostDelegate(); 226 if (innerCon == null) { 227 return c == null; 228 } else { 229 return innerCon.equals(c); 230 } 231 } 232 233 public boolean getAutoCommit() throws SQLException { 234 checkOpen(); 235 return delegate.getAutoCommit(); 236 } 237 238 public String getCatalog() throws SQLException { 239 checkOpen(); 240 return delegate.getCatalog(); 241 } 242 243 public DatabaseMetaData getMetaData() throws SQLException { 244 checkOpen(); 245 return delegate.getMetaData(); 246 } 247 248 public int getTransactionIsolation() throws SQLException { 249 checkOpen(); 250 return delegate.getTransactionIsolation(); 251 } 252 253 public Map getTypeMap() throws SQLException { 254 checkOpen(); 255 return delegate.getTypeMap(); 256 } 257 258 public SQLWarning getWarnings() throws SQLException { 259 checkOpen(); 260 return delegate.getWarnings(); 261 } 262 263 public int hashCode() { 264 if (delegate == null){ 265 return 0; 266 } 267 return delegate.hashCode(); 268 } 269 270 public boolean equals(Object obj) { 271 if (obj == null) { 272 return false; 273 } 274 if (obj == this) { 275 return true; 276 } 277 // Use superclass accessor to skip access test 278 Connection conn = super.getInnermostDelegate(); 279 if (conn == null) { 280 return false; 281 } 282 if (obj instanceof DelegatingConnection) { 283 DelegatingConnection c = (DelegatingConnection) obj; 284 return c.innermostDelegateEquals(conn); 285 } 286 else { 287 return conn.equals(obj); 288 } 289 } 290 291 public boolean isReadOnly() throws SQLException { 292 checkOpen(); 293 return delegate.isReadOnly(); 294 } 295 296 public String nativeSQL(String sql) throws SQLException { 297 checkOpen(); 298 return delegate.nativeSQL(sql); 299 } 300 301 public CallableStatement prepareCall(String sql) throws SQLException { 302 checkOpen(); 303 return new DelegatingCallableStatement(this, delegate.prepareCall(sql)); 304 } 305 306 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { 307 checkOpen(); 308 return new DelegatingCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency)); 309 } 310 311 public PreparedStatement prepareStatement(String sql) throws SQLException { 312 checkOpen(); 313 return new DelegatingPreparedStatement(this, delegate.prepareStatement(sql)); 314 } 315 316 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { 317 checkOpen(); 318 return new DelegatingPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency)); 319 } 320 321 public void rollback() throws SQLException { 322 checkOpen(); 323 delegate.rollback(); 324 } 325 326 public void setAutoCommit(boolean autoCommit) throws SQLException { 327 checkOpen(); 328 delegate.setAutoCommit(autoCommit); 329 } 330 331 public void setCatalog(String catalog) throws SQLException { 332 checkOpen(); 333 delegate.setCatalog(catalog); 334 } 335 336 public void setReadOnly(boolean readOnly) throws SQLException { 337 checkOpen(); 338 delegate.setReadOnly(readOnly); 339 } 340 341 public void setTransactionIsolation(int level) throws SQLException { 342 checkOpen(); 343 delegate.setTransactionIsolation(level); 344 } 345 346 public void setTypeMap(Map map) throws SQLException { 347 checkOpen(); 348 delegate.setTypeMap(map); 349 } 350 351 public String toString() { 352 if (delegate == null){ 353 return "NULL"; 354 } 355 return delegate.toString(); 356 } 357 358 public int getHoldability() throws SQLException { 359 checkOpen(); 360 return delegate.getHoldability(); 361 } 362 363 public void setHoldability(int holdability) throws SQLException { 364 checkOpen(); 365 delegate.setHoldability(holdability); 366 } 367 368 public java.sql.Savepoint setSavepoint() throws SQLException { 369 checkOpen(); 370 return delegate.setSavepoint(); 371 } 372 373 public java.sql.Savepoint setSavepoint(String name) throws SQLException { 374 checkOpen(); 375 return delegate.setSavepoint(name); 376 } 377 378 public void releaseSavepoint(java.sql.Savepoint savepoint) throws SQLException { 379 checkOpen(); 380 delegate.releaseSavepoint(savepoint); 381 } 382 383 public void rollback(java.sql.Savepoint savepoint) throws SQLException { 384 checkOpen(); 385 delegate.rollback(savepoint); 386 } 387 388 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { 389 checkOpen(); 390 return new DelegatingStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); 391 } 392 393 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { 394 checkOpen(); 395 return new DelegatingCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 396 } 397 398 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { 399 checkOpen(); 400 return new DelegatingPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys)); 401 } 402 403 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { 404 checkOpen(); 405 return new DelegatingPreparedStatement(this,delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 406 } 407 408 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { 409 checkOpen(); 410 return new DelegatingPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes)); 411 } 412 413 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { 414 checkOpen(); 415 return new DelegatingPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); 416 } 417 418 /** 419 * @see org.apache.commons.dbcp.DelegatingConnection#getDelegate() 420 */ 421 public Connection getDelegate() { 422 if (isAccessToUnderlyingConnectionAllowed()) { 423 return super.getDelegate(); 424 } else { 425 return null; 426 } 427 } 428 429 /** 430 * @see org.apache.commons.dbcp.DelegatingConnection#getInnermostDelegate() 431 */ 432 public Connection getInnermostDelegate() { 433 if (isAccessToUnderlyingConnectionAllowed()) { 434 return super.getInnermostDelegate(); 435 } else { 436 return null; 437 } 438 } 439 } 440 }