001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Arrays;
027 import java.util.List;
028 import java.util.concurrent.LinkedBlockingQueue;
029 import java.util.concurrent.TimeUnit;
030
031 import com.unboundid.asn1.ASN1Buffer;
032 import com.unboundid.asn1.ASN1BufferSequence;
033 import com.unboundid.asn1.ASN1Element;
034 import com.unboundid.asn1.ASN1Integer;
035 import com.unboundid.asn1.ASN1OctetString;
036 import com.unboundid.asn1.ASN1Sequence;
037 import com.unboundid.ldap.protocol.LDAPMessage;
038 import com.unboundid.ldap.protocol.LDAPResponse;
039 import com.unboundid.ldap.protocol.ProtocolOp;
040 import com.unboundid.util.InternalUseOnly;
041 import com.unboundid.util.LDAPSDKUsageException;
042
043 import static com.unboundid.ldap.sdk.LDAPMessages.*;
044 import static com.unboundid.util.Debug.*;
045 import static com.unboundid.util.StaticUtils.*;
046
047
048
049 /**
050 * This class implements the processing necessary to perform an LDAPv3 simple
051 * bind operation, which authenticates using a bind DN and password.
052 */
053 public final class SimpleBindRequest
054 extends BindRequest
055 implements ResponseAcceptor, ProtocolOp
056 {
057 /**
058 * The BER type to use for the credentials element in a simple bind request
059 * protocol op.
060 */
061 private static final byte CRED_TYPE_SIMPLE = (byte) 0x80;
062
063
064
065 /**
066 * The ASN.1 octet string that will be used for the bind DN if none was
067 * provided.
068 */
069 private static final ASN1OctetString NO_BIND_DN = new ASN1OctetString();
070
071
072
073 /**
074 * The ASN.1 octet string that will be used for the bind password if none was
075 * provided.
076 */
077 private static final ASN1OctetString NO_PASSWORD =
078 new ASN1OctetString(CRED_TYPE_SIMPLE);
079
080
081
082 /**
083 * The serial version UID for this serializable class.
084 */
085 private static final long serialVersionUID = 4725871243149974407L;
086
087
088
089 // The message ID from the last LDAP message sent from this request.
090 private int messageID = -1;
091
092 // The bind DN for this simple bind request.
093 private final ASN1OctetString bindDN;
094
095 // The password for this simple bind request.
096 private final ASN1OctetString password;
097
098 // The queue that will be used to receive response messages from the server.
099 private final LinkedBlockingQueue<LDAPResponse> responseQueue =
100 new LinkedBlockingQueue<LDAPResponse>();
101
102 // The password provider that should be used to obtain the password for this
103 // simple bind request.
104 private final PasswordProvider passwordProvider;
105
106
107
108 /**
109 * Creates a new simple bind request that may be used to perform an anonymous
110 * bind to the directory server (i.e., with a zero-length bind DN and a
111 * zero-length password).
112 */
113 public SimpleBindRequest()
114 {
115 this(NO_BIND_DN, NO_PASSWORD, null, NO_CONTROLS);
116 }
117
118
119
120 /**
121 * Creates a new simple bind request with the provided bind DN and password.
122 *
123 * @param bindDN The bind DN for this simple bind request.
124 * @param password The password for this simple bind request.
125 */
126 public SimpleBindRequest(final String bindDN, final String password)
127 {
128 this(bindDN, password, NO_CONTROLS);
129 }
130
131
132
133 /**
134 * Creates a new simple bind request with the provided bind DN and password.
135 *
136 * @param bindDN The bind DN for this simple bind request.
137 * @param password The password for this simple bind request.
138 */
139 public SimpleBindRequest(final String bindDN, final byte[] password)
140 {
141 this(bindDN, password, NO_CONTROLS);
142 }
143
144
145
146 /**
147 * Creates a new simple bind request with the provided bind DN and password.
148 *
149 * @param bindDN The bind DN for this simple bind request.
150 * @param password The password for this simple bind request.
151 */
152 public SimpleBindRequest(final DN bindDN, final String password)
153 {
154 this(bindDN, password, NO_CONTROLS);
155 }
156
157
158
159 /**
160 * Creates a new simple bind request with the provided bind DN and password.
161 *
162 * @param bindDN The bind DN for this simple bind request.
163 * @param password The password for this simple bind request.
164 */
165 public SimpleBindRequest(final DN bindDN, final byte[] password)
166 {
167 this(bindDN, password, NO_CONTROLS);
168 }
169
170
171
172 /**
173 * Creates a new simple bind request with the provided bind DN and password.
174 *
175 * @param bindDN The bind DN for this simple bind request.
176 * @param password The password for this simple bind request.
177 * @param controls The set of controls for this simple bind request.
178 */
179 public SimpleBindRequest(final String bindDN, final String password,
180 final Control... controls)
181 {
182 super(controls);
183
184 if (bindDN == null)
185 {
186 this.bindDN = NO_BIND_DN;
187 }
188 else
189 {
190 this.bindDN = new ASN1OctetString(bindDN);
191 }
192
193 if (password == null)
194 {
195 this.password = NO_PASSWORD;
196 }
197 else
198 {
199 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
200 }
201
202 passwordProvider = null;
203 }
204
205
206
207 /**
208 * Creates a new simple bind request with the provided bind DN and password.
209 *
210 * @param bindDN The bind DN for this simple bind request.
211 * @param password The password for this simple bind request.
212 * @param controls The set of controls for this simple bind request.
213 */
214 public SimpleBindRequest(final String bindDN, final byte[] password,
215 final Control... controls)
216 {
217 super(controls);
218
219 if (bindDN == null)
220 {
221 this.bindDN = NO_BIND_DN;
222 }
223 else
224 {
225 this.bindDN = new ASN1OctetString(bindDN);
226 }
227
228 if (password == null)
229 {
230 this.password = NO_PASSWORD;
231 }
232 else
233 {
234 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
235 }
236
237 passwordProvider = null;
238 }
239
240
241
242 /**
243 * Creates a new simple bind request with the provided bind DN and password.
244 *
245 * @param bindDN The bind DN for this simple bind request.
246 * @param password The password for this simple bind request.
247 * @param controls The set of controls for this simple bind request.
248 */
249 public SimpleBindRequest(final DN bindDN, final String password,
250 final Control... controls)
251 {
252 super(controls);
253
254 if (bindDN == null)
255 {
256 this.bindDN = NO_BIND_DN;
257 }
258 else
259 {
260 this.bindDN = new ASN1OctetString(bindDN.toString());
261 }
262
263 if (password == null)
264 {
265 this.password = NO_PASSWORD;
266 }
267 else
268 {
269 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
270 }
271
272 passwordProvider = null;
273 }
274
275
276
277 /**
278 * Creates a new simple bind request with the provided bind DN and password.
279 *
280 * @param bindDN The bind DN for this simple bind request.
281 * @param password The password for this simple bind request.
282 * @param controls The set of controls for this simple bind request.
283 */
284 public SimpleBindRequest(final DN bindDN, final byte[] password,
285 final Control... controls)
286 {
287 super(controls);
288
289 if (bindDN == null)
290 {
291 this.bindDN = NO_BIND_DN;
292 }
293 else
294 {
295 this.bindDN = new ASN1OctetString(bindDN.toString());
296 }
297
298 if (password == null)
299 {
300 this.password = NO_PASSWORD;
301 }
302 else
303 {
304 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
305 }
306
307 passwordProvider = null;
308 }
309
310
311
312 /**
313 * Creates a new simple bind request with the provided bind DN and that will
314 * use a password provider in order to obtain the bind password.
315 *
316 * @param bindDN The bind DN for this simple bind request. It
317 * must not be {@code null}.
318 * @param passwordProvider The password provider that will be used to obtain
319 * the password for this simple bind request. It
320 * must not be {@code null}.
321 * @param controls The set of controls for this simple bind request.
322 */
323 public SimpleBindRequest(final String bindDN,
324 final PasswordProvider passwordProvider,
325 final Control... controls)
326 {
327 super(controls);
328
329 this.bindDN = new ASN1OctetString(bindDN);
330 this.passwordProvider = passwordProvider;
331
332 password = null;
333 }
334
335
336
337 /**
338 * Creates a new simple bind request with the provided bind DN and that will
339 * use a password provider in order to obtain the bind password.
340 *
341 * @param bindDN The bind DN for this simple bind request. It
342 * must not be {@code null}.
343 * @param passwordProvider The password provider that will be used to obtain
344 * the password for this simple bind request. It
345 * must not be {@code null}.
346 * @param controls The set of controls for this simple bind request.
347 */
348 public SimpleBindRequest(final DN bindDN,
349 final PasswordProvider passwordProvider,
350 final Control... controls)
351 {
352 super(controls);
353
354 this.bindDN = new ASN1OctetString(bindDN.toString());
355 this.passwordProvider = passwordProvider;
356
357 password = null;
358 }
359
360
361
362 /**
363 * Creates a new simple bind request with the provided bind DN and password.
364 *
365 * @param bindDN The bind DN for this simple bind request.
366 * @param password The password for this simple bind request.
367 * @param passwordProvider The password provider that will be used to obtain
368 * the password to use for the bind request.
369 * @param controls The set of controls for this simple bind request.
370 */
371 private SimpleBindRequest(final ASN1OctetString bindDN,
372 final ASN1OctetString password,
373 final PasswordProvider passwordProvider,
374 final Control... controls)
375 {
376 super(controls);
377
378 this.bindDN = bindDN;
379 this.password = password;
380 this.passwordProvider = passwordProvider;
381 }
382
383
384
385 /**
386 * Retrieves the bind DN for this simple bind request.
387 *
388 * @return The bind DN for this simple bind request.
389 */
390 public String getBindDN()
391 {
392 return bindDN.stringValue();
393 }
394
395
396
397 /**
398 * Retrieves the password for this simple bind request, if no password
399 * provider has been configured.
400 *
401 * @return The password for this simple bind request, or {@code null} if a
402 * password provider will be used to obtain the password.
403 */
404 public ASN1OctetString getPassword()
405 {
406 return password;
407 }
408
409
410
411 /**
412 * Retrieves the password provider for this simple bind request, if defined.
413 *
414 * @return The password provider for this simple bind request, or
415 * {@code null} if this bind request was created with an explicit
416 * password rather than a password provider.
417 */
418 public PasswordProvider getPasswordProvider()
419 {
420 return passwordProvider;
421 }
422
423
424
425 /**
426 * {@inheritDoc}
427 */
428 public byte getProtocolOpType()
429 {
430 return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST;
431 }
432
433
434
435 /**
436 * {@inheritDoc}
437 */
438 public void writeTo(final ASN1Buffer buffer)
439 {
440 final ASN1BufferSequence requestSequence =
441 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST);
442 buffer.addElement(VERSION_ELEMENT);
443 buffer.addElement(bindDN);
444
445 if (passwordProvider == null)
446 {
447 buffer.addElement(password);
448 }
449 else
450 {
451 byte[] pwBytes;
452 try
453 {
454 pwBytes = passwordProvider.getPasswordBytes();
455 }
456 catch (final LDAPException le)
457 {
458 debugException(le);
459 throw new LDAPRuntimeException(le);
460 }
461
462 final ASN1OctetString pw = new ASN1OctetString(CRED_TYPE_SIMPLE, pwBytes);
463 buffer.addElement(pw);
464 buffer.setZeroBufferOnClear();
465 Arrays.fill(pwBytes, (byte) 0x00);
466 }
467
468 requestSequence.end();
469 }
470
471
472
473 /**
474 * {@inheritDoc}
475 * Use of this method is only supported if the bind request was created with a
476 * static password. It is not allowed if the password will be obtained
477 * through a password provider.
478 *
479 * @throws LDAPSDKUsageException If this bind request was created with a
480 * password provider rather than a static
481 * password.
482 */
483 public ASN1Element encodeProtocolOp()
484 throws LDAPSDKUsageException
485 {
486 if (password == null)
487 {
488 throw new LDAPSDKUsageException(
489 ERR_SIMPLE_BIND_ENCODE_PROTOCOL_OP_WITH_PROVIDER.get());
490 }
491
492 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST,
493 new ASN1Integer(3),
494 bindDN,
495 password);
496 }
497
498
499
500 /**
501 * {@inheritDoc}
502 */
503 @Override()
504 protected BindResult process(final LDAPConnection connection, final int depth)
505 throws LDAPException
506 {
507 if (connection.synchronousMode())
508 {
509 @SuppressWarnings("deprecation")
510 final boolean autoReconnect =
511 connection.getConnectionOptions().autoReconnect();
512 return processSync(connection, autoReconnect);
513 }
514
515 // See if a bind DN was provided without a password. If that is the case
516 // and this should not be allowed, then throw an exception.
517 if (password != null)
518 {
519 if ((bindDN.getValue().length > 0) && (password.getValue().length == 0) &&
520 connection.getConnectionOptions().bindWithDNRequiresPassword())
521 {
522 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR,
523 ERR_SIMPLE_BIND_DN_WITHOUT_PASSWORD.get());
524 debugCodingError(le);
525 throw le;
526 }
527 }
528
529
530 // Create the LDAP message.
531 messageID = connection.nextMessageID();
532 final LDAPMessage message = new LDAPMessage(messageID, this, getControls());
533
534
535 // Register with the connection reader to be notified of responses for the
536 // request that we've created.
537 connection.registerResponseAcceptor(messageID, this);
538
539
540 try
541 {
542 // Send the request to the server.
543 debugLDAPRequest(this);
544 final long requestTime = System.nanoTime();
545 connection.getConnectionStatistics().incrementNumBindRequests();
546 connection.sendMessage(message);
547
548 // Wait for and process the response.
549 final LDAPResponse response;
550 try
551 {
552 final long responseTimeout = getResponseTimeoutMillis(connection);
553 if (responseTimeout > 0)
554 {
555 response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS);
556 }
557 else
558 {
559 response = responseQueue.take();
560 }
561 }
562 catch (InterruptedException ie)
563 {
564 debugException(ie);
565 throw new LDAPException(ResultCode.LOCAL_ERROR,
566 ERR_BIND_INTERRUPTED.get(connection.getHostPort()), ie);
567 }
568
569 return handleResponse(connection, response, requestTime, false);
570 }
571 finally
572 {
573 connection.deregisterResponseAcceptor(messageID);
574 }
575 }
576
577
578
579 /**
580 * Processes this bind operation in synchronous mode, in which the same
581 * thread will send the request and read the response.
582 *
583 * @param connection The connection to use to communicate with the directory
584 * server.
585 * @param allowRetry Indicates whether the request may be re-tried on a
586 * re-established connection if the initial attempt fails
587 * in a way that indicates the connection is no longer
588 * valid and autoReconnect is true.
589 *
590 * @return An LDAP result object that provides information about the result
591 * of the bind processing.
592 *
593 * @throws LDAPException If a problem occurs while sending the request or
594 * reading the response.
595 */
596 private BindResult processSync(final LDAPConnection connection,
597 final boolean allowRetry)
598 throws LDAPException
599 {
600 // Create the LDAP message.
601 messageID = connection.nextMessageID();
602 final LDAPMessage message =
603 new LDAPMessage(messageID, this, getControls());
604
605
606 // Set the appropriate timeout on the socket.
607 try
608 {
609 connection.getConnectionInternals(true).getSocket().setSoTimeout(
610 (int) getResponseTimeoutMillis(connection));
611 }
612 catch (Exception e)
613 {
614 debugException(e);
615 }
616
617
618 // Send the request to the server.
619 final long requestTime = System.nanoTime();
620 debugLDAPRequest(this);
621 connection.getConnectionStatistics().incrementNumBindRequests();
622 try
623 {
624 connection.sendMessage(message);
625 }
626 catch (final LDAPException le)
627 {
628 debugException(le);
629
630 if (allowRetry)
631 {
632 final BindResult bindResult = reconnectAndRetry(connection,
633 le.getResultCode());
634 if (bindResult != null)
635 {
636 return bindResult;
637 }
638 }
639 }
640
641 while (true)
642 {
643 final LDAPResponse response = connection.readResponse(messageID);
644 if (response instanceof IntermediateResponse)
645 {
646 final IntermediateResponseListener listener =
647 getIntermediateResponseListener();
648 if (listener != null)
649 {
650 listener.intermediateResponseReturned(
651 (IntermediateResponse) response);
652 }
653 }
654 else
655 {
656 return handleResponse(connection, response, requestTime, allowRetry);
657 }
658 }
659 }
660
661
662
663 /**
664 * Performs the necessary processing for handling a response.
665 *
666 * @param connection The connection used to read the response.
667 * @param response The response to be processed.
668 * @param requestTime The time the request was sent to the server.
669 * @param allowRetry Indicates whether the request may be re-tried on a
670 * re-established connection if the initial attempt fails
671 * in a way that indicates the connection is no longer
672 * valid and autoReconnect is true.
673 *
674 * @return The bind result.
675 *
676 * @throws LDAPException If a problem occurs.
677 */
678 private BindResult handleResponse(final LDAPConnection connection,
679 final LDAPResponse response,
680 final long requestTime,
681 final boolean allowRetry)
682 throws LDAPException
683 {
684 if (response == null)
685 {
686 final long waitTime = nanosToMillis(System.nanoTime() - requestTime);
687 throw new LDAPException(ResultCode.TIMEOUT,
688 ERR_SIMPLE_BIND_CLIENT_TIMEOUT.get(waitTime, messageID,
689 bindDN.stringValue(), connection.getHostPort()));
690 }
691
692 connection.getConnectionStatistics().incrementNumBindResponses(
693 System.nanoTime() - requestTime);
694 if (response instanceof ConnectionClosedResponse)
695 {
696 // The connection was closed while waiting for the response.
697 if (allowRetry)
698 {
699 final BindResult retryResult = reconnectAndRetry(connection,
700 ResultCode.SERVER_DOWN);
701 if (retryResult != null)
702 {
703 return retryResult;
704 }
705 }
706
707 final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response;
708 final String message = ccr.getMessage();
709 if (message == null)
710 {
711 throw new LDAPException(ccr.getResultCode(),
712 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE.get(
713 connection.getHostPort(), toString()));
714 }
715 else
716 {
717 throw new LDAPException(ccr.getResultCode(),
718 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE_WITH_MESSAGE.get(
719 connection.getHostPort(), toString(), message));
720 }
721 }
722
723 final BindResult bindResult = (BindResult) response;
724 if (allowRetry)
725 {
726 final BindResult retryResult = reconnectAndRetry(connection,
727 bindResult.getResultCode());
728 if (retryResult != null)
729 {
730 return retryResult;
731 }
732 }
733
734 return bindResult;
735 }
736
737
738
739 /**
740 * Attempts to re-establish the connection and retry processing this request
741 * on it.
742 *
743 * @param connection The connection to be re-established.
744 * @param resultCode The result code for the previous operation attempt.
745 *
746 * @return The result from re-trying the bind, or {@code null} if it could
747 * not be re-tried.
748 */
749 private BindResult reconnectAndRetry(final LDAPConnection connection,
750 final ResultCode resultCode)
751 {
752 try
753 {
754 // We will only want to retry for certain result codes that indicate a
755 // connection problem.
756 switch (resultCode.intValue())
757 {
758 case ResultCode.SERVER_DOWN_INT_VALUE:
759 case ResultCode.DECODING_ERROR_INT_VALUE:
760 case ResultCode.CONNECT_ERROR_INT_VALUE:
761 connection.reconnect();
762 return processSync(connection, false);
763 }
764 }
765 catch (final Exception e)
766 {
767 debugException(e);
768 }
769
770 return null;
771 }
772
773
774
775 /**
776 * {@inheritDoc}
777 */
778 @Override()
779 public SimpleBindRequest getRebindRequest(final String host, final int port)
780 {
781 return new SimpleBindRequest(bindDN, password, passwordProvider,
782 getControls());
783 }
784
785
786
787 /**
788 * {@inheritDoc}
789 */
790 @InternalUseOnly()
791 public void responseReceived(final LDAPResponse response)
792 throws LDAPException
793 {
794 try
795 {
796 responseQueue.put(response);
797 }
798 catch (Exception e)
799 {
800 debugException(e);
801 throw new LDAPException(ResultCode.LOCAL_ERROR,
802 ERR_EXCEPTION_HANDLING_RESPONSE.get(getExceptionMessage(e)), e);
803 }
804 }
805
806
807
808 /**
809 * {@inheritDoc}
810 */
811 @Override()
812 public String getBindType()
813 {
814 return "SIMPLE";
815 }
816
817
818
819 /**
820 * {@inheritDoc}
821 */
822 @Override()
823 public int getLastMessageID()
824 {
825 return messageID;
826 }
827
828
829
830 /**
831 * {@inheritDoc}
832 */
833 @Override()
834 public SimpleBindRequest duplicate()
835 {
836 return duplicate(getControls());
837 }
838
839
840
841 /**
842 * {@inheritDoc}
843 */
844 @Override()
845 public SimpleBindRequest duplicate(final Control[] controls)
846 {
847 final SimpleBindRequest bindRequest =
848 new SimpleBindRequest(bindDN, password, passwordProvider, controls);
849 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
850 return bindRequest;
851 }
852
853
854
855 /**
856 * {@inheritDoc}
857 */
858 @Override()
859 public void toString(final StringBuilder buffer)
860 {
861 buffer.append("SimpleBindRequest(dn='");
862 buffer.append(bindDN);
863 buffer.append('\'');
864
865 final Control[] controls = getControls();
866 if (controls.length > 0)
867 {
868 buffer.append(", controls={");
869 for (int i=0; i < controls.length; i++)
870 {
871 if (i > 0)
872 {
873 buffer.append(", ");
874 }
875
876 buffer.append(controls[i]);
877 }
878 buffer.append('}');
879 }
880
881 buffer.append(')');
882 }
883
884
885
886 /**
887 * {@inheritDoc}
888 */
889 public void toCode(final List<String> lineList, final String requestID,
890 final int indentSpaces, final boolean includeProcessing)
891 {
892 // Create the request variable.
893 final ArrayList<ToCodeArgHelper> constructorArgs =
894 new ArrayList<ToCodeArgHelper>(3);
895 constructorArgs.add(ToCodeArgHelper.createString(bindDN.stringValue(),
896 "Bind DN"));
897 constructorArgs.add(ToCodeArgHelper.createString("---redacted-password---",
898 "Bind Password"));
899
900 final Control[] controls = getControls();
901 if (controls.length > 0)
902 {
903 constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
904 "Bind Controls"));
905 }
906
907 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "SimpleBindRequest",
908 requestID + "Request", "new SimpleBindRequest", constructorArgs);
909
910
911 // Add lines for processing the request and obtaining the result.
912 if (includeProcessing)
913 {
914 // Generate a string with the appropriate indent.
915 final StringBuilder buffer = new StringBuilder();
916 for (int i=0; i < indentSpaces; i++)
917 {
918 buffer.append(' ');
919 }
920 final String indent = buffer.toString();
921
922 lineList.add("");
923 lineList.add(indent + "try");
924 lineList.add(indent + '{');
925 lineList.add(indent + " BindResult " + requestID +
926 "Result = connection.bind(" + requestID + "Request);");
927 lineList.add(indent + " // The bind was processed successfully.");
928 lineList.add(indent + '}');
929 lineList.add(indent + "catch (LDAPException e)");
930 lineList.add(indent + '{');
931 lineList.add(indent + " // The bind failed. Maybe the following will " +
932 "help explain why.");
933 lineList.add(indent + " // Note that the connection is now likely in " +
934 "an unauthenticated state.");
935 lineList.add(indent + " ResultCode resultCode = e.getResultCode();");
936 lineList.add(indent + " String message = e.getMessage();");
937 lineList.add(indent + " String matchedDN = e.getMatchedDN();");
938 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();");
939 lineList.add(indent + " Control[] responseControls = " +
940 "e.getResponseControls();");
941 lineList.add(indent + '}');
942 }
943 }
944 }