package com.hwlcn.ldap.ldap.sdk.controls;
import java.util.ArrayList;
import com.hwlcn.ldap.asn1.ASN1Constants;
import com.hwlcn.ldap.asn1.ASN1Element;
import com.hwlcn.ldap.asn1.ASN1Enumerated;
import com.hwlcn.ldap.asn1.ASN1Exception;
import com.hwlcn.ldap.asn1.ASN1Long;
import com.hwlcn.ldap.asn1.ASN1OctetString;
import com.hwlcn.ldap.asn1.ASN1Sequence;
import com.hwlcn.ldap.ldap.sdk.Control;
import com.hwlcn.ldap.ldap.sdk.DecodeableControl;
import com.hwlcn.ldap.ldap.sdk.LDAPException;
import com.hwlcn.ldap.ldap.sdk.ResultCode;
import com.hwlcn.ldap.ldap.sdk.SearchResultEntry;
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.controls.ControlMessages.*;
import static com.hwlcn.ldap.util.Debug.*;
import static com.hwlcn.ldap.util.StaticUtils.*;
import static com.hwlcn.ldap.util.Validator.*;
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class EntryChangeNotificationControl
extends Control
implements DecodeableControl
{
public static final String ENTRY_CHANGE_NOTIFICATION_OID =
"2.16.840.1.113730.3.4.7";
private static final long serialVersionUID = -1305357948140939303L;
private final long changeNumber;
private final PersistentSearchChangeType changeType;
private final String previousDN;
EntryChangeNotificationControl()
{
changeNumber = -1;
changeType = null;
previousDN = null;
}
public EntryChangeNotificationControl(
final PersistentSearchChangeType changeType,
final String previousDN, final long changeNumber)
{
this(changeType, previousDN, changeNumber, false);
}
public EntryChangeNotificationControl(
final PersistentSearchChangeType changeType,
final String previousDN, final long changeNumber,
final boolean isCritical)
{
super(ENTRY_CHANGE_NOTIFICATION_OID, isCritical,
encodeValue(changeType, previousDN, changeNumber));
this.changeType = changeType;
this.previousDN = previousDN;
this.changeNumber = changeNumber;
}
public EntryChangeNotificationControl(final String oid,
final boolean isCritical,
final ASN1OctetString value)
throws LDAPException
{
super(oid, isCritical, value);
if (value == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_NO_VALUE.get());
}
final ASN1Sequence ecnSequence;
try
{
final ASN1Element element = ASN1Element.decode(value.getValue());
ecnSequence = ASN1Sequence.decodeAsSequence(element);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_VALUE_NOT_SEQUENCE.get(ae), ae);
}
final ASN1Element[] ecnElements = ecnSequence.elements();
if ((ecnElements.length < 1) || (ecnElements.length > 3))
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_INVALID_ELEMENT_COUNT.get(
ecnElements.length));
}
final ASN1Enumerated ecnEnumerated;
try
{
ecnEnumerated = ASN1Enumerated.decodeAsEnumerated(ecnElements[0]);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_FIRST_NOT_ENUMERATED.get(ae), ae);
}
changeType = PersistentSearchChangeType.valueOf(ecnEnumerated.intValue());
if (changeType == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_INVALID_CHANGE_TYPE.get(
ecnEnumerated.intValue()));
}
String prevDN = null;
long chgNum = -1;
for (int i=1; i < ecnElements.length; i++)
{
switch (ecnElements[i].getType())
{
case ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE:
prevDN = ASN1OctetString.decodeAsOctetString(
ecnElements[i]).stringValue();
break;
case ASN1Constants.UNIVERSAL_INTEGER_TYPE:
try
{
chgNum = ASN1Long.decodeAsLong(ecnElements[i]).longValue();
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_CANNOT_DECODE_CHANGE_NUMBER.get(ae),
ae);
}
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_ECN_INVALID_ELEMENT_TYPE.get(
toHex(ecnElements[i].getType())));
}
}
previousDN = prevDN;
changeNumber = chgNum;
}
public EntryChangeNotificationControl
decodeControl(final String oid, final boolean isCritical,
final ASN1OctetString value)
throws LDAPException
{
return new EntryChangeNotificationControl(oid, isCritical, value);
}
public static EntryChangeNotificationControl
get(final SearchResultEntry entry)
throws LDAPException
{
final Control c = entry.getControl(ENTRY_CHANGE_NOTIFICATION_OID);
if (c == null)
{
return null;
}
if (c instanceof EntryChangeNotificationControl)
{
return (EntryChangeNotificationControl) c;
}
else
{
return new EntryChangeNotificationControl(c.getOID(), c.isCritical(),
c.getValue());
}
}
private static ASN1OctetString encodeValue(
final PersistentSearchChangeType changeType,
final String previousDN, final long changeNumber)
{
ensureNotNull(changeType);
final ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3);
elementList.add(new ASN1Enumerated(changeType.intValue()));
if (previousDN != null)
{
elementList.add(new ASN1OctetString(previousDN));
}
if (changeNumber > 0)
{
elementList.add(new ASN1Long(changeNumber));
}
return new ASN1OctetString(new ASN1Sequence(elementList).encode());
}
public PersistentSearchChangeType getChangeType()
{
return changeType;
}
public String getPreviousDN()
{
return previousDN;
}
public long getChangeNumber()
{
return changeNumber;
}
@Override()
public String getControlName()
{
return INFO_CONTROL_NAME_ENTRY_CHANGE_NOTIFICATION.get();
}
@Override()
public void toString(final StringBuilder buffer)
{
buffer.append("EntryChangeNotificationControl(changeType=");
buffer.append(changeType.getName());
if (previousDN != null)
{
buffer.append(", previousDN='");
buffer.append(previousDN);
buffer.append('\'');
}
if (changeNumber > 0)
{
buffer.append(", changeNumber=");
buffer.append(changeNumber);
}
buffer.append(", isCritical=");
buffer.append(isCritical());
buffer.append(')');
}
}