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