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 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.controls; 028import org.forgerock.i18n.LocalizableMessage; 029 030 031import java.util.Set; 032import java.io.IOException; 033 034import org.forgerock.opendj.io.*; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036import org.opends.server.types.*; 037import org.forgerock.opendj.ldap.ResultCode; 038import org.forgerock.opendj.ldap.ByteString; 039import static org.opends.messages.ProtocolMessages.*; 040import static org.opends.server.util.ServerConstants.*; 041import static org.opends.server.util.StaticUtils.*; 042 043 044 045/** 046 * This class implements the persistent search control defined in 047 * draft-ietf-ldapext-psearch. It makes it possible for clients to be notified 048 * of changes to information in the Directory Server as they occur. 049 */ 050public class PersistentSearchControl 051 extends Control 052{ 053 /** 054 * ControlDecoder implementation to decode this control from a ByteString. 055 */ 056 private static final class Decoder 057 implements ControlDecoder<PersistentSearchControl> 058 { 059 /** {@inheritDoc} */ 060 public PersistentSearchControl decode(boolean isCritical, ByteString value) 061 throws DirectoryException 062 { 063 if (value == null) 064 { 065 LocalizableMessage message = ERR_PSEARCH_NO_CONTROL_VALUE.get(); 066 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 067 } 068 069 ASN1Reader reader = ASN1.getReader(value); 070 boolean changesOnly; 071 boolean returnECs; 072 Set<PersistentSearchChangeType> changeTypes; 073 try 074 { 075 reader.readStartSequence(); 076 077 int changeTypesValue = (int)reader.readInteger(); 078 changeTypes = PersistentSearchChangeType.intToTypes(changeTypesValue); 079 changesOnly = reader.readBoolean(); 080 returnECs = reader.readBoolean(); 081 082 reader.readEndSequence(); 083 } 084 catch (LDAPException le) 085 { 086 throw new DirectoryException(ResultCode.valueOf(le.getResultCode()), le 087 .getMessageObject()); 088 } 089 catch (Exception e) 090 { 091 logger.traceException(e); 092 093 LocalizableMessage message = 094 ERR_PSEARCH_CANNOT_DECODE_VALUE.get(getExceptionMessage(e)); 095 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 096 } 097 098 099 return new PersistentSearchControl(isCritical, 100 changeTypes, changesOnly, returnECs); 101 } 102 103 public String getOID() 104 { 105 return OID_PERSISTENT_SEARCH; 106 } 107 108 } 109 110 /** 111 * The Control Decoder that can be used to decode this control. 112 */ 113 public static final ControlDecoder<PersistentSearchControl> DECODER = 114 new Decoder(); 115 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 116 117 118 119 120 /** 121 * Indicates whether to only return entries that have been updated since the 122 * beginning of the search. 123 */ 124 private boolean changesOnly; 125 126 /** 127 * Indicates whether entries returned as a result of changes to directory data 128 * should include the entry change notification control. 129 */ 130 private boolean returnECs; 131 132 /** The set of change types associated with this control. */ 133 private Set<PersistentSearchChangeType> changeTypes; 134 135 136 137 /** 138 * Creates a new persistent search control with the provided information. 139 * 140 * @param changeTypes The set of change types for which to provide 141 * notification to the client. 142 * @param changesOnly Indicates whether to only return changes that match 143 * the associated search criteria, or to also return all 144 * existing entries that match the filter. 145 * @param returnECs Indicates whether to include the entry change 146 * notification control in updated entries that match the 147 * associated search criteria. 148 */ 149 public PersistentSearchControl(Set<PersistentSearchChangeType> changeTypes, 150 boolean changesOnly, boolean returnECs) 151 { 152 this(true, changeTypes, changesOnly, returnECs); 153 } 154 155 156 157 /** 158 * Creates a new persistent search control with the provided information. 159 * 160 * @param isCritical Indicates whether the control should be considered 161 * critical for the operation processing. 162 * @param changeTypes The set of change types for which to provide 163 * notification to the client. 164 * @param changesOnly Indicates whether to only return changes that match 165 * the associated search criteria, or to also return all 166 * existing entries that match the filter. 167 * @param returnECs Indicates whether to include the entry change 168 * notification control in updated entries that match the 169 * associated search criteria. 170 */ 171 public PersistentSearchControl(boolean isCritical, 172 Set<PersistentSearchChangeType> changeTypes, 173 boolean changesOnly, boolean returnECs) 174 { 175 super(OID_PERSISTENT_SEARCH, isCritical); 176 177 178 this.changeTypes = changeTypes; 179 this.changesOnly = changesOnly; 180 this.returnECs = returnECs; 181 } 182 183 184 185 /** 186 * Writes this control's value to an ASN.1 writer. The value (if any) must be 187 * written as an ASN1OctetString. 188 * 189 * @param writer The ASN.1 writer to use. 190 * @throws IOException If a problem occurs while writing to the stream. 191 */ 192 @Override 193 protected void writeValue(ASN1Writer writer) throws IOException { 194 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 195 196 writer.writeStartSequence(); 197 writer.writeInteger( 198 PersistentSearchChangeType.changeTypesToInt(changeTypes)); 199 writer.writeBoolean(changesOnly); 200 writer.writeBoolean(returnECs); 201 writer.writeEndSequence(); 202 203 writer.writeEndSequence(); 204 } 205 206 207 208 /** 209 * Retrieves the set of change types for this persistent search control. 210 * 211 * @return The set of change types for this persistent search control. 212 */ 213 public Set<PersistentSearchChangeType> getChangeTypes() 214 { 215 return changeTypes; 216 } 217 218 219 220 /** 221 * Indicates whether to only return changes that match the associated search 222 * criteria, or to also return all existing entries that match the filter. 223 * 224 * @return <CODE>true</CODE> if only changes to matching entries should be 225 * returned, or <CODE>false</CODE> if existing matches should also be 226 * included. 227 */ 228 public boolean getChangesOnly() 229 { 230 return changesOnly; 231 } 232 233 234 235 /** 236 * Indicates whether to include the entry change notification control in 237 * entries returned to the client as the result of a change in the Directory 238 * Server data. 239 * 240 * @return <CODE>true</CODE> if entry change notification controls should be 241 * included in applicable entries, or <CODE>false</CODE> if not. 242 */ 243 public boolean getReturnECs() 244 { 245 return returnECs; 246 } 247 248 249 250 /** 251 * Appends a string representation of this persistent search control to the 252 * provided buffer. 253 * 254 * @param buffer The buffer to which the information should be appended. 255 */ 256 @Override 257 public void toString(StringBuilder buffer) 258 { 259 buffer.append("PersistentSearchControl(changeTypes=\""); 260 PersistentSearchChangeType.changeTypesToString(changeTypes, buffer); 261 buffer.append("\",changesOnly="); 262 buffer.append(changesOnly); 263 buffer.append(",returnECs="); 264 buffer.append(returnECs); 265 buffer.append(")"); 266 } 267} 268