package com.hwlcn.ldap.ldap.sdk; import java.io.Serializable; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import com.hwlcn.ldap.util.Debug; import com.hwlcn.core.annotation.NotMutable; import com.hwlcn.ldap.util.StaticUtils; import com.hwlcn.core.annotation.ThreadSafety; import com.hwlcn.ldap.util.ThreadSafetyLevel; import static com.hwlcn.ldap.ldap.sdk.LDAPMessages.*; /** * This class defines an object that provides information about a request that * was initiated asynchronously. It may be used to abandon or cancel the * associated request. This class also implements the * {@code java.util.concurrent.Future} interface, so it may be used in that * manner. * <BR><BR> * <H2>Example</H2> * The following example initiates an asynchronous modify operation and then * attempts to abandon it: * <PRE> * Modification mod = new Modification(ModificationType.REPLACE, * "description", "This is the new description."); * ModifyRequest modifyRequest = * new ModifyRequest("dc=example,dc=com", mod); * * AsyncRequestID asyncRequestID = * connection.asyncModify(modifyRequest, myAsyncResultListener); * * // Assume that we've waited a reasonable amount of time but the modify * // hasn't completed yet so we'll try to abandon it. * * connection.abandon(asyncRequestID); * </PRE> */ @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public final class AsyncRequestID implements Serializable, Future<LDAPResult> { private static final long serialVersionUID = 8244005138437962030L; private final ArrayBlockingQueue<LDAPResult> resultQueue; private final AtomicBoolean cancelRequested; private final AtomicReference<LDAPResult> result; private final int messageID; private final LDAPConnection connection; private volatile AsyncTimeoutTimerTask timerTask; AsyncRequestID(final int messageID, final LDAPConnection connection) { this.messageID = messageID; this.connection = connection; resultQueue = new ArrayBlockingQueue<LDAPResult>(1); cancelRequested = new AtomicBoolean(false); result = new AtomicReference<LDAPResult>(); timerTask = null; } public int getMessageID() { return messageID; } public boolean cancel(final boolean mayInterruptIfRunning) { if (isDone()) { return false; } try { cancelRequested.set(true); result.compareAndSet(null, new LDAPResult(messageID, ResultCode.USER_CANCELED, INFO_ASYNC_REQUEST_USER_CANCELED.get(), null, StaticUtils.NO_STRINGS, StaticUtils.NO_CONTROLS)); connection.abandon(this); } catch (final Exception e) { Debug.debugException(e); } return true; } public boolean isCancelled() { return cancelRequested.get(); } public boolean isDone() { if (cancelRequested.get()) { return true; } if (result.get() != null) { return true; } final LDAPResult newResult = resultQueue.poll(); if (newResult != null) { result.set(newResult); return true; } return false; } public LDAPResult get() throws InterruptedException { final long maxWaitTime = connection.getConnectionOptions().getResponseTimeoutMillis(); try { return get(maxWaitTime, TimeUnit.MILLISECONDS); } catch (final TimeoutException te) { Debug.debugException(te); return new LDAPResult(messageID, ResultCode.TIMEOUT, te.getMessage(), null, StaticUtils.NO_STRINGS, StaticUtils.NO_CONTROLS); } } public LDAPResult get(final long timeout, final TimeUnit timeUnit) throws InterruptedException, TimeoutException { final LDAPResult newResult = resultQueue.poll(); if (newResult != null) { result.set(newResult); return newResult; } final LDAPResult previousResult = result.get(); if (previousResult != null) { return previousResult; } final LDAPResult resultAfterWaiting = resultQueue.poll(timeout, timeUnit); if (resultAfterWaiting == null) { final long timeoutMillis = timeUnit.toMillis(timeout); throw new TimeoutException( WARN_ASYNC_REQUEST_GET_TIMEOUT.get(timeoutMillis)); } else { result.set(resultAfterWaiting); return resultAfterWaiting; } } void setTimerTask(final AsyncTimeoutTimerTask timerTask) { this.timerTask = timerTask; } void setResult(final LDAPResult result) { resultQueue.offer(result); final AsyncTimeoutTimerTask t = timerTask; if (t != null) { t.cancel(); connection.getTimer().purge(); timerTask = null; } } @Override() public int hashCode() { return messageID; } @Override() public boolean equals(final Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o instanceof AsyncRequestID) { return (((AsyncRequestID) o).messageID == messageID); } else { return false; } } @Override() public String toString() { return "AsyncRequestID(messageID=" + messageID + ')'; } }