All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.ao.db.NuoDBDisposableDataSourceHandler Maven / Gradle / Ivy

Go to download

This is the full Active Objects library, if you don't know which one to use, you probably want this one.

The newest version!
/*
 * Licensed 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 net.java.ao.db;

import net.java.ao.Disposable;
import net.java.ao.DisposableDataSource;
import org.slf4j.Logger;

import javax.sql.DataSource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.Objects;

import static com.google.common.collect.Maps.newHashMap;
import static java.lang.reflect.Proxy.newProxyInstance;
import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
import static java.sql.Types.BIGINT;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * The NuoDB JDBC Driver supports ResultSet.TYPE_FORWARD_ONLY currently. The NuoDB data source handler intercepts
 * invocations of methods, which create SQL statements and forcibly overrides result set type to
 * {@link java.sql.ResultSet.TYPE_FORWARD_ONLY}. These are methods intercepted by the handler:
 * 
    *
  • Statement createStatement(int resultSetType, int resultSetConcurrency);
  • *
  • PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency);
  • *
  • CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency);
  • *
* * @author Sergey Bushik */ public class NuoDBDisposableDataSourceHandler { private static final ClassLoader CLASS_LOADER = NuoDBDisposableDataSourceHandler.class.getClassLoader(); /** * Creates reflection proxy for the specified NuoDB data source * * @param dataSource to intercept invocations * @return disposable data source */ public static DisposableDataSource newInstance(DataSource dataSource) { return newInstance(dataSource, null); } public static DisposableDataSource newInstance(DataSource dataSource, Disposable disposable) { return (DisposableDataSource) newProxy( new Class[]{DisposableDataSource.class}, new DelegatingDisposableDataSourceHandler(dataSource, disposable)); } private static Object newProxy(Class[] interfaces, InvocationHandler invocationHandler) { Object proxy = newProxyInstance(CLASS_LOADER, interfaces, invocationHandler); return proxy; } /** * Intercepts dispose() and getConnection() methods */ static class DelegatingDisposableDataSourceHandler extends DelegatingInvocationHandler { private static final String GET_CONNECTION = "getConnection"; private static final String DISPOSE = "dispose"; private Disposable disposable; public DelegatingDisposableDataSourceHandler(DataSource dataSource, Disposable disposable) { super(dataSource); this.disposable = disposable; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); Class[] parameterTypes = method.getParameterTypes(); Object result = null; // call dispose if (name.equals(DISPOSE) && parameterTypes.length == 0 && disposable != null) { disposable.dispose(); // proxy getConnection() invocation } else if (name.equals(GET_CONNECTION)) { Connection connection = (Connection) delegate(method, args); result = newProxy(new Class[]{Connection.class}, new DelegatingConnectionHandler(connection)); } else { result = delegate(method, args); } return result; } } /** * The handler, where result set type actually forcibly changed to those supported by NuoDB JDBC Driver. */ static class DelegatingConnectionHandler extends DelegatingInvocationHandler { public static final String CREATE_STATEMENT = "createStatement"; public static final String PREPARE_STATEMENT = "prepareStatement"; public static final String PREPARE_CALL = "prepareCall"; public DelegatingConnectionHandler(Connection connection) { super(connection); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); Class[] parameterTypes = method.getParameterTypes(); Class statement = null; Integer resultSetTypeArgIndex = null; // change result set type to java.sql.Types.TYPE_FORWARD_ONLY if (name.equals(CREATE_STATEMENT)) { statement = Statement.class; // Statement createStatement(int resultSetType, int resultSetConcurrency); // Statement createStatement(int resultSetType, int resultSetConcurrency, // int resultSetHoldability) throws SQLException; if (parameterTypes.length >= 2) { resultSetTypeArgIndex = 0; } } else if (name.equals(PREPARE_STATEMENT)) { // PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency); // PreparedStatement prepareStatement(String sql, int resultSetType, // int resultSetConcurrency, int resultSetHoldability); statement = PreparedStatement.class; if (parameterTypes.length >= 3) { resultSetTypeArgIndex = 1; } } else if (name.equals(PREPARE_CALL)) { statement = CallableStatement.class; // CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency); // CallableStatement prepareCall(String sql, int resultSetType, // int resultSetConcurrency, int resultSetHoldability) throws SQLException; if (parameterTypes.length >= 3) { resultSetTypeArgIndex = 1; } } if (resultSetTypeArgIndex != null && ((Integer) args[resultSetTypeArgIndex]) != TYPE_FORWARD_ONLY) { args[resultSetTypeArgIndex] = TYPE_FORWARD_ONLY; if (logger.isTraceEnabled()) { logger.trace("Result set type changed to forward only"); } } Object result = super.invoke(proxy, method, args); return statement != null ? newProxy(new Class[]{statement}, new DelegatingStatementHandler((Connection) proxy, (Statement) result)) : result; } } static class DelegatingStatementHandler extends DelegatingInvocationHandler { private static final String GET_CONNECTION = "getConnection"; private static final String GET_RESULT_SET = "getResultSet"; private static final String EXECUTE_QUERY = "executeQuery"; private Connection connection; public DelegatingStatementHandler(Connection connection, Statement statement) { super(statement); this.connection = connection; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); Object result; // proxy connection if (name.equals(GET_CONNECTION)) { result = connection; // proxy result set } else if (name.equals(EXECUTE_QUERY) || name.equals(GET_RESULT_SET)) { result = newProxy(new Class[]{ResultSet.class}, new DelegatingResultSetHandler((Statement) proxy, (ResultSet) super.invoke(proxy, method, args))); } else { result = super.invoke(proxy, method, args); } return result; } } static class DelegatingResultSetHandler extends DelegatingInvocationHandler { private static final String GET_STATEMENT = "getStatement"; private static final String GET_OBJECT = "getObject"; private ResultSetMetaData metaData; private Statement statement; private Map columns; protected DelegatingResultSetHandler(Statement statement, ResultSet resultSet) throws SQLException { super(resultSet); this.statement = statement; this.metaData = target.getMetaData(); int count = metaData.getColumnCount(); Map columns = newHashMap(); for (int index = 0; index < count; index++) { int column = index + 1; columns.put(metaData.getColumnName(column), column); } this.columns = columns; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); Object result; // proxy statement if (name.equals(GET_STATEMENT)) { result = statement; // change resultSet.getObject() for BIGINT to return resultSet.getLong() } else if (name.equals(GET_OBJECT)) { Integer column = null; if (method.getParameterTypes()[0].equals(String.class)) { column = columns.get(args[0]); } else { column = (Integer) args[0]; } // fixes get object for java.sql.Types.BIGINT to return long if (column != null && metaData.getColumnType(column) == BIGINT) { result = target.getLong(column); } else { result = super.invoke(proxy, method, args); } } else { result = super.invoke(proxy, method, args); } return result; } } /** * Base delegating invocation handler */ static class DelegatingInvocationHandler implements InvocationHandler { protected final Logger logger = getLogger(getClass()); protected final T target; protected DelegatingInvocationHandler(T target) { this.target = Objects.requireNonNull(target, "target can't be null"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return delegate(method, args); } protected Object delegate(Method method, Object[] args) throws Throwable { final Method m = target.getClass().getMethod(method.getName(), method.getParameterTypes()); m.setAccessible(true); try { return m.invoke(target, args); } catch (IllegalAccessException exception) { // avoid UndeclaredThrowableExceptions throw new RuntimeException(exception); } catch (IllegalArgumentException exception) { // avoid UndeclaredThrowableExceptions throw new RuntimeException(exception); } catch (InvocationTargetException exception) { // avoid UndeclaredThrowableExceptions throw exception.getCause(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy