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 import com.unboundid.util.NotMutable;
049 import com.unboundid.util.ThreadSafety;
050 import com.unboundid.util.ThreadSafetyLevel;
051
052 import static com.unboundid.ldap.protocol.ProtocolMessages.*;
053 import static com.unboundid.util.Debug.*;
054 import 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)
066 public 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 }