You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by bd...@apache.org on 2024/02/22 01:40:35 UTC

(directory-ldap-api) branch release-pooled created (now 607dac13d)

This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a change to branch release-pooled
in repository https://gitbox.apache.org/repos/asf/directory-ldap-api.git


      at 607dac13d Make Pooled LDAP connections return to pool when closed

This branch includes the following new commits:

     new 607dac13d Make Pooled LDAP connections return to pool when closed

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(directory-ldap-api) 01/01: Make Pooled LDAP connections return to pool when closed

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch release-pooled
in repository https://gitbox.apache.org/repos/asf/directory-ldap-api.git

commit 607dac13da44ab7992e386f7ce8333eb256c9e6e
Author: Brian Demers <bd...@apache.org>
AuthorDate: Wed Feb 21 20:40:18 2024 -0500

    Make Pooled LDAP connections return to pool when closed
    
    Fixes: DIRAPI-398
---
 .../api/AbstractPoolableLdapConnectionFactory.java | 55 +++++++++++++++++++
 .../api/DefaultPoolableLdapConnectionFactory.java  |  2 +-
 .../ldap/client/api/LdapConnectionPool.java        |  4 ++
 .../ldap/client/api/PooledLdapConnection.java      | 62 ++++++++++++++++++++++
 .../ValidatingPoolableLdapConnectionFactory.java   |  2 +-
 .../ldap/client/api/PooledLdapConnectionTest.java  | 49 +++++++++++++++++
 ...alidatingPoolableLdapConnectionFactoryTest.java |  7 ++-
 7 files changed, 178 insertions(+), 3 deletions(-)

diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java
index 3573c5d35..6a957f1dd 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java
@@ -49,6 +49,11 @@ public abstract class AbstractPoolableLdapConnectionFactory implements PooledObj
     /** The validator to use */
     protected LdapConnectionValidator validator = new LookupLdapConnectionValidator();
 
+    public AbstractPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
+    {
+        this.connectionFactory = new PooledLdapConnectionFactory( connectionFactory );
+    }
+
     /**
      * {@inheritDoc}
      * 
@@ -206,4 +211,54 @@ public abstract class AbstractPoolableLdapConnectionFactory implements PooledObj
         
         return validator.validate( connection.getObject() );
     }
+
+    private static class PooledLdapConnectionFactory implements LdapConnectionFactory
+    {
+        private final LdapConnectionFactory delegate;
+
+        PooledLdapConnectionFactory( LdapConnectionFactory delegate )
+        {
+            this.delegate = delegate;
+        }
+
+        private LdapConnection wrap( LdapConnection ldapConnection )
+        {
+            if ( ldapConnection instanceof PooledLdapConnection )
+            {
+                return ldapConnection;
+            }
+
+            return new PooledLdapConnection( ldapConnection );
+        }
+
+        @Override
+        public LdapConnection bindConnection( LdapConnection connection ) throws LdapException
+        {
+            return wrap( delegate.bindConnection( connection ) );
+        }
+
+        @Override
+        public LdapConnection configureConnection( LdapConnection connection )
+        {
+            return wrap( delegate.configureConnection( connection ) );
+        }
+
+        @Override
+        public LdapApiService getLdapApiService()
+        {
+            return delegate.getLdapApiService();
+        }
+
+        @Override
+        public LdapConnection newLdapConnection() throws LdapException
+        {
+            return wrap( delegate.newLdapConnection() );
+        }
+
+        @Override
+        public LdapConnection newUnboundLdapConnection()
+        {
+            return wrap( delegate.newUnboundLdapConnection() );
+        }
+    }
 }
diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java
index d9d601081..fae260633 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java
@@ -67,6 +67,6 @@ public class DefaultPoolableLdapConnectionFactory extends AbstractPoolableLdapCo
      */
     public DefaultPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
     {
-        this.connectionFactory = connectionFactory;
+        super( connectionFactory );
     }
 }
diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java
index 6bbc68925..7d5fb8c06 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java
@@ -123,6 +123,10 @@ public class LdapConnectionPool extends GenericObjectPool<LdapConnection>
         try
         {
             connection = super.borrowObject();
+            if ( connection instanceof PooledLdapConnection )
+            {
+                ( ( PooledLdapConnection ) connection ).setConnectionPool( this );
+            }
             
             if ( LOG.isTraceEnabled() )
             {
diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/PooledLdapConnection.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/PooledLdapConnection.java
new file mode 100644
index 000000000..71ad0071b
--- /dev/null
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/PooledLdapConnection.java
@@ -0,0 +1,62 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+import java.io.IOException;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+/**
+ * A wrapper around an LdapConnection that returns the connection to the pool when closed.
+ */
+class PooledLdapConnection extends LdapConnectionWrapper
+{
+
+    private LdapConnectionPool pool;
+
+    PooledLdapConnection( LdapConnection delegate )
+    {
+        super( delegate );
+    }
+
+    PooledLdapConnection( LdapConnection delegate, LdapConnectionPool pool )
+    {
+        super( delegate );
+        this.pool = pool;
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        try
+        {
+            pool.releaseConnection( connection );
+        }
+        catch ( LdapException e )
+        {
+            throw new IOException( "Failed to release connection to pool", e );
+        }
+    }
+
+    public void setConnectionPool( LdapConnectionPool pool )
+    {
+        this.pool = pool;
+    }
+}
diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java
index 8389ed39d..16510104c 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java
@@ -102,7 +102,7 @@ public class ValidatingPoolableLdapConnectionFactory extends AbstractPoolableLda
      */
     public ValidatingPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
     {
-        this.connectionFactory = connectionFactory;
+        super( connectionFactory );
     }
 
 
diff --git a/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/PooledLdapConnectionTest.java b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/PooledLdapConnectionTest.java
new file mode 100644
index 000000000..62db592df
--- /dev/null
+++ b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/PooledLdapConnectionTest.java
@@ -0,0 +1,49 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.junit.jupiter.api.Test;
+
+public class PooledLdapConnectionTest
+{
+    @Test
+    void closeReleasesToPool() throws IOException, LdapException
+    {
+        LdapConnectionPool pool = mock( LdapConnectionPool.class );
+        LdapConnection connection = mock( LdapConnection.class );
+        PooledLdapConnection spyPooledConnection = spy( new PooledLdapConnection( connection, pool ) );
+
+        try ( PooledLdapConnection pooledConnection = spyPooledConnection )
+        {
+            pooledConnection.isConnected();
+        }
+
+        verify( connection ).isConnected(); // called inside the try-with-resources block
+        verify( spyPooledConnection ).close(); // auto-closed
+        verify( pool ).releaseConnection( connection ); // close called releaseConnection
+    }
+}
diff --git a/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java
index a6ce7a299..db2eae82f 100755
--- a/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java
+++ b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java
@@ -516,7 +516,7 @@ public class ValidatingPoolableLdapConnectionFactoryTest
             {
                 connection = pool.getConnection();
                 assertNotNull( connection );
-                internal = ( InternalMonitoringLdapConnection ) ( ( LdapConnectionWrapper ) connection ).wrapped();
+                internal = ( InternalMonitoringLdapConnection ) unwrap( unwrap( connection ) ); // two levels of wrapping
                 borrowedCount = internal.incrementBorrowedCount();
                 org.mockito.Mockito.verify( validator, times( 2 * borrowedCount - 1 ) ).validate( connection );
                 internal.resetMonitors();
@@ -553,6 +553,11 @@ public class ValidatingPoolableLdapConnectionFactoryTest
         }
     }
 
+    private static LdapConnection unwrap( LdapConnection connection )
+    {
+        return ( ( LdapConnectionWrapper ) connection ).wrapped();
+    }
+
     private static interface WithConnection
     {
         /**