diff --git a/appserver/connectors/connectors-internal-api/src/main/java/com/sun/appserv/connectors/internal/api/TransactedPoolManager.java b/appserver/connectors/connectors-internal-api/src/main/java/com/sun/appserv/connectors/internal/api/TransactedPoolManager.java index 826fab1ae41..fbcd5e9986e 100644 --- a/appserver/connectors/connectors-internal-api/src/main/java/com/sun/appserv/connectors/internal/api/TransactedPoolManager.java +++ b/appserver/connectors/connectors-internal-api/src/main/java/com/sun/appserv/connectors/internal/api/TransactedPoolManager.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 Eclipse Foundation and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -35,22 +36,24 @@ public interface TransactedPoolManager { * pool manager. * * @param tran Transaction to which the resource is enlisted - * @param res Resource that is enlisted + * @param resource Resource that is enlisted * @throws IllegalStateException when unable to enlist the resource */ - void resourceEnlisted(Transaction tran, ResourceHandle res) throws IllegalStateException; + void resourceEnlisted(Transaction tran, ResourceHandle resource) throws IllegalStateException; /** - * registers the provided resource with the component & enlists the resource in the transaction - * @param handle resource-handle + * Registers the provided resource with the component & enlists the resource in the transaction + * + * @param resource Resource to be registered. * @throws PoolingException when unable to register the resource */ - void registerResource(ResourceHandle handle) throws PoolingException; + void registerResource(ResourceHandle resource) throws PoolingException; /** - * unregisters the resource from the component and delists the resource from the transaction - * @param resource resource-handle - * @param xaresFlag + * Unregisters the resource from the component and delists the resource from the transaction + * + * @param resource Resource to be unregistered. + * @param xaresFlag flag indicating transaction success. This can be XAResource.TMSUCCESS or XAResource.TMFAIL */ void unregisterResource(ResourceHandle resource, int xaresFlag); } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/connectors/util/ConnectionPoolReconfigHelper.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/connectors/util/ConnectionPoolReconfigHelper.java index fa4d513d6c5..578ff3a2e4a 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/connectors/util/ConnectionPoolReconfigHelper.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/connectors/util/ConnectionPoolReconfigHelper.java @@ -34,8 +34,17 @@ public final class ConnectionPoolReconfigHelper { LogDomains.RSR_LOGGER); public enum ReconfigAction { + /** + * Recreate connection pool + */ RECREATE_POOL, + /** + * Update ManagedConnectionFactory and attributes + */ UPDATE_MCF_AND_ATTRIBUTES, + /** + * No operation + */ NO_OP } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/allocator/ResourceAllocator.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/allocator/ResourceAllocator.java index e06fb2b6174..774c48f51d2 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/allocator/ResourceAllocator.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/allocator/ResourceAllocator.java @@ -54,6 +54,12 @@ public interface ResourceAllocator { boolean isTransactional(); + /** + * Forces the cleanup of the ManagedConnection associated to the given resource. + * + * @param resource the resource referencing a ManagedConnection + * @throws PoolingException in case the cleanup failed + */ void cleanup(ResourceHandle resource) throws PoolingException; boolean shareableWithinComponent(); diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/AbstractPoolManager.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/AbstractPoolManager.java index 151df17f5bf..e8b8c557417 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/AbstractPoolManager.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/AbstractPoolManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -17,33 +17,40 @@ package com.sun.enterprise.resource.pool; +<<<<<<< Upstream, based on origin/master import com.sun.enterprise.resource.ResourceSpec; import java.util.concurrent.ConcurrentHashMap; import org.glassfish.resourcebase.resources.api.PoolInfo; +======= +>>>>>>> f4ffa0b Part 3 for issue #24900 More documentation and more unit test coverage. /** * Abstract Pool manager for unimplemented features. Throws UnsupportedOperationException when invoked. */ public abstract class AbstractPoolManager implements PoolManager { - @Override - public void emptyResourcePool(ResourceSpec spec) { - throw new UnsupportedOperationException(); - } - - @Override - public void killAllPools() { - throw new UnsupportedOperationException(); - } - - @Override - public void setSelfManaged(PoolInfo poolInfo, boolean flag) { - throw new UnsupportedOperationException(); - } - - public ConcurrentHashMap getMonitoredPoolTable() { - throw new UnsupportedOperationException(); - } +// Not used in the code +// @Override +// public void emptyResourcePool(ResourceSpec spec) { +// throw new UnsupportedOperationException(); +// } + +// Not used in the code +// @Override +// public void killAllPools() { +// throw new UnsupportedOperationException(); +// } + +// Not used in the code +// @Override +// public void setSelfManaged(PoolInfo poolInfo, boolean flag) { +// throw new UnsupportedOperationException(); +// } + +// Not used in the code +// public ConcurrentHashMap getMonitoredPoolTable() { +// throw new UnsupportedOperationException(); +// } } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ConnectionPool.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ConnectionPool.java index 9457688b2d9..799f2aad290 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ConnectionPool.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ConnectionPool.java @@ -379,12 +379,12 @@ protected Resizer initializeResizer() { } /** - * add a resource with status busy and not enlisted + * Add a resource to the pool with status busy and not enlisted. * - * @param alloc ResourceAllocator + * @param alloc the ResourceAllocator to be used * @throws PoolingException when unable to add a resource */ - public void addResource(ResourceAllocator alloc) throws PoolingException { + private void addResource(ResourceAllocator alloc) throws PoolingException { int numResCreated = dataStructure.addResource(alloc, 1); if (numResCreated > 0) { for (int i = 0; i < numResCreated; i++) { @@ -568,7 +568,7 @@ public ResourceHandle getResource(ResourceSpec spec, ResourceAllocator alloc, Tr * Overridden in AssocWithThreadResourcePool to fetch the resource cached in the ThreadLocal In ConnectionPool this * simply returns null. * - * @param spec ResourceSpec + * @param spec the ResourceSpec used to locate the correct resource pool * @param alloc ResourceAllocator to create a resource * @param tran Transaction * @return ResourceHandle resource from ThreadLocal @@ -613,7 +613,7 @@ protected ResourceHandle internalGetResource(ResourceSpec resourceSpec, Resource * * @param transaction Current Transaction * @param resourceAllocator ResourceAllocator - * @param resourceSpec ResourceSpec + * @param resourceSpec the ResourceSpec used to locate the correct resource pool * @return result ResourceHandle */ private ResourceHandle getResourceFromTransaction(Transaction transaction, ResourceAllocator resourceAllocator, ResourceSpec resourceSpec) { @@ -706,7 +706,7 @@ private ResourceHandle getResourceFromTransaction(Transaction transaction, Resou /** * To provide an unenlisted, valid, matched resource from pool. * - * @param resourceSpec ResourceSpec + * @param resourceSpec the ResourceSpec used to locate the correct resource pool * @param resourceAllocator ResourceAllocator * @param transaction Transaction * @return ResourceHandle resource from pool @@ -793,6 +793,7 @@ protected boolean matchConnection(ResourceHandle resource, ResourceAllocator all * return a new resource. returns null if the pool new resources cannot be created.
* * @param resourceAllocator ResourceAllocator + * @param resourceSpec the ResourceSpec used to locate the correct resource pool * @return ResourceHandle resource from pool * @throws PoolingException if unable to create a new resource */ @@ -941,7 +942,7 @@ private ResourceHandle getMatchedResourceFromPool(ResourceAllocator alloc) { } /** - * Try to purge resources by size <= quantity
+ * Try to purge resources by size <= quantity * * @param quantity maximum no. of resources to remove.
* @return resourceCount No. of resources actually removed.
@@ -970,14 +971,16 @@ private int purgeResources(int quantity) { * replacement is required since the steadypoolsize might equal maxpoolsize and in that case if we were not to remove a * resource from the pool, our resource would be above maxPoolSize * - * @param resourceAllocator ResourceAllocator to create resource - * @param resourceSpec ResourceSpec + * @param resourceAllocator the resource allocator to be used to create the new resource + * @param resourceSpec the ResourceSpec used to locate the correct resource pool * @return newly created resource * @throws PoolingException when unable to create a resource */ protected ResourceHandle createSingleResourceAndAdjustPool(ResourceAllocator resourceAllocator, ResourceSpec resourceSpec) throws PoolingException { + // TODO document in getResource when a return value can be null ResourceHandle handle = dataStructure.getResource(); if (handle != null) { + // TODO document why it is removed / add unit test to show the behavior described in the javadoc of the method dataStructure.removeResource(handle); } @@ -986,9 +989,9 @@ protected ResourceHandle createSingleResourceAndAdjustPool(ResourceAllocator res /** * Method to be used to create resource, instead of calling ResourceAllocator.createConfigBean(). This method handles - * the connection creation retrial in case of failure + * the connection creation retry in case of failure. * - * @param resourceAllocator ResourceAllocator + * @param resourceAllocator the resource allocator to be used to create the new resource * @return ResourceHandle newly created resource * @throws PoolingException when unable create a resource */ @@ -1023,9 +1026,9 @@ protected ResourceHandle createSingleResource(ResourceAllocator resourceAllocato } /** - * Create specified number of resources. + * Create specified number of resources using the given resource allocater. * - * @param alloc ResourceAllocator + * @param alloc the resource allocator to be used to create the new resource * @param size number of resources to create. * @throws PoolingException When unable to create a resource */ @@ -1162,16 +1165,22 @@ protected void freeResource(ResourceHandle resourceHandle) { } - protected boolean cleanupResource(ResourceHandle handle) { + /** + * Asks the resource allocator to cleanup the resource + * + * @param resource the resource to be cleaned up + * @return true if cleanup was successful, otherwise false + */ + protected boolean cleanupResource(ResourceHandle resource) { boolean cleanupSuccessful = true; // cleanup resource try { - ResourceAllocator alloc = handle.getResourceAllocator(); - alloc.cleanup(handle); + ResourceAllocator alloc = resource.getResourceAllocator(); + alloc.cleanup(resource); } catch (PoolingException ex) { LOG.log(WARNING, "Cleanup of a resource from pool [" + poolInfo.getName() + "] failed.", ex); cleanupSuccessful = false; - resourceErrorOccurred(handle); + resourceErrorOccurred(resource); } return cleanupSuccessful; } @@ -1245,12 +1254,6 @@ private void doFailAllConnectionsProcessing() { scheduleResizerTask(); } - /** - * This method is called when a resource is enlisted in a transaction. - * - * @param tran Transaction - * @param resource ResourceHandle - */ @Override public void resourceEnlisted(Transaction tran, ResourceHandle resource) throws IllegalStateException { poolTxHelper.resourceEnlisted(tran, resource); @@ -1346,6 +1349,7 @@ private void incrementNumConnFailedValidation() { } } + // TODO: this method name should be createAndGetNewResource, but it is only used once, to it could be removed private ResourceHandle getNewResource(ResourceAllocator alloc) throws PoolingException { addResource(alloc); return dataStructure.getResource(); @@ -1364,6 +1368,9 @@ public void emptyPool() { @Override public void emptyFreeConnectionsInPool() { LOG.log(FINE, "Emptying free connections in the pool {0}", poolInfo.getName()); + + // TODO this is not completely thread safe, between getResource and removeResource + // the dataStructure can be altered by other threads ResourceHandle h; while ((h = dataStructure.getResource()) != null) { dataStructure.removeResource(h); @@ -1408,11 +1415,6 @@ public long getReconfigWaitTime() { return reconfigWaitTime; } - /** - * Reinitialize connections established in the connection pool and bring the pool to steady pool size. - * - * @throws com.sun.appserv.connectors.internal.api.PoolingException - */ @Override public synchronized boolean flushConnectionPool() throws PoolingException { LOG.log(FINE, "Flushing Connection Pool {0}", poolInfo); @@ -1430,13 +1432,6 @@ public synchronized boolean flushConnectionPool() throws PoolingException { return true; } - /** - * Reconfigure the Pool's properties. The reconfigConnectorConnectionPool method in the ConnectorRuntime will use this - * method (through PoolManager) if it needs to just change pool properties and not recreate the pool - * - * @param poolResource - the ConnectorConnectionPool JavaBean that holds the new pool properties - * @throws PoolingException if the pool resizing fails - */ @Override public synchronized void reconfigurePool(ConnectorConnectionPool poolResource) throws PoolingException { int _idleTime = Integer.parseInt(poolResource.getIdleTimeoutInSeconds()) * 1000; @@ -1564,8 +1559,13 @@ private void killExtraResources(int numToKill) { scheduleResizerTask(); } - /* - * Increase the number of steady resources in the pool if we detect that the steadyPoolSize has been increased + /** + * Increase the number of steady resources in the pool if we detect that the steadyPoolSize has been increased.
+ * Note: if the newSteadyPoolSize is smaller than the current pool size, no changes are made directly. The resizer task + * is updated in all cases and will resize the pool in the future. + * + * @param newSteadyPoolSize The new steady pool size + * @throws PoolingException when unable to add new resources to the pool */ private void increaseSteadyPoolSize(int newSteadyPoolSize) throws PoolingException { cancelResizerTask(); @@ -1575,27 +1575,16 @@ private void increaseSteadyPoolSize(int newSteadyPoolSize) throws PoolingExcepti scheduleResizerTask(); } - /** - * @param alloc ResourceAllocator - * @throws PoolingException when unable to create a resource - */ + // TODO is this private method needed? Why not call addResource directly? private void createResourceAndAddToPool(ResourceAllocator alloc) throws PoolingException { addResource(alloc); } - /** - * Switch on matching of connections in the pool. - */ @Override public void switchOnMatching() { matchConnections = true; } - /** - * query the name of this pool. Required by monitoring - * - * @return the name of this pool - */ @Override public final PoolInfo getPoolInfo() { return poolInfo; @@ -1707,12 +1696,6 @@ public void reclaimConnection(ResourceHandle handle) { notifyWaitingThreads(); } - /** - * Get Connection Pool status by computing the free/used values of the connections in the pool. Computations are based - * on whether the pool is initialized or not when this method is invoked. - * - * @return PoolStatus object - */ @Override public PoolStatus getPoolStatus() { PoolStatus poolStatus = new PoolStatus(this.poolInfo); diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManager.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManager.java index ddd4c0fe7e1..0d8a1b194d1 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManager.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManager.java @@ -46,62 +46,142 @@ public interface PoolManager extends TransactedPoolManager { // transaction support levels - int NO_TRANSACTION = 0; - int LOCAL_TRANSACTION = 1; - int XA_TRANSACTION = 2; + // int NO_TRANSACTION = 0; + // int LOCAL_TRANSACTION = 1; + // int XA_TRANSACTION = 2; // Authentication mechanism levels - int BASIC_PASSWORD = 0; - int KERBV5 = 1; + // int BASIC_PASSWORD = 0; + // int KERBV5 = 1; // Credential Interest levels - String PASSWORD_CREDENTIAL = "jakarta.resource.spi.security.PasswordCredential"; - String GENERIC_CREDENTIAL = "jakarta.resource.spi.security.GenericCredential"; + // String PASSWORD_CREDENTIAL = "jakarta.resource.spi.security.PasswordCredential"; + // String GENERIC_CREDENTIAL = "jakarta.resource.spi.security.GenericCredential"; /** * Flush Connection pool by reinitializing the connections established in the pool. * - * @param poolInfo - * @throws com.sun.appserv.connectors.internal.api.PoolingException + * @param poolInfo the pool identifier for which the status needs to be flushed. + * @throws com.sun.appserv.connectors.internal.api.PoolingException in case the given pool is not initialized. */ boolean flushConnectionPool(PoolInfo poolInfo) throws PoolingException; /** - * @return connection pool status. + * Returns the pool status for the pool identified by the given poolInfo. + * + * @param poolInfo the pool identifier for which the status needs to be returned. + * @return pool status information if the pool is found based on the provided poolInfo, otherwise null is returned. */ PoolStatus getPoolStatus(PoolInfo poolInfo); ResourceHandle getResourceFromPool(ResourceSpec spec, ResourceAllocator alloc, ClientSecurityInfo info, - Transaction transaction) throws PoolingException, RetryableUnavailableException; + Transaction transaction) throws PoolingException, RetryableUnavailableException; - void createEmptyConnectionPool(PoolInfo poolInfo, PoolType pt, Hashtable env) throws PoolingException; + /** + * Creates an empty connection pool with the given pool info and pool type. + * + * @param poolInfo the pool identifier of the new pool + * @param poolType the type of the connection pool + * @param env hashtable used to find the connection pool ConnectorConnectionPool information to set parameters like + * maximum number of connections + * @throws PoolingException when unable to create/initialize pool + */ + void createEmptyConnectionPool(PoolInfo poolInfo, PoolType poolType, Hashtable env) throws PoolingException; + /** + * Returns the resource back to the pool IF errorOccurred is false. If errorOccurred is true the resource is removed + * from the pool. + *

+ * Note: The resource object may not be used anymore by the calling code after this call. + * + * @param resourceHandle the resource handle. + * @param errorOccurred true if an error occurred and the resource should not be returned to the pool, otherwise use + * false + *

+ * TODO The method name is misleading
+ * TODO Why is NoTxConnectorAllocator the only one calling this interface method and the rest of the calls are using + * resourceClosed / resourceErrorOccurred and resourceAbortOccurred ? Is the difference between resourceClosed and + * putbackResourceToPool that resourceClosed informs the transaction and putbackResourceToPool does not? + */ void putbackResourceToPool(ResourceHandle resourceHandle, boolean errorOccurred); - void putbackBadResourceToPool(ResourceHandle resourceHandle); - + /** + * Notifies the pool the resource is not used by a bean/application anymore.
+ * The resource is returned to the pool and the state of the resource is no longer busy.
+ * The resource is NOT delisted / unenlisted from the current transaction. + *

+ * Note: The resource object may not be used anymore by the calling code after this call. + * + * @param resourceHandle the resource handle + * @param poolInfo the pool information of the pool where the resource is expected to be removed from. If the given pool + * info is not found no exception is thrown. + *

+ * TODO Why is this method public available and only used internal in PoolManagerImpl and externally in + * LazyEnlistableResourceManagerImpl. Why can't LazyEnlistableResourceManagerImpl just call resourceClosed? If poolInfo + * = resourceHandle.getResourceSpec().getPoolInfo() then LazyEnlistableResourceManagerImpl could just as well call + * resourceClosed and then this method can be removed from the interface. + */ void putbackDirectToPool(ResourceHandle resourceHandle, PoolInfo poolInfo); + /** + * Closes the resource handle and returns it back to the connection pool.
+ * The resource is returned to the pool and the state of the resource is no longer busy.
+ * The resource is also delisted / unenlisted from the current transaction. + *

+ * Note: The resource object may not be used anymore by the calling code after this call. + * + * @param resourceHandle the resource handle to be closed and returned to the pool. + */ void resourceClosed(ResourceHandle resourceHandle); + // TODO Why is this method public available? Why is it not called via resourceErrorOccurred or resourceAbortOccurred? void badResourceClosed(ResourceHandle resourceHandle); void resourceErrorOccurred(ResourceHandle resourceHandle); void resourceAbortOccurred(ResourceHandle resourceHandle); + /** + * Inform all the connection pools using this transaction that the transaction has completed. This method is called by + * the EJB Transaction Manager.
+ * All resource handles associated to the given transaction are delisted.
+ * All resource handles associated to the given transaction handed back to the connection pool. + * + * @param transaction the transaction that is completed + * @param status the status of the transaction + */ void transactionCompleted(Transaction transaction, int status); - void emptyResourcePool(ResourceSpec spec); + // Not used in the code + // void emptyResourcePool(ResourceSpec spec); + /** + * Kills the pool for the given PoolInfo.
+ * Note: if the pool is not found the method ends with success. + * + * @param poolInfo the pool identifier for which the pool needs to be killed. + */ void killPool(PoolInfo poolInfo); + /** + * Reconfigures the connection pool to apply the given properties.
+ * Note: if the pool is not found the method ends with success. + * + * @param ccp the object containing the new connection pool properties that will be applied to the existing pool + * @throws PoolingException if reconfiguration of the pool failed + */ void reconfigPoolProperties(ConnectorConnectionPool ccp) throws PoolingException; + /** + * Switch on matching in the pool. + * + * @param poolInfo the pool identifier for which the pool matching needs to be switched on. + */ boolean switchOnMatching(PoolInfo poolInfo); /** - * Obtain a transactional resource such as JDBC connection + * Obtain a transactional resource such as JDBC connection from the connection pool. The caller is blocked until a + * resource is acquired or the max-wait-time of the connection pool expires. * * @param spec Specification for the resource * @param alloc Allocator for the resource @@ -113,17 +193,39 @@ ResourceHandle getResourceFromPool(ResourceSpec spec, ResourceAllocator alloc, C ResourceReferenceDescriptor getResourceReference(SimpleJndiName jndiName, SimpleJndiName logicalName); - void killAllPools(); - + /** + * Kills all free connections in the registered connection pools. The pools are not killed. + */ void killFreeConnectionsInPools(); + /** + * Returns the ResourcePool for the given PoolInfo + * + * @param poolInfo the pool identifier + * @return the ResourcePool if found, otherwise null + */ ResourcePool getPool(PoolInfo poolInfo); - void setSelfManaged(PoolInfo poolInfo, boolean flag); - - void lazyEnlist(ManagedConnection mc) throws ResourceException; + /** + * This method gets called by the LazyEnlistableConnectionManagerImpl when a connection needs enlistment, i.e on use of + * a Statement etc. Based on the given managagedConneciton the transaction manager is found and used to find the + * transaction. If no transaction was found this method returns without an error. + * + * @param managedConnection the managedConnection that needs to be enlisted in the transaction + * @throws ResourceException in case enlistment to the transaction failed. + */ + void lazyEnlist(ManagedConnection managedConnection) throws ResourceException; + /** + * Registers a PoolLifeCycle listener in the pool manager. The listener is used to keep track of statistics of the pool + * life cycle: pool created and pool destroyed events. + * + * @param poolListener the listener instance + */ void registerPoolLifeCycleListener(PoolLifeCycle poolListener); + /** + * Unregisters the PoolLifeCycle listener in the pool manager. + */ void unregisterPoolLifeCycleListener(); } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManagerImpl.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManagerImpl.java index ac8f40565e3..3b6875b4d98 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManagerImpl.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/PoolManagerImpl.java @@ -225,11 +225,6 @@ public ResourceHandle getResourceFromPool(ResourceSpec resourceSpec, ResourceAll return getPool(resourceSpec.getPoolInfo()).getResource(resourceSpec, resourceAllocator, transaction); } - /** - * Switch on matching in the pool. - * - * @param poolInfo Name of the pool - */ @Override public boolean switchOnMatching(PoolInfo poolInfo) { ResourcePool pool = getPool(poolInfo); @@ -276,7 +271,6 @@ private void addSyncListener(Transaction transaction) { } } - // called by EJB Transaction Manager @Override public void transactionCompleted(Transaction transaction, int status) throws IllegalStateException { Set pools = ((JavaEETransaction) transaction).getAllParticipatingPools(); @@ -313,10 +307,6 @@ public void resourceEnlisted(Transaction transaction, com.sun.appserv.connectors } } - /** - * This method gets called by the LazyEnlistableConnectionManagerImpl when a connection needs enlistment, i.e on use of - * a Statement etc. - */ @Override public void lazyEnlist(ManagedConnection mc) throws ResourceException { lazyEnlistableResourceManager.lazyEnlist(mc); @@ -365,17 +355,35 @@ public void badResourceClosed(ResourceHandle resource) { @Override public void resourceErrorOccurred(ResourceHandle resource) { + // TODO: Why is delistResource not called like done in resourceAbortOccurred and in resourceClosed? + // Shouldn't delistResource be called with TMFAIL ? + // Added example in unit test PoolManagerImplTest that shows the delist is not called. + + // TODO: Why is resourceHandle.setConnectionErrorOccurred() not performed? + // Added example in unit test PoolManagerImplTest that shows connection error is not updated + putbackResourceToPool(resource, true); } @Override public void resourceAbortOccurred(ResourceHandle resource) { + // TODO: Why is TMSUCCESS used and not TMFAIL? Document the meaning of Abort. + //

+ // com.sun.gjc.spi.ManagedConnectionImpl.transactionCompleted() + // performs: badConnectionEventListener.connectionAbortOccurred -> jdbc.markedForRemoval_conAborted + //

+ // com.sun.gjc.spi.jdbc40.ConnectionHolder40.abort(Executor) documents: "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" getResourceManager(resource.getResourceSpec()).delistResource(resource, TMSUCCESS); + + // TODO: Why is resourceHandle.setConnectionErrorOccurred() not performed? + // Added example in unit test PoolManagerImplTest that shows connection error is not updated putbackResourceToPool(resource, true); } - @Override - public void putbackBadResourceToPool(ResourceHandle resourceHandle) { + private void putbackBadResourceToPool(ResourceHandle resourceHandle) { // Notify pool PoolInfo poolInfo = resourceHandle.getResourceSpec().getPoolInfo(); if (poolInfo != null) { diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ResourcePool.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ResourcePool.java index 17f941d612f..f9d79d3d896 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ResourcePool.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/ResourcePool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 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 @@ -46,11 +46,28 @@ public interface ResourcePool { */ void resourceClosed(ResourceHandle resource); + /** + * Updates the resource to be marked as not busy / free, remove the resource from the connection pool and inform any + * waiting threads that a resource has become available. + * + * @param resource the resource that will be removed from the connection pool + */ void resourceErrorOccurred(ResourceHandle resource); + /** + * This method is called when a resource is enlisted in a transaction. + * + * @param tran the Transaction to enlist the resource in + * @param resource the ResourceHandle that will be enlisted in the given transaction + */ void resourceEnlisted(Transaction tran, ResourceHandle resource); - // Get status of pool + /** + * Get the Pool status by computing the free/used values of the connections in the pool. Computations are based on + * whether the pool is initialized or not when this method is invoked. + * + * @return the PoolStatus object + */ PoolStatus getPoolStatus(); /** @@ -63,20 +80,43 @@ public interface ResourcePool { */ void transactionCompleted(Transaction tran, int status); + /** + * Resize the pool by removing idle and invalid resources.
+ * Only when forced is true the pool size is scaled down with the pool resize quantity. + * + * @param forced when force is true, scale down the pool with the pool resize quantity. + */ void resizePool(boolean forced); - // forcefully destroy all connections in the pool even if - // connections have transactions in progress + /** + * Forcefully destroy all connections in the pool even if connections have transactions in progress + */ void emptyPool(); - // reconfig the pool's properties + /** + * Reconfigure the Pool's properties. The reconfigConnectorConnectionPool method in the ConnectorRuntime will use this + * method (through PoolManager) if it needs to just change pool properties and not recreate the pool + * + * @param poolResource - the ConnectorConnectionPool JavaBean that holds the new pool properties + * @throws PoolingException if the pool resizing fails + */ void reconfigurePool(ConnectorConnectionPool ccp) throws PoolingException; - // cancel the resizer task in the pool + /** + * Cancel the resizer task in the pool if it exists. + */ void cancelResizerTask(); + /** + * Switch on matching of connections in the pool. + */ void switchOnMatching(); + /** + * Get the PoolInfo unique identifier of this pool. + * + * @return the PoolInfo unique identifier of this pool + */ PoolInfo getPoolInfo(); void emptyFreeConnectionsInPool(); @@ -131,22 +171,23 @@ public interface ResourcePool { void setSelfManaged(boolean selfManaged); /** - * set pool life cycle listener + * Set the pool life cycle listener * - * @param listener + * @param listener the new PoolLifeCycleListener */ void setPoolLifeCycleListener(PoolLifeCycleListener listener); /** - * remove pool life cycle listener + * Remove the pool life cycle listener */ void removePoolLifeCycleListener(); /** - * Flush Connection pool by reinitializing the connections established in the pool. + * Flush Connection pool by removing all resources established in the connection pool and bring the pool to steady pool + * size. * * @return boolean indicating whether flush operation was successful or not - * @throws com.sun.appserv.connectors.internal.api.PoolingException + * @throws PoolingException in case the pool was not initialized */ boolean flushConnectionPool() throws PoolingException; @@ -174,7 +215,7 @@ public interface ResourcePool { /** * returns the reconfig-wait-time * - * @return long + * @return the reconfig-wait-time */ long getReconfigWaitTime(); } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/datastructure/DataStructure.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/datastructure/DataStructure.java index 83245b0d4fa..58861730bfa 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/datastructure/DataStructure.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/datastructure/DataStructure.java @@ -43,11 +43,11 @@ public interface DataStructure { void setMaxSize(int maxSize); /** - * creates a new resource and adds to the datastructure. + * Create a new resource using the given resource-allocator and add it to the datastructure. * - * @param allocator ResourceAllocator - * @param count Number (units) of resources to create - * @return int number of resources added. + * @param allocator the resource-allocator to be used + * @param count the number (units) of resources to create + * @return the number of resources added * @throws PoolingException when unable to create a resource */ int addResource(ResourceAllocator allocator, int count) throws PoolingException; @@ -93,11 +93,11 @@ public interface DataStructure { int getResourcesSize(); /** - * Get all resources in the datastructure Note : do not use this for normal usages as it can potentially represent all - * resources (including the ones in use). This is used under special circumstances where there is a need to process all - * resources. + * Get all resources in the datastructure
+ * Note: do not use this for normal usages as it can potentially represent all resources (including the ones in use). + * This is used under special circumstances where there is a need to process all resources. * - * @return List + * @return the list of resources in the data structure. */ List getAllResources(); } diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/resizer/Resizer.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/resizer/Resizer.java index 10d8989ac40..b9046e20247 100644 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/resizer/Resizer.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/pool/resizer/Resizer.java @@ -83,9 +83,10 @@ public void run() { } /** - * Resize the pool + * Resize the pool by removing idle and invalid resources.
+ * Only when forced is true the pool size is scaled down with the pool resize quantity. * - * @param forced when force is true, scale down the pool. + * @param forced when force is true, scale down the pool with the pool resize quantity. */ public void resizePool(boolean forced) { @@ -125,13 +126,14 @@ private void ensureSteadyPool() { } /** - * Scale down pool by a size <= pool-resize-quantity + * Scale down pool by a size <= pool-resize-quantity but only if forced is true * - * @param forced scale-down only when forced - * @param scaleDownQuantity no. of resources to remove + * @param scaleDownQuantity the number of resources to remove + * @param forced scale-down only when forced value is true + * + * TODO: move forced parameter out of this method and move it to the calling code */ protected void scaleDownPool(int scaleDownQuantity, boolean forced) { - if (pool.getResizeQuantity() > 0 && forced) { scaleDownQuantity = (scaleDownQuantity <= (dataStructure.getResourcesSize() - pool.getSteadyPoolSize())) ? scaleDownQuantity : 0; diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/LazyEnlistableResourceManagerImpl.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/LazyEnlistableResourceManagerImpl.java index 9fb3d0eac26..77a3ea17a1e 100755 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/LazyEnlistableResourceManagerImpl.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/LazyEnlistableResourceManagerImpl.java @@ -17,6 +17,13 @@ package com.sun.enterprise.resource.rm; +import java.util.List; +import java.util.ListIterator; +import java.util.logging.Logger; + +import org.glassfish.api.invocation.ComponentInvocation; +import org.glassfish.resourcebase.resources.api.PoolInfo; + import com.sun.appserv.connectors.internal.api.PoolingException; import com.sun.enterprise.connectors.ConnectorRuntime; import com.sun.enterprise.resource.ResourceHandle; @@ -28,12 +35,6 @@ import jakarta.transaction.SystemException; import jakarta.transaction.Transaction; -import java.util.List; -import java.util.ListIterator; -import java.util.logging.Logger; - -import org.glassfish.api.invocation.ComponentInvocation; - import static com.sun.logging.LogDomains.RSR_LOGGER; import static java.util.logging.Level.WARNING; @@ -123,10 +124,11 @@ public void lazyEnlist(ManagedConnection managedConnection) throws ResourceExcep } catch (Exception e) { // In the rare cases where enlistResource throws exception, we // should return the resource to the pool - ConnectorRuntime.getRuntime().getPoolManager().putbackDirectToPool(resourceHandle, - resourceHandle.getResourceSpec().getPoolInfo()); + // TODO: Why not call resourceClosed instead of putbackDirectToPool? + PoolInfo poolInfo = resourceHandle.getResourceSpec().getPoolInfo(); + ConnectorRuntime.getRuntime().getPoolManager().putbackDirectToPool(resourceHandle, poolInfo); - LOG.log(WARNING, "poolmgr.err_enlisting_res_in_getconn", resourceHandle.getResourceSpec().getPoolInfo()); + LOG.log(WARNING, "poolmgr.err_enlisting_res_in_getconn", poolInfo); LOG.fine("rm.enlistResource threw Exception. Returning resource to pool"); // And rethrow the exception diff --git a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/ResourceManager.java b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/ResourceManager.java index 8911987ad2b..b93f7ef22c4 100755 --- a/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/ResourceManager.java +++ b/appserver/connectors/connectors-runtime/src/main/java/com/sun/enterprise/resource/rm/ResourceManager.java @@ -71,7 +71,7 @@ public interface ResourceManager { * Delist the resource from the transaction. * * @param resource Resource to be delisted. - * @param xaresFlag XA Flag + * @param xaresFlag flag indicating transaction success. This can be XAResource.TMSUCCESS or XAResource.TMFAIL */ void delistResource(ResourceHandle resource, int xaresFlag); @@ -79,7 +79,7 @@ public interface ResourceManager { * Unregister the resource from a transaction's list. * * @param resource Resource to be unregistered. - * @param xaresFlag XA Flag + * @param xaresFlag flag indicating transaction success. This can be XAResource.TMSUCCESS or XAResource.TMFAIL */ void unregisterResource(ResourceHandle resource, int xaresFlag); } diff --git a/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/PoolManagerImplTest.java b/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/PoolManagerImplTest.java index 9ace3d5b60e..5adbe6da1d1 100644 --- a/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/PoolManagerImplTest.java +++ b/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/PoolManagerImplTest.java @@ -1,309 +1,511 @@ -/* - * Copyright (c) 2024 Eclipse Foundation and/or its affiliates. All rights reserved. - * - * 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.enterprise.resource.pool; - -import static com.sun.enterprise.resource.pool.ConnectionPoolTest.getPoolInfo; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.isNull; -import static org.easymock.EasyMock.notNull; -import static org.easymock.EasyMock.replay; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.sun.appserv.connectors.internal.api.ConnectorConstants.PoolType; -import com.sun.appserv.connectors.internal.api.PoolingException; -import com.sun.enterprise.connectors.ConnectorRuntime; -import com.sun.enterprise.resource.ClientSecurityInfo; -import com.sun.enterprise.resource.ResourceHandle; -import com.sun.enterprise.resource.ResourceSpec; -import com.sun.enterprise.resource.allocator.ConnectorAllocator; -import com.sun.enterprise.resource.allocator.LocalTxConnectorAllocator; -import com.sun.enterprise.resource.allocator.NoTxConnectorAllocator; -import com.sun.enterprise.resource.allocator.ResourceAllocator; -import com.sun.enterprise.resource.pool.mock.JavaEETransactionMock; -import com.sun.enterprise.transaction.api.JavaEETransaction; -import com.sun.enterprise.transaction.api.JavaEETransactionManager; -import jakarta.resource.spi.ManagedConnection; -import jakarta.resource.spi.ManagedConnectionFactory; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Set; -import org.glassfish.api.admin.ProcessEnvironment; -import org.glassfish.api.invocation.InvocationManager; -import org.glassfish.api.invocation.InvocationManagerImpl; -import org.glassfish.api.naming.GlassfishNamingManager; -import org.glassfish.api.naming.SimpleJndiName; -import org.glassfish.resourcebase.resources.api.PoolInfo; -import org.glassfish.resourcebase.resources.naming.ResourceNamingService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class PoolManagerImplTest { - - // Mocked instances - private GlassfishNamingManager glassfishNamingManager; - private JavaEETransactionManager javaEETransactionManager; - private ManagedConnection managedConnection; - private ManagedConnectionFactory managedConnectionFactory; - - // Regular fields - private ClientSecurityInfo clientSecurityInfo = null; - private PoolManagerImpl poolManagerImpl = new MyPoolManagerImpl(); - private PoolInfo poolInfo = getPoolInfo(); - private JavaEETransaction javaEETransaction = new MyJavaEETransaction(); - - @BeforeEach - public void createAndPopulateMocks() throws Exception { - List mocks = new ArrayList<>(); - - // Mock JavaEETransactionManager - javaEETransactionManager = createNiceMock(JavaEETransactionManager.class); - mocks.add(javaEETransactionManager); - - // Mock GlassfishNamingManager - glassfishNamingManager = createNiceMock(GlassfishNamingManager.class); - mocks.add(glassfishNamingManager); - - // Mock ManagedConnection - managedConnection = createNiceMock(ManagedConnection.class); - expect(managedConnection.getConnection(isNull(), isNull())) - .andReturn(new MyDatabaseConnection()).anyTimes(); - mocks.add(managedConnection); - - // Mock ManagedConnectionFactory - ManagedConnectionFactory localConnectionFactory = createMock(ManagedConnectionFactory.class); - expect(localConnectionFactory.createManagedConnection(isNull(), isNull())) - .andReturn(managedConnection) - .atLeastOnce(); - // Must return a not null object in matchManagedConnections to ensure matching in the ConnectionPool is 'true' - expect(localConnectionFactory.matchManagedConnections(notNull(), isNull(), isNull())) - .andReturn(managedConnection) - .atLeastOnce(); - managedConnectionFactory = localConnectionFactory; - mocks.add(managedConnectionFactory); - - replay(mocks.toArray()); - - // Make sure ConnectorRuntime singleton is initialized - MyConnectorRuntime connectorRuntime = new MyConnectorRuntime(); - connectorRuntime.postConstruct(); - } - - /** - * Test to show the getResource behavior - */ - @Test - void getResourceTest() throws Exception { - poolManagerImpl.createEmptyConnectionPool(poolInfo, PoolType.STANDARD_POOL, new Hashtable<>()); - - ResourceSpec resourceSpec = new ResourceSpec(new SimpleJndiName("myResourceSpec"), ResourceSpec.JNDI_NAME); - resourceSpec.setPoolInfo(poolInfo); - - // Test getting a single resource, this will return a 'userConnection' / 'connection handle' object representing the - // physical connection, e.g. a database connection. - - // Test using the No transaction allocator - ResourceAllocator noTxAllocator = new NoTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, - null, null, null); - Object resource = poolManagerImpl.getResource(resourceSpec, noTxAllocator, clientSecurityInfo); - assertTrue(resource instanceof MyDatabaseConnection); - - // Test using the Local transaction allocator - ResourceAllocator localTxAllocator = new LocalTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, - null, null, null, false); - resource = poolManagerImpl.getResource(resourceSpec, localTxAllocator, clientSecurityInfo); - assertTrue(resource instanceof MyDatabaseConnection); - - // Test using the XA transaction allocator - ResourceAllocator xAllocator = new ConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, - null, null, null, false); - resource = poolManagerImpl.getResource(resourceSpec, xAllocator, clientSecurityInfo); - assertTrue(resource instanceof MyDatabaseConnection); - - // Resources from the pool should be occupied - assertPoolStatusNumberOfConnectionsUsed(3); - - // Get resource does not return a ResourceHandle, so we cannot return the resources to the pool. - // For now just flush all resources from the pool. - poolManagerImpl.flushConnectionPool(poolInfo); - - assertPoolStatusNumberOfConnectionsUsed(0); - - // Kill the pool - poolManagerImpl.killPool(poolInfo); - assertNull(poolManagerImpl.getPoolStatus(poolInfo)); - } - - /** - * Test to show the getResourceFromPool behavior in relation to the ResourceHandle enlisted and busy states, while using - * the LocalTxConnectorAllocator. - */ - @Test - public void getResourceFromPoolTest() throws Exception { - poolManagerImpl.createEmptyConnectionPool(poolInfo, PoolType.STANDARD_POOL, new Hashtable<>()); - assertPoolStatusNumberOfConnectionsUsed(0); - assertPoolStatusNumberOfConnectionsFree(0); - - ResourceSpec resourceSpec = new ResourceSpec(new SimpleJndiName("myResourceSpec"), ResourceSpec.JNDI_NAME); - resourceSpec.setPoolInfo(poolInfo); - - // Test using the Local transaction allocator - ResourceAllocator localTxAllocator = new LocalTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, - null, null, null, false); - ResourceHandle resource = poolManagerImpl.getResourceFromPool(resourceSpec, localTxAllocator, clientSecurityInfo, javaEETransaction); - assertNotNull(resource); - assertTrue(resource.getUserConnection() instanceof MyDatabaseConnection); - // The resource is not (yet) enlisted in a transaction - assertFalse(resource.isEnlisted()); - // Expecting all getResource from pool calls to mark the resource as busy - // ConnectionPool: getResourceFromPool / getUnenlistedResource / prefetch calls. - assertTrue(resource.getResourceState().isBusy()); - - // Enlist the resource in the transaction - resource.enlistedInTransaction(javaEETransaction); - assertTrue(resource.isEnlisted()); - assertTrue(resource.getResourceState().isBusy()); - - // One resource from the pool should be added to the pool and should be occupied - assertPoolStatusNumberOfConnectionsUsed(1); - assertPoolStatusNumberOfConnectionsFree(0); - - // Return the resource to the pool - poolManagerImpl.putbackResourceToPool(resource, false); - - // When resource is returned to the pool the state is no longer busy - assertFalse(resource.getResourceState().isBusy()); - - // Resource is still enlisted, because it is still part of a transaction - assertTrue(resource.isEnlisted()); - - // Resource is still in use - assertPoolStatusNumberOfConnectionsUsed(1); - assertPoolStatusNumberOfConnectionsFree(0); - - // Stop the transaction to get the resource delisted / unenlisted - // Mimic com.sun.enterprise.transaction.JavaEETransactionImpl.commit() call - poolManagerImpl.transactionCompleted(javaEETransaction, jakarta.transaction.Status.STATUS_COMMITTED); - - // Resource must be delisted / unenlisted by the transactionCompleted logic - // (warning for next assert: in multi-threaded tests resource can be used instantly by another thread!) - assertFalse(resource.isEnlisted()); - // Resource is returned to the pool, resource should be freed - // (warning for next assert: in multi-threaded tests resource can be used instantly by another thread!) - assertFalse(resource.getResourceState().isBusy()); - - // Connection should no longer be in use - assertPoolStatusNumberOfConnectionsUsed(0); - assertPoolStatusNumberOfConnectionsFree(1); - - // Kill the pool - poolManagerImpl.killPool(poolInfo); - assertNull(poolManagerImpl.getPoolStatus(poolInfo)); - } - - private void assertPoolStatusNumberOfConnectionsUsed(int expectedNumber) { - PoolStatus poolStatus = poolManagerImpl.getPoolStatus(poolInfo); - assertEquals(expectedNumber, poolStatus.getNumConnUsed()); - } - - private void assertPoolStatusNumberOfConnectionsFree(int expectedNumber) { - PoolStatus poolStatus = poolManagerImpl.getPoolStatus(poolInfo); - assertEquals(expectedNumber, poolStatus.getNumConnFree()); - } - - private class MyDatabaseConnection { - } - - private class MyConnectorRuntime extends ConnectorRuntime { - private InvocationManager manager = new InvocationManagerImpl(); - private ProcessEnvironment processEnvironment = new ProcessEnvironment(); - private ResourceNamingService resourceNamingService = new ResourceNamingService(); - - public MyConnectorRuntime() throws Exception { - // Force 'injection', unluckily ResourceNamingService is marked as final - // otherwise we could mock it, or subclass it for this unit test. - InjectionUtil.injectPrivateField(ResourceNamingService.class, resourceNamingService, "namingManager", glassfishNamingManager); - - // Force 'injection' of private field processEnvironment - InjectionUtil.injectPrivateField(ConnectorRuntime.class, this, "processEnvironment", processEnvironment); - } - - @Override - public JavaEETransactionManager getTransactionManager() { - return javaEETransactionManager; - } - - @Override - public InvocationManager getInvocationManager() { - return manager; - } - - @Override - public ResourceNamingService getResourceNamingService() { - return resourceNamingService ; - } - - @Override - public PoolManager getPoolManager() { - return poolManagerImpl; - } - } - - // We cannot depend on the real JavaEETransactionImpl due to dependency limitations, create our own - private class MyJavaEETransaction extends JavaEETransactionMock { - - private HashMap resourceTable = new HashMap<>(); - - @Override - public Set getAllParticipatingPools() { - return resourceTable.keySet(); - } - - @Override - public Set getResources(Object poolInfo) { - return resourceTable.get(poolInfo); - } - - @Override - public void setResources(Set resources, Object poolInfo) { - resourceTable.put(poolInfo, resources); - } - } - - private class MyPoolManagerImpl extends PoolManagerImpl { - - // Override createAndInitPool to be able to use our MyConnectionPool implementation to be able to override - // getPoolConfigurationFromJndi and scheduleResizerTask in the ConnectionPool class. - @Override - void createAndInitPool(PoolInfo poolInfo, PoolType poolType, Hashtable env) throws PoolingException { - // Abuse env hashTable to get fields into the getPoolConfigurationFromJndi method - env.put("maxPoolSize", Integer.valueOf(10)); - env.put("maxWaitTimeInMillis", Integer.valueOf(500)); - env.put("poolResizeQuantity", Integer.valueOf(1)); - - ConnectionPoolTest.MyConnectionPool pool = new ConnectionPoolTest.MyConnectionPool(poolInfo, env); - addPool(pool); - } - } -} +/* + * Copyright (c) 2024 Eclipse Foundation and/or its affiliates. All rights reserved. + * + * 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.enterprise.resource.pool; + +import static com.sun.enterprise.resource.pool.ConnectionPoolTest.getPoolInfo; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.isNull; +import static org.easymock.EasyMock.notNull; +import static org.easymock.EasyMock.replay; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import com.sun.appserv.connectors.internal.api.ConnectorConstants.PoolType; +import com.sun.appserv.connectors.internal.api.ConnectorRuntimeException; +import com.sun.appserv.connectors.internal.api.PoolingException; +import com.sun.enterprise.connectors.ConnectorRuntime; +import com.sun.enterprise.resource.ClientSecurityInfo; +import com.sun.enterprise.resource.ResourceHandle; +import com.sun.enterprise.resource.ResourceSpec; +import com.sun.enterprise.resource.allocator.ConnectorAllocator; +import com.sun.enterprise.resource.allocator.LocalTxConnectorAllocator; +import com.sun.enterprise.resource.allocator.NoTxConnectorAllocator; +import com.sun.enterprise.resource.allocator.ResourceAllocator; +import com.sun.enterprise.resource.pool.mock.JavaEETransactionManagerMock; +import com.sun.enterprise.resource.pool.mock.JavaEETransactionMock; +import com.sun.enterprise.transaction.api.JavaEETransaction; +import com.sun.enterprise.transaction.api.JavaEETransactionManager; +import com.sun.enterprise.transaction.spi.TransactionalResource; +import jakarta.resource.spi.ManagedConnection; +import jakarta.resource.spi.ManagedConnectionFactory; +import jakarta.transaction.SystemException; +import jakarta.transaction.Transaction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.glassfish.api.admin.ProcessEnvironment; +import org.glassfish.api.invocation.InvocationManager; +import org.glassfish.api.invocation.InvocationManagerImpl; +import org.glassfish.api.naming.GlassfishNamingManager; +import org.glassfish.api.naming.SimpleJndiName; +import org.glassfish.resourcebase.resources.api.PoolInfo; +import org.glassfish.resourcebase.resources.naming.ResourceNamingService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class PoolManagerImplTest { + + // Mocked instances + private GlassfishNamingManager glassfishNamingManager; + private ManagedConnection managedConnection; + private ManagedConnectionFactory managedConnectionFactory; + + // Regular fields + private ClientSecurityInfo clientSecurityInfo = null; + private PoolManagerImpl poolManagerImpl = new MyPoolManagerImpl(); + private PoolInfo poolInfo = getPoolInfo(); + private JavaEETransaction javaEETransaction = new MyJavaEETransaction(); + private MyJavaEETransactionManager javaEETransactionManager = new MyJavaEETransactionManager(); + private PoolType poolType; + + @BeforeEach + public void createAndPopulateMocks() throws Exception { + List mocks = new ArrayList<>(); + + // Mock GlassfishNamingManager + glassfishNamingManager = createNiceMock(GlassfishNamingManager.class); + mocks.add(glassfishNamingManager); + + // Mock ManagedConnection + managedConnection = createNiceMock(ManagedConnection.class); + expect(managedConnection.getConnection(isNull(), isNull())) + .andReturn(new MyDatabaseConnection()).anyTimes(); + mocks.add(managedConnection); + + // Mock ManagedConnectionFactory + ManagedConnectionFactory localConnectionFactory = createMock(ManagedConnectionFactory.class); + expect(localConnectionFactory.createManagedConnection(isNull(), isNull())) + .andReturn(managedConnection) + .atLeastOnce(); + // Must return a not null object in matchManagedConnections to ensure matching in the ConnectionPool is 'true' + expect(localConnectionFactory.matchManagedConnections(notNull(), isNull(), isNull())) + .andReturn(managedConnection) + .atLeastOnce(); + managedConnectionFactory = localConnectionFactory; + mocks.add(managedConnectionFactory); + + replay(mocks.toArray()); + + // Make sure ConnectorRuntime singleton is initialized + MyConnectorRuntime connectorRuntime = new MyConnectorRuntime(); + connectorRuntime.postConstruct(); + } + + /** + * Test to show the getResource behavior + */ + @Test + void getResourceTest() throws Exception { + // Create Standard pool + poolType = PoolType.STANDARD_POOL; + poolManagerImpl.createEmptyConnectionPool(poolInfo, poolType, new Hashtable<>()); + + ResourceSpec resourceSpec = createTestResourceSpec(poolInfo); + + // Test getting a single resource, this will return a 'userConnection' / 'connection handle' object representing the + // physical connection, e.g. a database connection. + + // Test using the No transaction allocator + ResourceAllocator noTxAllocator = new NoTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, + null, null, null); + Object resource = poolManagerImpl.getResource(resourceSpec, noTxAllocator, clientSecurityInfo); + assertTrue(resource instanceof MyDatabaseConnection); + + // Test using the Local transaction allocator + ResourceAllocator localTxAllocator = new LocalTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, + null, null, null, false); + resource = poolManagerImpl.getResource(resourceSpec, localTxAllocator, clientSecurityInfo); + assertTrue(resource instanceof MyDatabaseConnection); + + // Test using the XA transaction allocator + ResourceAllocator xAllocator = new ConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, + null, null, null, false); + resource = poolManagerImpl.getResource(resourceSpec, xAllocator, clientSecurityInfo); + assertTrue(resource instanceof MyDatabaseConnection); + + // Resources from the pool should be occupied + assertPoolStatusNumberOfConnectionsUsed(3); + + // Get resource does not return a ResourceHandle, so we cannot return the resources to the pool. + // For now just flush all resources from the pool. + poolManagerImpl.flushConnectionPool(poolInfo); + + assertPoolStatusNumberOfConnectionsUsed(0); + + // Kill the pool + poolManagerImpl.killPool(poolInfo); + assertNull(poolManagerImpl.getPoolStatus(poolInfo)); + } + + /** + * Test to show the getResourceFromPool and resourceClosed behavior in relation to the ResourceHandle enlisted and busy + * states, while using the LocalTxConnectorAllocator. + */ + @Test + public void resourceClosedTest() throws Exception { + // Create Standard pool + poolType = PoolType.STANDARD_POOL; + poolManagerImpl.createEmptyConnectionPool(poolInfo, poolType, new Hashtable<>()); + + assertPoolStatusNumberOfConnectionsUsed(0); + assertPoolStatusNumberOfConnectionsFree(0); + + ResourceSpec resourceSpec = new ResourceSpec(new SimpleJndiName("myResourceSpec"), ResourceSpec.JNDI_NAME); + resourceSpec.setPoolInfo(poolInfo); + + // Test using the Local transaction allocator + ResourceAllocator localTxAllocator = new LocalTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, + null, null, null, false); + ResourceHandle resource = poolManagerImpl.getResourceFromPool(resourceSpec, localTxAllocator, clientSecurityInfo, javaEETransaction); + assertNotNull(resource); + assertTrue(resource.getUserConnection() instanceof MyDatabaseConnection); + + // State should be marked busy directly after a getResource call + // The resource is not (yet) enlisted in a transaction + assertResourceIsBusy(resource); + assertResourceIsNotEnlisted(resource); + + // One resource from the pool should be added to the pool and should be occupied + assertPoolStatusNumberOfConnectionsUsed(1); + assertPoolStatusNumberOfConnectionsFree(0); + + // Enlist the resource in the transaction + assertResourceIsNotPartOfTransaction(javaEETransaction, resource); + resource.enlistedInTransaction(javaEETransaction); + assertResourceIsBusy(resource); + assertResourceIsEnlisted(resource); + assertResourceIsPartOfTransaction(javaEETransaction, resource); + + // Return the resource to the pool + poolManagerImpl.resourceClosed(resource); + // NOTE: in a multi threaded test the resource cannot be tested after this point! + + // When resource is returned to the pool the state is no longer busy + // But the resource is still enlisted in the transaction + assertResourceIsNotBusy(resource); + assertResourceIsEnlisted(resource); + assertResourceHasNoConnectionErrorOccured(resource); + assertResourceIsPartOfTransaction(javaEETransaction, resource); + + // Resource is still in use + assertPoolStatusNumberOfConnectionsUsed(1); + assertPoolStatusNumberOfConnectionsFree(0); + + // Stop the transaction to get the resource delisted / unenlisted from the transaction + // Mimic com.sun.enterprise.transaction.JavaEETransactionImpl.commit() call + poolManagerImpl.transactionCompleted(javaEETransaction, jakarta.transaction.Status.STATUS_COMMITTED); + + // State should remain not busy + // And the resource no longer enlisted in the transaction + assertResourceIsNotBusy(resource); + assertResourceIsNotEnlisted(resource); + assertResourceHasNoConnectionErrorOccured(resource); + assertResourceIsNotPartOfTransaction(javaEETransaction, resource); + + // Connection should no longer be in use + assertPoolStatusNumberOfConnectionsUsed(0); + assertPoolStatusNumberOfConnectionsFree(1); + + // Kill the pool + poolManagerImpl.killPool(poolInfo); + assertNull(poolManagerImpl.getPoolStatus(poolInfo)); + } + + /** + * Test to show the getResourceFromPool and resourceErrorOccurred behavior in relation to the ResourceHandle enlisted + * and busy states, while using the LocalTxConnectorAllocator. + */ + @Test + public void resourceErrorOccurredTest() throws Exception { + resourceErrorOrAbortedOccurredTest(false); + } + + /** + * Test to show the getResourceFromPool and resourceAbortOccurred behavior in relation to the ResourceHandle enlisted + * and busy states, while using the LocalTxConnectorAllocator. + */ + @Test + public void resourceAbortOccurredTest() throws Exception { + resourceErrorOrAbortedOccurredTest(true); + } + + private void resourceErrorOrAbortedOccurredTest(boolean resourceAbortedOccured) throws Exception { + // Create Standard pool + poolType = PoolType.STANDARD_POOL; + poolManagerImpl.createEmptyConnectionPool(poolInfo, poolType, new Hashtable<>()); + + assertPoolStatusNumberOfConnectionsUsed(0); + assertPoolStatusNumberOfConnectionsFree(0); + + ResourceSpec resourceSpec = new ResourceSpec(new SimpleJndiName("myResourceSpec"), ResourceSpec.JNDI_NAME); + resourceSpec.setPoolInfo(poolInfo); + + // Test using the Local transaction allocator + ResourceAllocator localTxAllocator = new LocalTxConnectorAllocator(null, managedConnectionFactory, resourceSpec, null, + null, null, null, false); + ResourceHandle resource = poolManagerImpl.getResourceFromPool(resourceSpec, localTxAllocator, clientSecurityInfo, javaEETransaction); + assertNotNull(resource); + assertTrue(resource.getUserConnection() instanceof MyDatabaseConnection); + + // State should be marked busy directly after a getResource call + // The resource is not (yet) enlisted in a transaction + assertResourceIsBusy(resource); + assertResourceIsNotEnlisted(resource); + + // One resource from the pool should be added to the pool and should be occupied + assertPoolStatusNumberOfConnectionsUsed(1); + assertPoolStatusNumberOfConnectionsFree(0); + + // Enlist the resource in the transaction + assertResourceIsNotPartOfTransaction(javaEETransaction, resource); + resource.enlistedInTransaction(javaEETransaction); + assertResourceIsBusy(resource); + assertResourceIsEnlisted(resource); + assertResourceIsPartOfTransaction(javaEETransaction, resource); + + if (resourceAbortedOccured) { + // Return the resource to the pool using resourceAbortOccurred + poolManagerImpl.resourceAbortOccurred(resource); + // Related transaction delist should be called for the resource + assertTrue(javaEETransactionManager.isDelistIsCalled(resource)); + + // TODO: connection error occurred flag on the resource is only set via badConnectionClosed + // why isn't it also called for resourceAbortedOccured? Bug?! + assertResourceHasNoConnectionErrorOccured(resource); + } else { + // Return the resource to the pool using resourceErrorOccurred + poolManagerImpl.resourceErrorOccurred(resource); + // Related transaction delist should be called for the resource, shouldn't it? + // resourceErrorOccurred does not seem to remove the resource from the transaction, possible bug? + // TODO: should be assertTrue + assertFalse(javaEETransactionManager.isDelistIsCalled(resource)); + + // TODO: connection error occurred flag on the resource is only set via badConnectionClosed + // why isn't it also called for resourceErrorOccurred? Bug?! + assertResourceHasNoConnectionErrorOccured(resource); + } + // NOTE: in a multi threaded test the resource cannot be tested after this point! + + // When resource is returned to the pool the state is no longer busy + // But the resource is still enlisted in the transaction + assertResourceIsNotBusy(resource); + assertResourceIsEnlisted(resource); + assertResourceIsPartOfTransaction(javaEETransaction, resource); + + // In case of putbackResourceToPool we would expect: Resource is still in use + // assertPoolStatusNumberOfConnectionsUsed(1); + // In case of putbackBadResourceToPool the resource is no longer listed as in use + assertPoolStatusNumberOfConnectionsUsed(0); + // And the bad resource should not have been returned to the free pool + assertPoolStatusNumberOfConnectionsFree(0); + + // Stop the transaction to get the resource delisted / unenlisted from the transaction + // Mimic com.sun.enterprise.transaction.JavaEETransactionImpl.commit() call + poolManagerImpl.transactionCompleted(javaEETransaction, jakarta.transaction.Status.STATUS_MARKED_ROLLBACK); + + // State should remain not busy + // And the resource no longer enlisted in the transaction + assertResourceIsNotBusy(resource); + assertResourceIsNotEnlisted(resource); + assertResourceIsNotPartOfTransaction(javaEETransaction, resource); + + // Connection should no longer be in use, and number of connections free should remain at 0 + assertPoolStatusNumberOfConnectionsUsed(0); + assertPoolStatusNumberOfConnectionsFree(0); + + // Kill the pool + poolManagerImpl.killPool(poolInfo); + assertNull(poolManagerImpl.getPoolStatus(poolInfo)); + + } + + private void assertResourceIsBusy(ResourceHandle resource) { + assertTrue(resource.getResourceState().isBusy()); + } + + private void assertResourceIsNotBusy(ResourceHandle resource) { + assertFalse(resource.getResourceState().isBusy()); + } + + private void assertResourceIsEnlisted(ResourceHandle resource) { + assertTrue(resource.isEnlisted()); + } + + private void assertResourceIsNotEnlisted(ResourceHandle resource) { + assertFalse(resource.isEnlisted()); + } + private void assertResourceHasNoConnectionErrorOccured(ResourceHandle resource) { + assertFalse(resource.hasConnectionErrorOccurred()); + } + + private void assertPoolStatusNumberOfConnectionsUsed(int expectedNumber) { + PoolStatus poolStatus = poolManagerImpl.getPoolStatus(poolInfo); + assertEquals(expectedNumber, poolStatus.getNumConnUsed()); + } + + private void assertPoolStatusNumberOfConnectionsFree(int expectedNumber) { + PoolStatus poolStatus = poolManagerImpl.getPoolStatus(poolInfo); + assertEquals(expectedNumber, poolStatus.getNumConnFree()); + } + + private static ResourceSpec createTestResourceSpec(PoolInfo thePoolInfo) { + ResourceSpec resourceSpec = new ResourceSpec(new SimpleJndiName("myResourceSpec"), ResourceSpec.JNDI_NAME); + resourceSpec.setPoolInfo(thePoolInfo); + return resourceSpec; + } + + private void assertResourceIsPartOfTransaction(JavaEETransaction transaction, ResourceHandle expectedResource) { + for (Object resource : transaction.getResources(poolInfo)) { + if (resource instanceof ResourceHandle) { + ResourceHandle foundResource = (ResourceHandle) resource; + if (foundResource.equals(expectedResource)) { + return; + } + } + } + fail(); + } + + private void assertResourceIsNotPartOfTransaction(JavaEETransaction transaction, ResourceHandle expectedResource) { + Set resources = transaction.getResources(poolInfo); + if (resources != null) { + for (Object resource : resources) { + if (resource instanceof ResourceHandle) { + ResourceHandle foundResource = (ResourceHandle) resource; + if (foundResource.equals(expectedResource)) { + fail(); + } + } + } + } + } + + private class MyDatabaseConnection { + } + + private class MyConnectorRuntime extends ConnectorRuntime { + private InvocationManager manager = new InvocationManagerImpl(); + private ProcessEnvironment processEnvironment = new ProcessEnvironment(); + private ResourceNamingService resourceNamingService = new ResourceNamingService(); + + public MyConnectorRuntime() throws Exception { + // Force 'injection', unluckily ResourceNamingService is marked as final + // otherwise we could mock it, or subclass it for this unit test. + InjectionUtil.injectPrivateField(ResourceNamingService.class, resourceNamingService, "namingManager", glassfishNamingManager); + + // Force 'injection' of private field processEnvironment + InjectionUtil.injectPrivateField(ConnectorRuntime.class, this, "processEnvironment", processEnvironment); + } + + @Override + public JavaEETransactionManager getTransactionManager() { + return javaEETransactionManager; + } + + @Override + public InvocationManager getInvocationManager() { + return manager; + } + + @Override + public ResourceNamingService getResourceNamingService() { + return resourceNamingService ; + } + + @Override + public PoolManager getPoolManager() { + return poolManagerImpl; + } + + @Override + public PoolType getPoolType(PoolInfo poolInfo) throws ConnectorRuntimeException { + // Overriden to avoid ResourceNamingService jndi lookup calls in unit test + return poolType; + } + } + + // We cannot depend on the real JavaEETransactionManagerSimplified implementation due to dependency limitations + private class MyJavaEETransactionManager extends JavaEETransactionManagerMock { + + Map delistIsCalled = new HashMap<>(); + + @Override + public Transaction getTransaction() throws SystemException { + // Assuming only 1 transaction used in each unit test, return it + return javaEETransaction; + } + + @Override + public boolean delistResource(Transaction tran, TransactionalResource resource, int flag) throws IllegalStateException, SystemException { + // Store state for unit test validation + delistIsCalled.put(resource, Boolean.TRUE); + + // Return delist success + return true; + } + + public boolean isDelistIsCalled(TransactionalResource resource) { + return delistIsCalled.getOrDefault(resource, Boolean.FALSE); + } + } + + // We cannot depend on the real JavaEETransactionImpl due to dependency limitations + private class MyJavaEETransaction extends JavaEETransactionMock { + + private HashMap resourceTable = new HashMap<>(); + + @Override + public Set getAllParticipatingPools() { + return resourceTable.keySet(); + } + + @Override + public Set getResources(Object poolInfo) { + return resourceTable.get(poolInfo); + } + + @Override + public void setResources(Set resources, Object poolInfo) { + resourceTable.put(poolInfo, resources); + } + } + + private class MyPoolManagerImpl extends PoolManagerImpl { + + // Override createAndInitPool to be able to use our MyConnectionPool implementation to be able to override + // getPoolConfigurationFromJndi and scheduleResizerTask in the ConnectionPool class. + @Override + void createAndInitPool(PoolInfo poolInfo, PoolType poolType, Hashtable env) throws PoolingException { + // Abuse env hashTable to get fields into the getPoolConfigurationFromJndi method + env.put("maxPoolSize", Integer.valueOf(10)); + env.put("maxWaitTimeInMillis", Integer.valueOf(500)); + env.put("poolResizeQuantity", Integer.valueOf(1)); + + ConnectionPoolTest.MyConnectionPool pool = new ConnectionPoolTest.MyConnectionPool(poolInfo, env); + addPool(pool); + } + } +} diff --git a/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/mock/JavaEETransactionManagerMock.java b/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/mock/JavaEETransactionManagerMock.java new file mode 100644 index 00000000000..af48116e8f4 --- /dev/null +++ b/appserver/connectors/connectors-runtime/src/test/java/com/sun/enterprise/resource/pool/mock/JavaEETransactionManagerMock.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2024 Eclipse Foundation and/or its affiliates. All rights reserved. + * + * 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.enterprise.resource.pool.mock; + +import com.sun.enterprise.transaction.api.JavaEETransaction; +import com.sun.enterprise.transaction.api.XAResourceWrapper; +import com.sun.enterprise.transaction.spi.JavaEETransactionManagerDelegate; +import com.sun.enterprise.transaction.spi.TransactionalResource; +import jakarta.resource.spi.XATerminator; +import jakarta.resource.spi.work.WorkException; +import jakarta.transaction.HeuristicMixedException; +import jakarta.transaction.HeuristicRollbackException; +import jakarta.transaction.InvalidTransactionException; +import jakarta.transaction.NotSupportedException; +import jakarta.transaction.RollbackException; +import jakarta.transaction.Synchronization; +import jakarta.transaction.SystemException; +import jakarta.transaction.Transaction; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.List; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import org.glassfish.api.invocation.ComponentInvocation; +import org.glassfish.api.invocation.InvocationException; +import org.glassfish.api.invocation.ResourceHandler; + +/** + * Mock class without any implementation + */ +public class JavaEETransactionManagerMock implements com.sun.enterprise.transaction.api.JavaEETransactionManager { + + @Override + public void begin() throws NotSupportedException, SystemException { + } + + @Override + public void commit() + throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException { + } + + @Override + public int getStatus() throws SystemException { + return 0; + } + + @Override + public Transaction getTransaction() throws SystemException { + return null; + } + + @Override + public void resume(Transaction tobj) throws InvalidTransactionException, IllegalStateException, SystemException { + } + + @Override + public void rollback() throws IllegalStateException, SecurityException, SystemException { + } + + @Override + public void setRollbackOnly() throws IllegalStateException, SystemException { + } + + @Override + public void setTransactionTimeout(int seconds) throws SystemException { + } + + @Override + public Transaction suspend() throws SystemException { + return null; + } + + @Override + public void registerSynchronization(Synchronization sync) throws RollbackException, IllegalStateException, SystemException { + } + + @Override + public boolean enlistResource(Transaction tran, TransactionalResource h) throws RollbackException, IllegalStateException, SystemException { + return false; + } + + @Override + public boolean delistResource(Transaction tran, TransactionalResource h, int flag) throws IllegalStateException, SystemException { + return false; + } + + @Override + public void enlistComponentResources() throws RemoteException { + } + + @Override + public void delistComponentResources(boolean suspend) throws RemoteException { + } + + @Override + public void componentDestroyed(Object instance, ComponentInvocation inv) { + } + + @Override + public void componentDestroyed(Object instance) { + } + + @Override + public void componentDestroyed(ResourceHandler rh) { + } + + @Override + public void preInvoke(ComponentInvocation prev) throws InvocationException { + } + + @Override + public void postInvoke(ComponentInvocation curr, ComponentInvocation prev) throws InvocationException { + } + + @Override + public void setDefaultTransactionTimeout(int seconds) { + } + + @Override + public void cleanTxnTimeout() { + } + + @Override + public List getExistingResourceList(Object instance, ComponentInvocation inv) { + return null; + } + + @Override + public void registerComponentResource(TransactionalResource h) { + } + + @Override + public void unregisterComponentResource(TransactionalResource h) { + } + + @Override + public void recover(XAResource[] resourceList) { + } + + @Override + public void initRecovery(boolean force) { + } + + @Override + public void shutdown() { + } + + @Override + public void begin(int timeout) throws NotSupportedException, SystemException { + } + + @Override + public boolean isNullTransaction() { + return false; + } + + @Override + public void checkTransactionExport(boolean isLocal) { + } + + @Override + public void checkTransactionImport() { + } + + @Override + public boolean isTimedOut() { + return false; + } + + @Override + public ArrayList getActiveTransactions() { + return null; + } + + @Override + public void forceRollback(String txnId) throws IllegalStateException, SystemException { + } + + @Override + public void setMonitoringEnabled(boolean enabled) { + } + + @Override + public void freeze() { + } + + @Override + public void unfreeze() { + } + + @Override + public boolean isFrozen() { + return false; + } + + @Override + public void recreate(Xid xid, long timeout) throws WorkException { + } + + @Override + public void release(Xid xid) throws WorkException { + } + + @Override + public XATerminator getXATerminator() { + return null; + } + + @Override + public void setDelegate(JavaEETransactionManagerDelegate delegate) { + } + + @Override + public JavaEETransaction getCurrentTransaction() { + return null; + } + + @Override + public void setCurrentTransaction(JavaEETransaction tx) { + } + + @Override + public XAResourceWrapper getXAResourceWrapper(String clName) { + return null; + } + + @Override + public void handlePropertyUpdate(String name, Object value) { + } + + @Override + public boolean recoverIncompleteTx(boolean delegated, String logPath, XAResource[] xaresArray) throws Exception { + return false; + } + + @Override + public List getResourceList(Object instance, ComponentInvocation inv) { + return null; + } + + @Override + public void clearThreadTx() { + } + + @Override + public String getTxLogLocation() { + return null; + } + + @Override + public void registerRecoveryResourceHandler(XAResource xaResource) { + } + + @Override + public int getPurgeCancelledTtransactionsAfter() { + return 0; + } + + @Override + public void setPurgeCancelledTtransactionsAfter(int value) { + } +} 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 4cae1c32d60..1bc418f6d44 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 @@ -714,7 +714,7 @@ void checkIfValid() throws ResourceException { * the connection handle and sends a CONNECTION_CLOSED event to all the * registered event listeners. * - * @param e Exception that may have occured while closing the connection handle + * @param e Exception that may have occurred while closing the connection handle * @param connHolder30Object ConnectionHolder30 that has been * closed * @throws SQLException in case closing the sql connection got out of diff --git a/appserver/transaction/internal-api/src/main/java/com/sun/enterprise/transaction/api/JavaEETransactionManager.java b/appserver/transaction/internal-api/src/main/java/com/sun/enterprise/transaction/api/JavaEETransactionManager.java index 4f9d77d5f89..3690b1fb34f 100644 --- a/appserver/transaction/internal-api/src/main/java/com/sun/enterprise/transaction/api/JavaEETransactionManager.java +++ b/appserver/transaction/internal-api/src/main/java/com/sun/enterprise/transaction/api/JavaEETransactionManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 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 @@ -93,6 +93,7 @@ boolean enlistResource(Transaction tran, * @param tran The transaction object * @param h The resource handle object * @param flag One of the values of TMSUCCESS, TMSUSPEND, or TMFAIL. + * @return true if the resource was delisted successfully; otherwise false. * * @exception IllegalStateException Thrown if the transaction in the * target object is inactive. diff --git a/appserver/transaction/jts/src/main/java/com/sun/enterprise/transaction/jts/JavaEETransactionManagerJTSDelegate.java b/appserver/transaction/jts/src/main/java/com/sun/enterprise/transaction/jts/JavaEETransactionManagerJTSDelegate.java index 8c378c0310b..7a0862cb18a 100644 --- a/appserver/transaction/jts/src/main/java/com/sun/enterprise/transaction/jts/JavaEETransactionManagerJTSDelegate.java +++ b/appserver/transaction/jts/src/main/java/com/sun/enterprise/transaction/jts/JavaEETransactionManagerJTSDelegate.java @@ -102,6 +102,9 @@ public class JavaEETransactionManagerJTSDelegate implements JavaEETransactionMan private Logger logger; + /** + * use-last-agent-optimization + */ private boolean lao = true; private volatile TransactionManager transactionManagerImpl;