001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 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 }