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