From eb78aabadc36e75ca680d12d80de7dcb3f6b6b20 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 24 Nov 2015 00:25:24 +0000
Subject: [PATCH] OPENDJ-1607 Merge HeartBeatConnectionFactory and AuthenticatedConnectionFactory into LDAPConnectionFactory

---
 opendj-sdk/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java |   79 +++++++++++++++++++++++++++++++--------
 1 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/opendj-sdk/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java b/opendj-sdk/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
index a2c2ab4..0c31689 100644
--- a/opendj-sdk/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
+++ b/opendj-sdk/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -26,11 +26,21 @@
  */
 package org.forgerock.opendj.grizzly;
 
+import static com.forgerock.opendj.grizzly.GrizzlyMessages.LDAP_CONNECTION_BIND_OR_START_TLS_CONNECTION_TIMEOUT;
+import static com.forgerock.opendj.grizzly.GrizzlyMessages.LDAP_CONNECTION_BIND_OR_START_TLS_REQUEST_TIMEOUT;
+import static com.forgerock.opendj.grizzly.GrizzlyMessages.LDAP_CONNECTION_REQUEST_TIMEOUT;
+import static org.forgerock.opendj.ldap.LDAPConnectionFactory.REQUEST_TIMEOUT;
+import static org.forgerock.opendj.ldap.LdapException.newLdapException;
+import static org.forgerock.opendj.ldap.ResultCode.CLIENT_SIDE_LOCAL_ERROR;
+import static org.forgerock.opendj.ldap.responses.Responses.newResult;
+import static org.forgerock.opendj.ldap.spi.LdapPromises.*;
+
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -40,7 +50,6 @@
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.io.LDAPWriter;
-import org.forgerock.opendj.ldap.AbstractAsynchronousConnection;
 import org.forgerock.opendj.ldap.ConnectionEventListener;
 import org.forgerock.opendj.ldap.Connections;
 import org.forgerock.opendj.ldap.IntermediateResponseHandler;
@@ -61,6 +70,7 @@
 import org.forgerock.opendj.ldap.requests.GenericBindRequest;
 import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
 import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.SearchRequest;
 import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
 import org.forgerock.opendj.ldap.requests.UnbindRequest;
@@ -71,24 +81,23 @@
 import org.forgerock.opendj.ldap.responses.Result;
 import org.forgerock.opendj.ldap.spi.BindResultLdapPromiseImpl;
 import org.forgerock.opendj.ldap.spi.ExtendedResultLdapPromiseImpl;
+import org.forgerock.opendj.ldap.spi.LDAPConnectionImpl;
 import org.forgerock.opendj.ldap.spi.ResultLdapPromiseImpl;
 import org.forgerock.opendj.ldap.spi.SearchResultLdapPromiseImpl;
 import org.forgerock.util.Options;
 import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.forgerock.util.time.Duration;
 import org.glassfish.grizzly.CompletionHandler;
+import org.glassfish.grizzly.EmptyCompletionHandler;
 import org.glassfish.grizzly.filterchain.Filter;
 import org.glassfish.grizzly.filterchain.FilterChain;
 import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
 import org.glassfish.grizzly.ssl.SSLFilter;
 
-import static org.forgerock.opendj.ldap.LDAPConnectionFactory.*;
-import static org.forgerock.opendj.ldap.LdapException.*;
-import static org.forgerock.opendj.ldap.spi.LdapPromises.*;
-
-import static com.forgerock.opendj.grizzly.GrizzlyMessages.*;
-
 /** LDAP connection implementation. */
-final class GrizzlyLDAPConnection extends AbstractAsynchronousConnection implements TimeoutEventListener {
+final class GrizzlyLDAPConnection implements LDAPConnectionImpl, TimeoutEventListener {
     /**
      * A dummy SSL client engine configurator as SSLFilter only needs client
      * config. This prevents Grizzly from needlessly using JVM defaults which
@@ -112,6 +121,7 @@
     private final AtomicInteger nextMsgID = new AtomicInteger(1);
     private final GrizzlyLDAPConnectionFactory factory;
     private final ConcurrentHashMap<Integer, ResultLdapPromiseImpl<?, ?>> pendingRequests = new ConcurrentHashMap<>();
+    private final long requestTimeoutMS;
     private final Object stateLock = new Object();
     /** Guarded by stateLock. */
     private Result connectionInvalidReason;
@@ -133,6 +143,8 @@
             final GrizzlyLDAPConnectionFactory factory) {
         this.connection = connection;
         this.factory = factory;
+        final Duration requestTimeout = factory.getLDAPOptions().get(REQUEST_TIMEOUT);
+        this.requestTimeoutMS = requestTimeout.isUnlimited() ? 0 : requestTimeout.to(TimeUnit.MILLISECONDS);
     }
 
     @Override
@@ -306,6 +318,11 @@
     }
 
     @Override
