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