package com.hwlcn.ldap.ldap.sdk.controls; import java.text.ParseException; import java.util.ArrayList; import java.util.UUID; import com.hwlcn.ldap.asn1.ASN1Element; import com.hwlcn.ldap.asn1.ASN1Enumerated; 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.ldap.ldap.sdk.SearchResultReference; import com.hwlcn.ldap.util.Debug; import com.hwlcn.core.annotation.NotMutable; import com.hwlcn.ldap.util.StaticUtils; 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.*; @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public final class ContentSyncStateControl extends Control implements DecodeableControl { public static final String SYNC_STATE_OID = "1.3.6.1.4.1.4203.1.9.1.2"; private static final long serialVersionUID = 4796325788870542241L; // The synchronization state cookie. private final ASN1OctetString cookie; // The synchronization state for the associated entry. private final ContentSyncState state; // The entryUUID value for the associated entry. private final UUID entryUUID; /** * Creates a new empty control instance that is intended to be used only for * decoding controls via the {@code DecodeableControl} interface. */ ContentSyncStateControl() { state = null; entryUUID = null; cookie = null; } /** * Creates a new content synchronization state control that provides * information about a search result entry or referenced returned by a search * containing the content synchronization request control. * * @param state The sync state for the associated entry or reference. * It must not be {@code null}. * @param entryUUID The entryUUID for the associated entry or reference. It * must not be {@code null}. * @param cookie A cookie with an updated synchronization state. It may * be {@code null} if no updated state is available. */ public ContentSyncStateControl(final ContentSyncState state, final UUID entryUUID, final ASN1OctetString cookie) { super(SYNC_STATE_OID, false, encodeValue(state, entryUUID, cookie)); this.state = state; this.entryUUID = entryUUID; this.cookie = cookie; } /** * Creates a new content synchronization state control which is decoded from * the provided information from a generic control. * * @param oid The OID for the control used to create this control. * @param isCritical Indicates whether the control is marked critical. * @param value The encoded value for the control. * * @throws LDAPException If the provided control cannot be decoded as a * content synchronization state control. */ public ContentSyncStateControl(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_SYNC_STATE_NO_VALUE.get()); } try { final ASN1Element[] elements = ASN1Sequence.decodeAsSequence(value.getValue()).elements(); final ASN1Enumerated e = ASN1Enumerated.decodeAsEnumerated(elements[0]); state = ContentSyncState.valueOf(e.intValue()); if (state == null) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_SYNC_STATE_VALUE_INVALID_STATE.get(e.intValue())); } try { entryUUID = StaticUtils.decodeUUID(elements[1].getValue()); } catch (final ParseException pe) { Debug.debugException(pe); throw new LDAPException(ResultCode.DECODING_ERROR, ERR_SYNC_STATE_VALUE_MALFORMED_UUID.get(pe.getMessage()), pe); } if (elements.length == 3) { cookie = ASN1OctetString.decodeAsOctetString(elements[2]); } else { cookie = null; } } catch (final LDAPException le) { throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.DECODING_ERROR, ERR_SYNC_STATE_VALUE_CANNOT_DECODE.get( StaticUtils.getExceptionMessage(e)), e); } } /** * Encodes the provided information into a form suitable for use as the value * of this control. * * @param state The sync state for the associated entry or reference. * It must not be {@code null}. * @param entryUUID The entryUUID for the associated entry or reference. It * must not be {@code null}. * @param cookie A cookie with an updated synchronization state. It may * be {@code null} if no updated state is available. * * @return An ASN.1 octet string containing the encoded control value. */ private static ASN1OctetString encodeValue(final ContentSyncState state, final UUID entryUUID, final ASN1OctetString cookie) { Validator.ensureNotNull(state, entryUUID); final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3); elements.add(new ASN1Enumerated(state.intValue())); elements.add(new ASN1OctetString(StaticUtils.encodeUUID(entryUUID))); if (cookie != null) { elements.add(cookie); } return new ASN1OctetString(new ASN1Sequence(elements).encode()); } /** * {@inheritDoc} */ public ContentSyncStateControl decodeControl(final String oid, final boolean isCritical, final ASN1OctetString value) throws LDAPException { return new ContentSyncStateControl(oid, isCritical, value); } /** * Extracts a content sync state control from the provided search result * entry. * * @param entry The search result entry from which to retrieve the content * sync state control. * * @return The content sync state control contained in the provided search * result entry, or {@code null} if the entry did not contain a * content sync state control. * * @throws LDAPException If a problem is encountered while attempting to * decode the content sync state control contained in * the provided search result entry. */ public static ContentSyncStateControl get(final SearchResultEntry entry) throws LDAPException { final Control c = entry.getControl(SYNC_STATE_OID); if (c == null) { return null; } if (c instanceof ContentSyncStateControl) { return (ContentSyncStateControl) c; } else { return new ContentSyncStateControl(c.getOID(), c.isCritical(), c.getValue()); } } /** * Extracts a content sync state control from the provided search result * reference. * * @param ref The search result reference from which to retrieve the content * sync state control. * * @return The content sync state control contained in the provided search * result reference, or {@code null} if the reference did not contain * a content sync state control. * * @throws LDAPException If a problem is encountered while attempting to * decode the content sync state control contained in * the provided search result reference. */ public static ContentSyncStateControl get(final SearchResultReference ref) throws LDAPException { final Control c = ref.getControl(SYNC_STATE_OID); if (c == null) { return null; } if (c instanceof ContentSyncStateControl) { return (ContentSyncStateControl) c; } else { return new ContentSyncStateControl(c.getOID(), c.isCritical(), c.getValue()); } } /** * Retrieves the synchronization state for this control, which provides * information about the state of the associated search result entry or * reference. * * @return The state value for this content synchronization state control. */ public ContentSyncState getState() { return state; } /** * Retrieves the entryUUID for the associated search result entry or * reference. * * @return The entryUUID for the associated search result entry or * reference. */ public UUID getEntryUUID() { return entryUUID; } /** * Retrieves a cookie providing updated state information for the * synchronization session, if available. * * @return A cookie providing updated state information for the * synchronization session, or {@code null} if none was included in * the control. */ public ASN1OctetString getCookie() { return cookie; } /** * {@inheritDoc} */ @Override() public String getControlName() { return INFO_CONTROL_NAME_CONTENT_SYNC_STATE.get(); } /** * {@inheritDoc} */ @Override() public void toString(final StringBuilder buffer) { buffer.append("ContentSyncStateControl(state='"); buffer.append(state.name()); buffer.append("', entryUUID='"); buffer.append(entryUUID); buffer.append('\''); if (cookie != null) { buffer.append(", cookie="); StaticUtils.toHex(cookie.getValue(), buffer); } buffer.append(')'); } }