mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Nicolas Capponi
28.35.2013 122f2a984f9aaf7a2bc363c6971b94e3663f129b
Fix OPENDJ-175: Decouple OpenDJ LDAP SDK from Grizzly
CR-2513

* Add base class LDAPBaseFilter to share code between
LDAPServerFilter and LDAPClientFilter classes as suggested
in code review.

Allows to share handleRead() method
1 files added
2 files modified
214 ■■■■ changed files
opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java 131 ●●●●● patch | view | raw | blame | history
opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPClientFilter.java 45 ●●●● patch | view | raw | blame | history
opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java 38 ●●●● patch | view | raw | blame | history
opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPBaseFilter.java
New file
@@ -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);
}
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) {
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,