View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.dbcp;
19  
20  import java.io.PrintWriter;
21  import java.sql.CallableStatement;
22  import java.sql.Connection;
23  import java.sql.DatabaseMetaData;
24  import java.sql.PreparedStatement;
25  import java.sql.SQLException;
26  import java.sql.SQLWarning;
27  import java.sql.Statement;
28  import java.util.Map;
29  import java.util.NoSuchElementException;
30  
31  import javax.sql.DataSource;
32  
33  import org.apache.commons.pool.ObjectPool;
34  
35  /**
36   * A simple {@link DataSource} implementation that obtains
37   * {@link Connection}s from the specified {@link ObjectPool}.
38   *
39   * @author Rodney Waldhoff
40   * @author Glenn L. Nielsen
41   * @author James House
42   * @author Dirk Verbeeck
43   * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
44   */
45  public class PoolingDataSource implements DataSource {
46  
47      /** Controls access to the underlying connection */
48      private boolean accessToUnderlyingConnectionAllowed = false; 
49  
50      public PoolingDataSource() {
51          this(null);
52      }
53  
54      public PoolingDataSource(ObjectPool pool) {
55          _pool = pool;
56      }
57  
58      public void setPool(ObjectPool pool) throws IllegalStateException, NullPointerException {
59          if(null != _pool) {
60              throw new IllegalStateException("Pool already set");
61          } else if(null == pool) {
62              throw new NullPointerException("Pool must not be null.");
63          } else {
64              _pool = pool;
65          }
66      }
67  
68      /**
69       * Returns the value of the accessToUnderlyingConnectionAllowed property.
70       * 
71       * @return true if access to the underlying is allowed, false otherwise.
72       */
73      public boolean isAccessToUnderlyingConnectionAllowed() {
74          return this.accessToUnderlyingConnectionAllowed;
75      }
76  
77      /**
78       * Sets the value of the accessToUnderlyingConnectionAllowed property.
79       * It controls if the PoolGuard allows access to the underlying connection.
80       * (Default: false)
81       * 
82       * @param allow Access to the underlying connection is granted when true.
83       */
84      public void setAccessToUnderlyingConnectionAllowed(boolean allow) {
85          this.accessToUnderlyingConnectionAllowed = allow;
86      }
87  
88      /* JDBC_4_ANT_KEY_BEGIN */
89      public boolean isWrapperFor(Class<?> iface) throws SQLException {
90          return false;
91      }
92  
93      public <T> T unwrap(Class<T> iface) throws SQLException {
94          throw new SQLException("PoolingDataSource is not a wrapper.");
95      }
96      /* JDBC_4_ANT_KEY_END */
97      
98      //--- DataSource methods -----------------------------------------
99  
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 }