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