001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 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;
022
023
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027
028 import com.unboundid.asn1.ASN1OctetString;
029 import com.unboundid.asn1.ASN1StreamReader;
030 import com.unboundid.asn1.ASN1StreamReaderSequence;
031 import com.unboundid.ldap.protocol.LDAPResponse;
032
033 import static com.unboundid.ldap.sdk.LDAPMessages.*;
034 import static com.unboundid.util.Debug.*;
035 import static com.unboundid.util.StaticUtils.*;
036
037
038
039 /**
040 * This class provides a data structure for holding information about an LDAP
041 * intermediate response, which provides the ability for the directory server to
042 * return multiple messages in response to operations that would not otherwise
043 * support it. Intermediate response messages will only be returned by the
044 * server if the client does something to explicitly indicate that it is able
045 * to accept them (e.g., by requesting an extended operation that may return
046 * intermediate response messages, or by including a control in a request that
047 * may cause the request to return intermediate response messages).
048 * Intermediate response messages may include one or both of the following:
049 * <UL>
050 * <LI>Response OID -- An optional OID that can be used to identify the type
051 * of intermediate response.</LI>
052 * <LI>Value -- An optional element that provides the encoded value for this
053 * intermediate response. If a value is provided, then the encoding for
054 * the value depends on the type of intermediate response.</LI>
055 * </UL>
056 * When requesting an operation which may return intermediate response messages,
057 * an {@code IntermediateResponseListener} must be provided for the associated
058 * request. If an intermediate response message is returned for a request that
059 * does not have a registered {@code IntermediateResponseListener}, then it will
060 * be silently discarded.
061 */
062 public class IntermediateResponse
063 implements Serializable, LDAPResponse
064 {
065 /**
066 * The BER type for the intermediate response OID element.
067 */
068 protected static final byte TYPE_INTERMEDIATE_RESPONSE_OID = (byte) 0x80;
069
070
071
072 /**
073 * The BER type for the intermediate response value element.
074 */
075 protected static final byte TYPE_INTERMEDIATE_RESPONSE_VALUE = (byte) 0x81;
076
077
078
079 /**
080 * An empty set of controls that will be used if no controls are provided.
081 */
082 private static final Control[] NO_CONTROLS = new Control[0];
083
084
085
086 /**
087 * The serial version UID for this serializable class.
088 */
089 private static final long serialVersionUID = 218434694212935869L;
090
091
092
093 // The encoded value for this intermediate response, if available.
094 private final ASN1OctetString value;
095
096 // The set of controls for this intermediate response.
097 private final Control[] controls;
098
099 // The message ID for this intermediate response.
100 private final int messageID;
101
102 // The OID for this extended request.
103 private final String oid;
104
105
106
107 /**
108 * Creates a new intermediate response with the provided information.
109 *
110 * @param oid The OID for this intermediate response. It may be
111 * {@code null} if there is no OID.
112 * @param value The value for this intermediate response. It may be
113 * {@code null} if there is no value.
114 */
115 public IntermediateResponse(final String oid, final ASN1OctetString value)
116 {
117 this(-1, oid, value, NO_CONTROLS);
118 }
119
120
121
122 /**
123 * Creates a new intermediate response with the provided information.
124 *
125 * @param messageID The message ID for the LDAP message containing this
126 * intermediate response.
127 * @param oid The OID for this intermediate response. It may be
128 * {@code null} if there is no OID.
129 * @param value The value for this intermediate response. It may be
130 * {@code null} if there is no value.
131 */
132 public IntermediateResponse(final int messageID, final String oid,
133 final ASN1OctetString value)
134 {
135 this(messageID, oid, value, NO_CONTROLS);
136 }
137
138
139
140 /**
141 * Creates a new intermediate response with the provided information.
142 *
143 * @param oid The OID for this intermediate response. It may be
144 * {@code null} if there is no OID.
145 * @param value The value for this intermediate response. It may be
146 * {@code null} if there is no value.
147 * @param controls The set of controls for this intermediate response.
148 */
149 public IntermediateResponse(final String oid, final ASN1OctetString value,
150 final Control[] controls)
151 {
152 this(-1, oid, value, controls);
153 }
154
155
156
157 /**
158 * Creates a new intermediate response with the provided information.
159 *
160 * @param messageID The message ID for the LDAP message containing this
161 * intermediate response.
162 * @param oid The OID for this intermediate response. It may be
163 * {@code null} if there is no OID.
164 * @param value The value for this intermediate response. It may be
165 * {@code null} if there is no value.
166 * @param controls The set of controls for this intermediate response.
167 */
168 public IntermediateResponse(final int messageID, final String oid,
169 final ASN1OctetString value,
170 final Control[] controls)
171 {
172 this.messageID = messageID;
173 this.oid = oid;
174 this.value = value;
175
176 if (controls == null)
177 {
178 this.controls = NO_CONTROLS;
179 }
180 else
181 {
182 this.controls = controls;
183 }
184 }
185
186
187
188 /**
189 * Creates a new intermediate response with the information from the provided
190 * intermediate response.
191 *
192 * @param intermediateResponse The intermediate response that should be used
193 * to create this new intermediate response.
194 */
195 protected IntermediateResponse(
196 final IntermediateResponse intermediateResponse)
197 {
198 messageID = intermediateResponse.messageID;
199 oid = intermediateResponse.oid;
200 value = intermediateResponse.value;
201 controls = intermediateResponse.controls;
202 }
203
204
205
206 /**
207 * Creates a new intermediate response object with the provided message ID and
208 * with the protocol op and controls read from the given ASN.1 stream reader.
209 *
210 * @param messageID The LDAP message ID for the LDAP message that is
211 * associated with this intermediate response.
212 * @param messageSequence The ASN.1 stream reader sequence used in the
213 * course of reading the LDAP message elements.
214 * @param reader The ASN.1 stream reader from which to read the
215 * protocol op and controls.
216 *
217 * @return The decoded intermediate response.
218 *
219 * @throws LDAPException If a problem occurs while reading or decoding data
220 * from the ASN.1 stream reader.
221 */
222 static IntermediateResponse readFrom(final int messageID,
223 final ASN1StreamReaderSequence messageSequence,
224 final ASN1StreamReader reader)
225 throws LDAPException
226 {
227 try
228 {
229 String oid = null;
230 ASN1OctetString value = null;
231
232 final ASN1StreamReaderSequence opSequence = reader.beginSequence();
233 while (opSequence.hasMoreElements())
234 {
235 final byte type = (byte) reader.peek();
236 switch (type)
237 {
238 case TYPE_INTERMEDIATE_RESPONSE_OID:
239 oid = reader.readString();
240 break;
241 case TYPE_INTERMEDIATE_RESPONSE_VALUE:
242 value = new ASN1OctetString(type, reader.readBytes());
243 break;
244 default:
245 throw new LDAPException(ResultCode.DECODING_ERROR,
246 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(toHex(type)));
247 }
248 }
249
250 final Control[] controls;
251 if (messageSequence.hasMoreElements())
252 {
253 final ArrayList<Control> controlList = new ArrayList<Control>(1);
254 final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
255 while (controlSequence.hasMoreElements())
256 {
257 controlList.add(Control.readFrom(reader));
258 }
259
260 controls = new Control[controlList.size()];
261 controlList.toArray(controls);
262 }
263 else
264 {
265 controls = NO_CONTROLS;
266 }
267
268 return new IntermediateResponse(messageID, oid, value, controls);
269 }
270 catch (LDAPException le)
271 {
272 debugException(le);
273 throw le;
274 }
275 catch (Exception e)
276 {
277 debugException(e);
278 throw new LDAPException(ResultCode.DECODING_ERROR,
279 ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)),
280 e);
281 }
282 }
283
284
285
286 /**
287 * {@inheritDoc}
288 */
289 public int getMessageID()
290 {
291 return messageID;
292 }
293
294
295
296 /**
297 * Retrieves the OID for this intermediate response, if any.
298 *
299 * @return The OID for this intermediate response, or {@code null} if there
300 * is no OID for this response.
301 */
302 public final String getOID()
303 {
304 return oid;
305 }
306
307
308
309 /**
310 * Retrieves the encoded value for this intermediate response, if any.
311 *
312 * @return The encoded value for this intermediate response, or {@code null}
313 * if there is no value for this response.
314 */
315 public final ASN1OctetString getValue()
316 {
317 return value;
318 }
319
320
321
322 /**
323 * Retrieves the set of controls returned with this intermediate response.
324 * Individual response controls of a specific type may be retrieved and
325 * decoded using the {@code get} method in the response control class.
326 *
327 * @return The set of controls returned with this intermediate response.
328 */
329 public final Control[] getControls()
330 {
331 return controls;
332 }
333
334
335
336 /**
337 * Retrieves the control with the specified OID. If there is more than one
338 * control with the given OID, then the first will be returned.
339 *
340 * @param oid The OID of the control to retrieve.
341 *
342 * @return The control with the requested OID, or {@code null} if there is no
343 * such control for this intermediate response.
344 */
345 public final Control getControl(final String oid)
346 {
347 for (final Control c : controls)
348 {
349 if (c.getOID().equals(oid))
350 {
351 return c;
352 }
353 }
354
355 return null;
356 }
357
358
359
360 /**
361 * Retrieves the user-friendly name for the intermediate response, if
362 * available. If no user-friendly name has been defined, but a response OID
363 * is available, then that will be returned. If neither a user-friendly name
364 * nor a response OID are available, then {@code null} will be returned.
365 *
366 * @return The user-friendly name for this intermediate response, the
367 * response OID if a user-friendly name is not available but a
368 * response OID is, or {@code null} if neither a user-friendly name
369 * nor a response OID are available.
370 */
371 public String getIntermediateResponseName()
372 {
373 // By default, we will return the OID (which may be null). Subclasses
374 // should override this to provide the user-friendly name.
375 return oid;
376 }
377
378
379
380 /**
381 * Retrieves a human-readable string representation for the contents of the
382 * value for this intermediate response, if appropriate. If one is provided,
383 * then it should be a relatively compact single-line representation of the
384 * most important elements of the value.
385 *
386 * @return A human-readable string representation for the contents of the
387 * value for this intermediate response, or {@code null} if there is
388 * no value or no string representation is available.
389 */
390 public String valueToString()
391 {
392 return null;
393 }
394
395
396
397 /**
398 * Retrieves a string representation of this intermediate response.
399 *
400 * @return A string representation of this intermediate response.
401 */
402 @Override()
403 public final String toString()
404 {
405 final StringBuilder buffer = new StringBuilder();
406 toString(buffer);
407 return buffer.toString();
408 }
409
410
411
412 /**
413 * Appends a string representation of this intermediate response to the
414 * provided buffer.
415 *
416 * @param buffer The buffer to which the string representation should be
417 * appended.
418 */
419 public void toString(final StringBuilder buffer)
420 {
421 buffer.append("IntermediateResponse(");
422
423 boolean added = false;
424
425 if (messageID >= 0)
426 {
427 buffer.append("messageID=");
428 buffer.append(messageID);
429 added = true;
430 }
431
432 if (oid != null)
433 {
434 if (added)
435 {
436 buffer.append(", ");
437 }
438
439 buffer.append("oid='");
440 buffer.append(oid);
441 buffer.append('\'');
442 added = true;
443 }
444
445 if (controls.length > 0)
446 {
447 if (added)
448 {
449 buffer.append(", ");
450 }
451
452 buffer.append("controls={");
453 for (int i=0; i < controls.length; i++)
454 {
455 if (i > 0)
456 {
457 buffer.append(", ");
458 }
459
460 buffer.append(controls[i]);
461 }
462 buffer.append('}');
463 }
464
465 buffer.append(')');
466 }
467 }