package com.hwlcn.ldap.ldap.sdk.extensions;
import com.hwlcn.ldap.asn1.ASN1Element;
import com.hwlcn.ldap.asn1.ASN1Integer;
import com.hwlcn.ldap.asn1.ASN1OctetString;
import com.hwlcn.ldap.asn1.ASN1Sequence;
import com.hwlcn.ldap.ldap.sdk.AsyncRequestID;
import com.hwlcn.ldap.ldap.sdk.Control;
import com.hwlcn.ldap.ldap.sdk.ExtendedRequest;
import com.hwlcn.ldap.ldap.sdk.ExtendedResult;
import com.hwlcn.ldap.ldap.sdk.LDAPConnection;
import com.hwlcn.ldap.ldap.sdk.LDAPException;
import com.hwlcn.ldap.ldap.sdk.ResultCode;
import com.hwlcn.core.annotation.NotMutable;
import com.hwlcn.core.annotation.ThreadSafety;
import com.hwlcn.ldap.util.ThreadSafetyLevel;
import static com.hwlcn.ldap.ldap.sdk.extensions.ExtOpMessages.*;
import static com.hwlcn.ldap.util.Debug.*;
/**
* This class provides an implementation of the LDAP cancel extended request as
* defined in <A HREF="http://www.ietf.org/rfc/rfc3909.txt">RFC 3909</A>. It
* may be used to request that the server interrupt processing on another
* operation in progress on the same connection. It behaves much like the
* abandon operation, with the exception that both the cancel request and the
* operation that is canceled will receive responses, whereas an abandon request
* never returns a response, and the operation that is abandoned will also not
* receive a response if the abandon is successful.
* <BR><BR>
* <H2>Example</H2>
* The following example initiates an asynchronous modify operation and then
* attempts to cancel 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 cancel it.
*
* CancelExtendedRequest cancelRequest =
* new CancelExtendedRequest(asyncRequestID);
*
* // NOTE: The processExtendedOperation method will only throw an exception
* // if a problem occurs while trying to send the request or read the
* // response. It will not throw an exception because of a non-success
* // response. That's good for us in this case because the cancel result
* // should never be "SUCCESS".
* ExtendedResult cancelResult =
* connection.processExtendedOperation(cancelRequest);
* switch (cancelResult.getResultCode())
* {
* case ResultCode.CANCELED:
* System.out.println("The operation was successfully canceled.");
* break;
* case ResultCode.NO_SUCH_OPERATION:
* System.out.println("The server didn't know anything about the " +
* "operation. Maybe it's already completed.");
* break;
* case ResultCode.TOO_LATE:
* System.out.println("It was too late in the operation processing " +
* "to cancel the operation.");
* break;
* case ResultCode.CANNOT_CANCEL:
* System.out.println("The target operation is not one that could be " +
* "canceled.");
* break;
* default:
* System.err.println("An error occurred while processing the cancel " +
* "request.");
* break;
* }
* </PRE>
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class CancelExtendedRequest
extends ExtendedRequest
{
public static final String CANCEL_REQUEST_OID = "1.3.6.1.1.8";
private static final long serialVersionUID = -7170687636394194183L;
private final int targetMessageID;
public CancelExtendedRequest(final AsyncRequestID requestID)
{
this(requestID.getMessageID(), null);
}
public CancelExtendedRequest(final int targetMessageID)
{
this(targetMessageID, null);
}
public CancelExtendedRequest(final AsyncRequestID requestID,
final Control[] controls)
{
this(requestID.getMessageID(), controls);
}
public CancelExtendedRequest(final int targetMessageID,
final Control[] controls)
{
super(CANCEL_REQUEST_OID, encodeValue(targetMessageID), controls);
this.targetMessageID = targetMessageID;
}
public CancelExtendedRequest(final ExtendedRequest extendedRequest)
throws LDAPException
{
super(extendedRequest);
final ASN1OctetString value = extendedRequest.getValue();
if (value == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CANCEL_REQUEST_NO_VALUE.get());
}
try
{
final ASN1Element valueElement = ASN1Element.decode(value.getValue());
final ASN1Element[] elements =
ASN1Sequence.decodeAsSequence(valueElement).elements();
targetMessageID = ASN1Integer.decodeAsInteger(elements[0]).intValue();
}
catch (Exception e)
{
debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CANCEL_REQUEST_CANNOT_DECODE.get(e), e);
}
}
private static ASN1OctetString encodeValue(final int targetMessageID)
{
final ASN1Element[] sequenceValues =
{
new ASN1Integer(targetMessageID)
};
return new ASN1OctetString(new ASN1Sequence(sequenceValues).encode());
}
@Override()
protected ExtendedResult process(final LDAPConnection connection,
final int depth)
throws LDAPException
{
if (connection.synchronousMode())
{
throw new LDAPException(ResultCode.NOT_SUPPORTED,
ERR_CANCEL_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
}
return super.process(connection, depth);
}
public int getTargetMessageID()
{
return targetMessageID;
}
@Override()
public CancelExtendedRequest duplicate()
{
return duplicate(getControls());
}
@Override()
public CancelExtendedRequest duplicate(final Control[] controls)
{
final CancelExtendedRequest cancelRequest =
new CancelExtendedRequest(targetMessageID, controls);
cancelRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
return cancelRequest;
}
@Override()
public String getExtendedRequestName()
{
return INFO_EXTENDED_REQUEST_NAME_CANCEL.get();
}
@Override()
public void toString(final StringBuilder buffer)
{
buffer.append("CancelExtendedRequest(targetMessageID=");
buffer.append(targetMessageID);
final Control[] controls = getControls();
if (controls.length > 0)
{
buffer.append(", controls={");
for (int i=0; i < controls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(controls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}