| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | import static com.forgerock.opendj.util.StaticUtils.DEBUG_LOG; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | |
| | | import org.glassfish.grizzly.ssl.SSLFilter; |
| | | |
| | | import com.forgerock.opendj.util.CompletedFutureResult; |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | | /** |
| | |
| | | private final org.glassfish.grizzly.Connection<?> connection; |
| | | private final LDAPWriter ldapWriter = new LDAPWriter(); |
| | | private final AtomicInteger nextMsgID = new AtomicInteger(1); |
| | | private final LDAPOptions options; |
| | | private final LDAPConnectionFactoryImpl factory; |
| | | private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests = |
| | | new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>(); |
| | | private final Object stateLock = new Object(); |
| | |
| | | private boolean isFailed = false; |
| | | private List<ConnectionEventListener> listeners = null; |
| | | |
| | | /** |
| | | * Creates a new LDAP connection. |
| | | * |
| | | * @param connection |
| | | * The Grizzly connection. |
| | | * @param options |
| | | * The LDAP client options. |
| | | */ |
| | | LDAPConnection(final org.glassfish.grizzly.Connection<?> connection, final LDAPOptions options) { |
| | | LDAPConnection(final org.glassfish.grizzly.Connection<?> connection, |
| | | final LDAPConnectionFactoryImpl factory) { |
| | | this.connection = connection; |
| | | this.options = options; |
| | | this.factory = factory; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Void> abandonAsync(final AbandonRequest request) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest; |
| | |
| | | pendingRequest = pendingRequests.remove(request.getRequestID()); |
| | | } |
| | | if (pendingRequest == null) { |
| | | // There has never been a request with the specified message ID or |
| | | // the response has already been received and handled. We can ignore |
| | | // this abandon request. |
| | | /* |
| | | * There has never been a request with the specified message ID |
| | | * or the response has already been received and handled. We can |
| | | * ignore this abandon request. |
| | | */ |
| | | |
| | | // Message ID will be -1 since no request was sent. |
| | | return new CompletedFutureResult<Void>((Void) null); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> addAsync(final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<BindResult> bindAsync(final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close(final UnbindRequest request, final String reason) { |
| | | // FIXME: I18N need to internationalize this message. |
| | |
| | | "Connection closed by client" + (reason != null ? ": " + reason : ""))); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<CompareResult> compareAsync(final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> deleteAsync(final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync( |
| | | final ExtendedRequest<R> request, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() { |
| | | synchronized (stateLock) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isValid() { |
| | | synchronized (stateLock) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyAsync(final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> searchAsync(final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder builder = new StringBuilder(); |
| | |
| | | } |
| | | |
| | | long cancelExpiredRequests(final long currentTime) { |
| | | final long timeout = options.getTimeout(TimeUnit.MILLISECONDS); |
| | | final long timeout = factory.getLDAPOptions().getTimeout(TimeUnit.MILLISECONDS); |
| | | long delay = timeout; |
| | | if (timeout > 0) { |
| | | for (final int requestID : pendingRequests.keySet()) { |
| | |
| | | if (future != null) { |
| | | final long diff = (future.getTimestamp() + timeout) - currentTime; |
| | | if (diff <= 0 && pendingRequests.remove(requestID) != null) { |
| | | StaticUtils.DEBUG_LOG.fine("Cancelling expired future result: " + future); |
| | | DEBUG_LOG.fine("Cancelling expired future result: " + future); |
| | | final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT); |
| | | future.adaptErrorResult(result); |
| | | |
| | | abandonAsync(Requests.newAbandonRequest(future.getRequestID())); |
| | | } else { |
| | | delay = Math.min(delay, diff); |
| | |
| | | // Underlying channel prob blown up. Just ignore. |
| | | } |
| | | } |
| | | TimeoutChecker.INSTANCE.removeConnection(this); |
| | | factory.getTimeoutChecker().removeConnection(this); |
| | | connection.closeSilently(); |
| | | |
| | | // Notify listeners. |
| | |
| | | } |
| | | |
| | | LDAPOptions getLDAPOptions() { |
| | | return options; |
| | | return factory.getLDAPOptions(); |
| | | } |
| | | |
| | | AbstractLDAPFutureResultImpl<?> getPendingRequest(final Integer messageID) { |
| | |
| | | private void checkConnectionIsValid() throws ErrorResultException { |
| | | if (!isValid0()) { |
| | | if (failedDueToDisconnect) { |
| | | // Connection termination was triggered remotely. We don't want |
| | | // to blindly pass on the result code to requests since it could |
| | | // be confused for a genuine response. For example, if the |
| | | // disconnect contained the invalidCredentials result code then |
| | | // this could be misinterpreted as a genuine authentication |
| | | // failure for subsequent bind requests. |
| | | /* |
| | | * Connection termination was triggered remotely. We don't want |
| | | * to blindly pass on the result code to requests since it could |
| | | * be confused for a genuine response. For example, if the |
| | | * disconnect contained the invalidCredentials result code then |
| | | * this could be misinterpreted as a genuine authentication |
| | | * failure for subsequent bind requests. |
| | | */ |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_SERVER_DOWN, |
| | | "Connection closed by server"); |
| | | } else { |