001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.protocols.ldap;
028
029import java.io.IOException;
030import java.util.ArrayList;
031import java.util.LinkedHashSet;
032import java.util.LinkedList;
033
034import org.forgerock.i18n.LocalizableMessage;
035import org.forgerock.i18n.slf4j.LocalizedLogger;
036import org.forgerock.opendj.io.ASN1;
037import org.forgerock.opendj.io.ASN1Reader;
038import org.forgerock.opendj.ldap.ByteString;
039import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
040import org.forgerock.opendj.ldap.SearchScope;
041import org.opends.server.types.*;
042
043import static org.opends.messages.ProtocolMessages.*;
044import static org.opends.server.protocols.ldap.LDAPConstants.*;
045import static org.opends.server.protocols.ldap.LDAPResultCode.*;
046
047/**
048 * Utility class used to decode LDAP messages from an ASN1Reader.
049 */
050public class LDAPReader
051{
052  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
053
054  /**
055   * Decodes the elements from the provided ASN.1 reader as an LDAP message.
056   *
057   * @param reader The ASN.1 reader.
058   *
059   * @return  The decoded LDAP message.
060   *
061   * @throws  LDAPException  If a problem occurs while attempting to decode the
062   *                         LDAP message.
063   */
064  public static LDAPMessage readMessage(ASN1Reader reader)
065      throws LDAPException
066  {
067    try
068    {
069      reader.readStartSequence();
070    }
071    catch(Exception e)
072    {
073      LocalizableMessage message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
074      throw new LDAPException(PROTOCOL_ERROR, message);
075    }
076
077    int messageID;
078    try
079    {
080      messageID = (int)reader.readInteger();
081    }
082    catch(Exception e)
083    {
084      logger.traceException(e);
085
086      LocalizableMessage message = ERR_LDAP_MESSAGE_DECODE_MESSAGE_ID.get(e);
087      throw new LDAPException(PROTOCOL_ERROR, message, e);
088    }
089
090    ProtocolOp protocolOp;
091    try
092    {
093      protocolOp = readProtocolOp(reader);
094    }
095    catch (Exception e)
096    {
097      logger.traceException(e);
098
099      LocalizableMessage message = ERR_LDAP_MESSAGE_DECODE_PROTOCOL_OP.get(e);
100      throw new LDAPException(PROTOCOL_ERROR, message, e);
101    }
102
103    ArrayList<Control> controls = null;
104    try
105    {
106      if(reader.hasNextElement())
107      {
108        controls = readControls(reader);
109      }
110    }
111    catch (Exception e)
112    {
113      logger.traceException(e);
114
115      LocalizableMessage message = ERR_LDAP_MESSAGE_DECODE_CONTROLS.get(e);
116      throw new LDAPException(PROTOCOL_ERROR, message, e);
117    }
118
119    try
120    {
121      reader.readEndSequence();
122    }
123    catch(Exception e)
124    {
125      LocalizableMessage message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
126      throw new LDAPException(PROTOCOL_ERROR, message);
127    }
128
129    return new LDAPMessage(messageID, protocolOp, controls);
130  }
131
132  /**
133   * Decodes the elements from the provided ASN.1 reader as an LDAP
134   * protocol op.
135   *
136   * @param reader The ASN.1 reader.
137   *
138   * @return  The LDAP protocol op decoded from the provided ASN.1 element.
139   *
140   * @throws  LDAPException  If a problem occurs while trying to decode the
141   *                         provided ASN.1 elements as an LDAP protocol op.
142   */
143  public static ProtocolOp readProtocolOp(ASN1Reader reader)
144      throws LDAPException
145  {
146    byte type;
147    try
148    {
149      type = reader.peekType();
150    }
151    catch(Exception e)
152    {
153      LocalizableMessage message = ERR_LDAP_PROTOCOL_OP_DECODE_NULL.get();
154      throw new LDAPException(PROTOCOL_ERROR, message);
155    }
156
157    switch(type)
158    {
159      case OP_TYPE_UNBIND_REQUEST:                                       // 0x42
160        return readUnbindRequest(reader);
161      case 0x43:                                                         // 0x43
162      case 0x44:                                                         // 0x44
163      case 0x45:                                                         // 0x45
164      case 0x46:                                                         // 0x46
165      case 0x47:                                                         // 0x47
166      case 0x48:                                                         // 0x48
167      case 0x49:                                                         // 0x49
168        LocalizableMessage message =
169            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
170        throw new LDAPException(PROTOCOL_ERROR, message);
171      case OP_TYPE_DELETE_REQUEST:                                       // 0x4A
172        return readDeleteRequest(reader);
173      case 0x4B:                                                         // 0x4B
174      case 0x4C:                                                         // 0x4C
175      case 0x4D:                                                         // 0x4D
176      case 0x4E:                                                         // 0x4E
177      case 0x4F:                                                         // 0x4F
178        message =
179            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
180        throw new LDAPException(PROTOCOL_ERROR, message);
181      case OP_TYPE_ABANDON_REQUEST:                                      // 0x50
182        return readAbandonRequest(reader);
183      case 0x51:                                                         // 0x51
184      case 0x52:                                                         // 0x52
185      case 0x53:                                                         // 0x53
186      case 0x54:                                                         // 0x54
187      case 0x55:                                                         // 0x55
188      case 0x56:                                                         // 0x56
189      case 0x57:                                                         // 0x57
190      case 0x58:                                                         // 0x58
191      case 0x59:                                                         // 0x59
192      case 0x5A:                                                         // 0x5A
193      case 0x5B:                                                         // 0x5B
194      case 0x5C:                                                         // 0x5C
195      case 0x5D:                                                         // 0x5D
196      case 0x5E:                                                         // 0x5E
197      case 0x5F:                                                         // 0x5F
198        message =
199            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
200        throw new LDAPException(PROTOCOL_ERROR, message);
201      case OP_TYPE_BIND_REQUEST:                                         // 0x60
202        return readBindRequest(reader);
203      case OP_TYPE_BIND_RESPONSE:                                        // 0x61
204        return readBindResponse(reader);
205      case 0x62:                                                         // 0x62
206        message =
207            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
208        throw new LDAPException(PROTOCOL_ERROR, message);
209      case OP_TYPE_SEARCH_REQUEST:                                       // 0x63
210        return readSearchRequest(reader);
211      case OP_TYPE_SEARCH_RESULT_ENTRY:                                  // 0x64
212        return readSearchEntry(reader);
213      case OP_TYPE_SEARCH_RESULT_DONE:                                   // 0x65
214        return readSearchDone(reader);
215      case OP_TYPE_MODIFY_REQUEST:                                       // 0x66
216        return readModifyRequest(reader);
217      case OP_TYPE_MODIFY_RESPONSE:                                      // 0x67
218        return readModifyResponse(reader);
219      case OP_TYPE_ADD_REQUEST:                                          // 0x68
220        return readAddRequest(reader);
221      case OP_TYPE_ADD_RESPONSE:                                         // 0x69
222        return readAddResponse(reader);
223      case 0x6A:                                                         // 0x6A
224        message =
225            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
226        throw new LDAPException(PROTOCOL_ERROR, message);
227      case OP_TYPE_DELETE_RESPONSE:                                      // 0x6B
228        return readDeleteResponse(reader);
229      case OP_TYPE_MODIFY_DN_REQUEST:                                    // 0x6C
230        return readModifyDNRequest(reader);
231      case OP_TYPE_MODIFY_DN_RESPONSE:                                   // 0x6D
232        return readModifyDNResponse(reader);
233      case OP_TYPE_COMPARE_REQUEST:                                      // 0x6E
234        return readCompareRequest(reader);
235      case OP_TYPE_COMPARE_RESPONSE:                                     // 0x6F
236        return readCompareResponse(reader);
237      case 0x70:                                                         // 0x70
238      case 0x71:                                                         // 0x71
239      case 0x72:                                                         // 0x72
240        message =
241            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
242        throw new LDAPException(PROTOCOL_ERROR, message);
243      case OP_TYPE_SEARCH_RESULT_REFERENCE:                              // 0x73
244        return readSearchReference(reader);
245      case 0x74:                                                         // 0x74
246      case 0x75:                                                         // 0x75
247      case 0x76:                                                         // 0x76
248        message =
249            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
250        throw new LDAPException(PROTOCOL_ERROR, message);
251      case OP_TYPE_EXTENDED_REQUEST:                                     // 0x77
252        return readExtendedRequest(reader);
253      case OP_TYPE_EXTENDED_RESPONSE:                                    // 0x78
254        return readExtendedResponse(reader);
255      case OP_TYPE_INTERMEDIATE_RESPONSE:                                // 0x79
256        return
257            readIntermediateResponse(reader);
258      default:
259        message =
260            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
261        throw new LDAPException(PROTOCOL_ERROR, message);
262    }
263  }
264
265
266  /**
267   * Decodes the elements from the provided ASN.1 read as an LDAP
268   *  abandon request protocol op.
269   *
270   * @param  reader The ASN.1 reader.
271   *
272   * @return  The decoded abandon request protocol op.
273   *
274   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
275   *                         an abandon request protocol op.
276   */
277  private static AbandonRequestProtocolOp readAbandonRequest(ASN1Reader reader)
278      throws LDAPException
279  {
280    long idToAbandon;
281    try
282    {
283      idToAbandon = reader.readInteger();
284    }
285    catch (Exception e)
286    {
287      logger.traceException(e);
288
289      LocalizableMessage message = ERR_LDAP_ABANDON_REQUEST_DECODE_ID.get(e);
290      throw new LDAPException(PROTOCOL_ERROR, message, e);
291    }
292
293    return new AbandonRequestProtocolOp((int)idToAbandon);
294  }
295
296  /**
297   * Decodes the elements from the provided ASN.1 reader as an LDAP
298   * add request protocol op.
299   *
300   * @param  reader The ASN.1 reader.
301   *
302   * @return  The decoded add request protocol op.
303   *
304   * @throws  LDAPException  If a problem occurs while decoding the provided
305   *                         ASN.1 element as an LDAP add request protocol op.
306   */
307  private static AddRequestProtocolOp readAddRequest(ASN1Reader reader)
308      throws LDAPException
309  {
310    try
311    {
312      reader.readStartSequence();
313    }
314    catch (Exception e)
315    {
316      logger.traceException(e);
317
318      LocalizableMessage message = ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE.get(e);
319      throw new LDAPException(PROTOCOL_ERROR, message, e);
320    }
321
322
323    ByteString dn;
324    try
325    {
326      dn = reader.readOctetString();
327    }
328    catch (Exception e)
329    {
330      logger.traceException(e);
331
332      LocalizableMessage message = ERR_LDAP_ADD_REQUEST_DECODE_DN.get(e);
333      throw new LDAPException(PROTOCOL_ERROR, message, e);
334    }
335
336
337
338    ArrayList<RawAttribute> attributes;
339    try
340    {
341      reader.readStartSequence();
342      attributes = new ArrayList<>();
343      while(reader.hasNextElement())
344      {
345        attributes.add(LDAPAttribute.decode(reader));
346      }
347      reader.readEndSequence();
348    }
349    catch (Exception e)
350    {
351      logger.traceException(e);
352
353      LocalizableMessage message = ERR_LDAP_ADD_REQUEST_DECODE_ATTRS.get(e);
354      throw new LDAPException(PROTOCOL_ERROR, message, e);
355    }
356
357    try
358    {
359      reader.readEndSequence();
360    }
361    catch (Exception e)
362    {
363      logger.traceException(e);
364
365      LocalizableMessage message = ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE.get(e);
366      throw new LDAPException(PROTOCOL_ERROR, message, e);
367    }
368
369
370    return new AddRequestProtocolOp(dn, attributes);
371  }
372
373  /**
374   * Decodes the elements from the provided ASN.1 reader as an
375   * add response protocol op.
376   *
377   * @param  reader The ASN.1 reader.
378   *
379   * @return  The decoded add response protocol op.
380   *
381   * @throws  LDAPException  If a problem occurs while attempting to decode the
382   *                         ASN.1 element to a protocol op.
383   */
384  private static AddResponseProtocolOp readAddResponse(ASN1Reader reader)
385      throws LDAPException
386  {
387    try
388    {
389      reader.readStartSequence();
390    }
391    catch (Exception e)
392    {
393      logger.traceException(e);
394
395      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
396      throw new LDAPException(PROTOCOL_ERROR, message, e);
397    }
398
399    int resultCode;
400    try
401    {
402      resultCode = (int)reader.readInteger();
403    }
404    catch (Exception e)
405    {
406      logger.traceException(e);
407
408      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
409      throw new LDAPException(PROTOCOL_ERROR, message, e);
410    }
411
412
413    DN matchedDN;
414    try
415    {
416      String dnString = reader.readOctetStringAsString();
417      if (dnString.length() == 0)
418      {
419        matchedDN = null;
420      }
421      else
422      {
423        matchedDN = DN.valueOf(dnString);
424      }
425    }
426    catch (Exception e)
427    {
428      logger.traceException(e);
429
430      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
431      throw new LDAPException(PROTOCOL_ERROR, message, e);
432    }
433
434
435    LocalizableMessage errorMessage;
436    try
437    {
438      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
439      if (errorMessage.length() == 0)
440      {
441        errorMessage = null;
442      }
443    }
444    catch (Exception e)
445    {
446      logger.traceException(e);
447
448      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
449      throw new LDAPException(PROTOCOL_ERROR, message, e);
450    }
451
452    ArrayList<String> referralURLs = null;
453
454    try
455    {
456      if (reader.hasNextElement())
457      {
458        reader.readStartSequence();
459        referralURLs = new ArrayList<>();
460
461        while(reader.hasNextElement())
462        {
463          referralURLs.add(reader.readOctetStringAsString());
464        }
465        reader.readEndSequence();
466      }
467    }
468    catch (Exception e)
469    {
470      logger.traceException(e);
471
472      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
473      throw new LDAPException(PROTOCOL_ERROR, message, e);
474    }
475
476    try
477    {
478      reader.readEndSequence();
479    }
480    catch (Exception e)
481    {
482      logger.traceException(e);
483
484      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
485      throw new LDAPException(PROTOCOL_ERROR, message, e);
486    }
487
488    return new AddResponseProtocolOp(resultCode, errorMessage, matchedDN,
489        referralURLs);
490  }
491
492  /**
493   * Decodes the elements from the provided ASN.1 read as an LDAP bind
494   * request protocol op.
495   *
496   * @param  reader The ASN.1 reader
497   *
498   * @return  The decoded LDAP bind request protocol op.
499   *
500   * @throws  LDAPException  If a problem occurs while trying to decode the
501   *                         provided ASN.1 element as an LDAP bind request.
502   */
503  private static BindRequestProtocolOp readBindRequest(ASN1Reader reader)
504      throws LDAPException
505  {
506    try
507    {
508      reader.readStartSequence();
509    }
510    catch (Exception e)
511    {
512      logger.traceException(e);
513
514      LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(e);
515      throw new LDAPException(PROTOCOL_ERROR, message, e);
516    }
517
518    int protocolVersion;
519    try
520    {
521      protocolVersion = (int)reader.readInteger();
522    }
523    catch (Exception e)
524    {
525      logger.traceException(e);
526
527      LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_VERSION.get(e);
528      throw new LDAPException(PROTOCOL_ERROR, message, e);
529    }
530
531
532    ByteString dn;
533    try
534    {
535      dn = reader.readOctetString();
536    }
537    catch (Exception e)
538    {
539      logger.traceException(e);
540
541      LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_DN.get(e);
542      throw new LDAPException(PROTOCOL_ERROR, message, e);
543    }
544
545    byte type;
546    try
547    {
548      type = reader.peekType();
549
550    }
551    catch (Exception e)
552    {
553      logger.traceException(e);
554
555      LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_CREDENTIALS.get(e);
556      throw new LDAPException(PROTOCOL_ERROR, message, e);
557    }
558
559    ByteString simplePassword  = null;
560    String     saslMechanism   = null;
561    ByteString saslCredentials = null;
562    switch (type)
563    {
564      case TYPE_AUTHENTICATION_SIMPLE:
565        try
566        {
567          simplePassword =
568              reader.readOctetString();
569        }
570        catch (Exception e)
571        {
572          LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_PASSWORD.get(e);
573          throw new LDAPException(PROTOCOL_ERROR, message, e);
574        }
575        break;
576      case TYPE_AUTHENTICATION_SASL:
577        try
578        {
579          reader.readStartSequence();
580          saslMechanism = reader.readOctetStringAsString();
581          if (reader.hasNextElement())
582          {
583            saslCredentials =
584                reader.readOctetString();
585          }
586          reader.readEndSequence();
587        }
588        catch (Exception e)
589        {
590          LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_SASL_INFO.get(e);
591          throw new LDAPException(PROTOCOL_ERROR, message, e);
592        }
593        break;
594      default:
595        LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_CRED_TYPE.get(
596            type);
597        throw new LDAPException(AUTH_METHOD_NOT_SUPPORTED, message);
598    }
599
600    try
601    {
602      reader.readEndSequence();
603    }
604    catch (Exception e)
605    {
606      logger.traceException(e);
607
608      LocalizableMessage message = ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(e);
609      throw new LDAPException(PROTOCOL_ERROR, message, e);
610    }
611
612    if(type == TYPE_AUTHENTICATION_SIMPLE)
613    {
614      return new BindRequestProtocolOp(dn, protocolVersion, simplePassword);
615    }
616    else
617    {
618      return new BindRequestProtocolOp(dn, saslMechanism, saslCredentials);
619    }
620  }
621
622  /**
623   * Decodes the elements from the provided ASN.1 reader as a bind
624   * response protocol op.
625   *
626   * @param  reader The ASN.1 reader.
627   *
628   * @return  The decoded bind response protocol op.
629   *
630   * @throws  LDAPException  If a problem occurs while attempting to decode the
631   *                         ASN.1 element to a protocol op.
632   */
633  private static BindResponseProtocolOp readBindResponse(ASN1Reader reader)
634      throws LDAPException
635  {
636    try
637    {
638      reader.readStartSequence();
639    }
640    catch (Exception e)
641    {
642      logger.traceException(e);
643
644      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
645      throw new LDAPException(PROTOCOL_ERROR, message, e);
646    }
647
648    int resultCode;
649    try
650    {
651      resultCode = (int)reader.readInteger();
652    }
653    catch (Exception e)
654    {
655      logger.traceException(e);
656
657      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
658      throw new LDAPException(PROTOCOL_ERROR, message, e);
659    }
660
661
662    DN matchedDN;
663    try
664    {
665      String dnString = reader.readOctetStringAsString();
666      if (dnString.length() == 0)
667      {
668        matchedDN = null;
669      }
670      else
671      {
672        matchedDN = DN.valueOf(dnString);
673      }
674    }
675    catch (Exception e)
676    {
677      logger.traceException(e);
678
679      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
680      throw new LDAPException(PROTOCOL_ERROR, message, e);
681    }
682
683
684    LocalizableMessage errorMessage;
685    try
686    {
687      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
688      if (errorMessage.length() == 0)
689      {
690        errorMessage = null;
691      }
692    }
693    catch (Exception e)
694    {
695      logger.traceException(e);
696
697      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
698      throw new LDAPException(PROTOCOL_ERROR, message, e);
699    }
700
701    ArrayList<String> referralURLs = null;
702    ByteString   serverSASLCredentials = null;
703
704    try
705    {
706      if(reader.hasNextElement() &&
707          reader.peekType() == TYPE_REFERRAL_SEQUENCE)
708      {
709        try
710        {
711          reader.readStartSequence();
712          referralURLs = new ArrayList<>();
713
714          // Should have at least 1.
715          do
716          {
717            referralURLs.add(reader.readOctetStringAsString());
718          }
719          while(reader.hasNextElement());
720          reader.readEndSequence();
721        }
722        catch (Exception e)
723        {
724          logger.traceException(e);
725
726          LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
727          throw new LDAPException(PROTOCOL_ERROR, message, e);
728        }
729      }
730      if(reader.hasNextElement() &&
731          reader.peekType() == TYPE_SERVER_SASL_CREDENTIALS)
732      {
733        try
734        {
735          serverSASLCredentials =
736              reader.readOctetString();
737        }
738        catch (Exception e)
739        {
740          logger.traceException(e);
741
742          LocalizableMessage message = ERR_LDAP_BIND_RESULT_DECODE_SERVER_SASL_CREDENTIALS.get(e);
743          throw new LDAPException(PROTOCOL_ERROR, message, e);
744        }
745      }
746    }
747    catch(IOException e)
748    {
749      logger.traceException(e);
750    }
751
752    try
753    {
754      reader.readEndSequence();
755    }
756    catch (Exception e)
757    {
758      logger.traceException(e);
759
760      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
761      throw new LDAPException(PROTOCOL_ERROR, message, e);
762    }
763
764    return new BindResponseProtocolOp(resultCode, errorMessage, matchedDN,
765        referralURLs, serverSASLCredentials);
766  }
767
768  /**
769   * Decodes the elements from the provided ASN.1 reader as an LDAP
770   * compare request protocol op.
771   *
772   * @param  reader The ASN.1 reader
773   *
774   * @return  The decoded LDAP compare request protocol op.
775   *
776   * @throws  LDAPException  If a problem occurs while attempting to decode the
777   *                         ASN.1 element as a compare request protocol op.
778   */
779  private static CompareRequestProtocolOp readCompareRequest(ASN1Reader reader)
780      throws LDAPException
781  {
782    try
783    {
784      reader.readStartSequence();
785    }
786    catch (Exception e)
787    {
788      logger.traceException(e);
789
790      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE.get(e);
791      throw new LDAPException(PROTOCOL_ERROR, message, e);
792    }
793
794
795    ByteString dn;
796    try
797    {
798      dn = reader.readOctetString();
799    }
800    catch (Exception e)
801    {
802      logger.traceException(e);
803
804      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_DN.get(e);
805      throw new LDAPException(PROTOCOL_ERROR, message, e);
806    }
807
808    try
809    {
810      reader.readStartSequence();
811    }
812    catch (Exception e)
813    {
814      logger.traceException(e);
815
816      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_AVA.get(e);
817      throw new LDAPException(PROTOCOL_ERROR, message, e);
818    }
819
820    String attributeType;
821    try
822    {
823      attributeType = reader.readOctetStringAsString();
824    }
825    catch (Exception e)
826    {
827      logger.traceException(e);
828
829      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_TYPE.get(e);
830      throw new LDAPException(PROTOCOL_ERROR, message, e);
831    }
832
833
834    ByteString assertionValue;
835    try
836    {
837      assertionValue = reader.readOctetString();
838    }
839    catch (Exception e)
840    {
841      logger.traceException(e);
842
843      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_VALUE.get(e);
844      throw new LDAPException(PROTOCOL_ERROR, message, e);
845    }
846
847    try
848    {
849      reader.readEndSequence();
850    }
851    catch (Exception e)
852    {
853      logger.traceException(e);
854
855      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_AVA.get(e);
856      throw new LDAPException(PROTOCOL_ERROR, message, e);
857    }
858
859    try
860    {
861      reader.readEndSequence();
862    }
863    catch (Exception e)
864    {
865      logger.traceException(e);
866
867      LocalizableMessage message = ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE.get(e);
868      throw new LDAPException(PROTOCOL_ERROR, message, e);
869    }
870
871    return new CompareRequestProtocolOp(dn, attributeType, assertionValue);
872  }
873
874  /**
875   * Decodes the elements from the provided ASN.1 reader as a
876   * compare response protocol op.
877   *
878   * @param  reader The ASN.1 reader.
879   *
880   * @return  The decoded compare response protocol op.
881   *
882   * @throws  LDAPException  If a problem occurs while attempting to decode the
883   *                         ASN.1 element to a protocol op.
884   */
885  private static CompareResponseProtocolOp readCompareResponse(ASN1Reader
886      reader)
887      throws LDAPException
888  {
889    try
890    {
891      reader.readStartSequence();
892    }
893    catch (Exception e)
894    {
895      logger.traceException(e);
896
897      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
898      throw new LDAPException(PROTOCOL_ERROR, message, e);
899    }
900
901    int resultCode;
902    try
903    {
904      resultCode = (int)reader.readInteger();
905    }
906    catch (Exception e)
907    {
908      logger.traceException(e);
909
910      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
911      throw new LDAPException(PROTOCOL_ERROR, message, e);
912    }
913
914
915    DN matchedDN;
916    try
917    {
918      String dnString = reader.readOctetStringAsString();
919      if (dnString.length() == 0)
920      {
921        matchedDN = null;
922      }
923      else
924      {
925        matchedDN = DN.valueOf(dnString);
926      }
927    }
928    catch (Exception e)
929    {
930      logger.traceException(e);
931
932      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
933      throw new LDAPException(PROTOCOL_ERROR, message, e);
934    }
935
936
937    LocalizableMessage errorMessage;
938    try
939    {
940      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
941      if (errorMessage.length() == 0)
942      {
943        errorMessage = null;
944      }
945    }
946    catch (Exception e)
947    {
948      logger.traceException(e);
949
950      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
951      throw new LDAPException(PROTOCOL_ERROR, message, e);
952    }
953
954    ArrayList<String> referralURLs = null;
955
956    try
957    {
958      if (reader.hasNextElement())
959      {
960        reader.readStartSequence();
961        referralURLs = new ArrayList<>();
962
963        while(reader.hasNextElement())
964        {
965          referralURLs.add(reader.readOctetStringAsString());
966        }
967        reader.readEndSequence();
968      }
969    }
970    catch (Exception e)
971    {
972      logger.traceException(e);
973
974      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
975      throw new LDAPException(PROTOCOL_ERROR, message, e);
976    }
977
978    try
979    {
980      reader.readEndSequence();
981    }
982    catch (Exception e)
983    {
984      logger.traceException(e);
985
986      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
987      throw new LDAPException(PROTOCOL_ERROR, message, e);
988    }
989
990    return new CompareResponseProtocolOp(resultCode, errorMessage, matchedDN,
991        referralURLs);
992  }
993
994  /**
995   * Decodes the elements from the provided ASN.1 reader as an LDAP delete
996   * request protocol op.
997   *
998   * @param  reader The ASN.1 reader.
999   *
1000   * @return  The decoded delete request protocol op.
1001   *
1002   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
1003   *                         an unbind request protocol op.
1004   */
1005  private static DeleteRequestProtocolOp readDeleteRequest(ASN1Reader reader)
1006      throws LDAPException
1007  {
1008    try
1009    {
1010      return new DeleteRequestProtocolOp(reader.readOctetString());
1011    }
1012    catch (Exception e)
1013    {
1014      logger.traceException(e);
1015
1016      LocalizableMessage message = ERR_LDAP_DELETE_REQUEST_DECODE_DN.get(e);
1017      throw new LDAPException(PROTOCOL_ERROR, message, e);
1018    }
1019  }
1020
1021  /**
1022   * Decodes the provided ASN.1 element as a delete response protocol op.
1023   *
1024   * @param  reader The ASN.1 reader.
1025   *
1026   * @return  The decoded delete response protocol op.
1027   *
1028   * @throws  LDAPException  If a problem occurs while attempting to decode the
1029   *                         ASN.1 element to a protocol op.
1030   */
1031  private static DeleteResponseProtocolOp readDeleteResponse(ASN1Reader reader)
1032      throws LDAPException
1033  {
1034    try
1035    {
1036      reader.readStartSequence();
1037    }
1038    catch (Exception e)
1039    {
1040      logger.traceException(e);
1041
1042      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1043      throw new LDAPException(PROTOCOL_ERROR, message, e);
1044    }
1045
1046    int resultCode;
1047    try
1048    {
1049      resultCode = (int)reader.readInteger();
1050    }
1051    catch (Exception e)
1052    {
1053      logger.traceException(e);
1054
1055      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
1056      throw new LDAPException(PROTOCOL_ERROR, message, e);
1057    }
1058
1059
1060    DN matchedDN;
1061    try
1062    {
1063      String dnString = reader.readOctetStringAsString();
1064      if (dnString.length() == 0)
1065      {
1066        matchedDN = null;
1067      }
1068      else
1069      {
1070        matchedDN = DN.valueOf(dnString);
1071      }
1072    }
1073    catch (Exception e)
1074    {
1075      logger.traceException(e);
1076
1077      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
1078      throw new LDAPException(PROTOCOL_ERROR, message, e);
1079    }
1080
1081
1082    LocalizableMessage errorMessage;
1083    try
1084    {
1085      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
1086      if (errorMessage.length() == 0)
1087      {
1088        errorMessage = null;
1089      }
1090    }
1091    catch (Exception e)
1092    {
1093      logger.traceException(e);
1094
1095      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
1096      throw new LDAPException(PROTOCOL_ERROR, message, e);
1097    }
1098
1099    ArrayList<String> referralURLs = null;
1100
1101    try
1102    {
1103      if (reader.hasNextElement())
1104      {
1105        reader.readStartSequence();
1106        referralURLs = new ArrayList<>();
1107
1108        while(reader.hasNextElement())
1109        {
1110          referralURLs.add(reader.readOctetStringAsString());
1111        }
1112        reader.readEndSequence();
1113      }
1114    }
1115    catch (Exception e)
1116    {
1117      logger.traceException(e);
1118
1119      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
1120      throw new LDAPException(PROTOCOL_ERROR, message, e);
1121    }
1122
1123    try
1124    {
1125      reader.readEndSequence();
1126    }
1127    catch (Exception e)
1128    {
1129      logger.traceException(e);
1130
1131      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1132      throw new LDAPException(PROTOCOL_ERROR, message, e);
1133    }
1134
1135
1136    return new DeleteResponseProtocolOp(resultCode, errorMessage, matchedDN,
1137        referralURLs);
1138  }
1139
1140  /**
1141   * Decodes the elements from the provided ASN.1 reader as an
1142   * LDAP extended request protocol op.
1143   *
1144   * @param  reader The ASN.1 reader.
1145   *
1146   * @return  The decoded extended request protocol op.
1147   *
1148   * @throws  LDAPException  If a problem occurs while attempting to decode the
1149   *                         provided ASN.1 element as an LDAP extended request
1150   *                         protocol op.
1151   */
1152  private static ExtendedRequestProtocolOp readExtendedRequest(ASN1Reader
1153      reader)
1154      throws LDAPException
1155  {
1156    try
1157    {
1158      reader.readStartSequence();
1159    }
1160    catch (Exception e)
1161    {
1162      logger.traceException(e);
1163
1164      LocalizableMessage message = ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE.get(e);
1165      throw new LDAPException(PROTOCOL_ERROR, message, e);
1166    }
1167
1168
1169    String oid;
1170    try
1171    {
1172      oid = reader.readOctetStringAsString();
1173    }
1174    catch (Exception e)
1175    {
1176      logger.traceException(e);
1177
1178      LocalizableMessage message = ERR_LDAP_EXTENDED_REQUEST_DECODE_OID.get(e);
1179      throw new LDAPException(PROTOCOL_ERROR, message, e);
1180    }
1181
1182
1183    ByteString value = null;
1184    try
1185    {
1186      if(reader.hasNextElement())
1187      {
1188        value = reader.readOctetString();
1189      }
1190    }
1191    catch (Exception e)
1192    {
1193      logger.traceException(e);
1194
1195      LocalizableMessage message = ERR_LDAP_EXTENDED_REQUEST_DECODE_VALUE.get(e);
1196      throw new LDAPException(PROTOCOL_ERROR, message, e);
1197    }
1198
1199    try
1200    {
1201      reader.readEndSequence();
1202    }
1203    catch (Exception e)
1204    {
1205      logger.traceException(e);
1206
1207      LocalizableMessage message = ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE.get(e);
1208      throw new LDAPException(PROTOCOL_ERROR, message, e);
1209    }
1210
1211    return new ExtendedRequestProtocolOp(oid, value);
1212  }
1213
1214  /**
1215   * Decodes the elements from the provided ASN.1 reader as a
1216   * extended response protocol op.
1217   *
1218   * @param  reader The ASN.1 reader.
1219   *
1220   * @return  The decoded extended response protocol op.
1221   *
1222   * @throws  LDAPException  If a problem occurs while attempting to decode the
1223   *                         ASN.1 element to a protocol op.
1224   */
1225  private static ExtendedResponseProtocolOp readExtendedResponse(ASN1Reader
1226      reader)
1227      throws LDAPException
1228  {
1229    try
1230    {
1231      reader.readStartSequence();
1232    }
1233    catch (Exception e)
1234    {
1235      logger.traceException(e);
1236
1237      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1238      throw new LDAPException(PROTOCOL_ERROR, message, e);
1239    }
1240
1241    int resultCode;
1242    try
1243    {
1244      resultCode = (int)reader.readInteger();
1245    }
1246    catch (Exception e)
1247    {
1248      logger.traceException(e);
1249
1250      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
1251      throw new LDAPException(PROTOCOL_ERROR, message, e);
1252    }
1253
1254
1255    DN matchedDN;
1256    try
1257    {
1258      String dnString = reader.readOctetStringAsString();
1259      if (dnString.length() == 0)
1260      {
1261        matchedDN = null;
1262      }
1263      else
1264      {
1265        matchedDN = DN.valueOf(dnString);
1266      }
1267    }
1268    catch (Exception e)
1269    {
1270      logger.traceException(e);
1271
1272      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
1273      throw new LDAPException(PROTOCOL_ERROR, message, e);
1274    }
1275
1276
1277    LocalizableMessage errorMessage;
1278    try
1279    {
1280      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
1281      if (errorMessage.length() == 0)
1282      {
1283        errorMessage = null;
1284      }
1285    }
1286    catch (Exception e)
1287    {
1288      logger.traceException(e);
1289
1290      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
1291      throw new LDAPException(PROTOCOL_ERROR, message, e);
1292    }
1293
1294    ArrayList<String> referralURLs = null;
1295    String            oid          = null;
1296    ByteString   value        = null;
1297
1298    try
1299    {
1300      if(reader.hasNextElement() &&
1301          reader.peekType() == TYPE_REFERRAL_SEQUENCE)
1302      {
1303        try
1304        {
1305          reader.readStartSequence();
1306          referralURLs = new ArrayList<>();
1307
1308          while(reader.hasNextElement())
1309          {
1310            referralURLs.add(reader.readOctetStringAsString());
1311          }
1312          reader.readEndSequence();
1313        }
1314        catch (Exception e)
1315        {
1316          logger.traceException(e);
1317
1318          LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
1319          throw new LDAPException(PROTOCOL_ERROR, message, e);
1320        }
1321      }
1322      if(reader.hasNextElement() &&
1323          reader.peekType() == TYPE_EXTENDED_RESPONSE_OID)
1324      {
1325        try
1326        {
1327          oid = reader.readOctetStringAsString();
1328        }
1329        catch (Exception e)
1330        {
1331          logger.traceException(e);
1332
1333          LocalizableMessage message = ERR_LDAP_EXTENDED_RESULT_DECODE_OID.get(e);
1334          throw new LDAPException(PROTOCOL_ERROR, message, e);
1335        }
1336      }
1337      if(reader.hasNextElement() &&
1338          reader.peekType() == TYPE_EXTENDED_RESPONSE_VALUE)
1339      {
1340        try
1341        {
1342          value = reader.readOctetString();
1343        }
1344        catch (Exception e)
1345        {
1346          logger.traceException(e);
1347
1348          LocalizableMessage message = ERR_LDAP_EXTENDED_RESULT_DECODE_VALUE.get(e);
1349          throw new LDAPException(PROTOCOL_ERROR, message, e);
1350        }
1351      }
1352    }
1353    catch(IOException e)
1354    {
1355      logger.traceException(e);
1356    }
1357
1358    try
1359    {
1360      reader.readEndSequence();
1361    }
1362    catch (Exception e)
1363    {
1364      logger.traceException(e);
1365
1366      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1367      throw new LDAPException(PROTOCOL_ERROR, message, e);
1368    }
1369
1370    return new ExtendedResponseProtocolOp(resultCode, errorMessage, matchedDN,
1371        referralURLs, oid, value);
1372  }
1373
1374  /**
1375   * Decodes the elements from the provided ASN.1 reader as an LDAP
1376   * intermediate response protocol op.
1377   *
1378   * @param  reader The ASN.1 reader.
1379   *
1380   * @return  The decoded intermediate response protocol op.
1381   *
1382   * @throws  LDAPException  If a problem occurs while attempting to decode the
1383   *                         provided ASN.1 element as an LDAP intermediate
1384   *                         response protocol op.
1385   */
1386  private static IntermediateResponseProtocolOp
1387  readIntermediateResponse(ASN1Reader reader)
1388      throws LDAPException
1389  {
1390    try
1391    {
1392      reader.readStartSequence();
1393    }
1394    catch (Exception e)
1395    {
1396      logger.traceException(e);
1397
1398      LocalizableMessage message = ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE.get(e);
1399      throw new LDAPException(PROTOCOL_ERROR, message, e);
1400    }
1401
1402    String          oid   = null;
1403    ByteString value = null;
1404
1405    try
1406    {
1407      if(reader.hasNextElement() &&
1408          reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_OID)
1409      {
1410        try
1411        {
1412          if(reader.hasNextElement())
1413          {
1414            oid = reader.readOctetStringAsString();
1415          }
1416        }
1417        catch (Exception e)
1418        {
1419          logger.traceException(e);
1420
1421          LocalizableMessage message =
1422              ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID.get(
1423                  e.getMessage());
1424          throw new LDAPException(PROTOCOL_ERROR, message);
1425        }
1426      }
1427      if(reader.hasNextElement() &&
1428          reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_VALUE)
1429      {
1430        try
1431        {
1432          value = reader.readOctetString();
1433        }
1434        catch (Exception e)
1435        {
1436          logger.traceException(e);
1437
1438          LocalizableMessage message =
1439              ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_VALUE.
1440                  get(e.getMessage());
1441          throw new LDAPException(PROTOCOL_ERROR, message);
1442        }
1443      }
1444    }
1445    catch(IOException e)
1446    {
1447      logger.traceException(e);
1448    }
1449
1450    try
1451    {
1452      reader.readEndSequence();
1453    }
1454    catch (Exception e)
1455    {
1456      logger.traceException(e);
1457
1458      LocalizableMessage message = ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE.get(e);
1459      throw new LDAPException(PROTOCOL_ERROR, message, e);
1460    }
1461
1462    return new IntermediateResponseProtocolOp(oid, value);
1463  }
1464
1465  /**
1466   * Decodes the elements from the provided ASN.1 reader as a
1467   * modify DN request protocol op.
1468   *
1469   * @param  reader The ASN.1 reader.
1470   *
1471   * @return  The decoded modify DN request protocol op.
1472   *
1473   * @throws  LDAPException  If a problem occurs while trying to decode the
1474   *                         provided ASN.1 element as an LDAP modify DN request
1475   *                         protocol op.
1476   */
1477  private static ModifyDNRequestProtocolOp readModifyDNRequest(ASN1Reader
1478      reader)
1479      throws LDAPException
1480  {
1481    try
1482    {
1483      reader.readStartSequence();
1484    }
1485    catch (Exception e)
1486    {
1487      logger.traceException(e);
1488
1489      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE.get(e);
1490      throw new LDAPException(PROTOCOL_ERROR, message, e);
1491    }
1492
1493
1494    ByteString entryDN;
1495    try
1496    {
1497      entryDN = reader.readOctetString();
1498    }
1499    catch (Exception e)
1500    {
1501      logger.traceException(e);
1502
1503      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DN.get(e);
1504      throw new LDAPException(PROTOCOL_ERROR, message, e);
1505    }
1506
1507
1508    ByteString newRDN;
1509    try
1510    {
1511      newRDN = reader.readOctetString();
1512    }
1513    catch (Exception e)
1514    {
1515      logger.traceException(e);
1516
1517      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_RDN.get(e);
1518      throw new LDAPException(PROTOCOL_ERROR, message, e);
1519    }
1520
1521
1522    boolean deleteOldRDN;
1523    try
1524    {
1525      deleteOldRDN = reader.readBoolean();
1526    }
1527    catch (Exception e)
1528    {
1529      logger.traceException(e);
1530
1531      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DELETE_OLD_RDN.get(e);
1532      throw new LDAPException(PROTOCOL_ERROR, message, e);
1533    }
1534
1535
1536    ByteString newSuperior = null;
1537    try
1538    {
1539      if(reader.hasNextElement())
1540      {
1541        newSuperior = reader.readOctetString();
1542      }
1543    }
1544    catch (Exception e)
1545    {
1546      logger.traceException(e);
1547
1548      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_SUPERIOR.get(e);
1549      throw new LDAPException(PROTOCOL_ERROR, message, e);
1550    }
1551
1552    try
1553    {
1554      reader.readEndSequence();
1555    }
1556    catch (Exception e)
1557    {
1558      logger.traceException(e);
1559
1560      LocalizableMessage message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE.get(e);
1561      throw new LDAPException(PROTOCOL_ERROR, message, e);
1562    }
1563
1564    return new ModifyDNRequestProtocolOp(entryDN, newRDN, deleteOldRDN,
1565        newSuperior);
1566  }
1567
1568  /**
1569   * Decodes the elements from the provided ASN.1 reader as a
1570   * modify DN response protocol op.
1571   *
1572   * @param  reader The ASN.1 reader.
1573   *
1574   * @return  The decoded modify DN response protocol op.
1575   *
1576   * @throws  LDAPException  If a problem occurs while attempting to decode the
1577   *                         ASN.1 element to a protocol op.
1578   */
1579  private static ModifyDNResponseProtocolOp readModifyDNResponse(ASN1Reader
1580      reader)
1581      throws LDAPException
1582  {
1583    try
1584    {
1585      reader.readStartSequence();
1586    }
1587    catch (Exception e)
1588    {
1589      logger.traceException(e);
1590
1591      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1592      throw new LDAPException(PROTOCOL_ERROR, message, e);
1593    }
1594
1595    int resultCode;
1596    try
1597    {
1598      resultCode = (int)reader.readInteger();
1599    }
1600    catch (Exception e)
1601    {
1602      logger.traceException(e);
1603
1604      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
1605      throw new LDAPException(PROTOCOL_ERROR, message, e);
1606    }
1607
1608
1609    DN matchedDN;
1610    try
1611    {
1612      String dnString = reader.readOctetStringAsString();
1613      if (dnString.length() == 0)
1614      {
1615        matchedDN = null;
1616      }
1617      else
1618      {
1619        matchedDN = DN.valueOf(dnString);
1620      }
1621    }
1622    catch (Exception e)
1623    {
1624      logger.traceException(e);
1625
1626      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
1627      throw new LDAPException(PROTOCOL_ERROR, message, e);
1628    }
1629
1630
1631    LocalizableMessage errorMessage;
1632    try
1633    {
1634      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
1635      if (errorMessage.length() == 0)
1636      {
1637        errorMessage = null;
1638      }
1639    }
1640    catch (Exception e)
1641    {
1642      logger.traceException(e);
1643
1644      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
1645      throw new LDAPException(PROTOCOL_ERROR, message, e);
1646    }
1647
1648    ArrayList<String> referralURLs = null;
1649
1650    try
1651    {
1652      if (reader.hasNextElement())
1653      {
1654        reader.readStartSequence();
1655        referralURLs = new ArrayList<>();
1656
1657        while(reader.hasNextElement())
1658        {
1659          referralURLs.add(reader.readOctetStringAsString());
1660        }
1661        reader.readEndSequence();
1662      }
1663    }
1664    catch (Exception e)
1665    {
1666      logger.traceException(e);
1667
1668      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
1669      throw new LDAPException(PROTOCOL_ERROR, message, e);
1670    }
1671
1672    try
1673    {
1674      reader.readEndSequence();
1675    }
1676    catch (Exception e)
1677    {
1678      logger.traceException(e);
1679
1680      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1681      throw new LDAPException(PROTOCOL_ERROR, message, e);
1682    }
1683
1684    return new ModifyDNResponseProtocolOp(resultCode, errorMessage, matchedDN,
1685        referralURLs);
1686  }
1687
1688  /**
1689   * Decodes the elements from the provided ASN.1 reader as an LDAP
1690   * modify request protocol op.
1691   *
1692   * @param  reader The ASN.1 reader.
1693   *
1694   * @return  The decoded modify request protocol op.
1695   *
1696   * @throws  LDAPException  If a problem occurs while decoding the provided
1697   *                         ASN.1 element as an LDAP modify request protocol
1698   *                         op.
1699   */
1700  private static ModifyRequestProtocolOp readModifyRequest(ASN1Reader reader)
1701      throws LDAPException
1702  {
1703    try
1704    {
1705      reader.readStartSequence();
1706    }
1707    catch (Exception e)
1708    {
1709      logger.traceException(e);
1710
1711      LocalizableMessage message = ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE.get(e);
1712      throw new LDAPException(PROTOCOL_ERROR, message, e);
1713    }
1714
1715    ByteString dn;
1716    try
1717    {
1718      dn = reader.readOctetString();
1719    }
1720    catch (Exception e)
1721    {
1722      logger.traceException(e);
1723
1724      LocalizableMessage message = ERR_LDAP_MODIFY_REQUEST_DECODE_DN.get(e);
1725      throw new LDAPException(PROTOCOL_ERROR, message, e);
1726    }
1727
1728
1729
1730    ArrayList<RawModification> modifications;
1731    try
1732    {
1733      reader.readStartSequence();
1734      modifications = new ArrayList<>();
1735      while(reader.hasNextElement())
1736      {
1737        modifications.add(LDAPModification.decode(reader));
1738      }
1739      reader.readEndSequence();
1740    }
1741    catch (Exception e)
1742    {
1743      logger.traceException(e);
1744
1745      LocalizableMessage message = ERR_LDAP_MODIFY_REQUEST_DECODE_MODS.get(e);
1746      throw new LDAPException(PROTOCOL_ERROR, message, e);
1747    }
1748
1749    try
1750    {
1751      reader.readEndSequence();
1752    }
1753    catch (Exception e)
1754    {
1755      logger.traceException(e);
1756
1757      LocalizableMessage message = ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE.get(e);
1758      throw new LDAPException(PROTOCOL_ERROR, message, e);
1759    }
1760
1761
1762    return new ModifyRequestProtocolOp(dn, modifications);
1763  }
1764
1765  /**
1766   * Decodes the elements from the provided ASN.1 reader as a modify
1767   * response protocol op.
1768   *
1769   * @param  reader The ASN.1 reader.
1770   *
1771   * @return  The decoded modify response protocol op.
1772   *
1773   * @throws  LDAPException  If a problem occurs while attempting to decode the
1774   *                         ASN.1 element to a protocol op.
1775   */
1776  private static ModifyResponseProtocolOp readModifyResponse(ASN1Reader
1777      reader)
1778      throws LDAPException
1779  {
1780    try
1781    {
1782      reader.readStartSequence();
1783    }
1784    catch (Exception e)
1785    {
1786      logger.traceException(e);
1787
1788      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1789      throw new LDAPException(PROTOCOL_ERROR, message, e);
1790    }
1791
1792    int resultCode;
1793    try
1794    {
1795      resultCode = (int)reader.readInteger();
1796    }
1797    catch (Exception e)
1798    {
1799      logger.traceException(e);
1800
1801      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
1802      throw new LDAPException(PROTOCOL_ERROR, message, e);
1803    }
1804
1805
1806    DN matchedDN;
1807    try
1808    {
1809      String dnString = reader.readOctetStringAsString();
1810      if (dnString.length() == 0)
1811      {
1812        matchedDN = null;
1813      }
1814      else
1815      {
1816        matchedDN = DN.valueOf(dnString);
1817      }
1818    }
1819    catch (Exception e)
1820    {
1821      logger.traceException(e);
1822
1823      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
1824      throw new LDAPException(PROTOCOL_ERROR, message, e);
1825    }
1826
1827
1828    LocalizableMessage errorMessage;
1829    try
1830    {
1831      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
1832      if (errorMessage.length() == 0)
1833      {
1834        errorMessage = null;
1835      }
1836    }
1837    catch (Exception e)
1838    {
1839      logger.traceException(e);
1840
1841      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
1842      throw new LDAPException(PROTOCOL_ERROR, message, e);
1843    }
1844
1845    ArrayList<String> referralURLs = null;
1846
1847    try
1848    {
1849      if (reader.hasNextElement())
1850      {
1851        reader.readStartSequence();
1852        referralURLs = new ArrayList<>();
1853
1854        while(reader.hasNextElement())
1855        {
1856          referralURLs.add(reader.readOctetStringAsString());
1857        }
1858        reader.readEndSequence();
1859      }
1860    }
1861    catch (Exception e)
1862    {
1863      logger.traceException(e);
1864
1865      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
1866      throw new LDAPException(PROTOCOL_ERROR, message, e);
1867    }
1868
1869    try
1870    {
1871      reader.readEndSequence();
1872    }
1873    catch (Exception e)
1874    {
1875      logger.traceException(e);
1876
1877      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
1878      throw new LDAPException(PROTOCOL_ERROR, message, e);
1879    }
1880
1881    return new ModifyResponseProtocolOp(resultCode, errorMessage, matchedDN,
1882        referralURLs);
1883  }
1884
1885  /**
1886   * Decodes the elements from the provided ASN.1 reader as an LDAP search
1887   * request protocol op.
1888   *
1889   * @param  reader The ASN.1 reader.
1890   *
1891   * @return  The decoded LDAP search request protocol op.
1892   *
1893   * @throws  LDAPException  If a problem occurs while decoding the provided
1894   *                         ASN.1 element as an LDAP search request protocol
1895   *                         op.
1896   */
1897  private static SearchRequestProtocolOp readSearchRequest(ASN1Reader reader)
1898      throws LDAPException
1899  {
1900    try
1901    {
1902      reader.readStartSequence();
1903    }
1904    catch (Exception e)
1905    {
1906      logger.traceException(e);
1907
1908      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(e);
1909      throw new LDAPException(PROTOCOL_ERROR, message, e);
1910    }
1911
1912    ByteString baseDN;
1913    try
1914    {
1915      baseDN = reader.readOctetString();
1916    }
1917    catch (Exception e)
1918    {
1919      logger.traceException(e);
1920
1921      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_BASE.get(e);
1922      throw new LDAPException(PROTOCOL_ERROR, message, e);
1923    }
1924
1925
1926    SearchScope scope;
1927    try
1928    {
1929      int scopeValue = (int)reader.readInteger();
1930      switch (scopeValue)
1931      {
1932        case SCOPE_BASE_OBJECT:
1933          scope = SearchScope.BASE_OBJECT;
1934          break;
1935        case SCOPE_SINGLE_LEVEL:
1936          scope = SearchScope.SINGLE_LEVEL;
1937          break;
1938        case SCOPE_WHOLE_SUBTREE:
1939          scope = SearchScope.WHOLE_SUBTREE;
1940          break;
1941        case SCOPE_SUBORDINATE_SUBTREE:
1942          scope = SearchScope.SUBORDINATES;
1943          break;
1944        default:
1945          LocalizableMessage message =
1946              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE.get(scopeValue);
1947          throw new LDAPException(PROTOCOL_ERROR, message);
1948      }
1949    }
1950    catch (LDAPException le)
1951    {
1952      throw le;
1953    }
1954    catch (Exception e)
1955    {
1956      logger.traceException(e);
1957
1958      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE.get(e);
1959      throw new LDAPException(PROTOCOL_ERROR, message, e);
1960    }
1961
1962
1963    DereferenceAliasesPolicy dereferencePolicy;
1964    try
1965    {
1966      int derefValue = (int)reader.readInteger();
1967      switch (derefValue)
1968      {
1969        case DEREF_NEVER:
1970        case DEREF_IN_SEARCHING:
1971        case DEREF_FINDING_BASE:
1972        case DEREF_ALWAYS:
1973          dereferencePolicy = DereferenceAliasesPolicy.valueOf(derefValue);
1974          break;
1975        default:
1976          LocalizableMessage message =
1977              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF.get(derefValue);
1978          throw new LDAPException(PROTOCOL_ERROR, message);
1979      }
1980    }
1981    catch (LDAPException le)
1982    {
1983      throw le;
1984    }
1985    catch (Exception e)
1986    {
1987      logger.traceException(e);
1988
1989      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF.get(e);
1990      throw new LDAPException(PROTOCOL_ERROR, message, e);
1991    }
1992
1993
1994    int sizeLimit;
1995    try
1996    {
1997      sizeLimit = (int)reader.readInteger();
1998    }
1999    catch (Exception e)
2000    {
2001      logger.traceException(e);
2002
2003      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT.get(e);
2004      throw new LDAPException(PROTOCOL_ERROR, message, e);
2005    }
2006
2007
2008    int timeLimit;
2009    try
2010    {
2011      timeLimit = (int)reader.readInteger();
2012    }
2013    catch (Exception e)
2014    {
2015      logger.traceException(e);
2016
2017      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT.get(e);
2018      throw new LDAPException(PROTOCOL_ERROR, message, e);
2019    }
2020
2021
2022    boolean typesOnly;
2023    try
2024    {
2025      typesOnly = reader.readBoolean();
2026    }
2027    catch (Exception e)
2028    {
2029      logger.traceException(e);
2030
2031      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY.get(e);
2032      throw new LDAPException(PROTOCOL_ERROR, message, e);
2033    }
2034
2035    RawFilter filter;
2036    try
2037    {
2038      filter = RawFilter.decode(reader);
2039    }
2040    catch (Exception e)
2041    {
2042      logger.traceException(e);
2043
2044      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER.get(e);
2045      throw new LDAPException(PROTOCOL_ERROR, message, e);
2046    }
2047
2048
2049    LinkedHashSet<String> attributes;
2050    try
2051    {
2052      reader.readStartSequence();
2053      attributes = new LinkedHashSet<>();
2054      while(reader.hasNextElement())
2055      {
2056        attributes.add(reader.readOctetStringAsString());
2057      }
2058      reader.readEndSequence();
2059    }
2060    catch (Exception e)
2061    {
2062      logger.traceException(e);
2063
2064      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES.get(e);
2065      throw new LDAPException(PROTOCOL_ERROR, message, e);
2066    }
2067
2068    try
2069    {
2070      reader.readEndSequence();
2071    }
2072    catch (Exception e)
2073    {
2074      logger.traceException(e);
2075
2076      LocalizableMessage message = ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(e);
2077      throw new LDAPException(PROTOCOL_ERROR, message, e);
2078    }
2079
2080    return new SearchRequestProtocolOp(baseDN, scope, dereferencePolicy,
2081        sizeLimit, timeLimit, typesOnly, filter,
2082        attributes);
2083  }
2084
2085  /**
2086   * Decodes the elements from the provided ASN.1 reader as a search
2087   * result done protocol op.
2088   *
2089   * @param  reader The ASN.1 reader
2090   *
2091   * @return  The decoded search result done protocol op.
2092   *
2093   * @throws  LDAPException  If a problem occurs while attempting to decode the
2094   *                         ASN.1 element to a protocol op.
2095   */
2096  private static SearchResultDoneProtocolOp readSearchDone(ASN1Reader
2097      reader)
2098      throws LDAPException
2099  {
2100    try
2101    {
2102      reader.readStartSequence();
2103    }
2104    catch (Exception e)
2105    {
2106      logger.traceException(e);
2107
2108      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
2109      throw new LDAPException(PROTOCOL_ERROR, message, e);
2110    }
2111
2112    int resultCode;
2113    try
2114    {
2115      resultCode = (int)reader.readInteger();
2116    }
2117    catch (Exception e)
2118    {
2119      logger.traceException(e);
2120
2121      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(e);
2122      throw new LDAPException(PROTOCOL_ERROR, message, e);
2123    }
2124
2125
2126    DN matchedDN;
2127    try
2128    {
2129      String dnString = reader.readOctetStringAsString();
2130      if (dnString.length() == 0)
2131      {
2132        matchedDN = null;
2133      }
2134      else
2135      {
2136        matchedDN = DN.valueOf(dnString);
2137      }
2138    }
2139    catch (Exception e)
2140    {
2141      logger.traceException(e);
2142
2143      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(e);
2144      throw new LDAPException(PROTOCOL_ERROR, message, e);
2145    }
2146
2147
2148    LocalizableMessage errorMessage;
2149    try
2150    {
2151      errorMessage = LocalizableMessage.raw(reader.readOctetStringAsString());
2152      if (errorMessage.length() == 0)
2153      {
2154        errorMessage = null;
2155      }
2156    }
2157    catch (Exception e)
2158    {
2159      logger.traceException(e);
2160
2161      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(e);
2162      throw new LDAPException(PROTOCOL_ERROR, message, e);
2163    }
2164
2165    ArrayList<String> referralURLs = null;
2166
2167    try
2168    {
2169      if (reader.hasNextElement())
2170      {
2171        reader.readStartSequence();
2172        referralURLs = new ArrayList<>();
2173
2174        while(reader.hasNextElement())
2175        {
2176          referralURLs.add(reader.readOctetStringAsString());
2177        }
2178        reader.readEndSequence();
2179      }
2180    }
2181    catch (Exception e)
2182    {
2183      logger.traceException(e);
2184
2185      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_REFERRALS.get(e);
2186      throw new LDAPException(PROTOCOL_ERROR, message, e);
2187    }
2188
2189    try
2190    {
2191      reader.readEndSequence();
2192    }
2193    catch (Exception e)
2194    {
2195      logger.traceException(e);
2196
2197      LocalizableMessage message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(e);
2198      throw new LDAPException(PROTOCOL_ERROR, message, e);
2199    }
2200
2201    return new SearchResultDoneProtocolOp(resultCode, errorMessage, matchedDN,
2202        referralURLs);
2203  }
2204
2205  /**
2206   * Decodes the elements from the provided ASN.1 reader as an LDAP search
2207   * result entry protocol op.
2208   *
2209   * @param  reader The ASN.1 reader.
2210   *
2211   * @return  The decoded search result entry protocol op.
2212   *
2213   * @throws  LDAPException  If a problem occurs while decoding the provided
2214   *                         ASN.1 element as an LDAP search result entry
2215   *                         protocol op.
2216   */
2217  public static SearchResultEntryProtocolOp readSearchEntry(ASN1Reader
2218      reader)
2219      throws LDAPException
2220  {
2221    try
2222    {
2223      reader.readStartSequence();
2224    }
2225    catch (Exception e)
2226    {
2227      logger.traceException(e);
2228
2229      LocalizableMessage message = ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE.get(e);
2230      throw new LDAPException(PROTOCOL_ERROR, message, e);
2231    }
2232
2233
2234    DN dn;
2235    try
2236    {
2237      dn = DN.valueOf(reader.readOctetStringAsString());
2238    }
2239    catch (Exception e)
2240    {
2241      logger.traceException(e);
2242
2243      LocalizableMessage message = ERR_LDAP_SEARCH_ENTRY_DECODE_DN.get(e);
2244      throw new LDAPException(PROTOCOL_ERROR, message, e);
2245    }
2246
2247
2248
2249    LinkedList<LDAPAttribute> attributes;
2250    try
2251    {
2252      reader.readStartSequence();
2253      attributes = new LinkedList<>();
2254      while(reader.hasNextElement())
2255      {
2256        attributes.add(LDAPAttribute.decode(reader));
2257      }
2258      reader.readEndSequence();
2259    }
2260    catch (Exception e)
2261    {
2262      logger.traceException(e);
2263
2264      LocalizableMessage message = ERR_LDAP_SEARCH_ENTRY_DECODE_ATTRS.get(e);
2265      throw new LDAPException(PROTOCOL_ERROR, message, e);
2266    }
2267
2268    try
2269    {
2270      reader.readEndSequence();
2271    }
2272    catch (Exception e)
2273    {
2274      logger.traceException(e);
2275
2276      LocalizableMessage message = ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE.get(e);
2277      throw new LDAPException(PROTOCOL_ERROR, message, e);
2278    }
2279
2280
2281    return new SearchResultEntryProtocolOp(dn, attributes);
2282  }
2283
2284  /**
2285   * Decodes the elements from the provided ASN.1 reader as a search
2286   * result reference protocol op.
2287   *
2288   * @param  reader The ASN.1 reader.
2289   *
2290   * @return  The decoded search result reference protocol op.
2291   *
2292   * @throws  LDAPException  If a problem occurs while decoding the provided
2293   *                         ASN.1 element as an LDAP search result reference
2294   *                         protocol op.
2295   */
2296  private static SearchResultReferenceProtocolOp
2297  readSearchReference(ASN1Reader reader)
2298      throws LDAPException
2299  {
2300    try
2301    {
2302      reader.readStartSequence();
2303    }
2304    catch (Exception e)
2305    {
2306      logger.traceException(e);
2307
2308      LocalizableMessage message = ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE.get(e);
2309      throw new LDAPException(PROTOCOL_ERROR, message, e);
2310    }
2311
2312
2313    ArrayList<String> referralURLs = new ArrayList<>();
2314    try
2315    {
2316      // Should have atleast 1 URL.
2317      do
2318      {
2319        referralURLs.add(reader.readOctetStringAsString());
2320      }
2321      while(reader.hasNextElement());
2322    }
2323    catch (Exception e)
2324    {
2325      logger.traceException(e);
2326
2327      LocalizableMessage message = ERR_LDAP_SEARCH_REFERENCE_DECODE_URLS.get(e);
2328      throw new LDAPException(PROTOCOL_ERROR, message, e);
2329    }
2330
2331    try
2332    {
2333      reader.readEndSequence();
2334    }
2335    catch (Exception e)
2336    {
2337      logger.traceException(e);
2338
2339      LocalizableMessage message = ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE.get(e);
2340      throw new LDAPException(PROTOCOL_ERROR, message, e);
2341    }
2342
2343    return new SearchResultReferenceProtocolOp(referralURLs);
2344  }
2345
2346  /**
2347   * Decodes the elements from the provided ASN.1 read as an LDAP unbind
2348   * request protocol op.
2349   *
2350   * @param  reader The ASN.1 reader.
2351   *
2352   * @return  The decoded LDAP unbind request protocol op.
2353   *
2354   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
2355   *                         an unbind request protocol op.
2356   */
2357  private static UnbindRequestProtocolOp readUnbindRequest(ASN1Reader reader)
2358      throws LDAPException
2359  {
2360    try
2361    {
2362      reader.readNull();
2363      return new UnbindRequestProtocolOp();
2364    }
2365    catch (Exception e)
2366    {
2367      logger.traceException(e);
2368
2369      LocalizableMessage message = ERR_LDAP_UNBIND_DECODE.get(e);
2370      throw new LDAPException(PROTOCOL_ERROR, message, e);
2371    }
2372  }
2373
2374  /**
2375   * Decodes the elements from the provided ASN.1 reader as a set of controls.
2376   *
2377   * @param  reader The ASN.1 reader.
2378   *
2379   * @return  The decoded set of controls.
2380   *
2381   * @throws  LDAPException  If a problem occurs while attempting to decode the
2382   *                         controls.
2383   */
2384  private static ArrayList<Control> readControls(ASN1Reader reader)
2385      throws LDAPException
2386  {
2387    try
2388    {
2389      reader.readStartSequence();
2390      ArrayList<Control> controls = new ArrayList<>();
2391      while(reader.hasNextElement())
2392      {
2393        controls.add(readControl(reader));
2394      }
2395
2396      reader.readEndSequence();
2397      return controls;
2398    }
2399    catch (Exception e)
2400    {
2401      LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE.get(e);
2402      throw new LDAPException(PROTOCOL_ERROR, message, e);
2403    }
2404  }
2405
2406  /**
2407   * Decodes the elements from the provided ASN.1 reader as an LDAP control.
2408   *
2409   * @param  reader The ASN.1 reader.
2410   *
2411   * @return  The decoded LDAP control.
2412   *
2413   * @throws  LDAPException  If a problem occurs while attempting to decode the
2414   *                         provided ASN.1 element as an LDAP control.
2415   */
2416  public static LDAPControl readControl(ASN1Reader reader)
2417      throws LDAPException
2418  {
2419    try
2420    {
2421      reader.readStartSequence();
2422    }
2423    catch (Exception e)
2424    {
2425      logger.traceException(e);
2426
2427      LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(e);
2428      throw new LDAPException(PROTOCOL_ERROR, message, e);
2429    }
2430
2431
2432    String oid;
2433    try
2434    {
2435      oid = reader.readOctetStringAsString();
2436    }
2437    catch (Exception e)
2438    {
2439      logger.traceException(e);
2440
2441      LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_OID.get(e);
2442      throw new LDAPException(PROTOCOL_ERROR, message, e);
2443    }
2444
2445    boolean isCritical = false;
2446    ByteString value = null;
2447    try
2448    {
2449      if(reader.hasNextElement() &&
2450          reader.peekType() == ASN1.UNIVERSAL_BOOLEAN_TYPE)
2451      {
2452        try
2453        {
2454          isCritical = reader.readBoolean();
2455        }
2456        catch (Exception e2)
2457        {
2458          logger.traceException(e2);
2459
2460          LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(e2);
2461          throw new LDAPException(PROTOCOL_ERROR, message, e2);
2462        }
2463      }
2464      if(reader.hasNextElement() &&
2465          reader.peekType() == ASN1.UNIVERSAL_OCTET_STRING_TYPE)
2466      {
2467        try
2468        {
2469          value = reader.readOctetString();
2470        }
2471        catch (Exception e2)
2472        {
2473          logger.traceException(e2);
2474
2475          LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_VALUE.get(e2);
2476          throw new LDAPException(PROTOCOL_ERROR, message, e2);
2477        }
2478      }
2479    }
2480    catch(IOException e)
2481    {
2482      logger.traceException(e);
2483    }
2484
2485    try
2486    {
2487      reader.readEndSequence();
2488    }
2489    catch (Exception e)
2490    {
2491      logger.traceException(e);
2492
2493      LocalizableMessage message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(e);
2494      throw new LDAPException(PROTOCOL_ERROR, message, e);
2495    }
2496
2497    return new LDAPControl(oid, isCritical, value);
2498  }
2499}