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