From 48ac4129c6b93fff96360e71f722c0447153dc06 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 05 Sep 2012 09:58:26 +0000
Subject: [PATCH] Fix OPENDJ-515: Upgrade OpenDJ SDK to Grizzly 2.2.x

---
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java |  257 +++++++++++++++++++++++----------------------------
 1 files changed, 116 insertions(+), 141 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 3563302..81c91b2 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
@@ -45,7 +45,6 @@
 import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
 import org.forgerock.opendj.ldap.responses.ExtendedResult;
-import org.forgerock.opendj.ldap.responses.Result;
 import org.glassfish.grizzly.CompletionHandler;
 import org.glassfish.grizzly.EmptyCompletionHandler;
 import org.glassfish.grizzly.filterchain.FilterChain;
@@ -53,144 +52,142 @@
 import org.glassfish.grizzly.filterchain.TransportFilter;
 import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
 
-import com.forgerock.opendj.util.CompletedFutureResult;
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
+import com.forgerock.opendj.util.AsynchronousFutureResult;
 
 /**
  * LDAP connection factory implementation.
  */
 public final class LDAPConnectionFactoryImpl implements ConnectionFactory {
-
+    /**
+     * Adapts a Grizzly connection completion handler to an LDAP connection
+     * asynchronous future result.
+     */
     @SuppressWarnings("rawtypes")
-    private final class ConnectionCompletionHandler implements
+    private final class CompletionHandlerAdapter implements
             CompletionHandler<org.glassfish.grizzly.Connection> {
-        private final FutureResultTransformer<Result, Connection> startTLSFutureResult;
-        private final RecursiveFutureResult<LDAPConnection, ExtendedResult> connectionFutureResult;
-        private LDAPConnection connection;
 
-        private ConnectionCompletionHandler(final ResultHandler<? super Connection> handler) {
-            this.startTLSFutureResult = new FutureResultTransformer<Result, Connection>(handler) {
+        private final AsynchronousFutureResult<? super Connection> future;
 
-                @Override
-                protected ErrorResultException transformErrorResult(
-                        final ErrorResultException errorResult) {
-                    // Ensure that the connection is closed.
-                    try {
-                        if (connection != null) {
-                            connection.close();
-                        }
-                    } catch (final Exception e) {
-                        // Ignore.
-                    }
-                    return errorResult;
-                }
-
-                @Override
-                protected LDAPConnection transformResult(final Result result)
-                        throws ErrorResultException {
-                    return connection;
-                }
-
-            };
-
-            this.connectionFutureResult =
-                    new RecursiveFutureResult<LDAPConnection, ExtendedResult>(startTLSFutureResult) {
-
-                        @Override
-                        protected FutureResult<? extends ExtendedResult> chainResult(
-                                final LDAPConnection innerResult,
-                                final ResultHandler<? super ExtendedResult> handler)
-                                throws ErrorResultException {
-                            connection = innerResult;
-
-                            if (options.getSSLContext() != null && options.useStartTLS()) {
-                                // Chain StartTLS extended request.
-                                final StartTLSExtendedRequest startTLS =
-                                        Requests.newStartTLSExtendedRequest(options.getSSLContext());
-                                startTLS.addEnabledCipherSuite(options
-                                        .getEnabledCipherSuites()
-                                        .toArray(
-                                                new String[options.getEnabledCipherSuites().size()]));
-                                startTLS.addEnabledProtocol(options.getEnabledProtocols().toArray(
-                                        new String[options.getEnabledProtocols().size()]));
-                                return connection.extendedRequestAsync(startTLS, null, handler);
-                            } else if (options.getSSLContext() != null) {
-                                // Install SSL/TLS layer.
-                                try {
-                                    connection.startTLS(options.getSSLContext(), options
-                                            .getEnabledProtocols(), options
-                                            .getEnabledCipherSuites(),
-                                            new EmptyCompletionHandler<SSLEngine>() {
-                                                @Override
-                                                public void completed(final SSLEngine result) {
-                                                    handler.handleResult(null);
-                                                }
-
-                                                @Override
-                                                public void failed(final Throwable throwable) {
-                                                    handler.handleErrorResult(newErrorResult(
-                                                            ResultCode.CLIENT_SIDE_CONNECT_ERROR,
-                                                            throwable.getMessage(), throwable));
-                                                }
-                                            });
-                                    return null;
-                                } catch (final IOException ioe) {
-                                    throw newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, ioe
-                                            .getMessage(), ioe);
-                                }
-                            } else {
-                                // Plain connection.
-                                handler.handleResult(null);
-                                return new CompletedFutureResult<ExtendedResult>(
-                                        (ExtendedResult) null);
-                            }
-                        }
-
-                    };
-
-            startTLSFutureResult.setFutureResult(connectionFutureResult);
+        private CompletionHandlerAdapter(final AsynchronousFutureResult<? super Connection> future) {
+            this.future = future;
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        @Override
         public void cancelled() {
             // Ignore this.
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void completed(final org.glassfish.grizzly.Connection connection) {
-            connectionFutureResult.handleResult(adaptConnection(connection));
+        public void completed(final org.glassfish.grizzly.Connection result) {
+            // Adapt the connection.
+            final LDAPConnection connection = adaptConnection(result);
+
+            // Plain connection.
+            if (options.getSSLContext() == null) {
+                onSuccess(connection);
+                return;
+            }
+
+            // Start TLS or install SSL layer asynchronously.
+
+            // Give up immediately if the future has been cancelled.
+            if (future.isCancelled()) {
+                connection.close();
+                return;
+            }
+
+            if (options.useStartTLS()) {
+                // Chain StartTLS extended request.
+                final StartTLSExtendedRequest startTLS =
+                        Requests.newStartTLSExtendedRequest(options.getSSLContext());
+                startTLS.addEnabledCipherSuite(options.getEnabledCipherSuites().toArray(
+                        new String[options.getEnabledCipherSuites().size()]));
+                startTLS.addEnabledProtocol(options.getEnabledProtocols().toArray(
+                        new String[options.getEnabledProtocols().size()]));
+                final ResultHandler<ExtendedResult> handler = new ResultHandler<ExtendedResult>() {
+                    public void handleErrorResult(final ErrorResultException error) {
+                        onFailure(connection, error);
+                    }
+
+                    public void handleResult(final ExtendedResult result) {
+                        onSuccess(connection);
+                    }
+                };
+                connection.extendedRequestAsync(startTLS, null, handler);
+            } else {
+                // Install SSL/TLS layer.
+                try {
+                    connection.startTLS(options.getSSLContext(), options.getEnabledProtocols(),
+                            options.getEnabledCipherSuites(),
+                            new EmptyCompletionHandler<SSLEngine>() {
+                                @Override
+                                public void completed(final SSLEngine result) {
+                                    onSuccess(connection);
+                                }
+
+                                @Override
+                                public void failed(final Throwable throwable) {
+                                    onFailure(connection, throwable);
+                                }
+
+                            });
+                } catch (final IOException e) {
+                    onFailure(connection, e);
+                }
+            }
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        @Override
         public void failed(final Throwable throwable) {
-            connectionFutureResult.handleErrorResult(adaptConnectionException(throwable));
+            // Adapt and forward.
+            future.handleErrorResult(adaptConnectionException(throwable));
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void updated(final org.glassfish.grizzly.Connection connection) {
+        public void updated(final org.glassfish.grizzly.Connection result) {
             // Ignore this.
         }
 
-    }
+        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.
+            connection.configureBlocking(true);
+            connection.setProcessor(defaultFilterChain);
 
+            final LDAPConnection ldapConnection = new LDAPConnection(connection, options);
+            clientFilter.registerConnection(connection, ldapConnection);
+            return ldapConnection;
+        }
+
+        private ErrorResultException adaptConnectionException(Throwable t) {
+            if (t instanceof ExecutionException) {
+                t = t.getCause();
+            }
+
+            if (t instanceof ErrorResultException) {
+                return (ErrorResultException) t;
+            } else {
+                return newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, t.getMessage(), t);
+            }
+        }
+
+        private void onFailure(final LDAPConnection connection, final Throwable t) {
+            // Abort connection attempt due to error.
+            connection.close();
+            future.handleErrorResult(adaptConnectionException(t));
+        }
+
+        private void onSuccess(final LDAPConnection connection) {
+            future.handleResult(connection);
+
+            // Close the connection if the future was cancelled.
+            if (future.isCancelled()) {
+                connection.close();
+            }
+        }
+    };
+
+    private final LDAPClientFilter clientFilter;
+    private final FilterChain defaultFilterChain;
+    private final LDAPOptions options;
     private final SocketAddress socketAddress;
     private final TCPNIOTransport transport;
-    private final FilterChain defaultFilterChain;
-    private final LDAPClientFilter clientFilter;
-    private final LDAPOptions options;
 
     /**
      * Creates a new LDAP connection factory implementation which can be used to
@@ -223,7 +220,7 @@
     public Connection getConnection() throws ErrorResultException {
         try {
             return getConnectionAsync(null).get();
-        } catch (InterruptedException e) {
+        } catch (final InterruptedException e) {
             throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, e);
         }
     }
@@ -234,14 +231,11 @@
     @Override
     public FutureResult<Connection> getConnectionAsync(
             final ResultHandler<? super Connection> handler) {
-        final ConnectionCompletionHandler ch = new ConnectionCompletionHandler(handler);
-        try {
-            ch.connectionFutureResult.setFutureResult(transport.connect(socketAddress, ch));
-            return ch.startTLSFutureResult;
-        } catch (final IOException e) {
-            final ErrorResultException result = adaptConnectionException(e);
-            return new CompletedFutureResult<Connection>(result);
-        }
+        final AsynchronousFutureResult<Connection> future =
+                new AsynchronousFutureResult<Connection>(handler);
+        final CompletionHandlerAdapter cha = new CompletionHandlerAdapter(future);
+        transport.connect(socketAddress, cha);
+        return future;
     }
 
     /**
@@ -264,23 +258,4 @@
         builder.append(')');
         return builder.toString();
     }
-
-    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.
-        connection.configureBlocking(true);
-        connection.setProcessor(defaultFilterChain);
-
-        final LDAPConnection ldapConnection = new LDAPConnection(connection, options);
-        clientFilter.registerConnection(connection, ldapConnection);
-        return ldapConnection;
-    }
-
-    private ErrorResultException adaptConnectionException(Throwable t) {
-        if (t instanceof ExecutionException) {
-            t = t.getCause();
-        }
-
-        return newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, t.getMessage(), t);
-    }
 }

--
Gitblit v1.10.0