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 }