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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.controls; 028 029import org.forgerock.i18n.LocalizableMessage; 030 031import org.forgerock.i18n.slf4j.LocalizedLogger; 032import static org.opends.messages.ProtocolMessages.*; 033import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL; 034 035import org.forgerock.opendj.io.*; 036import org.opends.server.types.*; 037import org.forgerock.opendj.ldap.ResultCode; 038import org.forgerock.opendj.ldap.ByteString; 039import java.io.IOException; 040 041/** 042 * This class represents a paged results control value as defined in 043 * RFC 2696. 044 * 045 * The searchControlValue is an OCTET STRING wrapping the BER-encoded 046 * version of the following SEQUENCE: 047 * 048 * <pre> 049 * realSearchControlValue ::= SEQUENCE { 050 * size INTEGER (0..maxInt), 051 * -- requested page size from client 052 * -- result set size estimate from server 053 * cookie OCTET STRING 054 * } 055 * </pre> 056 */ 057public class PagedResultsControl extends Control 058{ 059 /** 060 * ControlDecoder implementation to decode this control from a ByteString. 061 */ 062 private static final class Decoder 063 implements ControlDecoder<PagedResultsControl> 064 { 065 /** {@inheritDoc} */ 066 public PagedResultsControl decode(boolean isCritical, ByteString value) 067 throws DirectoryException 068 { 069 if (value == null) 070 { 071 LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL.get(); 072 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 073 } 074 075 ASN1Reader reader = ASN1.getReader(value); 076 try 077 { 078 reader.readStartSequence(); 079 } 080 catch (Exception e) 081 { 082 logger.traceException(e); 083 084 LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(e); 085 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 086 } 087 088 int size; 089 try 090 { 091 size = (int)reader.readInteger(); 092 } 093 catch (Exception e) 094 { 095 logger.traceException(e); 096 097 LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SIZE.get(e); 098 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 099 } 100 101 ByteString cookie; 102 try 103 { 104 cookie = reader.readOctetString(); 105 } 106 catch (Exception e) 107 { 108 logger.traceException(e); 109 110 LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE.get(e); 111 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 112 } 113 114 try 115 { 116 reader.readEndSequence(); 117 } 118 catch (Exception e) 119 { 120 logger.traceException(e); 121 122 LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(e); 123 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 124 } 125 126 return new PagedResultsControl(isCritical, size, cookie); 127 } 128 129 public String getOID() 130 { 131 return OID_PAGED_RESULTS_CONTROL; 132 } 133 134 } 135 136 /** 137 * The Control Decoder that can be used to decode this control. 138 */ 139 public static final ControlDecoder<PagedResultsControl> DECODER = 140 new Decoder(); 141 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 142 143 144 145 /** 146 * The control value size element, which is either the requested page size 147 * from the client, or the result set size estimate from the server. 148 */ 149 private int size; 150 151 152 /** 153 * The control value cookie element. 154 */ 155 private ByteString cookie; 156 157 158 /** 159 * Creates a new paged results control with the specified information. 160 * 161 * @param isCritical Indicates whether this control should be considered 162 * critical in processing the request. 163 * @param size The size element. 164 * @param cookie The cookie element. 165 */ 166 public PagedResultsControl(boolean isCritical, int size, 167 ByteString cookie) 168 { 169 super(OID_PAGED_RESULTS_CONTROL, isCritical); 170 171 172 this.size = size; 173 if(cookie == null) 174 { 175 this.cookie=ByteString.empty(); 176 } 177 else 178 { 179 this.cookie = cookie; 180 } 181 } 182 183 184 /** 185 * Writes this control's value to an ASN.1 writer. The value (if any) must be 186 * written as an ASN1OctetString. 187 * 188 * @param writer The ASN.1 output stream to write to. 189 * @throws IOException If a problem occurs while writing to the stream. 190 */ 191 @Override 192 public void writeValue(ASN1Writer writer) throws IOException { 193 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 194 195 writer.writeStartSequence(); 196 writer.writeInteger(size); 197 writer.writeOctetString(cookie); 198 writer.writeEndSequence(); 199 200 writer.writeEndSequence(); 201 } 202 203 204 /** 205 * Get the control value size element, which is either the requested page size 206 * from the client, or the result set size estimate from the server. 207 * @return The control value size element. 208 */ 209 public int getSize() 210 { 211 return size; 212 } 213 214 215 216 /** 217 * Get the control value cookie element. 218 * @return The control value cookie element. 219 */ 220 public ByteString getCookie() 221 { 222 return cookie; 223 } 224}