From 5bb6c450fbf04361e37a0fc1de2a7220de00e8ee Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 18 Oct 2013 15:52:51 +0000
Subject: [PATCH] Fix OPENDJ-41: Expose LDAP Grizzly filter APIs This a a part of OPENDJ-175 - Decouple OpenDJ LDAP SDK from Grizzly CR2491
---
opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java | 21 ---
opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java | 16 --
opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyUtils.java | 126 +++++++++++++++++++++
opendj-sdk/opendj3/opendj-grizzly/src/test/java/com/forgerock/opendj/grizzly/GrizzlyUtilsTestCase.java | 113 ++++++++++++++++++
opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java | 5
opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java | 21 ---
6 files changed, 247 insertions(+), 55 deletions(-)
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
index 40cd7b9..6a2f5d8 100644
--- a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -84,7 +84,6 @@
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.filterchain.FilterChain;
-import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
@@ -706,25 +705,7 @@
*/
void installFilter(final Filter filter) {
synchronized (stateLock) {
- // Determine the index where the filter should be added.
- final FilterChain oldFilterChain = (FilterChain) connection.getProcessor();
- int filterIndex = oldFilterChain.size() - 1;
- if (filter instanceof SSLFilter) {
- // Beneath any ConnectionSecurityLayerFilters if present,
- // otherwise beneath the LDAP filter.
- for (int i = oldFilterChain.size() - 2; i >= 0; i--) {
- if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) {
- filterIndex = i + 1;
- break;
- }
- }
- }
-
- // Create the new filter chain.
- final FilterChain newFilterChain =
- FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter)
- .build();
- connection.setProcessor(newFilterChain);
+ GrizzlyUtils.addFilterToConnection(filter, connection);
}
}
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
index 10e10e0..165e400 100644
--- a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
@@ -53,8 +53,6 @@
import org.glassfish.grizzly.EmptyCompletionHandler;
import org.glassfish.grizzly.SocketConnectorHandler;
import org.glassfish.grizzly.filterchain.FilterChain;
-import org.glassfish.grizzly.filterchain.FilterChainBuilder;
-import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.TCPNIOConnectorHandler;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
@@ -257,7 +255,8 @@
this.socketAddress = address;
this.options = new LDAPOptions(options);
this.clientFilter = new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0);
- this.defaultFilterChain = FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
+ this.defaultFilterChain = GrizzlyUtils.buildFilterChain(this.transport.get().getProcessor(), clientFilter);
+
}
@Override
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
index bcc0f88..b441b64 100644
--- a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
@@ -40,8 +40,6 @@
import org.forgerock.opendj.ldap.ServerConnectionFactory;
import org.forgerock.opendj.ldap.spi.LDAPListenerImpl;
import org.glassfish.grizzly.filterchain.FilterChain;
-import org.glassfish.grizzly.filterchain.FilterChainBuilder;
-import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.TCPNIOBindingHandler;
import org.glassfish.grizzly.nio.transport.TCPNIOServerConnection;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
@@ -53,7 +51,6 @@
*/
public final class GrizzlyLDAPListener implements LDAPListenerImpl {
private final ReferenceCountedObject<TCPNIOTransport>.Reference transport;
- private final FilterChain defaultFilterChain;
private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory;
private final TCPNIOServerConnection serverConnection;
private final AtomicBoolean isClosed = new AtomicBoolean();
@@ -105,12 +102,11 @@
this.connectionFactory = factory;
final DecodeOptions decodeOptions = new DecodeOptions(options.getDecodeOptions());
- this.defaultFilterChain =
- FilterChainBuilder.stateless().add(new TransportFilter()).add(
- new LDAPServerFilter(this, new LDAPReader(decodeOptions), options
- .getMaxRequestSize())).build();
+ final LDAPServerFilter serverFilter = new LDAPServerFilter(this, new LDAPReader(decodeOptions), options
+ .getMaxRequestSize());
+ final FilterChain ldapChain = GrizzlyUtils.buildFilterChain(this.transport.get().getProcessor(), serverFilter);
final TCPNIOBindingHandler bindingHandler =
- TCPNIOBindingHandler.builder(this.transport.get()).processor(defaultFilterChain).build();
+ TCPNIOBindingHandler.builder(this.transport.get()).processor(ldapChain).build();
this.serverConnection = bindingHandler.bind(address, options.getBacklog());
}
@@ -148,8 +144,4 @@
ServerConnectionFactory<LDAPClientContext, Integer> getConnectionFactory() {
return connectionFactory;
}
-
- FilterChain getDefaultFilterChain() {
- return defaultFilterChain;
- }
}
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyUtils.java b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyUtils.java
new file mode 100644
index 0000000..4750bdd
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyUtils.java
@@ -0,0 +1,126 @@
+/*
+ * 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 org.glassfish.grizzly.Processor;
+import org.glassfish.grizzly.filterchain.Filter;
+import org.glassfish.grizzly.filterchain.FilterChain;
+import org.glassfish.grizzly.filterchain.FilterChainBuilder;
+import org.glassfish.grizzly.filterchain.TransportFilter;
+import org.glassfish.grizzly.ssl.SSLFilter;
+
+/**
+ * Common utility methods.
+ */
+final class GrizzlyUtils {
+
+
+ /**
+ * Build a filter chain from the provided processor if possible and the
+ * provided filter.
+ * <p>
+ * If the provided processor can't be used for building the new filter
+ * chain, then a chain with only a {@code TransportFilter} is used as a base
+ * chain.
+ *
+ * @param processor
+ * processor to build the filter chain from. If the processor is
+ * not a filter chain (for example, it can be a
+ * {@code StandaloneProcessor} then it is ignored to build the
+ * returned filter chain
+ * @param filter
+ * filter to add at the end of the filter chain
+ * @return a new filter chain, based on the provided processor if processor
+ * is a {@code FilterChain}, and having the provided filter as the
+ * last filter
+ */
+ public static FilterChain buildFilterChain(Processor processor, Filter filter) {
+ if (processor instanceof FilterChain) {
+ return FilterChainBuilder.stateless().addAll((FilterChain) processor).add(filter).build();
+ } else {
+ return FilterChainBuilder.stateless().add(new TransportFilter()).add(filter).build();
+ }
+ }
+
+ /**
+ * Adds a filter to filter chain registered with the given connection.
+ * <p>
+ * For a non-SSL filter, filter is added at the last position before the
+ * LDAP filter.
+ * <p>
+ * For a SSL filter, filter is added before any
+ * {@code ConnectionSecurityLayerFilter} which is already present in the
+ * filter chain.
+ *
+ * @param filter
+ * filter to add
+ * @param connection
+ * connection to update with the new filter chain containing the
+ * provided filter
+ */
+ public static void addFilterToConnection(final Filter filter, org.glassfish.grizzly.Connection<?> connection) {
+ final FilterChain currentChain = (FilterChain) connection.getProcessor();
+ final FilterChain newChain = addFilterToChain(filter, currentChain);
+ connection.setProcessor(newChain);
+ }
+
+ /**
+ * Adds a filter to a filter chain.
+ * <p>
+ * For a non-SSL filter, filter is added at the last position before the
+ * LDAP filter.
+ * <p>
+ * For a SSL filter, filter is added before any
+ * {@code ConnectionSecurityLayerFilter} which is already present in the
+ * filter chain.
+ *
+ * @param filter
+ * filter to add
+ * @param chain
+ * initial filter chain
+ * @return a new filter chain which includes the provided filter
+ */
+ public static FilterChain addFilterToChain(final Filter filter, final FilterChain chain) {
+ // By default, before LDAP filter which is the last one
+ int indexToAddFilter = chain.size() - 1;
+ if (filter instanceof SSLFilter) {
+ // Before any ConnectionSecurityLayerFilters if present
+ for (int i = chain.size() - 2; i >= 0; i--) {
+ if (!(chain.get(i) instanceof ConnectionSecurityLayerFilter)) {
+ indexToAddFilter = i + 1;
+ break;
+ }
+ }
+ }
+ return FilterChainBuilder.stateless().addAll(chain).add(indexToAddFilter, filter).build();
+ }
+
+ // Prevent instantiation.
+ private GrizzlyUtils() {
+ // No implementation required.
+ }
+
+}
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
index 6080156..f0c9f43 100644
--- a/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -76,7 +76,6 @@
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.filterchain.FilterChain;
-import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
@@ -360,25 +359,7 @@
* The filter to be installed.
*/
private void installFilter(final Filter filter) {
- // Determine the index where the filter should be added.
- final FilterChain oldFilterChain = (FilterChain) connection.getProcessor();
- int filterIndex = oldFilterChain.size() - 1;
- if (filter instanceof SSLFilter) {
- // Beneath any ConnectionSecurityLayerFilters if present,
- // otherwise beneath the LDAP filter.
- for (int i = oldFilterChain.size() - 2; i >= 0; i--) {
- if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) {
- filterIndex = i + 1;
- break;
- }
- }
- }
-
- // Create the new filter chain.
- final FilterChain newFilterChain =
- FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter)
- .build();
- connection.setProcessor(newFilterChain);
+ GrizzlyUtils.addFilterToConnection(filter, connection);
}
/**
diff --git a/opendj-sdk/opendj3/opendj-grizzly/src/test/java/com/forgerock/opendj/grizzly/GrizzlyUtilsTestCase.java b/opendj-sdk/opendj3/opendj-grizzly/src/test/java/com/forgerock/opendj/grizzly/GrizzlyUtilsTestCase.java
new file mode 100644
index 0000000..845e0fe
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-grizzly/src/test/java/com/forgerock/opendj/grizzly/GrizzlyUtilsTestCase.java
@@ -0,0 +1,113 @@
+/*
+ * 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 static org.fest.assertions.Assertions.*;
+
+import org.forgerock.opendj.ldap.SdkTestCase;
+import org.glassfish.grizzly.StandaloneProcessor;
+import org.glassfish.grizzly.filterchain.BaseFilter;
+import org.glassfish.grizzly.filterchain.FilterChain;
+import org.glassfish.grizzly.filterchain.FilterChainBuilder;
+import org.glassfish.grizzly.filterchain.TransportFilter;
+import org.glassfish.grizzly.ssl.SSLFilter;
+import org.testng.annotations.Test;
+
+@SuppressWarnings("javadoc")
+public class GrizzlyUtilsTestCase extends SdkTestCase {
+
+ private static final class DummyLDAPFilter extends BaseFilter { // only need type
+ }
+
+ private static final class FilterOne extends BaseFilter { // only need type
+ }
+
+ private static final class DummySSLFilter extends SSLFilter { // only need type
+ }
+
+ /**
+ * Default filter chain contains a transport filter and a ldap filter.
+ */
+ private FilterChain getDefaultFilterChain() {
+ return FilterChainBuilder.stateless().
+ add(new TransportFilter()).add(new DummyLDAPFilter()).build();
+ }
+
+ @Test
+ public void addFilterToChain() throws Exception {
+ final FilterChain chain = GrizzlyUtils.addFilterToChain(new FilterOne(), getDefaultFilterChain());
+
+ assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0);
+ assertThat(chain.indexOfType(FilterOne.class)).isEqualTo(1);
+ assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(2);
+ assertThat(chain.size()).isEqualTo(3);
+ }
+
+ @Test
+ public void addSSLFilterToChain() throws Exception {
+ final FilterChain chain = GrizzlyUtils.addFilterToChain(new DummySSLFilter(), getDefaultFilterChain());
+
+ assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0);
+ assertThat(chain.indexOfType(DummySSLFilter.class)).isEqualTo(1);
+ assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(2);
+ assertThat(chain.size()).isEqualTo(3);
+ }
+
+ @Test
+ public void addConnectionSecurityLayerAndSSLFilterToChain() throws Exception {
+ final FilterChain chain = GrizzlyUtils.addFilterToChain(new ConnectionSecurityLayerFilter(null, null),
+ getDefaultFilterChain());
+ final FilterChain sslChain = GrizzlyUtils.addFilterToChain(new DummySSLFilter(), chain);
+
+ // SSLFilter must be beneath ConnectionSecurityLayerFilter
+ assertThat(sslChain.indexOfType(TransportFilter.class)).isEqualTo(0);
+ assertThat(sslChain.indexOfType(DummySSLFilter.class)).isEqualTo(1);
+ assertThat(sslChain.indexOfType(ConnectionSecurityLayerFilter.class)).isEqualTo(2);
+ assertThat(sslChain.indexOfType(DummyLDAPFilter.class)).isEqualTo(3);
+ assertThat(sslChain.size()).isEqualTo(4);
+ }
+
+ @Test
+ public void buildFilterChainFromFilterChainProcessor() throws Exception {
+ final FilterChain chain = GrizzlyUtils.buildFilterChain(
+ FilterChainBuilder.stateless().add(new TransportFilter()).build(), new DummyLDAPFilter());
+
+ assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0);
+ assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(1);
+ assertThat(chain.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void buildFilterChainFromNonFilterChainProcessor() throws Exception {
+ final FilterChain chain = GrizzlyUtils.buildFilterChain(new StandaloneProcessor(), new DummyLDAPFilter());
+
+ assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0);
+ assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(1);
+ assertThat(chain.size()).isEqualTo(2);
+ }
+
+
+}
--
Gitblit v1.10.0