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/DefaultTCPNIOTransport.java |  222 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 114 insertions(+), 108 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/DefaultTCPNIOTransport.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/DefaultTCPNIOTransport.java
index 9366df8..9f7c413 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/DefaultTCPNIOTransport.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/DefaultTCPNIOTransport.java
@@ -22,133 +22,139 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
- *      Portions copyright 2011 ForgeRock AS
+ *      Portions copyright 2011-2013 ForgeRock AS
  */
 
 package com.forgerock.opendj.ldap;
 
+import static com.forgerock.opendj.util.StaticUtils.DEBUG_LOG;
+
 import java.io.IOException;
+import java.util.logging.Level;
 
 import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
 import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
 import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
 import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy;
 
+import com.forgerock.opendj.util.ReferenceCountedObject;
+
 /**
  * The default {@link TCPNIOTransport} which all {@code LDAPConnectionFactory}s
  * and {@code LDAPListener}s will use unless otherwise specified in their
  * options.
  */
-final class DefaultTCPNIOTransport {
-    private static TCPNIOTransport defaultTransport = null;
-
-    /**
-     * Returns the default {@link TCPNIOTransport} which all
-     * {@code LDAPConnectionFactory}s and {@code LDAPListener}s will use unless
-     * otherwise specified in their options.
-     *
-     * @return The default {@link TCPNIOTransport}.
-     */
-    static synchronized TCPNIOTransport getInstance() {
-        if (defaultTransport == null) {
-            final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance();
-
-            // Determine which threading strategy to use, and total number of
-            // threads.
-            final String useWorkerThreadsStr =
-                    System.getProperty("org.forgerock.opendj.transport.useWorkerThreads");
-            final boolean useWorkerThreadStrategy;
-            if (useWorkerThreadsStr != null) {
-                useWorkerThreadStrategy = Boolean.parseBoolean(useWorkerThreadsStr);
-            } else {
-                // The most best performing strategy to use is the
-                // SameThreadIOStrategy, however it can only be used in cases
-                // where result listeners will not block.
-                useWorkerThreadStrategy = true;
-            }
-
-            if (useWorkerThreadStrategy) {
-                builder.setIOStrategy(WorkerThreadIOStrategy.getInstance());
-            } else {
-                builder.setIOStrategy(SameThreadIOStrategy.getInstance());
-            }
-
-            // Calculate thread counts.
-            final int cpus = Runtime.getRuntime().availableProcessors();
-
-            // Calculate the number of selector threads.
-            final String selectorsStr =
-                    System.getProperty("org.forgerock.opendj.transport.selectors");
-            final int selectorThreadCount;
-
-            if (selectorsStr != null) {
-                selectorThreadCount = Integer.parseInt(selectorsStr);
-            } else {
-                selectorThreadCount =
-                        useWorkerThreadStrategy ? Math.max(2, cpus / 4) : Math.max(5,
-                                (cpus / 2) - 1);
-            }
-
-            builder.getSelectorThreadPoolConfig().setCorePoolSize(selectorThreadCount)
-                    .setMaxPoolSize(selectorThreadCount).setPoolName(
-                            "OpenDJ LDAP SDK Grizzly selector thread");
-
-            // Calculate the number of worker threads.
-            if (builder.getWorkerThreadPoolConfig() != null) {
-                final String workersStr =
-                        System.getProperty("org.forgerock.opendj.transport.workers");
-                final int workerThreadCount;
-
-                if (workersStr != null) {
-                    workerThreadCount = Integer.parseInt(workersStr);
-                } else {
-                    workerThreadCount = useWorkerThreadStrategy ? Math.max(5, (cpus * 2)) : 0;
-                }
-
-                builder.getWorkerThreadPoolConfig().setCorePoolSize(workerThreadCount)
-                        .setMaxPoolSize(workerThreadCount).setPoolName(
-                                "OpenDJ LDAP SDK Grizzly worker thread");
-            }
-
-            // Parse IO related options.
-            final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger");
-            if (lingerStr != null) {
-                // Disabled by default.
-                builder.setLinger(Integer.parseInt(lingerStr));
-            }
-
-            final String tcpNoDelayStr =
-                    System.getProperty("org.forgerock.opendj.transport.tcpNoDelay");
-            if (tcpNoDelayStr != null) {
-                // Enabled by default.
-                builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr));
-            }
-
-            final String reuseAddressStr =
-                    System.getProperty("org.forgerock.opendj.transport.reuseAddress");
-            if (reuseAddressStr != null) {
-                // Enabled by default.
-                builder.setReuseAddress(Boolean.parseBoolean(reuseAddressStr));
-            }
-
-            defaultTransport = builder.build();
-
-            // FIXME: raise bug in Grizzly. We should not need to do this, but
-            // failure to do so causes many deadlocks.
-            defaultTransport.setSelectorRunnersCount(selectorThreadCount);
-
-            try {
-                defaultTransport.start();
-            } catch (final IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        return defaultTransport;
-    }
+final class DefaultTCPNIOTransport extends ReferenceCountedObject<TCPNIOTransport> {
+    static final DefaultTCPNIOTransport DEFAULT_TRANSPORT = new DefaultTCPNIOTransport();
 
     private DefaultTCPNIOTransport() {
         // Prevent instantiation.
     }
 
+    @Override
+    protected void destroyInstance(final TCPNIOTransport instance) {
+        try {
+            instance.stop();
+        } catch (final IOException e) {
+            DEBUG_LOG.log(Level.WARNING,
+                    "An error occurred while shutting down the Grizzly transport", e.getMessage());
+        }
+    }
+
+    @Override
+    protected TCPNIOTransport newInstance() {
+        final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance();
+
+        /*
+         * Determine which threading strategy to use, and total number of
+         * threads.
+         */
+        final String useWorkerThreadsStr =
+                System.getProperty("org.forgerock.opendj.transport.useWorkerThreads");
+        final boolean useWorkerThreadStrategy;
+        if (useWorkerThreadsStr != null) {
+            useWorkerThreadStrategy = Boolean.parseBoolean(useWorkerThreadsStr);
+        } else {
+            /*
+             * The most best performing strategy to use is the
+             * SameThreadIOStrategy, however it can only be used in cases where
+             * result listeners will not block.
+             */
+            useWorkerThreadStrategy = true;
+        }
+
+        if (useWorkerThreadStrategy) {
+            builder.setIOStrategy(WorkerThreadIOStrategy.getInstance());
+        } else {
+            builder.setIOStrategy(SameThreadIOStrategy.getInstance());
+        }
+
+        // Calculate thread counts.
+        final int cpus = Runtime.getRuntime().availableProcessors();
+
+        // Calculate the number of selector threads.
+        final String selectorsStr = System.getProperty("org.forgerock.opendj.transport.selectors");
+        final int selectorThreadCount;
+
+        if (selectorsStr != null) {
+            selectorThreadCount = Integer.parseInt(selectorsStr);
+        } else {
+            selectorThreadCount =
+                    useWorkerThreadStrategy ? Math.max(2, cpus / 4) : Math.max(5, (cpus / 2) - 1);
+        }
+
+        builder.getSelectorThreadPoolConfig().setCorePoolSize(selectorThreadCount).setMaxPoolSize(
+                selectorThreadCount).setPoolName("OpenDJ LDAP SDK Grizzly selector thread");
+
+        // Calculate the number of worker threads.
+        if (builder.getWorkerThreadPoolConfig() != null) {
+            final String workersStr = System.getProperty("org.forgerock.opendj.transport.workers");
+            final int workerThreadCount;
+
+            if (workersStr != null) {
+                workerThreadCount = Integer.parseInt(workersStr);
+            } else {
+                workerThreadCount = useWorkerThreadStrategy ? Math.max(5, (cpus * 2)) : 0;
+            }
+
+            builder.getWorkerThreadPoolConfig().setCorePoolSize(workerThreadCount).setMaxPoolSize(
+                    workerThreadCount).setPoolName("OpenDJ LDAP SDK Grizzly worker thread");
+        }
+
+        // Parse IO related options.
+        final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger");
+        if (lingerStr != null) {
+            // Disabled by default.
+            builder.setLinger(Integer.parseInt(lingerStr));
+        }
+
+        final String tcpNoDelayStr =
+                System.getProperty("org.forgerock.opendj.transport.tcpNoDelay");
+        if (tcpNoDelayStr != null) {
+            // Enabled by default.
+            builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr));
+        }
+
+        final String reuseAddressStr =
+                System.getProperty("org.forgerock.opendj.transport.reuseAddress");
+        if (reuseAddressStr != null) {
+            // Enabled by default.
+            builder.setReuseAddress(Boolean.parseBoolean(reuseAddressStr));
+        }
+
+        final TCPNIOTransport transport = builder.build();
+
+        // FIXME: raise bug in Grizzly. We should not need to do this, but
+        // failure to do so causes many deadlocks.
+        transport.setSelectorRunnersCount(selectorThreadCount);
+
+        try {
+            transport.start();
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        return transport;
+    }
+
 }

--
Gitblit v1.10.0