001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.controls;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033
034 import org.opends.server.protocols.asn1.ASN1Element;
035 import org.opends.server.protocols.asn1.ASN1Enumerated;
036 import org.opends.server.protocols.asn1.ASN1Integer;
037 import org.opends.server.protocols.asn1.ASN1OctetString;
038 import org.opends.server.protocols.asn1.ASN1Sequence;
039 import org.opends.server.protocols.ldap.LDAPResultCode;
040 import org.opends.server.types.ByteString;
041 import org.opends.server.types.Control;
042 import org.opends.server.types.LDAPException;
043
044 import static org.opends.messages.ProtocolMessages.*;
045 import static org.opends.server.util.ServerConstants.*;
046 import static org.opends.server.util.StaticUtils.*;
047
048
049
050 /**
051 * This class implements the virtual list view response controls as defined in
052 * draft-ietf-ldapext-ldapv3-vlv. The ASN.1 description for the control value
053 * is:
054 * <BR><BR>
055 * <PRE>
056 * VirtualListViewResponse ::= SEQUENCE {
057 * targetPosition INTEGER (0 .. maxInt),
058 * contentCount INTEGER (0 .. maxInt),
059 * virtualListViewResult ENUMERATED {
060 * success (0),
061 * operationsError (1),
062 * protocolError (3),
063 * unwillingToPerform (53),
064 * insufficientAccessRights (50),
065 * timeLimitExceeded (3),
066 * adminLimitExceeded (11),
067 * innapropriateMatching (18),
068 * sortControlMissing (60),
069 * offsetRangeError (61),
070 * other(80),
071 * ... },
072 * contextID OCTET STRING OPTIONAL }
073 * </PRE>
074 */
075 public class VLVResponseControl
076 extends Control
077 {
078 // The context ID for this VLV response control.
079 private ByteString contextID;
080
081 // The content count estimating the total number of entries in the result set.
082 private int contentCount;
083
084 // The offset of the target entry in the result set.
085 private int targetPosition;
086
087 // The result code for the VLV operation.
088 private int vlvResultCode;
089
090
091
092 /**
093 * Creates a new VLV response control with the provided information.
094 *
095 * @param targetPosition The position of the target entry in the result set.
096 * @param contentCount The content count estimating the total number of
097 * entries in the result set.
098 * @param vlvResultCode The result code for the VLV operation.
099 */
100 public VLVResponseControl(int targetPosition, int contentCount,
101 int vlvResultCode)
102 {
103 this(targetPosition, contentCount, vlvResultCode, null);
104 }
105
106
107
108 /**
109 * Creates a new VLV response control with the provided information.
110 *
111 * @param targetPosition The position of the target entry in the result set.
112 * @param contentCount The content count estimating the total number of
113 * entries in the result set.
114 * @param vlvResultCode The result code for the VLV operation.
115 * @param contextID The context ID for this VLV response control.
116 */
117 public VLVResponseControl(int targetPosition, int contentCount,
118 int vlvResultCode, ByteString contextID)
119 {
120 super(OID_VLV_RESPONSE_CONTROL, false,
121 encodeControlValue(targetPosition, contentCount, vlvResultCode,
122 contextID));
123
124 this.targetPosition = targetPosition;
125 this.contentCount = contentCount;
126 this.vlvResultCode = vlvResultCode;
127 this.contextID = contextID;
128 }
129
130
131
132 /**
133 * Creates a new VLV response control with the provided information.
134 *
135 * @param oid The OID for the control.
136 * @param isCritical Indicates whether the control should be considered
137 * critical.
138 * @param controlValue The pre-encoded value for the control.
139 * @param targetPosition The position of the target entry in the result set.
140 * @param contentCount The content count estimating the total number of
141 * entries in the result set.
142 * @param vlvResultCode The result code for the VLV operation.
143 * @param contextID The context ID for this VLV response control.
144 */
145 private VLVResponseControl(String oid, boolean isCritical,
146 ASN1OctetString controlValue, int targetPosition,
147 int contentCount, int vlvResultCode,
148 ByteString contextID)
149 {
150 super(oid, isCritical, controlValue);
151
152 this.targetPosition = targetPosition;
153 this.contentCount = contentCount;
154 this.vlvResultCode = vlvResultCode;
155 this.contextID = contextID;
156 }
157
158
159
160 /**
161 * Retrieves the position of the target entry in the result set.
162 *
163 * @return The position of the target entry in the result set.
164 */
165 public int getTargetPosition()
166 {
167 return targetPosition;
168 }
169
170
171
172 /**
173 * Retrieves the estimated total number of entries in the result set.
174 *
175 * @return The estimated total number of entries in the result set.
176 */
177 public int getContentCount()
178 {
179 return contentCount;
180 }
181
182
183
184 /**
185 * Retrieves the result code for the VLV operation.
186 *
187 * @return The result code for the VLV operation.
188 */
189 public int getVLVResultCode()
190 {
191 return vlvResultCode;
192 }
193
194
195
196 /**
197 * Retrieves a context ID value that should be included in the next request
198 * to retrieve a page of the same result set.
199 *
200 * @return A context ID value that should be included in the next request to
201 * retrieve a page of the same result set, or {@code null} if there
202 * is no context ID.
203 */
204 public ByteString getContextID()
205 {
206 return contextID;
207 }
208
209
210
211 /**
212 * Encodes the provided information in a manner suitable for use as the value
213 * of this control.
214 *
215 * @param targetPosition The position of the target entry in the result set.
216 * @param contentCount The content count estimating the total number of
217 * entries in the result set.
218 * @param vlvResultCode The result code for the VLV operation.
219 * @param contextID The context ID for this VLV response control.
220 *
221 * @return The ASN.1 octet string containing the encoded sort order.
222 */
223 private static ASN1OctetString encodeControlValue(int targetPosition,
224 int contentCount, int vlvResultCode,
225 ByteString contextID)
226 {
227 ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4);
228 vlvElements.add(new ASN1Integer(targetPosition));
229 vlvElements.add(new ASN1Integer(contentCount));
230 vlvElements.add(new ASN1Enumerated(vlvResultCode));
231
232 if (contextID != null)
233 {
234 vlvElements.add(contextID.toASN1OctetString());
235 }
236
237 return new ASN1OctetString(new ASN1Sequence(vlvElements).encode());
238 }
239
240
241
242 /**
243 * Creates a new VLV response control from the contents of the provided
244 * control.
245 *
246 * @param control The generic control containing the information to use to
247 * create this VLV response control. It must not be
248 * {@code null}.
249 *
250 * @return The VLV response control decoded from the provided control.
251 *
252 * @throws LDAPException If this control cannot be decoded as a valid VLV
253 * response control.
254 */
255 public static VLVResponseControl decodeControl(Control control)
256 throws LDAPException
257 {
258 ASN1OctetString controlValue = control.getValue();
259 if (controlValue == null)
260 {
261 Message message = INFO_VLVRES_CONTROL_NO_VALUE.get();
262 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
263 }
264
265 try
266 {
267 ASN1Sequence vlvSequence =
268 ASN1Sequence.decodeAsSequence(controlValue.value());
269 ArrayList<ASN1Element> elements = vlvSequence.elements();
270
271 if ((elements.size() < 3) || (elements.size() > 4))
272 {
273 Message message =
274 INFO_VLVRES_CONTROL_INVALID_ELEMENT_COUNT.get(elements.size());
275 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
276 }
277
278 int targetPosition = elements.get(0).decodeAsInteger().intValue();
279 int contentCount = elements.get(1).decodeAsInteger().intValue();
280 int vlvResultCode = elements.get(2).decodeAsEnumerated().intValue();
281
282 ASN1OctetString contextID = null;
283 if (elements.size() == 4)
284 {
285 contextID = elements.get(3).decodeAsOctetString();
286 }
287
288 return new VLVResponseControl(control.getOID(), control.isCritical(),
289 controlValue, targetPosition, contentCount,
290 vlvResultCode, contextID);
291 }
292 catch (LDAPException le)
293 {
294 throw le;
295 }
296 catch (Exception e)
297 {
298 Message message =
299 INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
300 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
301 }
302 }
303
304
305
306 /**
307 * Retrieves a string representation of this VLV request control.
308 *
309 * @return A string representation of this VLV request control.
310 */
311 public String toString()
312 {
313 StringBuilder buffer = new StringBuilder();
314 toString(buffer);
315 return buffer.toString();
316 }
317
318
319
320 /**
321 * Appends a string representation of this VLV request control to the provided
322 * buffer.
323 *
324 * @param buffer The buffer to which the information should be appended.
325 */
326 public void toString(StringBuilder buffer)
327 {
328 buffer.append("VLVResponseControl(targetPosition=");
329 buffer.append(targetPosition);
330 buffer.append(", contentCount=");
331 buffer.append(contentCount);
332 buffer.append(", vlvResultCode=");
333 buffer.append(vlvResultCode);
334
335 if (contextID != null)
336 {
337 buffer.append(", contextID=");
338 buffer.append(contextID);
339 }
340
341 buffer.append(")");
342 }
343 }
344