+    public void close() {
+        close(Requests.newUnbindRequest(), null);
+    }
+
+    @Override
     public void close(final UnbindRequest request, final String reason) {
         // FIXME: I18N need to internationalize this message.
         Reject.ifNull(request);
@@ -548,17 +565,16 @@
 
     @Override
     public long handleTimeout(final long currentTime) {
-        final long timeout = factory.getLDAPOptions().get(TIMEOUT_IN_MILLISECONDS);
-        if (timeout <= 0) {
+        if (requestTimeoutMS <= 0) {
             return 0;
         }
 
-        long delay = timeout;
+        long delay = requestTimeoutMS;
         for (final ResultLdapPromiseImpl<?, ?> promise : pendingRequests.values()) {
             if (promise == null || !promise.checkForTimeout()) {
                 continue;
             }
-            final long diff = (promise.getTimestamp() + timeout) - currentTime;
+            final long diff = (promise.getTimestamp() + requestTimeoutMS) - currentTime;
             if (diff > 0) {
                 // Will expire in diff milliseconds.
                 delay = Math.min(delay, diff);
@@ -577,17 +593,17 @@
                 logger.debug(LocalizableMessage.raw("Failing bind or StartTLS request due to timeout %s"
                         + "(connection will be invalidated): ", promise));
                 final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
-                        LDAP_CONNECTION_BIND_OR_START_TLS_REQUEST_TIMEOUT.get(timeout).toString());
+                        LDAP_CONNECTION_BIND_OR_START_TLS_REQUEST_TIMEOUT.get(requestTimeoutMS).toString());
                 promise.adaptErrorResult(result);
 
                 // Fail the connection.
                 final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
-                        LDAP_CONNECTION_BIND_OR_START_TLS_CONNECTION_TIMEOUT.get(timeout).toString());
+                        LDAP_CONNECTION_BIND_OR_START_TLS_CONNECTION_TIMEOUT.get(requestTimeoutMS).toString());
                 connectionErrorOccurred(errorResult);
             } else {
                 logger.debug(LocalizableMessage.raw("Failing request due to timeout: %s", promise));
                 final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
-                        LDAP_CONNECTION_REQUEST_TIMEOUT.get(timeout).toString());
+                        LDAP_CONNECTION_REQUEST_TIMEOUT.get(requestTimeoutMS).toString());
                 promise.adaptErrorResult(result);
 
                 /*
@@ -607,7 +623,7 @@
 
     @Override
     public long getTimeout() {
-        return factory.getLDAPOptions().get(TIMEOUT_IN_MILLISECONDS);
+        return requestTimeoutMS;
     }
 
     /**
@@ -769,8 +785,37 @@
         bindOrStartTLSInProgress.set(state);
     }
 
+    @Override
+    public Promise<Void, LdapException> enableTLS(
+            final SSLContext sslContext,
+            final List<String> sslEnabledProtocols,
+            final List<String> sslEnabledCipherSuites) {
+        final PromiseImpl<Void, LdapException> promise = PromiseImpl.create();
+        final EmptyCompletionHandler<SSLEngine> completionHandler = new EmptyCompletionHandler<SSLEngine>() {
+            @Override
+            public void completed(final SSLEngine result) {
+                promise.handleResult(null);
+            }
+
+            @Override
+            public void failed(final Throwable throwable) {
+                final Result errorResult = newResult(CLIENT_SIDE_LOCAL_ERROR)
+                        .setCause(throwable).setDiagnosticMessage("SSL handshake failed");
+                connectionErrorOccurred(errorResult);
+                promise.handleException(newLdapException(errorResult));
+            }
+        };
+
+        try {
+            startTLS(sslContext, sslEnabledProtocols, sslEnabledCipherSuites, completionHandler);
+        } catch (final IOException e) {
+            completionHandler.failed(e);
+        }
+        return promise;
+    }
+
     void startTLS(final SSLContext sslContext, final List<String> protocols, final List<String> cipherSuites,
-            final CompletionHandler<SSLEngine> completionHandler) throws IOException {
+                  final CompletionHandler<SSLEngine> completionHandler) throws IOException {
         synchronized (stateLock) {
             if (isTLSEnabled()) {
                 throw new IllegalStateException("TLS already enabled");

--
Gitblit v1.10.0