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,