package com.hwlcn.ldap.ldap.sdk.controls; import java.util.ArrayList; import java.util.Collection; import com.hwlcn.ldap.asn1.ASN1Element; import com.hwlcn.ldap.asn1.ASN1OctetString; import com.hwlcn.ldap.ldap.sdk.Attribute; import com.hwlcn.ldap.ldap.sdk.Control; import com.hwlcn.ldap.ldap.sdk.Entry; import com.hwlcn.ldap.ldap.sdk.Filter; 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 com.hwlcn.ldap.util.Validator; import static com.hwlcn.ldap.ldap.sdk.controls.ControlMessages.*; import static com.hwlcn.ldap.util.Debug.*; /** * This class provides an implementation of the LDAP assertion request control * as defined in <A HREF="http://www.ietf.org/rfc/rfc4528.txt">RFC 4528</A>. It * may be used in conjunction with an add, compare, delete, modify, modify DN, * or search operation. The assertion control includes a search filter, and the * associated operation should only be allowed to continue if the target entry * matches the provided filter. If the filter does not match the target entry, * then the operation should fail with an * {@link ResultCode#ASSERTION_FAILED} result. * <BR><BR> * The behavior of the assertion request control makes it ideal for atomic * "check and set" types of operations, particularly when modifying an entry. * For example, it can be used to ensure that when changing the value of an * attribute, the current value has not been modified since it was last * retrieved. * <BR><BR> * <H2>Example</H2> * The following example demonstrates the use of the assertion request control. * It shows an attempt to modify an entry's "accountBalance" attribute to set * the value to "543.21" only if the current value is "1234.56": * <PRE> * Modification mod = new Modification(ModificationType.REPLACE, * "accountBalance", "543.21"); * ModifyRequest modifyRequest = * new ModifyRequest("uid=john.doe,ou=People,dc=example,dc=com", mod); * modifyRequest.addControl( * new AssertionRequestControl("(accountBalance=1234.56)")); * * try * { * LDAPResult modifyResult = connection.modify(modifyRequest); * // If we've gotten here, then the modification was successful. * } * catch (LDAPException le) * { * if (le.getResultCode() == ResultCode.ASSERTION_FAILED) * { * The modification failed because the accountBalance value wasn't what * we thought it was. * } * else * { * The modification failed for some other reason. * } * } * </PRE> */ @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public final class AssertionRequestControl extends Control { public static final String ASSERTION_REQUEST_OID = "1.3.6.1.1.12"; private static final long serialVersionUID = 6592634203410511095L; private final Filter filter; public AssertionRequestControl(final String filter) throws LDAPException { this(Filter.create(filter), true); } public AssertionRequestControl(final Filter filter) { this(filter, true); } public AssertionRequestControl(final String filter, final boolean isCritical) throws LDAPException { this(Filter.create(filter), isCritical); } public AssertionRequestControl(final Filter filter, final boolean isCritical) { super(ASSERTION_REQUEST_OID, isCritical, encodeValue(filter)); this.filter = filter; } public AssertionRequestControl(final Control control) throws LDAPException { super(control); final ASN1OctetString value = control.getValue(); if (value == null) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_ASSERT_NO_VALUE.get()); } try { final ASN1Element valueElement = ASN1Element.decode(value.getValue()); filter = Filter.decode(valueElement); } catch (Exception e) { debugException(e); throw new LDAPException(ResultCode.DECODING_ERROR, ERR_ASSERT_CANNOT_DECODE.get(e), e); } } public static AssertionRequestControl generate(final Entry sourceEntry, final String... attributes) { Validator.ensureNotNull(sourceEntry); final ArrayList<Filter> andComponents; if ((attributes == null) || (attributes.length == 0)) { final Collection<Attribute> entryAttrs = sourceEntry.getAttributes(); andComponents = new ArrayList<Filter>(entryAttrs.size()); for (final Attribute a : entryAttrs) { for (final ASN1OctetString v : a.getRawValues()) { andComponents.add(Filter.createEqualityFilter(a.getName(), v.getValue())); } } } else { andComponents = new ArrayList<Filter>(attributes.length); for (final String name : attributes) { final Attribute a = sourceEntry.getAttribute(name); if (a != null) { for (final ASN1OctetString v : a.getRawValues()) { andComponents.add(Filter.createEqualityFilter(name, v.getValue())); } } } } if (andComponents.size() == 1) { return new AssertionRequestControl(andComponents.get(0)); } else { return new AssertionRequestControl(Filter.createANDFilter(andComponents)); } } private static ASN1OctetString encodeValue(final Filter filter) { return new ASN1OctetString(filter.encode().encode()); } public Filter getFilter() { return filter; } @Override() public String getControlName() { return INFO_CONTROL_NAME_ASSERTION_REQUEST.get(); } @Override() public void toString(final StringBuilder buffer) { buffer.append("AssertionRequestControl(filter='"); filter.toString(buffer); buffer.append("', isCritical="); buffer.append(isCritical()); buffer.append(')'); } }