001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 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 */
021 package com.unboundid.ldap.sdk.controls;
022
023
024
025 import com.unboundid.asn1.ASN1Element;
026 import com.unboundid.asn1.ASN1OctetString;
027 import com.unboundid.asn1.ASN1Sequence;
028 import com.unboundid.ldap.sdk.Control;
029 import com.unboundid.ldap.sdk.LDAPException;
030 import com.unboundid.ldap.sdk.ResultCode;
031 import com.unboundid.util.NotMutable;
032 import com.unboundid.util.StaticUtils;
033 import com.unboundid.util.ThreadSafety;
034 import com.unboundid.util.ThreadSafetyLevel;
035
036 import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
037 import 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)
069 public 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 }