mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
24.49.2015 99aaa917a95d7ec19e14dad25f61f58ff84753b1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/*
 * 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(")");
  }
}