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