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 }