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