001/* 002 * Copyright 2012-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2012-2020 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) 2015-2020 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.ArrayList; 041 042import com.unboundid.asn1.ASN1Boolean; 043import com.unboundid.asn1.ASN1Element; 044import com.unboundid.asn1.ASN1OctetString; 045import com.unboundid.asn1.ASN1Sequence; 046import com.unboundid.ldap.sdk.Control; 047import com.unboundid.ldap.sdk.LDAPException; 048import com.unboundid.ldap.sdk.ResultCode; 049import com.unboundid.util.Debug; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054 055import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 056 057 058 059/** 060 * This class provides a request control which may be included in a search 061 * request to indicate that soft-deleted entries may be included in the results, 062 * or it may be included in a compare or modify request to indicate that the 063 * operation should operate against the target entry even if it is a 064 * soft-deleted entry. 065 * <BR> 066 * <BLOCKQUOTE> 067 * <B>NOTE:</B> This class, and other classes within the 068 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 069 * supported for use against Ping Identity, UnboundID, and 070 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 071 * for proprietary functionality or for external specifications that are not 072 * considered stable or mature enough to be guaranteed to work in an 073 * interoperable way with other types of LDAP servers. 074 * </BLOCKQUOTE> 075 * <BR> 076 * The criticality for this control may be either {@code TRUE} or {@code FALSE}, 077 * but this will only impact how the delete request is to be handled by servers 078 * which do not support this control. A criticality of {@code TRUE} will cause 079 * any server which does not support this control to reject the request, while 080 * a criticality of {@code FALSE} should cause the request to be processed as if 081 * the control had not been included. 082 * <BR><BR> 083 * The control may optionally have a value. If a value is provided, then it 084 * must be the encoded representation of the following ASN.1 element: 085 * <PRE> 086 * SoftDeleteAccessRequestValue ::= SEQUENCE { 087 * includeNonSoftDeletedEntries [0] BOOLEAN DEFAULT TRUE, 088 * returnEntriesInUndeletedForm [1] BOOLEAN DEFAULT FALSE, 089 * ... } 090 * </PRE> 091 * See the documentation for the {@link SoftDeleteRequestControl} class for an 092 * example demonstrating the use of this control. 093 * 094 * @see SoftDeleteResponseControl 095 */ 096@NotMutable() 097@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 098public final class SoftDeletedEntryAccessRequestControl 099 extends Control 100{ 101 /** 102 * The OID (1.3.6.1.4.1.30221.2.5.24) for the soft-deleted entry access 103 * request control. 104 */ 105 public static final String SOFT_DELETED_ENTRY_ACCESS_REQUEST_OID = 106 "1.3.6.1.4.1.30221.2.5.24"; 107 108 109 110 /** 111 * The BER type for the include non-soft-deleted entries element. 112 */ 113 private static final byte TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES = (byte) 0x80; 114 115 116 117 /** 118 * The BER type for the return entries in undeleted form element. 119 */ 120 private static final byte TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM = (byte) 0x81; 121 122 123 124 /** 125 * The serial version UID for this serializable class. 126 */ 127 private static final long serialVersionUID = -3633807543861389512L; 128 129 130 131 // Indicates whether to include non-soft-deleted entries in search results. 132 private final boolean includeNonSoftDeletedEntries; 133 134 // Indicates whether to return soft-deleted entries in the form they appeared 135 // before they were deleted. 136 private final boolean returnEntriesInUndeletedForm; 137 138 139 140 /** 141 * Creates a new soft-deleted entry access request control with the default 142 * settings for all elements. It will not be marked critical. 143 */ 144 public SoftDeletedEntryAccessRequestControl() 145 { 146 this(false, true, false); 147 } 148 149 150 151 /** 152 * Creates a new soft delete request control with the provided information. 153 * 154 * @param isCritical Indicates whether this control should 155 * be marked critical. This will only 156 * have an effect on the way the 157 * associated delete operation is 158 * handled by servers which do NOT 159 * support the soft-deleted entry access 160 * request control. For such servers, a 161 * control that is critical will cause 162 * associated request to be rejected, 163 * while a control that is not critical 164 * will be processed as if the control 165 * was not included in the request. 166 * @param includeNonSoftDeletedEntries Indicates whether search results 167 * should include non-soft-deleted 168 * entries if they match the criteria 169 * for the associated search request. 170 * @param returnEntriesInUndeletedForm Indicates whether soft-deleted 171 * entries returned in search results 172 * should be returned in the form in 173 * which they would appear if they were 174 * undeleted. Note that if soft-deleted 175 * entries should be returned in their 176 * undeleted form, then it may be 177 * possible for multiple entries to be 178 * returned with the same DN (if 179 * multiple soft-deleted entries with 180 * the same original DN match the 181 * criteria, or if at least one 182 * soft-deleted entry and one normal 183 * entry with the same DN both match the 184 * search criteria). 185 */ 186 public SoftDeletedEntryAccessRequestControl(final boolean isCritical, 187 final boolean includeNonSoftDeletedEntries, 188 final boolean returnEntriesInUndeletedForm) 189 { 190 super(SOFT_DELETED_ENTRY_ACCESS_REQUEST_OID, isCritical, 191 encodeValue(includeNonSoftDeletedEntries, 192 returnEntriesInUndeletedForm)); 193 194 this.includeNonSoftDeletedEntries = includeNonSoftDeletedEntries; 195 this.returnEntriesInUndeletedForm = returnEntriesInUndeletedForm; 196 } 197 198 199 200 /** 201 * Creates a new soft-deleted entry access request control which is decoded 202 * from the provided generic control. 203 * 204 * @param control The generic control to be decoded as a soft-deleted entry 205 * access request control. 206 * 207 * @throws LDAPException If the provided control cannot be decoded as a 208 * soft-deleted entry access request control. 209 */ 210 public SoftDeletedEntryAccessRequestControl(final Control control) 211 throws LDAPException 212 { 213 super(control); 214 215 boolean includeNonSoftDeleted = true; 216 boolean returnAsUndeleted = false; 217 218 if (control.hasValue()) 219 { 220 try 221 { 222 final ASN1Sequence valueSequence = 223 ASN1Sequence.decodeAsSequence(control.getValue().getValue()); 224 for (final ASN1Element e : valueSequence.elements()) 225 { 226 switch (e.getType()) 227 { 228 case TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES: 229 includeNonSoftDeleted = 230 ASN1Boolean.decodeAsBoolean(e).booleanValue(); 231 break; 232 case TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM: 233 returnAsUndeleted = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 234 break; 235 default: 236 throw new LDAPException(ResultCode.DECODING_ERROR, 237 ERR_SOFT_DELETED_ACCESS_REQUEST_UNSUPPORTED_ELEMENT_TYPE.get( 238 StaticUtils.toHex(e.getType()))); 239 } 240 } 241 } 242 catch (final LDAPException le) 243 { 244 Debug.debugException(le); 245 throw le; 246 } 247 catch (final Exception e) 248 { 249 Debug.debugException(e); 250 throw new LDAPException(ResultCode.DECODING_ERROR, 251 ERR_SOFT_DELETED_ACCESS_REQUEST_CANNOT_DECODE_VALUE.get( 252 StaticUtils.getExceptionMessage(e)), 253 e); 254 } 255 } 256 257 includeNonSoftDeletedEntries = includeNonSoftDeleted; 258 returnEntriesInUndeletedForm = returnAsUndeleted; 259 } 260 261 262 263 /** 264 * Encodes the provided information into an ASN.1 octet string suitable for 265 * use as the value of a soft-deleted entry access request control. 266 * 267 * @param includeNonSoftDeletedEntries Indicates whether search results 268 * should include non-soft-deleted 269 * entries if they match the criteria 270 * for the associated search request. 271 * @param returnEntriesInUndeletedForm Indicates whether soft-deleted 272 * entries returned in search results 273 * should be returned in the form in 274 * which they would appear if they were 275 * undeleted. Note that if soft-deleted 276 * entries should be returned in their 277 * undeleted form, then it may be 278 * possible for multiple entries to be 279 * returned with the same DN (if 280 * multiple soft-deleted entries with 281 * the same original DN match the 282 * criteria, or if at least one 283 * soft-deleted entry and one normal 284 * entry with the same DN both match the 285 * search criteria). 286 * 287 * @return An ASN.1 octet string with an encoding suitable for use as the 288 * value of a soft-deleted entry access request control, or 289 * {@code null} if no value is needed for the control. 290 */ 291 private static ASN1OctetString encodeValue( 292 final boolean includeNonSoftDeletedEntries, 293 final boolean returnEntriesInUndeletedForm) 294 { 295 if (includeNonSoftDeletedEntries && (! returnEntriesInUndeletedForm)) 296 { 297 return null; 298 } 299 300 final ArrayList<ASN1Element> elements = new ArrayList<>(2); 301 if (! includeNonSoftDeletedEntries) 302 { 303 elements.add(new ASN1Boolean(TYPE_INCLUDE_NON_SOFT_DELETED_ENTRIES, 304 false)); 305 } 306 307 if (returnEntriesInUndeletedForm) 308 { 309 elements.add(new ASN1Boolean(TYPE_RETURN_ENTRIES_IN_UNDELETED_FORM, 310 true)); 311 } 312 313 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 314 } 315 316 317 318 /** 319 * Indicates whether search results should include non-soft-deleted entries 320 * if they match the criteria for the associated search request. 321 * 322 * @return {@code true} if the server should return any "normal" 323 * non-soft-deleted entries that match the search criteria, or 324 * {@code false} if the server should only return soft-deleted 325 * entries that match the search criteria. 326 */ 327 public boolean includeNonSoftDeletedEntries() 328 { 329 return includeNonSoftDeletedEntries; 330 } 331 332 333 334 /** 335 * Indicates whether soft-deleted entries returned in search results should be 336 * returned in the form in which they would appear if they were undeleted. 337 * Note that if soft-deleted entries should be returned in their undeleted 338 * form, then it may be possible for multiple entries to be returned with the 339 * same DN (if multiple soft-deleted entries with the same original DN match 340 * the criteria, or if at least one soft-deleted entry and one normal entry 341 * with the same DN both match the search criteria). 342 * 343 * @return {@code false} if soft-deleted entries should be returned in their 344 * current form as soft-deleted entries, or {@code true} if they 345 * should be returned in the form in which they would appear if they 346 * were undeleted (e.g., using the original DN for the entry and 347 * without all the additional meta-attributes added during the 348 * soft delete process). 349 */ 350 public boolean returnEntriesInUndeletedForm() 351 { 352 return returnEntriesInUndeletedForm; 353 } 354 355 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override() 361 public String getControlName() 362 { 363 return INFO_CONTROL_NAME_SOFT_DELETED_ACCESS_REQUEST.get(); 364 } 365 366 367 368 /** 369 * {@inheritDoc} 370 */ 371 @Override() 372 public void toString(final StringBuilder buffer) 373 { 374 buffer.append("SoftDeletedEntryAccessRequestControl(isCritical="); 375 buffer.append(isCritical()); 376 buffer.append(", includeNonSoftDeletedEntries="); 377 buffer.append(includeNonSoftDeletedEntries); 378 buffer.append(", returnEntriesInUndeletedForm="); 379 buffer.append(returnEntriesInUndeletedForm); 380 buffer.append(')'); 381 } 382}