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