001/* 002 * Copyright 2009-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2018 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.protocol; 022 023 024 025import java.io.InterruptedIOException; 026import java.io.IOException; 027import java.io.Serializable; 028import java.net.SocketTimeoutException; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.Collections; 032import java.util.Iterator; 033import java.util.List; 034 035import com.unboundid.asn1.ASN1Buffer; 036import com.unboundid.asn1.ASN1BufferSequence; 037import com.unboundid.asn1.ASN1Element; 038import com.unboundid.asn1.ASN1Integer; 039import com.unboundid.asn1.ASN1Sequence; 040import com.unboundid.asn1.ASN1StreamReader; 041import com.unboundid.asn1.ASN1StreamReaderSequence; 042import com.unboundid.ldap.sdk.Control; 043import com.unboundid.ldap.sdk.InternalSDKHelper; 044import com.unboundid.ldap.sdk.LDAPException; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.schema.Schema; 047import com.unboundid.util.Debug; 048import com.unboundid.util.InternalUseOnly; 049import com.unboundid.util.NotMutable; 050import com.unboundid.util.StaticUtils; 051import com.unboundid.util.ThreadSafety; 052import com.unboundid.util.ThreadSafetyLevel; 053 054import static com.unboundid.ldap.protocol.ProtocolMessages.*; 055 056 057 058/** 059 * This class provides a data structure that may be used to represent LDAP 060 * protocol messages. Each LDAP message contains a message ID, a protocol op, 061 * and an optional set of controls. 062 */ 063@InternalUseOnly() 064@NotMutable() 065@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 066public final class LDAPMessage 067 implements Serializable 068{ 069 /** 070 * The BER type to use for the bind request protocol op. 071 */ 072 public static final byte PROTOCOL_OP_TYPE_BIND_REQUEST = 0x60; 073 074 075 076 /** 077 * The BER type to use for the bind response protocol op. 078 */ 079 public static final byte PROTOCOL_OP_TYPE_BIND_RESPONSE = 0x61; 080 081 082 083 /** 084 * The BER type to use for the unbind request protocol op. 085 */ 086 public static final byte PROTOCOL_OP_TYPE_UNBIND_REQUEST = 0x42; 087 088 089 090 /** 091 * The BER type to use for the search request protocol op. 092 */ 093 public static final byte PROTOCOL_OP_TYPE_SEARCH_REQUEST = 0x63; 094 095 096 097 /** 098 * The BER type to use for the search result entry protocol op. 099 */ 100 public static final byte PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY = 0x64; 101 102 103 104 /** 105 * The BER type to use for the search result reference protocol op. 106 */ 107 public static final byte PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE = 0x73; 108 109 110 111 /** 112 * The BER type to use for the search result done protocol op. 113 */ 114 public static final byte PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE = 0x65; 115 116 117 118 /** 119 * The BER type to use for the modify request protocol op. 120 */ 121 public static final byte PROTOCOL_OP_TYPE_MODIFY_REQUEST = 0x66; 122 123 124 125 /** 126 * The BER type to use for the modify response protocol op. 127 */ 128 public static final byte PROTOCOL_OP_TYPE_MODIFY_RESPONSE = 0x67; 129 130 131 132 /** 133 * The BER type to use for the add request protocol op. 134 */ 135 public static final byte PROTOCOL_OP_TYPE_ADD_REQUEST = 0x68; 136 137 138 139 /** 140 * The BER type to use for the add response protocol op. 141 */ 142 public static final byte PROTOCOL_OP_TYPE_ADD_RESPONSE = 0x69; 143 144 145 146 /** 147 * The BER type to use for the delete request protocol op. 148 */ 149 public static final byte PROTOCOL_OP_TYPE_DELETE_REQUEST = 0x4A; 150 151 152 153 /** 154 * The BER type to use for the delete response protocol op. 155 */ 156 public static final byte PROTOCOL_OP_TYPE_DELETE_RESPONSE = 0x6B; 157 158 159 160 /** 161 * The BER type to use for the modify DN request protocol op. 162 */ 163 public static final byte PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST = 0x6C; 164 165 166 167 /** 168 * The BER type to use for the modify DN response protocol op. 169 */ 170 public static final byte PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE = 0x6D; 171 172 173 174 /** 175 * The BER type to use for the compare request protocol op. 176 */ 177 public static final byte PROTOCOL_OP_TYPE_COMPARE_REQUEST = 0x6E; 178 179 180 181 /** 182 * The BER type to use for the compare response protocol op. 183 */ 184 public static final byte PROTOCOL_OP_TYPE_COMPARE_RESPONSE = 0x6F; 185 186 187 188 /** 189 * The BER type to use for the abandon request protocol op. 190 */ 191 public static final byte PROTOCOL_OP_TYPE_ABANDON_REQUEST = 0x50; 192 193 194 195 /** 196 * The BER type to use for the extended request protocol op. 197 */ 198 public static final byte PROTOCOL_OP_TYPE_EXTENDED_REQUEST = 0x77; 199 200 201 202 /** 203 * The BER type to use for the extended response protocol op. 204 */ 205 public static final byte PROTOCOL_OP_TYPE_EXTENDED_RESPONSE = 0x78; 206 207 208 209 /** 210 * The BER type to use for the intermediate response protocol op. 211 */ 212 public static final byte PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE = 0x79; 213 214 215 216 /** 217 * The BER type to use for the set of controls. 218 */ 219 public static final byte MESSAGE_TYPE_CONTROLS = (byte) 0xA0; 220 221 222 223 /** 224 * The serial version UID for this serializable class. 225 */ 226 private static final long serialVersionUID = 909272448857832592L; 227 228 229 230 // The message ID for this LDAP message. 231 private final int messageID; 232 233 // The protocol op for this LDAP message. 234 private final ProtocolOp protocolOp; 235 236 // The set of controls for this LDAP message. 237 private final List<Control> controls; 238 239 240 241 /** 242 * Creates a new LDAP message with the provided information. 243 * 244 * @param messageID The message ID for this LDAP message. 245 * @param protocolOp The protocol op for this LDAP message. It must not be 246 * {@code null}. 247 * @param controls The set of controls for this LDAP message. It may be 248 * {@code null} or empty if no controls are required. 249 */ 250 public LDAPMessage(final int messageID, final ProtocolOp protocolOp, 251 final Control... controls) 252 { 253 this.messageID = messageID; 254 this.protocolOp = protocolOp; 255 256 if (controls == null) 257 { 258 this.controls = Collections.emptyList(); 259 } 260 else 261 { 262 this.controls = Collections.unmodifiableList(Arrays.asList(controls)); 263 } 264 } 265 266 267 268 /** 269 * Creates a new LDAP message with the provided information. 270 * 271 * @param messageID The message ID for this LDAP message. 272 * @param protocolOp The protocol op for this LDAP message. It must not be 273 * {@code null}. 274 * @param controls The set of controls for this LDAP message. It may be 275 * {@code null} or empty if no controls are required. 276 */ 277 public LDAPMessage(final int messageID, final ProtocolOp protocolOp, 278 final List<Control> controls) 279 { 280 this.messageID = messageID; 281 this.protocolOp = protocolOp; 282 283 if (controls == null) 284 { 285 this.controls = Collections.emptyList(); 286 } 287 else 288 { 289 this.controls = Collections.unmodifiableList(controls); 290 } 291 } 292 293 294 295 /** 296 * Retrieves the message ID for this LDAP message. 297 * 298 * @return The message ID for this LDAP message. 299 */ 300 public int getMessageID() 301 { 302 return messageID; 303 } 304 305 306 307 /** 308 * Retrieves the protocol op for this LDAP message. 309 * 310 * @return The protocol op for this LDAP message. 311 */ 312 public ProtocolOp getProtocolOp() 313 { 314 return protocolOp; 315 } 316 317 318 319 /** 320 * Retrieves the BER type for the protocol op contained in this LDAP message. 321 * 322 * @return The BER type for the protocol op contained in this LDAP message. 323 */ 324 public byte getProtocolOpType() 325 { 326 return protocolOp.getProtocolOpType(); 327 } 328 329 330 331 /** 332 * Retrieves the abandon request protocol op from this LDAP message. This may 333 * only be used if this LDAP message was obtained using the {@link #readFrom} 334 * method. 335 * 336 * @return The abandon request protocol op from this LDAP message. 337 * 338 * @throws ClassCastException If the protocol op for this LDAP message is 339 * not an abandon request protocol op. 340 */ 341 public AbandonRequestProtocolOp getAbandonRequestProtocolOp() 342 throws ClassCastException 343 { 344 return (AbandonRequestProtocolOp) protocolOp; 345 } 346 347 348 349 /** 350 * Retrieves the add request protocol op from this LDAP message. This may 351 * only be used if this LDAP message was obtained using the {@link #readFrom} 352 * method. 353 * 354 * @return The add request protocol op from this LDAP message. 355 * 356 * @throws ClassCastException If the protocol op for this LDAP message is 357 * not an add request protocol op. 358 */ 359 public AddRequestProtocolOp getAddRequestProtocolOp() 360 throws ClassCastException 361 { 362 return (AddRequestProtocolOp) protocolOp; 363 } 364 365 366 367 /** 368 * Retrieves the add response protocol op from this LDAP message. This may 369 * only be used if this LDAP message was obtained using the {@link #readFrom} 370 * method. 371 * 372 * @return The add response protocol op from this LDAP message. 373 * 374 * @throws ClassCastException If the protocol op for this LDAP message is 375 * not an add response protocol op. 376 */ 377 public AddResponseProtocolOp getAddResponseProtocolOp() 378 throws ClassCastException 379 { 380 return (AddResponseProtocolOp) protocolOp; 381 } 382 383 384 385 /** 386 * Retrieves the bind request protocol op from this LDAP message. This may 387 * only be used if this LDAP message was obtained using the {@link #readFrom} 388 * method. 389 * 390 * @return The bind request protocol op from this LDAP message. 391 * 392 * @throws ClassCastException If the protocol op for this LDAP message is 393 * not a bind request protocol op. 394 */ 395 public BindRequestProtocolOp getBindRequestProtocolOp() 396 throws ClassCastException 397 { 398 return (BindRequestProtocolOp) protocolOp; 399 } 400 401 402 403 /** 404 * Retrieves the bind response protocol op from this LDAP message. This may 405 * only be used if this LDAP message was obtained using the {@link #readFrom} 406 * method. 407 * 408 * @return The bind response protocol op from this LDAP message. 409 * 410 * @throws ClassCastException If the protocol op for this LDAP message is 411 * not a bind response protocol op. 412 */ 413 public BindResponseProtocolOp getBindResponseProtocolOp() 414 throws ClassCastException 415 { 416 return (BindResponseProtocolOp) protocolOp; 417 } 418 419 420 421 /** 422 * Retrieves the compare request protocol op from this LDAP message. This may 423 * only be used if this LDAP message was obtained using the {@link #readFrom} 424 * method. 425 * 426 * @return The compare request protocol op from this LDAP message. 427 * 428 * @throws ClassCastException If the protocol op for this LDAP message is 429 * not a compare request protocol op. 430 */ 431 public CompareRequestProtocolOp getCompareRequestProtocolOp() 432 throws ClassCastException 433 { 434 return (CompareRequestProtocolOp) protocolOp; 435 } 436 437 438 439 /** 440 * Retrieves the compare response protocol op from this LDAP message. This 441 * may only be used if this LDAP message was obtained using the 442 * {@link #readFrom} method. 443 * 444 * @return The compare response protocol op from this LDAP message. 445 * 446 * @throws ClassCastException If the protocol op for this LDAP message is 447 * not a compare response protocol op. 448 */ 449 public CompareResponseProtocolOp getCompareResponseProtocolOp() 450 throws ClassCastException 451 { 452 return (CompareResponseProtocolOp) protocolOp; 453 } 454 455 456 457 /** 458 * Retrieves the delete request protocol op from this LDAP message. This may 459 * only be used if this LDAP message was obtained using the {@link #readFrom} 460 * method. 461 * 462 * @return The delete request protocol op from this LDAP message. 463 * 464 * @throws ClassCastException If the protocol op for this LDAP message is 465 * not a delete request protocol op. 466 */ 467 public DeleteRequestProtocolOp getDeleteRequestProtocolOp() 468 throws ClassCastException 469 { 470 return (DeleteRequestProtocolOp) protocolOp; 471 } 472 473 474 475 /** 476 * Retrieves the delete response protocol op from this LDAP message. This may 477 * only be used if this LDAP message was obtained using the {@link #readFrom} 478 * method. 479 * 480 * @return The delete response protocol op from this LDAP message. 481 * 482 * @throws ClassCastException If the protocol op for this LDAP message is 483 * not a delete response protocol op. 484 */ 485 public DeleteResponseProtocolOp getDeleteResponseProtocolOp() 486 throws ClassCastException 487 { 488 return (DeleteResponseProtocolOp) protocolOp; 489 } 490 491 492 493 /** 494 * Retrieves the extended request protocol op from this LDAP message. This 495 * may only be used if this LDAP message was obtained using the 496 * {@link #readFrom} method. 497 * 498 * @return The extended request protocol op from this LDAP message. 499 * 500 * @throws ClassCastException If the protocol op for this LDAP message is 501 * not an extended request protocol op. 502 */ 503 public ExtendedRequestProtocolOp getExtendedRequestProtocolOp() 504 throws ClassCastException 505 { 506 return (ExtendedRequestProtocolOp) protocolOp; 507 } 508 509 510 511 /** 512 * Retrieves the extended response protocol op from this LDAP message. This 513 * may only be used if this LDAP message was obtained using the 514 * {@link #readFrom} method. 515 * 516 * @return The extended response protocol op from this LDAP message. 517 * 518 * @throws ClassCastException If the protocol op for this LDAP message is 519 * not an extended response protocol op. 520 */ 521 public ExtendedResponseProtocolOp getExtendedResponseProtocolOp() 522 throws ClassCastException 523 { 524 return (ExtendedResponseProtocolOp) protocolOp; 525 } 526 527 528 529 /** 530 * Retrieves the modify request protocol op from this LDAP message. This may 531 * only be used if this LDAP message was obtained using the {@link #readFrom} 532 * method. 533 * 534 * @return The modify request protocol op from this LDAP message. 535 * 536 * @throws ClassCastException If the protocol op for this LDAP message is 537 * not a modify request protocol op. 538 */ 539 public ModifyRequestProtocolOp getModifyRequestProtocolOp() 540 throws ClassCastException 541 { 542 return (ModifyRequestProtocolOp) protocolOp; 543 } 544 545 546 547 /** 548 * Retrieves the modify response protocol op from this LDAP message. This may 549 * only be used if this LDAP message was obtained using the {@link #readFrom} 550 * method. 551 * 552 * @return The modify response protocol op from this LDAP message. 553 * 554 * @throws ClassCastException If the protocol op for this LDAP message is 555 * not a modify response protocol op. 556 */ 557 public ModifyResponseProtocolOp getModifyResponseProtocolOp() 558 throws ClassCastException 559 { 560 return (ModifyResponseProtocolOp) protocolOp; 561 } 562 563 564 565 /** 566 * Retrieves the modify DN request protocol op from this LDAP message. This 567 * may only be used if this LDAP message was obtained using the 568 * {@link #readFrom} method. 569 * 570 * @return The modify DN request protocol op from this LDAP message. 571 * 572 * @throws ClassCastException If the protocol op for this LDAP message is 573 * not a modify DN request protocol op. 574 */ 575 public ModifyDNRequestProtocolOp getModifyDNRequestProtocolOp() 576 throws ClassCastException 577 { 578 return (ModifyDNRequestProtocolOp) protocolOp; 579 } 580 581 582 583 /** 584 * Retrieves the modify DN response protocol op from this LDAP message. This 585 * may only be used if this LDAP message was obtained using the 586 * {@link #readFrom} method. 587 * 588 * @return The modify DN response protocol op from this LDAP message. 589 * 590 * @throws ClassCastException If the protocol op for this LDAP message is 591 * not a modify DN response protocol op. 592 */ 593 public ModifyDNResponseProtocolOp getModifyDNResponseProtocolOp() 594 throws ClassCastException 595 { 596 return (ModifyDNResponseProtocolOp) protocolOp; 597 } 598 599 600 601 /** 602 * Retrieves the search request protocol op from this LDAP message. This 603 * may only be used if this LDAP message was obtained using the 604 * {@link #readFrom} method. 605 * 606 * @return The search request protocol op from this LDAP message. 607 * 608 * @throws ClassCastException If the protocol op for this LDAP message is 609 * not a search request protocol op. 610 */ 611 public SearchRequestProtocolOp getSearchRequestProtocolOp() 612 throws ClassCastException 613 { 614 return (SearchRequestProtocolOp) protocolOp; 615 } 616 617 618 619 /** 620 * Retrieves the search result entry protocol op from this LDAP message. This 621 * may only be used if this LDAP message was obtained using the 622 * {@link #readFrom} method. 623 * 624 * @return The search result entry protocol op from this LDAP message. 625 * 626 * @throws ClassCastException If the protocol op for this LDAP message is 627 * not a search result entry protocol op. 628 */ 629 public SearchResultEntryProtocolOp getSearchResultEntryProtocolOp() 630 throws ClassCastException 631 { 632 return (SearchResultEntryProtocolOp) protocolOp; 633 } 634 635 636 637 /** 638 * Retrieves the search result reference protocol op from this LDAP message. 639 * This may only be used if this LDAP message was obtained using the 640 * {@link #readFrom} method. 641 * 642 * @return The search result reference protocol op from this LDAP message. 643 * 644 * @throws ClassCastException If the protocol op for this LDAP message is 645 * not a search result reference protocol op. 646 */ 647 public SearchResultReferenceProtocolOp getSearchResultReferenceProtocolOp() 648 throws ClassCastException 649 { 650 return (SearchResultReferenceProtocolOp) protocolOp; 651 } 652 653 654 655 /** 656 * Retrieves the search result done protocol op from this LDAP message. This 657 * may only be used if this LDAP message was obtained using the 658 * {@link #readFrom} method. 659 * 660 * @return The search result done protocol op from this LDAP message. 661 * 662 * @throws ClassCastException If the protocol op for this LDAP message is 663 * not a search result done protocol op. 664 */ 665 public SearchResultDoneProtocolOp getSearchResultDoneProtocolOp() 666 throws ClassCastException 667 { 668 return (SearchResultDoneProtocolOp) protocolOp; 669 } 670 671 672 673 /** 674 * Retrieves the unbind request protocol op from this LDAP message. This may 675 * only be used if this LDAP message was obtained using the {@link #readFrom} 676 * method. 677 * 678 * @return The unbind request protocol op from this LDAP message. 679 * 680 * @throws ClassCastException If the protocol op for this LDAP message is 681 * not an unbind request protocol op. 682 */ 683 public UnbindRequestProtocolOp getUnbindRequestProtocolOp() 684 throws ClassCastException 685 { 686 return (UnbindRequestProtocolOp) protocolOp; 687 } 688 689 690 691 /** 692 * Retrieves the intermediate response protocol op from this LDAP message. 693 * This may only be used if this LDAP message was obtained using the 694 * {@link #readFrom} method. 695 * 696 * @return The intermediate response protocol op from this LDAP message. 697 * 698 * @throws ClassCastException If the protocol op for this LDAP message is 699 * not an intermediate response protocol op. 700 */ 701 public IntermediateResponseProtocolOp getIntermediateResponseProtocolOp() 702 throws ClassCastException 703 { 704 return (IntermediateResponseProtocolOp) protocolOp; 705 } 706 707 708 709 /** 710 * Retrieves the set of controls for this LDAP message. 711 * 712 * @return The set of controls for this LDAP message. 713 */ 714 public List<Control> getControls() 715 { 716 return controls; 717 } 718 719 720 721 /** 722 * Encodes this LDAP message to an ASN.1 element. 723 * 724 * @return The ASN.1 element containing the encoded representation of this 725 * LDAP message. 726 */ 727 public ASN1Element encode() 728 { 729 if (controls.isEmpty()) 730 { 731 return new ASN1Sequence( 732 new ASN1Integer(messageID), 733 protocolOp.encodeProtocolOp()); 734 } 735 else 736 { 737 final Control[] controlArray = new Control[controls.size()]; 738 controls.toArray(controlArray); 739 740 return new ASN1Sequence( 741 new ASN1Integer(messageID), 742 protocolOp.encodeProtocolOp(), 743 Control.encodeControls(controlArray)); 744 } 745 } 746 747 748 749 /** 750 * Decodes the provided ASN.1 element as an LDAP message. 751 * 752 * @param element The ASN.1 element to be decoded. 753 * 754 * @return The LDAP message decoded from the provided ASN.1 element. 755 * 756 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 757 * a valid LDAP message. 758 */ 759 public static LDAPMessage decode(final ASN1Element element) 760 throws LDAPException 761 { 762 try 763 { 764 final ASN1Element[] elements = 765 ASN1Sequence.decodeAsSequence(element).elements(); 766 if ((elements.length < 2) || (elements.length > 3)) 767 { 768 throw new LDAPException(ResultCode.DECODING_ERROR, 769 ERR_MESSAGE_DECODE_VALUE_SEQUENCE_INVALID_ELEMENT_COUNT.get( 770 elements.length)); 771 } 772 773 final int messageID = ASN1Integer.decodeAsInteger(elements[0]).intValue(); 774 775 final ProtocolOp protocolOp; 776 switch (elements[1].getType()) 777 { 778 case PROTOCOL_OP_TYPE_ABANDON_REQUEST: 779 protocolOp = AbandonRequestProtocolOp.decodeProtocolOp(elements[1]); 780 break; 781 case PROTOCOL_OP_TYPE_ADD_REQUEST: 782 protocolOp = AddRequestProtocolOp.decodeProtocolOp(elements[1]); 783 break; 784 case PROTOCOL_OP_TYPE_ADD_RESPONSE: 785 protocolOp = AddResponseProtocolOp.decodeProtocolOp(elements[1]); 786 break; 787 case PROTOCOL_OP_TYPE_BIND_REQUEST: 788 protocolOp = BindRequestProtocolOp.decodeProtocolOp(elements[1]); 789 break; 790 case PROTOCOL_OP_TYPE_BIND_RESPONSE: 791 protocolOp = BindResponseProtocolOp.decodeProtocolOp(elements[1]); 792 break; 793 case PROTOCOL_OP_TYPE_COMPARE_REQUEST: 794 protocolOp = CompareRequestProtocolOp.decodeProtocolOp(elements[1]); 795 break; 796 case PROTOCOL_OP_TYPE_COMPARE_RESPONSE: 797 protocolOp = CompareResponseProtocolOp.decodeProtocolOp(elements[1]); 798 break; 799 case PROTOCOL_OP_TYPE_DELETE_REQUEST: 800 protocolOp = DeleteRequestProtocolOp.decodeProtocolOp(elements[1]); 801 break; 802 case PROTOCOL_OP_TYPE_DELETE_RESPONSE: 803 protocolOp = DeleteResponseProtocolOp.decodeProtocolOp(elements[1]); 804 break; 805 case PROTOCOL_OP_TYPE_EXTENDED_REQUEST: 806 protocolOp = ExtendedRequestProtocolOp.decodeProtocolOp(elements[1]); 807 break; 808 case PROTOCOL_OP_TYPE_EXTENDED_RESPONSE: 809 protocolOp = ExtendedResponseProtocolOp.decodeProtocolOp(elements[1]); 810 break; 811 case PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE: 812 protocolOp = 813 IntermediateResponseProtocolOp.decodeProtocolOp(elements[1]); 814 break; 815 case PROTOCOL_OP_TYPE_MODIFY_REQUEST: 816 protocolOp = ModifyRequestProtocolOp.decodeProtocolOp(elements[1]); 817 break; 818 case PROTOCOL_OP_TYPE_MODIFY_RESPONSE: 819 protocolOp = ModifyResponseProtocolOp.decodeProtocolOp(elements[1]); 820 break; 821 case PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST: 822 protocolOp = ModifyDNRequestProtocolOp.decodeProtocolOp(elements[1]); 823 break; 824 case PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE: 825 protocolOp = ModifyDNResponseProtocolOp.decodeProtocolOp(elements[1]); 826 break; 827 case PROTOCOL_OP_TYPE_SEARCH_REQUEST: 828 protocolOp = SearchRequestProtocolOp.decodeProtocolOp(elements[1]); 829 break; 830 case PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE: 831 protocolOp = SearchResultDoneProtocolOp.decodeProtocolOp(elements[1]); 832 break; 833 case PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY: 834 protocolOp = 835 SearchResultEntryProtocolOp.decodeProtocolOp(elements[1]); 836 break; 837 case PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE: 838 protocolOp = 839 SearchResultReferenceProtocolOp.decodeProtocolOp(elements[1]); 840 break; 841 case PROTOCOL_OP_TYPE_UNBIND_REQUEST: 842 protocolOp = UnbindRequestProtocolOp.decodeProtocolOp(elements[1]); 843 break; 844 default: 845 throw new LDAPException(ResultCode.DECODING_ERROR, 846 ERR_MESSAGE_DECODE_INVALID_PROTOCOL_OP_TYPE.get( 847 StaticUtils.toHex(elements[1].getType()))); 848 } 849 850 final Control[] controls; 851 if (elements.length == 3) 852 { 853 controls = 854 Control.decodeControls(ASN1Sequence.decodeAsSequence(elements[2])); 855 } 856 else 857 { 858 controls = null; 859 } 860 861 return new LDAPMessage(messageID, protocolOp, controls); 862 } 863 catch (final LDAPException le) 864 { 865 Debug.debugException(le); 866 throw le; 867 } 868 catch (final Exception e) 869 { 870 Debug.debugException(e); 871 throw new LDAPException(ResultCode.DECODING_ERROR, 872 ERR_MESSAGE_DECODE_ERROR.get(StaticUtils.getExceptionMessage(e)), 873 e); 874 } 875 } 876 877 878 879 /** 880 * Writes an encoded representation of this LDAP message to the provided ASN.1 881 * buffer. 882 * 883 * @param buffer The ASN.1 buffer to which the encoded representation should 884 * be written. 885 */ 886 public void writeTo(final ASN1Buffer buffer) 887 { 888 final ASN1BufferSequence messageSequence = buffer.beginSequence(); 889 buffer.addInteger(messageID); 890 protocolOp.writeTo(buffer); 891 892 if (! controls.isEmpty()) 893 { 894 final ASN1BufferSequence controlsSequence = 895 buffer.beginSequence(MESSAGE_TYPE_CONTROLS); 896 for (final Control c : controls) 897 { 898 c.writeTo(buffer); 899 } 900 controlsSequence.end(); 901 } 902 messageSequence.end(); 903 } 904 905 906 907 /** 908 * Reads an LDAP message from the provided ASN.1 stream reader. 909 * 910 * @param reader The ASN.1 stream reader from which the LDAP 911 * message should be read. 912 * @param ignoreSocketTimeout Indicates whether to ignore socket timeout 913 * exceptions caught during processing. This 914 * should be {@code true} when the associated 915 * connection is operating in asynchronous mode, 916 * and {@code false} when operating in 917 * synchronous mode. In either case, exceptions 918 * will not be ignored for the first read, since 919 * that will be handled by the connection reader. 920 * 921 * @return The decoded LDAP message, or {@code null} if the end of the input 922 * stream has been reached.. 923 * 924 * @throws LDAPException If an error occurs while attempting to read or 925 * decode the LDAP message. 926 */ 927 public static LDAPMessage readFrom(final ASN1StreamReader reader, 928 final boolean ignoreSocketTimeout) 929 throws LDAPException 930 { 931 final ASN1StreamReaderSequence messageSequence; 932 try 933 { 934 reader.setIgnoreSocketTimeout(false, ignoreSocketTimeout); 935 messageSequence = reader.beginSequence(); 936 if (messageSequence == null) 937 { 938 return null; 939 } 940 } 941 catch (final IOException ioe) 942 { 943 if (! ((ioe instanceof SocketTimeoutException) || 944 (ioe instanceof InterruptedIOException))) 945 { 946 Debug.debugException(ioe); 947 } 948 949 throw new LDAPException(ResultCode.SERVER_DOWN, 950 ERR_MESSAGE_IO_ERROR.get(StaticUtils.getExceptionMessage(ioe)), ioe); 951 } 952 catch (final Exception e) 953 { 954 Debug.debugException(e); 955 956 throw new LDAPException(ResultCode.DECODING_ERROR, 957 ERR_MESSAGE_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), 958 e); 959 } 960 961 try 962 { 963 964 reader.setIgnoreSocketTimeout(ignoreSocketTimeout, ignoreSocketTimeout); 965 final int messageID = reader.readInteger(); 966 967 final ProtocolOp protocolOp; 968 final byte protocolOpType = (byte) reader.peek(); 969 switch (protocolOpType) 970 { 971 case PROTOCOL_OP_TYPE_BIND_REQUEST: 972 protocolOp = new BindRequestProtocolOp(reader); 973 break; 974 case PROTOCOL_OP_TYPE_BIND_RESPONSE: 975 protocolOp = new BindResponseProtocolOp(reader); 976 break; 977 case PROTOCOL_OP_TYPE_UNBIND_REQUEST: 978 protocolOp = new UnbindRequestProtocolOp(reader); 979 break; 980 case PROTOCOL_OP_TYPE_SEARCH_REQUEST: 981 protocolOp = new SearchRequestProtocolOp(reader); 982 break; 983 case PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY: 984 protocolOp = new SearchResultEntryProtocolOp(reader); 985 break; 986 case PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE: 987 protocolOp = new SearchResultReferenceProtocolOp(reader); 988 break; 989 case PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE: 990 protocolOp = new SearchResultDoneProtocolOp(reader); 991 break; 992 case PROTOCOL_OP_TYPE_MODIFY_REQUEST: 993 protocolOp = new ModifyRequestProtocolOp(reader); 994 break; 995 case PROTOCOL_OP_TYPE_MODIFY_RESPONSE: 996 protocolOp = new ModifyResponseProtocolOp(reader); 997 break; 998 case PROTOCOL_OP_TYPE_ADD_REQUEST: 999 protocolOp = new AddRequestProtocolOp(reader); 1000 break; 1001 case PROTOCOL_OP_TYPE_ADD_RESPONSE: 1002 protocolOp = new AddResponseProtocolOp(reader); 1003 break; 1004 case PROTOCOL_OP_TYPE_DELETE_REQUEST: 1005 protocolOp = new DeleteRequestProtocolOp(reader); 1006 break; 1007 case PROTOCOL_OP_TYPE_DELETE_RESPONSE: 1008 protocolOp = new DeleteResponseProtocolOp(reader); 1009 break; 1010 case PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST: 1011 protocolOp = new ModifyDNRequestProtocolOp(reader); 1012 break; 1013 case PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE: 1014 protocolOp = new ModifyDNResponseProtocolOp(reader); 1015 break; 1016 case PROTOCOL_OP_TYPE_COMPARE_REQUEST: 1017 protocolOp = new CompareRequestProtocolOp(reader); 1018 break; 1019 case PROTOCOL_OP_TYPE_COMPARE_RESPONSE: 1020 protocolOp = new CompareResponseProtocolOp(reader); 1021 break; 1022 case PROTOCOL_OP_TYPE_ABANDON_REQUEST: 1023 protocolOp = new AbandonRequestProtocolOp(reader); 1024 break; 1025 case PROTOCOL_OP_TYPE_EXTENDED_REQUEST: 1026 protocolOp = new ExtendedRequestProtocolOp(reader); 1027 break; 1028 case PROTOCOL_OP_TYPE_EXTENDED_RESPONSE: 1029 protocolOp = new ExtendedResponseProtocolOp(reader); 1030 break; 1031 case PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE: 1032 protocolOp = new IntermediateResponseProtocolOp(reader); 1033 break; 1034 default: 1035 throw new LDAPException(ResultCode.DECODING_ERROR, 1036 ERR_MESSAGE_INVALID_PROTOCOL_OP_TYPE.get( 1037 StaticUtils.toHex(protocolOpType))); 1038 } 1039 1040 final ArrayList<Control> controls = new ArrayList<>(5); 1041 if (messageSequence.hasMoreElements()) 1042 { 1043 final ASN1StreamReaderSequence controlSequence = reader.beginSequence(); 1044 while (controlSequence.hasMoreElements()) 1045 { 1046 controls.add(Control.readFrom(reader)); 1047 } 1048 } 1049 1050 return new LDAPMessage(messageID, protocolOp, controls); 1051 } 1052 catch (final LDAPException le) 1053 { 1054 Debug.debugException(le); 1055 throw le; 1056 } 1057 catch (final IOException ioe) 1058 { 1059 Debug.debugException(ioe); 1060 1061 if ((ioe instanceof SocketTimeoutException) || 1062 (ioe instanceof InterruptedIOException)) 1063 { 1064 // We don't want to provide this exception as the cause because we want 1065 // to ensure that a failure in the middle of the response causes the 1066 // connection to be terminated. 1067 throw new LDAPException(ResultCode.DECODING_ERROR, 1068 ERR_MESSAGE_CANNOT_DECODE.get(StaticUtils. 1069 getExceptionMessage(ioe))); 1070 } 1071 else 1072 { 1073 throw new LDAPException(ResultCode.SERVER_DOWN, 1074 ERR_MESSAGE_IO_ERROR.get(StaticUtils.getExceptionMessage(ioe)), 1075 ioe); 1076 } 1077 } 1078 catch (final Exception e) 1079 { 1080 Debug.debugException(e); 1081 1082 throw new LDAPException(ResultCode.DECODING_ERROR, 1083 ERR_MESSAGE_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), 1084 e); 1085 } 1086 } 1087 1088 1089 1090 /** 1091 * Reads {@link LDAPResponse} object from the provided ASN.1 stream reader. 1092 * 1093 * @param reader The ASN.1 stream reader from which the LDAP 1094 * message should be read. 1095 * @param ignoreSocketTimeout Indicates whether to ignore socket timeout 1096 * exceptions caught during processing. This 1097 * should be {@code true} when the associated 1098 * connection is operating in asynchronous mode, 1099 * and {@code false} when operating in 1100 * synchronous mode. In either case, exceptions 1101 * will not be ignored for the first read, since 1102 * that will be handled by the connection reader. 1103 * 1104 * @return The decoded LDAP message, or {@code null} if the end of the input 1105 * stream has been reached.. 1106 * 1107 * @throws LDAPException If an error occurs while attempting to read or 1108 * decode the LDAP message. 1109 */ 1110 public static LDAPResponse readLDAPResponseFrom(final ASN1StreamReader reader, 1111 final boolean ignoreSocketTimeout) 1112 throws LDAPException 1113 { 1114 return readLDAPResponseFrom(reader, ignoreSocketTimeout, null); 1115 } 1116 1117 1118 1119 /** 1120 * Reads {@link LDAPResponse} object from the provided ASN.1 stream reader. 1121 * 1122 * @param reader The ASN.1 stream reader from which the LDAP 1123 * message should be read. 1124 * @param ignoreSocketTimeout Indicates whether to ignore socket timeout 1125 * exceptions caught during processing. This 1126 * should be {@code true} when the associated 1127 * connection is operating in asynchronous mode, 1128 * and {@code false} when operating in 1129 * synchronous mode. In either case, exceptions 1130 * will not be ignored for the first read, since 1131 * that will be handled by the connection reader. 1132 * @param schema The schema to use to select the appropriate 1133 * matching rule for attributes included in the 1134 * response. 1135 * 1136 * @return The decoded LDAP message, or {@code null} if the end of the input 1137 * stream has been reached.. 1138 * 1139 * @throws LDAPException If an error occurs while attempting to read or 1140 * decode the LDAP message. 1141 */ 1142 public static LDAPResponse readLDAPResponseFrom(final ASN1StreamReader reader, 1143 final boolean ignoreSocketTimeout, 1144 final Schema schema) 1145 throws LDAPException 1146 { 1147 final ASN1StreamReaderSequence messageSequence; 1148 try 1149 { 1150 reader.setIgnoreSocketTimeout(false, ignoreSocketTimeout); 1151 messageSequence = reader.beginSequence(); 1152 if (messageSequence == null) 1153 { 1154 return null; 1155 } 1156 } 1157 catch (final IOException ioe) 1158 { 1159 if (! ((ioe instanceof SocketTimeoutException) || 1160 (ioe instanceof InterruptedIOException))) 1161 { 1162 Debug.debugException(ioe); 1163 } 1164 1165 throw new LDAPException(ResultCode.SERVER_DOWN, 1166 ERR_MESSAGE_IO_ERROR.get(StaticUtils.getExceptionMessage(ioe)), ioe); 1167 } 1168 catch (final Exception e) 1169 { 1170 Debug.debugException(e); 1171 1172 throw new LDAPException(ResultCode.DECODING_ERROR, 1173 ERR_MESSAGE_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), 1174 e); 1175 } 1176 1177 try 1178 { 1179 reader.setIgnoreSocketTimeout(ignoreSocketTimeout, ignoreSocketTimeout); 1180 final int messageID = reader.readInteger(); 1181 1182 final byte protocolOpType = (byte) reader.peek(); 1183 switch (protocolOpType) 1184 { 1185 case PROTOCOL_OP_TYPE_ADD_RESPONSE: 1186 case PROTOCOL_OP_TYPE_DELETE_RESPONSE: 1187 case PROTOCOL_OP_TYPE_MODIFY_RESPONSE: 1188 case PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE: 1189 return InternalSDKHelper.readLDAPResultFrom(messageID, 1190 messageSequence, reader); 1191 1192 case PROTOCOL_OP_TYPE_BIND_RESPONSE: 1193 return InternalSDKHelper.readBindResultFrom(messageID, 1194 messageSequence, reader); 1195 1196 case PROTOCOL_OP_TYPE_COMPARE_RESPONSE: 1197 return InternalSDKHelper.readCompareResultFrom(messageID, 1198 messageSequence, reader); 1199 1200 case PROTOCOL_OP_TYPE_EXTENDED_RESPONSE: 1201 return InternalSDKHelper.readExtendedResultFrom(messageID, 1202 messageSequence, reader); 1203 1204 case PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY: 1205 return InternalSDKHelper.readSearchResultEntryFrom(messageID, 1206 messageSequence, reader, schema); 1207 1208 case PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE: 1209 return InternalSDKHelper.readSearchResultReferenceFrom(messageID, 1210 messageSequence, reader); 1211 1212 case PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE: 1213 return InternalSDKHelper.readSearchResultFrom(messageID, 1214 messageSequence, reader); 1215 1216 case PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE: 1217 return InternalSDKHelper.readIntermediateResponseFrom(messageID, 1218 messageSequence, reader); 1219 1220 case PROTOCOL_OP_TYPE_ABANDON_REQUEST: 1221 case PROTOCOL_OP_TYPE_ADD_REQUEST: 1222 case PROTOCOL_OP_TYPE_BIND_REQUEST: 1223 case PROTOCOL_OP_TYPE_COMPARE_REQUEST: 1224 case PROTOCOL_OP_TYPE_DELETE_REQUEST: 1225 case PROTOCOL_OP_TYPE_EXTENDED_REQUEST: 1226 case PROTOCOL_OP_TYPE_MODIFY_REQUEST: 1227 case PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST: 1228 case PROTOCOL_OP_TYPE_SEARCH_REQUEST: 1229 case PROTOCOL_OP_TYPE_UNBIND_REQUEST: 1230 throw new LDAPException(ResultCode.DECODING_ERROR, 1231 ERR_MESSAGE_PROTOCOL_OP_TYPE_NOT_RESPONSE.get( 1232 StaticUtils.toHex(protocolOpType))); 1233 1234 default: 1235 throw new LDAPException(ResultCode.DECODING_ERROR, 1236 ERR_MESSAGE_INVALID_PROTOCOL_OP_TYPE.get( 1237 StaticUtils.toHex(protocolOpType))); 1238 } 1239 } 1240 catch (final LDAPException le) 1241 { 1242 Debug.debugException(le); 1243 throw le; 1244 } 1245 catch (final IOException ioe) 1246 { 1247 Debug.debugException(ioe); 1248 1249 if ((ioe instanceof SocketTimeoutException) || 1250 (ioe instanceof InterruptedIOException)) 1251 { 1252 // We don't want to provide this exception as the cause because we want 1253 // to ensure that a failure in the middle of the response causes the 1254 // connection to be terminated. 1255 throw new LDAPException(ResultCode.DECODING_ERROR, 1256 ERR_MESSAGE_CANNOT_DECODE.get( 1257 StaticUtils.getExceptionMessage(ioe))); 1258 } 1259 else 1260 { 1261 throw new LDAPException(ResultCode.SERVER_DOWN, 1262 ERR_MESSAGE_IO_ERROR.get(StaticUtils.getExceptionMessage(ioe)), 1263 ioe); 1264 } 1265 } 1266 catch (final Exception e) 1267 { 1268 Debug.debugException(e); 1269 1270 throw new LDAPException(ResultCode.DECODING_ERROR, 1271 ERR_MESSAGE_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), 1272 e); 1273 } 1274 } 1275 1276 1277 1278 /** 1279 * Retrieves a string representation of this LDAP message. 1280 * 1281 * @return A string representation of this LDAP message. 1282 */ 1283 @Override() 1284 public String toString() 1285 { 1286 final StringBuilder buffer = new StringBuilder(); 1287 toString(buffer); 1288 return buffer.toString(); 1289 } 1290 1291 1292 1293 /** 1294 * Appends a string representation of this LDAP message to the provided 1295 * buffer. 1296 * 1297 * @param buffer The buffer to which the string representation should be 1298 * appended. 1299 */ 1300 public void toString(final StringBuilder buffer) 1301 { 1302 buffer.append("LDAPMessage(msgID="); 1303 buffer.append(messageID); 1304 buffer.append(", protocolOp="); 1305 protocolOp.toString(buffer); 1306 1307 if (! controls.isEmpty()) 1308 { 1309 buffer.append(", controls={"); 1310 final Iterator<Control> iterator = controls.iterator(); 1311 while (iterator.hasNext()) 1312 { 1313 iterator.next().toString(buffer); 1314 if (iterator.hasNext()) 1315 { 1316 buffer.append(','); 1317 } 1318 } 1319 buffer.append('}'); 1320 } 1321 1322 buffer.append(')'); 1323 } 1324}