001/*
002 * Copyright 2012-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.controls;
022
023
024
025import java.util.ArrayList;
026
027import com.unboundid.asn1.ASN1Boolean;
028import com.unboundid.asn1.ASN1Element;
029import com.unboundid.asn1.ASN1OctetString;
030import com.unboundid.asn1.ASN1Sequence;
031import com.unboundid.ldap.sdk.Control;
032import com.unboundid.ldap.sdk.LDAPException;
033import com.unboundid.ldap.sdk.ResultCode;
034import com.unboundid.util.Debug;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.StaticUtils;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039
040import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
041
042
043
044/**
045 * This class provides a request control which may be included in a search
046 * request to indicate that soft-deleted entries may be included in the results,
047 * or it may be included in a compare or modify request to indicate that the
048 * operation should operate against the target entry even if it is a
049 * soft-deleted entry.
050 * <BR>
051 * <BLOCKQUOTE>
052 *   <B>NOTE:</B>  This class, and other classes within the
053 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
054 *   supported for use against Ping Identity, UnboundID, and
055 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
056 *   for proprietary functionality or for external specifications that are not
057 *   considered stable or mature enough to be guaranteed to work in an
058 *   interoperable way with other types of LDAP servers.
059 * </BLOCKQUOTE>
060 * <BR>
061 * The criticality for this control may be either {@code TRUE} or {@code FALSE},
062 * but this will only impact how the delete request is to be handled by servers
063 * which do not support this control.  A criticality of {@code TRUE} will cause
064 * any server which does not support this control to reject the request, while
065 * a criticality of {@code FALSE} should cause the request to be processed as if
066 * the control had not been included.
067 * <BR><BR>
068 * The control may optionally have a value.  If a value is provided, then it
069 * must be the encoded representation of the following ASN.1 element:
070 * <PRE>
071 *   SoftDeleteAccessRequestValue ::= SEQUENCE {
072 *     includeNonSoftDeletedEntries     [0] BOOLEAN DEFAULT TRUE,
073 *     returnEntriesInUndeletedForm     [1] BOOLEAN DEFAULT FALSE,
074 *     ... }
075 * </PRE>
076 * See the documentation for the {@link SoftDeleteRequestControl} class for an
077 * example demonstrating the use of this control.
078 *
079 * @see  SoftDeleteResponseControl
080 */
081@NotMutable()
082@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
083public final class SoftDeletedEntryAccessRequestControl
084       extends Control
085{
086  /**
087   * The OID (1.3.6.1.4.1.30221.2.5.24) for the soft-deleted entry access
088   * request control.
089   */
090  public static final String SOFT_DELETED_ENTRY_ACCESS_REQUEST_OID =
091       "1.3.6.1.4.1.30221.2.5.24";
092
093
094
095  /**
096   * The BER type for the include non-soft-deleted entries element.
097   */
098  private static final byte TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES = (byte) 0x80;
099
100
101
102  /**
103   * The BER type for the return entries in undeleted form element.
104   */
105  private static final byte TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM = (byte) 0x81;
106
107
108
109  /**
110   * The serial version UID for this serializable class.
111   */
112  private static final long serialVersionUID = -3633807543861389512L;
113
114
115
116  // Indicates whether to include non-soft-deleted entries in search results.
117  private final boolean includeNonSoftDeletedEntries;
118
119  // Indicates whether to return soft-deleted entries in the form they appeared
120  // before they were deleted.
121  private final boolean returnEntriesInUndeletedForm;
122
123
124
125  /**
126   * Creates a new soft-deleted entry access request control with the default
127   * settings for all elements.  It will not be marked critical.
128   */
129  public SoftDeletedEntryAccessRequestControl()
130  {
131    this(false, true, false);
132  }
133
134
135
136  /**
137   * Creates a new soft delete request control with the provided information.
138   *
139   * @param  isCritical                    Indicates whether this control should
140   *                                       be marked critical.  This will only
141   *                                       have an effect on the way the
142   *                                       associated delete operation is
143   *                                       handled by servers which do NOT
144   *                                       support the soft-deleted entry access
145   *                                       request control.  For such servers, a
146   *                                       control that is critical will cause
147   *                                       associated request to be rejected,
148   *                                       while a control that is not critical
149   *                                       will be processed as if the control
150   *                                       was not included in the request.
151   * @param  includeNonSoftDeletedEntries  Indicates whether search results
152   *                                       should include non-soft-deleted
153   *                                       entries if they match the criteria
154   *                                       for the associated search request.
155   * @param  returnEntriesInUndeletedForm  Indicates whether soft-deleted
156   *                                       entries returned in search results
157   *                                       should be returned in the form in
158   *                                       which they would appear if they were
159   *                                       undeleted.  Note that if soft-deleted
160   *                                       entries should be returned in their
161   *                                       undeleted form, then it may be
162   *                                       possible for multiple entries to be
163   *                                       returned with the same DN (if
164   *                                       multiple soft-deleted entries with
165   *                                       the same original DN match the
166   *                                       criteria, or if at least one
167   *                                       soft-deleted entry and one normal
168   *                                       entry with the same DN both match the
169   *                                       search criteria).
170   */
171  public SoftDeletedEntryAccessRequestControl(final boolean isCritical,
172              final boolean includeNonSoftDeletedEntries,
173              final boolean returnEntriesInUndeletedForm)
174  {
175    super(SOFT_DELETED_ENTRY_ACCESS_REQUEST_OID, isCritical,
176         encodeValue(includeNonSoftDeletedEntries,
177              returnEntriesInUndeletedForm));
178
179    this.includeNonSoftDeletedEntries = includeNonSoftDeletedEntries;
180    this.returnEntriesInUndeletedForm = returnEntriesInUndeletedForm;
181  }
182
183
184
185  /**
186   * Creates a new soft-deleted entry access request control which is decoded
187   * from the provided generic control.
188   *
189   * @param  control  The generic control to be decoded as a soft-deleted entry
190   *                  access request control.
191   *
192   * @throws  LDAPException  If the provided control cannot be decoded as a
193   *                         soft-deleted entry access request control.
194   */
195  public SoftDeletedEntryAccessRequestControl(final Control control)
196         throws LDAPException
197  {
198    super(control);
199
200    boolean includeNonSoftDeleted = true;
201    boolean returnAsUndeleted     = false;
202
203    if (control.hasValue())
204    {
205      try
206      {
207        final ASN1Sequence valueSequence =
208             ASN1Sequence.decodeAsSequence(control.getValue().getValue());
209        for (final ASN1Element e : valueSequence.elements())
210        {
211          switch (e.getType())
212          {
213            case TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES:
214              includeNonSoftDeleted =
215                   ASN1Boolean.decodeAsBoolean(e).booleanValue();
216              break;
217            case TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM:
218              returnAsUndeleted = ASN1Boolean.decodeAsBoolean(e).booleanValue();
219              break;
220            default:
221              throw new LDAPException(ResultCode.DECODING_ERROR,
222                   ERR_SOFT_DELETED_ACCESS_REQUEST_UNSUPPORTED_ELEMENT_TYPE.get(
223                        StaticUtils.toHex(e.getType())));
224          }
225        }
226      }
227      catch (final LDAPException le)
228      {
229        Debug.debugException(le);
230        throw le;
231      }
232      catch (final Exception e)
233      {
234        Debug.debugException(e);
235        throw new LDAPException(ResultCode.DECODING_ERROR,
236             ERR_SOFT_DELETED_ACCESS_REQUEST_CANNOT_DECODE_VALUE.get(
237                  StaticUtils.getExceptionMessage(e)),
238             e);
239      }
240    }
241
242    includeNonSoftDeletedEntries = includeNonSoftDeleted;
243    returnEntriesInUndeletedForm = returnAsUndeleted;
244  }
245
246
247
248  /**
249   * Encodes the provided information into an ASN.1 octet string suitable for
250   * use as the value of a soft-deleted entry access request control.
251   *
252   * @param  includeNonSoftDeletedEntries  Indicates whether search results
253   *                                       should include non-soft-deleted
254   *                                       entries if they match the criteria
255   *                                       for the associated search request.
256   * @param  returnEntriesInUndeletedForm  Indicates whether soft-deleted
257   *                                       entries returned in search results
258   *                                       should be returned in the form in
259   *                                       which they would appear if they were
260   *                                       undeleted.  Note that if soft-deleted
261   *                                       entries should be returned in their
262   *                                       undeleted form, then it may be
263   *                                       possible for multiple entries to be
264   *                                       returned with the same DN (if
265   *                                       multiple soft-deleted entries with
266   *                                       the same original DN match the
267   *                                       criteria, or if at least one
268   *                                       soft-deleted entry and one normal
269   *                                       entry with the same DN both match the
270   *                                       search criteria).
271   *
272   * @return  An ASN.1 octet string with an encoding suitable for use as the
273   *          value of a soft-deleted entry access request control, or
274   *          {@code null} if no value is needed for the control.
275   */
276  private static ASN1OctetString encodeValue(
277                      final boolean includeNonSoftDeletedEntries,
278                      final boolean returnEntriesInUndeletedForm)
279  {
280    if (includeNonSoftDeletedEntries && (! returnEntriesInUndeletedForm))
281    {
282      return null;
283    }
284
285    final ArrayList<ASN1Element> elements = new ArrayList<>(2);
286    if (! includeNonSoftDeletedEntries)
287    {
288      elements.add(new ASN1Boolean(TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES,
289           false));
290    }
291
292    if (returnEntriesInUndeletedForm)
293    {
294      elements.add(new ASN1Boolean(TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM,
295           true));
296    }
297
298    return new ASN1OctetString(new ASN1Sequence(elements).encode());
299  }
300
301
302
303  /**
304   * Indicates whether search results should include non-soft-deleted entries
305   * if they match the criteria for the associated search request.
306   *
307   * @return  {@code true} if the server should return any "normal"
308   *          non-soft-deleted entries that match the search criteria, or
309   *          {@code false} if the server should only return soft-deleted
310   *          entries that match the search criteria.
311   */
312  public boolean includeNonSoftDeletedEntries()
313  {
314    return includeNonSoftDeletedEntries;
315  }
316
317
318
319  /**
320   * Indicates whether soft-deleted entries returned in search results should be
321   * returned in the form in which they would appear if they were undeleted.
322   * Note that if soft-deleted entries should be returned in their undeleted
323   * form, then it may be possible for multiple entries to be returned with the
324   * same DN (if multiple soft-deleted entries with the same original DN match
325   * the criteria, or if at least one soft-deleted entry and one normal entry
326   * with the same DN both match the search criteria).
327   *
328   * @return  {@code false} if soft-deleted entries should be returned in their
329   *          current form as soft-deleted entries, or {@code true} if they
330   *          should be returned in the form in which they would appear if they
331   *          were undeleted (e.g., using the original DN for the entry and
332   *          without all the additional meta-attributes added during the
333   *          soft delete process).
334   */
335  public boolean returnEntriesInUndeletedForm()
336  {
337    return returnEntriesInUndeletedForm;
338  }
339
340
341
342  /**
343   * {@inheritDoc}
344   */
345  @Override()
346  public String getControlName()
347  {
348    return INFO_CONTROL_NAME_SOFT_DELETED_ACCESS_REQUEST.get();
349  }
350
351
352
353  /**
354   * {@inheritDoc}
355   */
356  @Override()
357  public void toString(final StringBuilder buffer)
358  {
359    buffer.append("SoftDeletedEntryAccessRequestControl(isCritical=");
360    buffer.append(isCritical());
361    buffer.append(", includeNonSoftDeletedEntries=");
362    buffer.append(includeNonSoftDeletedEntries);
363    buffer.append(", returnEntriesInUndeletedForm=");
364    buffer.append(returnEntriesInUndeletedForm);
365    buffer.append(')');
366  }
367}