| | |
| | | import java.net.SocketAddress; |
| | | import java.util.concurrent.ExecutionException; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | |
| | | // Give up immediately if the future has been cancelled. |
| | | if (future.isCancelled()) { |
| | | connection.close(); |
| | | releaseTransportAndTimeoutChecker(); |
| | | return; |
| | | } |
| | | |
| | |
| | | public void failed(final Throwable throwable) { |
| | | onFailure(connection, throwable); |
| | | } |
| | | |
| | | }); |
| | | } catch (final IOException e) { |
| | | onFailure(connection, e); |
| | |
| | | public void failed(final Throwable throwable) { |
| | | // Adapt and forward. |
| | | future.handleErrorResult(adaptConnectionException(throwable)); |
| | | releaseTransportAndTimeoutChecker(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // Abort connection attempt due to error. |
| | | connection.close(); |
| | | future.handleErrorResult(adaptConnectionException(t)); |
| | | releaseTransportAndTimeoutChecker(); |
| | | } |
| | | |
| | | private void onSuccess(final LDAPConnection connection) { |
| | |
| | | // Close the connection if the future was cancelled. |
| | | if (future.isCancelled()) { |
| | | connection.close(); |
| | | releaseTransportAndTimeoutChecker(); |
| | | } |
| | | } |
| | | } |
| | |
| | | private final FilterChain defaultFilterChain; |
| | | private final LDAPOptions options; |
| | | private final SocketAddress socketAddress; |
| | | private final ReferenceCountedObject<TCPNIOTransport>.Reference transport; |
| | | |
| | | /** |
| | | * Prevents the transport and timeoutChecker being released when there are |
| | | * remaining references (this factory or any connections). It is initially |
| | | * set to 1 because this factory has a reference. |
| | | */ |
| | | private final AtomicInteger referenceCount = new AtomicInteger(1); |
| | | |
| | | /** |
| | | * Indicates whether this factory has been closed or not. |
| | | */ |
| | | private final AtomicBoolean isClosed = new AtomicBoolean(); |
| | | |
| | | private final ReferenceCountedObject<TCPNIOTransport>.Reference transport; |
| | | private final ReferenceCountedObject<TimeoutChecker>.Reference timeoutChecker = TIMEOUT_CHECKER |
| | | .acquire(); |
| | | |
| | |
| | | @Override |
| | | public void close() { |
| | | if (isClosed.compareAndSet(false, true)) { |
| | | transport.release(); |
| | | timeoutChecker.release(); |
| | | releaseTransportAndTimeoutChecker(); |
| | | } |
| | | } |
| | | |
| | |
| | | @Override |
| | | public FutureResult<Connection> getConnectionAsync( |
| | | final ResultHandler<? super Connection> handler) { |
| | | acquireTransportAndTimeoutChecker(); // Protect resources. |
| | | final SocketConnectorHandler connectorHandler = |
| | | TCPNIOConnectorHandler.builder(transport.get()).processor(defaultFilterChain) |
| | | .build(); |
| | |
| | | return socketAddress; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnectionFactory("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | TimeoutChecker getTimeoutChecker() { |
| | | return timeoutChecker.get(); |
| | | } |
| | |
| | | return options; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnectionFactory("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | void releaseTransportAndTimeoutChecker() { |
| | | if (referenceCount.decrementAndGet() == 0) { |
| | | transport.release(); |
| | | timeoutChecker.release(); |
| | | } |
| | | } |
| | | |
| | | private void acquireTransportAndTimeoutChecker() { |
| | | /* |
| | | * If the factory is not closed then we need to prevent the resources |
| | | * (transport, timeout checker) from being released while the connection |
| | | * attempt is in progress. |
| | | */ |
| | | referenceCount.incrementAndGet(); |
| | | if (isClosed.get()) { |
| | | releaseTransportAndTimeoutChecker(); |
| | | throw new IllegalStateException("Attempted to get a connection after factory close"); |
| | | } |
| | | } |
| | | } |