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.controls; 037 038 039 040import java.util.List; 041 042import com.unboundid.asn1.ASN1OctetString; 043import com.unboundid.ldap.sdk.Control; 044import com.unboundid.ldap.sdk.DecodeableControl; 045import com.unboundid.ldap.sdk.DN; 046import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 047import com.unboundid.ldap.sdk.LDAPException; 048import com.unboundid.ldap.sdk.LDAPResult; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.NotNull; 052import com.unboundid.util.Nullable; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055import com.unboundid.util.Validator; 056import com.unboundid.util.json.JSONField; 057import com.unboundid.util.json.JSONObject; 058 059import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 060 061 062 063/** 064 * This class provides a response control that holds information about the 065 * soft-deleted entry that results from a soft delete request, and may also be 066 * included in a search result entry which represents a soft-deleted entry. The 067 * value of this control will be the DN of the soft-deleted entry. 068 * <BR> 069 * <BLOCKQUOTE> 070 * <B>NOTE:</B> This class, and other classes within the 071 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 072 * supported for use against Ping Identity, UnboundID, and 073 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 074 * for proprietary functionality or for external specifications that are not 075 * considered stable or mature enough to be guaranteed to work in an 076 * interoperable way with other types of LDAP servers. 077 * </BLOCKQUOTE> 078 * <BR> 079 * This control has an OID of 1.3.6.1.4.1.30221.2.5.21, a criticality of false, 080 * and a value that is simply the string representation of the new DN for the 081 * soft-deleted entry. 082 * <BR><BR> 083 * See the documentation for the {@link SoftDeleteRequestControl} class for an 084 * example demonstrating the use of this control. 085 * 086 * @see SoftDeleteRequestControl 087 */ 088@NotMutable() 089@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 090public final class SoftDeleteResponseControl 091 extends Control 092 implements DecodeableControl 093{ 094 /** 095 * The OID (1.3.6.1.4.1.30221.2.5.21) for the soft delete response control. 096 */ 097 @NotNull public static final String SOFT_DELETE_RESPONSE_OID = 098 "1.3.6.1.4.1.30221.2.5.21"; 099 100 101 102 /** 103 * The name of the field used to hold the soft-deleted entry DN in the JSON 104 * representation of this control. 105 */ 106 @NotNull private static final String JSON_FIELD_SOFT_DELETED_ENTRY_DN = 107 "soft-deleted-entry-dn"; 108 109 110 111 /** 112 * The serial version UID for this serializable class. 113 */ 114 private static final long serialVersionUID = 3163679387266190228L; 115 116 117 118 // The DN of the soft-deleted representation of the target entry. 119 @NotNull private final String softDeletedEntryDN; 120 121 122 123 /** 124 * Creates a new empty control instance that is intended to be used only for 125 * decoding controls via the {@code DecodeableControl} interface. 126 */ 127 SoftDeleteResponseControl() 128 { 129 softDeletedEntryDN = null; 130 } 131 132 133 134 /** 135 * Creates a new soft delete response control with the provided information. 136 * 137 * @param softDeletedEntryDN The DN of the soft-deleted representation of 138 * the target entry. 139 */ 140 public SoftDeleteResponseControl(@NotNull final String softDeletedEntryDN) 141 { 142 super(SOFT_DELETE_RESPONSE_OID, false, 143 new ASN1OctetString(softDeletedEntryDN)); 144 145 Validator.ensureNotNull(softDeletedEntryDN); 146 147 this.softDeletedEntryDN = softDeletedEntryDN; 148 } 149 150 151 152 /** 153 * Creates a new soft delete response control with the provided information. 154 * 155 * @param oid The OID for the control. 156 * @param isCritical Indicates whether the control should be considered 157 * critical. 158 * @param value The value for the control. 159 * 160 * @throws LDAPException If the provided information cannot be used to 161 * create a valid soft delete response control. 162 */ 163 public SoftDeleteResponseControl(@NotNull final String oid, 164 final boolean isCritical, 165 @Nullable final ASN1OctetString value) 166 throws LDAPException 167 { 168 super(oid, isCritical, value); 169 170 if (value == null) 171 { 172 throw new LDAPException(ResultCode.DECODING_ERROR, 173 ERR_SOFT_DELETE_RESPONSE_NO_VALUE.get()); 174 } 175 176 softDeletedEntryDN = value.stringValue(); 177 if (! DN.isValidDN(softDeletedEntryDN)) 178 { 179 throw new LDAPException(ResultCode.DECODING_ERROR, 180 ERR_SOFT_DELETE_RESPONSE_VALUE_NOT_DN.get()); 181 } 182 } 183 184 185 186 /** 187 * {@inheritDoc} 188 */ 189 @Override() 190 @NotNull() 191 public SoftDeleteResponseControl decodeControl(@NotNull final String oid, 192 final boolean isCritical, 193 @Nullable final ASN1OctetString value) 194 throws LDAPException 195 { 196 return new SoftDeleteResponseControl(oid, isCritical, value); 197 } 198 199 200 201 /** 202 * Retrieves the DN of the entry containing the soft-deleted representation of 203 * the target entry. 204 * 205 * @return The DN of the entry containing the soft-deleted representation of 206 * the target entry. 207 */ 208 @NotNull() 209 public String getSoftDeletedEntryDN() 210 { 211 return softDeletedEntryDN; 212 } 213 214 215 216 /** 217 * Extracts a soft delete response control from the provided delete result. 218 * 219 * @param deleteResult The delete result from which to retrieve the soft 220 * delete response control. 221 * 222 * @return The soft delete response control contained in the provided delete 223 * result, or {@code null} if the result did not contain a soft 224 * delete response control. 225 * 226 * @throws LDAPException If a problem is encountered while attempting to 227 * decode the soft delete response control contained 228 * in the provided result. 229 */ 230 @Nullable() 231 public static SoftDeleteResponseControl get( 232 @NotNull final LDAPResult deleteResult) 233 throws LDAPException 234 { 235 final Control c = deleteResult.getResponseControl(SOFT_DELETE_RESPONSE_OID); 236 if (c == null) 237 { 238 return null; 239 } 240 241 if (c instanceof SoftDeleteResponseControl) 242 { 243 return (SoftDeleteResponseControl) c; 244 } 245 else 246 { 247 return new SoftDeleteResponseControl(c.getOID(), c.isCritical(), 248 c.getValue()); 249 } 250 } 251 252 253 254 /** 255 * {@inheritDoc} 256 */ 257 @Override() 258 @NotNull() 259 public String getControlName() 260 { 261 return INFO_CONTROL_NAME_SOFT_DELETE_RESPONSE.get(); 262 } 263 264 265 266 /** 267 * Retrieves a representation of this soft delete response control as a JSON 268 * object. The JSON object uses the following fields: 269 * <UL> 270 * <LI> 271 * {@code oid} -- A mandatory string field whose value is the object 272 * identifier for this control. For the soft delete response control, 273 * the OID is "1.3.6.1.4.1.30221.2.5.21". 274 * </LI> 275 * <LI> 276 * {@code control-name} -- An optional string field whose value is a 277 * human-readable name for this control. This field is only intended for 278 * descriptive purposes, and when decoding a control, the {@code oid} 279 * field should be used to identify the type of control. 280 * </LI> 281 * <LI> 282 * {@code criticality} -- A mandatory Boolean field used to indicate 283 * whether this control is considered critical. 284 * </LI> 285 * <LI> 286 * {@code value-base64} -- An optional string field whose value is a 287 * base64-encoded representation of the raw value for this soft delete 288 * response control. Exactly one of the {@code value-base64} and 289 * {@code value-json} fields must be present. 290 * </LI> 291 * <LI> 292 * {@code value-json} -- An optional JSON object field whose value is a 293 * user-friendly representation of the value for this soft delete response 294 * control. Exactly one of the {@code value-base64} and 295 * {@code value-json} fields must be present, and if the 296 * {@code value-json} field is used, then it will use the following 297 * fields: 298 * <UL> 299 * <LI> 300 * {@code soft-deleted-entry-dn} -- A string field whose value is the 301 * DN of the soft-deleted entry that was created from the original 302 * entry. 303 * </LI> 304 * </UL> 305 * </LI> 306 * </UL> 307 * 308 * @return A JSON object that contains a representation of this control. 309 */ 310 @Override() 311 @NotNull() 312 public JSONObject toJSONControl() 313 { 314 return new JSONObject( 315 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 316 SOFT_DELETE_RESPONSE_OID), 317 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 318 INFO_CONTROL_NAME_SOFT_DELETE_RESPONSE.get()), 319 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 320 isCritical()), 321 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 322 new JSONObject( 323 new JSONField(JSON_FIELD_SOFT_DELETED_ENTRY_DN, 324 softDeletedEntryDN)))); 325 } 326 327 328 329 /** 330 * Attempts to decode the provided object as a JSON representation of a soft 331 * delete response control. 332 * 333 * @param controlObject The JSON object to be decoded. It must not be 334 * {@code null}. 335 * @param strict Indicates whether to use strict mode when decoding 336 * the provided JSON object. If this is {@code true}, 337 * then this method will throw an exception if the 338 * provided JSON object contains any unrecognized 339 * fields. If this is {@code false}, then unrecognized 340 * fields will be ignored. 341 * 342 * @return The soft delete response control that was decoded from 343 * the provided JSON object. 344 * 345 * @throws LDAPException If the provided JSON object cannot be parsed as a 346 * valid soft delete response control. 347 */ 348 @NotNull() 349 public static SoftDeleteResponseControl decodeJSONControl( 350 @NotNull final JSONObject controlObject, 351 final boolean strict) 352 throws LDAPException 353 { 354 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 355 controlObject, strict, true, true); 356 357 final ASN1OctetString rawValue = jsonControl.getRawValue(); 358 if (rawValue != null) 359 { 360 return new SoftDeleteResponseControl(jsonControl.getOID(), 361 jsonControl.getCriticality(), rawValue); 362 } 363 364 365 final JSONObject valueObject = jsonControl.getValueObject(); 366 367 final String softDeletedEntryDN = 368 valueObject.getFieldAsString(JSON_FIELD_SOFT_DELETED_ENTRY_DN); 369 if (softDeletedEntryDN == null) 370 { 371 throw new LDAPException(ResultCode.DECODING_ERROR, 372 ERR_SOFT_DELETE_RESPONSE_JSON_MISSING_FIELD.get( 373 controlObject.toSingleLineString(), 374 JSON_FIELD_SOFT_DELETED_ENTRY_DN)); 375 } 376 377 378 if (strict) 379 { 380 final List<String> unrecognizedFields = 381 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 382 valueObject, JSON_FIELD_SOFT_DELETED_ENTRY_DN); 383 if (! unrecognizedFields.isEmpty()) 384 { 385 throw new LDAPException(ResultCode.DECODING_ERROR, 386 ERR_SOFT_DELETE_RESPONSE_JSON_UNRECOGNIZED_FIELD.get( 387 controlObject.toSingleLineString(), 388 unrecognizedFields.get(0))); 389 } 390 } 391 392 393 return new SoftDeleteResponseControl(softDeletedEntryDN); 394 } 395 396 397 398 /** 399 * {@inheritDoc} 400 */ 401 @Override() 402 public void toString(@NotNull final StringBuilder buffer) 403 { 404 buffer.append("SoftDeleteResponseControl(softDeletedEntryDN='"); 405 buffer.append(softDeletedEntryDN); 406 buffer.append("')"); 407 } 408}