From 38fe921bd2d09734277828b638a4947e45a99bcd Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 25 Oct 2013 09:44:02 +0000
Subject: [PATCH] Checkpoint commit for OPENDJ-175: Decouple OpenDJ LDAP SDK from Grizzly

---
 opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java |  123 ++++++++++++++++++++++++-----------------
 1 files changed, 72 insertions(+), 51 deletions(-)

diff --git a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
index 6a2f5d8..c348a33 100644
--- a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
+++ b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -44,8 +44,8 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 
+import org.forgerock.opendj.io.LDAPWriter;
 import org.forgerock.opendj.ldap.AbstractAsynchronousConnection;
-import org.forgerock.opendj.ldap.Connection;
 import org.forgerock.opendj.ldap.ConnectionEventListener;
 import org.forgerock.opendj.ldap.ErrorResultException;
 import org.forgerock.opendj.ldap.FutureResult;
@@ -55,6 +55,7 @@
 import org.forgerock.opendj.ldap.ResultHandler;
 import org.forgerock.opendj.ldap.SSLContextBuilder;
 import org.forgerock.opendj.ldap.SearchResultHandler;
+import org.forgerock.opendj.ldap.TimeoutEventListener;
 import org.forgerock.opendj.ldap.TrustManagers;
 import org.forgerock.opendj.ldap.requests.AbandonRequest;
 import org.forgerock.opendj.ldap.requests.AddRequest;
@@ -93,7 +94,7 @@
 /**
  * LDAP connection implementation.
  */
-final class GrizzlyLDAPConnection extends AbstractAsynchronousConnection implements Connection {
+final class GrizzlyLDAPConnection extends AbstractAsynchronousConnection implements TimeoutEventListener {
     /**
      * A dummy SSL client engine configurator as SSLFilter only needs client
      * config. This prevents Grizzly from needlessly using JVM defaults which
@@ -113,7 +114,6 @@
 
     private final AtomicBoolean bindOrStartTLSInProgress = new AtomicBoolean(false);
     private final org.glassfish.grizzly.Connection<?> connection;
-    private final LDAPWriter ldapWriter = new LDAPWriter();
     private final AtomicInteger nextMsgID = new AtomicInteger(1);
     private final GrizzlyLDAPConnectionFactory factory;
     private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests =
@@ -126,6 +126,15 @@
     private boolean isFailed = false;
     private List<ConnectionEventListener> listeners = null;
 
+    /**
+     * Create a LDAP Connection with provided Grizzly connection and LDAP
+     * connection factory.
+     *
+     * @param connection
+     *            actual connection
+     * @param factory
+     *            factory that provides LDAP connections
+     */
     GrizzlyLDAPConnection(final org.glassfish.grizzly.Connection<?> connection,
             final GrizzlyLDAPConnectionFactory factory) {
         this.connection = connection;
@@ -155,13 +164,13 @@
             }
             pendingRequest.cancel(false);
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.abandonRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeAbandonRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                     return new CompletedFutureResult<Void>((Void) null, messageID);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 throw adaptRequestIOException(e);
@@ -186,12 +195,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.addRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeAddRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -275,15 +284,15 @@
             }
 
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
                     // Use the bind client to get the initial request instead of
                     // using the bind request passed to this method.
                     final GenericBindRequest initialRequest = context.nextBindRequest();
-                    ldapWriter.bindRequest(asn1Writer, messageID, 3, initialRequest);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeBindRequest(messageID, 3, initialRequest);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -320,12 +329,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.compareRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeCompareRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -352,12 +361,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.deleteRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeDeleteRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -404,12 +413,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.extendedRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeExtendedRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -451,12 +460,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.modifyRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeModifyRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -483,12 +492,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.modifyDNRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeModifyDNRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -525,12 +534,12 @@
                 pendingRequests.put(messageID, future);
             }
             try {
-                final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+                final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
                 try {
-                    ldapWriter.searchRequest(asn1Writer, messageID, request);
-                    connection.write(asn1Writer.getBuffer(), null);
+                    writer.writeSearchRequest(messageID, request);
+                    connection.write(writer.getASN1Writer().getBuffer(), null);
                 } finally {
-                    asn1Writer.recycle();
+                    GrizzlyUtils.recycleWriter(writer);
                 }
             } catch (final IOException e) {
                 pendingRequests.remove(messageID);
@@ -553,19 +562,26 @@
         return builder.toString();
     }
 
-    long cancelExpiredRequests(final long currentTime) {
-        final long timeout = factory.getLDAPOptions().getTimeout(TimeUnit.MILLISECONDS);
+    @Override
+    public long handleTimeout(final long currentTime) {
+        final long timeout = getTimeout();
         long delay = timeout;
         if (timeout > 0) {
             for (final int requestID : pendingRequests.keySet()) {
                 final AbstractLDAPFutureResultImpl<?> future = pendingRequests.get(requestID);
                 if (future != null && future.checkForTimeout()) {
                     final long diff = (future.getTimestamp() + timeout) - currentTime;
-                    if (diff <= 0 && pendingRequests.remove(requestID) != null) {
-                        DEFAULT_LOG.debug("Cancelling expired future result: {}", future);
-                        final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT);
-                        future.adaptErrorResult(result);
-                        abandonAsync(Requests.newAbandonRequest(future.getRequestID()));
+                    if (diff <= 0) {
+                        if (pendingRequests.remove(requestID) != null) {
+                            DEFAULT_LOG.debug("Cancelling expired future result: {}", future);
+                            final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT);
+                            future.adaptErrorResult(result);
+                            abandonAsync(Requests.newAbandonRequest(future.getRequestID()));
+                        } else {
+                            DEFAULT_LOG.debug(
+                                    "Pending request {} has already been removed, not cancelling future result",
+                                    requestID);
+                        }
                     } else {
                         delay = Math.min(delay, diff);
                     }
@@ -575,6 +591,11 @@
         return delay;
     }
 
+    @Override
+    public long getTimeout() {
+        return factory.getLDAPOptions().getTimeout(TimeUnit.MILLISECONDS);
+    }
+
     /**
      * Closes this connection, invoking event listeners as needed.
      *
@@ -633,19 +654,19 @@
          * connection and release resources.
          */
         if (notifyClose) {
-            final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+            final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter();
             try {
-                ldapWriter.unbindRequest(asn1Writer, nextMsgID.getAndIncrement(), unbindRequest);
-                connection.write(asn1Writer.getBuffer(), null);
+                writer.writeUnbindRequest(nextMsgID.getAndIncrement(), unbindRequest);
+                connection.write(writer.getASN1Writer().getBuffer(), null);
             } catch (final Exception ignore) {
                 /*
                  * Underlying channel probably blown up. Ignore all errors,
                  * including possibly runtime exceptions (see OPENDJ-672).
                  */
             } finally {
-                asn1Writer.recycle();
+                GrizzlyUtils.recycleWriter(writer);
             }
-            factory.getTimeoutChecker().removeConnection(this);
+            factory.getTimeoutChecker().removeListener(this);
             connection.closeSilently();
             factory.releaseTransportAndTimeoutChecker();
         }

--
Gitblit v1.10.0