From 122f2a984f9aaf7a2bc363c6971b94e3663f129b Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Mon, 28 Oct 2013 15:35:48 +0000
Subject: [PATCH] Fix OPENDJ-175: Decouple OpenDJ LDAP SDK from Grizzly CR-2513

---
 opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java   |  131 ++++++++++++++++++++++++++++++++
 opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java |   38 ++-------
 opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java |   45 +++--------
 3 files changed, 152 insertions(+), 62 deletions(-)

diff --git a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java
new file mode 100644
index 0000000..8236aa4
--- /dev/null
+++ b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2013 ForgeRock AS.
+ */
+package com.forgerock.opendj.grizzly;
+
+import java.io.IOException;
+
+import org.forgerock.opendj.io.LDAPReader;
+import org.forgerock.opendj.ldap.DecodeOptions;
+import org.forgerock.opendj.ldap.spi.LDAPMessageHandler;
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.filterchain.BaseFilter;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.filterchain.NextAction;
+
+/**
+ * Base class for LDAP-enabled filter.
+ * <p>
+ * Provides a common {@code handleRead()} method for both client and server
+ * filters.
+ */
+public abstract class LDAPBaseFilter extends BaseFilter {
+
+    /**
+     * The maximum BER element size, or <code>0</code> to indicate that there is
+     * no limit.
+     */
+    protected final int maxASN1ElementSize;
+
+    /**
+     * Allow to control how to decode requests and responses.
+     */
+    protected final DecodeOptions decodeOptions;
+
+    /**
+     * Creates a filter with provided decode options and max size of
+     * ASN1 element.
+     *
+     * @param options
+     *            control how to decode requests and responses
+     * @param maxASN1ElementSize
+     *            The maximum BER element size, or <code>0</code> to indicate
+     *            that there is no limit.
+     */
+    protected LDAPBaseFilter(final DecodeOptions options, final int maxASN1ElementSize) {
+        this.decodeOptions = options;
+        this.maxASN1ElementSize = maxASN1ElementSize;
+    }
+
+    @Override
+    public final NextAction handleRead(final FilterChainContext ctx) throws IOException {
+        final LDAPBaseHandler handler = getLDAPHandler(ctx);
+        final LDAPReader<ASN1BufferReader> reader = handler.getReader();
+        final ASN1BufferReader asn1Reader = reader.getASN1Reader();
+        final Buffer buffer = (Buffer) ctx.getMessage();
+
+        asn1Reader.appendBytesRead(buffer);
+        try {
+            while (reader.hasMessageAvailable()) {
+                reader.readMessage(handler);
+            }
+        } catch (IOException e) {
+            handleReadException(ctx, e);
+            throw e;
+        } finally {
+            asn1Reader.disposeBytesRead();
+        }
+
+        return ctx.getStopAction();
+    }
+
+    /**
+     * Handle an exception occuring during a read within the
+     * {@code handleRead()} method.
+     *
+     * @param ctx
+     *            context when reading
+     * @param e
+     *            exception occuring while reading
+     */
+    protected abstract void handleReadException(FilterChainContext ctx, IOException e);
+
+    /**
+     * Interface for the {@code LDAPMessageHandler} used in the filter, that
+     * must be able to retrieve a Grizzly reader.
+     */
+    protected interface LDAPBaseHandler extends LDAPMessageHandler {
+        /**
+         * Returns the LDAP reader for this handler.
+         * @return the reader
+         */
+        LDAPReader<ASN1BufferReader> getReader();
+    }
+
+    /**
+     * Returns the LDAP message handler associated to the underlying connection
+     * of the provided context.
+     * <p>
+     * If no handler exists yet for the underlying connection, a new one is
+     * created and recorded for the connection.
+     *
+     * @param ctx
+     *            current filter chain context
+     * @return the response handler associated to the connection, which can be a
+     *         new one if no handler have been created yet
+     */
+    protected abstract LDAPBaseHandler getLDAPHandler(final FilterChainContext ctx);
+
+}
diff --git a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java
index a529127..0331276 100644
--- a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java
+++ b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java
@@ -64,12 +64,10 @@
 import org.forgerock.opendj.ldap.spi.LDAPFutureResultImpl;
 import org.forgerock.opendj.ldap.spi.LDAPSearchFutureResultImpl;
 import org.forgerock.opendj.ldap.spi.UnexpectedResponseException;
