001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2016 ForgeRock AS.
015 */
016package org.forgerock.opendj.ldap.controls;
017
018import org.forgerock.opendj.ldap.ByteString;
019
020/**
021 * The persistent search request control for Active Directory as defined by
022 * Microsoft. This control allows a client to receive notification of changes
023 * that occur in an Active Directory server.
024 * <br/>
025 *
026 * <pre>
027 * Connection connection = ...;
028 *
029 * SearchRequest request =
030 *         Requests.newSearchRequest("dc=example,dc=com",
031 *                 SearchScope.WHOLE_SUBTREE, "(objectclass=*)", "cn",
032 *                 "isDeleted", "whenChanged", "whenCreated").addControl(
033 *                 ADNotificationRequestControl.newControl(true));
034 *
035 * ConnectionEntryReader reader = connection.search(request);
036 *
037 * while (reader.hasNext()) {
038 *     if (!reader.isReference()) {
039 *         SearchResultEntry entry = reader.readEntry(); // Entry that changed
040 *
041 *         Boolean isDeleted = entry.parseAttribute("isDeleted").asBoolean();
042 *         if (isDeleted != null && isDeleted) {
043 *             // Handle entry deletion
044 *         }
045 *         String whenCreated = entry.parseAttribute("whenCreated").asString();
046 *         String whenChanged = entry.parseAttribute("whenChanged").asString();
047 *         if (whenCreated != null && whenChanged != null) {
048 *             if (whenCreated.equals(whenChanged)) {
049 *                 //Handle entry addition
050 *             } else {
051 *                 //Handle entry modification
052 *             }
053 *         }
054 *     } else {
055 *         reader.readReference(); //read and ignore reference
056 *     }
057 * }
058 *
059 * </pre>
060 *
061 * @see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa772153(v=vs.85).aspx">
062 *      Change Notifications in Active Directory Domain Services</a>
063 */
064public final class ADNotificationRequestControl implements Control {
065
066    /**
067     * The OID for the Microsoft Active Directory persistent search request
068     * control. The control itself is empty and the changes are returned as
069     * attributes, such as "isDeleted", "whenChanged", "whenCreated".
070     */
071    public static final String OID = "1.2.840.113556.1.4.528";
072
073    /**
074     * The name of the isDeleted attribute as defined in the Active Directory
075     * schema. If the value of the attribute is <code>TRUE</code>, the object
076     * has been marked for deletion.
077     */
078    public static final String IS_DELETED_ATTR = "isDeleted";
079
080    /**
081     * The name of the whenCreated attribute as defined in the Active Directory
082     * schema. Holds the date of the creation of the object in GeneralizedTime
083     * format.
084     */
085    public static final String WHEN_CREATED_ATTR = "whenCreated";
086
087    /**
088     * The name of the whenChanged attribute as defined in the Active Directory
089     * schema. Holds the date of the last modification of the object in
090     * GeneralizedTime format.
091     */
092    public static final String WHEN_CHANGED_ATTR = "whenChanged";
093
094    /**
095     * The name of the objectGUID attribute as defined in the Active Directory
096     * schema. This is the unique identifier of an object stored in binary
097     * format.
098     */
099    public static final String OBJECT_GUID_ATTR = "objectGUID";
100
101    /**
102     * The name of the uSNChanged attribute as defined in the Active Directory
103     * schema. This attribute can be used to determine whether the current
104     * state of the object on the server reflects the latest changes that the
105     * client has received.
106     */
107    public static final String USN_CHANGED_ATTR = "uSNChanged";
108
109    private final boolean isCritical;
110
111    private ADNotificationRequestControl(final boolean isCritical) {
112        this.isCritical = isCritical;
113    }
114
115    /**
116     * Creates a new Active Directory change notification request control.
117     *
118     * @param isCritical
119     *            {@code true} if it is unacceptable to perform the operation
120     *            without applying the semantics of this control, or
121     *            {@code false} if it can be ignored
122     * @return The new control.
123     */
124    public static ADNotificationRequestControl newControl(final boolean isCritical) {
125        return new ADNotificationRequestControl(isCritical);
126    }
127
128    @Override
129    public String getOID() {
130        return OID;
131    }
132
133    @Override
134    public ByteString getValue() {
135        return null;
136    }
137
138    @Override
139    public boolean hasValue() {
140        return false;
141    }
142
143    @Override
144    public boolean isCritical() {
145        return isCritical;
146    }
147
148    @Override
149    public String toString() {
150        final StringBuilder builder = new StringBuilder();
151        builder.append("ADNotificationRequestControl(oid=");
152        builder.append(getOID());
153        builder.append(", criticality=");
154        builder.append(isCritical());
155        builder.append(")");
156        return builder.toString();
157    }
158}