From 3f7ddbf313aaabbfba4650cb2036cb41e51a9bde Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 18 Apr 2013 11:37:28 +0000
Subject: [PATCH] Fix OPENDJ-838: Add ConnectionFactory.close() method to facilitate resource cleanup after application exit

---
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java |   53 ++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
index 706e9b3..9a60962 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
@@ -27,11 +27,14 @@
 
 package com.forgerock.opendj.ldap;
 
+import static com.forgerock.opendj.ldap.DefaultTCPNIOTransport.DEFAULT_TRANSPORT;
+import static com.forgerock.opendj.ldap.TimeoutChecker.TIMEOUT_CHECKER;
 import static org.forgerock.opendj.ldap.ErrorResultException.*;
 
 import java.io.IOException;
 import java.net.SocketAddress;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.net.ssl.SSLEngine;
 
@@ -55,6 +58,7 @@
 import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
 
 import com.forgerock.opendj.util.AsynchronousFutureResult;
+import com.forgerock.opendj.util.ReferenceCountedObject;
 
 /**
  * LDAP connection factory implementation.
@@ -154,10 +158,14 @@
         }
 
         private LDAPConnection adaptConnection(final org.glassfish.grizzly.Connection<?> connection) {
-            // Test shows that its much faster with non block writes but risk
-            // running out of memory if the server is slow.
+            /*
+             * Test shows that its much faster with non block writes but risk
+             * running out of memory if the server is slow.
+             */
             connection.configureBlocking(true);
-            final LDAPConnection ldapConnection = new LDAPConnection(connection, options);
+            final LDAPConnection ldapConnection =
+                    new LDAPConnection(connection, LDAPConnectionFactoryImpl.this);
+            timeoutChecker.get().addConnection(ldapConnection);
             clientFilter.registerConnection(connection, ldapConnection);
             return ldapConnection;
         }
@@ -194,7 +202,10 @@
     private final FilterChain defaultFilterChain;
     private final LDAPOptions options;
     private final SocketAddress socketAddress;
-    private final TCPNIOTransport transport;
+    private final ReferenceCountedObject<TCPNIOTransport>.Reference transport;
+    private final AtomicBoolean isClosed = new AtomicBoolean();
+    private final ReferenceCountedObject<TimeoutChecker>.Reference timeoutChecker = TIMEOUT_CHECKER
+            .acquire();
 
     /**
      * Creates a new LDAP connection factory implementation which can be used to
@@ -207,11 +218,7 @@
      *            The LDAP connection options to use when creating connections.
      */
     public LDAPConnectionFactoryImpl(final SocketAddress address, final LDAPOptions options) {
-        if (options.getTCPNIOTransport() == null) {
-            this.transport = DefaultTCPNIOTransport.getInstance();
-        } else {
-            this.transport = options.getTCPNIOTransport();
-        }
+        this.transport = DEFAULT_TRANSPORT.acquireIfNull(options.getTCPNIOTransport());
         this.socketAddress = address;
         this.options = new LDAPOptions(options);
         this.clientFilter =
@@ -220,9 +227,14 @@
                 FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
+    public void close() {
+        if (isClosed.compareAndSet(false, true)) {
+            transport.release();
+            timeoutChecker.release();
+        }
+    }
+
     @Override
     public Connection getConnection() throws ErrorResultException {
         try {
@@ -232,14 +244,12 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public FutureResult<Connection> getConnectionAsync(
             final ResultHandler<? super Connection> handler) {
         final SocketConnectorHandler connectorHandler =
-                TCPNIOConnectorHandler.builder(transport).processor(defaultFilterChain).build();
+                TCPNIOConnectorHandler.builder(transport.get()).processor(defaultFilterChain)
+                        .build();
         final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future =
                 new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(handler);
         final CompletionHandlerAdapter cha = new CompletionHandlerAdapter(future);
@@ -256,9 +266,14 @@
         return socketAddress;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    TimeoutChecker getTimeoutChecker() {
+        return timeoutChecker.get();
+    }
+
+    LDAPOptions getLDAPOptions() {
+        return options;
+    }
+
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();

--
Gitblit v1.10.0