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;
022
023
024
025import java.util.Date;
026
027import com.unboundid.ldap.sdk.Entry;
028import com.unboundid.ldap.sdk.LDAPException;
029import com.unboundid.ldap.sdk.ReadOnlyEntry;
030import com.unboundid.ldap.sdk.ResultCode;
031import com.unboundid.ldap.sdk.unboundidds.controls.
032            SoftDeletedEntryAccessRequestControl;
033import com.unboundid.util.NotMutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*;
038
039
040
041/**
042 * This class provides a data structure for representing information about a
043 * soft-deleted entry, which results from a soft delete operation that has
044 * caused the entry to be hidden so that it is not accessible to clients under
045 * normal circumstances, rather than causing the entry to be completely removed
046 * from the server.
047 * <BR>
048 * <BLOCKQUOTE>
049 *   <B>NOTE:</B>  This class, and other classes within the
050 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
051 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
052 *   server products.  These classes provide support for proprietary
053 *   functionality or for external specifications that are not considered stable
054 *   or mature enough to be guaranteed to work in an interoperable way with
055 *   other types of LDAP servers.
056 * </BLOCKQUOTE>
057 * <BR>
058 * A soft-deleted entry will have its RDN altered to include the entryUUID for
059 * the original entry, will be updated to include the "ds-soft-delete-entry"
060 * auxiliary object class, and will have additional metadata attributes added to
061 * it which may include:
062 * <UL>
063 *   <LI>
064 *     ds-soft-delete-from-dn -- This specifies the DN assigned to the entry
065 *     before it was converted to a soft-deleted entry.
066 *   </LI>
067 *   <LI>
068 *     ds-soft-delete-timestamp -- This specifies the time that the entry was
069 *     converted to a soft-deleted entry.
070 *   </LI>
071 *   <LI>
072 *     ds-soft-delete-requester-dn -- This specifies the DN of the user who
073 *     requested the soft delete operation.
074 *   </LI>
075 *   <LI>
076 *     ds-soft-delete-requester-ip-address -- This specifies the IP address of
077 *     the client that requested the soft delete operation.
078 *   </LI>
079 * </UL>
080 * <BR><BR>
081 * Soft-deleted entries may only be retrieved by users who have the
082 * soft-delete-read privilege, and then only by clients who issue a search
083 * request with one or more of the following characteristics:
084 * <UL>
085 *   <LI>
086 *     The search operation has a scope of baseObject and a base DN which
087 *     specifically targets a soft-deleted entry.
088 *   </LI>
089 *   <LI>
090 *     The search operation includes a filter with a component that will
091 *     specifically match entries that have the ds-soft-delete-entry object
092 *     class (e.g., "(objectClass=ds-soft-delete-entry)").
093 *   </LI>
094 *   <LI>
095 *     The search operation includes a
096 *     {@link SoftDeletedEntryAccessRequestControl}.
097 *   </LI>
098 * </UL>
099 */
100@NotMutable()
101@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
102public final class SoftDeletedEntry
103       extends ReadOnlyEntry
104{
105  /**
106   * The name of the attribute that will be included in a soft-deleted entry to
107   * indicate the original DN the entry held before it was converted to a
108   * soft-deleted entry.
109   */
110  public static final String ATTR_SOFT_DELETE_FROM_DN =
111       "ds-soft-delete-from-dn";
112
113
114
115  /**
116   * The name of the attribute that will be included in a soft-deleted entry to
117   * indicate the DN of the user that requested the soft delete operation.
118   */
119  public static final String ATTR_SOFT_DELETE_REQUESTER_DN =
120       "ds-soft-delete-requester-dn";
121
122
123
124  /**
125   * The name of the attribute that will be included in a soft-deleted entry to
126   * indicate the IP address of the client that requested the soft delete
127   * operation.
128   */
129  public static final String ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS =
130       "ds-soft-delete-requester-ip-address";
131
132
133
134  /**
135   * The name of the attribute that will be included in a soft-deleted entry to
136   * indicate the time it was converted to a soft-deleted entry.
137   */
138  public static final String ATTR_SOFT_DELETE_TIMESTAMP =
139       "ds-soft-delete-timestamp";
140
141
142
143  /**
144   * The name of the auxiliary object class that will be used to mark
145   * soft-deleted entries.
146   */
147  public static final String OC_SOFT_DELETED_ENTRY = "ds-soft-delete-entry";
148
149
150
151  /**
152   * The serial version UID for this serializable class.
153   */
154  private static final long serialVersionUID = -3450703461178674797L;
155
156
157
158  // The time the entry was converted to a soft-deleted entry.
159  private final Date softDeleteTimestamp;
160
161  // The DN held by the entry at the time it was converted to a soft-deleted
162  // entry.
163  private final String softDeleteFromDN;
164
165  // The DN of the user that requested the soft delete operation.
166  private final String softDeleteRequesterDN;
167
168  // The IP address of the client that requested the soft delete operation.
169  private final String softDeleteRequesterIPAddress;
170
171
172
173  /**
174   * Creates a soft-deleted entry from the provided entry.
175   *
176   * @param  entry  The entry to be processed as a soft-deleted entry.  It must
177   *                not be {@code null}.
178   *
179   * @throws  LDAPException  If the provided entry does not represent a valid
180   *                         soft-deleted entry.
181   */
182  public SoftDeletedEntry(final Entry entry)
183         throws LDAPException
184  {
185    super(entry);
186
187    if (! entry.hasObjectClass(OC_SOFT_DELETED_ENTRY))
188    {
189      throw new LDAPException(ResultCode.LOCAL_ERROR,
190           ERR_SOFT_DELETED_ENTRY_MISSING_OC.get(entry.getDN()));
191    }
192
193    softDeleteFromDN = entry.getAttributeValue(ATTR_SOFT_DELETE_FROM_DN);
194    softDeleteTimestamp =
195         entry.getAttributeValueAsDate(ATTR_SOFT_DELETE_TIMESTAMP);
196    softDeleteRequesterDN =
197         entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_DN);
198    softDeleteRequesterIPAddress =
199         entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS);
200
201    if (softDeleteFromDN == null)
202    {
203      throw new LDAPException(ResultCode.LOCAL_ERROR,
204           ERR_SOFT_DELETED_ENTRY_MISSING_FROM_DN.get(entry.getDN()));
205    }
206
207    // NOTE:  This isn't actually used, but it's needed to satisfy checkstyle
208    // because although we reference SoftDeletedEntryAccessRequestControl in
209    // the javadoc, checkstyle doesn't recognize that as a use of the class.
210    final SoftDeletedEntryAccessRequestControl c = null;
211  }
212
213
214
215  /**
216   * Retrieves the DN held by the entry at the time it was converted to a
217   * soft-deleted entry.
218   *
219   * @return  The DN held by the entry at the time it was converted to a
220   *          soft-deleted entry.
221   */
222  public String getSoftDeleteFromDN()
223  {
224    return softDeleteFromDN;
225  }
226
227
228
229  /**
230   * Retrieves the time that the entry was converted to a soft-deleted entry,
231   * if available.
232   *
233   * @return  The time that the entry was converted to a soft-deleted entry, or
234   *          {@code null} if this is not available in the entry.
235   */
236  public Date getSoftDeleteTimestamp()
237  {
238    return softDeleteTimestamp;
239  }
240
241
242
243  /**
244   * Retrieves the DN of the user that requested the soft delete operation,
245   * if available.
246   *
247   * @return  The DN of the user that requested the soft delete operation, or
248   *          {@code null} if this is not available in the entry.
249   */
250  public String getSoftDeleteRequesterDN()
251  {
252    return softDeleteRequesterDN;
253  }
254
255
256
257  /**
258   * Retrieves the IP address of the client that requested the soft delete
259   * operation, if available.
260   *
261   * @return  The IP address of the client that requested the soft delete
262   *          operation, or {@code null} if this is not available in the entry.
263   */
264  public String getSoftDeleteRequesterIPAddress()
265  {
266    return softDeleteRequesterIPAddress;
267  }
268
269
270
271  /**
272   * Retrieves a copy of the original entry as it appeared before the soft
273   * delete operation was processed.  It will have its original DN and all
274   * soft delete metadata attributes and auxiliary object class removed.
275   *
276   * @return  A copy of the original entry as it appeared before the soft delete
277   *          operation was processed.
278   */
279  public ReadOnlyEntry getUndeletedEntry()
280  {
281    final Entry e = duplicate();
282
283    e.setDN(softDeleteFromDN);
284
285    e.removeAttributeValue("objectClass", OC_SOFT_DELETED_ENTRY);
286    e.removeAttribute(ATTR_SOFT_DELETE_FROM_DN);
287    e.removeAttribute(ATTR_SOFT_DELETE_TIMESTAMP);
288    e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_DN);
289    e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS);
290
291    return new ReadOnlyEntry(e);
292  }
293
294
295
296  /**
297   * Indicates whether the provided entry may be parsed as a valid soft-deleted
298   * entry.
299   *
300   * @param  entry  The entry to be examined.  It must not be {@code null}.
301   *
302   * @return  {@code true} if the provided entry contains at least a
303   *          ds-soft-delete-entry object class and a ds-soft-delete-from-dn
304   *          attribute.
305   */
306  public static boolean isSoftDeletedEntry(final Entry entry)
307  {
308    return (entry.hasObjectClass(OC_SOFT_DELETED_ENTRY) &&
309         entry.hasAttribute(ATTR_SOFT_DELETE_FROM_DN));
310  }
311}