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

com.sun.gjc.spi.jdbc40.ConnectionHolder40 Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 * Portions Copyright 2016-2022 Payara Foundation and/or affiliates
 */

package com.sun.gjc.spi.jdbc40;

import com.sun.enterprise.util.i18n.StringManager;
import com.sun.gjc.common.DataSourceObjectBuilder;
import com.sun.gjc.spi.ManagedConnectionFactoryImpl;
import com.sun.gjc.spi.ManagedConnectionImpl;
import com.sun.gjc.spi.base.ConnectionHolder;
import com.sun.logging.LogDomains;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.resource.ResourceException;


/**
 * Holds the java.sql.Connection object, which is to be
 * passed to the application program.
 *
 * @author Jagadish Ramu
 * @version 1.0, 25-Aug-2006
 */
public class ConnectionHolder40 extends ConnectionHolder {

    private static final String NUM_SERVERS = "numServers";
    
    private static final String SERVER0 = "server0";

    // this class uses LogStrings.properties of the jdbc-core library.
    private static final Logger _logger = LogDomains.getLogger(ConnectionHolder40.class, LogDomains.RSR_LOGGER,
            ConnectionHolder.class.getClassLoader());
    protected final static StringManager localStrings =
            StringManager.getManager(ManagedConnectionFactoryImpl.class);

    protected Properties defaultClientInfo;

    /**
     * Connection wrapper given to application program
     *
     * @param con           Connection that is wrapped
     * @param mc            ManagedConnection
     * @param cxRequestInfo Connection Request Information
     */
    public ConnectionHolder40(Connection con, ManagedConnectionImpl mc,
                              jakarta.resource.spi.ConnectionRequestInfo cxRequestInfo) {
        super(con, mc, cxRequestInfo);
        init();
    }

