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}