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