    /**
     * cache the default client info which can will set back during close()
* as this connection may be re-used by connection pool of application server
*/ protected void init() { try { if (isSupportClientInfo()) { defaultClientInfo = getClientInfo(); } } catch (Exception e) { if(_logger.isLoggable(Level.FINEST)) { _logger.log(Level.FINEST, "jdbc.unable_to_get_client_info", e); } } } /** * Constructs an object that implements the Clob interface. The object * returned initially contains no data. The setAsciiStream, * setCharacterStream and setString methods of * the Clob interface may be used to add data to the Clob. * * @return An object that implements the Clob interface * @throws java.sql.SQLException if an object that implements the * Clob interface can not be constructed, this method is * called on a closed connection or a database access error occurs. * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support * this data type * @since 1.6 */ @Override public Clob createClob() throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createClob(); } /** * Constructs an object that implements the Blob interface. The object * returned initially contains no data. The setBinaryStream and * setBytes methods of the Blob interface may be used to add data to * the Blob. * * @return An object that implements the Blob interface * @throws java.sql.SQLException if an object that implements the * Blob interface can not be constructed, this method is * called on a closed connection or a database access error occurs. * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support * this data type * @since 1.6 */ @Override public Blob createBlob() throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createBlob(); } /** * Constructs an object that implements the NClob interface. The object * returned initially contains no data. The setAsciiStream, * setCharacterStream and setString methods of the NClob interface may * be used to add data to the NClob. * * @return An object that implements the NClob interface * @throws java.sql.SQLException if an object that implements the * NClob interface can not be constructed, this method is * called on a closed connection or a database access error occurs. * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support * this data type * @since 1.6 */ @Override public NClob createNClob() throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createNClob(); } /** * Constructs an object that implements the SQLXML interface. The object * returned initially contains no data. The createXmlStreamWriter object and * setString method of the SQLXML interface may be used to add data to the SQLXML * object. * * @return An object that implements the SQLXML interface * @throws java.sql.SQLException if an object that implements the SQLXML interface can not * be constructed, this method is * called on a closed connection or a database access error occurs. * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support * this data type * @since 1.6 */ @Override public SQLXML createSQLXML() throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createSQLXML(); } /** * Returns true if the connection has not been closed and is still valid. * The driver shall submit a query on the connection or use some other * mechanism that positively verifies the connection is still valid when * this method is called. *

* The query submitted by the driver to validate the connection shall be * executed in the context of the current transaction. *

* @param timeout The time in seconds to wait for the database operation * used to validate the connection to complete. If * the timeout period expires before the operation * completes, this method returns false. A value of * 0 indicates a timeout is not applied to the * database operation. * @return true if the connection is valid, false otherwise * @throws java.sql.SQLException if the value supplied for timeout * is less then 0 * @see java.sql.DatabaseMetaData#getClientInfoProperties * @since 1.6 */ @Override public boolean isValid(int timeout) throws SQLException { checkValidity(); return con.isValid(timeout); } /** * Sets the value of the client info property specified by name to the * value specified by value. *

* Applications may use the DatabaseMetaData.getClientInfoProperties * method to determine the client info properties supported by the driver * and the maximum length that may be specified for each property. *

* The driver stores the value specified in a suitable location in the * database. For example in a special register, session parameter, or * system table column. For efficiency the driver may defer setting the * value in the database until the next time a statement is executed or * prepared. Other than storing the client information in the appropriate * place in the database, these methods shall not alter the behavior of * the connection in anyway. The values supplied to these methods are * used for accounting, diagnostics and debugging purposes only. *

* The driver shall generate a warning if the client info name specified * is not recognized by the driver. *

* If the value specified to this method is greater than the maximum * length for the property the driver may either truncate the value and * generate a warning or generate a SQLClientInfoException. If the driver * generates a SQLClientInfoException, the value specified was not set on the * connection. *

* The following are standard client info properties. Drivers are not * required to support these properties however if the driver supports a * client info property that can be described by one of the standard * properties, the standard property name should be used. *

*
    *
  • ApplicationName - The name of the application currently utilizing * the connection
  • *
  • ClientUser - The name of the user that the application using * the connection is performing work for. This may * not be the same as the user name that was used * in establishing the connection.
  • *
  • ClientHostname - The hostname of the computer the application * using the connection is running on.
  • *
* * @param name The name of the client info property to set * @param value The value to set the client info property to. If the * value is null, the current value of the specified * property is cleared. * @throws java.sql.SQLClientInfoException * if the database server returns an error while * setting the client info value on the database server or this method * is called on a closed connection * @since 1.6 */ @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { try { checkValidity(); } catch (SQLException sqe) { SQLClientInfoException sce = new SQLClientInfoException(); sce.setStackTrace(sqe.getStackTrace()); throw sce; } con.setClientInfo(name, value); } /** * Sets the value of the connection's client info properties. The * Properties object contains the names and values of the client info * properties to be set. The set of client info properties contained in * the properties list replaces the current set of client info properties * on the connection. If a property that is currently set on the * connection is not present in the properties list, that property is * cleared. Specifying an empty properties list will clear all of the * properties on the connection. See setClientInfo (String, String) for * more information. *

* If an error occurs in setting any of the client info properties, a * SQLClientInfoException is thrown. The SQLClientInfoException * contains information indicating which client info properties were not set. * The state of the client information is unknown because * some databases do not allow multiple client info properties to be set * atomically. For those databases, one or more properties may have been * set before the error occurred. *

* * @param properties the list of client info properties to set * @throws java.sql.SQLClientInfoException * if the database server returns an error while * setting the clientInfo values on the database server or this method * is called on a closed connection * @see java.sql.Connection#setClientInfo(String,String) setClientInfo(String, String) * @since 1.6 */ @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { try { checkValidity(); } catch (SQLException sqe) { SQLClientInfoException sce = new SQLClientInfoException(); sce.setStackTrace(sqe.getStackTrace()); throw sce; } // PAYARA-1127 // Starting With h2 version 1.4.192, numServers property is treated as internal property // and it should not be set through client info. if (properties.containsKey(NUM_SERVERS) || properties.containsKey(SERVER0)) { Properties filteredProperties = new Properties(); filteredProperties.putAll(properties); filteredProperties.remove(NUM_SERVERS); filteredProperties.remove(SERVER0); con.setClientInfo(filteredProperties); } else { con.setClientInfo(properties); } } /** * Returns the value of the client info property specified by name. This * method may return null if the specified client info property has not * been set and does not have a default value. This method will also * return null if the specified client info property name is not supported * by the driver. *

* Applications may use the DatabaseMetaData.getClientInfoProperties * method to determine the client info properties supported by the driver. *

* * @param name The name of the client info property to retrieve * @return The value of the client info property specified * @throws java.sql.SQLException if the database server returns an error when * fetching the client info value from the database * or this method is called on a closed connection * @see java.sql.DatabaseMetaData#getClientInfoProperties * @since 1.6 */ @Override public String getClientInfo(String name) throws SQLException { checkValidity(); return con.getClientInfo(name); } /** * Returns a list containing the name and current value of each client info * property supported by the driver. The value of a client info property * may be null if the property has not been set and does not have a * default value. * @return A Properties object that contains the name and current value of * each of the client info properties supported by the driver. * @throws java.sql.SQLException if the database server returns an error when * fetching the client info values from the database * or this method is called on a closed connection * @since 1.6 */ @Override public Properties getClientInfo() throws SQLException { checkValidity(); return con.getClientInfo(); } /** * Returns true if the client info properties are supported. * The application server calls the getClientInfo method and the setClientInfo method * only if the driver supports the client info properties. * The DatabaseMetaData#getClientInfoProperties method is used to determine * whether the driver supports the client info properties or not. * Note that the DatabaseMetaData will be cached by ManagedConnection. *

* * @return true if the client info properties are supported, false otherwise * * @see java.sql.DatabaseMetaData#getClientInfoProperties * @since 1.6 */ private boolean isSupportClientInfo() { Boolean isSupportClientInfo = getManagedConnection().isClientInfoSupported(); if (isSupportClientInfo != null) { return isSupportClientInfo; } ResultSet rs = null; try { rs = getManagedConnection().getCachedDatabaseMetaData().getClientInfoProperties(); isSupportClientInfo = rs.next(); } catch (final Exception e) { isSupportClientInfo = false; if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "jdbc.unable_to_get_client_info", e); } } finally { try { if (rs != null) { rs.close(); } } catch(SQLException e) { _logger.log(Level.SEVERE, "Cannot close resultset!", e); } } getManagedConnection().setClientInfoSupported(isSupportClientInfo); return isSupportClientInfo; } /** * Factory method for creating Array objects. * * @param typeName the SQL name of the type the elements of the array map to. The typeName is a * database-specific name which may be the name of a built-in type, a user-defined type or a standard SQL type supported by this database. This * is the value returned by Array.getBaseTypeName * @param elements the elements that populate the returned object * @return an Array object whose elements map to the specified SQL type * @throws java.sql.SQLException if a database error occurs, the typeName is null or this method is called on a closed connection * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support this data type * @since 1.6 */ @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createArrayOf(typeName, elements); } /** * Factory method for creating Struct objects. * * @param typeName the SQL type name of the SQL structured type that this Struct * object maps to. The typeName is the name of a user-defined type that * has been defined for this database. It is the value returned by * Struct.getSQLTypeName. * @param attributes the attributes that populate the returned object * @return a Struct object that maps to the given SQL type and is populated with the given attributes * @throws java.sql.SQLException if a database error occurs, the typeName is null or this method is called on a closed connection * @throws java.sql.SQLFeatureNotSupportedException * if the JDBC driver does not support this data type * @since 1.6 */ @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { checkValidity(); jdbcPreInvoke(); return con.createStruct(typeName, attributes); } /** * Returns an object that implements the given interface to allow access to * non-standard methods, or standard methods not exposed by the proxy. *

* If the receiver implements the interface then the result is the receiver * or a proxy for the receiver. If the receiver is a wrapper * and the wrapped object implements the interface then the result is the * wrapped object or a proxy for the wrapped object. Otherwise return the * the result of calling unwrap recursively on the wrapped object * or a proxy for that result. If the receiver is not a * wrapper and does not implement the interface, then an SQLException is thrown. * * @param iface A Class defining an interface that the result must implement. * @return an object that implements the interface. May be a proxy for the actual implementing object. * @throws java.sql.SQLException If no object found that implements the interface * @since 1.6 */ @Override public T unwrap(Class iface) throws SQLException { checkValidity(); T result = null; if (iface.isInstance(this)) { //if iface is "java.sql.Connection" result = iface.cast(this); } else if (iface.isInstance(con)) { //if iface is not "java.sql.Connection" & implemented by native Connection Class listIntf[] = new Class[]{iface}; result = getProxyObject(con, listIntf); } else { //probably a proxy, delegating to native connection result = con.unwrap(iface); if (Connection.class.isInstance(result)) { // rare case : returned object implements both iface & java.sql.Connection Class listIntf[] = new Class[]{iface, Connection.class}; result = getProxyObject(result, listIntf); } } return result; } /** * @param actualObject Object from jdbc vendor connection's unwrap * @param ifaces Interfaces for which proxy is needed * @return Proxy class implmenting the interfaces * @throws SQLException */ private T getProxyObject(final Object actualObject, Class[] ifaces) throws SQLException { T result; InvocationHandler ih; try { ih = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws SQLException, IllegalAccessException, InvocationTargetException { // When close() is called on proxy object, call close() on resource adapter's // Connection Holder instead of physical connection. if (method.getName().equals("close") && method.getParameterTypes().length == 0) { if (_logger.isLoggable(Level.FINE)) { String msg = localStrings.getString("jdbc.close_called_on_proxy_object", actualObject); _logger.log(Level.FINE, msg); } ConnectionHolder40.this.close(); return null; } // default return method.invoke(actualObject, args); } }; } catch (Exception e) { throw new SQLException(e.fillInStackTrace()); } result = (T) Proxy.newProxyInstance(actualObject.getClass().getClassLoader(), ifaces, ih); return result; } /** * Returns true if this either implements the interface argument or is directly or indirectly a wrapper * for an object that does. Returns false otherwise. If this implements the interface then return true, * else if this is a wrapper then return the result of recursively calling isWrapperFor on the wrapped * object. If this does not implement the interface and is not a wrapper, return false. * This method should be implemented as a low-cost operation compared to unwrap so that * callers can use this method to avoid expensive unwrap calls that may fail. If this method * returns true then calling unwrap with the same argument should succeed. * * @param iface a Class defining an interface. * @return true if this implements the interface or directly or indirectly wraps an object that does. * @throws java.sql.SQLException if an error occurs while determining whether this is a wrapper * for an object with the given interface. * @since 1.6 */ @Override public boolean isWrapperFor(Class iface) throws SQLException { checkValidity(); boolean result; if (iface.isInstance(this)) { result = true; } else { result = con.isWrapperFor(iface); } return result; } /** * Closes the logical connection.
* Cleans up client specific details
* * @throws SQLException In case of a database error. */ @Override public void close() throws SQLException { if (isClosed) { if (_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "jdbc.duplicate_close_connection", this); } return; } try { checkValidity(); if (isSupportClientInfo()) { if (defaultClientInfo == null) { setClientInfo(new Properties()); } else { setClientInfo(defaultClientInfo); } } } catch (Exception e) { _logger.log(Level.SEVERE, "jdbc.unable_to_set_client_info", e); } super.close(); } @Override public void setSchema(String schema) throws SQLException { if(DataSourceObjectBuilder.isJDBC41()) { checkValidity(); Class[] valueTypes = new Class[]{String.class}; try { getMethodExecutor().invokeMethod(con, "setSchema", valueTypes, schema); } catch (ResourceException ex) { _logger.log(Level.SEVERE, "jdbc.ex_connection_holder", ex); throw new SQLException(ex); } return; } throw new UnsupportedOperationException("Operation not supported in this runtime."); } @Override public String getSchema() throws SQLException { if(DataSourceObjectBuilder.isJDBC41()) { checkValidity(); try { return (String) getMethodExecutor().invokeMethod(con, "getSchema", null); } catch (ResourceException ex) { _logger.log(Level.SEVERE, "jdbc.ex_connection_holder", ex); throw new SQLException(ex); } } throw new UnsupportedOperationException("Operation not supported in this runtime."); } @Override public void setNetworkTimeout(Executor executorObj, int milliseconds) throws SQLException { if (DataSourceObjectBuilder.isJDBC41()) { checkValidity(); Class[] valueTypes = new Class[]{Executor.class, Integer.TYPE}; try { getMethodExecutor().invokeMethod(con, "setNetworkTimeout", valueTypes, executorObj, milliseconds); } catch (ResourceException ex) { _logger.log(Level.SEVERE, "jdbc.ex_connection_holder", ex); throw new SQLException(ex); } return; } throw new UnsupportedOperationException("Operation not supported in this runtime."); } @Override public int getNetworkTimeout() throws SQLException { if (DataSourceObjectBuilder.isJDBC41()) { checkValidity(); try { return (Integer) getMethodExecutor().invokeMethod(con, "getNetworkTimeout", null); } catch (ResourceException ex) { _logger.log(Level.SEVERE, "jdbc.ex_connection_holder", ex); throw new SQLException(ex); } } throw new UnsupportedOperationException("Operation not supported in this runtime."); } /** * Abort operation to mark the connection internally as a bad connection * for removal and to close the connection. This ensures that at the end * of the transaction, the connection is destroyed. A running thread * holding a connection will run to completion before the connection is * destroyed * * @param executor * @throws SQLException */ @Override public void abort(Executor executor) throws SQLException { if (DataSourceObjectBuilder.isJDBC41()) { getManagedConnection().markForRemoval(true); getManagedConnection().setAborted(true); if(!getManagedConnection().isTransactionInProgress()) { close(); } } else { throw new UnsupportedOperationException("Operation not supported in this runtime."); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy