001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.controls; 018import org.forgerock.i18n.LocalizableMessage; 019 020 021import java.io.IOException; 022 023import org.forgerock.opendj.io.*; 024import org.opends.server.types.Control; 025import org.opends.server.types.DirectoryException; 026import org.forgerock.opendj.ldap.ByteString; 027import org.forgerock.opendj.ldap.ResultCode; 028 029import static org.opends.messages.ProtocolMessages.*; 030import static org.opends.server.util.ServerConstants.*; 031import static org.opends.server.util.StaticUtils.*; 032 033 034 035/** 036 * This class implements the virtual list view request controls as defined in 037 * draft-ietf-ldapext-ldapv3-vlv. The ASN.1 description for the control value 038 * is: 039 * <BR><BR> 040 * <PRE> 041 * VirtualListViewRequest ::= SEQUENCE { 042 * beforeCount INTEGER (0..maxInt), 043 * afterCount INTEGER (0..maxInt), 044 * target CHOICE { 045 * byOffset [0] SEQUENCE { 046 * offset INTEGER (1 .. maxInt), 047 * contentCount INTEGER (0 .. maxInt) }, 048 * greaterThanOrEqual [1] AssertionValue }, 049 * contextID OCTET STRING OPTIONAL } 050 * </PRE> 051 */ 052public class VLVRequestControl 053 extends Control 054{ 055 /** ControlDecoder implementation to decode this control from a ByteString. */ 056 private static final class Decoder 057 implements ControlDecoder<VLVRequestControl> 058 { 059 @Override 060 public VLVRequestControl decode(boolean isCritical, ByteString value) 061 throws DirectoryException 062 { 063 if (value == null) 064 { 065 LocalizableMessage message = INFO_VLVREQ_CONTROL_NO_VALUE.get(); 066 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 067 } 068 069 ASN1Reader reader = ASN1.getReader(value); 070 try 071 { 072 reader.readStartSequence(); 073 074 int beforeCount = (int)reader.readInteger(); 075 int afterCount = (int)reader.readInteger(); 076 077 int offset = 0; 078 int contentCount = 0; 079 ByteString greaterThanOrEqual = null; 080 byte targetType = reader.peekType(); 081 switch (targetType) 082 { 083 case TYPE_TARGET_BYOFFSET: 084 reader.readStartSequence(); 085 offset = (int)reader.readInteger(); 086 contentCount = (int)reader.readInteger(); 087 reader.readEndSequence(); 088 break; 089 090 case TYPE_TARGET_GREATERTHANOREQUAL: 091 greaterThanOrEqual = reader.readOctetString(); 092 break; 093 094 default: 095 LocalizableMessage message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE.get( 096 byteToHex(targetType)); 097 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 098 } 099 100 ByteString contextID = null; 101 if (reader.hasNextElement()) 102 { 103 contextID = reader.readOctetString(); 104 } 105 106 if(targetType == TYPE_TARGET_BYOFFSET) 107 { 108 return new VLVRequestControl(isCritical, beforeCount, 109 afterCount, offset, contentCount, contextID); 110 } 111 112 return new VLVRequestControl(isCritical, beforeCount, 113 afterCount, greaterThanOrEqual, contextID); 114 } 115 catch (DirectoryException de) 116 { 117 throw de; 118 } 119 catch (Exception e) 120 { 121 LocalizableMessage message = 122 INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e)); 123 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 124 } 125 } 126 127 @Override 128 public String getOID() 129 { 130 return OID_VLV_REQUEST_CONTROL; 131 } 132 133 } 134 135 /** The Control Decoder that can be used to decode this control. */ 136 public static final ControlDecoder<VLVRequestControl> DECODER = 137 new Decoder(); 138 139 /** The BER type to use when encoding the byOffset target element. */ 140 public static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0; 141 142 143 144 /** The BER type to use when encoding the greaterThanOrEqual target element. */ 145 public static final byte TYPE_TARGET_GREATERTHANOREQUAL = (byte) 0x81; 146 147 148 149 /** The target type for this VLV request control. */ 150 private byte targetType; 151 152 /** The context ID for this VLV request control. */ 153 private ByteString contextID; 154 155 /** The greaterThanOrEqual target assertion value for this VLV request control. */ 156 private ByteString greaterThanOrEqual; 157 158 /** The after count for this VLV request control. */ 159 private int afterCount; 160 161 /** The before count for this VLV request control. */ 162 private int beforeCount; 163 164 /** The content count for the byOffset target of this VLV request control. */ 165 private int contentCount; 166 167 /** The offset for the byOffset target of this VLV request control. */ 168 private int offset; 169 170 171 172 /** 173 * Creates a new VLV request control with the provided information. 174 * 175 * @param beforeCount The number of entries before the target offset to 176 * retrieve in the results page. 177 * @param afterCount The number of entries after the target offset to 178 * retrieve in the results page. 179 * @param offset The offset in the result set to target for the 180 * beginning of the page of results. 181 * @param contentCount The content count returned by the server in the last 182 * phase of the VLV request, or zero for a new VLV 183 * request session. 184 */ 185 public VLVRequestControl(int beforeCount, int afterCount, int offset, 186 int contentCount) 187 { 188 this(false, beforeCount, afterCount, offset, contentCount, null); 189 } 190 191 192 193 /** 194 * Creates a new VLV request control with the provided information. 195 * 196 * @param isCritical Indicates whether the control is critical. 197 * @param beforeCount The number of entries before the target offset to 198 * retrieve in the results page. 199 * @param afterCount The number of entries after the target offset to 200 * retrieve in the results page. 201 * @param offset The offset in the result set to target for the 202 * beginning of the page of results. 203 * @param contentCount The content count returned by the server in the last 204 * phase of the VLV request, or zero for a new VLV 205 * request session. 206 * @param contextID The context ID provided by the server in the last 207 * VLV response for the same set of criteria, or 208 * {@code null} if there was no previous VLV response or 209 * the server did not include a context ID in the 210 * last response. 211 */ 212 public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount, 213 int offset, int contentCount, ByteString contextID) 214 { 215 super(OID_VLV_REQUEST_CONTROL, isCritical); 216 217 this.beforeCount = beforeCount; 218 this.afterCount = afterCount; 219 this.offset = offset; 220 this.contentCount = contentCount; 221 this.contextID = contextID; 222 223 targetType = TYPE_TARGET_BYOFFSET; 224 } 225 226 227 228 /** 229 * Creates a new VLV request control with the provided information. 230 * 231 * @param beforeCount The number of entries before the target offset 232 * to retrieve in the results page. 233 * @param afterCount The number of entries after the target offset 234 * to retrieve in the results page. 235 * @param greaterThanOrEqual The greaterThanOrEqual target assertion value 236 * that indicates where to start the page of 237 * results. 238 */ 239 public VLVRequestControl(int beforeCount, int afterCount, 240 ByteString greaterThanOrEqual) 241 { 242 this(false, beforeCount, afterCount, greaterThanOrEqual, null); 243 } 244 245 246 247 /** 248 * Creates a new VLV request control with the provided information. 249 * 250 * @param isCritical Indicates whether the control should be 251 * considered critical. 252 * @param beforeCount The number of entries before the target 253 * assertion value. 254 * @param afterCount The number of entries after the target 255 * assertion value. 256 * @param greaterThanOrEqual The greaterThanOrEqual target assertion value 257 * that indicates where to start the page of 258 * results. 259 * @param contextID The context ID provided by the server in the 260 * last VLV response for the same set of criteria, 261 * or {@code null} if there was no previous VLV 262 * response or the server did not include a 263 * context ID in the last response. 264 */ 265 public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount, 266 ByteString greaterThanOrEqual, 267 ByteString contextID) 268 { 269 super(OID_VLV_REQUEST_CONTROL, isCritical); 270 271 this.beforeCount = beforeCount; 272 this.afterCount = afterCount; 273 this.greaterThanOrEqual = greaterThanOrEqual; 274 this.contextID = contextID; 275 276 targetType = TYPE_TARGET_GREATERTHANOREQUAL; 277 } 278 279 280 281 /** 282 * Retrieves the number of entries before the target offset or assertion value 283 * to include in the results page. 284 * 285 * @return The number of entries before the target offset to include in the 286 * results page. 287 */ 288 public int getBeforeCount() 289 { 290 return beforeCount; 291 } 292 293 294 295 /** 296 * Retrieves the number of entries after the target offset or assertion value 297 * to include in the results page. 298 * 299 * @return The number of entries after the target offset to include in the 300 * results page. 301 */ 302 public int getAfterCount() 303 { 304 return afterCount; 305 } 306 307 308 309 /** 310 * Retrieves the BER type for the target that specifies the beginning of the 311 * results page. 312 * 313 * @return {@code TYPE_TARGET_BYOFFSET} if the beginning of the results page 314 * should be specified as a nuemric offset, or 315 * {@code TYPE_TARGET_GREATERTHANOREQUAL} if it should be specified 316 * by an assertion value. 317 */ 318 public byte getTargetType() 319 { 320 return targetType; 321 } 322 323 324 325 /** 326 * Retrieves the offset that indicates the beginning of the results page. The 327 * return value will only be applicable if the {@code getTargetType} method 328 * returns {@code TYPE_TARGET_BYOFFSET}. 329 * 330 * @return The offset that indicates the beginning of the results page. 331 */ 332 public int getOffset() 333 { 334 return offset; 335 } 336 337 338 339 /** 340 * Retrieves the content count indicating the estimated number of entries in 341 * the complete result set. The return value will only be applicable if the 342 * {@code getTargetType} method returns {@code TYPE_TARGET_BYOFFSET}. 343 * 344 * @return The content count indicating the estimated number of entries in 345 * the complete result set. 346 */ 347 public int getContentCount() 348 { 349 return contentCount; 350 } 351 352 353 354 /** 355 * Retrieves the assertion value that will be used to locate the beginning of 356 * the results page. This will only be applicable if the 357 * {@code getTargetType} method returns 358 * {@code TYPE_TARGET_GREATERTHANOREQUAL}. 359 * 360 * @return The assertion value that will be used to locate the beginning of 361 * the results page, or {@code null} if the beginning of the results 362 * page is to be specified using an offset. 363 */ 364 public ByteString getGreaterThanOrEqualAssertion() 365 { 366 return greaterThanOrEqual; 367 } 368 369 370 371 /** 372 * Retrieves a context ID value that should be used to resume a previous VLV 373 * results session. 374 * 375 * @return A context ID value that should be used to resume a previous VLV 376 * results session, or {@code null} if none is available. 377 */ 378 public ByteString getContextID() 379 { 380 return contextID; 381 } 382 383 384 385 /** 386 * Writes this control's value to an ASN.1 writer. The value (if any) must be 387 * written as an ASN1OctetString. 388 * 389 * @param writer The ASN.1 writer to use. 390 * @throws IOException If a problem occurs while writing to the stream. 391 */ 392 @Override 393 protected void writeValue(ASN1Writer writer) throws IOException { 394 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 395 396 writer.writeStartSequence(); 397 writer.writeInteger(beforeCount); 398 writer.writeInteger(afterCount); 399 if(targetType == TYPE_TARGET_BYOFFSET) 400 { 401 writer.writeStartSequence(TYPE_TARGET_BYOFFSET); 402 writer.writeInteger(offset); 403 writer.writeInteger(contentCount); 404 writer.writeEndSequence(); 405 } 406 else 407 { 408 writer.writeOctetString(TYPE_TARGET_GREATERTHANOREQUAL, 409 greaterThanOrEqual); 410 } 411 if (contextID != null) 412 { 413 writer.writeOctetString(contextID); 414 } 415 writer.writeEndSequence(); 416 417 writer.writeEndSequence(); 418 } 419 420 421 422 /** 423 * Appends a string representation of this VLV request control to the provided 424 * buffer. 425 * 426 * @param buffer The buffer to which the information should be appended. 427 */ 428 @Override 429 public void toString(StringBuilder buffer) 430 { 431 buffer.append("VLVRequestControl(beforeCount="); 432 buffer.append(beforeCount); 433 buffer.append(", afterCount="); 434 buffer.append(afterCount); 435 436 if (targetType == TYPE_TARGET_BYOFFSET) 437 { 438 buffer.append(", offset="); 439 buffer.append(offset); 440 buffer.append(", contentCount="); 441 buffer.append(contentCount); 442 } 443 else 444 { 445 buffer.append(", greaterThanOrEqual="); 446 buffer.append(greaterThanOrEqual); 447 } 448 449 if (contextID != null) 450 { 451 buffer.append(", contextID="); 452 buffer.append(contextID); 453 } 454 455 buffer.append(")"); 456 } 457} 458