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