-import org.glassfish.grizzly.Buffer;
 import org.glassfish.grizzly.Connection;
 import org.glassfish.grizzly.EmptyCompletionHandler;
 import org.glassfish.grizzly.Grizzly;
 import org.glassfish.grizzly.attributes.Attribute;
-import org.glassfish.grizzly.filterchain.BaseFilter;
 import org.glassfish.grizzly.filterchain.FilterChainContext;
 import org.glassfish.grizzly.filterchain.NextAction;
 
@@ -77,17 +75,14 @@
  * Grizzly filter implementation for decoding LDAP responses and handling client
  * side logic for SSL and SASL operations over LDAP.
  */
-final class LDAPClientFilter extends BaseFilter {
+final class LDAPClientFilter extends LDAPBaseFilter {
     private static final Attribute<GrizzlyLDAPConnection> LDAP_CONNECTION_ATTR =
             Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPClientConnection");
 
     private static final Attribute<ClientResponseHandler> RESPONSE_HANDLER_ATTR =
             Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("ClientResponseHandler");
 
-    private final int maxASN1ElementSize;
-    private final DecodeOptions decodeOptions;
-
-    private static final class ClientResponseHandler extends AbstractLDAPMessageHandler {
+    static final class ClientResponseHandler extends AbstractLDAPMessageHandler implements LDAPBaseHandler {
 
         private final LDAPReader<ASN1BufferReader> reader;
         private FilterChainContext context;
@@ -486,8 +481,7 @@
      *            that there is no limit.
      */
     LDAPClientFilter(final DecodeOptions options, final int maxASN1ElementSize) {
-        this.decodeOptions = options;
-        this.maxASN1ElementSize = maxASN1ElementSize;
+        super(options, maxASN1ElementSize);
     }
 
     @Override
@@ -524,30 +518,14 @@
         return ctx.getInvokeAction();
     }
 
+
     @Override
-    public NextAction handleRead(final FilterChainContext ctx) throws IOException {
-        final ClientResponseHandler handler = getResponseHandler(ctx);
-        final LDAPReader<ASN1BufferReader> reader = handler.getReader();
-        final ASN1BufferReader asn1Reader = reader.getASN1Reader();
-        final Buffer buffer = (Buffer) ctx.getMessage();
-
-        asn1Reader.appendBytesRead(buffer);
-        try {
-            while (reader.hasMessageAvailable()) {
-                reader.readMessage(handler);
-            }
-        } catch (IOException e) {
-            final GrizzlyLDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
-            final Result errorResult =
-                    Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR).setCause(e)
-                            .setDiagnosticMessage(e.getMessage());
-            ldapConnection.close(null, false, errorResult);
-            throw e;
-        } finally {
-            asn1Reader.disposeBytesRead();
-        }
-
-        return ctx.getStopAction();
+    protected final void handleReadException(FilterChainContext ctx, IOException e) {
+        final GrizzlyLDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
+        final Result errorResult =
+                Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR).setCause(e)
+                        .setDiagnosticMessage(e.getMessage());
+        ldapConnection.close(null, false, errorResult);
     }
 
     /**
@@ -562,7 +540,8 @@
      * @return the response handler associated to the context, which can be a
      *         new one if no handler have been created yet
      */
-    private ClientResponseHandler getResponseHandler(final FilterChainContext ctx) {
+    @Override
+    protected final LDAPBaseHandler getLDAPHandler(final FilterChainContext ctx) {
         Connection<?> connection = ctx.getConnection();
         ClientResponseHandler handler = RESPONSE_HANDLER_ATTR.get(connection);
         if (handler == null) {
diff --git a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
index 33c5d61..eea9d48 100644
--- a/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
+++ b/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -75,11 +75,9 @@
 import org.forgerock.opendj.ldap.spi.AbstractLDAPMessageHandler;
 import org.forgerock.opendj.ldap.spi.UnexpectedRequestException;
 import org.forgerock.opendj.ldap.spi.UnsupportedMessageException;
-import org.glassfish.grizzly.Buffer;
 import org.glassfish.grizzly.Connection;
 import org.glassfish.grizzly.Grizzly;
 import org.glassfish.grizzly.attributes.Attribute;
-import org.glassfish.grizzly.filterchain.BaseFilter;
 import org.glassfish.grizzly.filterchain.Filter;
 import org.glassfish.grizzly.filterchain.FilterChain;
 import org.glassfish.grizzly.filterchain.FilterChainContext;
@@ -94,7 +92,7 @@
  * Grizzly filter implementation for decoding LDAP requests and handling server
  * side logic for SSL and SASL operations over LDAP.
  */
-final class LDAPServerFilter extends BaseFilter {
+final class LDAPServerFilter extends LDAPBaseFilter {
 
     /**
      * Provides an arbitrary write operation on a LDAP writer.
@@ -659,10 +657,9 @@
     }
 
     private final GrizzlyLDAPListener listener;
-    private final int maxASN1ElementSize;
-    private final DecodeOptions decodeOptions;
 
-    private static final class ServerRequestHandler extends AbstractLDAPMessageHandler {
+    private static final class ServerRequestHandler
+        extends AbstractLDAPMessageHandler implements LDAPBaseHandler {
 
         private final Connection<?> connection;
         private final LDAPReader<ASN1BufferReader> reader;
@@ -830,10 +827,8 @@
      */
     LDAPServerFilter(final GrizzlyLDAPListener listener, final DecodeOptions options,
             final int maxASN1ElementSize) {
+        super(options, maxASN1ElementSize <= 0 ? DEFAULT_MAX_REQUEST_SIZE : maxASN1ElementSize);
         this.listener = listener;
-        this.decodeOptions = options;
-        this.maxASN1ElementSize =
-                maxASN1ElementSize <= 0 ? DEFAULT_MAX_REQUEST_SIZE : maxASN1ElementSize;
     }
 
     @Override
@@ -875,25 +870,8 @@
     }
 
     @Override
-    public NextAction handleRead(final FilterChainContext ctx) throws IOException {
-        final ServerRequestHandler requestHandler = getRequestHandler(ctx.getConnection());
-        final LDAPReader<ASN1BufferReader> reader = requestHandler.getReader();
-        final ASN1BufferReader asn1Reader = reader.getASN1Reader();
-        final Buffer buffer = (Buffer) ctx.getMessage();
-
-        asn1Reader.appendBytesRead(buffer);
-        try {
-            while (reader.hasMessageAvailable()) {
-                reader.readMessage(requestHandler);
-            }
-        } catch (IOException e) {
-            exceptionOccurred(ctx, e);
-            throw e;
-        } finally {
-            asn1Reader.disposeBytesRead();
-        }
-
-        return ctx.getStopAction();
+    protected final void handleReadException(FilterChainContext ctx, IOException e) {
+        exceptionOccurred(ctx, e);
     }
 
     /**
@@ -907,7 +885,9 @@
      * @return the response handler associated to the context, which can be a
      *         new one if no handler have been created yet
      */
-    private ServerRequestHandler getRequestHandler(final Connection<?> connection) {
+    @Override
+    protected final LDAPBaseHandler getLDAPHandler(final FilterChainContext ctx) {
+        Connection<?> connection = ctx.getConnection();
         ServerRequestHandler handler = REQUEST_HANDLER_ATTR.get(connection);
         if (handler == null) {
             LDAPReader<ASN1BufferReader> reader = GrizzlyUtils.createReader(decodeOptions,

--
Gitblit v1.10.0