Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* Copyright 2010 Sun Microsystems, Inc.
* Portions copyright 2011-2016 ForgeRock AS.
* Portions copyright 2025 3A Systems, LLC.
* Portions copyright 2025-2026 3A Systems, LLC.
*/
package org.forgerock.opendj.grizzly;

Expand All @@ -37,6 +37,7 @@
import org.forgerock.opendj.ldap.spi.LDAPListenerImpl;
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapRequestEnvelope;
import org.forgerock.util.Function;
import org.forgerock.util.Option;
import org.forgerock.util.Options;
import org.glassfish.grizzly.filterchain.FilterChain;
import org.glassfish.grizzly.nio.transport.TCPNIOBindingHandler;
Expand All @@ -52,6 +53,13 @@
* LDAP listener implementation using Grizzly for transport.
*/
public final class GrizzlyLDAPListener implements LDAPListenerImpl {
/**
* Grizzly TCP Transport NIO implementation to bind the listener to and to serve its connections with. If
* {@code null}, the default server transport shared by every listener in the JVM will be used. A transport
* provided here is not shut down when the listener is closed: its owner remains responsible for it.
*/
public static final Option<TCPNIOTransport> GRIZZLY_TRANSPORT = Option.of(TCPNIOTransport.class, null);

private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private final ReferenceCountedObject<TCPNIOTransport>.Reference transport;
private final Collection<TCPNIOServerConnection> serverConnections;
Expand All @@ -66,7 +74,7 @@ public final class GrizzlyLDAPListener implements LDAPListenerImpl {
* @param addresses
* The addresses to listen on.
* @param options
* The LDAP listener options.
* The LDAP listener options, including the optional {@link #GRIZZLY_TRANSPORT}.
* @param requestHandlerFactory
* The server connection factory which will be used to create server connections.
* @throws IOException
Expand All @@ -76,7 +84,7 @@ public GrizzlyLDAPListener(final Set<InetSocketAddress> addresses, final Options
final Function<LDAPClientContext,
ReactiveHandler<LDAPClientContext, LdapRequestEnvelope, Stream<Response>>,
LdapException> requestHandlerFactory) throws IOException {
this(addresses, requestHandlerFactory, options, null);
this(addresses, requestHandlerFactory, options, options.get(GRIZZLY_TRANSPORT));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static org.mockito.Mockito.mock;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.Arrays;
Expand Down Expand Up @@ -72,6 +73,8 @@
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.util.Options;
import org.forgerock.util.promise.PromiseImpl;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -280,6 +283,43 @@ public void testLDAPListenerBasic() throws Exception {
}
}

/**
* A listener given a transport with {@link GrizzlyLDAPListener#GRIZZLY_TRANSPORT} serves its connections with that
* transport, and leaves it running when it is closed.
*/
@Test(timeOut = 10000)
public void testLDAPListenerWithProvidedTransport() throws Exception {
final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();
transport.start();
try {
final MockServerConnection serverConnection = new MockServerConnection();
final Options options = defaultOptions().set(GrizzlyLDAPListener.GRIZZLY_TRANSPORT, transport);
final LDAPListener listener = new LDAPListener(Collections.singleton(loopbackWithDynamicPort()),
new ServerConnectionFactoryAdapter(options.get(LDAP_DECODE_OPTIONS),
new MockServerConnectionFactory(serverConnection)),
options);
try {
final InetSocketAddress addr = listener.firstSocketAddress();
final Connection connection =
new LDAPConnectionFactory(addr.getHostName(), addr.getPort()).getConnection();
try {
final LDAPClientContext context = serverConnection.context.get(10, TimeUnit.SECONDS);
final Field field = context.getClass().getDeclaredField("connection");
field.setAccessible(true);
assertThat(((org.glassfish.grizzly.Connection<?>) field.get(context)).getTransport())
.isSameAs(transport);
} finally {
connection.close();
}
} finally {
listener.close();
}
assertThat(transport.isStopped()).isFalse();
} finally {
transport.shutdownNow();
}
}

/**
* Tests LDAP listener which attempts to open a connection to a remote
* offline server at the point when the listener accepts the client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,72 @@
<adm:property-reference name="listen-port" />
<adm:property-reference name="use-ssl" />
<adm:property-reference name="ssl-cert-nickname" />
<adm:property-reference name="use-tcp-keep-alive" />
<adm:property-reference name="use-tcp-no-delay" />
<adm:property name="use-tcp-keep-alive" advanced="true">
<adm:synopsis>
Indicates whether the
<adm:user-friendly-name />
should use TCP keep-alive.
</adm:synopsis>
<adm:description>
If enabled, the SO_KEEPALIVE socket option is used to indicate that TCP
keepalive messages should periodically be sent to the client to
verify that the associated connection is still valid. This may
also help prevent cases in which intermediate network hardware
could silently drop an otherwise idle client connection, provided
that the keepalive interval configured in the underlying operating
system is smaller than the timeout enforced by the network
hardware.
</adm:description>
<adm:requires-admin-action>
<adm:component-restart />
</adm:requires-admin-action>
<adm:default-behavior>
<adm:defined>
<adm:value>true</adm:value>
</adm:defined>
</adm:default-behavior>
<adm:syntax>
<adm:boolean />
</adm:syntax>
<adm:profile name="ldap">
<ldap:attribute>
<ldap:name>ds-cfg-use-tcp-keep-alive</ldap:name>
</ldap:attribute>
</adm:profile>
</adm:property>
<adm:property name="use-tcp-no-delay" advanced="true">
<adm:synopsis>
Indicates whether the
<adm:user-friendly-name />
should use TCP no-delay.
</adm:synopsis>
<adm:description>
If enabled, the TCP_NODELAY socket option is used to ensure
that response messages to the client are sent immediately rather
than potentially waiting to determine whether additional response
messages can be sent in the same packet. In most cases, using the
TCP_NODELAY socket option provides better performance and
lower response times, but disabling it may help for some cases in
which the server sends a large number of entries to a client
in response to a search request.
</adm:description>
<adm:requires-admin-action>
<adm:component-restart />
</adm:requires-admin-action>
<adm:default-behavior>
<adm:defined>
<adm:value>true</adm:value>
</adm:defined>
</adm:default-behavior>
<adm:syntax>
<adm:boolean />
</adm:syntax>
<adm:profile name="ldap">
<ldap:attribute>
<ldap:name>ds-cfg-use-tcp-no-delay</ldap:name>
</ldap:attribute>
</adm:profile>
</adm:property>
<adm:property-reference name="allow-tcp-reuse-address" />
<adm:property name="key-manager-provider">
<adm:synopsis>
Expand Down Expand Up @@ -338,6 +402,9 @@
each client connection and used to buffer LDAP response messages data
when writing.
</adm:description>
<adm:requires-admin-action>
<adm:component-restart />
</adm:requires-admin-action>
<adm:default-behavior>
<adm:defined>
<adm:value>4096 bytes</adm:value>
Expand Down
5 changes: 5 additions & 0 deletions opendj-server-legacy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@
<artifactId>opendj-server</artifactId>
</dependency>

<dependency>
<groupId>org.openidentityplatform.opendj</groupId>
<artifactId>opendj-grizzly</artifactId>
</dependency>

<dependency>
<groupId>org.openidentityplatform.opendj</groupId>
<artifactId>opendj-ldap-toolkit</artifactId>
Expand Down
Loading
Loading