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