001/* 002 * Copyright 2007-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-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) 2008-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.controls; 037 038 039 040import com.unboundid.asn1.ASN1Element; 041import com.unboundid.asn1.ASN1OctetString; 042import com.unboundid.asn1.ASN1Sequence; 043import com.unboundid.ldap.sdk.Control; 044import com.unboundid.ldap.sdk.LDAPException; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.util.Debug; 047import com.unboundid.util.NotMutable; 048import com.unboundid.util.StaticUtils; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.ldap.sdk.controls.ControlMessages.*; 053 054 055 056/** 057 * This class provides an implementation of the LDAP pre-read request control 058 * as defined in <A HREF="http://www.ietf.org/rfc/rfc4527.txt">RFC 4527</A>. It 059 * may be used to request that the server retrieve a copy of the target entry as 060 * it appeared immediately before processing a delete, modify, or modify DN 061 * operation. 062 * <BR><BR> 063 * If this control is included in a delete, modify, or modify DN request, then 064 * the corresponding response may include a {@link PreReadResponseControl} 065 * containing a version of the entry as it before after applying that change. 066 * Note that this response control will only be included if the operation was 067 * successful, so it will not be provided if the operation failed for some 068 * reason (e.g., if the change would have violated the server schema, or if the 069 * requester did not have sufficient permission to perform that operation). 070 * <BR><BR> 071 * The value of this control should contain a set of requested attributes to 072 * include in the entry that is returned. The server should treat this set of 073 * requested attributes exactly as it treats the requested attributes from a 074 * {@link com.unboundid.ldap.sdk.SearchRequest}. As is the case with a search 075 * request, if no attributes are specified, then all user attributes will be 076 * included. 077 * <BR><BR> 078 * The use of the LDAP pre-read request control is virtually identical to the 079 * use of the LDAP post-read request control. See the documentation for the 080 * {@link PostReadRequestControl} for an example that illustrates its use. 081 */ 082@NotMutable() 083@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 084public final class PreReadRequestControl 085 extends Control 086{ 087 /** 088 * The OID (1.3.6.1.1.13.1) for the pre-read request control. 089 */ 090 public static final String PRE_READ_REQUEST_OID = "1.3.6.1.1.13.1"; 091 092 093 094 /** 095 * The set of requested attributes that will be used if none are provided. 096 */ 097 private static final String[] NO_ATTRIBUTES = StaticUtils.NO_STRINGS; 098 099 100 101 /** 102 * The serial version UID for this serializable class. 103 */ 104 private static final long serialVersionUID = 1205235290978028739L; 105 106 107 108 // The set of requested attributes to retrieve from the target entry. 109 private final String[] attributes; 110 111 112 113 /** 114 * Creates a new pre-read request control that will retrieve the specified set 115 * of attributes from the target entry. It will be marked critical. 116 * 117 * @param attributes The set of attributes to retrieve from the target 118 * entry. It behaves in the same way as the set of 119 * requested attributes for a search operation. If this 120 * is empty or {@code null}, then all user attributes 121 * will be returned. 122 */ 123 public PreReadRequestControl(final String... attributes) 124 { 125 this(true, attributes); 126 } 127 128 129 130 /** 131 * Creates a new pre-read request control that will retrieve the specified set 132 * of attributes from the target entry. 133 * 134 * @param isCritical Indicates whether this control should be marked 135 * critical. 136 * @param attributes The set of attributes to retrieve from the target 137 * entry. It behaves in the same way as the set of 138 * requested attributes for a search operation. If this 139 * is empty or {@code null}, then all user attributes 140 * will be returned. 141 */ 142 public PreReadRequestControl(final boolean isCritical, 143 final String... attributes) 144 { 145 super(PRE_READ_REQUEST_OID, isCritical, encodeValue(attributes)); 146 147 if (attributes == null) 148 { 149 this.attributes = NO_ATTRIBUTES; 150 } 151 else 152 { 153 this.attributes = attributes; 154 } 155 } 156 157 158 159 /** 160 * Creates a new pre-read request control which is decoded from the provided 161 * generic control. 162 * 163 * @param control The generic control to be decoded as a pre-read request 164 * control. 165 * 166 * @throws LDAPException If the provided control cannot be decoded as a 167 * pre-read request control. 168 */ 169 public PreReadRequestControl(final Control control) 170 throws LDAPException 171 { 172 super(control); 173 174 final ASN1OctetString value = control.getValue(); 175 if (value == null) 176 { 177 throw new LDAPException(ResultCode.DECODING_ERROR, 178 ERR_PRE_READ_REQUEST_NO_VALUE.get()); 179 } 180 181 try 182 { 183 final ASN1Element valueElement = ASN1Element.decode(value.getValue()); 184 final ASN1Element[] attrElements = 185 ASN1Sequence.decodeAsSequence(valueElement).elements(); 186 attributes = new String[attrElements.length]; 187 for (int i=0; i < attrElements.length; i++) 188 { 189 attributes[i] = 190 ASN1OctetString.decodeAsOctetString(attrElements[i]).stringValue(); 191 } 192 } 193 catch (final Exception e) 194 { 195 Debug.debugException(e); 196 throw new LDAPException(ResultCode.DECODING_ERROR, 197 ERR_PRE_READ_REQUEST_CANNOT_DECODE.get(e), e); 198 } 199 } 200 201 202 203 /** 204 * Encodes the provided information into an octet string that can be used as 205 * the value for this control. 206 * 207 * @param attributes The set of attributes to retrieve from the target 208 * entry. It behaves in the same way as the set of 209 * requested attributes for a search operation. If this 210 * is empty or {@code null}, then all user attributes 211 * will be returned. 212 * 213 * @return An ASN.1 octet string that can be used as the value for this 214 * control. 215 */ 216 private static ASN1OctetString encodeValue(final String[] attributes) 217 { 218 if ((attributes == null) || (attributes.length == 0)) 219 { 220 return new ASN1OctetString(new ASN1Sequence().encode()); 221 } 222 223 final ASN1OctetString[] elements = new ASN1OctetString[attributes.length]; 224 for (int i=0; i < attributes.length; i++) 225 { 226 elements[i] = new ASN1OctetString(attributes[i]); 227 } 228 229 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 230 } 231 232 233 234 /** 235 * Retrieves the set of attributes that will be requested for inclusion in the 236 * entry returned in the response control. 237 * 238 * @return The set of attributes that will be requested for inclusion in the 239 * entry returned in the response control, or an empty array if all 240 * user attributes should be returned. 241 */ 242 public String[] getAttributes() 243 { 244 return attributes; 245 } 246 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override() 253 public String getControlName() 254 { 255 return INFO_CONTROL_NAME_PRE_READ_REQUEST.get(); 256 } 257 258 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override() 264 public void toString(final StringBuilder buffer) 265 { 266 buffer.append("PreReadRequestControl(attributes={"); 267 for (int i=0; i < attributes.length; i++) 268 { 269 if (i > 0) 270 { 271 buffer.append(", "); 272 } 273 buffer.append('\''); 274 buffer.append(attributes[i]); 275 buffer.append('\''); 276 } 277 buffer.append("}, isCritical="); 278 buffer.append(isCritical()); 279 buffer.append(')'); 280 } 281}