Coverage Report - org.apache.ibatis.datasource.pooled.PooledConnection
 
Classes in this File Line Coverage Branch Coverage Complexity
PooledConnection
80%
40/50
45%
11/24
1,762
 
 1  
 /**
 2  
  *    Copyright 2009-2015 the original author or authors.
 3  
  *
 4  
  *    Licensed under the Apache License, Version 2.0 (the "License");
 5  
  *    you may not use this file except in compliance with the License.
 6  
  *    You may obtain a copy of the License at
 7  
  *
 8  
  *       http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  *    Unless required by applicable law or agreed to in writing, software
 11  
  *    distributed under the License is distributed on an "AS IS" BASIS,
 12  
  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  *    See the License for the specific language governing permissions and
 14  
  *    limitations under the License.
 15  
  */
 16  
 package org.apache.ibatis.datasource.pooled;
 17  
 
 18  
 import java.lang.reflect.InvocationHandler;
 19  
 import java.lang.reflect.Method;
 20  
 import java.lang.reflect.Proxy;
 21  
 import java.sql.Connection;
 22  
 import java.sql.SQLException;
 23  
 
 24  
 import org.apache.ibatis.reflection.ExceptionUtil;
 25  
 
 26  
 /**
 27  
  * @author Clinton Begin
 28  
  */
 29  
 class PooledConnection implements InvocationHandler {
 30  
 
 31  
   private static final String CLOSE = "close";
 32  1
   private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };
 33  
 
 34  16
   private int hashCode = 0;
 35  
   private PooledDataSource dataSource;
 36  
   private Connection realConnection;
 37  
   private Connection proxyConnection;
 38  
   private long checkoutTimestamp;
 39  
   private long createdTimestamp;
 40  
   private long lastUsedTimestamp;
 41  
   private int connectionTypeCode;
 42  
   private boolean valid;
 43  
 
 44  
   /*
 45  
    * Constructor for SimplePooledConnection that uses the Connection and PooledDataSource passed in
 46  
    *
 47  
    * @param connection - the connection that is to be presented as a pooled connection
 48  
    * @param dataSource - the dataSource that the connection is from
 49  
    */
 50  16
   public PooledConnection(Connection connection, PooledDataSource dataSource) {
 51  16
     this.hashCode = connection.hashCode();
 52  16
     this.realConnection = connection;
 53  16
     this.dataSource = dataSource;
 54  16
     this.createdTimestamp = System.currentTimeMillis();
 55  16
     this.lastUsedTimestamp = System.currentTimeMillis();
 56  16
     this.valid = true;
 57  16
     this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
 58  16
   }
 59  
 
 60  
   /*
 61  
    * Invalidates the connection
 62  
    */
 63  
   public void invalidate() {
 64  15
     valid = false;
 65  15
   }
 66  
 
 67  
   /*
 68  
    * Method to see if the connection is usable
 69  
    *
 70  
    * @return True if the connection is usable
 71  
    */
 72  
   public boolean isValid() {
 73  17
     return valid && realConnection != null && dataSource.pingConnection(this);
 74  
   }
 75  
 
 76  
   /*
 77  
    * Getter for the *real* connection that this wraps
 78  
    *
 79  
    * @return The connection
 80  
    */
 81  
   public Connection getRealConnection() {
 82  56
     return realConnection;
 83  
   }
 84  
 
 85  
   /*
 86  
    * Getter for the proxy for the connection
 87  
    *
 88  
    * @return The proxy
 89  
    */
 90  
   public Connection getProxyConnection() {
 91  10
     return proxyConnection;
 92  
   }
 93  
 
 94  
   /*
 95  
    * Gets the hashcode of the real connection (or 0 if it is null)
 96  
    *
 97  
    * @return The hashcode of the real connection (or 0 if it is null)
 98  
    */
 99  
   public int getRealHashCode() {
 100  0
     return realConnection == null ? 0 : realConnection.hashCode();
 101  
   }
 102  
 
 103  
   /*
 104  
    * Getter for the connection type (based on url + user + password)
 105  
    *
 106  
    * @return The connection type
 107  
    */
 108  
   public int getConnectionTypeCode() {
 109  6
     return connectionTypeCode;
 110  
   }
 111  
 
 112  
   /*
 113  
    * Setter for the connection type
 114  
    *
 115  
    * @param connectionTypeCode - the connection type
 116  
    */
 117  
   public void setConnectionTypeCode(int connectionTypeCode) {
 118  10
     this.connectionTypeCode = connectionTypeCode;
 119  10
   }
 120  
 
 121  
   /*
 122  
    * Getter for the time that the connection was created
 123  
    *
 124  
    * @return The creation timestamp
 125  
    */
 126  
   public long getCreatedTimestamp() {
 127  6
     return createdTimestamp;
 128  
   }
 129  
 
 130  
   /*
 131  
    * Setter for the time that the connection was created
 132  
    *
 133  
    * @param createdTimestamp - the timestamp
 134  
    */
 135  
   public void setCreatedTimestamp(long createdTimestamp) {
 136  6
     this.createdTimestamp = createdTimestamp;
 137  6
   }
 138  
 
 139  
   /*
 140  
    * Getter for the time that the connection was last used
 141  
    *
 142  
    * @return - the timestamp
 143  
    */
 144  
   public long getLastUsedTimestamp() {
 145  6
     return lastUsedTimestamp;
 146  
   }
 147  
 
 148  
   /*
 149  
    * Setter for the time that the connection was last used
 150  
    *
 151  
    * @param lastUsedTimestamp - the timestamp
 152  
    */
 153  
   public void setLastUsedTimestamp(long lastUsedTimestamp) {
 154  16
     this.lastUsedTimestamp = lastUsedTimestamp;
 155  16
   }
 156  
 
 157  
   /*
 158  
    * Getter for the time since this connection was last used
 159  
    *
 160  
    * @return - the time since the last use
 161  
    */
 162  
   public long getTimeElapsedSinceLastUse() {
 163  6
     return System.currentTimeMillis() - lastUsedTimestamp;
 164  
   }
 165  
 
 166  
   /*
 167  
    * Getter for the age of the connection
 168  
    *
 169  
    * @return the age
 170  
    */
 171  
   public long getAge() {
 172  0
     return System.currentTimeMillis() - createdTimestamp;
 173  
   }
 174  
 
 175  
   /*
 176  
    * Getter for the timestamp that this connection was checked out
 177  
    *
 178  
    * @return the timestamp
 179  
    */
 180  
   public long getCheckoutTimestamp() {
 181  0
     return checkoutTimestamp;
 182  
   }
 183  
 
 184  
   /*
 185  
    * Setter for the timestamp that this connection was checked out
 186  
    *
 187  
    * @param timestamp the timestamp
 188  
    */
 189  
   public void setCheckoutTimestamp(long timestamp) {
 190  10
     this.checkoutTimestamp = timestamp;
 191  10
   }
 192  
 
 193  
   /*
 194  
    * Getter for the time that this connection has been checked out
 195  
    *
 196  
    * @return the time
 197  
    */
 198  
   public long getCheckoutTime() {
 199  7
     return System.currentTimeMillis() - checkoutTimestamp;
 200  
   }
 201  
 
 202  
   @Override
 203  
   public int hashCode() {
 204  0
     return hashCode;
 205  
   }
 206  
 
 207  
   /*
 208  
    * Allows comparing this connection to another
 209  
    *
 210  
    * @param obj - the other connection to test for equality
 211  
    * @see Object#equals(Object)
 212  
    */
 213  
   @Override
 214  
   public boolean equals(Object obj) {
 215  7
     if (obj instanceof PooledConnection) {
 216  7
       return realConnection.hashCode() == (((PooledConnection) obj).realConnection.hashCode());
 217  0
     } else if (obj instanceof Connection) {
 218  0
       return hashCode == obj.hashCode();
 219  
     } else {
 220  0
       return false;
 221  
     }
 222  
   }
 223  
 
 224  
   /*
 225  
    * Required for InvocationHandler implementation.
 226  
    *
 227  
    * @param proxy  - not used
 228  
    * @param method - the method to be executed
 229  
    * @param args   - the parameters to be passed to the method
 230  
    * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
 231  
    */
 232  
   @Override
 233  
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 234  67
     String methodName = method.getName();
 235  67
     if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
 236  7
       dataSource.pushConnection(this);
 237  7
       return null;
 238  
     } else {
 239  
       try {
 240  60
         if (!Object.class.equals(method.getDeclaringClass())) {
 241  
           // issue #579 toString() should never fail
 242  
           // throw an SQLException instead of a Runtime
 243  59
           checkConnection();
 244  
         }
 245  60
         return method.invoke(realConnection, args);
 246  0
       } catch (Throwable t) {
 247  0
         throw ExceptionUtil.unwrapThrowable(t);
 248  
       }
 249  
     }
 250  
   }
 251  
 
 252  
   private void checkConnection() throws SQLException {
 253  59
     if (!valid) {
 254  0
       throw new SQLException("Error accessing PooledConnection. Connection is invalid.");
 255  
     }
 256  59
   }
 257  
 
 258  
 }