blob: eb466d384b0d32d41a8065ab0c97af90d49ea98e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.jdbc.pool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
/**
* Abstract class that is to be extended for implementations of interceptors.
* Everytime an operation is called on the {@link java.sql.Connection} object the
* {@link #invoke(Object, Method, Object[])} method on the interceptor will be called.
* Interceptors are useful to change or improve behavior of the connection pool.<br>
* Interceptors can receive a set of properties. Each sub class is responsible for parsing the properties during runtime when they
* are needed or simply override the {@link #setProperties(Map)} method.
* Properties arrive in a key-value pair of Strings as they were received through the configuration.
* This method is called once per cached connection object when the object is first configured.
*
* @version 1.0
*/
public abstract class JdbcInterceptor implements InvocationHandler {
/**
* {@link java.sql.Connection#close()} method name
*/
public static final String CLOSE_VAL = "close";
/**
* {@link Object#toString()} method name
*/
public static final String TOSTRING_VAL = "toString";
/**
* {@link java.sql.Connection#isClosed()} method name
*/
public static final String ISCLOSED_VAL = "isClosed";
/**
* {@link javax.sql.PooledConnection#getConnection()} method name
*/
public static final String GETCONNECTION_VAL = "getConnection";
/**
* {@link java.sql.Wrapper#unwrap(Class)} method name
*/
public static final String UNWRAP_VAL = "unwrap";
/**
* {@link java.sql.Wrapper#isWrapperFor(Class)} method name
*/
public static final String ISWRAPPERFOR_VAL = "isWrapperFor";
/**
* {@link java.sql.Connection#isValid(int)} method name
*/
public static final String ISVALID_VAL = "isValid";
/**
* {@link java.lang.Object#equals(Object)}
*/
public static final String EQUALS_VAL = "equals";
/**
* {@link java.lang.Object#hashCode()}
*/
public static final String HASHCODE_VAL = "hashCode";
/**
* Properties for this interceptor.
*/
protected Map<String,InterceptorProperty> properties = null;
/**
* The next interceptor in the chain
*/
private volatile JdbcInterceptor next = null;
/**
* Property that decides how we do string comparison, default is to use
* {@link String#equals(Object)}. If set to <code>false</code> then the
* equality operator (==) is used.
*/
private boolean useEquals = true;
/**
* Public constructor for instantiation through reflection
*/
public JdbcInterceptor() {
// NOOP
}
/**
* Gets invoked each time an operation on {@link java.sql.Connection} is invoked.
* {@inheritDoc}
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (getNext()!=null) return getNext().invoke(proxy,method,args);
else throw new NullPointerException();
}
/**
* Returns the next interceptor in the chain
* @return the next interceptor in the chain
*/
public JdbcInterceptor getNext() {
return next;
}
/**
* configures the next interceptor in the chain
* @param next
*/
public void setNext(JdbcInterceptor next) {
this.next = next;
}
/**
* Performs a string comparison, using references unless the useEquals property is set to true.
* @param name1
* @param name2
* @return true if name1 is equal to name2 based on {@link #useEquals}
*/
public boolean compare(String name1, String name2) {
if (isUseEquals()) {
return name1.equals(name2);
} else {
return name1==name2;
}
}
/**
* Compares a method name (String) to a method (Method)
* {@link #compare(String,String)}
* Uses reference comparison unless the useEquals property is set to true
* @param methodName
* @param method
* @return true if the name matches
*/
public boolean compare(String methodName, Method method) {
return compare(methodName, method.getName());
}
/**
* Gets called each time the connection is borrowed from the pool
* This means that if an interceptor holds a reference to the connection
* the interceptor can be reused for another connection.
* <br>
* This method may be called with null as both arguments when we are closing down the connection.
* @param parent - the connection pool owning the connection
* @param con - the pooled connection
*/
public abstract void reset(ConnectionPool parent, PooledConnection con);
/**
* Called when {@link java.sql.Connection#close()} is called on the underlying connection.
* This is to notify the interceptors, that the physical connection has been released.
* Implementation of this method should be thought through with care, as no actions should trigger an exception.
* @param parent - the connection pool that this connection belongs to
* @param con - the pooled connection that holds this connection
* @param finalizing - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection
*/
public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
}
/**
* Returns the properties configured for this interceptor
* @return the configured properties for this interceptor
*/
public Map<String,InterceptorProperty> getProperties() {
return properties;
}
/**
* Called during the creation of an interceptor
* The properties can be set during the configuration of an interceptor
* Override this method to perform type casts between string values and object properties
* @param properties
*/
public void setProperties(Map<String,InterceptorProperty> properties) {
this.properties = properties;
final String useEquals = "useEquals";
InterceptorProperty p = properties.get(useEquals);
if (p!=null) {
setUseEquals(Boolean.parseBoolean(p.getValue()));
}
}
/**
* @return true if the compare method uses the Object.equals(Object) method
* false if comparison is done on a reference level
*/
public boolean isUseEquals() {
return useEquals;
}
/**
* Set to true if string comparisons (for the {@link #compare(String, Method)} and {@link #compare(String, String)} methods) should use the Object.equals(Object) method
* The default is false
* @param useEquals
*/
public void setUseEquals(boolean useEquals) {
this.useEquals = useEquals;
}
/**
* This method is invoked by a connection pool when the pool is closed.
* Interceptor classes can override this method if they keep static
* variables or other tracking means around.
* <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
* @param pool - the pool that is being closed.
*/
public void poolClosed(ConnectionPool pool) {
// NOOP
}
/**
* This method is invoked by a connection pool when the pool is first started up, usually when the first connection is requested.
* Interceptor classes can override this method if they keep static
* variables or other tracking means around.
* <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
* @param pool - the pool that is being closed.
*/
public void poolStarted(ConnectionPool pool) {
// NOOP
}
}