Package org.ldaptive.transport.netty
Class NettyConnection
- java.lang.Object
-
- org.ldaptive.transport.TransportConnection
-
- org.ldaptive.transport.netty.NettyConnection
-
- All Implemented Interfaces:
AutoCloseable
,Connection
public final class NettyConnection extends TransportConnection
Netty based connection implementation.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static class
NettyConnection.AutoReadEventHandler
Initiates a channel read when an LDAP message has been processed and auto read is false.class
NettyConnection.BindOperationHandle
Bind specific operation handle that locks other operations until the bind completes.private class
NettyConnection.ClientInitializer
Sets up the Netty pipeline for this connection.private class
NettyConnection.CloseFutureListener
Listener for channel close events.private class
NettyConnection.InboundExceptionHandler
SetsinboundException
and closes the channel when an exception occurs.private class
NettyConnection.InboundMessageHandler
Matches an inbound LDAP response message to its operation handle and removes that handle from the response queue.private class
NettyConnection.LogFutureListener
Listener that logs the future success state when it occurs.protected static class
NettyConnection.MessageDecoder
Decodes byte buffer into a concrete LDAP response message.protected static class
NettyConnection.MessageStatus
Enum that describes the state of an LDAP message in the pipeline.protected static class
NettyConnection.RequestEncoder
Encodes an LDAP request into its DER bytes.private class
NettyConnection.ValidatorHandler
Schedules a connection validator to run based on its strategy.
-
Field Summary
Fields Modifier and Type Field Description private ReentrantReadWriteLock
bindLock
Operation lock when a bind occurs.private io.netty.channel.Channel
channel
Connection to the LDAP server.private Map<io.netty.channel.ChannelOption,Object>
channelOptions
Netty channel configuration options.private Class<? extends io.netty.channel.Channel>
channelType
Type of channel.private NettyConnection.CloseFutureListener
closeListener
Listener notified when the connection is closed.private ExecutorService
connectionExecutor
Executor for scheduling various connection related tasks that cannot or should not be handled by the netty event loop groups.private Instant
connectTime
Time this connection was successfully established, null if the connection is not open.private Throwable
inboundException
Last exception received on the inbound pipeline.private io.netty.channel.EventLoopGroup
ioWorkerGroup
Event worker group used to process I/O.private LdapURL
ldapURL
URL derived from the connection strategy.private static Logger
LOGGER
Logger for this class.private AtomicInteger
messageID
Message ID counter, incremented as requests are sent.private io.netty.channel.EventLoopGroup
messageWorkerGroup
Event worker group used to process inbound messages.private HandleMap
pendingResponses
Queue holding requests that haven't received a response.private static NettyConnection.AutoReadEventHandler
READ_NEXT_MESSAGE
Inbound handler to read the next message if autoRead is false.private ReentrantReadWriteLock
reconnectLock
Block operations while a reconnect is occurring.private static NettyConnection.RequestEncoder
REQUEST_ENCODER
Request encoder pipeline handler.private boolean
shutdownOnClose
Whether to shutdown the event loop groups onConnection.close()
.-
Fields inherited from class org.ldaptive.transport.TransportConnection
closeLock, connectionConfig, lastSuccessfulOpen, openLock
-
-
Constructor Summary
Constructors Constructor Description NettyConnection(ConnectionConfig config, Class<? extends io.netty.channel.Channel> type, io.netty.channel.EventLoopGroup ioGroup, io.netty.channel.EventLoopGroup messageGroup, boolean shutdownGroups)
Creates a new connection.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
close(RequestControl... controls)
Closes this connection.protected void
complete(DefaultOperationHandle handle)
Report that the supplied handle has completed.private io.netty.channel.ChannelFuture
connectBootstrap(NettyConnection.ClientInitializer initializer)
Creates a new bootstrap with the supplied initializer and uses that bootstrap to connect to the ldapURL.private io.netty.channel.Channel
connectInternal()
Creates a Netty bootstrap and connects to the LDAP server.private Object
convertChannelOption(String value)
Performs a best effort at converting a channel option value to the correct type.private io.netty.bootstrap.Bootstrap
createBootstrap(NettyConnection.ClientInitializer initializer)
Creates a NettyBootstrap
with the supplied client initializer.private NettyConnection.ClientInitializer
createClientInitializer()
Creates a new client initializer.private io.netty.handler.ssl.SslHandler
createSslHandler(ConnectionConfig config)
Creates a Netty SSL handler using the supplied connection config.(package private) int
getAndIncrementMessageID()
Returns the value of the next message ID and increments the counter.(package private) Map<io.netty.channel.ChannelOption,Object>
getChannelOptions()
Returns the channel options.LdapURL
getLdapURL()
Returns the URL that was selected for this connection.(package private) int
getMessageID()
Returns the value of the next message ID.private boolean
isClosing()
Returns whether this connection is currently attempting to close.boolean
isOpen()
Returns whether the underlying Netty channel is open.private boolean
isOpening()
Returns whether this connection is currently attempting to open.private void
notifyOperationHandlesOfClose()
Sends an exception notification to all pending responses that the connection has been closed.protected void
open(LdapURL url)
Attempt to open a connection to the supplied LDAP URL.private void
openInitialize(LdapURL url)
Initializes this connection for use after it has been established.void
operation(AbandonRequest request)
Executes an abandon operation.DefaultOperationHandle<AddRequest,AddResponse>
operation(AddRequest request)
Creates a handle for an add operation.NettyConnection.BindOperationHandle
operation(BindRequest request)
Creates a handle for a bind operation.DefaultCompareOperationHandle
operation(CompareRequest request)
Creates a handle for a compare operation.DefaultOperationHandle<DeleteRequest,DeleteResponse>
operation(DeleteRequest request)
Creates a handle for a delete operation.DefaultExtendedOperationHandle
operation(ExtendedRequest request)
Creates a handle for an extended operation.(package private) Result
operation(StartTLSRequest request)
Performs a startTLS operation.DefaultOperationHandle<ModifyDnRequest,ModifyDnResponse>
operation(ModifyDnRequest request)
Creates a handle for a modify dn operation.DefaultOperationHandle<ModifyRequest,ModifyResponse>
operation(ModifyRequest request)
Creates a handle for a modify operation.BindResponse
operation(DefaultSaslClientRequest request)
Performs a SASL client bind operation.BindResponse
operation(SaslClientRequest request)
Performs a SASL bind operation that uses a custom client.DefaultSearchOperationHandle
operation(SearchRequest request)
Creates a handle for a search operation.protected void
operation(UnbindRequest request)
Executes an unbind operation.private void
reconnect()
Attempts to reestablish the channel for this connection.(package private) void
setMessageID(int i)
Sets the value of the next message ID.protected boolean
test(LdapURL url)
Determine whether the supplied URL is acceptable for use.private void
throwIfClosed()
Throws an exception if the Netty channel is closed.String
toString()
private void
waitForConnectionEstablish(NettyConnection.ClientInitializer initializer, io.netty.channel.ChannelFuture future)
Waits until the TCP connection has completed.private void
waitForSSLHandshake(io.netty.channel.Channel ch)
Waits until the SSL handshake has completed.protected void
write(DefaultOperationHandle handle)
Write the request in the supplied handle to the LDAP server.-
Methods inherited from class org.ldaptive.transport.TransportConnection
open, reopen, strategyOpen
-
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
-
Methods inherited from interface org.ldaptive.Connection
close
-
-
-
-
Field Detail
-
LOGGER
private static final Logger LOGGER
Logger for this class.
-
REQUEST_ENCODER
private static final NettyConnection.RequestEncoder REQUEST_ENCODER
Request encoder pipeline handler.
-
READ_NEXT_MESSAGE
private static final NettyConnection.AutoReadEventHandler READ_NEXT_MESSAGE
Inbound handler to read the next message if autoRead is false.
-
channelType
private final Class<? extends io.netty.channel.Channel> channelType
Type of channel.
-
ioWorkerGroup
private final io.netty.channel.EventLoopGroup ioWorkerGroup
Event worker group used to process I/O.
-
messageWorkerGroup
private final io.netty.channel.EventLoopGroup messageWorkerGroup
Event worker group used to process inbound messages.
-
shutdownOnClose
private final boolean shutdownOnClose
Whether to shutdown the event loop groups onConnection.close()
.
-
channelOptions
private final Map<io.netty.channel.ChannelOption,Object> channelOptions
Netty channel configuration options.
-
pendingResponses
private final HandleMap pendingResponses
Queue holding requests that haven't received a response.
-
closeListener
private final NettyConnection.CloseFutureListener closeListener
Listener notified when the connection is closed.
-
messageID
private final AtomicInteger messageID
Message ID counter, incremented as requests are sent.
-
reconnectLock
private final ReentrantReadWriteLock reconnectLock
Block operations while a reconnect is occurring.
-
bindLock
private final ReentrantReadWriteLock bindLock
Operation lock when a bind occurs.
-
connectionExecutor
private ExecutorService connectionExecutor
Executor for scheduling various connection related tasks that cannot or should not be handled by the netty event loop groups. Reconnects in particular require a dedicated thread as the event loop group may be shared or may not be configured with enough threads to handle the task.
-
ldapURL
private LdapURL ldapURL
URL derived from the connection strategy.
-
channel
private io.netty.channel.Channel channel
Connection to the LDAP server.
-
connectTime
private Instant connectTime
Time this connection was successfully established, null if the connection is not open.
-
inboundException
private Throwable inboundException
Last exception received on the inbound pipeline.
-
-
Constructor Detail
-
NettyConnection
public NettyConnection(ConnectionConfig config, Class<? extends io.netty.channel.Channel> type, io.netty.channel.EventLoopGroup ioGroup, io.netty.channel.EventLoopGroup messageGroup, boolean shutdownGroups)
Creates a new connection. Netty supports various transport implementations including NIO, EPOLL, KQueue, etc. The class type and event loop group are tightly coupled in this regard.- Parameters:
config
- connection configurationtype
- type of channelioGroup
- event loop group that handles I/O and supports the channel type, cannot be nullmessageGroup
- event loop group that handles inbound messages, can be nullshutdownGroups
- whether to shutdown the event loop groups when the connection is closed
-
-
Method Detail
-
convertChannelOption
private Object convertChannelOption(String value)
Performs a best effort at converting a channel option value to the correct type. Handles Boolean and Integer types.- Parameters:
value
- to convert- Returns:
- converted value or the supplied value if no conversion occurred
-
createBootstrap
private io.netty.bootstrap.Bootstrap createBootstrap(NettyConnection.ClientInitializer initializer)
Creates a NettyBootstrap
with the supplied client initializer.- Parameters:
initializer
- to provide to the bootstrap- Returns:
- Netty bootstrap
-
test
protected boolean test(LdapURL url)
Description copied from class:TransportConnection
Determine whether the supplied URL is acceptable for use.- Specified by:
test
in classTransportConnection
- Parameters:
url
- LDAP URL to test- Returns:
- whether URL can be become active
-
open
protected void open(LdapURL url) throws LdapException
Description copied from class:TransportConnection
Attempt to open a connection to the supplied LDAP URL.- Specified by:
open
in classTransportConnection
- Parameters:
url
- LDAP URL to connect to- Throws:
LdapException
- if opening the connection fails
-
openInitialize
private void openInitialize(LdapURL url) throws LdapException
Initializes this connection for use after it has been established. If startTLS is configured it will be performed. Any configured connection initializers are invoked.- Parameters:
url
- LDAP URL to connect to- Throws:
LdapException
- if initializing the connection fails
-
getLdapURL
public LdapURL getLdapURL()
Description copied from interface:Connection
Returns the URL that was selected for this connection. The existence of this value does not indicate a current established connection.- Returns:
- LDAP URL
-
connectInternal
private io.netty.channel.Channel connectInternal() throws ConnectException
Creates a Netty bootstrap and connects to the LDAP server. Handles the details of adding an SSL handler to the pipeline. This method waits until the connection is established.- Returns:
- channel for the established connection.
- Throws:
ConnectException
- if the connection fails
-
createClientInitializer
private NettyConnection.ClientInitializer createClientInitializer() throws ConnectException
Creates a new client initializer. If theldapURL
is LDAPS an SSL handler is added to the client initializer.- Returns:
- client initializer
- Throws:
ConnectException
- if the SSL engine cannot be initialized
-
createSslHandler
private io.netty.handler.ssl.SslHandler createSslHandler(ConnectionConfig config) throws SSLException
Creates a Netty SSL handler using the supplied connection config.- Parameters:
config
- containing SSL config- Returns:
- SSL handler
- Throws:
SSLException
- if the SSL engine cannot be initialized
-
connectBootstrap
private io.netty.channel.ChannelFuture connectBootstrap(NettyConnection.ClientInitializer initializer)
Creates a new bootstrap with the supplied initializer and uses that bootstrap to connect to the ldapURL.- Parameters:
initializer
- to create bootstrap with- Returns:
- channel future produced from the connect invocation
-
waitForConnectionEstablish
private void waitForConnectionEstablish(NettyConnection.ClientInitializer initializer, io.netty.channel.ChannelFuture future) throws ConnectException
Waits until the TCP connection has completed.- Parameters:
initializer
- used to determine whether to wait for the SSL handshake to completefuture
- to wait on- Throws:
ConnectException
- if the connection fails
-
waitForSSLHandshake
private void waitForSSLHandshake(io.netty.channel.Channel ch) throws SSLException
Waits until the SSL handshake has completed.- Parameters:
ch
- that the handshake is occurring on- Throws:
SSLException
- if the handshake fails
-
operation
Result operation(StartTLSRequest request) throws LdapException
Performs a startTLS operation. This method can only be invoked when a connection is opened.- Parameters:
request
- to send- Returns:
- result of the startTLS operation
- Throws:
LdapException
- if the operation fails
-
operation
protected void operation(UnbindRequest request)
Description copied from class:TransportConnection
Executes an unbind operation. Clients should close connections usingConnection.close()
.- Specified by:
operation
in classTransportConnection
- Parameters:
request
- unbind request
-
operation
public BindResponse operation(SaslClientRequest request) throws LdapException
Performs a SASL bind operation that uses a custom client.- Parameters:
request
- to send- Returns:
- result of the GSS-API bind operation
- Throws:
LdapException
- if the operation fails or another bind is in progress
-
operation
public BindResponse operation(DefaultSaslClientRequest request) throws LdapException
Performs a SASL client bind operation.- Parameters:
request
- to send- Returns:
- result of the SASL client bind operation
- Throws:
LdapException
- if the operation fails or another bind is in progress
-
operation
public void operation(AbandonRequest request)
Description copied from interface:Connection
Executes an abandon operation. Clients should execute abandons usingOperationHandle.abandon()
.- Parameters:
request
- abandon request
-
operation
public DefaultOperationHandle<AddRequest,AddResponse> operation(AddRequest request)
Description copied from interface:Connection
Creates a handle for an add operation.- Parameters:
request
- add request- Returns:
- operation handle
-
operation
public NettyConnection.BindOperationHandle operation(BindRequest request)
Description copied from interface:Connection
Creates a handle for a bind operation. Since clients must not send requests while a bind is in progress, some methods may not be supported on the operation handle.- Parameters:
request
- bind request- Returns:
- operation handle
-
operation
public DefaultCompareOperationHandle operation(CompareRequest request)
Description copied from interface:Connection
Creates a handle for a compare operation.- Parameters:
request
- compare request- Returns:
- compare operation handle
-
operation
public DefaultOperationHandle<DeleteRequest,DeleteResponse> operation(DeleteRequest request)
Description copied from interface:Connection
Creates a handle for a delete operation.- Parameters:
request
- delete request- Returns:
- operation handle
-
operation
public DefaultExtendedOperationHandle operation(ExtendedRequest request)
Description copied from interface:Connection
Creates a handle for an extended operation.- Parameters:
request
- extended request- Returns:
- extended operation handle
-
operation
public DefaultOperationHandle<ModifyRequest,ModifyResponse> operation(ModifyRequest request)
Description copied from interface:Connection
Creates a handle for a modify operation.- Parameters:
request
- modify request- Returns:
- operation handle
-
operation
public DefaultOperationHandle<ModifyDnRequest,ModifyDnResponse> operation(ModifyDnRequest request)
Description copied from interface:Connection
Creates a handle for a modify dn operation.- Parameters:
request
- modify dn request- Returns:
- operation handle
-
operation
public DefaultSearchOperationHandle operation(SearchRequest request)
Description copied from interface:Connection
Creates a handle for a search operation.- Parameters:
request
- search request- Returns:
- search operation handle
-
write
protected void write(DefaultOperationHandle handle)
Description copied from class:TransportConnection
Write the request in the supplied handle to the LDAP server. This method does not throw, it should report exceptions to the handle.- Specified by:
write
in classTransportConnection
- Parameters:
handle
- for the operation write
-
complete
protected void complete(DefaultOperationHandle handle)
Description copied from class:TransportConnection
Report that the supplied handle has completed. Allows the connection to clean up any resources associated with the handle.- Specified by:
complete
in classTransportConnection
- Parameters:
handle
- that has completed
-
getAndIncrementMessageID
int getAndIncrementMessageID()
Returns the value of the next message ID and increments the counter.- Returns:
- message ID
-
getMessageID
int getMessageID()
Returns the value of the next message ID.- Returns:
- message ID
-
setMessageID
void setMessageID(int i)
Sets the value of the next message ID.- Parameters:
i
- message ID
-
getChannelOptions
Map<io.netty.channel.ChannelOption,Object> getChannelOptions()
Returns the channel options.- Returns:
- channel options
-
close
public void close(RequestControl... controls)
Closes this connection. Abandons all pending responses and sends an unbind to the LDAP server if the connection is open when this method is invoked.- Parameters:
controls
- to send with the unbind request when closing the connection
-
notifyOperationHandlesOfClose
private void notifyOperationHandlesOfClose()
Sends an exception notification to all pending responses that the connection has been closed. Since this invokes any configured exception handlers, notifications will use themessageWorkerGroup
if it is configured.
-
reconnect
private void reconnect()
Attempts to reestablish the channel for this connection.- Throws:
IllegalStateException
- if the connection is open
-
isOpen
public boolean isOpen()
Returns whether the underlying Netty channel is open. SeeChannel.isOpen()
.- Returns:
- whether the Netty channel is open
-
isOpening
private boolean isOpening()
Returns whether this connection is currently attempting to open.- Returns:
- whether the Netty channel is in the process of opening
-
isClosing
private boolean isClosing()
Returns whether this connection is currently attempting to close.- Returns:
- whether the Netty channel is in the process of closing
-
throwIfClosed
private void throwIfClosed() throws LdapException
Throws an exception if the Netty channel is closed. SeeisOpen()
.- Throws:
LdapException
- if the connection is closed
-
-