001 /*
002 * Copyright 2008-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.controls;
022
023
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027
028 import com.unboundid.asn1.ASN1Boolean;
029 import com.unboundid.asn1.ASN1Constants;
030 import com.unboundid.asn1.ASN1Element;
031 import com.unboundid.asn1.ASN1OctetString;
032 import com.unboundid.asn1.ASN1Sequence;
033 import com.unboundid.ldap.sdk.LDAPException;
034 import com.unboundid.ldap.sdk.ResultCode;
035 import com.unboundid.util.NotMutable;
036 import com.unboundid.util.ThreadSafety;
037 import com.unboundid.util.ThreadSafetyLevel;
038
039 import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
040 import static com.unboundid.util.Debug.*;
041 import static com.unboundid.util.StaticUtils.*;
042
043
044
045 /**
046 * <BLOCKQUOTE>
047 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
048 * LDAP SDK for Java. It is not available for use in applications that
049 * include only the Standard Edition of the LDAP SDK, and is not supported for
050 * use in conjunction with non-UnboundID products.
051 * </BLOCKQUOTE>
052 * This class implements a data structure which encapsulates the value of an
053 * intermediate client response value. It may recursively embed intermediate
054 * client response values from upstream servers.
055 * <BR><BR>
056 * See the documentation in the {@link IntermediateClientRequestControl} class
057 * for an example of using the intermediate client request and response
058 * controls.
059 */
060 @NotMutable()
061 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
062 public final class IntermediateClientResponseValue
063 implements Serializable
064 {
065 /**
066 * The BER type for the upstreamResponse element.
067 */
068 private static final byte TYPE_UPSTREAM_RESPONSE = (byte) 0xA0;
069
070
071
072 /**
073 * The BER type for the upstreamServerAddress element.
074 */
075 private static final byte TYPE_UPSTREAM_SERVER_ADDRESS = (byte) 0x81;
076
077
078
079 /**
080 * The BER type for the upstreamServerSecure element.
081 */
082 private static final byte TYPE_UPSTREAM_SERVER_SECURE = (byte) 0x82;
083
084
085
086 /**
087 * The BER type for the serverName element.
088 */
089 private static final byte TYPE_SERVER_NAME = (byte) 0x83;
090
091
092
093 /**
094 * The BER type for the serverSessionID element.
095 */
096 private static final byte TYPE_SERVER_SESSION_ID = (byte) 0x84;
097
098
099
100 /**
101 * The BER type for the serverResponseID element.
102 */
103 private static final byte TYPE_SERVER_RESPONSE_ID = (byte) 0x85;
104
105
106
107 /**
108 * The serial version UID for this serializable class.
109 */
110 private static final long serialVersionUID = 5165171788442351399L;
111
112
113
114 // Indicates whether communication with the upstream server is secure.
115 private final Boolean upstreamServerSecure;
116
117 // The upstream response, if available.
118 private final IntermediateClientResponseValue upstreamResponse;
119
120 // The server name, which describes the server application, if present.
121 private final String serverName;
122
123 // The server response ID, if present.
124 private final String serverResponseID;
125
126 // The server session ID, if present.
127 private final String serverSessionID;
128
129 // The address of the upstream server, if available.
130 private final String upstreamServerAddress;
131
132
133
134 /**
135 * Creates a new intermediate client response value with the provided
136 * information.
137 *
138 * @param upstreamResponse A wrapped intermediate client response from
139 * an upstream server. It may be {@code null}
140 * if there is no wrapped upstream response.
141 * @param upstreamServerAddress The IP address or resolvable name of the
142 * upstream server system. It may be
143 * {@code null} if there is no upstream server
144 * or its address is not available.
145 * @param upstreamServerSecure Indicates whether communication with the
146 * upstream server is secure. It may be
147 * {@code null} if there is no upstream server
148 * or it is not known whether the communication
149 * is secure.
150 * @param serverName An identifier string that summarizes the
151 * server application that created this
152 * intermediate client response. It may be
153 * {@code null} if that information is not
154 * available.
155 * @param serverSessionID A string that may be used to identify the
156 * session in the server application. It may
157 * be {@code null} if there is no available
158 * session identifier.
159 * @param serverResponseID A string that may be used to identify the
160 * response in the server application. It may
161 * be {@code null} if there is no available
162 * response identifier.
163 */
164 public IntermediateClientResponseValue(
165 final IntermediateClientResponseValue upstreamResponse,
166 final String upstreamServerAddress,
167 final Boolean upstreamServerSecure, final String serverName,
168 final String serverSessionID, final String serverResponseID)
169 {
170 this.upstreamResponse = upstreamResponse;
171 this.upstreamServerAddress = upstreamServerAddress;
172 this.upstreamServerSecure = upstreamServerSecure;
173 this.serverName = serverName;
174 this.serverSessionID = serverSessionID;
175 this.serverResponseID = serverResponseID;
176 }
177
178
179
180 /**
181 * Retrieves the wrapped response from an upstream server, if available.
182 *
183 * @return The wrapped response from an upstream server, or {@code null} if
184 * there is none.
185 */
186 public IntermediateClientResponseValue getUpstreamResponse()
187 {
188 return upstreamResponse;
189 }
190
191
192
193 /**
194 * Retrieves the IP address or resolvable name of the upstream server system,
195 * if available.
196 *
197 * @return The IP address or resolvable name of the upstream server system,
198 * {@code null} if there is no upstream server or its address is not
199 * available.
200 */
201 public String getUpstreamServerAddress()
202 {
203 return upstreamServerAddress;
204 }
205
206
207
208 /**
209 * Indicates whether the communication with the communication with the
210 * upstream server is secure (i.e., whether communication between the
211 * server application and the upstream server is safe from interpretation or
212 * undetectable alteration by a third party observer or interceptor).
213 *
214 *
215 * @return {@code Boolean.TRUE} if communication with the upstream server is
216 * secure, {@code Boolean.FALSE} if it is not secure, or
217 * {@code null} if there is no upstream server or it is not known
218 * whether the communication is secure.
219 */
220 public Boolean upstreamServerSecure()
221 {
222 return upstreamServerSecure;
223 }
224
225
226
227 /**
228 * Retrieves a string that identifies the server application that created this
229 * intermediate client response value.
230 *
231 * @return A string that may be used to identify the server application that
232 * created this intermediate client response value.
233 */
234 public String getServerName()
235 {
236 return serverName;
237 }
238
239
240
241 /**
242 * Retrieves a string that may be used to identify the session in the server
243 * application.
244 *
245 * @return A string that may be used to identify the session in the server
246 * application, or {@code null} if there is none.
247 */
248 public String getServerSessionID()
249 {
250 return serverSessionID;
251 }
252
253
254
255 /**
256 * Retrieves a string that may be used to identify the response in the server
257 * application.
258 *
259 * @return A string that may be used to identify the response in the server
260 * application, or {@code null} if there is none.
261 */
262 public String getServerResponseID()
263 {
264 return serverResponseID;
265 }
266
267
268
269 /**
270 * Encodes this intermediate client response value to a form that may be
271 * included in the response control.
272 *
273 * @return An ASN.1 octet string containing the encoded client response
274 * value.
275 */
276 public ASN1Sequence encode()
277 {
278 return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
279 }
280
281
282
283 /**
284 * Encodes this intermediate client response value to a form that may be
285 * included in the response control.
286 *
287 * @param type The BER type to use for this element.
288 *
289 * @return An ASN.1 octet string containing the encoded client response
290 * value.
291 */
292 private ASN1Sequence encode(final byte type)
293 {
294 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(6);
295
296 if (upstreamResponse != null)
297 {
298 elements.add(upstreamResponse.encode(TYPE_UPSTREAM_RESPONSE));
299 }
300
301 if (upstreamServerAddress != null)
302 {
303 elements.add(new ASN1OctetString(TYPE_UPSTREAM_SERVER_ADDRESS,
304 upstreamServerAddress));
305 }
306
307 if (upstreamServerSecure != null)
308 {
309 elements.add(new ASN1Boolean(TYPE_UPSTREAM_SERVER_SECURE,
310 upstreamServerSecure));
311 }
312
313 if (serverName != null)
314 {
315 elements.add(new ASN1OctetString(TYPE_SERVER_NAME, serverName));
316 }
317
318 if (serverSessionID != null)
319 {
320 elements.add(new ASN1OctetString(TYPE_SERVER_SESSION_ID,
321 serverSessionID));
322 }
323
324 if (serverResponseID != null)
325 {
326 elements.add(new ASN1OctetString(TYPE_SERVER_RESPONSE_ID,
327 serverResponseID));
328 }
329
330 return new ASN1Sequence(type, elements);
331 }
332
333
334
335 /**
336 * Decodes the provided ASN.1 sequence as an intermediate client response
337 * value.
338 *
339 * @param sequence The sequence to be decoded as an intermediate client
340 * response value.
341 *
342 * @return The decoded intermediate client response value.
343 *
344 * @throws LDAPException If the provided sequence cannot be decoded as an
345 * intermediate client response value.
346 */
347 public static IntermediateClientResponseValue
348 decode(final ASN1Sequence sequence)
349 throws LDAPException
350 {
351 Boolean upstreamServerSecure = null;
352 IntermediateClientResponseValue upstreamResponse = null;
353 String upstreamServerAddress = null;
354 String serverName = null;
355 String serverResponseID = null;
356 String serverSessionID = null;
357
358 for (final ASN1Element element : sequence.elements())
359 {
360 switch (element.getType())
361 {
362 case TYPE_UPSTREAM_RESPONSE:
363 try
364 {
365 final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element);
366 upstreamResponse = decode(s);
367 }
368 catch (LDAPException le)
369 {
370 debugException(le);
371 throw new LDAPException(ResultCode.DECODING_ERROR,
372 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get(
373 le.getMessage()), le);
374 }
375 catch (Exception e)
376 {
377 debugException(e);
378 throw new LDAPException(ResultCode.DECODING_ERROR,
379 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get(
380 String.valueOf(e)), e);
381 }
382 break;
383
384 case TYPE_UPSTREAM_SERVER_ADDRESS:
385 upstreamServerAddress =
386 ASN1OctetString.decodeAsOctetString(element).stringValue();
387 break;
388
389 case TYPE_UPSTREAM_SERVER_SECURE:
390 try
391 {
392 upstreamServerSecure =
393 ASN1Boolean.decodeAsBoolean(element).booleanValue();
394 }
395 catch (Exception e)
396 {
397 debugException(e);
398 throw new LDAPException(ResultCode.DECODING_ERROR,
399 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_SECURE.get(
400 String.valueOf(e)), e);
401 }
402 break;
403
404 case TYPE_SERVER_NAME:
405 serverName =
406 ASN1OctetString.decodeAsOctetString(element).stringValue();
407 break;
408
409 case TYPE_SERVER_SESSION_ID:
410 serverSessionID =
411 ASN1OctetString.decodeAsOctetString(element).stringValue();
412 break;
413
414 case TYPE_SERVER_RESPONSE_ID:
415 serverResponseID =
416 ASN1OctetString.decodeAsOctetString(element).stringValue();
417 break;
418
419 default:
420 throw new LDAPException(ResultCode.DECODING_ERROR,
421 ERR_ICRESP_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
422 }
423 }
424
425 return new IntermediateClientResponseValue(upstreamResponse,
426 upstreamServerAddress,
427 upstreamServerSecure,
428 serverName, serverSessionID,
429 serverResponseID);
430 }
431
432
433
434 /**
435 * Generates a hash code for this intermediate client response value.
436 *
437 * @return A hash code for this intermediate client response value.
438 */
439 @Override()
440 public int hashCode()
441 {
442 int hashCode = 0;
443
444 if (upstreamResponse != null)
445 {
446 hashCode += upstreamResponse.hashCode();
447 }
448
449 if (upstreamServerAddress != null)
450 {
451 hashCode += upstreamServerAddress.hashCode();
452 }
453
454 if (upstreamServerSecure != null)
455 {
456 hashCode += upstreamServerSecure.hashCode();
457 }
458
459 if (serverName != null)
460 {
461 hashCode += serverName.hashCode();
462 }
463
464 if (serverSessionID != null)
465 {
466 hashCode += serverSessionID.hashCode();
467 }
468
469 if (serverResponseID != null)
470 {
471 hashCode += serverResponseID.hashCode();
472 }
473
474 return hashCode;
475 }
476
477
478
479 /**
480 * Indicates whether the provided object is equal to this intermediate client
481 * response value. It will only be considered equal if the provided object is
482 * also an intermediate client response value with all the same fields.
483 *
484 * @param o The object for which to make the determination.
485 *
486 * @return {@code true} if the provided object is considered equal to this
487 * intermediate client response value, or {@code false} if not.
488 */
489 @Override()
490 public boolean equals(final Object o)
491 {
492 if (o == this)
493 {
494 return true;
495 }
496 else if (o == null)
497 {
498 return false;
499 }
500 else if (! (o instanceof IntermediateClientResponseValue))
501 {
502 return false;
503 }
504
505 final IntermediateClientResponseValue v =
506 (IntermediateClientResponseValue) o;
507
508 if (upstreamResponse == null)
509 {
510 if (v.upstreamResponse != null)
511 {
512 return false;
513 }
514 }
515 else
516 {
517 if (! upstreamResponse.equals(v.upstreamResponse))
518 {
519 return false;
520 }
521 }
522
523 if (upstreamServerAddress == null)
524 {
525 if (v.upstreamServerAddress != null)
526 {
527 return false;
528 }
529 }
530 else
531 {
532 if (! upstreamServerAddress.equals(v.upstreamServerAddress))
533 {
534 return false;
535 }
536 }
537
538 if (upstreamServerSecure == null)
539 {
540 if (v.upstreamServerSecure != null)
541 {
542 return false;
543 }
544 }
545 else
546 {
547 if (! upstreamServerSecure.equals(v.upstreamServerSecure))
548 {
549 return false;
550 }
551 }
552
553 if (serverName == null)
554 {
555 if (v.serverName != null)
556 {
557 return false;
558 }
559 }
560 else
561 {
562 if (! serverName.equals(v.serverName))
563 {
564 return false;
565 }
566 }
567
568 if (serverSessionID == null)
569 {
570 if (v.serverSessionID != null)
571 {
572 return false;
573 }
574 }
575 else
576 {
577 if (! serverSessionID.equals(v.serverSessionID))
578 {
579 return false;
580 }
581 }
582
583 if (serverResponseID == null)
584 {
585 if (v.serverResponseID != null)
586 {
587 return false;
588 }
589 }
590 else
591 {
592 if (! serverResponseID.equals(v.serverResponseID))
593 {
594 return false;
595 }
596 }
597
598 return true;
599 }
600
601
602
603 /**
604 * Retrieves a string representation of this intermediate client response
605 * value.
606 *
607 * @return A string representation of this intermediate client response
608 * value.
609 */
610 @Override()
611 public String toString()
612 {
613 final StringBuilder buffer = new StringBuilder();
614 toString(buffer);
615 return buffer.toString();
616 }
617
618
619
620 /**
621 * Appends a string representation of this intermediate client response value
622 * to the provided buffer.
623 *
624 * @param buffer The buffer to which the information is to be appended.
625 */
626 public void toString(final StringBuilder buffer)
627 {
628 buffer.append("IntermediateClientResponseValue(");
629
630 boolean added = false;
631 if (upstreamResponse != null)
632 {
633 buffer.append("upstreamResponse=");
634 upstreamResponse.toString(buffer);
635 added = true;
636 }
637
638 if (upstreamServerAddress != null)
639 {
640 if (added)
641 {
642 buffer.append(", ");
643 }
644 else
645 {
646 added = true;
647 }
648
649 buffer.append("upstreamServerAddress='");
650 buffer.append(upstreamServerAddress);
651 buffer.append('\'');
652 }
653
654 if (upstreamServerSecure != null)
655 {
656 if (added)
657 {
658 buffer.append(", ");
659 }
660 else
661 {
662 added = true;
663 }
664
665 buffer.append("upstreamServerSecure='");
666 buffer.append(upstreamServerSecure);
667 buffer.append('\'');
668 }
669
670 if (serverName != null)
671 {
672 if (added)
673 {
674 buffer.append(", ");
675 }
676 else
677 {
678 added = true;
679 }
680
681 buffer.append("serverName='");
682 buffer.append(serverName);
683 buffer.append('\'');
684 }
685
686 if (serverSessionID != null)
687 {
688 if (added)
689 {
690 buffer.append(", ");
691 }
692 else
693 {
694 added = true;
695 }
696
697 buffer.append("serverSessionID='");
698 buffer.append(serverSessionID);
699 buffer.append('\'');
700 }
701
702 if (serverResponseID != null)
703 {
704 if (added)
705 {
706 buffer.append(", ");
707 }
708 else
709 {
710 added = true;
711 }
712
713 buffer.append("serverResponseID='");
714 buffer.append(serverResponseID);
715 buffer.append('\'');
716 }
717
718 buffer.append(')');
719 }
720 }