001/* 002 * Copyright 2009-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2017 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 */ 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.InternalUseOnly; 048import com.unboundid.util.NotMutable; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.ldap.protocol.ProtocolMessages.*; 053import static com.unboundid.util.Debug.*; 054import static com.unboundid.util.StaticUtils.*; 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 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 debugException(le); 866 throw le; 867 } 868 catch (final Exception e) 869 { 870 debugException(e); 871 throw new LDAPException(ResultCode.DECODING_ERROR, 872 ERR_MESSAGE_DECODE_ERROR.get(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 (IOException ioe) 942 { 943 if (! ((ioe instanceof SocketTimeoutException) || 944 (ioe instanceof InterruptedIOException))) 945 { 946 debugException(ioe); 947 } 948 949 throw new LDAPException(ResultCode.SERVER_DOWN, 950 ERR_MESSAGE_IO_ERROR.get(getExceptionMessage(ioe)), ioe); 951 } 952 catch (Exception e) 953 { 954 debugException(e); 955 956 throw new LDAPException(ResultCode.DECODING_ERROR, 957 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 958 } 959 960 try 961 { 962 963 reader.setIgnoreSocketTimeout(ignoreSocketTimeout, ignoreSocketTimeout); 964 final int messageID = reader.readInteger(); 965 966 final ProtocolOp protocolOp; 967 final byte protocolOpType = (byte) reader.peek(); 968 switch (protocolOpType) 969 { 970 case PROTOCOL_OP_TYPE_BIND_REQUEST: 971 protocolOp = new BindRequestProtocolOp(reader); 972 break; 973 case PROTOCOL_OP_TYPE_BIND_RESPONSE: 974 protocolOp = new BindResponseProtocolOp(reader); 975 break; 976 case PROTOCOL_OP_TYPE_UNBIND_REQUEST: 977 protocolOp = new UnbindRequestProtocolOp(reader); 978 break; 979 case PROTOCOL_OP_TYPE_SEARCH_REQUEST: 980 protocolOp = new SearchRequestProtocolOp(reader); 981 break; 982 case PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY: 983 protocolOp = new SearchResultEntryProtocolOp(reader); 984 break; 985 case PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE: 986 protocolOp = new SearchResultReferenceProtocolOp(reader); 987 break; 988 case PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE: 989 protocolOp = new SearchResultDoneProtocolOp(reader); 990 break; 991 case PROTOCOL_OP_TYPE_MODIFY_REQUEST: 992 protocolOp = new ModifyRequestProtocolOp(reader); 993 break; 994 case PROTOCOL_OP_TYPE_MODIFY_RESPONSE: 995 protocolOp = new ModifyResponseProtocolOp(reader); 996 break; 997 case PROTOCOL_OP_TYPE_ADD_REQUEST: 998 protocolOp = new AddRequestProtocolOp(reader); 999 break; 1000 case PROTOCOL_OP_TYPE_ADD_RESPONSE: 1001 protocolOp = new AddResponseProtocolOp(reader); 1002 break; 1003 case PROTOCOL_OP_TYPE_DELETE_REQUEST: 1004 protocolOp = new DeleteRequestProtocolOp(reader); 1005 break; 1006 case PROTOCOL_OP_TYPE_DELETE_RESPONSE: 1007 protocolOp = new DeleteResponseProtocolOp(reader); 1008 break; 1009 case PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST: 1010 protocolOp = new ModifyDNRequestProtocolOp(reader); 1011 break; 1012 case PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE: 1013 protocolOp = new ModifyDNResponseProtocolOp(reader); 1014 break; 1015 case PROTOCOL_OP_TYPE_COMPARE_REQUEST: 1016 protocolOp = new CompareRequestProtocolOp(reader); 1017 break; 1018 case PROTOCOL_OP_TYPE_COMPARE_RESPONSE: 1019 protocolOp = new CompareResponseProtocolOp(reader); 1020 break; 1021 case PROTOCOL_OP_TYPE_ABANDON_REQUEST: 1022 protocolOp = new AbandonRequestProtocolOp(reader); 1023 break; 1024 case PROTOCOL_OP_TYPE_EXTENDED_REQUEST: 1025 protocolOp = new ExtendedRequestProtocolOp(reader); 1026 break; 1027 case PROTOCOL_OP_TYPE_EXTENDED_RESPONSE: 1028 protocolOp = new ExtendedResponseProtocolOp(reader); 1029 break; 1030 case PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE: 1031 protocolOp = new IntermediateResponseProtocolOp(reader); 1032 break; 1033 default: 1034 throw new LDAPException(ResultCode.DECODING_ERROR, 1035 ERR_MESSAGE_INVALID_PROTOCOL_OP_TYPE.get(toHex(protocolOpType))); 1036 } 1037 1038 final ArrayList<Control> controls = new ArrayList<Control>(5); 1039 if (messageSequence.hasMoreElements()) 1040 { 1041 final ASN1StreamReaderSequence controlSequence = reader.beginSequence(); 1042 while (controlSequence.hasMoreElements()) 1043 { 1044 controls.add(Control.readFrom(reader)); 1045 } 1046 } 1047 1048 return new LDAPMessage(messageID, protocolOp, controls); 1049 } 1050 catch (LDAPException le) 1051 { 1052 debugException(le); 1053 throw le; 1054 } 1055 catch (IOException ioe) 1056 { 1057 debugException(ioe); 1058 1059 if ((ioe instanceof SocketTimeoutException) || 1060 (ioe instanceof InterruptedIOException)) 1061 { 1062 // We don't want to provide this exception as the cause because we want 1063 // to ensure that a failure in the middle of the response causes the 1064 // connection to be terminated. 1065 throw new LDAPException(ResultCode.DECODING_ERROR, 1066 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(ioe))); 1067 } 1068 else 1069 { 1070 throw new LDAPException(ResultCode.SERVER_DOWN, 1071 ERR_MESSAGE_IO_ERROR.get(getExceptionMessage(ioe)), ioe); 1072 } 1073 } 1074 catch (Exception e) 1075 { 1076 debugException(e); 1077 1078 throw new LDAPException(ResultCode.DECODING_ERROR, 1079 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 1080 } 1081 } 1082 1083 1084 1085 /** 1086 * Reads {@link LDAPResponse} object from the provided ASN.1 stream reader. 1087 * 1088 * @param reader The ASN.1 stream reader from which the LDAP 1089 * message should be read. 1090 * @param ignoreSocketTimeout Indicates whether to ignore socket timeout 1091 * exceptions caught during processing. This 1092 * should be {@code true} when the associated 1093 * connection is operating in asynchronous mode, 1094 * and {@code false} when operating in 1095 * synchronous mode. In either case, exceptions 1096 * will not be ignored for the first read, since 1097 * that will be handled by the connection reader. 1098 * 1099 * @return The decoded LDAP message, or {@code null} if the end of the input 1100 * stream has been reached.. 1101 * 1102 * @throws LDAPException If an error occurs while attempting to read or 1103 * decode the LDAP message. 1104 */ 1105 public static LDAPResponse readLDAPResponseFrom(final ASN1StreamReader reader, 1106 final boolean ignoreSocketTimeout) 1107 throws LDAPException 1108 { 1109 return readLDAPResponseFrom(reader, ignoreSocketTimeout, null); 1110 } 1111 1112 1113 1114 /** 1115 * Reads {@link LDAPResponse} object from the provided ASN.1 stream reader. 1116 * 1117 * @param reader The ASN.1 stream reader from which the LDAP 1118 * message should be read. 1119 * @param ignoreSocketTimeout Indicates whether to ignore socket timeout 1120 * exceptions caught during processing. This 1121 * should be {@code true} when the associated 1122 * connection is operating in asynchronous mode, 1123 * and {@code false} when operating in 1124 * synchronous mode. In either case, exceptions 1125 * will not be ignored for the first read, since 1126 * that will be handled by the connection reader. 1127 * @param schema The schema to use to select the appropriate 1128 * matching rule for attributes included in the 1129 * response. 1130 * 1131 * @return The decoded LDAP message, or {@code null} if the end of the input 1132 * stream has been reached.. 1133 * 1134 * @throws LDAPException If an error occurs while attempting to read or 1135 * decode the LDAP message. 1136 */ 1137 public static LDAPResponse readLDAPResponseFrom(final ASN1StreamReader reader, 1138 final boolean ignoreSocketTimeout, 1139 final Schema schema) 1140 throws LDAPException 1141 { 1142 final ASN1StreamReaderSequence messageSequence; 1143 try 1144 { 1145 reader.setIgnoreSocketTimeout(false, ignoreSocketTimeout); 1146 messageSequence = reader.beginSequence(); 1147 if (messageSequence == null) 1148 { 1149 return null; 1150 } 1151 } 1152 catch (IOException ioe) 1153 { 1154 if (! ((ioe instanceof SocketTimeoutException) || 1155 (ioe instanceof InterruptedIOException))) 1156 { 1157 debugException(ioe); 1158 } 1159 1160 throw new LDAPException(ResultCode.SERVER_DOWN, 1161 ERR_MESSAGE_IO_ERROR.get(getExceptionMessage(ioe)), ioe); 1162 } 1163 catch (Exception e) 1164 { 1165 debugException(e); 1166 1167 throw new LDAPException(ResultCode.DECODING_ERROR, 1168 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 1169 } 1170 1171 try 1172 { 1173 reader.setIgnoreSocketTimeout(ignoreSocketTimeout, ignoreSocketTimeout); 1174 final int messageID = reader.readInteger(); 1175 1176 final byte protocolOpType = (byte) reader.peek(); 1177 switch (protocolOpType) 1178 { 1179 case PROTOCOL_OP_TYPE_ADD_RESPONSE: 1180 case PROTOCOL_OP_TYPE_DELETE_RESPONSE: 1181 case PROTOCOL_OP_TYPE_MODIFY_RESPONSE: 1182 case PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE: 1183 return InternalSDKHelper.readLDAPResultFrom(messageID, 1184 messageSequence, reader); 1185 1186 case PROTOCOL_OP_TYPE_BIND_RESPONSE: 1187 return InternalSDKHelper.readBindResultFrom(messageID, 1188 messageSequence, reader); 1189 1190 case PROTOCOL_OP_TYPE_COMPARE_RESPONSE: 1191 return InternalSDKHelper.readCompareResultFrom(messageID, 1192 messageSequence, reader); 1193 1194 case PROTOCOL_OP_TYPE_EXTENDED_RESPONSE: 1195 return InternalSDKHelper.readExtendedResultFrom(messageID, 1196 messageSequence, reader); 1197 1198 case PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY: 1199 return InternalSDKHelper.readSearchResultEntryFrom(messageID, 1200 messageSequence, reader, schema); 1201 1202 case PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE: 1203 return InternalSDKHelper.readSearchResultReferenceFrom(messageID, 1204 messageSequence, reader); 1205 1206 case PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE: 1207 return InternalSDKHelper.readSearchResultFrom(messageID, 1208 messageSequence, reader); 1209 1210 case PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE: 1211 return InternalSDKHelper.readIntermediateResponseFrom(messageID, 1212 messageSequence, reader); 1213 1214 case PROTOCOL_OP_TYPE_ABANDON_REQUEST: 1215 case PROTOCOL_OP_TYPE_ADD_REQUEST: 1216 case PROTOCOL_OP_TYPE_BIND_REQUEST: 1217 case PROTOCOL_OP_TYPE_COMPARE_REQUEST: 1218 case PROTOCOL_OP_TYPE_DELETE_REQUEST: 1219 case PROTOCOL_OP_TYPE_EXTENDED_REQUEST: 1220 case PROTOCOL_OP_TYPE_MODIFY_REQUEST: 1221 case PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST: 1222 case PROTOCOL_OP_TYPE_SEARCH_REQUEST: 1223 case PROTOCOL_OP_TYPE_UNBIND_REQUEST: 1224 throw new LDAPException(ResultCode.DECODING_ERROR, 1225 ERR_MESSAGE_PROTOCOL_OP_TYPE_NOT_RESPONSE.get( 1226 toHex(protocolOpType))); 1227 1228 default: 1229 throw new LDAPException(ResultCode.DECODING_ERROR, 1230 ERR_MESSAGE_INVALID_PROTOCOL_OP_TYPE.get(toHex(protocolOpType))); 1231 } 1232 } 1233 catch (LDAPException le) 1234 { 1235 debugException(le); 1236 throw le; 1237 } 1238 catch (IOException ioe) 1239 { 1240 debugException(ioe); 1241 1242 if ((ioe instanceof SocketTimeoutException) || 1243 (ioe instanceof InterruptedIOException)) 1244 { 1245 // We don't want to provide this exception as the cause because we want 1246 // to ensure that a failure in the middle of the response causes the 1247 // connection to be terminated. 1248 throw new LDAPException(ResultCode.DECODING_ERROR, 1249 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(ioe))); 1250 } 1251 else 1252 { 1253 throw new LDAPException(ResultCode.SERVER_DOWN, 1254 ERR_MESSAGE_IO_ERROR.get(getExceptionMessage(ioe)), ioe); 1255 } 1256 } 1257 catch (Exception e) 1258 { 1259 debugException(e); 1260 1261 throw new LDAPException(ResultCode.DECODING_ERROR, 1262 ERR_MESSAGE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 1263 } 1264 } 1265 1266 1267 1268 /** 1269 * Retrieves a string representation of this LDAP message. 1270 * 1271 * @return A string representation of this LDAP message. 1272 */ 1273 @Override() 1274 public String toString() 1275 { 1276 final StringBuilder buffer = new StringBuilder(); 1277 toString(buffer); 1278 return buffer.toString(); 1279 } 1280 1281 1282 1283 /** 1284 * Appends a string representation of this LDAP message to the provided 1285 * buffer. 1286 * 1287 * @param buffer The buffer to which the string representation should be 1288 * appended. 1289 */ 1290 public void toString(final StringBuilder buffer) 1291 { 1292 buffer.append("LDAPMessage(msgID="); 1293 buffer.append(messageID); 1294 buffer.append(", protocolOp="); 1295 protocolOp.toString(buffer); 1296 1297 if (! controls.isEmpty()) 1298 { 1299 buffer.append(", controls={"); 1300 final Iterator<Control> iterator = controls.iterator(); 1301 while (iterator.hasNext()) 1302 { 1303 iterator.next().toString(buffer); 1304 if (iterator.hasNext()) 1305 { 1306 buffer.append(','); 1307 } 1308 } 1309 buffer.append('}'); 1310 } 1311 1312 buffer.append(')'); 1313 } 1314}