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-2015 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 /** 056 * ControlDecoder implementation to decode this control from a ByteString. 057 */ 058 private static final class Decoder 059 implements ControlDecoder<VLVRequestControl> 060 { 061 /** {@inheritDoc} */ 062 public VLVRequestControl decode(boolean isCritical, ByteString value) 063 throws DirectoryException 064 { 065 if (value == null) 066 { 067 LocalizableMessage message = INFO_VLVREQ_CONTROL_NO_VALUE.get(); 068 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 069 } 070 071 ASN1Reader reader = ASN1.getReader(value); 072 try 073 { 074 reader.readStartSequence(); 075 076 int beforeCount = (int)reader.readInteger(); 077 int afterCount = (int)reader.readInteger(); 078 079 int offset = 0; 080 int contentCount = 0; 081 ByteString greaterThanOrEqual = null; 082 byte targetType = reader.peekType(); 083 switch (targetType) 084 { 085 case TYPE_TARGET_BYOFFSET: 086 reader.readStartSequence(); 087 offset = (int)reader.readInteger(); 088 contentCount = (int)reader.readInteger(); 089 reader.readEndSequence(); 090 break; 091 092 case TYPE_TARGET_GREATERTHANOREQUAL: 093 greaterThanOrEqual = reader.readOctetString(); 094 break; 095 096 default: 097 LocalizableMessage message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE.get( 098 byteToHex(targetType)); 099 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 100 } 101 102 ByteString contextID = null; 103 if (reader.hasNextElement()) 104 { 105 contextID = reader.readOctetString(); 106 } 107 108 if(targetType == TYPE_TARGET_BYOFFSET) 109 { 110 return new VLVRequestControl(isCritical, beforeCount, 111 afterCount, offset, contentCount, contextID); 112 } 113 114 return new VLVRequestControl(isCritical, beforeCount, 115 afterCount, greaterThanOrEqual, contextID); 116 } 117 catch (DirectoryException de) 118 { 119 throw de; 120 } 121 catch (Exception e) 122 { 123 LocalizableMessage message = 124 INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e)); 125 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 126 } 127 } 128 129 public String getOID() 130 { 131 return OID_VLV_REQUEST_CONTROL; 132 } 133 134 } 135 136 /** 137 * The Control Decoder that can be used to decode this control. 138 */ 139 public static final ControlDecoder<VLVRequestControl> DECODER = 140 new Decoder(); 141 142 /** 143 * The BER type to use when encoding the byOffset target element. 144 */ 145 public static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0; 146 147 148 149 /** 150 * The BER type to use when encoding the greaterThanOrEqual target element. 151 */ 152 public static final byte TYPE_TARGET_GREATERTHANOREQUAL = (byte) 0x81; 153 154 155 156 /** The target type for this VLV request control. */ 157 private byte targetType; 158 159 /** The context ID for this VLV request control. */ 160 private ByteString contextID; 161 162 /** The greaterThanOrEqual target assertion value for this VLV request control. */ 163 private ByteString greaterThanOrEqual; 164 165 /** The after count for this VLV request control. */ 166 private int afterCount; 167 168 /** The before count for this VLV request control. */ 169 private int beforeCount; 170 171 /** The content count for the byOffset target of this VLV request control. */ 172 private int contentCount; 173 174 /** The offset for the byOffset target of this VLV request control. */ 175 private int offset; 176 177 178 179 /** 180 * Creates a new VLV request control with the provided information. 181 * 182 * @param beforeCount The number of entries before the target offset to 183 * retrieve in the results page. 184 * @param afterCount The number of entries after the target offset to 185 * retrieve in the results page. 186 * @param offset The offset in the result set to target for the 187 * beginning of the page of results. 188 * @param contentCount The content count returned by the server in the last 189 * phase of the VLV request, or zero for a new VLV 190 * request session. 191 */ 192 public VLVRequestControl(int beforeCount, int afterCount, int offset, 193 int contentCount) 194 { 195 this(false, beforeCount, afterCount, offset, contentCount, null); 196 } 197 198 199 200 /** 201 * Creates a new VLV request control with the provided information. 202 * 203 * @param isCritical Indicates whether or not the control is critical. 204 * @param beforeCount The number of entries before the target offset to 205 * retrieve in the results page. 206 * @param afterCount The number of entries after the target offset to 207 * retrieve in the results page. 208 * @param offset The offset in the result set to target for the 209 * beginning of the page of results. 210 * @param contentCount The content count returned by the server in the last 211 * phase of the VLV request, or zero for a new VLV 212 * request session. 213 * @param contextID The context ID provided by the server in the last 214 * VLV response for the same set of criteria, or 215 * {@code null} if there was no previous VLV response or 216 * the server did not include a context ID in the 217 * last response. 218 */ 219 public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount, 220 int offset, int contentCount, ByteString contextID) 221 { 222 super(OID_VLV_REQUEST_CONTROL, isCritical); 223 224 this.beforeCount = beforeCount; 225 this.afterCount = afterCount; 226 this.offset = offset; 227 this.contentCount = contentCount; 228 this.contextID = contextID; 229 230 targetType = TYPE_TARGET_BYOFFSET; 231 } 232 233 234 235 /** 236 * Creates a new VLV request control with the provided information. 237 * 238 * @param beforeCount The number of entries before the target offset 239 * to retrieve in the results page. 240 * @param afterCount The number of entries after the target offset 241 * to retrieve in the results page. 242 * @param greaterThanOrEqual The greaterThanOrEqual target assertion value 243 * that indicates where to start the page of 244 * results. 245 */ 246 public VLVRequestControl(int beforeCount, int afterCount, 247 ByteString greaterThanOrEqual) 248 { 249 this(false, beforeCount, afterCount, greaterThanOrEqual, null); 250 } 251 252 253 254 /** 255 * Creates a new VLV request control with the provided information. 256 * 257 * @param isCritical Indicates whether the control should be 258 * considered critical. 259 * @param beforeCount The number of entries before the target 260 * assertion value. 261 * @param afterCount The number of entries after the target 262 * assertion value. 263 * @param greaterThanOrEqual The greaterThanOrEqual target assertion value 264 * that indicates where to start the page of 265 * results. 266 * @param contextID The context ID provided by the server in the 267 * last VLV response for the same set of criteria, 268 * or {@code null} if there was no previous VLV 269 * response or the server did not include a 270 * context ID in the last response. 271 */ 272 public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount, 273 ByteString greaterThanOrEqual, 274 ByteString contextID) 275 { 276 super(OID_VLV_REQUEST_CONTROL, isCritical); 277 278 this.beforeCount = beforeCount; 279 this.afterCount = afterCount; 280 this.greaterThanOrEqual = greaterThanOrEqual; 281 this.contextID = contextID; 282 283 targetType = TYPE_TARGET_GREATERTHANOREQUAL; 284 } 285 286 287 288 /** 289 * Retrieves the number of entries before the target offset or assertion value 290 * to include in the results page. 291 * 292 * @return The number of entries before the target offset to include in the 293 * results page. 294 */ 295 public int getBeforeCount() 296 { 297 return beforeCount; 298 } 299 300 301 302 /** 303 * Retrieves the number of entries after the target offset or assertion value 304 * to include in the results page. 305 * 306 * @return The number of entries after the target offset to include in the 307 * results page. 308 */ 309 public int getAfterCount() 310 { 311 return afterCount; 312 } 313 314 315 316 /** 317 * Retrieves the BER type for the target that specifies the beginning of the 318 * results page. 319 * 320 * @return {@code TYPE_TARGET_BYOFFSET} if the beginning of the results page 321 * should be specified as a nuemric offset, or 322 * {@code TYPE_TARGET_GREATERTHANOREQUAL} if it should be specified 323 * by an assertion value. 324 */ 325 public byte getTargetType() 326 { 327 return targetType; 328 } 329 330 331 332 /** 333 * Retrieves the offset that indicates the beginning of the results page. The 334 * return value will only be applicable if the {@code getTargetType} method 335 * returns {@code TYPE_TARGET_BYOFFSET}. 336 * 337 * @return The offset that indicates the beginning of the results page. 338 */ 339 public int getOffset() 340 { 341 return offset; 342 } 343 344 345 346 /** 347 * Retrieves the content count indicating the estimated number of entries in 348 * the complete result set. The return value will only be applicable if the 349 * {@code getTargetType} method returns {@code TYPE_TARGET_BYOFFSET}. 350 * 351 * @return The content count indicating the estimated number of entries in 352 * the complete result set. 353 */ 354 public int getContentCount() 355 { 356 return contentCount; 357 } 358 359 360 361 /** 362 * Retrieves the assertion value that will be used to locate the beginning of 363 * the results page. This will only be applicable if the 364 * {@code getTargetType} method returns 365 * {@code TYPE_TARGET_GREATERTHANOREQUAL}. 366 * 367 * @return The assertion value that will be used to locate the beginning of 368 * the results page, or {@code null} if the beginning of the results 369 * page is to be specified using an offset. 370 */ 371 public ByteString getGreaterThanOrEqualAssertion() 372 { 373 return greaterThanOrEqual; 374 } 375 376 377 378 /** 379 * Retrieves a context ID value that should be used to resume a previous VLV 380 * results session. 381 * 382 * @return A context ID value that should be used to resume a previous VLV 383 * results session, or {@code null} if none is available. 384 */ 385 public ByteString getContextID() 386 { 387 return contextID; 388 } 389 390 391 392 /** 393 * Writes this control's value to an ASN.1 writer. The value (if any) must be 394 * written as an ASN1OctetString. 395 * 396 * @param writer The ASN.1 writer to use. 397 * @throws IOException If a problem occurs while writing to the stream. 398 */ 399 @Override 400 protected void writeValue(ASN1Writer writer) throws IOException { 401 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 402 403 writer.writeStartSequence(); 404 writer.writeInteger(beforeCount); 405 writer.writeInteger(afterCount); 406 if(targetType == TYPE_TARGET_BYOFFSET) 407 { 408 writer.writeStartSequence(TYPE_TARGET_BYOFFSET); 409 writer.writeInteger(offset); 410 writer.writeInteger(contentCount); 411 writer.writeEndSequence(); 412 } 413 else 414 { 415 writer.writeOctetString(TYPE_TARGET_GREATERTHANOREQUAL, 416 greaterThanOrEqual); 417 } 418 if (contextID != null) 419 { 420 writer.writeOctetString(contextID); 421 } 422 writer.writeEndSequence(); 423 424 writer.writeEndSequence(); 425 } 426 427 428 429 /** 430 * Appends a string representation of this VLV request control to the provided 431 * buffer. 432 * 433 * @param buffer The buffer to which the information should be appended. 434 */ 435 @Override 436 public void toString(StringBuilder buffer) 437 { 438 buffer.append("VLVRequestControl(beforeCount="); 439 buffer.append(beforeCount); 440 buffer.append(", afterCount="); 441 buffer.append(afterCount); 442 443 if (targetType == TYPE_TARGET_BYOFFSET) 444 { 445 buffer.append(", offset="); 446 buffer.append(offset); 447 buffer.append(", contentCount="); 448 buffer.append(contentCount); 449 } 450 else 451 { 452 buffer.append(", greaterThanOrEqual="); 453 buffer.append(greaterThanOrEqual); 454 } 455 456 if (contextID != null) 457 { 458 buffer.append(", contextID="); 459 buffer.append(contextID); 460 } 461 462 buffer.append(")"); 463 } 464} 465