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 request value. It may recursively embed intermediate 054 * client request values from downstream clients. 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 IntermediateClientRequestValue 063 implements Serializable 064 { 065 /** 066 * The BER type for the downstreamRequest element. 067 */ 068 private static final byte TYPE_DOWNSTREAM_REQUEST = (byte) 0xA0; 069 070 071 072 /** 073 * The BER type for the downstreamClientAddress element. 074 */ 075 private static final byte TYPE_DOWNSTREAM_CLIENT_ADDRESS = (byte) 0x81; 076 077 078 079 /** 080 * The BER type for the downstreamClientSecure element. 081 */ 082 private static final byte TYPE_DOWNSTREAM_CLIENT_SECURE = (byte) 0x82; 083 084 085 086 /** 087 * The BER type for the clientIdentity element. 088 */ 089 private static final byte TYPE_CLIENT_IDENTITY = (byte) 0x83; 090 091 092 093 /** 094 * The BER type for the clientName element. 095 */ 096 private static final byte TYPE_CLIENT_NAME = (byte) 0x84; 097 098 099 100 /** 101 * The BER type for the clientSessionID element. 102 */ 103 private static final byte TYPE_CLIENT_SESSION_ID = (byte) 0x85; 104 105 106 107 /** 108 * The BER type for the clientRequestID element. 109 */ 110 private static final byte TYPE_CLIENT_REQUEST_ID = (byte) 0x86; 111 112 113 114 /** 115 * The serial version UID for this serializable class. 116 */ 117 private static final long serialVersionUID = -794887520013838259L; 118 119 120 121 // Indicates whether the communication with the downstream client is secure. 122 private final Boolean downstreamClientSecure; 123 124 // The downstream request value, if present. 125 private final IntermediateClientRequestValue downstreamRequest; 126 127 // The requested client authorization identity, if present. 128 private final String clientIdentity; 129 130 // The downstream client address, if present. 131 private final String downstreamClientAddress; 132 133 // The client name, which describes the client application, if present. 134 private final String clientName; 135 136 // The client request ID, if present. 137 private final String clientRequestID; 138 139 // The client session ID, if present. 140 private final String clientSessionID; 141 142 143 144 /** 145 * Creates a new intermediate client request value with the provided 146 * information. 147 * 148 * @param downstreamRequest A wrapped intermediate client request from 149 * a downstream client. It may be 150 * {@code null} if there is no downstream 151 * request. 152 * @param downstreamClientAddress The IP address or resolvable name of the 153 * downstream client system. It may be 154 * {@code null} if there is no downstream 155 * client or its address is not available. 156 * @param downstreamClientSecure Indicates whether communication with the 157 * downstream client is secure. It may be 158 * {@code null} if there is no downstream 159 * client or it is not known whether the 160 * communication is secure. 161 * @param clientIdentity The requested client authorization 162 * identity. It may be {@code null} if there 163 * is no requested authorization identity. 164 * @param clientName An identifier string that summarizes the 165 * client application that created this 166 * intermediate client request. It may be 167 * {@code null} if that information is not 168 * available. 169 * @param clientSessionID A string that may be used to identify the 170 * session in the client application. It may 171 * be {@code null} if there is no available 172 * session identifier. 173 * @param clientRequestID A string that may be used to identify the 174 * request in the client application. It may 175 * be {@code null} if there is no available 176 * request identifier. 177 */ 178 public IntermediateClientRequestValue( 179 final IntermediateClientRequestValue downstreamRequest, 180 final String downstreamClientAddress, 181 final Boolean downstreamClientSecure, final String clientIdentity, 182 final String clientName, final String clientSessionID, 183 final String clientRequestID) 184 { 185 this.downstreamRequest = downstreamRequest; 186 this.downstreamClientAddress = downstreamClientAddress; 187 this.downstreamClientSecure = downstreamClientSecure; 188 this.clientIdentity = clientIdentity; 189 this.clientName = clientName; 190 this.clientSessionID = clientSessionID; 191 this.clientRequestID = clientRequestID; 192 } 193 194 195 196 /** 197 * Retrieves the wrapped request from a downstream client, if available. 198 * 199 * @return The wrapped request from a downstream client, or {@code null} if 200 * there is none. 201 */ 202 public IntermediateClientRequestValue getDownstreamRequest() 203 { 204 return downstreamRequest; 205 } 206 207 208 209 /** 210 * Retrieves the requested client authorization identity, if available. 211 * 212 * @return The requested client authorization identity, or {@code null} if 213 * there is none. 214 */ 215 public String getClientIdentity() 216 { 217 return clientIdentity; 218 } 219 220 221 222 /** 223 * Retrieves the IP address or resolvable name of the downstream client 224 * system, if available. 225 * 226 * @return The IP address or resolvable name of the downstream client system, 227 * or {@code null} if there is no downstream client or its address is 228 * not available. 229 */ 230 public String getDownstreamClientAddress() 231 { 232 return downstreamClientAddress; 233 } 234 235 236 237 /** 238 * Indicates whether the communication with the communication with the 239 * downstream client is secure (i.e., whether communication between the 240 * client application and the downstream client is safe from interpretation or 241 * undetectable alteration by a third party observer or interceptor). 242 * 243 * 244 * @return {@code Boolean.TRUE} if communication with the downstream client 245 * is secure, {@code Boolean.FALSE} if it is not secure, or 246 * {@code null} if there is no downstream client or it is not known 247 * whether the communication is secure. 248 */ 249 public Boolean downstreamClientSecure() 250 { 251 return downstreamClientSecure; 252 } 253 254 255 256 /** 257 * Retrieves a string that identifies the client application that created this 258 * intermediate client request value. 259 * 260 * @return A string that may be used to identify the client application that 261 * created this intermediate client request value. 262 */ 263 public String getClientName() 264 { 265 return clientName; 266 } 267 268 269 270 /** 271 * Retrieves a string that may be used to identify the session in the client 272 * application. 273 * 274 * @return A string that may be used to identify the session in the client 275 * application, or {@code null} if there is none. 276 */ 277 public String getClientSessionID() 278 { 279 return clientSessionID; 280 } 281 282 283 284 /** 285 * Retrieves a string that may be used to identify the request in the client 286 * application. 287 * 288 * @return A string that may be used to identify the request in the client 289 * application, or {@code null} if there is none. 290 */ 291 public String getClientRequestID() 292 { 293 return clientRequestID; 294 } 295 296 297 298 /** 299 * Encodes this intermediate client request value to a form that may be 300 * included in the request control. 301 * 302 * @return An ASN.1 octet string containing the encoded client request value. 303 */ 304 public ASN1Sequence encode() 305 { 306 return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 307 } 308 309 310 311 /** 312 * Encodes this intermediate client request value to a form that may be 313 * included in the request control. 314 * 315 * @param type The BER type to use for this element. 316 * 317 * @return An ASN.1 octet string containing the encoded client request value. 318 */ 319 private ASN1Sequence encode(final byte type) 320 { 321 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(7); 322 323 if (downstreamRequest != null) 324 { 325 elements.add(downstreamRequest.encode(TYPE_DOWNSTREAM_REQUEST)); 326 } 327 328 if (downstreamClientAddress != null) 329 { 330 elements.add(new ASN1OctetString(TYPE_DOWNSTREAM_CLIENT_ADDRESS, 331 downstreamClientAddress)); 332 } 333 334 if (downstreamClientSecure != null) 335 { 336 elements.add(new ASN1Boolean(TYPE_DOWNSTREAM_CLIENT_SECURE, 337 downstreamClientSecure)); 338 } 339 340 if (clientIdentity != null) 341 { 342 elements.add(new ASN1OctetString(TYPE_CLIENT_IDENTITY, clientIdentity)); 343 } 344 345 if (clientName != null) 346 { 347 elements.add(new ASN1OctetString(TYPE_CLIENT_NAME, clientName)); 348 } 349 350 if (clientSessionID != null) 351 { 352 elements.add(new ASN1OctetString(TYPE_CLIENT_SESSION_ID, 353 clientSessionID)); 354 } 355 356 if (clientRequestID != null) 357 { 358 elements.add(new ASN1OctetString(TYPE_CLIENT_REQUEST_ID, 359 clientRequestID)); 360 } 361 362 return new ASN1Sequence(type, elements); 363 } 364 365 366 367 /** 368 * Decodes the provided ASN.1 sequence as an intermediate client request 369 * value. 370 * 371 * @param sequence The sequence to be decoded as an intermediate client 372 * request value. 373 * 374 * @return The decoded intermediate client request value. 375 * 376 * @throws LDAPException If the provided sequence cannot be decoded as an 377 * intermediate client request value. 378 */ 379 public static IntermediateClientRequestValue 380 decode(final ASN1Sequence sequence) 381 throws LDAPException 382 { 383 Boolean downstreamClientSecure = null; 384 IntermediateClientRequestValue downstreamRequest = null; 385 String clientIdentity = null; 386 String downstreamClientAddress = null; 387 String clientName = null; 388 String clientRequestID = null; 389 String clientSessionID = null; 390 391 for (final ASN1Element element : sequence.elements()) 392 { 393 switch (element.getType()) 394 { 395 case TYPE_DOWNSTREAM_REQUEST: 396 try 397 { 398 final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element); 399 downstreamRequest = decode(s); 400 } 401 catch (LDAPException le) 402 { 403 debugException(le); 404 throw new LDAPException(ResultCode.DECODING_ERROR, 405 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get( 406 le.getMessage()), le); 407 } 408 catch (Exception e) 409 { 410 debugException(e); 411 throw new LDAPException(ResultCode.DECODING_ERROR, 412 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get( 413 String.valueOf(e)), e); 414 } 415 break; 416 417 case TYPE_DOWNSTREAM_CLIENT_ADDRESS: 418 downstreamClientAddress = 419 ASN1OctetString.decodeAsOctetString(element).stringValue(); 420 break; 421 422 case TYPE_DOWNSTREAM_CLIENT_SECURE: 423 try 424 { 425 downstreamClientSecure = 426 ASN1Boolean.decodeAsBoolean(element).booleanValue(); 427 } 428 catch (Exception e) 429 { 430 debugException(e); 431 throw new LDAPException(ResultCode.DECODING_ERROR, 432 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_SECURE.get( 433 String.valueOf(e)), e); 434 } 435 break; 436 437 case TYPE_CLIENT_IDENTITY: 438 clientIdentity = 439 ASN1OctetString.decodeAsOctetString(element).stringValue(); 440 break; 441 442 case TYPE_CLIENT_NAME: 443 clientName = 444 ASN1OctetString.decodeAsOctetString(element).stringValue(); 445 break; 446 447 case TYPE_CLIENT_SESSION_ID: 448 clientSessionID = 449 ASN1OctetString.decodeAsOctetString(element).stringValue(); 450 break; 451 452 case TYPE_CLIENT_REQUEST_ID: 453 clientRequestID = 454 ASN1OctetString.decodeAsOctetString(element).stringValue(); 455 break; 456 457 default: 458 throw new LDAPException(ResultCode.DECODING_ERROR, 459 ERR_ICREQ_INVALID_ELEMENT_TYPE.get(toHex(element.getType()))); 460 } 461 } 462 463 return new IntermediateClientRequestValue(downstreamRequest, 464 downstreamClientAddress, 465 downstreamClientSecure, 466 clientIdentity, clientName, 467 clientSessionID, clientRequestID); 468 } 469 470 471 472 /** 473 * Generates a hash code for this intermediate client request value. 474 * 475 * @return A hash code for this intermediate client request value. 476 */ 477 @Override() 478 public int hashCode() 479 { 480 int hashCode = 0; 481 482 if (downstreamRequest != null) 483 { 484 hashCode += downstreamRequest.hashCode(); 485 } 486 487 if (downstreamClientAddress != null) 488 { 489 hashCode += downstreamClientAddress.hashCode(); 490 } 491 492 if (downstreamClientSecure != null) 493 { 494 hashCode += downstreamClientSecure.hashCode(); 495 } 496 497 if (clientIdentity != null) 498 { 499 hashCode += clientIdentity.hashCode(); 500 } 501 502 if (clientName != null) 503 { 504 hashCode += clientName.hashCode(); 505 } 506 507 if (clientSessionID != null) 508 { 509 hashCode += clientSessionID.hashCode(); 510 } 511 512 if (clientRequestID != null) 513 { 514 hashCode += clientRequestID.hashCode(); 515 } 516 517 return hashCode; 518 } 519 520 521 522 /** 523 * Indicates whether the provided object is equal to this intermediate client 524 * request value. It will only be considered equal if the provided object is 525 * also an intermediate client request value with all the same fields. 526 * 527 * @param o The object for which to make the determination. 528 * 529 * @return {@code true} if the provided object is considered equal to this 530 * intermediate client request value, or {@code false} if not. 531 */ 532 @Override() 533 public boolean equals(final Object o) 534 { 535 if (o == this) 536 { 537 return true; 538 } 539 else if (o == null) 540 { 541 return false; 542 } 543 else if (! (o instanceof IntermediateClientRequestValue)) 544 { 545 return false; 546 } 547 548 final IntermediateClientRequestValue v = (IntermediateClientRequestValue) o; 549 550 if (downstreamRequest == null) 551 { 552 if (v.downstreamRequest != null) 553 { 554 return false; 555 } 556 } 557 else 558 { 559 if (! downstreamRequest.equals(v.downstreamRequest)) 560 { 561 return false; 562 } 563 } 564 565 if (downstreamClientAddress == null) 566 { 567 if (v.downstreamClientAddress != null) 568 { 569 return false; 570 } 571 } 572 else 573 { 574 if (! downstreamClientAddress.equals(v.downstreamClientAddress)) 575 { 576 return false; 577 } 578 } 579 580 if (downstreamClientSecure == null) 581 { 582 if (v.downstreamClientSecure != null) 583 { 584 return false; 585 } 586 } 587 else 588 { 589 if (! downstreamClientSecure.equals(v.downstreamClientSecure)) 590 { 591 return false; 592 } 593 } 594 595 if (clientIdentity == null) 596 { 597 if (v.clientIdentity != null) 598 { 599 return false; 600 } 601 } 602 else 603 { 604 if (! clientIdentity.equals(v.clientIdentity)) 605 { 606 return false; 607 } 608 } 609 610 if (clientName == null) 611 { 612 if (v.clientName != null) 613 { 614 return false; 615 } 616 } 617 else 618 { 619 if (! clientName.equals(v.clientName)) 620 { 621 return false; 622 } 623 } 624 625 if (clientSessionID == null) 626 { 627 if (v.clientSessionID != null) 628 { 629 return false; 630 } 631 } 632 else 633 { 634 if (! clientSessionID.equals(v.clientSessionID)) 635 { 636 return false; 637 } 638 } 639 640 if (clientRequestID == null) 641 { 642 if (v.clientRequestID != null) 643 { 644 return false; 645 } 646 } 647 else 648 { 649 if (! clientRequestID.equals(v.clientRequestID)) 650 { 651 return false; 652 } 653 } 654 655 return true; 656 } 657 658 659 660 /** 661 * Retrieves a string representation of this intermediate client request 662 * value. 663 * 664 * @return A string representation of this intermediate client request value. 665 */ 666 @Override() 667 public String toString() 668 { 669 final StringBuilder buffer = new StringBuilder(); 670 toString(buffer); 671 return buffer.toString(); 672 } 673 674 675 676 /** 677 * Appends a string representation of this intermediate client request value 678 * to the provided buffer. 679 * 680 * @param buffer The buffer to which the information is to be appended. 681 */ 682 public void toString(final StringBuilder buffer) 683 { 684 buffer.append("IntermediateClientRequestValue("); 685 686 boolean added = false; 687 if (downstreamRequest != null) 688 { 689 buffer.append("downstreamRequest="); 690 downstreamRequest.toString(buffer); 691 added = true; 692 } 693 694 if (clientIdentity != null) 695 { 696 if (added) 697 { 698 buffer.append(", "); 699 } 700 else 701 { 702 added = true; 703 } 704 705 buffer.append("clientIdentity='"); 706 buffer.append(clientIdentity); 707 buffer.append('\''); 708 } 709 710 if (downstreamClientAddress != null) 711 { 712 if (added) 713 { 714 buffer.append(", "); 715 } 716 else 717 { 718 added = true; 719 } 720 721 buffer.append("downstreamClientAddress='"); 722 buffer.append(downstreamClientAddress); 723 buffer.append('\''); 724 } 725 726 if (downstreamClientSecure != null) 727 { 728 if (added) 729 { 730 buffer.append(", "); 731 } 732 else 733 { 734 added = true; 735 } 736 737 buffer.append("downstreamClientSecure='"); 738 buffer.append(downstreamClientSecure); 739 buffer.append('\''); 740 } 741 742 if (clientName != null) 743 { 744 if (added) 745 { 746 buffer.append(", "); 747 } 748 else 749 { 750 added = true; 751 } 752 753 buffer.append("clientName='"); 754 buffer.append(clientName); 755 buffer.append('\''); 756 } 757 758 if (clientSessionID != null) 759 { 760 if (added) 761 { 762 buffer.append(", "); 763 } 764 else 765 { 766 added = true; 767 } 768 769 buffer.append("clientSessionID='"); 770 buffer.append(clientSessionID); 771 buffer.append('\''); 772 } 773 774 if (clientRequestID != null) 775 { 776 if (added) 777 { 778 buffer.append(", "); 779 } 780 else 781 { 782 added = true; 783 } 784 785 buffer.append("clientRequestID='"); 786 buffer.append(clientRequestID); 787 buffer.append('\''); 788 } 789 790 buffer.append(')'); 791 } 792 }