package com.hwlcn.ldap.ldap.sdk;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import com.hwlcn.ldap.asn1.ASN1Boolean;
import com.hwlcn.ldap.asn1.ASN1Buffer;
import com.hwlcn.ldap.asn1.ASN1BufferSequence;
import com.hwlcn.ldap.asn1.ASN1Element;
import com.hwlcn.ldap.asn1.ASN1Exception;
import com.hwlcn.ldap.asn1.ASN1OctetString;
import com.hwlcn.ldap.asn1.ASN1Sequence;
import com.hwlcn.ldap.asn1.ASN1StreamReader;
import com.hwlcn.ldap.asn1.ASN1StreamReaderSequence;
import com.hwlcn.core.annotation.Extensible;
import com.hwlcn.core.annotation.NotMutable;
import com.hwlcn.core.annotation.ThreadSafety;
import com.hwlcn.ldap.util.ThreadSafetyLevel;
import static com.hwlcn.ldap.asn1.ASN1Constants.*;
import static com.hwlcn.ldap.ldap.sdk.LDAPMessages.*;
import static com.hwlcn.ldap.util.Debug.*;
import static com.hwlcn.ldap.util.StaticUtils.*;
import static com.hwlcn.ldap.util.Validator.*;
@Extensible()
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public class Control
implements Serializable
{
private static final byte CONTROLS_TYPE = (byte) 0xA0;
private static final ConcurrentHashMap<String,DecodeableControl>
decodeableControlMap = new ConcurrentHashMap<String,DecodeableControl>();
private static final long serialVersionUID = 4440956109070220054L;
private final ASN1OctetString value;
private final boolean isCritical;
private final String oid;
static
{
try
{
final Class<?> unboundIDControlHelperClass = Class.forName(
"com.hwlcn.ldap.ldap.sdk.controls.ControlHelper");
final Method method = unboundIDControlHelperClass.getMethod(
"registerDefaultResponseControls");
method.invoke(null);
}
catch (Exception e)
{
}
try
{
final Class<?> unboundIDControlHelperClass = Class.forName(
"com.hwlcn.ldap.ldap.sdk.experimental.ControlHelper");
final Method method = unboundIDControlHelperClass.getMethod(
"registerDefaultResponseControls");
method.invoke(null);
}
catch (Exception e)
{
}
try
{
final Class<?> unboundIDControlHelperClass = Class.forName(
"com.hwlcn.ldap.ldap.sdk.unboundidds.controls.ControlHelper");
final Method method = unboundIDControlHelperClass.getMethod(
"registerDefaultResponseControls");
method.invoke(null);
}
catch (Exception e)
{
try
{
final Class<?> experimentalControlHelperClass = Class.forName(
"com.hwlcn.ldap.ldap.sdk.experimental.ControlHelper");
final Method method = experimentalControlHelperClass.getMethod(
"registerNonCommercialResponseControls");
method.invoke(null);
}
catch (Exception e2)
{
}
}
}
protected Control()
{
oid = null;
isCritical = true;
value = null;
}
protected Control(final Control control)
{
oid = control.oid;
isCritical = control.isCritical;
value = control.value;
}
public Control(final String oid)
{
ensureNotNull(oid);
this.oid = oid;
isCritical = false;
value = null;
}
public Control(final String oid, final boolean isCritical)
{
ensureNotNull(oid);
this.oid = oid;
this.isCritical = isCritical;
value = null;
}
public Control(final String oid, final boolean isCritical,
final ASN1OctetString value)
{
ensureNotNull(oid);
this.oid = oid;
this.isCritical = isCritical;
this.value = value;
}
public final String getOID()
{
return oid;
}
public final boolean isCritical()
{
return isCritical;
}
public final boolean hasValue()
{
return (value != null);
}
public final ASN1OctetString getValue()
{
return value;
}
public final void writeTo(final ASN1Buffer writer)
{
final ASN1BufferSequence controlSequence = writer.beginSequence();
writer.addOctetString(oid);
if (isCritical)
{
writer.addBoolean(true);
}
if (value != null)
{
writer.addOctetString(value.getValue());
}
controlSequence.end();
}
public final ASN1Sequence encode()
{
final ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3);
elementList.add(new ASN1OctetString(oid));
if (isCritical)
{
elementList.add(new ASN1Boolean(isCritical));
}
if (value != null)
{
elementList.add(new ASN1OctetString(value.getValue()));
}
return new ASN1Sequence(elementList);
}
public static Control readFrom(final ASN1StreamReader reader)
throws LDAPException
{
try
{
final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
final String oid = reader.readString();
boolean isCritical = false;
ASN1OctetString value = null;
while (controlSequence.hasMoreElements())
{
final byte type = (byte) reader.peek();
switch (type)
{
case UNIVERSAL_BOOLEAN_TYPE:
isCritical = reader.readBoolean();
break;
case UNIVERSAL_OCTET_STRING_TYPE:
value = new ASN1OctetString(reader.readBytes());
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_INVALID_TYPE.get(toHex(type)));
}
}
return decode(oid, isCritical, value);
}
catch (LDAPException le)
{
debugException(le);
throw le;
}
catch (Exception e)
{
debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_CANNOT_DECODE.get(getExceptionMessage(e)), e);
}
}
public static Control decode(final ASN1Sequence controlSequence)
throws LDAPException
{
final ASN1Element[] elements = controlSequence.elements();
if ((elements.length < 1) || (elements.length > 3))
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_DECODE_INVALID_ELEMENT_COUNT.get(
elements.length));
}
final String oid =
ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
boolean isCritical = false;
ASN1OctetString value = null;
if (elements.length == 2)
{
switch (elements[1].getType())
{
case UNIVERSAL_BOOLEAN_TYPE:
try
{
isCritical =
ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
}
catch (ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_DECODE_CRITICALITY.get(getExceptionMessage(ae)),
ae);
}
break;
case UNIVERSAL_OCTET_STRING_TYPE:
value = ASN1OctetString.decodeAsOctetString(elements[1]);
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_INVALID_TYPE.get(
toHex(elements[1].getType())));
}
}
else if (elements.length == 3)
{
try
{
isCritical = ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
}
catch (ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROL_DECODE_CRITICALITY.get(getExceptionMessage(ae)), ae);
}
value = ASN1OctetString.decodeAsOctetString(elements[2]);
}
return decode(oid, isCritical, value);
}
public static Control decode(final String oid, final boolean isCritical,
final ASN1OctetString value)
throws LDAPException
{
final DecodeableControl decodeableControl = decodeableControlMap.get(oid);
if (decodeableControl == null)
{
return new Control(oid, isCritical, value);
}
else
{
try
{
return decodeableControl.decodeControl(oid, isCritical, value);
}
catch (Exception e)
{
debugException(e);
return new Control(oid, isCritical, value);
}
}
}
public static ASN1Sequence encodeControls(final Control[] controls)
{
final ASN1Sequence[] controlElements = new ASN1Sequence[controls.length];
for (int i=0; i < controls.length; i++)
{
controlElements[i] = controls[i].encode();
}
return new ASN1Sequence(CONTROLS_TYPE, controlElements);
}
public static Control[] decodeControls(final ASN1Sequence controlSequence)
throws LDAPException
{
final ASN1Element[] controlElements = controlSequence.elements();
final Control[] controls = new Control[controlElements.length];
for (int i=0; i < controlElements.length; i++)
{
try
{
controls[i] = decode(ASN1Sequence.decodeAsSequence(controlElements[i]));
}
catch (ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_CONTROLS_DECODE_ELEMENT_NOT_SEQUENCE.get(
getExceptionMessage(ae)),
ae);
}
}
return controls;
}
public static void registerDecodeableControl(final String oid,
final DecodeableControl controlInstance)
{
decodeableControlMap.put(oid, controlInstance);
}
public static void deregisterDecodeableControl(final String oid)
{
decodeableControlMap.remove(oid);
}
@Override()
public final int hashCode()
{
int hashCode = oid.hashCode();
if (isCritical)
{
hashCode++;
}
if (value != null)
{
hashCode += value.hashCode();
}
return hashCode;
}
@Override()
public final boolean equals(final Object o)
{
if (o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (! (o instanceof Control))
{
return false;
}
final Control c = (Control) o;
if (! oid.equals(c.oid))
{
return false;
}
if (isCritical != c.isCritical)
{
return false;
}
if (value == null)
{
if (c.value != null)
{
return false;
}
}
else
{
if (c.value == null)
{
return false;
}
if (! value.equals(c.value))
{
return false;
}
}
return true;
}
public String getControlName()
{
return oid;
}
@Override()
public String toString()
{
final StringBuilder buffer = new StringBuilder();
toString(buffer);
return buffer.toString();
}
public void toString(final StringBuilder buffer)
{
buffer.append("Control(oid=");
buffer.append(oid);
buffer.append(", isCritical=");
buffer.append(isCritical);
buffer.append(", value=");
if (value == null)
{
buffer.append("{null}");
}
else
{
buffer.append("{byte[");
buffer.append(value.getValue().length);
buffer.append("]}");
}
buffer.append(')');
}
}