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 proxy values intermediate
058 * response, which may be used to provide a partial or complete list of the
059 * values for a specified attribute, or DNs of entries contained in a specified
060 * portion of the server DIT. This intermediate response has an OID of
061 * "1.3.6.1.4.1.30221.2.6.9" and the value is encoded as follows:
062 * <PRE>
063 * StreamProxyValuesIntermediateResponse ::= 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 [4] SET OF BackendSetValue OPTIONAL,
073 * ... }
074 *
075 * BackendSetValue ::= SEQUENCE {
076 * backendSetID OCTET STRING,
077 * value OCTET STRING }
078 * </PRE>
079 */
080 @NotMutable()
081 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
082 public final class StreamProxyValuesIntermediateResponse
083 extends IntermediateResponse
084 {
085 /**
086 * The OID (1.3.6.1.4.1.30221.2.6.9) for the get stream proxy values
087 * intermediate response.
088 */
089 public static final String STREAM_PROXY_VALUES_INTERMEDIATE_RESPONSE_OID =
090 "1.3.6.1.4.1.30221.2.6.9";
091
092
093
094 /**
095 * The integer value for the "all values returned" result.
096 */
097 public static final int RESULT_ALL_VALUES_RETURNED = 0;
098
099
100
101 /**
102 * The integer value for the "more values to return" result.
103 */
104 public static final int RESULT_MORE_VALUES_TO_RETURN = 1;
105
106
107
108 /**
109 * The integer value for the "attribute not indexed" result.
110 */
111 public static final int RESULT_ATTRIBUTE_NOT_INDEXED = 2;
112
113
114
115 /**
116 * The integer value for the "processing error" result.
117 */
118 public static final int RESULT_PROCESSING_ERROR = 3;
119
120
121
122 /**
123 * The BER type for the attribute name element.
124 */
125 private static final byte TYPE_ATTRIBUTE_NAME = (byte) 0x80;
126
127
128
129 /**
130 * The BER type for the result element.
131 */
132 private static final byte TYPE_RESULT = (byte) 0x81;
133
134
135
136 /**
137 * The BER type for the diagnostic message element.
138 */
139 private static final byte TYPE_DIAGNOSTIC_MESSAGE = (byte) 0x82;
140
141
142
143 /**
144 * The BER type for the values element.
145 */
146 private static final byte TYPE_VALUES = (byte) 0xA4;
147
148
149
150 /**
151 * The serial version UID for this serializable class.
152 */
153 private static final long serialVersionUID = 6861844092877880224L;
154
155
156
157 // The result code for this stream proxy values intermediate response.
158 private final int result;
159
160 // The list of values for this stream proxy values intermediate response.
161 private final List<StreamProxyValuesBackendSetValue> values;
162
163 // The attribute name for this stream proxy values intermediate response, if
164 // any.
165 private final String attributeName;
166
167 // The diagnostic message for this stream proxy values intermediate response,
168 // if any.
169 private final String diagnosticMessage;
170
171
172
173 /**
174 * Creates a new stream proxy values intermediate response with the
175 * provided information.
176 *
177 * @param attributeName The name of the attribute with which the
178 * included values are associated. This may be
179 * {@code null} if the provided values are DNs.
180 * @param result The integer value that provides information
181 * about the state of the stream proxy values
182 * response.
183 * @param diagnosticMessage The diagnostic message that provides more
184 * information about the result, or {@code null} if
185 * none is required.
186 * @param values The set of values included in this stream proxy
187 * values intermediate response. It may be
188 * {@code null} or empty if this is an error
189 * result, or there are no values of the specified
190 * type in the server.
191 * @param controls The set of controls to include in this
192 * intermediate response. It may be {@code null}
193 * or empty if there should not be any controls.
194 */
195 public StreamProxyValuesIntermediateResponse(final String attributeName,
196 final int result, final String diagnosticMessage,
197 final Collection<StreamProxyValuesBackendSetValue> values,
198 final Control... controls)
199 {
200 super(STREAM_PROXY_VALUES_INTERMEDIATE_RESPONSE_OID,
201 encodeValue(attributeName, result, diagnosticMessage, values),
202 controls);
203
204 this.attributeName = attributeName;
205 this.result = result;
206 this.diagnosticMessage = diagnosticMessage;
207
208 if ((values == null) || values.isEmpty())
209 {
210 this.values = Collections.emptyList();
211 }
212 else
213 {
214 this.values = Collections.unmodifiableList(
215 new ArrayList<StreamProxyValuesBackendSetValue>(values));
216 }
217 }
218
219
220
221 /**
222 * Creates a new stream proxy values intermediate response with
223 * information from the provided generic intermediate response.
224 *
225 * @param intermediateResponse The generic intermediate response that should
226 * be used to create this new intermediate
227 * response.
228 *
229 * @throws LDAPException If the provided intermediate response cannot be
230 * parsed as a stream proxy values intermediate
231 * response.
232 */
233 public StreamProxyValuesIntermediateResponse(
234 final IntermediateResponse intermediateResponse)
235 throws LDAPException
236 {
237 super(intermediateResponse);
238
239 final ASN1OctetString value = intermediateResponse.getValue();
240 if (value == null)
241 {
242 throw new LDAPException(ResultCode.DECODING_ERROR,
243 ERR_STREAM_PROXY_VALUES_RESPONSE_NO_VALUE.get());
244 }
245
246 int tmpResult = -1;
247 String tmpAttr = null;
248 String tmpMessage = null;
249 final ArrayList<StreamProxyValuesBackendSetValue> tmpValues =
250 new ArrayList<StreamProxyValuesBackendSetValue>();
251
252 try
253 {
254 final ASN1Element[] elements =
255 ASN1Element.decode(value.getValue()).decodeAsSequence().elements();
256 for (final ASN1Element e : elements)
257 {
258 switch (e.getType())
259 {
260 case TYPE_ATTRIBUTE_NAME:
261 tmpAttr = e.decodeAsOctetString().stringValue();
262 break;
263 case TYPE_RESULT:
264 tmpResult = e.decodeAsEnumerated().intValue();
265 if (tmpResult < 0)
266 {
267 throw new LDAPException(ResultCode.DECODING_ERROR,
268 ERR_STREAM_PROXY_VALUES_RESPONSE_INVALID_RESULT.get(
269 tmpResult));
270 }
271 break;
272 case TYPE_DIAGNOSTIC_MESSAGE:
273 tmpMessage = e.decodeAsOctetString().stringValue();
274 break;
275 case TYPE_VALUES:
276 final ASN1Element[] valueElements = e.decodeAsSet().elements();
277 for (final ASN1Element ve : valueElements)
278 {
279 tmpValues.add(StreamProxyValuesBackendSetValue.decode(ve));
280 }
281 break;
282 default:
283 throw new LDAPException(ResultCode.DECODING_ERROR,
284 ERR_STREAM_PROXY_VALUES_RESPONSE_INVALID_SEQUENCE_TYPE.get(
285 toHex(e.getType())));
286 }
287 }
288 }
289 catch (LDAPException le)
290 {
291 throw le;
292 }
293 catch (Exception e)
294 {
295 debugException(e);
296 throw new LDAPException(ResultCode.DECODING_ERROR,
297 ERR_STREAM_PROXY_VALUES_RESPONSE_CANNOT_DECODE.get(
298 getExceptionMessage(e)), e);
299 }
300
301 if (tmpResult < 0)
302 {
303 throw new LDAPException(ResultCode.DECODING_ERROR,
304 ERR_STREAM_PROXY_VALUES_RESPONSE_NO_RESULT.get());
305 }
306
307 attributeName = tmpAttr;
308 result = tmpResult;
309 diagnosticMessage = tmpMessage;
310 values = Collections.unmodifiableList(tmpValues);
311 }
312
313
314
315 /**
316 * Encodes the provided information in a form suitable for use as the value of
317 * this intermediate response.
318 *
319 * @param attributeName The name of the attribute with which the
320 * included values are associated. This may be
321 * {@code null} if the provided values are DNs.
322 * @param result The integer value that provides information
323 * about the state of the stream proxy values
324 * response.
325 * @param diagnosticMessage The diagnostic message that provides more
326 * information about the result, or {@code null} if
327 * none is required.
328 * @param values The set of values included in this stream
329 * proxy values intermediate response. It may
330 * be {@code null} or empty if this is an error
331 * result, or there are no values of the specified
332 * type in the server.
333 *
334 * @return An ASN.1 octet string containing the encoded value to use for this
335 * intermediate response.
336 */
337 private static ASN1OctetString encodeValue(final String attributeName,
338 final int result, final String diagnosticMessage,
339 final Collection<StreamProxyValuesBackendSetValue> values)
340 {
341 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
342
343 if (attributeName != null)
344 {
345 elements.add(new ASN1OctetString(TYPE_ATTRIBUTE_NAME, attributeName));
346 }
347
348 elements.add(new ASN1Enumerated(TYPE_RESULT, result));
349
350 if (diagnosticMessage != null)
351 {
352 elements.add(new ASN1OctetString(TYPE_DIAGNOSTIC_MESSAGE,
353 diagnosticMessage));
354 }
355
356 if ((values != null) && (! values.isEmpty()))
357 {
358 final ArrayList<ASN1Element> valueElements =
359 new ArrayList<ASN1Element>(values.size());
360 for (final StreamProxyValuesBackendSetValue v : values)
361 {
362 valueElements.add(v.encode());
363 }
364
365 elements.add(new ASN1Set(TYPE_VALUES, valueElements));
366 }
367
368 return new ASN1OctetString(new ASN1Sequence(elements).encode());
369 }
370
371
372
373 /**
374 * Retrieves the name of the attribute with which this stream proxy values
375 * intermediate response is associated.
376 *
377 * @return The name of the attribute with which this stream proxy values
378 * intermediate response is associated, or {@code null} if the values
379 * are entry DNs rather than attribute values.
380 */
381 public String getAttributeName()
382 {
383 return attributeName;
384 }
385
386
387
388 /**
389 * Retrieves the integer value of the result for this stream proxy values
390 * intermediate response.
391 *
392 * @return The integer value of the result for this stream proxy values
393 * intermediate response.
394 */
395 public int getResult()
396 {
397 return result;
398 }
399
400
401
402 /**
403 * Retrieves the diagnostic message for this stream proxy values intermediate
404 * response.
405 *
406 * @return The diagnostic message for this stream proxy values intermediate
407 * response, or {@code null} if there is none.
408 */
409 public String getDiagnosticMessage()
410 {
411 return diagnosticMessage;
412 }
413
414
415
416 /**
417 * Retrieves the list of values for this stream proxy values intermediate
418 * response.
419 *
420 * @return The list of values for this stream proxy values intermediate
421 * response, or an empty list if there are no values.
422 */
423 public List<StreamProxyValuesBackendSetValue> getValues()
424 {
425 return values;
426 }
427
428
429
430 /**
431 * {@inheritDoc}
432 */
433 @Override()
434 public String getIntermediateResponseName()
435 {
436 return INFO_INTERMEDIATE_RESPONSE_NAME_STREAM_PROXY_VALUES.get();
437 }
438
439
440
441 /**
442 * {@inheritDoc}
443 */
444 @Override()
445 public String valueToString()
446 {
447 final StringBuilder buffer = new StringBuilder();
448
449 if (attributeName != null)
450 {
451 buffer.append("attributeName='");
452 buffer.append(attributeName);
453 buffer.append("' ");
454 }
455
456 buffer.append("result='");
457 switch (result)
458 {
459 case RESULT_ALL_VALUES_RETURNED:
460 buffer.append("all values returned");
461 break;
462 case RESULT_ATTRIBUTE_NOT_INDEXED:
463 buffer.append("attribute not indexed");
464 break;
465 case RESULT_MORE_VALUES_TO_RETURN:
466 buffer.append("more values to return");
467 break;
468 case RESULT_PROCESSING_ERROR:
469 buffer.append("processing error");
470 break;
471 default:
472 buffer.append(result);
473 break;
474 }
475 buffer.append('\'');
476
477 if (diagnosticMessage != null)
478 {
479 buffer.append(" diagnosticMessage='");
480 buffer.append(diagnosticMessage);
481 buffer.append('\'');
482 }
483
484 buffer.append(" valueCount='");
485 buffer.append(values.size());
486 buffer.append('\'');
487
488 return buffer.toString();
489 }
490
491
492
493 /**
494 * {@inheritDoc}
495 */
496 @Override()
497 public void toString(final StringBuilder buffer)
498 {
499 buffer.append("StreamProxyValuesIntermediateResponse(");
500
501 final int messageID = getMessageID();
502 if (messageID >= 0)
503 {
504 buffer.append("messageID=");
505 buffer.append(messageID);
506 buffer.append(", ");
507 }
508
509 if (attributeName != null)
510 {
511 buffer.append("attributeName='");
512 buffer.append(attributeName);
513 buffer.append("', ");
514 }
515
516 buffer.append("result=");
517 buffer.append(result);
518
519 if (diagnosticMessage != null)
520 {
521 buffer.append(", diagnosticMessage='");
522 buffer.append(diagnosticMessage);
523 buffer.append('\'');
524 }
525
526 buffer.append(", values={");
527
528 final Iterator<StreamProxyValuesBackendSetValue> iterator =
529 values.iterator();
530 while (iterator.hasNext())
531 {
532 iterator.next().toString(buffer);
533 if (iterator.hasNext())
534 {
535 buffer.append(", ");
536 }
537 }
538
539 final Control[] controls = getControls();
540 if (controls.length > 0)
541 {
542 buffer.append(", controls={");
543 for (int i=0; i < controls.length; i++)
544 {
545 if (i > 0)
546 {
547 buffer.append(", ");
548 }
549
550 buffer.append(controls[i]);
551 }
552 buffer.append('}');
553 }
554
555 buffer.append("})");
556 }
557 }