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