diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/pom.xml b/appserver/jdbc/jdbc-ra/jdbc-core/pom.xml index 0841d822e53..a5123f52149 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/pom.xml +++ b/appserver/jdbc/jdbc-ra/jdbc-core/pom.xml @@ -57,6 +57,11 @@ org.glassfish.gmbal gmbal + + + org.junit.jupiter + junit-jupiter-engine + diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/DSManagedConnectionFactory.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/DSManagedConnectionFactory.java index 483560fdfca..6ef8e027c69 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/DSManagedConnectionFactory.java +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/DSManagedConnectionFactory.java @@ -51,7 +51,7 @@ @ConnectionDefinition( connectionFactory = DataSource.class, connectionFactoryImpl = AbstractDataSource.class, - connection = java.sql.Connection.class, + connection = Connection.class, connectionImpl = ConnectionHolder.class ) public class DSManagedConnectionFactory extends ManagedConnectionFactoryImpl { diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/JdbcObjectsFactory.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/JdbcObjectsFactory.java index 3db381b569b..de8718e376c 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/JdbcObjectsFactory.java +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/JdbcObjectsFactory.java @@ -52,13 +52,14 @@ public abstract class JdbcObjectsFactory implements Serializable { * @return JdbcObjectsFactory */ public static JdbcObjectsFactory getInstance() { + String className = "com.sun.gjc.spi.jdbc40.Jdbc40ObjectsFactory"; try { return(JdbcObjectsFactory) - Class.forName("com.sun.gjc.spi.jdbc40.Jdbc40ObjectsFactory") + Class.forName(className) .getDeclaredConstructor() .newInstance(); } catch (Exception e) { - _logger.log(WARNING, "jdbc.jdbc_factory_class_load_exception", e); + _logger.log(WARNING, "jdbc.jdbc_factory_class_load_exception", className); return null; } } diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/ManagedConnectionImpl.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/ManagedConnectionImpl.java index 1bc418f6d44..6ef55707d90 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/ManagedConnectionImpl.java +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/ManagedConnectionImpl.java @@ -34,6 +34,7 @@ import jakarta.resource.ResourceException; import jakarta.resource.spi.ConnectionEvent; import jakarta.resource.spi.ConnectionEventListener; +import jakarta.resource.spi.ConnectionRequestInfo; import jakarta.resource.spi.DissociatableManagedConnection; import jakarta.resource.spi.LazyEnlistableManagedConnection; import jakarta.resource.spi.LocalTransaction; @@ -129,24 +130,36 @@ public class ManagedConnectionImpl private Boolean isClientInfoSupported; /** - * Constructor for ManagedConnectionImpl. The pooledConn parameter - * is expected to be null and sqlConn parameter is the actual connection in case - * where the actual connection is got from a non pooled datasource object. The - * pooledConn parameter is expected to be non null and sqlConn parameter is - * expected to be null in the case where the datasource object is a connection - * pool datasource or an xa datasource. + * Constructor for ManagedConnectionImpl. The pooledConn parameter is expected to be null and sqlConn + * parameter is the actual connection in case where the actual connection is got from a non pooled datasource object. + * The pooledConn parameter is expected to be non null and sqlConn parameter is expected to be null in the case where + * the datasource object is a connection pool datasource or an xa datasource. * - * @param pooledConn PooledConnection object in case the physical - * connection is to be obtained from a pooled DataSource; null - * otherwise - * @param sqlConn java.sql.Connection object in case the physical - * connection is to be obtained from a non pooled DataSource; null - * otherwise - * @param passwdCred object conatining the user and password for allocating the - * connection - * @throws ResourceException if the ManagedConnectionFactory object - * that created this ManagedConnectionImpl object is not the same - * as returned by PasswordCredential object passed + * @param pooledConn PooledConnection object in case the physical connection is to be obtained from a + * pooled DataSource; null otherwise + * @param sqlConn java.sql.Connection object in case the physical connection is to be obtained from a non + * pooled DataSource; null otherwise + * @param passwdCred object containing the user and password for allocating the connection, value is allowed to be null. + * @param mcf the reference to the ManagedConnectionFactory instance that created this ManagedConnectionImpl instance. + * @param poolInfo Name of the pool + * @param statementCacheSize Statement caching is usually a feature of the JDBC driver. The GlassFish Server provides + * caching for drivers that do not support caching. To enable this feature, set the Statement Cache Size. By default, + * this attribute is set to zero and the statement caching is turned off. To enable statement caching, you can set any + * positive nonzero value. The built-in cache eviction strategy is LRU-based (Least Recently Used). When a connection + * pool is flushed, the connections in the statement cache are recreated.
+ * Configured via create-jdbc-connection-pool --statementcachesize + * @param statementCacheType In case statementCacheSize is not 0 this defines the statement cache type to be used. Valid + * values are defined in com.sun.gjc.spi.base.datastructure.CacheFactory. Value null or "" uses an LRU Cache + * implementation. Value FIXED uses FIXED size cache implementation. Any other values are expected to be a className for + * a cache implementation. + * @param delegator optional SqlTraceDelegator, value is allowed to be null. + * @param statementLeakTimeout statement leak timeout in seconds.
+ * Configured via create-jdbc-connection-pool --statementleaktimeout + * @param statementLeakReclaim true if statements need to be reclaimed.
+ * Configured via create-jdbc-connection-pool --statementleakreclaim + * @throws ResourceException if the ManagedConnectionFactory object that created this + * ManagedConnectionImpl object is not the same as returned by PasswordCredential object + * passed. And throws ResourceException in case both pooledConn and sqlConn are null. */ public ManagedConnectionImpl(PooledConnection pooledConn, Connection sqlConn, PasswordCredential passwdCred, ManagedConnectionFactory mcf, PoolInfo poolInfo, int statementCacheSize, String statementCacheType, @@ -154,7 +167,6 @@ public ManagedConnectionImpl(PooledConnection pooledConn, Connection sqlConn, Pa throws ResourceException { if (pooledConn == null && sqlConn == null) { - String i18nMsg = localStrings.getString("jdbc.conn_obj_null"); throw new ResourceException(i18nMsg); } @@ -170,7 +182,6 @@ public ManagedConnectionImpl(PooledConnection pooledConn, Connection sqlConn, Pa this.managedConnectionFactory = mcf; if (passwdCredential != null && this.managedConnectionFactory.equals(passwdCredential.getManagedConnectionFactory()) == false) { - String i18nMsg = localStrings.getString("jdbc.mc_construct_err"); throw new ResourceException(i18nMsg); } @@ -248,6 +259,7 @@ private void tuneStatementLeakTracing(PoolInfo poolInfo, long statementLeakTimeo * @param listener ConnectionEventListener * @see removeConnectionEventListener */ + @Override public void addConnectionEventListener(ConnectionEventListener listener) { this.listener = listener; } @@ -256,11 +268,12 @@ public void addConnectionEventListener(ConnectionEventListener listener) { * Used by the container to change the association of an application-level * connection handle with a ManagedConnectionImpl instance. * - * @param connection ConnectionHolder30 to be associated with this + * @param connection ConnectionHolder to be associated with this * ManagedConnectionImpl instance * @throws ResourceException if the physical connection is no more valid or the * connection handle passed is null */ + @Override public void associateConnection(Object connection) throws ResourceException { logFine("In associateConnection"); checkIfValid(); @@ -282,7 +295,7 @@ public void associateConnection(Object connection) throws ResourceException { * previous statements and result sets also need to be removed. */ - connectionHolder.setActive(true); + connectionHolder.setActive(); incrementCount(); // associate the MC to the supplied logical connection similar to associating @@ -304,6 +317,7 @@ public void associateConnection(Object connection) throws ResourceException { * * @throws ResourceException if the physical connection is no more valid */ + @Override public void cleanup() throws ResourceException { logFine("In cleanup"); @@ -351,6 +365,7 @@ private void clearStatementCache() { * @throws ResourceException if there is an error in closing the physical * connection */ + @Override public void destroy() throws ResourceException { logFine("In destroy"); if (isDestroyed) { @@ -400,7 +415,8 @@ public void destroy() throws ResourceException { * @throws jakarta.resource.spi.SecurityException if there is a mismatch between * the password credentials or reauthentication is requested */ - public Object getConnection(Subject sub, jakarta.resource.spi.ConnectionRequestInfo cxReqInfo) throws ResourceException { + @Override + public Object getConnection(Subject sub, ConnectionRequestInfo cxReqInfo) throws ResourceException { logFine("In getConnection"); checkIfValid(); @@ -431,7 +447,7 @@ public Object getConnection(Subject sub, jakarta.resource.spi.ConnectionRequestI incrementCount(); isClean = false; - myLogicalConnection.setActive(true); + myLogicalConnection.setActive(); return myLogicalConnection; } @@ -484,6 +500,7 @@ private void resetAutoCommit() throws ResourceException { * @return LocalTransactionImpl instance * @throws ResourceException if the physical connection is not valid */ + @Override public LocalTransaction getLocalTransaction() throws ResourceException { logFine("In getLocalTransaction"); checkIfValid(); @@ -498,6 +515,7 @@ public LocalTransaction getLocalTransaction() throws ResourceException { * @throws ResourceException if the physical connection is not valid * @see setLogWriter */ + @Override public PrintWriter getLogWriter() throws ResourceException { logFine("In getLogWriter"); checkIfValid(); @@ -512,6 +530,7 @@ public PrintWriter getLogWriter() throws ResourceException { * @return ManagedConnectionMetaData instance * @throws ResourceException if the physical connection is not valid */ + @Override public ManagedConnectionMetaData getMetaData() throws ResourceException { logFine("In getMetaData"); checkIfValid(); @@ -528,6 +547,7 @@ public ManagedConnectionMetaData getMetaData() throws ResourceException { * @throws NotSupportedException if underlying datasource is not an * XADataSource */ + @Override public XAResource getXAResource() throws ResourceException { logFine("In getXAResource"); checkIfValid(); @@ -556,7 +576,11 @@ public XAResource getXAResource() throws ResourceException { * @param listener ConnectionEventListener to be removed * @see addConnectionEventListener */ + @Override public void removeConnectionEventListener(ConnectionEventListener listener) { + if (this.listener == listener) { + this.listener = null; + } } /** @@ -709,22 +733,22 @@ void checkIfValid() throws ResourceException { } /** - * This method is called by the ConnectionHolder30 when its close + * This method is called by the ConnectionHolder when its close * method is called. This ManagedConnection instance invalidates * the connection handle and sends a CONNECTION_CLOSED event to all the * registered event listeners. * * @param e Exception that may have occurred while closing the connection handle - * @param connHolder30Object ConnectionHolder30 that has been + * @param connectionHolder ConnectionHolder that has been * closed * @throws SQLException in case closing the sql connection got out of * getConnection on the underlying PooledConnection * throws an exception */ - public void connectionClosed(Exception e, ConnectionHolder connHolder30Object) throws SQLException { - connHolder30Object.invalidate(); + public void connectionClosed(Exception e, ConnectionHolder connectionHolder) throws SQLException { + connectionHolder.invalidate(); decrementCount(); - connectionEvent.setConnectionHandle(connHolder30Object); + connectionEvent.setConnectionHandle(connectionHolder); if (markedForRemoval && !transactionInProgress) { BadConnectionEventListener badConnectionEventListener = (BadConnectionEventListener) listener; @@ -732,13 +756,15 @@ public void connectionClosed(Exception e, ConnectionHolder connHolder30Object) t _logger.log(INFO, "jdbc.markedForRemoval_conClosed"); markedForRemoval = false; } else { - listener.connectionClosed(connectionEvent); + if (listener != null) { + listener.connectionClosed(connectionEvent); + } } } /** - * This method is called by the ConnectionHolder30 when it detects - * a connecion related error. + * This method is called by the ConnectionHolder when it detects + * a connection related error. * * @param e Exception that has occurred during an operation on the physical * connection @@ -793,13 +819,12 @@ void XAEndOccurred() { * to the calling Connection Handle object to this object if the active * Connection Handle is null. * - * @param ch ConnectionHolder30 that requests this + * @param connectionHolder ConnectionHolder that requests this * ManagedConnection instance whether it can be active or not * @throws SQLException in case the physical is not valid or there is already an * active connection handle */ - - public void checkIfActive(ConnectionHolder ch) throws SQLException { + public void checkIfActive(ConnectionHolder connectionHolder) throws SQLException { if (isDestroyed || !isUsable) { throw new SQLException(localStrings.getString("jdbc.conn_not_usable")); } @@ -822,6 +847,7 @@ public void decrementCount() { connectionCount--; } + @Override public void dissociateConnections() { if (myLogicalConnection != null) { myLogicalConnection.dissociateConnection(); diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/base/ConnectionHolder.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/base/ConnectionHolder.java index cbf2a13e0a6..e886d133822 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/base/ConnectionHolder.java +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/java/com/sun/gjc/spi/base/ConnectionHolder.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -58,6 +59,15 @@ public abstract class ConnectionHolder implements Connection { protected boolean wrappedAlready; protected boolean isClosed; protected boolean valid = true; + + /** + * The active flag is false when the connection handle is created. When a method + * is invoked on this object, it asks the ManagedConnection if it can be the + * active connection handle out of the multiple connection handles. If the + * ManagedConnection reports that this connection handle can be active by + * setting this flag to true via the setActive function, the above method + * invocation succeeds; otherwise an exception is thrown. + */ protected boolean active; private LazyAssociatableConnectionManager lazyAssocCm_; @@ -77,17 +87,6 @@ public static enum ConnectionType { private ConnectionType myType_ = ConnectionType.STANDARD; - /** - * The active flag is false when the connection handle is created. When a method - * is invoked on this object, it asks the ManagedConnection if it can be the - * active connection handle out of the multiple connection handles. If the - * ManagedConnection reports that this connection handle can be active by - * setting this flag to true via the setActive function, the above method - * invocation succeeds; otherwise an exception is thrown. - */ - - - /** * Constructs a Connection holder. * @@ -168,6 +167,7 @@ public void dissociateConnection() { * * @throws SQLException In case of a database error. */ + @Override public void clearWarnings() throws SQLException { checkValidity(); connection.clearWarnings(); @@ -178,6 +178,7 @@ public void clearWarnings() throws SQLException { * * @throws SQLException In case of a database error. */ + @Override public void close() throws SQLException { if (_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "ConnectionHolder.close() START managedConnectionImpl=" + managedConnectionImpl); @@ -777,11 +778,9 @@ protected void checkValidity() throws SQLException { /** * Sets the active flag to true - * - * @param actv boolean */ - public void setActive(boolean actv) { - active = actv; + public void setActive() { + active = true; } /* diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/resources/com/sun/gjc/spi/LogStrings.properties b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/resources/com/sun/gjc/spi/LogStrings.properties index 129ef0a2dde..50216072908 100644 --- a/appserver/jdbc/jdbc-ra/jdbc-core/src/main/resources/com/sun/gjc/spi/LogStrings.properties +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/main/resources/com/sun/gjc/spi/LogStrings.properties @@ -24,7 +24,7 @@ jdbc.unable_to_get_client_info=RAR7114: Unable to get ClientInfo for connection jdbc.unable_to_set_client_info=RAR7115: Unable to set ClientInfo for connection jdbc.exc_unwrap=RAR7116: Unable to unwrap jdbc.exc_is_wrapper=RAR7117: Exception during isWrapper -jdbc.jdbc_factory_class_load_exception=RAR7118: Unable to load jdbc objects factory +jdbc.jdbc_factory_class_load_exception=RAR7118: Unable to load jdbc objects factory : {0} jdbc.exc_get_XA=RAR7119: Unable to get XADataSource jdbc.exc_cce_CP=RAR7120: Unable to get ConnectionPoolDataSource jdbc.exc_md=RAR7121: Exception while retrieving meta-data of connection @@ -175,7 +175,7 @@ jdbc.set_custom_validation_class_name_failure=RAR9001 : Custom validation class RAR9001.diag.cause.1=Custom validation class name is invalid as it does not implement interface org.glassfish.jdbc.api.ConnectionValidation RAR9001.diag.cause.2=Custom validation class name could not be loaded RAR9001.diag.cause.3=Custom validation class name is not in the classpath. -jdbc.jdbc_factory_class_load_exception=RAR9002 : Exception while getting Proxied Connection during SQL tracing : {0} +#jdbc.jdbc_factory_class_load_exception=RAR9002 : Exception while getting Proxied Connection during SQL tracing : {0} RAR9002.diag.cause.1=Connection object could be null RAR9002.diag.cause.2=Initialization provoked by method could have failed. RAR9002.diag.cause.3=Underlying method inaccessible. diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/AbstractManagedConnectionFactoryImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/AbstractManagedConnectionFactoryImplTest.java new file mode 100644 index 00000000000..3df9dd7efd6 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/AbstractManagedConnectionFactoryImplTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.stub.MyDataSource; + +import jakarta.resource.spi.ConnectionRequestInfo; +import jakarta.resource.spi.ManagedConnection; +import jakarta.resource.spi.ManagedConnectionFactory; +import jakarta.resource.spi.ResourceAllocationException; +import jakarta.resource.spi.security.PasswordCredential; + +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public abstract class AbstractManagedConnectionFactoryImplTest { + + protected static final String USERNAME = "myUsername"; + protected static final String PASSWORD = "myPassword"; + protected static final String ANOTHER_PASSWORD = "anotherPassword"; + + public abstract ManagedConnectionFactoryImpl getManagedConnectionFactory() throws Exception; + + @Test + public void testCreateManagedConnection_NoCredentials() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // No credentials at all + Subject subject = null; + ConnectionRequestInfo connectionRequestInfo = null; + + // Credentials 'both null', should receive a connection in current code. + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + } + + @Test + public void testCreateManagedConnection_SubjectCredentials() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // No credentials in ConnectionRequestInfo + ConnectionRequestInfo connectionRequestInfo = null; + + // Test subject with matching password + Subject subject = createSubjectWithCredentials(mcf, PASSWORD); + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test subject without matching password, driver must now handle username/password + subject = createSubjectWithCredentials(mcf, ANOTHER_PASSWORD); + managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test with driver not accepting username/password + final Subject subjectNotAccepted = createSubjectWithCredentials(mcf, MyDataSource.NOT_ALLOWED_PASSWORD); + assertThrows(ResourceAllocationException.class, () -> { + mcf.createManagedConnection(subjectNotAccepted, connectionRequestInfo); + }); + } + + @Test + public void testCreateManagedConnection_ConnectionRequestInfoCredentials() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // No credentials in subject + Subject subject = null; + + // Test with matching password + ConnectionRequestInfo connectionRequestInfo = new ConnectionRequestInfoImpl(USERNAME, PASSWORD.toCharArray()); + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test without matching password, driver must now handle username/password + connectionRequestInfo = new ConnectionRequestInfoImpl(USERNAME, ANOTHER_PASSWORD.toCharArray()); + managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test with driver not accepting username/password + assertThrows(ResourceAllocationException.class, () -> { + ConnectionRequestInfoImpl cr = new ConnectionRequestInfoImpl(USERNAME, MyDataSource.NOT_ALLOWED_PASSWORD.toCharArray()); + mcf.createManagedConnection(subject, cr); + }); + } + + @Test + public void testCreateManagedConnection_AnotherPassword() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // No credentials in subject + Subject subject = null; + ConnectionRequestInfo connectionRequestInfo = new ConnectionRequestInfoImpl(USERNAME, ANOTHER_PASSWORD.toCharArray()); + + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + } + + @Test + public void testGetDataSource() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + assertNotNull(mcf.getDataSource()); + } + + /** + * This is about connection 'matching' and not in transaction matching as used in connector-runtime + */ + @Test + public void testMatchManagedConnections() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // connectionSet null, expect null + Set connectionSet = null; + assertNull(mcf.matchManagedConnections(connectionSet, null, null)); + + // Create a managed connection + Subject subject = createSubjectWithCredentials(mcf, PASSWORD); + ConnectionRequestInfo connectionRequestInfo = null; + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + + // Match it + connectionSet = new HashSet<>(); + connectionSet.add(managedConnection); + assertEquals(managedConnection, mcf.matchManagedConnections(connectionSet, null, null)); + + // Could test some more complex matching variations + } + + protected Subject createSubjectWithCredentials(ManagedConnectionFactory mcf, String password) { + Subject subject = new Subject(); + PasswordCredential passwordCredential = new PasswordCredential(USERNAME, password.toCharArray()); + subject.getPrivateCredentials().add(passwordCredential); + passwordCredential.setManagedConnectionFactory(mcf); + return subject; + } + +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/CPManagedConnectionFactoryImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/CPManagedConnectionFactoryImplTest.java new file mode 100644 index 00000000000..262758cb6ec --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/CPManagedConnectionFactoryImplTest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.stub.MyConnectionPoolDatasource; + +public class CPManagedConnectionFactoryImplTest extends AbstractManagedConnectionFactoryImplTest { + + @Override + public ManagedConnectionFactoryImpl getManagedConnectionFactory() { + ManagedConnectionFactoryImpl mcf = new CPManagedConnectionFactory(); + mcf.setClassName(MyConnectionPoolDatasource.class.getCanonicalName()); + return mcf; + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ConnectionHolderTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ConnectionHolderTest.java new file mode 100644 index 00000000000..4f6da7c008a --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ConnectionHolderTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.base.ConnectionHolder; +import com.sun.gjc.spi.stub.MyConnection; +import com.sun.gjc.spi.stub.MyConnectionHolder; + +import jakarta.resource.spi.ConnectionRequestInfo; + +import java.sql.Connection; + +import org.junit.jupiter.api.Test; + +import static com.sun.gjc.spi.ManagedConnectionImplTest.createManagedConnection; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ConnectionHolderTest { + + @Test + public void testAssociateAndDissociateConnection() throws Exception { + ConnectionRequestInfo cxRequestInfo = null; + + Connection connection1 = new MyConnection(); + ManagedConnectionImpl managedConnection1 = createManagedConnection(null, connection1); + + Connection connection2 = new MyConnection(); + ManagedConnectionImpl managedConnection2 = createManagedConnection(null, connection2); + + try (ConnectionHolder connectionHolder = new MyConnectionHolder(connection1, managedConnection1, cxRequestInfo)) { + assertEquals(connectionHolder.getConnection(), connection1); + assertEquals(connectionHolder.getManagedConnection(), managedConnection1); + + // Associate a new connection and managed connection + connectionHolder.associateConnection(connection2, managedConnection2); + assertEquals(connectionHolder.getConnection(), connection2); + assertEquals(connectionHolder.getManagedConnection(), managedConnection2); + + // Disassociate connection and managed connection + connectionHolder.dissociateConnection(); + assertNull(connectionHolder.getConnection()); + assertNull(connectionHolder.getManagedConnection()); + } + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DMManagedConnectionFactoryImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DMManagedConnectionFactoryImplTest.java new file mode 100644 index 00000000000..3559a2a72e4 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DMManagedConnectionFactoryImplTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.common.DataSourceSpec; +import com.sun.gjc.spi.stub.MyDataSource; +import com.sun.gjc.spi.stub.MyDriver; + +import jakarta.resource.spi.ConnectionRequestInfo; +import jakarta.resource.spi.ManagedConnection; +import jakarta.resource.spi.ResourceAllocationException; + +import java.sql.DriverManager; + +import javax.security.auth.Subject; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DMManagedConnectionFactoryImplTest extends AbstractManagedConnectionFactoryImplTest { + + @Override + public ManagedConnectionFactoryImpl getManagedConnectionFactory() throws Exception { + // A database driver is required + DriverManager.registerDriver(new MyDriver()); + + ManagedConnectionFactoryImpl mcf = new DMManagedConnectionFactory(); + mcf.setClassName(MyDataSource.class.getCanonicalName()); + mcf.spec.setDetail(DataSourceSpec.URL, MyDriver.ACCEPTED_URL); + return mcf; + } + + @Test + public void testCreateManagedConnection_SubjectCredentials() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + + // No credentials in ConnectionRequestInfo + ConnectionRequestInfo connectionRequestInfo = null; + + // Test subject with matching password + // DIFFERENCE: DMManagedConnectionFactory ignores subject credentials. + // Change via mcf spec the password: + Subject subject = createSubjectWithCredentials(mcf, PASSWORD); + mcf.spec.setDetail(DataSourceSpec.PASSWORD, PASSWORD); + ManagedConnection managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test subject without matching password, driver must now handle username/password + // DIFFERENCE: DMManagedConnectionFactory ignores subject credentials. + // Change via mcf spec the password: + subject = createSubjectWithCredentials(mcf, ANOTHER_PASSWORD); + mcf.spec.setDetail(DataSourceSpec.PASSWORD, ANOTHER_PASSWORD); + managedConnection = mcf.createManagedConnection(subject, connectionRequestInfo); + assertNotNull(managedConnection); + + // Test with driver not accepting username/password + // DIFFERENCE: DMManagedConnectionFactory ignores subject credentials. + // Change via mcf spec the password: + mcf.spec.setDetail(DataSourceSpec.PASSWORD, MyDataSource.NOT_ALLOWED_PASSWORD); + final Subject subjectNotAccepted = createSubjectWithCredentials(mcf, MyDataSource.NOT_ALLOWED_PASSWORD); + assertThrows(ResourceAllocationException.class, () -> { + mcf.createManagedConnection(subjectNotAccepted, connectionRequestInfo); + }); + } + + @Test + public void testGetDataSource() throws Exception { + ManagedConnectionFactoryImpl mcf = getManagedConnectionFactory(); + // Method always returns null in DMManagedConnectionFactory + assertNull(mcf.getDataSource()); + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DSManagedConnectionFactoryImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DSManagedConnectionFactoryImplTest.java new file mode 100644 index 00000000000..9ab9f16b77c --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/DSManagedConnectionFactoryImplTest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.stub.MyDataSource; + +public class DSManagedConnectionFactoryImplTest extends AbstractManagedConnectionFactoryImplTest { + + @Override + public ManagedConnectionFactoryImpl getManagedConnectionFactory() { + ManagedConnectionFactoryImpl mcf = new DSManagedConnectionFactory(); + mcf.setClassName(MyDataSource.class.getCanonicalName()); + return mcf; + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ManagedConnectionImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ManagedConnectionImplTest.java new file mode 100644 index 00000000000..c85c941e980 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/ManagedConnectionImplTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.base.ConnectionHolder; +import com.sun.gjc.spi.stub.MyConnection; +import com.sun.gjc.spi.stub.MyConnectionHolder; +import com.sun.gjc.spi.stub.MyPooledConnection; +import com.sun.gjc.util.SQLTraceDelegator; + +import jakarta.resource.ResourceException; +import jakarta.resource.spi.ConnectionRequestInfo; +import jakarta.resource.spi.ManagedConnectionFactory; +import jakarta.resource.spi.security.PasswordCredential; + +import java.sql.Connection; + +import javax.sql.PooledConnection; + +import org.glassfish.api.naming.SimpleJndiName; +import org.glassfish.resourcebase.resources.api.PoolInfo; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ManagedConnectionImplTest { + + @Test + public void testConstructor() throws Exception { + // pooledConn and sqlConn not allowed to be both null + assertThrows(ResourceException.class, () -> createManagedConnection(null, null)); + + // pooledConn and sqlConn not allowed to be both not null according to javadoc + // but testing this fails so use assertDoesNotThrow for now but it should be assertThrows(ResourceException.class + assertDoesNotThrow(() -> createManagedConnection(new MyPooledConnection(), new MyConnection())); + + // valid ManagedConnection + ManagedConnectionImpl managedConnection = createManagedConnection(null, new MyConnection()); + assertNotNull(managedConnection.getActualConnection()); + } + + @Test + public void testAssociateConnection() throws Exception { + ConnectionRequestInfo cxRequestInfo = null; + + final ManagedConnectionImpl managedConnection1 = createManagedConnection(null, new MyConnection()); + final Connection connection1 = managedConnection1.getActualConnection(); + assertEquals(0, managedConnection1.connectionCount); + + final ManagedConnectionImpl managedConnection2 = createManagedConnection(null, new MyConnection()); + final Connection connection2 = managedConnection2.getActualConnection(); + assertEquals(0, managedConnection2.connectionCount); + + // Create an application-level connection handle ConnectionHolder linked to managedConnection2 + // and instruct the managedConnection1 to associate with this ConnectionHolder + try (ConnectionHolder connectionHolder = new MyConnectionHolder(connection2, managedConnection2, cxRequestInfo)) { + assertEquals(connection2, connectionHolder.getConnection()); + assertEquals(managedConnection2, connectionHolder.getManagedConnection()); + + // Associate ManagedCollection1 to the connectionholder / handle + managedConnection1.associateConnection(connectionHolder); + + // Spec: jakarta.resource.spi.ManagedConnection.associateConnection(Object) + // "The method implementation for a ManagedConnection should dissociate the connection handle (passed as a parameter) + // from its currently associated ManagedConnection and associate the new connection handle with itself. " + // + // Expect the connectionHolder to be changed and point to ManagedCollection1 + assertEquals(connection1, connectionHolder.getConnection()); + assertEquals(managedConnection1, connectionHolder.getManagedConnection()); + + // Expect both ManagedconnectionImpl instances to not be changed regarding the actual (database) connection + assertEquals(connection1, managedConnection1.getActualConnection()); + assertEquals(connection2, managedConnection2.getActualConnection()); + + // Expect managedConnection2.myLogicalConnection to be null, it was never linked to a connection holder + assertNull(managedConnection2.myLogicalConnection); + + // Expect managedConnection1.myLogicalConnection to reference the new connectionHolder. + // This means a circular dependency between the managedConnection1 and the connectionHolder is added + // by the associateConnection logic. This makes the objects relations hard to understand. + // Show both sides of the relation: + assertEquals(connectionHolder, managedConnection1.myLogicalConnection); + assertEquals(managedConnection1, connectionHolder.getManagedConnection()); + assertEquals(managedConnection1.getActualConnection(), connectionHolder.getConnection()); + + // The associateContext also increases the connectionCount for the connection associated + // to the connectionholder + assertEquals(1, managedConnection1.connectionCount); + // And decreases the connectionCount for the one that was used in the connection holder + assertEquals(-1, managedConnection2.connectionCount); + } + } + + @Test + public void testAssociateAndDissociateConnection() throws Exception { + ConnectionRequestInfo cxRequestInfo = null; + + final ManagedConnectionImpl managedConnection1 = createManagedConnection(null, new MyConnection()); + assertEquals(0, managedConnection1.connectionCount); + + final ManagedConnectionImpl managedConnection2 = createManagedConnection(null, new MyConnection()); + final Connection connection2 = managedConnection2.getActualConnection(); + assertEquals(0, managedConnection2.connectionCount); + + // Create an application-level connection handle ConnectionHolder linked to managedConnection2 + // and instruct the managedConnection1 to associate with this ConnectionHolder + try (ConnectionHolder connectionHolder = new MyConnectionHolder(connection2, managedConnection2, cxRequestInfo)) { + // Associate ManagedCollection1 to the connectionholder / handle + managedConnection1.associateConnection(connectionHolder); + assertNotNull(managedConnection1.myLogicalConnection); + assertNotNull(connectionHolder.getConnection()); + assertNotNull(connectionHolder.getManagedConnection()); + assertEquals(1, managedConnection1.connectionCount); + + // Dissociate, could be called by the application server in case "lazy connection association optimization" is used. + // Expect managedConnection1.myLogicalConnection to no longer reference the new connectionHolder. + // And the connectionHolder should no longer reference the managedConnection. + managedConnection1.dissociateConnections(); + assertNull(managedConnection1.myLogicalConnection); + assertNull(connectionHolder.getConnection()); + assertNull(connectionHolder.getManagedConnection()); + // Note: count is not decreased on dissociate call, it is decreased on connectionholder.close call + assertEquals(1, managedConnection1.connectionCount); + } + + // Close is called on connectionHolder, but it was no longer linked to managedConnection1. + // Thus connectionCount is not decreased from 1 to 0. + assertEquals(1, managedConnection1.connectionCount); + } + + /** + * Creates a ManagedConnectionImpl with a DSManagedConnectionFactory + */ + public static ManagedConnectionImpl createManagedConnection(PooledConnection pooledConnection, Connection sqlConnection) throws ResourceException { + // Password is optional + PasswordCredential passwdCred = null; + // Use DSManagedConnectionFactory + ManagedConnectionFactory mcf = new DSManagedConnectionFactory(); + // poolInfo + PoolInfo poolInfo = new PoolInfo(SimpleJndiName.of("myPoolInfo")); + // Default value is 0, no statement cache enabled + int statementCacheSize = 0; + // Cache is not enabled, no type needed + String statementCacheType = null; + // No SqlTrace needed + SQLTraceDelegator delegator = null; + // Leak timeout not used + long statementLeakTimeout = 0; + // Leak reclaim is not used + boolean statementLeakReclaim = false; + + return new ManagedConnectionImpl(pooledConnection, sqlConnection, passwdCred, + mcf, poolInfo, statementCacheSize, statementCacheType, + delegator, statementLeakTimeout, statementLeakReclaim); + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/XAManagedConnectionFactoryImplTest.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/XAManagedConnectionFactoryImplTest.java new file mode 100644 index 00000000000..23108de8855 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/XAManagedConnectionFactoryImplTest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi; + +import com.sun.gjc.spi.stub.MyXADataSource; + +public class XAManagedConnectionFactoryImplTest extends AbstractManagedConnectionFactoryImplTest { + + @Override + public ManagedConnectionFactoryImpl getManagedConnectionFactory() { + ManagedConnectionFactoryImpl mcf = new XAManagedConnectionFactory(); + mcf.setClassName(MyXADataSource.class.getCanonicalName()); + return mcf; + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnection.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnection.java new file mode 100644 index 00000000000..4d53eb8a933 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnection.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * Stub for java.sql.Connection with no implementation at all. Just to avoid using mocks. + */ +public class MyConnection implements Connection { + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + @Override + public Statement createStatement() throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return null; + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return null; + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + } + + @Override + public boolean getAutoCommit() throws SQLException { + return false; + } + + @Override + public void commit() throws SQLException { + } + + @Override + public void rollback() throws SQLException { + } + + @Override + public void close() throws SQLException { + } + + @Override + public boolean isClosed() throws SQLException { + return false; + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return null; + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public void setCatalog(String catalog) throws SQLException { + } + + @Override + public String getCatalog() throws SQLException { + return null; + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + } + + @Override + public int getTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return null; + } + + @Override + public void clearWarnings() throws SQLException { + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public Map> getTypeMap() throws SQLException { + return null; + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + } + + @Override + public void setHoldability(int holdability) throws SQLException { + } + + @Override + public int getHoldability() throws SQLException { + return 0; + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return null; + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return null; + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return null; + } + + @Override + public Clob createClob() throws SQLException { + return null; + } + + @Override + public Blob createBlob() throws SQLException { + return null; + } + + @Override + public NClob createNClob() throws SQLException { + return null; + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return null; + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return false; + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + } + + @Override + public String getClientInfo(String name) throws SQLException { + return null; + } + + @Override + public Properties getClientInfo() throws SQLException { + return null; + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return null; + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return null; + } + + @Override + public void setSchema(String schema) throws SQLException { + } + + @Override + public String getSchema() throws SQLException { + return null; + } + + @Override + public void abort(Executor executor) throws SQLException { + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + } + + @Override + public int getNetworkTimeout() throws SQLException { + return 0; + } +} \ No newline at end of file diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionHolder.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionHolder.java new file mode 100644 index 00000000000..61ccd14e80f --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionHolder.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import com.sun.gjc.spi.ManagedConnectionImpl; +import com.sun.gjc.spi.base.ConnectionHolder; + +import jakarta.resource.spi.ConnectionRequestInfo; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.NClob; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLXML; +import java.sql.Struct; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * Stub for com.sun.gjc.spi.base.ConnectionHolder with no implementation at all. Just to avoid using mocks. + */ +public class MyConnectionHolder extends ConnectionHolder { + + public MyConnectionHolder(Connection con, ManagedConnectionImpl mc, ConnectionRequestInfo cxRequestInfo) { + super(con, mc, cxRequestInfo); + } + + @Override + public Clob createClob() throws SQLException { + return null; + } + + @Override + public Blob createBlob() throws SQLException { + return null; + } + + @Override + public NClob createNClob() throws SQLException { + return null; + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return null; + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return false; + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + } + + @Override + public String getClientInfo(String name) throws SQLException { + return null; + } + + @Override + public Properties getClientInfo() throws SQLException { + return null; + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return null; + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return null; + } + + @Override + public void setSchema(String schema) throws SQLException { + } + + @Override + public String getSchema() throws SQLException { + return null; + } + + @Override + public void abort(Executor executor) throws SQLException { + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + } + + @Override + public int getNetworkTimeout() throws SQLException { + return 0; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionPoolDatasource.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionPoolDatasource.java new file mode 100644 index 00000000000..75639d473f1 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyConnectionPoolDatasource.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.io.PrintWriter; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.ConnectionPoolDataSource; +import javax.sql.PooledConnection; + +/** + * Stub for javax.sql.ConnectionPoolDataSource with no implementation at all. Just to avoid using mocks. + */ +public class MyConnectionPoolDatasource implements ConnectionPoolDataSource { + + public static final String NOT_ALLOWED_PASSWORD = "notAllowedPassword"; + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public PooledConnection getPooledConnection() throws SQLException { + return new MyPooledConnection(); + } + + @Override + public PooledConnection getPooledConnection(String user, String password) throws SQLException { + if (password.equals(NOT_ALLOWED_PASSWORD)) { + throw new SQLException("incorrect credentials"); + } + return new MyPooledConnection(); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } +} \ No newline at end of file diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDataSource.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDataSource.java new file mode 100644 index 00000000000..ab9d43b9bbd --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDataSource.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.DataSource; + +/** + * Stub for javax.sql.DataSource with no implementation at all. Just to avoid using mocks. + */ +public class MyDataSource implements DataSource { + + public static final String NOT_ALLOWED_PASSWORD = "notAllowedPassword"; + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + @Override + public Connection getConnection() throws SQLException { + return new MyConnection(); + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + if (password.equals(NOT_ALLOWED_PASSWORD)) { + throw new SQLException("incorrect credentials"); + } + return new MyConnection(); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDriver.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDriver.java new file mode 100644 index 00000000000..5ca8966117b --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyDriver.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.Properties; +import java.util.logging.Logger; + +/** + * Stub for java.sql.Driver with no implementation at all. Just to avoid using mocks. + */ +public class MyDriver implements Driver { + + public static final String ACCEPTED_URL = "jdbc/mydriver/url"; + public static final String NOT_ALLOWED_PASSWORD = "notAllowedPassword"; + + @Override + public Connection connect(String url, Properties info) throws SQLException { + String password = info.getProperty("password"); + if (password != null && password.equals(NOT_ALLOWED_PASSWORD)) { + throw new SQLException("incorrect credentials"); + } + return new MyConnection(); + } + + @Override + public boolean acceptsURL(String url) throws SQLException { + if (url.equals(ACCEPTED_URL)) { + return true; + } + return false; + } + + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return null; + } + + @Override + public int getMajorVersion() { + return 0; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public boolean jdbcCompliant() { + return false; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + +} diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyPooledConnection.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyPooledConnection.java new file mode 100644 index 00000000000..af4cb800a08 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyPooledConnection.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.ConnectionEventListener; +import javax.sql.PooledConnection; +import javax.sql.StatementEventListener; + +/** + * Stub for javax.sql.PooledConnection with no implementation at all. Just to avoid using mocks. + */ +public class MyPooledConnection implements PooledConnection { + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public void close() throws SQLException { + } + + @Override + public void addConnectionEventListener(ConnectionEventListener listener) { + } + + @Override + public void removeConnectionEventListener(ConnectionEventListener listener) { + } + + @Override + public void addStatementEventListener(StatementEventListener listener) { + } + + @Override + public void removeStatementEventListener(StatementEventListener listener) { + } +} \ No newline at end of file diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXAConnection.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXAConnection.java new file mode 100644 index 00000000000..2b7eb0fa6f4 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXAConnection.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.ConnectionEventListener; +import javax.sql.StatementEventListener; +import javax.sql.XAConnection; +import javax.transaction.xa.XAResource; + +/** + * Stub for javax.sql.XAConnection with no implementation at all. Just to avoid using mocks. + */ +public class MyXAConnection implements XAConnection { + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public void close() throws SQLException { + } + + @Override + public void addConnectionEventListener(ConnectionEventListener listener) { + } + + @Override + public void removeConnectionEventListener(ConnectionEventListener listener) { + } + + @Override + public void addStatementEventListener(StatementEventListener listener) { + } + + @Override + public void removeStatementEventListener(StatementEventListener listener) { + } + + @Override + public XAResource getXAResource() throws SQLException { + return null; + } +} \ No newline at end of file diff --git a/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXADataSource.java b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXADataSource.java new file mode 100644 index 00000000000..bb113d3fc85 --- /dev/null +++ b/appserver/jdbc/jdbc-ra/jdbc-core/src/test/java/com/sun/gjc/spi/stub/MyXADataSource.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.gjc.spi.stub; + +import java.io.PrintWriter; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.XAConnection; +import javax.sql.XADataSource; + +/** + * Stub for javax.sql.XADataSource with no implementation at all. Just to avoid using mocks. + */ +public class MyXADataSource implements XADataSource { + + public static final String NOT_ALLOWED_PASSWORD = "notAllowedPassword"; + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public XAConnection getXAConnection() throws SQLException { + return new MyXAConnection(); + } + + @Override + public XAConnection getXAConnection(String user, String password) throws SQLException { + if (password.equals(NOT_ALLOWED_PASSWORD)) { + throw new SQLException("incorrect credentials"); + } + return new MyXAConnection(); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } +} \ No newline at end of file diff --git a/appserver/tests/appserv-tests/connectors-ra-redeploy/jars/src/main/java/com/sun/jdbcra/spi/ManagedConnection.java b/appserver/tests/appserv-tests/connectors-ra-redeploy/jars/src/main/java/com/sun/jdbcra/spi/ManagedConnection.java index 1fdd2948f4d..a7a29313cb0 100755 --- a/appserver/tests/appserv-tests/connectors-ra-redeploy/jars/src/main/java/com/sun/jdbcra/spi/ManagedConnection.java +++ b/appserver/tests/appserv-tests/connectors-ra-redeploy/jars/src/main/java/com/sun/jdbcra/spi/ManagedConnection.java @@ -413,7 +413,9 @@ public XAResource getXAResource() throws ResourceException { */ @Override public void removeConnectionEventListener(ConnectionEventListener listener) { - listener = null; + if (this.listener == listener) { + this.listener = null; + } } /** @@ -572,12 +574,13 @@ void connectionClosed(Exception e, ConnectionHolder connHolderObject) throws SQL activeConnectionHandle = null; ce.setConnectionHandle(connHolderObject); - listener.connectionClosed(ce); - + if (listener != null) { + listener.connectionClosed(ce); + } } /** - * This method is called by the ConnectionHolder when it detects a connecion + * This method is called by the ConnectionHolder when it detects a connection * related error. * * @param e Exception that has occurred during an operation on the physical connection @@ -587,7 +590,6 @@ void connectionClosed(Exception e, ConnectionHolder connHolderObject) throws SQL void connectionErrorOccurred(Exception e, com.sun.jdbcra.spi.ConnectionHolder connHolderObject) { - ConnectionEventListener cel = this.listener; ConnectionEvent ce = null; ce = e == null ? new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED) : new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, e); @@ -595,12 +597,12 @@ void connectionErrorOccurred(Exception e, ce.setConnectionHandle(connHolderObject); } - cel.connectionErrorOccurred(ce); + if (listener != null) { + listener.connectionErrorOccurred(ce); + } isUsable = false; } - - /** * This method is called by the XAResource object when its start method * has been invoked.