001/* 002 * Copyright 2012-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2012-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2012-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds; 037 038 039 040import java.util.Date; 041 042import com.unboundid.ldap.sdk.Entry; 043import com.unboundid.ldap.sdk.LDAPException; 044import com.unboundid.ldap.sdk.ReadOnlyEntry; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.unboundidds.controls. 047 SoftDeletedEntryAccessRequestControl; 048import com.unboundid.util.NotMutable; 049import com.unboundid.util.NotNull; 050import com.unboundid.util.Nullable; 051import com.unboundid.util.ThreadSafety; 052import com.unboundid.util.ThreadSafetyLevel; 053 054import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*; 055 056 057 058/** 059 * This class provides a data structure for representing information about a 060 * soft-deleted entry, which results from a soft delete operation that has 061 * caused the entry to be hidden so that it is not accessible to clients under 062 * normal circumstances, rather than causing the entry to be completely removed 063 * from the server. 064 * <BR> 065 * <BLOCKQUOTE> 066 * <B>NOTE:</B> This class, and other classes within the 067 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 068 * supported for use against Ping Identity, UnboundID, and 069 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 070 * for proprietary functionality or for external specifications that are not 071 * considered stable or mature enough to be guaranteed to work in an 072 * interoperable way with other types of LDAP servers. 073 * </BLOCKQUOTE> 074 * <BR> 075 * A soft-deleted entry will have its RDN altered to include the entryUUID for 076 * the original entry, will be updated to include the "ds-soft-delete-entry" 077 * auxiliary object class, and will have additional metadata attributes added to 078 * it which may include: 079 * <UL> 080 * <LI> 081 * ds-soft-delete-from-dn -- This specifies the DN assigned to the entry 082 * before it was converted to a soft-deleted entry. 083 * </LI> 084 * <LI> 085 * ds-soft-delete-timestamp -- This specifies the time that the entry was 086 * converted to a soft-deleted entry. 087 * </LI> 088 * <LI> 089 * ds-soft-delete-requester-dn -- This specifies the DN of the user who 090 * requested the soft delete operation. 091 * </LI> 092 * <LI> 093 * ds-soft-delete-requester-ip-address -- This specifies the IP address of 094 * the client that requested the soft delete operation. 095 * </LI> 096 * </UL> 097 * <BR><BR> 098 * Soft-deleted entries may only be retrieved by users who have the 099 * soft-delete-read privilege, and then only by clients who issue a search 100 * request with one or more of the following characteristics: 101 * <UL> 102 * <LI> 103 * The search operation has a scope of baseObject and a base DN which 104 * specifically targets a soft-deleted entry. 105 * </LI> 106 * <LI> 107 * The search operation includes a filter with a component that will 108 * specifically match entries that have the ds-soft-delete-entry object 109 * class (e.g., "(objectClass=ds-soft-delete-entry)"). 110 * </LI> 111 * <LI> 112 * The search operation includes a 113 * {@link SoftDeletedEntryAccessRequestControl}. 114 * </LI> 115 * </UL> 116 */ 117@NotMutable() 118@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 119public final class SoftDeletedEntry 120 extends ReadOnlyEntry 121{ 122 /** 123 * The name of the attribute that will be included in a soft-deleted entry to 124 * indicate the original DN the entry held before it was converted to a 125 * soft-deleted entry. 126 */ 127 @NotNull public static final String ATTR_SOFT_DELETE_FROM_DN = 128 "ds-soft-delete-from-dn"; 129 130 131 132 /** 133 * The name of the attribute that will be included in a soft-deleted entry to 134 * indicate the DN of the user that requested the soft delete operation. 135 */ 136 @NotNull public static final String ATTR_SOFT_DELETE_REQUESTER_DN = 137 "ds-soft-delete-requester-dn"; 138 139 140 141 /** 142 * The name of the attribute that will be included in a soft-deleted entry to 143 * indicate the IP address of the client that requested the soft delete 144 * operation. 145 */ 146 @NotNull public static final String ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS = 147 "ds-soft-delete-requester-ip-address"; 148 149 150 151 /** 152 * The name of the attribute that will be included in a soft-deleted entry to 153 * indicate the time it was converted to a soft-deleted entry. 154 */ 155 @NotNull public static final String ATTR_SOFT_DELETE_TIMESTAMP = 156 "ds-soft-delete-timestamp"; 157 158 159 160 /** 161 * The name of the auxiliary object class that will be used to mark 162 * soft-deleted entries. 163 */ 164 @NotNull public static final String OC_SOFT_DELETED_ENTRY = 165 "ds-soft-delete-entry"; 166 167 168 169 /** 170 * The serial version UID for this serializable class. 171 */ 172 private static final long serialVersionUID = -3450703461178674797L; 173 174 175 176 // The time the entry was converted to a soft-deleted entry. 177 @Nullable private final Date softDeleteTimestamp; 178 179 // The DN held by the entry at the time it was converted to a soft-deleted 180 // entry. 181 @NotNull private final String softDeleteFromDN; 182 183 // The DN of the user that requested the soft delete operation. 184 @Nullable private final String softDeleteRequesterDN; 185 186 // The IP address of the client that requested the soft delete operation. 187 @Nullable private final String softDeleteRequesterIPAddress; 188 189 190 191 /** 192 * Creates a soft-deleted entry from the provided entry. 193 * 194 * @param entry The entry to be processed as a soft-deleted entry. It must 195 * not be {@code null}. 196 * 197 * @throws LDAPException If the provided entry does not represent a valid 198 * soft-deleted entry. 199 */ 200 public SoftDeletedEntry(@NotNull final Entry entry) 201 throws LDAPException 202 { 203 super(entry); 204 205 if (! entry.hasObjectClass(OC_SOFT_DELETED_ENTRY)) 206 { 207 throw new LDAPException(ResultCode.LOCAL_ERROR, 208 ERR_SOFT_DELETED_ENTRY_MISSING_OC.get(entry.getDN())); 209 } 210 211 softDeleteFromDN = entry.getAttributeValue(ATTR_SOFT_DELETE_FROM_DN); 212 softDeleteTimestamp = 213 entry.getAttributeValueAsDate(ATTR_SOFT_DELETE_TIMESTAMP); 214 softDeleteRequesterDN = 215 entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_DN); 216 softDeleteRequesterIPAddress = 217 entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS); 218 219 if (softDeleteFromDN == null) 220 { 221 throw new LDAPException(ResultCode.LOCAL_ERROR, 222 ERR_SOFT_DELETED_ENTRY_MISSING_FROM_DN.get(entry.getDN())); 223 } 224 } 225 226 227 228 /** 229 * Retrieves the DN held by the entry at the time it was converted to a 230 * soft-deleted entry. 231 * 232 * @return The DN held by the entry at the time it was converted to a 233 * soft-deleted entry. 234 */ 235 @NotNull() 236 public String getSoftDeleteFromDN() 237 { 238 return softDeleteFromDN; 239 } 240 241 242 243 /** 244 * Retrieves the time that the entry was converted to a soft-deleted entry, 245 * if available. 246 * 247 * @return The time that the entry was converted to a soft-deleted entry, or 248 * {@code null} if this is not available in the entry. 249 */ 250 @Nullable() 251 public Date getSoftDeleteTimestamp() 252 { 253 return softDeleteTimestamp; 254 } 255 256 257 258 /** 259 * Retrieves the DN of the user that requested the soft delete operation, 260 * if available. 261 * 262 * @return The DN of the user that requested the soft delete operation, or 263 * {@code null} if this is not available in the entry. 264 */ 265 @Nullable() 266 public String getSoftDeleteRequesterDN() 267 { 268 return softDeleteRequesterDN; 269 } 270 271 272 273 /** 274 * Retrieves the IP address of the client that requested the soft delete 275 * operation, if available. 276 * 277 * @return The IP address of the client that requested the soft delete 278 * operation, or {@code null} if this is not available in the entry. 279 */ 280 @Nullable() 281 public String getSoftDeleteRequesterIPAddress() 282 { 283 return softDeleteRequesterIPAddress; 284 } 285 286 287 288 /** 289 * Retrieves a copy of the original entry as it appeared before the soft 290 * delete operation was processed. It will have its original DN and all 291 * soft delete metadata attributes and auxiliary object class removed. 292 * 293 * @return A copy of the original entry as it appeared before the soft delete 294 * operation was processed. 295 */ 296 @NotNull() 297 public ReadOnlyEntry getUndeletedEntry() 298 { 299 final Entry e = duplicate(); 300 301 e.setDN(softDeleteFromDN); 302 303 e.removeAttributeValue("objectClass", OC_SOFT_DELETED_ENTRY); 304 e.removeAttribute(ATTR_SOFT_DELETE_FROM_DN); 305 e.removeAttribute(ATTR_SOFT_DELETE_TIMESTAMP); 306 e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_DN); 307 e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS); 308 309 return new ReadOnlyEntry(e); 310 } 311 312 313 314 /** 315 * Indicates whether the provided entry may be parsed as a valid soft-deleted 316 * entry. 317 * 318 * @param entry The entry to be examined. It must not be {@code null}. 319 * 320 * @return {@code true} if the provided entry contains at least a 321 * ds-soft-delete-entry object class and a ds-soft-delete-from-dn 322 * attribute. 323 */ 324 public static boolean isSoftDeletedEntry(@NotNull final Entry entry) 325 { 326 return (entry.hasObjectClass(OC_SOFT_DELETED_ENTRY) && 327 entry.hasAttribute(ATTR_SOFT_DELETE_FROM_DN)); 328 } 329}