/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.tools.ldapdecoder.protocol;
import java.util.ArrayList;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1Enumerated;
import com.slamd.asn1.ASN1Integer;
import com.slamd.asn1.ASN1OctetString;
import com.slamd.asn1.ASN1Sequence;
/**
* This class defines the entry change notification control, which may be used
* in conjunction with the persistent search control to provide details on the
* type of change that occurred with an entry.
*
*
* @author Neil A. Wilson
*/
public class EntryChangeNotificationControl
extends LDAPControl
{
/**
* The OID of the entry change notification control.
*/
public static final String ENTRY_CHANGE_NOTIFICATION_CONTROL_OID =
"2.16.840.1.113730.3.4.7";
// The change number associated with this change, if applicable.
private int changeNumber;
// The type of change that occurred to the entry.
private int changeType;
// The previous DN for this entry if the change was a modify DN.
private String previousDN;
/**
* Creates a new entry change notification control.
*
* @param isCritical Indicates whether this control should be marked
* critical.
* @param changeType The type of change that occurred to the entry.
* @param previousDN The previous DN of the entry if the change was a
* modify DN operation.
* @param changeNumber The change number associated with this change, if
* applicable. A negative value should be used to
* indicate that no change number is available.
*/
public EntryChangeNotificationControl(boolean isCritical, int changeType,
String previousDN, int changeNumber)
{
super(ENTRY_CHANGE_NOTIFICATION_CONTROL_OID, isCritical,
encodeValue(changeType, previousDN, changeNumber));
this.changeType = changeType;
this.previousDN = previousDN;
this.changeNumber = changeNumber;
}
/**
* Creates a new entry change notification control by decoding the provided
* value.
*
* @param isCritical Indicates whether this control should be marked
* critical.
* @param controlValue The encoded value for this control.
*
* @throws ProtocolException If a problem occurs while decoding the control
* value.
*/
public EntryChangeNotificationControl(boolean isCritical,
ASN1OctetString controlValue)
throws ProtocolException
{
super(ENTRY_CHANGE_NOTIFICATION_CONTROL_OID, isCritical, controlValue);
ASN1Element[] sequenceElements;
try
{
sequenceElements =
ASN1Element.decodeAsSequence(controlValue.getValue()).getElements();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode entry change " +
"notification control value sequence", e);
}
if ((sequenceElements.length < 1) || (sequenceElements.length > 3))
{
throw new ProtocolException("There must be between 1 and 3 elements in " +
"an entry change notification value " +
"sequence");
}
try
{
changeType = sequenceElements[0].decodeAsEnumerated().getIntValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode change type from " +
"entry change notification control", e);
}
previousDN = null;
changeNumber = -1;
if (changeType == PersistentSearchControl.CHANGE_TYPE_MODIFY_DN)
{
try
{
previousDN = sequenceElements[1].decodeAsOctetString().getStringValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode previous DN from " +
"entry change notification control", e);
}
if (sequenceElements.length == 3)
{
try
{
changeNumber = sequenceElements[2].decodeAsInteger().getIntValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode change number from " +
"entry change notification control", e);
}
}
}
else
{
if (sequenceElements.length == 2)
{
try
{
changeNumber = sequenceElements[1].decodeAsInteger().getIntValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode change number from " +
"entry change notification control", e);
}
}
}
}
/**
* Encodes the provided information into an octet string suitable for use as
* the value of this control.
*
* @param changeType The type of change that occurred to the entry.
* @param previousDN The previous DN of the entry if the change was a
* modify DN operation.
* @param changeNumber The change number associated with this change, if
* applicable.
*
* @return An octet string containing the encoded control value.
*/
public static ASN1OctetString encodeValue(int changeType, String previousDN,
int changeNumber)
{
ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3);
elementList.add(new ASN1Enumerated(changeType));
if (changeType == PersistentSearchControl.CHANGE_TYPE_MODIFY_DN)
{
elementList.add(new ASN1OctetString(previousDN));
}
if (changeNumber >= 0)
{
elementList.add(new ASN1Integer(changeNumber));
}
ASN1Element[] sequenceElements = new ASN1Element[elementList.size()];
elementList.toArray(sequenceElements);
ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
return new ASN1OctetString(valueSequence.encode());
}
/**
* Retrieves a string representation of this control with the specified
* indent.
*
* @param indent The number of spaces to indent the output.
*
* @return A string representation of this control with the specified indent.
*/
public String toString(int indent)
{
StringBuilder indentBuf = new StringBuilder(indent);
for (int i=0; i < indent; i++)
{
indentBuf.append(' ');
}
StringBuilder buffer = new StringBuilder();
buffer.append(indentBuf).append("LDAP Entry Change Notification Control").
append(LDAPMessage.EOL);
buffer.append(indentBuf).append(" OID: ").append(getControlOID()).
append(LDAPMessage.EOL);
buffer.append(indentBuf).append(" Criticality: ").
append(isCritical()).append(LDAPMessage.EOL);
String changeTypeStr;
switch (changeType)
{
case PersistentSearchControl.CHANGE_TYPE_ADD:
changeTypeStr = "add";
break;
case PersistentSearchControl.CHANGE_TYPE_DELETE:
changeTypeStr = "delete";
break;
case PersistentSearchControl.CHANGE_TYPE_MODIFY:
changeTypeStr = "modify";
break;
case PersistentSearchControl.CHANGE_TYPE_MODIFY_DN:
changeTypeStr = "modify DN";
break;
default:
changeTypeStr = "invalid change type (" + changeType + ')';
break;
}
buffer.append(indentBuf).append(" Change Type: ").
append(changeType).append(" (").append(changeTypeStr).append(')').
append(LDAPMessage.EOL);
if (changeType == PersistentSearchControl.CHANGE_TYPE_MODIFY_DN)
{
buffer.append(indentBuf).append(" Previous DN: ").append(previousDN).
append(LDAPMessage.EOL);
}
if (changeNumber >= 0)
{
buffer.append(indentBuf).append(" Change Number: ").
append(changeNumber).append(LDAPMessage.EOL);
}
return buffer.toString();
}
}