001 /*
002 * Copyright 2009-2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.unboundidds.extensions;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collection;
027 import java.util.Collections;
028 import java.util.Iterator;
029 import java.util.List;
030
031 import com.unboundid.asn1.ASN1Element;
032 import com.unboundid.asn1.ASN1Enumerated;
033 import com.unboundid.asn1.ASN1OctetString;
034 import com.unboundid.asn1.ASN1Sequence;
035 import com.unboundid.asn1.ASN1Set;
036 import com.unboundid.ldap.sdk.Control;
037 import com.unboundid.ldap.sdk.IntermediateResponse;
038 import com.unboundid.ldap.sdk.LDAPException;
039 import com.unboundid.ldap.sdk.ResultCode;
040 import com.unboundid.util.NotMutable;
041 import com.unboundid.util.ThreadSafety;
042 import com.unboundid.util.ThreadSafetyLevel;
043
044 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
045 import static com.unboundid.util.Debug.*;
046 import static com.unboundid.util.StaticUtils.*;
047
048
049
050 /**
051 * <BLOCKQUOTE>
052 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
053 * LDAP SDK for Java. It is not available for use in applications that
054 * include only the Standard Edition of the LDAP SDK, and is not supported for
055 * use in conjunction with non-UnboundID products.
056 * </BLOCKQUOTE>
057 * This class provides an implementation of the stream directory values
058 * intermediate response, which may be used to provide a partial or complete
059 * list of the values for a specified attribute, or DNs of entries contained in
060 * a specified portion of the server DIT. This intermediate response has an OID
061 * of "1.3.6.1.4.1.30221.2.6.7" and the value is encoded as follows:
062 * <PRE>
063 * StreamDirectoryValuesIntermediateResponse ::= SEQUENCE {
064 * attributeName [0] LDAPString OPTIONAL,
065 * result [1] ENUMERATED {
066 * allValuesReturned (0),
067 * moreValuesToReturn (1),
068 * attributeNotIndexed (2),
069 * processingError (3),
070 * ... },
071 * diagnosticMessage [2] OCTET STRING OPTIONAL,
072 * values [3] SET OF OCTET STRING OPTIONAL,
073 * ... }
074 * </PRE>
075 */
076 @NotMutable()
077 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
078 public final class StreamDirectoryValuesIntermediateResponse
079 extends IntermediateResponse
080 {
081 /**
082 * The OID (1.3.6.1.4.1.30221.2.6.7) for the get stream directory values
083 * intermediate response.
084 */
085 public static final String STREAM_DIRECTORY_VALUES_INTERMEDIATE_RESPONSE_OID =
086 "1.3.6.1.4.1.30221.2.6.7";
087
088
089
090 /**
091 * The integer value for the "all values returned" result.
092 */
093 public static final int RESULT_ALL_VALUES_RETURNED = 0;
094
095
096
097 /**
098 * The integer value for the "more values to return" result.
099 */
100 public static final int RESULT_MORE_VALUES_TO_RETURN = 1;
101
102
103
104 /**
105 * The integer value for the "attribute not indexed" result.
106 */
107 public static final int RESULT_ATTRIBUTE_NOT_INDEXED = 2;
108
109
110
111 /**
112 * The integer value for the "processing error" result.
113 */
114 public static final int RESULT_PROCESSING_ERROR = 3;
115
116
117
118 /**
119 * The BER type for the attribute name element.
120 */
121 private static final byte TYPE_ATTRIBUTE_NAME = (byte) 0x80;
122
123
124
125 /**
126 * The BER type for the result element.
127 */
128 private static final byte TYPE_RESULT = (byte) 0x81;
129
130
131
132 /**
133 * The BER type for the diagnostic message element.
134 */
135 private static final byte TYPE_DIAGNOSTIC_MESSAGE = (byte) 0x82;
136
137
138
139 /**
140 * The BER type for the values element.
141 */
142 private static final byte TYPE_VALUES = (byte) 0xA3;
143
144
145
146 /**
147 * The serial version UID for this serializable class.
148 */
149 private static final long serialVersionUID = -1756020236490168006L;
150
151
152
153 // The result code for this stream directory values intermediate response.
154 private final int result;
155
156 // The list of values for this stream directory values intermediate response.
157 private final List<ASN1OctetString> values;
158
159 // The attribute name for this stream directory values intermediate response,
160 // if any.
161 private final String attributeName;
162
163 // The diagnostic message for this stream directory values intermediate
164 // response, if any.
165 private final String diagnosticMessage;
166
167
168
169 /**
170 * Creates a new stream directory values intermediate response with the
171 * provided information.
172 *
173 * @param attributeName The name of the attribute with which the
174 * included values are associated. This may be
175 * {@code null} if the provided values are DNs.
176 * @param result The integer value that provides information
177 * about the state of the stream directory values
178 * response.
179 * @param diagnosticMessage The diagnostic message that provides more
180 * information about the result, or {@code null} if
181 * none is required.
182 * @param values The set of values included in this stream
183 * directory values intermediate response. It may
184 * be {@code null} or empty if this is an error
185 * result, or there are no values of the specified
186 * type in the server.
187 * @param controls The set of controls to include in this
188 * intermediate response. It may be {@code null}
189 * or empty if there should not be any controls.
190 */
191 public StreamDirectoryValuesIntermediateResponse(final String attributeName,
192 final int result, final String diagnosticMessage,
193 final Collection<ASN1OctetString> values,
194 final Control... controls)
195 {
196 super(STREAM_DIRECTORY_VALUES_INTERMEDIATE_RESPONSE_OID,
197 encodeValue(attributeName, result, diagnosticMessage, values),
198 controls);
199
200 this.attributeName = attributeName;
201 this.result = result;
202 this.diagnosticMessage = diagnosticMessage;
203
204 if ((values == null) || values.isEmpty())
205 {
206 this.values = Collections.emptyList();
207 }
208 else
209 {
210 this.values = Collections.unmodifiableList(
211 new ArrayList<ASN1OctetString>(values));
212 }
213 }
214
215
216
217 /**
218 * Creates a new stream directory values intermediate response with
219 * information from the provided generic intermediate response.
220 *
221 * @param intermediateResponse The generic intermediate response that should
222 * be used to create this new intermediate
223 * response.
224 *
225 * @throws LDAPException If the provided intermediate response cannot be
226 * parsed as a stream directory values intermediate
227 * response.
228 */
229 public StreamDirectoryValuesIntermediateResponse(
230 final IntermediateResponse intermediateResponse)
231 throws LDAPException
232 {
233 super(intermediateResponse);
234
235 final ASN1OctetString value = intermediateResponse.getValue();
236 if (value == null)
237 {
238 throw new LDAPException(ResultCode.DECODING_ERROR,
239 ERR_STREAM_DIRECTORY_VALUES_RESPONSE_NO_VALUE.get());
240 }
241
242 int tmpResult = -1;
243 String tmpAttr = null;
244 String tmpMessage = null;
245 final ArrayList<ASN1OctetString> tmpValues =
246 new ArrayList<ASN1OctetString>();
247
248 try
249 {
250 final ASN1Element[] elements =
251 ASN1Element.decode(value.getValue()).decodeAsSequence().elements();
252 for (final ASN1Element e : elements)
253 {
254 switch (e.getType())
255 {
256 case TYPE_ATTRIBUTE_NAME:
257 tmpAttr = e.decodeAsOctetString().stringValue();
258 break;
259 case TYPE_RESULT:
260 tmpResult = e.decodeAsEnumerated().intValue();
261 if (tmpResult < 0)
262 {
263 throw new LDAPException(ResultCode.DECODING_ERROR,
264 ERR_STREAM_DIRECTORY_VALUES_RESPONSE_INVALID_RESULT.get(
265 tmpResult));
266 }
267 break;
268 case TYPE_DIAGNOSTIC_MESSAGE:
269 tmpMessage = e.decodeAsOctetString().stringValue();
270 break;
271 case TYPE_VALUES:
272 final ASN1Element[] valueElements = e.decodeAsSet().elements();
273 for (final ASN1Element ve : valueElements)
274 {
275 tmpValues.add(ve.decodeAsOctetString());
276 }
277 break;
278 default:
279 throw new LDAPException(ResultCode.DECODING_ERROR,
280 ERR_STREAM_DIRECTORY_VALUES_RESPONSE_INVALID_SEQUENCE_TYPE.get(
281 toHex(e.getType())));
282 }
283 }
284 }
285 catch (LDAPException le)
286 {
287 throw le;
288 }
289 catch (Exception e)
290 {
291 debugException(e);
292 throw new LDAPException(ResultCode.DECODING_ERROR,
293 ERR_STREAM_DIRECTORY_VALUES_RESPONSE_CANNOT_DECODE.get(
294 getExceptionMessage(e)), e);
295 }
296
297 if (tmpResult < 0)
298 {
299 throw new LDAPException(ResultCode.DECODING_ERROR,
300 ERR_STREAM_DIRECTORY_VALUES_RESPONSE_NO_RESULT.get());
301 }
302
303 attributeName = tmpAttr;
304 result = tmpResult;
305 diagnosticMessage = tmpMessage;
306 values = Collections.unmodifiableList(tmpValues);
307 }
308
309
310
311 /**
312 * Encodes the provided information in a form suitable for use as the value of
313 * this intermediate response.
314 *
315 * @param attributeName The name of the attribute with which the
316 * included values are associated. This may be
317 * {@code null} if the provided values are DNs.
318 * @param result The integer value that provides information
319 * about the state of the stream directory values
320 * response.
321 * @param diagnosticMessage The diagnostic message that provides more
322 * information about the result, or {@code null} if
323 * none is required.
324 * @param values The set of values included in this stream
325 * directory values intermediate response. It may
326 * be {@code null} or empty if this is an error
327 * result, or there are no values of the specified
328 * type in the server.
329 *
330 * @return An ASN.1 octet string containing the encoded value to use for this
331 * intermediate response.
332 */
333 private static ASN1OctetString encodeValue(final String attributeName,
334 final int result, final String diagnosticMessage,
335 final Collection<ASN1OctetString> values)
336 {
337 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
338
339 if (attributeName != null)
340 {
341 elements.add(new ASN1OctetString(TYPE_ATTRIBUTE_NAME, attributeName));
342 }
343
344 elements.add(new ASN1Enumerated(TYPE_RESULT, result));
345
346 if (diagnosticMessage != null)
347 {
348 elements.add(new ASN1OctetString(TYPE_DIAGNOSTIC_MESSAGE,
349 diagnosticMessage));
350 }
351
352 if ((values != null) && (! values.isEmpty()))
353 {
354 elements.add(new ASN1Set(TYPE_VALUES, values));
355 }
356
357 return new ASN1OctetString(new ASN1Sequence(elements).encode());
358 }
359
360
361
362 /**
363 * Retrieves the name of the attribute with which this stream directory values
364 * intermediate response is associated.
365 *
366 * @return The name of the attribute with which this stream directory values
367 * intermediate response is associated, or {@code null} if the values
368 * are entry DNs rather than attribute values.
369 */
370 public String getAttributeName()
371 {
372 return attributeName;
373 }
374
375
376
377 /**
378 * Retrieves the integer value of the result for this stream directory values
379 * intermediate response.
380 *
381 * @return The integer value of the result for this stream directory values
382 * intermediate response.
383 */
384 public int getResult()
385 {
386 return result;
387 }
388
389
390
391 /**
392 * Retrieves the diagnostic message for this stream directory values
393 * intermediate response.
394 *
395 * @return The diagnostic message for this stream directory values
396 * intermediate response, or {@code null} if there is none.
397 */
398 public String getDiagnosticMessage()
399 {
400 return diagnosticMessage;
401 }
402
403
404
405 /**
406 * Retrieves the list of values for this stream directory values intermediate
407 * response.
408 *
409 * @return The list of values for this stream directory values intermediate
410 * response, or an empty list if there are no values.
411 */
412 public List<ASN1OctetString> getValues()
413 {
414 return values;
415 }
416
417
418
419 /**
420 * {@inheritDoc}
421 */
422 @Override()
423 public String getIntermediateResponseName()
424 {
425 return INFO_INTERMEDIATE_RESPONSE_NAME_STREAM_DIRECTORY_VALUES.get();
426 }
427
428
429
430 /**
431 * {@inheritDoc}
432 */
433 @Override()
434 public String valueToString()
435 {
436 final StringBuilder buffer = new StringBuilder();
437
438 if (attributeName != null)
439 {
440 buffer.append("attributeName='");
441 buffer.append(attributeName);
442 buffer.append("' ");
443 }
444
445 buffer.append("result='");
446 switch (result)
447 {
448 case RESULT_ALL_VALUES_RETURNED:
449 buffer.append("all values returned");
450 break;
451 case RESULT_ATTRIBUTE_NOT_INDEXED:
452 buffer.append("attribute not indexed");
453 break;
454 case RESULT_MORE_VALUES_TO_RETURN:
455 buffer.append("more values to return");
456 break;
457 case RESULT_PROCESSING_ERROR:
458 buffer.append("processing error");
459 break;
460 default:
461 buffer.append(result);
462 break;
463 }
464 buffer.append('\'');
465
466 if (diagnosticMessage != null)
467 {
468 buffer.append(" diagnosticMessage='");
469 buffer.append(diagnosticMessage);
470 buffer.append('\'');
471 }
472
473 buffer.append(" valueCount='");
474 buffer.append(values.size());
475 buffer.append('\'');
476
477 return buffer.toString();
478 }
479
480
481
482 /**
483 * {@inheritDoc}
484 */
485 @Override()
486 public void toString(final StringBuilder buffer)
487 {
488 buffer.append("StreamDirectoryValuesIntermediateResponse(");
489
490 final int messageID = getMessageID();
491 if (messageID >= 0)
492 {
493 buffer.append("messageID=");
494 buffer.append(messageID);
495 buffer.append(", ");
496 }
497
498 if (attributeName != null)
499 {
500 buffer.append("attributeName='");
501 buffer.append(attributeName);
502 buffer.append("', ");
503 }
504
505 buffer.append("result=");
506 buffer.append(result);
507
508 if (diagnosticMessage != null)
509 {
510 buffer.append(", diagnosticMessage='");
511 buffer.append(diagnosticMessage);
512 buffer.append('\'');
513 }
514
515 buffer.append(", values={");
516
517 final Iterator<ASN1OctetString> iterator = values.iterator();
518 while (iterator.hasNext())
519 {
520 buffer.append('\'');
521 buffer.append(iterator.next().stringValue());
522 buffer.append('\'');
523 if (iterator.hasNext())
524 {
525 buffer.append(", ");
526 }
527 }
528
529 final Control[] controls = getControls();
530 if (controls.length > 0)
531 {
532 buffer.append(", controls={");
533 for (int i=0; i < controls.length; i++)
534 {
535 if (i > 0)
536 {
537 buffer.append(", ");
538 }
539
540 buffer.append(controls[i]);
541 }
542 buffer.append('}');
543 }
544
545 buffer.append("})");
546 }
547 }