VLVRequestControl.java revision 94e9037522922b67e8af412b4cfe476f5e991118
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.server.controls;
import org.forgerock.i18n.LocalizableMessage;
import java.io.IOException;
import org.forgerock.opendj.io.*;
import org.opends.server.types.Control;
import org.opends.server.types.DirectoryException;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
* This class implements the virtual list view request controls as defined in
* draft-ietf-ldapext-ldapv3-vlv. The ASN.1 description for the control value
* is:
* <BR><BR>
* <PRE>
* VirtualListViewRequest ::= SEQUENCE {
* beforeCount INTEGER (0..maxInt),
* afterCount INTEGER (0..maxInt),
* target CHOICE {
* byOffset [0] SEQUENCE {
* offset INTEGER (1 .. maxInt),
* contentCount INTEGER (0 .. maxInt) },
* greaterThanOrEqual [1] AssertionValue },
* contextID OCTET STRING OPTIONAL }
* </PRE>
*/
public class VLVRequestControl
extends Control
{
/**
* ControlDecoder implementation to decode this control from a ByteString.
*/
private static final class Decoder
implements ControlDecoder<VLVRequestControl>
{
/**
* {@inheritDoc}
*/
public VLVRequestControl decode(boolean isCritical, ByteString value)
throws DirectoryException
{
if (value == null)
{
LocalizableMessage message = INFO_VLVREQ_CONTROL_NO_VALUE.get();
throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
}
ASN1Reader reader = ASN1.getReader(value);
try
{
reader.readStartSequence();
int beforeCount = (int)reader.readInteger();
int afterCount = (int)reader.readInteger();
int offset = 0;
int contentCount = 0;
ByteString greaterThanOrEqual = null;
byte targetType = reader.peekType();
switch (targetType)
{
case TYPE_TARGET_BYOFFSET:
reader.readStartSequence();
offset = (int)reader.readInteger();
contentCount = (int)reader.readInteger();
reader.readEndSequence();
break;
case TYPE_TARGET_GREATERTHANOREQUAL:
greaterThanOrEqual = reader.readOctetString();
break;
default:
LocalizableMessage message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE.get(
byteToHex(targetType));
throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
}
ByteString contextID = null;
if (reader.hasNextElement())
{
contextID = reader.readOctetString();
}
if(targetType == TYPE_TARGET_BYOFFSET)
{
return new VLVRequestControl(isCritical, beforeCount,
afterCount, offset, contentCount, contextID);
}
return new VLVRequestControl(isCritical, beforeCount,
afterCount, greaterThanOrEqual, contextID);
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
LocalizableMessage message =
INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
}
}
public String getOID()
{
return OID_VLV_REQUEST_CONTROL;
}
}
/**
* The Control Decoder that can be used to decode this control.
*/
public static final ControlDecoder<VLVRequestControl> DECODER =
new Decoder();
/**
* The BER type to use when encoding the byOffset target element.
*/
public static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0;
/**
* The BER type to use when encoding the greaterThanOrEqual target element.
*/
public static final byte TYPE_TARGET_GREATERTHANOREQUAL = (byte) 0x81;
// The target type for this VLV request control.
private byte targetType;
// The context ID for this VLV request control.
private ByteString contextID;
// The greaterThanOrEqual target assertion value for this VLV request control.
private ByteString greaterThanOrEqual;
// The after count for this VLV request control.
private int afterCount;
// The before count for this VLV request control.
private int beforeCount;
// The content count for the byOffset target of this VLV request control.
private int contentCount;
// The offset for the byOffset target of this VLV request control.
private int offset;
/**
* Creates a new VLV request control with the provided information.
*
* @param beforeCount The number of entries before the target offset to
* retrieve in the results page.
* @param afterCount The number of entries after the target offset to
* retrieve in the results page.
* @param offset The offset in the result set to target for the
* beginning of the page of results.
* @param contentCount The content count returned by the server in the last
* phase of the VLV request, or zero for a new VLV
* request session.
*/
public VLVRequestControl(int beforeCount, int afterCount, int offset,
int contentCount)
{
this(false, beforeCount, afterCount, offset, contentCount, null);
}
/**
* Creates a new VLV request control with the provided information.
*
* @param isCritical Indicates whether or not the control is critical.
* @param beforeCount The number of entries before the target offset to
* retrieve in the results page.
* @param afterCount The number of entries after the target offset to
* retrieve in the results page.
* @param offset The offset in the result set to target for the
* beginning of the page of results.
* @param contentCount The content count returned by the server in the last
* phase of the VLV request, or zero for a new VLV
* request session.
* @param contextID The context ID provided by the server in the last
* VLV response for the same set of criteria, or
* {@code null} if there was no previous VLV response or
* the server did not include a context ID in the
* last response.
*/
public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount,
int offset, int contentCount, ByteString contextID)
{
super(OID_VLV_REQUEST_CONTROL, isCritical);
this.beforeCount = beforeCount;
this.afterCount = afterCount;
this.offset = offset;
this.contentCount = contentCount;
this.contextID = contextID;
targetType = TYPE_TARGET_BYOFFSET;
}
/**
* Creates a new VLV request control with the provided information.
*
* @param beforeCount The number of entries before the target offset
* to retrieve in the results page.
* @param afterCount The number of entries after the target offset
* to retrieve in the results page.
* @param greaterThanOrEqual The greaterThanOrEqual target assertion value
* that indicates where to start the page of
* results.
*/
public VLVRequestControl(int beforeCount, int afterCount,
ByteString greaterThanOrEqual)
{
this(false, beforeCount, afterCount, greaterThanOrEqual, null);
}
/**
* Creates a new VLV request control with the provided information.
*
* @param isCritical Indicates whether the control should be
* considered critical.
* @param beforeCount The number of entries before the target
* assertion value.
* @param afterCount The number of entries after the target
* assertion value.
* @param greaterThanOrEqual The greaterThanOrEqual target assertion value
* that indicates where to start the page of
* results.
* @param contextID The context ID provided by the server in the
* last VLV response for the same set of criteria,
* or {@code null} if there was no previous VLV
* response or the server did not include a
* context ID in the last response.
*/
public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount,
ByteString greaterThanOrEqual,
ByteString contextID)
{
super(OID_VLV_REQUEST_CONTROL, isCritical);
this.beforeCount = beforeCount;
this.afterCount = afterCount;
this.greaterThanOrEqual = greaterThanOrEqual;
this.contextID = contextID;
targetType = TYPE_TARGET_GREATERTHANOREQUAL;
}
/**
* Retrieves the number of entries before the target offset or assertion value
* to include in the results page.
*
* @return The number of entries before the target offset to include in the
* results page.
*/
public int getBeforeCount()
{
return beforeCount;
}
/**
* Retrieves the number of entries after the target offset or assertion value
* to include in the results page.
*
* @return The number of entries after the target offset to include in the
* results page.
*/
public int getAfterCount()
{
return afterCount;
}
/**
* Retrieves the BER type for the target that specifies the beginning of the
* results page.
*
* @return {@code TYPE_TARGET_BYOFFSET} if the beginning of the results page
* should be specified as a nuemric offset, or
* {@code TYPE_TARGET_GREATERTHANOREQUAL} if it should be specified
* by an assertion value.
*/
public byte getTargetType()
{
return targetType;
}
/**
* Retrieves the offset that indicates the beginning of the results page. The
* return value will only be applicable if the {@code getTargetType} method
* returns {@code TYPE_TARGET_BYOFFSET}.
*
* @return The offset that indicates the beginning of the results page.
*/
public int getOffset()
{
return offset;
}
/**
* Retrieves the content count indicating the estimated number of entries in
* the complete result set. The return value will only be applicable if the
* {@code getTargetType} method returns {@code TYPE_TARGET_BYOFFSET}.
*
* @return The content count indicating the estimated number of entries in
* the complete result set.
*/
public int getContentCount()
{
return contentCount;
}
/**
* Retrieves the assertion value that will be used to locate the beginning of
* the results page. This will only be applicable if the
* {@code getTargetType} method returns
* {@code TYPE_TARGET_GREATERTHANOREQUAL}.
*
* @return The assertion value that will be used to locate the beginning of
* the results page, or {@code null} if the beginning of the results
* page is to be specified using an offset.
*/
public ByteString getGreaterThanOrEqualAssertion()
{
return greaterThanOrEqual;
}
/**
* Retrieves a context ID value that should be used to resume a previous VLV
* results session.
*
* @return A context ID value that should be used to resume a previous VLV
* results session, or {@code null} if none is available.
*/
public ByteString getContextID()
{
return contextID;
}
/**
* Writes this control's value to an ASN.1 writer. The value (if any) must be
* written as an ASN1OctetString.
*
* @param writer The ASN.1 writer to use.
* @throws IOException If a problem occurs while writing to the stream.
*/
@Override
protected void writeValue(ASN1Writer writer) throws IOException {
writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
writer.writeStartSequence();
writer.writeInteger(beforeCount);
writer.writeInteger(afterCount);
if(targetType == TYPE_TARGET_BYOFFSET)
{
writer.writeStartSequence(TYPE_TARGET_BYOFFSET);
writer.writeInteger(offset);
writer.writeInteger(contentCount);
writer.writeEndSequence();
}
else
{
writer.writeOctetString(TYPE_TARGET_GREATERTHANOREQUAL,
greaterThanOrEqual);
}
if (contextID != null)
{
writer.writeOctetString(contextID);
}
writer.writeEndSequence();
writer.writeEndSequence();
}
/**
* Appends a string representation of this VLV request control to the provided
* buffer.
*
* @param buffer The buffer to which the information should be appended.
*/
@Override
public void toString(StringBuilder buffer)
{
buffer.append("VLVRequestControl(beforeCount=");
buffer.append(beforeCount);
buffer.append(", afterCount=");
buffer.append(afterCount);
if (targetType == TYPE_TARGET_BYOFFSET)
{
buffer.append(", offset=");
buffer.append(offset);
buffer.append(", contentCount=");
buffer.append(contentCount);
}
else
{
buffer.append(", greaterThanOrEqual=");
buffer.append(greaterThanOrEqual);
}
if (contextID != null)
{
buffer.append(", contextID=");
buffer.append(contextID);
}
buffer.append(")");
}
}