001/* 002 * Copyright 2007-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-2022 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2007-2022 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk; 037 038 039 040import java.io.Closeable; 041import java.net.InetAddress; 042import java.net.Socket; 043import java.util.Arrays; 044import java.util.Collection; 045import java.util.Collections; 046import java.util.HashMap; 047import java.util.List; 048import java.util.Map; 049import java.util.Timer; 050import java.util.concurrent.atomic.AtomicBoolean; 051import java.util.concurrent.atomic.AtomicLong; 052import java.util.concurrent.atomic.AtomicReference; 053import java.util.logging.Level; 054import javax.net.SocketFactory; 055import javax.net.ssl.SSLSession; 056import javax.net.ssl.SSLSocket; 057import javax.net.ssl.SSLSocketFactory; 058import javax.security.sasl.SaslClient; 059 060import com.unboundid.asn1.ASN1OctetString; 061import com.unboundid.ldap.protocol.AbandonRequestProtocolOp; 062import com.unboundid.ldap.protocol.LDAPMessage; 063import com.unboundid.ldap.protocol.LDAPResponse; 064import com.unboundid.ldap.protocol.UnbindRequestProtocolOp; 065import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest; 066import com.unboundid.ldap.sdk.schema.Schema; 067import com.unboundid.ldap.sdk.unboundidds.controls.RetainIdentityRequestControl; 068import com.unboundid.ldif.LDIFException; 069import com.unboundid.util.Debug; 070import com.unboundid.util.DebugType; 071import com.unboundid.util.NotNull; 072import com.unboundid.util.Nullable; 073import com.unboundid.util.StaticUtils; 074import com.unboundid.util.SynchronizedSocketFactory; 075import com.unboundid.util.SynchronizedSSLSocketFactory; 076import com.unboundid.util.ThreadSafety; 077import com.unboundid.util.ThreadSafetyLevel; 078import com.unboundid.util.Validator; 079import com.unboundid.util.WeakHashSet; 080import com.unboundid.util.ssl.SSLUtil; 081 082import static com.unboundid.ldap.sdk.LDAPMessages.*; 083 084 085 086/** 087 * This class provides a facility for interacting with an LDAPv3 directory 088 * server. It provides a means of establishing a connection to the server, 089 * sending requests, and reading responses. See 090 * <A HREF="http://www.ietf.org/rfc/rfc4511.txt">RFC 4511</A> for the LDAPv3 091 * protocol specification and more information about the types of operations 092 * defined in LDAP. 093 * <BR><BR> 094 * <H2>Creating, Establishing, and Authenticating Connections</H2> 095 * An LDAP connection can be established either at the time that the object is 096 * created or as a separate step. Similarly, authentication can be performed on 097 * the connection at the time it is created, at the time it is established, or 098 * as a separate process. For example: 099 * <BR><BR> 100 * <PRE> 101 * // Create a new, unestablished connection. Then connect and perform a 102 * // simple bind as separate operations. 103 * LDAPConnection c = new LDAPConnection(); 104 * c.connect(address, port); 105 * BindResult bindResult = c.bind(bindDN, password); 106 * 107 * // Create a new connection that is established at creation time, and then 108 * // authenticate separately using simple authentication. 109 * LDAPConnection c = new LDAPConnection(address, port); 110 * BindResult bindResult = c.bind(bindDN, password); 111 * 112 * // Create a new connection that is established and bound using simple 113 * // authentication all in one step. 114 * LDAPConnection c = new LDAPConnection(address, port, bindDN, password); 115 * </PRE> 116 * <BR><BR> 117 * When authentication is performed at the time that the connection is 118 * established, it is only possible to perform a simple bind and it is not 119 * possible to include controls in the bind request, nor is it possible to 120 * receive response controls if the bind was successful. Therefore, it is 121 * recommended that authentication be performed as a separate step if the server 122 * may return response controls even in the event of a successful authentication 123 * (e.g., a control that may indicate that the user's password will soon 124 * expire). See the {@link BindRequest} class for more information about 125 * authentication in the UnboundID LDAP SDK for Java. 126 * <BR><BR> 127 * By default, connections will use standard unencrypted network sockets. 128 * However, it may be desirable to create connections that use SSL/TLS to 129 * encrypt communication. This can be done by specifying a 130 * {@code SocketFactory} that should be used to create the socket to use to 131 * communicate with the directory server. The 132 * {@code SSLSocketFactory.getDefault} method or the 133 * {@code SSLContext.getSocketFactory} method may be used to obtain a socket 134 * factory for performing SSL communication. See the 135 * <A HREF= 136 * "http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html"> 137 * JSSE Reference Guide</A> for more information on using these classes. 138 * Alternately, you may use the {@link SSLUtil} class to simplify the process. 139 * <BR><BR> 140 * Whenever the connection is no longer needed, it may be terminated using the 141 * {@link LDAPConnection#close} method. 142 * <BR><BR> 143 * <H2>Processing LDAP Operations</H2> 144 * This class provides a number of methods for processing the different types of 145 * operations. The types of operations that can be processed include: 146 * <UL> 147 * <LI>Abandon -- This may be used to request that the server stop processing 148 * on an operation that has been invoked asynchronously.</LI> 149 * <LI>Add -- This may be used to add a new entry to the directory 150 * server. See the {@link AddRequest} class for more information about 151 * processing add operations.</LI> 152 * <LI>Bind -- This may be used to authenticate to the directory server. See 153 * the {@link BindRequest} class for more information about processing 154 * bind operations.</LI> 155 * <LI>Compare -- This may be used to determine whether a specified entry has 156 * a given attribute value. See the {@link CompareRequest} class for more 157 * information about processing compare operations.</LI> 158 * <LI>Delete -- This may be used to remove an entry from the directory 159 * server. See the {@link DeleteRequest} class for more information about 160 * processing delete operations.</LI> 161 * <LI>Extended -- This may be used to process an operation which is not 162 * part of the core LDAP protocol but is a custom extension supported by 163 * the directory server. See the {@link ExtendedRequest} class for more 164 * information about processing extended operations.</LI> 165 * <LI>Modify -- This may be used to alter an entry in the directory 166 * server. See the {@link ModifyRequest} class for more information about 167 * processing modify operations.</LI> 168 * <LI>Modify DN -- This may be used to rename an entry or subtree and/or move 169 * that entry or subtree below a new parent in the directory server. See 170 * the {@link ModifyDNRequest} class for more information about processing 171 * modify DN operations.</LI> 172 * <LI>Search -- This may be used to retrieve a set of entries in the server 173 * that match a given set of criteria. See the {@link SearchRequest} 174 * class for more information about processing search operations.</LI> 175 * </UL> 176 * <BR><BR> 177 * Most of the methods in this class used to process operations operate in a 178 * synchronous manner. In these cases, the SDK will send a request to the 179 * server and wait for a response to arrive before returning to the caller. In 180 * these cases, the value returned will include the contents of that response, 181 * including the result code, diagnostic message, matched DN, referral URLs, and 182 * any controls that may have been included. However, it also possible to 183 * process operations asynchronously, in which case the SDK will return control 184 * back to the caller after the request has been sent to the server but before 185 * the response has been received. In this case, the SDK will return an 186 * {@link AsyncRequestID} object which may be used to later abandon or cancel 187 * that operation if necessary, and will notify the client when the response 188 * arrives via a listener interface. 189 * <BR><BR> 190 * This class is mostly threadsafe. It is possible to process multiple 191 * concurrent operations over the same connection as long as the methods being 192 * invoked will not change the state of the connection in a way that might 193 * impact other operations in progress in unexpected ways. In particular, the 194 * following should not be attempted while any other operations may be in 195 * progress on this connection: 196 * <UL> 197 * <LI> 198 * Using one of the {@code connect} methods to re-establish the connection. 199 * </LI> 200 * <LI> 201 * Using one of the {@code close} methods to terminate the connection. 202 * </LI> 203 * <LI> 204 * Using one of the {@code bind} methods to attempt to authenticate the 205 * connection (unless you are certain that the bind will not impact the 206 * identity of the associated connection, for example by including the 207 * retain identity request control in the bind request if using the 208 * LDAP SDK in conjunction with a Ping Identity, UnboundID, or 209 * Nokia/Alcatel-Lucent 8661 Directory Server). 210 * </LI> 211 * <LI> 212 * Attempting to make a change to the way that the underlying communication 213 * is processed (e.g., by using the StartTLS extended operation to convert 214 * an insecure connection into a secure one). 215 * </LI> 216 * </UL> 217 */ 218@ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE) 219public final class LDAPConnection 220 implements FullLDAPInterface, LDAPConnectionInfo, ReferralConnector, 221 Closeable 222{ 223 /** 224 * The counter that will be used when assigning connection IDs to connections. 225 */ 226 @NotNull private static final AtomicLong NEXT_CONNECTION_ID = 227 new AtomicLong(0L); 228 229 230 231 /** 232 * The default socket factory that will be used if no alternate factory is 233 * provided. 234 */ 235 @NotNull private static final SocketFactory DEFAULT_SOCKET_FACTORY = 236 SocketFactory.getDefault(); 237 238 239 240 /** 241 * A set of weak references to schema objects that can be shared across 242 * connections if they are identical. 243 */ 244 @NotNull private static final WeakHashSet<Schema> SCHEMA_SET = 245 new WeakHashSet<>(); 246 247 248 249 // The connection pool with which this connection is associated, if 250 // applicable. 251 @Nullable private AbstractConnectionPool connectionPool; 252 253 // Indicates whether to perform a reconnect before the next write. 254 @NotNull private final AtomicBoolean needsReconnect; 255 256 // The disconnect information for this connection. 257 @NotNull private final AtomicReference<DisconnectInfo> disconnectInfo; 258 259 // The last successful bind request processed on this connection. 260 @Nullable private volatile BindRequest lastBindRequest; 261 262 // Indicates whether a request has been made to close this connection. 263 private volatile boolean closeRequested; 264 265 // Indicates whether an unbind request has been sent over this connection. 266 private volatile boolean unbindRequestSent; 267 268 // The extended request used to initiate StartTLS on this connection. 269 @Nullable private volatile ExtendedRequest startTLSRequest; 270 271 // The port of the server to which a connection should be re-established. 272 private int reconnectPort = -1; 273 274 // The connection internals used to actually perform the network 275 // communication. 276 @Nullable private volatile LDAPConnectionInternals connectionInternals; 277 278 // The set of connection options for this connection. 279 @NotNull private LDAPConnectionOptions connectionOptions; 280 281 // The set of statistics for this connection. 282 @NotNull private final LDAPConnectionStatistics connectionStatistics; 283 284 // The unique identifier assigned to this connection when it was created. It 285 // will not change over the life of the connection, even if the connection is 286 // closed and re-established (or even re-established to a different server). 287 private final long connectionID; 288 289 // The time of the last rebind attempt. 290 private long lastReconnectTime; 291 292 // The most recent time that an LDAP message was sent or received on this 293 // connection. 294 private volatile long lastCommunicationTime; 295 296 // A map in which arbitrary attachments may be stored or managed. 297 @Nullable private Map<String,Object> attachments; 298 299 // The referral connector that will be used to establish connections to remote 300 // servers when following a referral. 301 @Nullable private volatile ReferralConnector referralConnector; 302 303 // The cached schema read from the server. 304 @Nullable private volatile Schema cachedSchema; 305 306 // The server set that was used to create this connection, if available. 307 @Nullable private volatile ServerSet serverSet; 308 309 // The socket factory used for the last connection attempt. 310 @Nullable private SocketFactory lastUsedSocketFactory; 311 312 // The socket factory used to create sockets for subsequent connection 313 // attempts. 314 @NotNull private volatile SocketFactory socketFactory; 315 316 // A stack trace of the thread that last established this connection. 317 @Nullable private StackTraceElement[] connectStackTrace; 318 319 // The user-friendly name assigned to this connection. 320 @Nullable private String connectionName; 321 322 // The user-friendly name assigned to the connection pool with which this 323 // connection is associated. 324 @Nullable private String connectionPoolName; 325 326 // A string representation of the host and port to which the last connection 327 // attempt (whether successful or not, and whether it is still established) 328 // was made. 329 @Nullable private String hostPort; 330 331 // The address of the server to which a connection should be re-established. 332 @Nullable private String reconnectAddress; 333 334 // A timer that may be used to enforce timeouts for asynchronous operations. 335 @Nullable private Timer timer; 336 337 338 339 /** 340 * Creates a new LDAP connection using the default socket factory and default 341 * set of connection options. No actual network connection will be 342 * established. 343 */ 344 public LDAPConnection() 345 { 346 this(null, null); 347 } 348 349 350 351 /** 352 * Creates a new LDAP connection using the default socket factory and provided 353 * set of connection options. No actual network connection will be 354 * established. 355 * 356 * @param connectionOptions The set of connection options to use for this 357 * connection. If it is {@code null}, then a 358 * default set of options will be used. 359 */ 360 public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions) 361 { 362 this(null, connectionOptions); 363 } 364 365 366 367 /** 368 * Creates a new LDAP connection using the specified socket factory. No 369 * actual network connection will be established. 370 * 371 * @param socketFactory The socket factory to use when establishing 372 * connections. If it is {@code null}, then a default 373 * socket factory will be used. 374 */ 375 public LDAPConnection(@Nullable final SocketFactory socketFactory) 376 { 377 this(socketFactory, null); 378 } 379 380 381 382 /** 383 * Creates a new LDAP connection using the specified socket factory. No 384 * actual network connection will be established. 385 * 386 * @param socketFactory The socket factory to use when establishing 387 * connections. If it is {@code null}, then a 388 * default socket factory will be used. 389 * @param connectionOptions The set of connection options to use for this 390 * connection. If it is {@code null}, then a 391 * default set of options will be used. 392 */ 393 public LDAPConnection(@Nullable final SocketFactory socketFactory, 394 @Nullable final LDAPConnectionOptions connectionOptions) 395 { 396 needsReconnect = new AtomicBoolean(false); 397 disconnectInfo = new AtomicReference<>(); 398 lastCommunicationTime = -1L; 399 400 connectionID = NEXT_CONNECTION_ID.getAndIncrement(); 401 402 if (connectionOptions == null) 403 { 404 this.connectionOptions = new LDAPConnectionOptions(); 405 } 406 else 407 { 408 this.connectionOptions = connectionOptions.duplicate(); 409 } 410 411 final SocketFactory f; 412 if (socketFactory == null) 413 { 414 f = DEFAULT_SOCKET_FACTORY; 415 } 416 else 417 { 418 f = socketFactory; 419 } 420 421 if (this.connectionOptions.allowConcurrentSocketFactoryUse()) 422 { 423 this.socketFactory = f; 424 } 425 else 426 { 427 if (f instanceof SSLSocketFactory) 428 { 429 this.socketFactory = 430 new SynchronizedSSLSocketFactory((SSLSocketFactory) f); 431 } 432 else 433 { 434 this.socketFactory = new SynchronizedSocketFactory(f); 435 } 436 } 437 438 attachments = null; 439 connectionStatistics = new LDAPConnectionStatistics(); 440 connectionName = null; 441 connectionPoolName = null; 442 cachedSchema = null; 443 timer = null; 444 serverSet = null; 445 446 referralConnector = this.connectionOptions.getReferralConnector(); 447 if (referralConnector == null) 448 { 449 referralConnector = this; 450 } 451 } 452 453 454 455 /** 456 * Creates a new, unauthenticated LDAP connection that is established to the 457 * specified server. 458 * 459 * @param host The string representation of the address of the server to 460 * which the connection should be established. It may be a 461 * resolvable name or an IP address. It must not be 462 * {@code null}. 463 * @param port The port number of the server to which the connection should 464 * be established. It should be a value between 1 and 65535, 465 * inclusive. 466 * 467 * @throws LDAPException If a problem occurs while attempting to connect to 468 * the specified server. 469 */ 470 public LDAPConnection(@NotNull final String host, final int port) 471 throws LDAPException 472 { 473 this(null, null, host, port); 474 } 475 476 477 478 /** 479 * Creates a new, unauthenticated LDAP connection that is established to the 480 * specified server. 481 * 482 * @param connectionOptions The set of connection options to use for this 483 * connection. If it is {@code null}, then a 484 * default set of options will be used. 485 * @param host The string representation of the address of the 486 * server to which the connection should be 487 * established. It may be a resolvable name or an 488 * IP address. It must not be {@code null}. 489 * @param port The port number of the server to which the 490 * connection should be established. It should be 491 * a value between 1 and 65535, inclusive. 492 * 493 * @throws LDAPException If a problem occurs while attempting to connect to 494 * the specified server. 495 */ 496 public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions, 497 @NotNull final String host, final int port) 498 throws LDAPException 499 { 500 this(null, connectionOptions, host, port); 501 } 502 503 504 505 /** 506 * Creates a new, unauthenticated LDAP connection that is established to the 507 * specified server. 508 * 509 * @param socketFactory The socket factory to use when establishing 510 * connections. If it is {@code null}, then a default 511 * socket factory will be used. 512 * @param host The string representation of the address of the 513 * server to which the connection should be 514 * established. It may be a resolvable name or an IP 515 * address. It must not be {@code null}. 516 * @param port The port number of the server to which the 517 * connection should be established. It should be a 518 * value between 1 and 65535, inclusive. 519 * 520 * @throws LDAPException If a problem occurs while attempting to connect to 521 * the specified server. 522 */ 523 public LDAPConnection(@Nullable final SocketFactory socketFactory, 524 @NotNull final String host, final int port) 525 throws LDAPException 526 { 527 this(socketFactory, null, host, port); 528 } 529 530 531 532 /** 533 * Creates a new, unauthenticated LDAP connection that is established to the 534 * specified server. 535 * 536 * @param socketFactory The socket factory to use when establishing 537 * connections. If it is {@code null}, then a 538 * default socket factory will be used. 539 * @param connectionOptions The set of connection options to use for this 540 * connection. If it is {@code null}, then a 541 * default set of options will be used. 542 * @param host The string representation of the address of the 543 * server to which the connection should be 544 * established. It may be a resolvable name or an 545 * IP address. It must not be {@code null}. 546 * @param port The port number of the server to which the 547 * connection should be established. It should be 548 * a value between 1 and 65535, inclusive. 549 * 550 * @throws LDAPException If a problem occurs while attempting to connect to 551 * the specified server. 552 */ 553 public LDAPConnection(@Nullable final SocketFactory socketFactory, 554 @Nullable final LDAPConnectionOptions connectionOptions, 555 @NotNull final String host, final int port) 556 throws LDAPException 557 { 558 this(socketFactory, connectionOptions); 559 560 connect(host, port); 561 } 562 563 564 565 /** 566 * Creates a new LDAP connection that is established to the specified server 567 * and is authenticated as the specified user (via LDAP simple 568 * authentication). 569 * 570 * @param host The string representation of the address of the 571 * server to which the connection should be established. 572 * It may be a resolvable name or an IP address. It 573 * must not be {@code null}. 574 * @param port The port number of the server to which the 575 * connection should be established. It should be a 576 * value between 1 and 65535, inclusive. 577 * @param bindDN The DN to use to authenticate to the directory 578 * server. 579 * @param bindPassword The password to use to authenticate to the directory 580 * server. 581 * 582 * @throws LDAPException If a problem occurs while attempting to connect to 583 * the specified server. 584 */ 585 public LDAPConnection(@NotNull final String host, final int port, 586 @Nullable final String bindDN, 587 @Nullable final String bindPassword) 588 throws LDAPException 589 { 590 this(null, null, host, port, bindDN, bindPassword); 591 } 592 593 594 595 /** 596 * Creates a new LDAP connection that is established to the specified server 597 * and is authenticated as the specified user (via LDAP simple 598 * authentication). 599 * 600 * @param connectionOptions The set of connection options to use for this 601 * connection. If it is {@code null}, then a 602 * default set of options will be used. 603 * @param host The string representation of the address of the 604 * server to which the connection should be 605 * established. It may be a resolvable name or an 606 * IP address. It must not be {@code null}. 607 * @param port The port number of the server to which the 608 * connection should be established. It should be 609 * a value between 1 and 65535, inclusive. 610 * @param bindDN The DN to use to authenticate to the directory 611 * server. 612 * @param bindPassword The password to use to authenticate to the 613 * directory server. 614 * 615 * @throws LDAPException If a problem occurs while attempting to connect to 616 * the specified server. 617 */ 618 public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions, 619 @NotNull final String host, final int port, 620 @Nullable final String bindDN, 621 @Nullable final String bindPassword) 622 throws LDAPException 623 { 624 this(null, connectionOptions, host, port, bindDN, bindPassword); 625 } 626 627 628 629 /** 630 * Creates a new LDAP connection that is established to the specified server 631 * and is authenticated as the specified user (via LDAP simple 632 * authentication). 633 * 634 * @param socketFactory The socket factory to use when establishing 635 * connections. If it is {@code null}, then a default 636 * socket factory will be used. 637 * @param host The string representation of the address of the 638 * server to which the connection should be 639 * established. It may be a resolvable name or an IP 640 * address. It must not be {@code null}. 641 * @param port The port number of the server to which the 642 * connection should be established. It should be a 643 * value between 1 and 65535, inclusive. 644 * @param bindDN The DN to use to authenticate to the directory 645 * server. 646 * @param bindPassword The password to use to authenticate to the directory 647 * server. 648 * 649 * @throws LDAPException If a problem occurs while attempting to connect to 650 * the specified server. 651 */ 652 public LDAPConnection(@Nullable final SocketFactory socketFactory, 653 @NotNull final String host, 654 final int port, @Nullable final String bindDN, 655 @Nullable final String bindPassword) 656 throws LDAPException 657 { 658 this(socketFactory, null, host, port, bindDN, bindPassword); 659 } 660 661 662 663 /** 664 * Creates a new LDAP connection that is established to the specified server 665 * and is authenticated as the specified user (via LDAP simple 666 * authentication). 667 * 668 * @param socketFactory The socket factory to use when establishing 669 * connections. If it is {@code null}, then a 670 * default socket factory will be used. 671 * @param connectionOptions The set of connection options to use for this 672 * connection. If it is {@code null}, then a 673 * default set of options will be used. 674 * @param host The string representation of the address of the 675 * server to which the connection should be 676 * established. It may be a resolvable name or an 677 * IP address. It must not be {@code null}. 678 * @param port The port number of the server to which the 679 * connection should be established. It should be 680 * a value between 1 and 65535, inclusive. 681 * @param bindDN The DN to use to authenticate to the directory 682 * server. 683 * @param bindPassword The password to use to authenticate to the 684 * directory server. 685 * 686 * @throws LDAPException If a problem occurs while attempting to connect to 687 * the specified server. 688 */ 689 public LDAPConnection(@Nullable final SocketFactory socketFactory, 690 @Nullable final LDAPConnectionOptions connectionOptions, 691 @NotNull final String host, final int port, 692 @Nullable final String bindDN, 693 @Nullable final String bindPassword) 694 throws LDAPException 695 { 696 this(socketFactory, connectionOptions, host, port); 697 698 try 699 { 700 bind(new SimpleBindRequest(bindDN, bindPassword)); 701 } 702 catch (final LDAPException le) 703 { 704 Debug.debugException(le); 705 setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); 706 close(); 707 throw le; 708 } 709 } 710 711 712 713 /** 714 * Establishes an unauthenticated connection to the directory server using the 715 * provided information. If the connection is already established, then it 716 * will be closed and re-established. 717 * <BR><BR> 718 * If this method is invoked while any operations are in progress on this 719 * connection, then the directory server may or may not abort processing for 720 * those operations, depending on the type of operation and how far along the 721 * server has already gotten while processing that operation. It is 722 * recommended that all active operations be abandoned, canceled, or allowed 723 * to complete before attempting to re-establish an active connection. 724 * 725 * @param host The string representation of the address of the server to 726 * which the connection should be established. It may be a 727 * resolvable name or an IP address. It must not be 728 * {@code null}. 729 * @param port The port number of the server to which the connection should 730 * be established. It should be a value between 1 and 65535, 731 * inclusive. 732 * 733 * @throws LDAPException If an error occurs while attempting to establish 734 * the connection. 735 */ 736 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 737 public void connect(@NotNull final String host, final int port) 738 throws LDAPException 739 { 740 connect(host, port, connectionOptions.getConnectTimeoutMillis()); 741 } 742 743 744 745 /** 746 * Establishes an unauthenticated connection to the directory server using the 747 * provided information. If the connection is already established, then it 748 * will be closed and re-established. 749 * <BR><BR> 750 * If this method is invoked while any operations are in progress on this 751 * connection, then the directory server may or may not abort processing for 752 * those operations, depending on the type of operation and how far along the 753 * server has already gotten while processing that operation. It is 754 * recommended that all active operations be abandoned, canceled, or allowed 755 * to complete before attempting to re-establish an active connection. 756 * 757 * @param host The string representation of the address of the server to 758 * which the connection should be established. It may be a 759 * resolvable name or an IP address. It must not be 760 * {@code null}. 761 * @param port The port number of the server to which the connection 762 * should be established. It should be a value between 1 and 763 * 65535, inclusive. 764 * @param timeout The maximum length of time in milliseconds to wait for the 765 * connection to be established before failing, or zero to 766 * indicate that no timeout should be enforced (although if 767 * the attempt stalls long enough, then the underlying 768 * operating system may cause it to timeout). 769 * 770 * @throws LDAPException If an error occurs while attempting to establish 771 * the connection. 772 */ 773 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 774 public void connect(@NotNull final String host, final int port, 775 final int timeout) 776 throws LDAPException 777 { 778 final InetAddress inetAddress; 779 try 780 { 781 inetAddress = connectionOptions.getNameResolver().getByName(host); 782 } 783 catch (final Exception e) 784 { 785 Debug.debugException(e); 786 787 final LDAPException connectException = new LDAPException( 788 ResultCode.CONNECT_ERROR, 789 ERR_CONN_RESOLVE_ERROR.get(host, StaticUtils.getExceptionMessage(e)), 790 e); 791 792 final LDAPConnectionLogger logger = 793 connectionOptions.getConnectionLogger(); 794 if (logger != null) 795 { 796 logger.logConnectFailure(this, host, port, connectException); 797 } 798 799 throw connectException; 800 } 801 802 connect(host, inetAddress, port, timeout); 803 } 804 805 806 807 /** 808 * Establishes an unauthenticated connection to the directory server using the 809 * provided information. If the connection is already established, then it 810 * will be closed and re-established. 811 * <BR><BR> 812 * If this method is invoked while any operations are in progress on this 813 * connection, then the directory server may or may not abort processing for 814 * those operations, depending on the type of operation and how far along the 815 * server has already gotten while processing that operation. It is 816 * recommended that all active operations be abandoned, canceled, or allowed 817 * to complete before attempting to re-establish an active connection. 818 * 819 * @param inetAddress The inet address of the server to which the connection 820 * should be established. It must not be {@code null}. 821 * @param port The port number of the server to which the connection 822 * should be established. It should be a value between 1 823 * and 65535, inclusive. 824 * @param timeout The maximum length of time in milliseconds to wait for 825 * the connection to be established before failing, or 826 * zero to indicate that no timeout should be enforced 827 * (although if the attempt stalls long enough, then the 828 * underlying operating system may cause it to timeout). 829 * 830 * @throws LDAPException If an error occurs while attempting to establish 831 * the connection. 832 */ 833 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 834 public void connect(@NotNull final InetAddress inetAddress, final int port, 835 final int timeout) 836 throws LDAPException 837 { 838 connect(connectionOptions.getNameResolver().getHostName(inetAddress), 839 inetAddress, port, timeout); 840 } 841 842 843 844 /** 845 * Establishes an unauthenticated connection to the directory server using the 846 * provided information. If the connection is already established, then it 847 * will be closed and re-established. 848 * <BR><BR> 849 * If this method is invoked while any operations are in progress on this 850 * connection, then the directory server may or may not abort processing for 851 * those operations, depending on the type of operation and how far along the 852 * server has already gotten while processing that operation. It is 853 * recommended that all active operations be abandoned, canceled, or allowed 854 * to complete before attempting to re-establish an active connection. 855 * 856 * @param host The string representation of the address of the server 857 * to which the connection should be established. It may 858 * be a resolvable name or an IP address. It must not be 859 * {@code null}. 860 * @param inetAddress The inet address of the server to which the connection 861 * should be established. It must not be {@code null}. 862 * @param port The port number of the server to which the connection 863 * should be established. It should be a value between 1 864 * and 65535, inclusive. 865 * @param timeout The maximum length of time in milliseconds to wait for 866 * the connection to be established before failing, or 867 * zero to indicate that no timeout should be enforced 868 * (although if the attempt stalls long enough, then the 869 * underlying operating system may cause it to timeout). 870 * 871 * @throws LDAPException If an error occurs while attempting to establish 872 * the connection. 873 */ 874 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 875 public void connect(@NotNull final String host, 876 @NotNull final InetAddress inetAddress, 877 final int port, final int timeout) 878 throws LDAPException 879 { 880 Validator.ensureNotNull(host, inetAddress, port); 881 882 needsReconnect.set(false); 883 hostPort = host + ':' + port; 884 lastCommunicationTime = -1L; 885 startTLSRequest = null; 886 887 if (isConnected()) 888 { 889 setDisconnectInfo(DisconnectType.RECONNECT, null, null); 890 close(); 891 } 892 893 lastUsedSocketFactory = socketFactory; 894 reconnectAddress = host; 895 reconnectPort = port; 896 cachedSchema = null; 897 unbindRequestSent = false; 898 899 disconnectInfo.set(null); 900 901 try 902 { 903 connectionStatistics.incrementNumConnects(); 904 connectionInternals = new LDAPConnectionInternals(this, connectionOptions, 905 lastUsedSocketFactory, host, inetAddress, port, timeout); 906 connectionInternals.startConnectionReader(); 907 lastCommunicationTime = System.currentTimeMillis(); 908 } 909 catch (final Exception e) 910 { 911 Debug.debugException(e); 912 setDisconnectInfo(DisconnectType.LOCAL_ERROR, null, e); 913 connectionInternals = null; 914 915 final LDAPException connectException = new LDAPException( 916 ResultCode.CONNECT_ERROR, 917 ERR_CONN_CONNECT_ERROR.get(getHostPort(), 918 StaticUtils.getExceptionMessage(e)), 919 e); 920 921 final LDAPConnectionLogger logger = 922 connectionOptions.getConnectionLogger(); 923 if (logger != null) 924 { 925 logger.logConnectFailure(this, host, port, connectException); 926 } 927 928 throw connectException; 929 } 930 931 if (connectionOptions.useSchema()) 932 { 933 try 934 { 935 cachedSchema = getCachedSchema(this); 936 } 937 catch (final Exception e) 938 { 939 Debug.debugException(e); 940 } 941 } 942 } 943 944 945 946 /** 947 * Attempts to re-establish a connection to the server and re-authenticate if 948 * appropriate. 949 * 950 * @throws LDAPException If a problem occurs while attempting to re-connect 951 * or re-authenticate. 952 */ 953 public void reconnect() 954 throws LDAPException 955 { 956 needsReconnect.set(false); 957 if ((System.currentTimeMillis() - lastReconnectTime) < 1000L) 958 { 959 // If the last reconnect attempt was less than 1 second ago, then abort. 960 throw new LDAPException(ResultCode.SERVER_DOWN, 961 ERR_CONN_MULTIPLE_FAILURES.get()); 962 } 963 964 BindRequest bindRequest = null; 965 if (lastBindRequest != null) 966 { 967 bindRequest = lastBindRequest.getRebindRequest(reconnectAddress, 968 reconnectPort); 969 if (bindRequest == null) 970 { 971 throw new LDAPException(ResultCode.SERVER_DOWN, 972 ERR_CONN_CANNOT_REAUTHENTICATE.get(getHostPort())); 973 } 974 } 975 976 final ExtendedRequest startTLSExtendedRequest = startTLSRequest; 977 978 setDisconnectInfo(DisconnectType.RECONNECT, null, null); 979 terminate(null); 980 981 try 982 { 983 Thread.sleep(1000L); 984 } 985 catch (final Exception e) 986 { 987 Debug.debugException(e); 988 989 if (e instanceof InterruptedException) 990 { 991 Thread.currentThread().interrupt(); 992 throw new LDAPException(ResultCode.LOCAL_ERROR, 993 ERR_CONN_INTERRUPTED_DURING_RECONNECT.get(), e); 994 } 995 } 996 997 connect(reconnectAddress, reconnectPort); 998 999 if (startTLSExtendedRequest != null) 1000 { 1001 try 1002 { 1003 final ExtendedResult startTLSResult = 1004 processExtendedOperation(startTLSExtendedRequest); 1005 if (startTLSResult.getResultCode() != ResultCode.SUCCESS) 1006 { 1007 throw new LDAPException(startTLSResult); 1008 } 1009 } 1010 catch (final LDAPException le) 1011 { 1012 Debug.debugException(le); 1013 setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le); 1014 terminate(null); 1015 1016 throw le; 1017 } 1018 } 1019 1020 if (bindRequest != null) 1021 { 1022 try 1023 { 1024 bind(bindRequest); 1025 } 1026 catch (final LDAPException le) 1027 { 1028 Debug.debugException(le); 1029 setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); 1030 terminate(null); 1031 1032 throw le; 1033 } 1034 } 1035 1036 lastReconnectTime = System.currentTimeMillis(); 1037 } 1038 1039 1040 1041 /** 1042 * Sets a flag indicating that the connection should be re-established before 1043 * sending the next request. 1044 */ 1045 void setNeedsReconnect() 1046 { 1047 needsReconnect.set(true); 1048 } 1049 1050 1051 1052 /** 1053 * {@inheritDoc} 1054 */ 1055 @Override() 1056 public boolean isConnected() 1057 { 1058 final LDAPConnectionInternals internals = connectionInternals; 1059 1060 if (internals == null) 1061 { 1062 return false; 1063 } 1064 1065 if (! internals.isConnected()) 1066 { 1067 setClosed(); 1068 return false; 1069 } 1070 1071 return (! needsReconnect.get()); 1072 } 1073 1074 1075 1076 /** 1077 * Converts this clear-text connection to one that encrypts all communication 1078 * using Transport Layer Security. This method is intended for use as a 1079 * helper for processing in the course of the StartTLS extended operation and 1080 * should not be used for other purposes. 1081 * 1082 * @param sslSocketFactory The SSL socket factory to use to convert an 1083 * insecure connection into a secure connection. It 1084 * must not be {@code null}. 1085 * 1086 * @throws LDAPException If a problem occurs while converting this 1087 * connection to use TLS. 1088 */ 1089 void convertToTLS(@NotNull final SSLSocketFactory sslSocketFactory) 1090 throws LDAPException 1091 { 1092 final LDAPConnectionInternals internals = connectionInternals; 1093 if (internals == null) 1094 { 1095 throw new LDAPException(ResultCode.SERVER_DOWN, 1096 ERR_CONN_NOT_ESTABLISHED.get()); 1097 } 1098 else 1099 { 1100 internals.convertToTLS(sslSocketFactory); 1101 } 1102 } 1103 1104 1105 1106 /** 1107 * Applies a communication security layer that has been negotiated using the 1108 * provided {@code SaslClient} object to this connection. The connection must 1109 * be established and must not have any other security layer already in place. 1110 * 1111 * @param saslClient The SASL client that will be used to secure the 1112 * communication. It must not be {@code null}. 1113 * 1114 * @throws LDAPException If a problem occurs while attempting to convert the 1115 * connection to use SASL QoP. 1116 */ 1117 public void applySASLSecurityLayer(@NotNull final SaslClient saslClient) 1118 throws LDAPException 1119 { 1120 applySASLQoP(saslClient); 1121 } 1122 1123 1124 1125 /** 1126 * Applies a communication security layer that has been negotiated using the 1127 * provided {@code SaslClient} object to this connection. The connection must 1128 * be established and must not have any other security layer already in place. 1129 * 1130 * @param saslClient The SASL client that will be used to secure the 1131 * communication. It must not be {@code null}. 1132 * 1133 * @throws LDAPException If a problem occurs while attempting to convert the 1134 * connection to use SASL QoP. 1135 */ 1136 void applySASLQoP(@NotNull final SaslClient saslClient) 1137 throws LDAPException 1138 { 1139 final LDAPConnectionInternals internals = connectionInternals; 1140 if (internals == null) 1141 { 1142 throw new LDAPException(ResultCode.SERVER_DOWN, 1143 ERR_CONN_NOT_ESTABLISHED.get()); 1144 } 1145 else 1146 { 1147 internals.applySASLQoP(saslClient); 1148 } 1149 } 1150 1151 1152 1153 /** 1154 * Retrieves the set of connection options for this connection. Changes to 1155 * the object that is returned will directly impact this connection. 1156 * 1157 * @return The set of connection options for this connection. 1158 */ 1159 @NotNull() 1160 public LDAPConnectionOptions getConnectionOptions() 1161 { 1162 return connectionOptions; 1163 } 1164 1165 1166 1167 /** 1168 * Specifies the set of connection options for this connection. Some changes 1169 * may not take effect for operations already in progress, and some changes 1170 * may not take effect for a connection that is already established. 1171 * 1172 * @param connectionOptions The set of connection options for this 1173 * connection. It may be {@code null} if a default 1174 * set of options is to be used. 1175 */ 1176 public void setConnectionOptions( 1177 @Nullable final LDAPConnectionOptions connectionOptions) 1178 { 1179 if (connectionOptions == null) 1180 { 1181 this.connectionOptions = new LDAPConnectionOptions(); 1182 } 1183 else 1184 { 1185 final LDAPConnectionOptions newOptions = connectionOptions.duplicate(); 1186 if (Debug.debugEnabled(DebugType.LDAP) && 1187 newOptions.useSynchronousMode() && 1188 (! connectionOptions.useSynchronousMode()) && isConnected()) 1189 { 1190 Debug.debug(Level.WARNING, DebugType.LDAP, 1191 "A call to LDAPConnection.setConnectionOptions() with " + 1192 "useSynchronousMode=true will have no effect for this " + 1193 "connection because it is already established. The " + 1194 "useSynchronousMode option must be set before the " + 1195 "connection is established to have any effect."); 1196 } 1197 1198 this.connectionOptions = newOptions; 1199 } 1200 1201 final ReferralConnector rc = this.connectionOptions.getReferralConnector(); 1202 if (rc == null) 1203 { 1204 referralConnector = this; 1205 } 1206 else 1207 { 1208 referralConnector = rc; 1209 } 1210 } 1211 1212 1213 1214 /** 1215 * {@inheritDoc} 1216 */ 1217 @Override() 1218 @Nullable() 1219 public SocketFactory getLastUsedSocketFactory() 1220 { 1221 return lastUsedSocketFactory; 1222 } 1223 1224 1225 1226 /** 1227 * {@inheritDoc} 1228 */ 1229 @Override() 1230 @NotNull() 1231 public SocketFactory getSocketFactory() 1232 { 1233 return socketFactory; 1234 } 1235 1236 1237 1238 /** 1239 * Specifies the socket factory to use to create the socket for subsequent 1240 * connection attempts. This will not impact any established connection. 1241 * 1242 * @param socketFactory The socket factory to use to create the socket for 1243 * subsequent connection attempts. 1244 */ 1245 public void setSocketFactory(@Nullable final SocketFactory socketFactory) 1246 { 1247 if (socketFactory == null) 1248 { 1249 this.socketFactory = DEFAULT_SOCKET_FACTORY; 1250 } 1251 else 1252 { 1253 this.socketFactory = socketFactory; 1254 } 1255 } 1256 1257 1258 1259 /** 1260 * {@inheritDoc} 1261 */ 1262 @Override() 1263 @Nullable() 1264 public SSLSession getSSLSession() 1265 { 1266 final LDAPConnectionInternals internals = connectionInternals; 1267 1268 if (internals == null) 1269 { 1270 return null; 1271 } 1272 1273 final Socket socket = internals.getSocket(); 1274 if ((socket != null) && (socket instanceof SSLSocket)) 1275 { 1276 final SSLSocket sslSocket = (SSLSocket) socket; 1277 return sslSocket.getSession(); 1278 } 1279 else 1280 { 1281 return null; 1282 } 1283 } 1284 1285 1286 1287 /** 1288 * {@inheritDoc} 1289 */ 1290 @Override() 1291 public long getConnectionID() 1292 { 1293 return connectionID; 1294 } 1295 1296 1297 1298 /** 1299 * {@inheritDoc} 1300 */ 1301 @Override() 1302 @Nullable() 1303 public String getConnectionName() 1304 { 1305 return connectionName; 1306 } 1307 1308 1309 1310 /** 1311 * Specifies the user-friendly name that should be used for this connection. 1312 * This name may be used in debugging to help identify the purpose of this 1313 * connection. This will have no effect for connections which are part of a 1314 * connection pool. 1315 * 1316 * @param connectionName The user-friendly name that should be used for this 1317 * connection. 1318 */ 1319 public void setConnectionName(@Nullable final String connectionName) 1320 { 1321 if (connectionPool == null) 1322 { 1323 this.connectionName = connectionName; 1324 if (connectionInternals != null) 1325 { 1326 final LDAPConnectionReader reader = 1327 connectionInternals.getConnectionReader(); 1328 reader.updateThreadName(); 1329 } 1330 } 1331 } 1332 1333 1334 1335 /** 1336 * Retrieves the connection pool with which this connection is associated, if 1337 * any. 1338 * 1339 * @return The connection pool with which this connection is associated, or 1340 * {@code null} if it is not associated with any connection pool. 1341 */ 1342 @Nullable() 1343 public AbstractConnectionPool getConnectionPool() 1344 { 1345 return connectionPool; 1346 } 1347 1348 1349 1350 /** 1351 * {@inheritDoc} 1352 */ 1353 @Override() 1354 @Nullable() 1355 public String getConnectionPoolName() 1356 { 1357 return connectionPoolName; 1358 } 1359 1360 1361 1362 /** 1363 * Specifies the user-friendly name that should be used for the connection 1364 * pool with which this connection is associated. 1365 * 1366 * @param connectionPoolName The user-friendly name that should be used for 1367 * the connection pool with which this connection 1368 * is associated. 1369 */ 1370 void setConnectionPoolName(@Nullable final String connectionPoolName) 1371 { 1372 this.connectionPoolName = connectionPoolName; 1373 if (connectionInternals != null) 1374 { 1375 final LDAPConnectionReader reader = 1376 connectionInternals.getConnectionReader(); 1377 reader.updateThreadName(); 1378 } 1379 } 1380 1381 1382 1383 /** 1384 * Retrieves the server set that was used to create this connection. 1385 * 1386 * @return The server set that was used to create this connection, or 1387 * {@code null} if it is not associated with any server set. 1388 */ 1389 @Nullable() 1390 ServerSet getServerSet() 1391 { 1392 return serverSet; 1393 } 1394 1395 1396 1397 /** 1398 * Specifies the server set that was used to create this connection. 1399 * 1400 * @param serverSet The server set that was used to create this connection, 1401 * or {@code null} if it was not created by a server set. 1402 */ 1403 void setServerSet(@Nullable final ServerSet serverSet) 1404 { 1405 this.serverSet = serverSet; 1406 } 1407 1408 1409 1410 /** 1411 * {@inheritDoc} 1412 */ 1413 @Override() 1414 @NotNull() 1415 public String getHostPort() 1416 { 1417 if (hostPort == null) 1418 { 1419 return ""; 1420 } 1421 else 1422 { 1423 return hostPort; 1424 } 1425 } 1426 1427 1428 1429 /** 1430 * {@inheritDoc} 1431 */ 1432 @Override() 1433 @Nullable() 1434 public String getConnectedAddress() 1435 { 1436 final LDAPConnectionInternals internals = connectionInternals; 1437 if (internals == null) 1438 { 1439 return null; 1440 } 1441 else 1442 { 1443 return internals.getHost(); 1444 } 1445 } 1446 1447 1448 1449 /** 1450 * {@inheritDoc} 1451 */ 1452 @Override() 1453 @Nullable() 1454 public String getConnectedIPAddress() 1455 { 1456 final LDAPConnectionInternals internals = connectionInternals; 1457 if (internals == null) 1458 { 1459 return null; 1460 } 1461 else 1462 { 1463 return internals.getInetAddress().getHostAddress(); 1464 } 1465 } 1466 1467 1468 1469 /** 1470 * {@inheritDoc} 1471 */ 1472 @Override() 1473 @Nullable() 1474 public InetAddress getConnectedInetAddress() 1475 { 1476 final LDAPConnectionInternals internals = connectionInternals; 1477 if (internals == null) 1478 { 1479 return null; 1480 } 1481 else 1482 { 1483 return internals.getInetAddress(); 1484 } 1485 } 1486 1487 1488 1489 /** 1490 * {@inheritDoc} 1491 */ 1492 @Override() 1493 public int getConnectedPort() 1494 { 1495 final LDAPConnectionInternals internals = connectionInternals; 1496 if (internals == null) 1497 { 1498 return -1; 1499 } 1500 else 1501 { 1502 return internals.getPort(); 1503 } 1504 } 1505 1506 1507 1508 /** 1509 * {@inheritDoc} 1510 */ 1511 @Override() 1512 @Nullable() 1513 public StackTraceElement[] getConnectStackTrace() 1514 { 1515 return connectStackTrace; 1516 } 1517 1518 1519 1520 /** 1521 * Provides a stack trace for the thread that last attempted to establish this 1522 * connection. 1523 * 1524 * @param connectStackTrace A stack trace for the thread that last attempted 1525 * to establish this connection. 1526 */ 1527 void setConnectStackTrace( 1528 @Nullable final StackTraceElement[] connectStackTrace) 1529 { 1530 this.connectStackTrace = connectStackTrace; 1531 } 1532 1533 1534 1535 /** 1536 * Unbinds from the server and closes the connection. 1537 * <BR><BR> 1538 * If this method is invoked while any operations are in progress on this 1539 * connection, then the directory server may or may not abort processing for 1540 * those operations, depending on the type of operation and how far along the 1541 * server has already gotten while processing that operation. It is 1542 * recommended that all active operations be abandoned, canceled, or allowed 1543 * to complete before attempting to close an active connection. 1544 */ 1545 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 1546 @Override() 1547 public void close() 1548 { 1549 close(StaticUtils.NO_CONTROLS); 1550 } 1551 1552 1553 1554 /** 1555 * Unbinds from the server and closes the connection, optionally including 1556 * the provided set of controls in the unbind request. 1557 * <BR><BR> 1558 * If this method is invoked while any operations are in progress on this 1559 * connection, then the directory server may or may not abort processing for 1560 * those operations, depending on the type of operation and how far along the 1561 * server has already gotten while processing that operation. It is 1562 * recommended that all active operations be abandoned, canceled, or allowed 1563 * to complete before attempting to close an active connection. 1564 * 1565 * @param controls The set of controls to include in the unbind request. It 1566 * may be {@code null} if there are not to be any controls 1567 * sent in the unbind request. 1568 */ 1569 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 1570 public void close(@Nullable final Control[] controls) 1571 { 1572 closeRequested = true; 1573 setDisconnectInfo(DisconnectType.UNBIND, null, null); 1574 1575 if (connectionPool == null) 1576 { 1577 terminate(controls); 1578 } 1579 else 1580 { 1581 connectionPool.releaseDefunctConnection(this); 1582 } 1583 } 1584 1585 1586 1587 /** 1588 * Closes the connection without first sending an unbind request. Using this 1589 * method is generally discouraged, although it may be useful under certain 1590 * circumstances, like when it is known or suspected that an attempt to write 1591 * data over the connection will fail or block for some period of time. 1592 * <BR><BR> 1593 * If this method is invoked while any operations are in progress on this 1594 * connection, then the directory server may or may not abort processing for 1595 * those operations, depending on the type of operation and how far along the 1596 * server has already gotten while processing that operation. It is 1597 * recommended that all active operations be abandoned, canceled, or allowed 1598 * to complete before attempting to close an active connection. 1599 */ 1600 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 1601 public void closeWithoutUnbind() 1602 { 1603 closeRequested = true; 1604 setDisconnectInfo(DisconnectType.CLOSED_WITHOUT_UNBIND, null, null); 1605 1606 if (connectionPool == null) 1607 { 1608 setClosed(); 1609 } 1610 else 1611 { 1612 connectionPool.releaseDefunctConnection(this); 1613 } 1614 } 1615 1616 1617 1618 /** 1619 * Unbinds from the server and closes the connection, optionally including the 1620 * provided set of controls in the unbind request. This method is only 1621 * intended for internal use, since it does not make any attempt to release 1622 * the connection back to its associated connection pool, if there is one. 1623 * 1624 * @param controls The set of controls to include in the unbind request. It 1625 * may be {@code null} if there are not to be any controls 1626 * sent in the unbind request. 1627 */ 1628 void terminate(@Nullable final Control[] controls) 1629 { 1630 if (isConnected() && (! unbindRequestSent)) 1631 { 1632 try 1633 { 1634 unbindRequestSent = true; 1635 setDisconnectInfo(DisconnectType.UNBIND, null, null); 1636 1637 final int messageID = nextMessageID(); 1638 if (Debug.debugEnabled(DebugType.LDAP)) 1639 { 1640 Debug.debugLDAPRequest(Level.INFO, 1641 createUnbindRequestString(controls), messageID, this); 1642 } 1643 1644 final LDAPConnectionLogger logger = 1645 connectionOptions.getConnectionLogger(); 1646 if (logger != null) 1647 { 1648 final List<Control> controlList; 1649 if (controls == null) 1650 { 1651 controlList = Collections.emptyList(); 1652 } 1653 else 1654 { 1655 controlList = Arrays.asList(controls); 1656 } 1657 1658 logger.logUnbindRequest(this, messageID, controlList); 1659 } 1660 1661 connectionStatistics.incrementNumUnbindRequests(); 1662 sendMessage( 1663 new LDAPMessage(messageID, new UnbindRequestProtocolOp(), 1664 controls), 1665 connectionOptions.getResponseTimeoutMillis(OperationType.UNBIND)); 1666 } 1667 catch (final Exception e) 1668 { 1669 Debug.debugException(e); 1670 } 1671 } 1672 1673 setClosed(); 1674 } 1675 1676 1677 1678 /** 1679 * Creates a string representation of an unbind request with the provided 1680 * information. 1681 * 1682 * @param controls The set of controls included in the unbind request, if 1683 * any. 1684 * 1685 * @return The string representation of the unbind request. 1686 */ 1687 @NotNull() 1688 private static String createUnbindRequestString( 1689 @Nullable final Control... controls) 1690 { 1691 final StringBuilder buffer = new StringBuilder(); 1692 buffer.append("UnbindRequest("); 1693 1694 if ((controls != null) && (controls.length > 0)) 1695 { 1696 buffer.append("controls={"); 1697 for (int i=0; i < controls.length; i++) 1698 { 1699 if (i > 0) 1700 { 1701 buffer.append(", "); 1702 } 1703 1704 buffer.append(controls[i]); 1705 } 1706 buffer.append('}'); 1707 } 1708 1709 buffer.append(')'); 1710 return buffer.toString(); 1711 } 1712 1713 1714 1715 /** 1716 * Indicates whether a request has been made to close this connection. 1717 * 1718 * @return {@code true} if a request has been made to close this connection, 1719 * or {@code false} if not. 1720 */ 1721 boolean closeRequested() 1722 { 1723 return closeRequested; 1724 } 1725 1726 1727 1728 /** 1729 * Indicates whether an unbind request has been sent over this connection. 1730 * 1731 * @return {@code true} if an unbind request has been sent over this 1732 * connection, or {@code false} if not. 1733 */ 1734 boolean unbindRequestSent() 1735 { 1736 return unbindRequestSent; 1737 } 1738 1739 1740 1741 /** 1742 * Indicates that this LDAP connection is part of the specified 1743 * connection pool. 1744 * 1745 * @param connectionPool The connection pool with which this LDAP connection 1746 * is associated. 1747 */ 1748 void setConnectionPool(@Nullable final AbstractConnectionPool connectionPool) 1749 { 1750 this.connectionPool = connectionPool; 1751 } 1752 1753 1754 1755 /** 1756 * Retrieves the directory server root DSE, which provides information about 1757 * the directory server, including the capabilities that it provides and the 1758 * type of data that it is configured to handle. 1759 * 1760 * @return The directory server root DSE, or {@code null} if it is not 1761 * available. 1762 * 1763 * @throws LDAPException If a problem occurs while attempting to retrieve 1764 * the server root DSE. 1765 */ 1766 @Override() 1767 @Nullable() 1768 public RootDSE getRootDSE() 1769 throws LDAPException 1770 { 1771 return RootDSE.getRootDSE(this); 1772 } 1773 1774 1775 1776 /** 1777 * Retrieves the directory server schema definitions, using the subschema 1778 * subentry DN contained in the server's root DSE. For directory servers 1779 * containing a single schema, this should be sufficient for all purposes. 1780 * For servers with multiple schemas, it may be necessary to specify the DN 1781 * of the target entry for which to obtain the associated schema. 1782 * 1783 * @return The directory server schema definitions, or {@code null} if the 1784 * schema information could not be retrieved (e.g, the client does 1785 * not have permission to read the server schema). 1786 * 1787 * @throws LDAPException If a problem occurs while attempting to retrieve 1788 * the server schema. 1789 */ 1790 @Override() 1791 @Nullable() 1792 public Schema getSchema() 1793 throws LDAPException 1794 { 1795 return Schema.getSchema(this, ""); 1796 } 1797 1798 1799 1800 /** 1801 * Retrieves the directory server schema definitions that govern the specified 1802 * entry. The subschemaSubentry attribute will be retrieved from the target 1803 * entry, and then the appropriate schema definitions will be loaded from the 1804 * entry referenced by that attribute. This may be necessary to ensure 1805 * correct behavior in servers that support multiple schemas. 1806 * 1807 * @param entryDN The DN of the entry for which to retrieve the associated 1808 * schema definitions. It may be {@code null} or an empty 1809 * string if the subschemaSubentry attribute should be 1810 * retrieved from the server's root DSE. 1811 * 1812 * @return The directory server schema definitions, or {@code null} if the 1813 * schema information could not be retrieved (e.g, the client does 1814 * not have permission to read the server schema). 1815 * 1816 * @throws LDAPException If a problem occurs while attempting to retrieve 1817 * the server schema. 1818 */ 1819 @Override() 1820 @Nullable() 1821 public Schema getSchema(@Nullable final String entryDN) 1822 throws LDAPException 1823 { 1824 return Schema.getSchema(this, entryDN); 1825 } 1826 1827 1828 1829 /** 1830 * Retrieves the entry with the specified DN. All user attributes will be 1831 * requested in the entry to return. 1832 * 1833 * @param dn The DN of the entry to retrieve. It must not be {@code null}. 1834 * 1835 * @return The requested entry, or {@code null} if the target entry does not 1836 * exist or no entry was returned (e.g., if the authenticated user 1837 * does not have permission to read the target entry). 1838 * 1839 * @throws LDAPException If a problem occurs while sending the request or 1840 * reading the response. 1841 */ 1842 @Override() 1843 @Nullable() 1844 public SearchResultEntry getEntry(@NotNull final String dn) 1845 throws LDAPException 1846 { 1847 return getEntry(dn, (String[]) null); 1848 } 1849 1850 1851 1852 /** 1853 * Retrieves the entry with the specified DN. 1854 * 1855 * @param dn The DN of the entry to retrieve. It must not be 1856 * {@code null}. 1857 * @param attributes The set of attributes to request for the target entry. 1858 * If it is {@code null}, then all user attributes will be 1859 * requested. 1860 * 1861 * @return The requested entry, or {@code null} if the target entry does not 1862 * exist or no entry was returned (e.g., if the authenticated user 1863 * does not have permission to read the target entry). 1864 * 1865 * @throws LDAPException If a problem occurs while sending the request or 1866 * reading the response. 1867 */ 1868 @Override() 1869 @Nullable() 1870 public SearchResultEntry getEntry(@NotNull final String dn, 1871 @Nullable final String... attributes) 1872 throws LDAPException 1873 { 1874 final Filter filter = Filter.createPresenceFilter("objectClass"); 1875 1876 final SearchResult result; 1877 try 1878 { 1879 final SearchRequest searchRequest = 1880 new SearchRequest(dn, SearchScope.BASE, DereferencePolicy.NEVER, 1, 1881 0, false, filter, attributes); 1882 result = search(searchRequest); 1883 } 1884 catch (final LDAPException le) 1885 { 1886 if (le.getResultCode().equals(ResultCode.NO_SUCH_OBJECT)) 1887 { 1888 return null; 1889 } 1890 else 1891 { 1892 throw le; 1893 } 1894 } 1895 1896 if (! result.getResultCode().equals(ResultCode.SUCCESS)) 1897 { 1898 throw new LDAPException(result); 1899 } 1900 1901 final List<SearchResultEntry> entryList = result.getSearchEntries(); 1902 if (entryList.isEmpty()) 1903 { 1904 return null; 1905 } 1906 else 1907 { 1908 return entryList.get(0); 1909 } 1910 } 1911 1912 1913 1914 /** 1915 * Processes an abandon request with the provided information. 1916 * 1917 * @param requestID The async request ID for the request to abandon. 1918 * 1919 * @throws LDAPException If a problem occurs while sending the request to 1920 * the server. 1921 */ 1922 public void abandon(@NotNull final AsyncRequestID requestID) 1923 throws LDAPException 1924 { 1925 abandon(requestID, null); 1926 } 1927 1928 1929 1930 /** 1931 * Processes an abandon request with the provided information. 1932 * 1933 * @param requestID The async request ID for the request to abandon. 1934 * @param controls The set of controls to include in the abandon request. 1935 * It may be {@code null} or empty if there are no 1936 * controls. 1937 * 1938 * @throws LDAPException If a problem occurs while sending the request to 1939 * the server. 1940 */ 1941 public void abandon(@NotNull final AsyncRequestID requestID, 1942 @Nullable final Control[] controls) 1943 throws LDAPException 1944 { 1945 if (synchronousMode()) 1946 { 1947 throw new LDAPException(ResultCode.NOT_SUPPORTED, 1948 ERR_ABANDON_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 1949 } 1950 1951 final int messageID = requestID.getMessageID(); 1952 try 1953 { 1954 connectionInternals.getConnectionReader().deregisterResponseAcceptor( 1955 messageID); 1956 } 1957 catch (final Exception e) 1958 { 1959 Debug.debugException(e); 1960 } 1961 1962 connectionStatistics.incrementNumAbandonRequests(); 1963 final int abandonMessageID = nextMessageID(); 1964 if (Debug.debugEnabled(DebugType.LDAP)) 1965 { 1966 Debug.debugLDAPRequest(Level.INFO, 1967 createAbandonRequestString(messageID, controls), abandonMessageID, 1968 this); 1969 } 1970 1971 final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); 1972 if (logger != null) 1973 { 1974 final List<Control> controlList; 1975 if (controls == null) 1976 { 1977 controlList = Collections.emptyList(); 1978 } 1979 else 1980 { 1981 controlList = Arrays.asList(controls); 1982 } 1983 1984 logger.logAbandonRequest(this, abandonMessageID, messageID, controlList); 1985 } 1986 1987 sendMessage( 1988 new LDAPMessage(abandonMessageID, 1989 new AbandonRequestProtocolOp(messageID), controls), 1990 connectionOptions.getResponseTimeoutMillis(OperationType.ABANDON)); 1991 } 1992 1993 1994 1995 /** 1996 * Sends an abandon request with the provided information. 1997 * 1998 * @param messageID The message ID for the request to abandon. 1999 * @param controls The set of controls to include in the abandon request. 2000 * It may be {@code null} or empty if there are no 2001 * controls. 2002 * 2003 * @throws LDAPException If a problem occurs while sending the request to 2004 * the server. 2005 */ 2006 void abandon(final int messageID, @Nullable final Control... controls) 2007 throws LDAPException 2008 { 2009 try 2010 { 2011 connectionInternals.getConnectionReader().deregisterResponseAcceptor( 2012 messageID); 2013 } 2014 catch (final Exception e) 2015 { 2016 Debug.debugException(e); 2017 } 2018 2019 connectionStatistics.incrementNumAbandonRequests(); 2020 final int abandonMessageID = nextMessageID(); 2021 if (Debug.debugEnabled(DebugType.LDAP)) 2022 { 2023 Debug.debugLDAPRequest(Level.INFO, 2024 createAbandonRequestString(messageID, controls), abandonMessageID, 2025 this); 2026 } 2027 2028 final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); 2029 if (logger != null) 2030 { 2031 final List<Control> controlList; 2032 if (controls == null) 2033 { 2034 controlList = Collections.emptyList(); 2035 } 2036 else 2037 { 2038 controlList = Arrays.asList(controls); 2039 } 2040 2041 logger.logAbandonRequest(this, abandonMessageID, messageID, controlList); 2042 } 2043 2044 sendMessage( 2045 new LDAPMessage(abandonMessageID, 2046 new AbandonRequestProtocolOp(messageID), controls), 2047 connectionOptions.getResponseTimeoutMillis(OperationType.ABANDON)); 2048 } 2049 2050 2051 2052 /** 2053 * Creates a string representation of an abandon request with the provided 2054 * information. 2055 * 2056 * @param idToAbandon The message ID of the operation to abandon. 2057 * @param controls The set of controls included in the abandon request, 2058 * if any. 2059 * 2060 * @return The string representation of the abandon request. 2061 */ 2062 @NotNull() 2063 private static String createAbandonRequestString(final int idToAbandon, 2064 @Nullable final Control... controls) 2065 { 2066 final StringBuilder buffer = new StringBuilder(); 2067 buffer.append("AbandonRequest(idToAbandon="); 2068 buffer.append(idToAbandon); 2069 2070 if ((controls != null) && (controls.length > 0)) 2071 { 2072 buffer.append(", controls={"); 2073 for (int i=0; i < controls.length; i++) 2074 { 2075 if (i > 0) 2076 { 2077 buffer.append(", "); 2078 } 2079 2080 buffer.append(controls[i]); 2081 } 2082 buffer.append('}'); 2083 } 2084 2085 buffer.append(')'); 2086 return buffer.toString(); 2087 } 2088 2089 2090 2091 /** 2092 * Processes an add operation with the provided information. 2093 * 2094 * @param dn The DN of the entry to add. It must not be 2095 * {@code null}. 2096 * @param attributes The set of attributes to include in the entry to add. 2097 * It must not be {@code null}. 2098 * 2099 * @return The result of processing the add operation. 2100 * 2101 * @throws LDAPException If the server rejects the add request, or if a 2102 * problem is encountered while sending the request or 2103 * reading the response. 2104 */ 2105 @Override() 2106 @NotNull() 2107 public LDAPResult add(@NotNull final String dn, 2108 @NotNull final Attribute... attributes) 2109 throws LDAPException 2110 { 2111 Validator.ensureNotNull(dn, attributes); 2112 2113 return add(new AddRequest(dn, attributes)); 2114 } 2115 2116 2117 2118 /** 2119 * Processes an add operation with the provided information. 2120 * 2121 * @param dn The DN of the entry to add. It must not be 2122 * {@code null}. 2123 * @param attributes The set of attributes to include in the entry to add. 2124 * It must not be {@code null}. 2125 * 2126 * @return The result of processing the add operation. 2127 * 2128 * @throws LDAPException If the server rejects the add request, or if a 2129 * problem is encountered while sending the request or 2130 * reading the response. 2131 */ 2132 @Override() 2133 @NotNull() 2134 public LDAPResult add(@NotNull final String dn, 2135 @NotNull final Collection<Attribute> attributes) 2136 throws LDAPException 2137 { 2138 Validator.ensureNotNull(dn, attributes); 2139 2140 return add(new AddRequest(dn, attributes)); 2141 } 2142 2143 2144 2145 /** 2146 * Processes an add operation with the provided information. 2147 * 2148 * @param entry The entry to add. It must not be {@code null}. 2149 * 2150 * @return The result of processing the add operation. 2151 * 2152 * @throws LDAPException If the server rejects the add request, or if a 2153 * problem is encountered while sending the request or 2154 * reading the response. 2155 */ 2156 @Override() 2157 @NotNull() 2158 public LDAPResult add(@NotNull final Entry entry) 2159 throws LDAPException 2160 { 2161 Validator.ensureNotNull(entry); 2162 2163 return add(new AddRequest(entry)); 2164 } 2165 2166 2167 2168 /** 2169 * Processes an add operation with the provided information. 2170 * 2171 * @param ldifLines The lines that comprise an LDIF representation of the 2172 * entry to add. It must not be empty or {@code null}. 2173 * 2174 * @return The result of processing the add operation. 2175 * 2176 * @throws LDIFException If the provided entry lines cannot be decoded as an 2177 * entry in LDIF form. 2178 * 2179 * @throws LDAPException If the server rejects the add request, or if a 2180 * problem is encountered while sending the request or 2181 * reading the response. 2182 */ 2183 @Override() 2184 @NotNull() 2185 public LDAPResult add(@NotNull final String... ldifLines) 2186 throws LDIFException, LDAPException 2187 { 2188 return add(new AddRequest(ldifLines)); 2189 } 2190 2191 2192 2193 /** 2194 * Processes the provided add request. 2195 * 2196 * @param addRequest The add request to be processed. It must not be 2197 * {@code null}. 2198 * 2199 * @return The result of processing the add operation. 2200 * 2201 * @throws LDAPException If the server rejects the add request, or if a 2202 * problem is encountered while sending the request or 2203 * reading the response. 2204 */ 2205 @Override() 2206 @NotNull() 2207 public LDAPResult add(@NotNull final AddRequest addRequest) 2208 throws LDAPException 2209 { 2210 Validator.ensureNotNull(addRequest); 2211 2212 final LDAPResult ldapResult = addRequest.process(this, 1); 2213 2214 switch (ldapResult.getResultCode().intValue()) 2215 { 2216 case ResultCode.SUCCESS_INT_VALUE: 2217 case ResultCode.NO_OPERATION_INT_VALUE: 2218 return ldapResult; 2219 2220 default: 2221 throw new LDAPException(ldapResult); 2222 } 2223 } 2224 2225 2226 2227 /** 2228 * Processes the provided add request. 2229 * 2230 * @param addRequest The add request to be processed. It must not be 2231 * {@code null}. 2232 * 2233 * @return The result of processing the add operation. 2234 * 2235 * @throws LDAPException If the server rejects the add request, or if a 2236 * problem is encountered while sending the request or 2237 * reading the response. 2238 */ 2239 @Override() 2240 @NotNull 2241 public LDAPResult add(@NotNull final ReadOnlyAddRequest addRequest) 2242 throws LDAPException 2243 { 2244 return add((AddRequest) addRequest); 2245 } 2246 2247 2248 2249 /** 2250 * Processes the provided add request as an asynchronous operation. 2251 * 2252 * @param addRequest The add request to be processed. It must not be 2253 * {@code null}. 2254 * @param resultListener The async result listener to use to handle the 2255 * response for the add operation. It may be 2256 * {@code null} if the result is going to be obtained 2257 * from the returned {@code AsyncRequestID} object via 2258 * the {@code Future} API. 2259 * 2260 * @return An async request ID that may be used to reference the operation. 2261 * 2262 * @throws LDAPException If a problem occurs while sending the request. 2263 */ 2264 @NotNull() 2265 public AsyncRequestID asyncAdd(@NotNull final AddRequest addRequest, 2266 @Nullable final AsyncResultListener resultListener) 2267 throws LDAPException 2268 { 2269 Validator.ensureNotNull(addRequest); 2270 2271 if (synchronousMode()) 2272 { 2273 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2274 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2275 } 2276 2277 final AsyncResultListener listener; 2278 if (resultListener == null) 2279 { 2280 listener = DiscardAsyncListener.getInstance(); 2281 } 2282 else 2283 { 2284 listener = resultListener; 2285 } 2286 2287 return addRequest.processAsync(this, listener); 2288 } 2289 2290 2291 2292 /** 2293 * Processes the provided add request as an asynchronous operation. 2294 * 2295 * @param addRequest The add request to be processed. It must not be 2296 * {@code null}. 2297 * @param resultListener The async result listener to use to handle the 2298 * response for the add operation. It may be 2299 * {@code null} if the result is going to be obtained 2300 * from the returned {@code AsyncRequestID} object via 2301 * the {@code Future} API. 2302 * 2303 * @return An async request ID that may be used to reference the operation. 2304 * 2305 * @throws LDAPException If a problem occurs while sending the request. 2306 */ 2307 @NotNull() 2308 public AsyncRequestID asyncAdd(@NotNull final ReadOnlyAddRequest addRequest, 2309 @Nullable final AsyncResultListener resultListener) 2310 throws LDAPException 2311 { 2312 if (synchronousMode()) 2313 { 2314 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2315 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2316 } 2317 2318 return asyncAdd((AddRequest) addRequest, resultListener); 2319 } 2320 2321 2322 2323 /** 2324 * Processes a simple bind request with the provided DN and password. 2325 * <BR><BR> 2326 * The LDAP protocol specification forbids clients from attempting to perform 2327 * a bind on a connection in which one or more other operations are already in 2328 * progress. If a bind is attempted while any operations are in progress, 2329 * then the directory server may or may not abort processing for those 2330 * operations, depending on the type of operation and how far along the 2331 * server has already gotten while processing that operation (unless the bind 2332 * request is one that will not cause the server to attempt to change the 2333 * identity of this connection, for example by including the retain identity 2334 * request control in the bind request if using the LDAP SDK in conjunction 2335 * with a Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 Directory 2336 * Server). It is recommended that all active operations be abandoned, 2337 * canceled, or allowed to complete before attempting to perform a bind on an 2338 * active connection. 2339 * 2340 * @param bindDN The bind DN for the bind operation. 2341 * @param password The password for the simple bind operation. 2342 * 2343 * @return The result of processing the bind operation. 2344 * 2345 * @throws LDAPException If the server rejects the bind request, or if a 2346 * problem occurs while sending the request or reading 2347 * the response. 2348 */ 2349 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2350 @NotNull() 2351 public BindResult bind(@Nullable final String bindDN, 2352 @Nullable final String password) 2353 throws LDAPException 2354 { 2355 return bind(new SimpleBindRequest(bindDN, password)); 2356 } 2357 2358 2359 2360 /** 2361 * Processes the provided bind request. 2362 * <BR><BR> 2363 * The LDAP protocol specification forbids clients from attempting to perform 2364 * a bind on a connection in which one or more other operations are already in 2365 * progress. If a bind is attempted while any operations are in progress, 2366 * then the directory server may or may not abort processing for those 2367 * operations, depending on the type of operation and how far along the 2368 * server has already gotten while processing that operation (unless the bind 2369 * request is one that will not cause the server to attempt to change the 2370 * identity of this connection, for example by including the retain identity 2371 * request control in the bind request if using the LDAP SDK in conjunction 2372 * with a Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 Directory 2373 * Server). It is recommended that all active operations be abandoned, 2374 * canceled, or allowed to complete before attempting to perform a bind on an 2375 * active connection. 2376 * 2377 * @param bindRequest The bind request to be processed. It must not be 2378 * {@code null}. 2379 * 2380 * @return The result of processing the bind operation. 2381 * 2382 * @throws LDAPException If the server rejects the bind request, or if a 2383 * problem occurs while sending the request or reading 2384 * the response. 2385 */ 2386 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2387 @NotNull() 2388 public BindResult bind(@NotNull final BindRequest bindRequest) 2389 throws LDAPException 2390 { 2391 Validator.ensureNotNull(bindRequest); 2392 2393 final BindResult bindResult = processBindOperation(bindRequest); 2394 switch (bindResult.getResultCode().intValue()) 2395 { 2396 case ResultCode.SUCCESS_INT_VALUE: 2397 return bindResult; 2398 case ResultCode.SASL_BIND_IN_PROGRESS_INT_VALUE: 2399 throw new SASLBindInProgressException(bindResult); 2400 default: 2401 throw new LDAPBindException(bindResult); 2402 } 2403 } 2404 2405 2406 2407 /** 2408 * Processes a compare operation with the provided information. 2409 * 2410 * @param dn The DN of the entry in which to make the 2411 * comparison. It must not be {@code null}. 2412 * @param attributeName The attribute name for which to make the 2413 * comparison. It must not be {@code null}. 2414 * @param assertionValue The assertion value to verify in the target entry. 2415 * It must not be {@code null}. 2416 * 2417 * @return The result of processing the compare operation. 2418 * 2419 * @throws LDAPException If the server rejects the compare request, or if a 2420 * problem is encountered while sending the request or 2421 * reading the response. 2422 */ 2423 @Override() 2424 @NotNull() 2425 public CompareResult compare(@NotNull final String dn, 2426 @NotNull final String attributeName, 2427 @NotNull final String assertionValue) 2428 throws LDAPException 2429 { 2430 Validator.ensureNotNull(dn, attributeName, assertionValue); 2431 2432 return compare(new CompareRequest(dn, attributeName, assertionValue)); 2433 } 2434 2435 2436 2437 /** 2438 * Processes the provided compare request. 2439 * 2440 * @param compareRequest The compare request to be processed. It must not 2441 * be {@code null}. 2442 * 2443 * @return The result of processing the compare operation. 2444 * 2445 * @throws LDAPException If the server rejects the compare request, or if a 2446 * problem is encountered while sending the request or 2447 * reading the response. 2448 */ 2449 @Override() 2450 @NotNull() 2451 public CompareResult compare(@NotNull final CompareRequest compareRequest) 2452 throws LDAPException 2453 { 2454 Validator.ensureNotNull(compareRequest); 2455 2456 final LDAPResult result = compareRequest.process(this, 1); 2457 switch (result.getResultCode().intValue()) 2458 { 2459 case ResultCode.COMPARE_FALSE_INT_VALUE: 2460 case ResultCode.COMPARE_TRUE_INT_VALUE: 2461 return new CompareResult(result); 2462 2463 default: 2464 throw new LDAPException(result); 2465 } 2466 } 2467 2468 2469 2470 /** 2471 * Processes the provided compare request. 2472 * 2473 * @param compareRequest The compare request to be processed. It must not 2474 * be {@code null}. 2475 * 2476 * @return The result of processing the compare operation. 2477 * 2478 * @throws LDAPException If the server rejects the compare request, or if a 2479 * problem is encountered while sending the request or 2480 * reading the response. 2481 */ 2482 @Override() 2483 @NotNull() 2484 public CompareResult compare( 2485 @NotNull final ReadOnlyCompareRequest compareRequest) 2486 throws LDAPException 2487 { 2488 return compare((CompareRequest) compareRequest); 2489 } 2490 2491 2492 2493 /** 2494 * Processes the provided compare request as an asynchronous operation. 2495 * 2496 * @param compareRequest The compare request to be processed. It must not 2497 * be {@code null}. 2498 * @param resultListener The async result listener to use to handle the 2499 * response for the compare operation. It may be 2500 * {@code null} if the result is going to be obtained 2501 * from the returned {@code AsyncRequestID} object via 2502 * the {@code Future} API. 2503 * 2504 * @return An async request ID that may be used to reference the operation. 2505 * 2506 * @throws LDAPException If a problem occurs while sending the request. 2507 */ 2508 @NotNull() 2509 public AsyncRequestID asyncCompare( 2510 @NotNull final CompareRequest compareRequest, 2511 @Nullable final AsyncCompareResultListener resultListener) 2512 throws LDAPException 2513 { 2514 Validator.ensureNotNull(compareRequest); 2515 2516 if (synchronousMode()) 2517 { 2518 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2519 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2520 } 2521 2522 final AsyncCompareResultListener listener; 2523 if (resultListener == null) 2524 { 2525 listener = DiscardAsyncListener.getInstance(); 2526 } 2527 else 2528 { 2529 listener = resultListener; 2530 } 2531 2532 return compareRequest.processAsync(this, listener); 2533 } 2534 2535 2536 2537 /** 2538 * Processes the provided compare request as an asynchronous operation. 2539 * 2540 * @param compareRequest The compare request to be processed. It must not 2541 * be {@code null}. 2542 * @param resultListener The async result listener to use to handle the 2543 * response for the compare operation. It may be 2544 * {@code null} if the result is going to be obtained 2545 * from the returned {@code AsyncRequestID} object via 2546 * the {@code Future} API. 2547 * 2548 * @return An async request ID that may be used to reference the operation. 2549 * 2550 * @throws LDAPException If a problem occurs while sending the request. 2551 */ 2552 @NotNull() 2553 public AsyncRequestID asyncCompare( 2554 @NotNull final ReadOnlyCompareRequest compareRequest, 2555 @Nullable final AsyncCompareResultListener resultListener) 2556 throws LDAPException 2557 { 2558 if (synchronousMode()) 2559 { 2560 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2561 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2562 } 2563 2564 return asyncCompare((CompareRequest) compareRequest, resultListener); 2565 } 2566 2567 2568 2569 /** 2570 * Deletes the entry with the specified DN. 2571 * 2572 * @param dn The DN of the entry to delete. It must not be {@code null}. 2573 * 2574 * @return The result of processing the delete operation. 2575 * 2576 * @throws LDAPException If the server rejects the delete request, or if a 2577 * problem is encountered while sending the request or 2578 * reading the response. 2579 */ 2580 @Override() 2581 @NotNull() 2582 public LDAPResult delete(@NotNull final String dn) 2583 throws LDAPException 2584 { 2585 return delete(new DeleteRequest(dn)); 2586 } 2587 2588 2589 2590 /** 2591 * Processes the provided delete request. 2592 * 2593 * @param deleteRequest The delete request to be processed. It must not be 2594 * {@code null}. 2595 * 2596 * @return The result of processing the delete operation. 2597 * 2598 * @throws LDAPException If the server rejects the delete request, or if a 2599 * problem is encountered while sending the request or 2600 * reading the response. 2601 */ 2602 @Override() 2603 @NotNull() 2604 public LDAPResult delete(@NotNull final DeleteRequest deleteRequest) 2605 throws LDAPException 2606 { 2607 Validator.ensureNotNull(deleteRequest); 2608 2609 final LDAPResult ldapResult = deleteRequest.process(this, 1); 2610 2611 switch (ldapResult.getResultCode().intValue()) 2612 { 2613 case ResultCode.SUCCESS_INT_VALUE: 2614 case ResultCode.NO_OPERATION_INT_VALUE: 2615 return ldapResult; 2616 2617 default: 2618 throw new LDAPException(ldapResult); 2619 } 2620 } 2621 2622 2623 2624 /** 2625 * Processes the provided delete request. 2626 * 2627 * @param deleteRequest The delete request to be processed. It must not be 2628 * {@code null}. 2629 * 2630 * @return The result of processing the delete operation. 2631 * 2632 * @throws LDAPException If the server rejects the delete request, or if a 2633 * problem is encountered while sending the request or 2634 * reading the response. 2635 */ 2636 @Override() 2637 @NotNull() 2638 public LDAPResult delete(@NotNull final ReadOnlyDeleteRequest deleteRequest) 2639 throws LDAPException 2640 { 2641 return delete((DeleteRequest) deleteRequest); 2642 } 2643 2644 2645 2646 /** 2647 * Processes the provided delete request as an asynchronous operation. 2648 * 2649 * @param deleteRequest The delete request to be processed. It must not be 2650 * {@code null}. 2651 * @param resultListener The async result listener to use to handle the 2652 * response for the delete operation. It may be 2653 * {@code null} if the result is going to be obtained 2654 * from the returned {@code AsyncRequestID} object via 2655 * the {@code Future} API. 2656 * 2657 * @return An async request ID that may be used to reference the operation. 2658 * 2659 * @throws LDAPException If a problem occurs while sending the request. 2660 */ 2661 @NotNull() 2662 public AsyncRequestID asyncDelete(@NotNull final DeleteRequest deleteRequest, 2663 @Nullable final AsyncResultListener resultListener) 2664 throws LDAPException 2665 { 2666 Validator.ensureNotNull(deleteRequest); 2667 2668 if (synchronousMode()) 2669 { 2670 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2671 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2672 } 2673 2674 final AsyncResultListener listener; 2675 if (resultListener == null) 2676 { 2677 listener = DiscardAsyncListener.getInstance(); 2678 } 2679 else 2680 { 2681 listener = resultListener; 2682 } 2683 2684 return deleteRequest.processAsync(this, listener); 2685 } 2686 2687 2688 2689 /** 2690 * Processes the provided delete request as an asynchronous operation. 2691 * 2692 * @param deleteRequest The delete request to be processed. It must not be 2693 * {@code null}. 2694 * @param resultListener The async result listener to use to handle the 2695 * response for the delete operation. It may be 2696 * {@code null} if the result is going to be obtained 2697 * from the returned {@code AsyncRequestID} object via 2698 * the {@code Future} API. 2699 * 2700 * @return An async request ID that may be used to reference the operation. 2701 * 2702 * @throws LDAPException If a problem occurs while sending the request. 2703 */ 2704 @NotNull() 2705 public AsyncRequestID asyncDelete( 2706 @NotNull final ReadOnlyDeleteRequest deleteRequest, 2707 @Nullable final AsyncResultListener resultListener) 2708 throws LDAPException 2709 { 2710 if (synchronousMode()) 2711 { 2712 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2713 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2714 } 2715 2716 return asyncDelete((DeleteRequest) deleteRequest, resultListener); 2717 } 2718 2719 2720 2721 /** 2722 * Processes an extended request with the provided request OID. Note that 2723 * because some types of extended operations return unusual result codes under 2724 * "normal" conditions, the server may not always throw an exception for a 2725 * failed extended operation like it does for other types of operations. It 2726 * will throw an exception under conditions where there appears to be a 2727 * problem with the connection or the server to which the connection is 2728 * established, but there may be many circumstances in which an extended 2729 * operation is not processed correctly but this method does not throw an 2730 * exception. In the event that no exception is thrown, it is the 2731 * responsibility of the caller to interpret the result to determine whether 2732 * the operation was processed as expected. 2733 * <BR><BR> 2734 * Note that extended operations which may change the state of this connection 2735 * (e.g., the StartTLS extended operation, which will add encryption to a 2736 * previously-unencrypted connection) should not be invoked while any other 2737 * operations are active on the connection. It is recommended that all active 2738 * operations be abandoned, canceled, or allowed to complete before attempting 2739 * to process an extended operation that may change the state of this 2740 * connection. 2741 * 2742 * @param requestOID The OID for the extended request to process. It must 2743 * not be {@code null}. 2744 * 2745 * @return The extended result object that provides information about the 2746 * result of the request processing. It may or may not indicate that 2747 * the operation was successful. 2748 * 2749 * @throws LDAPException If a problem occurs while sending the request or 2750 * reading the response. 2751 */ 2752 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2753 @NotNull() 2754 public ExtendedResult processExtendedOperation( 2755 @NotNull final String requestOID) 2756 throws LDAPException 2757 { 2758 Validator.ensureNotNull(requestOID); 2759 2760 return processExtendedOperation(new ExtendedRequest(requestOID)); 2761 } 2762 2763 2764 2765 /** 2766 * Processes an extended request with the provided request OID and value. 2767 * Note that because some types of extended operations return unusual result 2768 * codes under "normal" conditions, the server may not always throw an 2769 * exception for a failed extended operation like it does for other types of 2770 * operations. It will throw an exception under conditions where there 2771 * appears to be a problem with the connection or the server to which the 2772 * connection is established, but there may be many circumstances in which an 2773 * extended operation is not processed correctly but this method does not 2774 * throw an exception. In the event that no exception is thrown, it is the 2775 * responsibility of the caller to interpret the result to determine whether 2776 * the operation was processed as expected. 2777 * <BR><BR> 2778 * Note that extended operations which may change the state of this connection 2779 * (e.g., the StartTLS extended operation, which will add encryption to a 2780 * previously-unencrypted connection) should not be invoked while any other 2781 * operations are active on the connection. It is recommended that all active 2782 * operations be abandoned, canceled, or allowed to complete before attempting 2783 * to process an extended operation that may change the state of this 2784 * connection. 2785 * 2786 * @param requestOID The OID for the extended request to process. It must 2787 * not be {@code null}. 2788 * @param requestValue The encoded value for the extended request to 2789 * process. It may be {@code null} if there does not 2790 * need to be a value for the requested operation. 2791 * 2792 * @return The extended result object that provides information about the 2793 * result of the request processing. It may or may not indicate that 2794 * the operation was successful. 2795 * 2796 * @throws LDAPException If a problem occurs while sending the request or 2797 * reading the response. 2798 */ 2799 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2800 @NotNull() 2801 public ExtendedResult processExtendedOperation( 2802 @NotNull final String requestOID, 2803 @Nullable final ASN1OctetString requestValue) 2804 throws LDAPException 2805 { 2806 Validator.ensureNotNull(requestOID); 2807 2808 return processExtendedOperation(new ExtendedRequest(requestOID, 2809 requestValue)); 2810 } 2811 2812 2813 2814 /** 2815 * Processes the provided extended request. Note that because some types of 2816 * extended operations return unusual result codes under "normal" conditions, 2817 * the server may not always throw an exception for a failed extended 2818 * operation like it does for other types of operations. It will throw an 2819 * exception under conditions where there appears to be a problem with the 2820 * connection or the server to which the connection is established, but there 2821 * may be many circumstances in which an extended operation is not processed 2822 * correctly but this method does not throw an exception. In the event that 2823 * no exception is thrown, it is the responsibility of the caller to interpret 2824 * the result to determine whether the operation was processed as expected. 2825 * <BR><BR> 2826 * Note that extended operations which may change the state of this connection 2827 * (e.g., the StartTLS extended operation, which will add encryption to a 2828 * previously-unencrypted connection) should not be invoked while any other 2829 * operations are active on the connection. It is recommended that all active 2830 * operations be abandoned, canceled, or allowed to complete before attempting 2831 * to process an extended operation that may change the state of this 2832 * connection. 2833 * 2834 * @param extendedRequest The extended request to be processed. It must not 2835 * be {@code null}. 2836 * 2837 * @return The extended result object that provides information about the 2838 * result of the request processing. It may or may not indicate that 2839 * the operation was successful. 2840 * 2841 * @throws LDAPException If a problem occurs while sending the request or 2842 * reading the response. 2843 */ 2844 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2845 @NotNull() 2846 public ExtendedResult processExtendedOperation( 2847 @NotNull final ExtendedRequest extendedRequest) 2848 throws LDAPException 2849 { 2850 Validator.ensureNotNull(extendedRequest); 2851 2852 final ExtendedResult extendedResult = extendedRequest.process(this, 1); 2853 2854 if ((extendedResult.getOID() == null) && 2855 (extendedResult.getValue() == null)) 2856 { 2857 switch (extendedResult.getResultCode().intValue()) 2858 { 2859 case ResultCode.OPERATIONS_ERROR_INT_VALUE: 2860 case ResultCode.PROTOCOL_ERROR_INT_VALUE: 2861 case ResultCode.BUSY_INT_VALUE: 2862 case ResultCode.UNAVAILABLE_INT_VALUE: 2863 case ResultCode.OTHER_INT_VALUE: 2864 case ResultCode.SERVER_DOWN_INT_VALUE: 2865 case ResultCode.LOCAL_ERROR_INT_VALUE: 2866 case ResultCode.ENCODING_ERROR_INT_VALUE: 2867 case ResultCode.DECODING_ERROR_INT_VALUE: 2868 case ResultCode.TIMEOUT_INT_VALUE: 2869 case ResultCode.NO_MEMORY_INT_VALUE: 2870 case ResultCode.CONNECT_ERROR_INT_VALUE: 2871 throw new LDAPException(extendedResult); 2872 } 2873 } 2874 2875 if ((extendedResult.getResultCode() == ResultCode.SUCCESS) && 2876 extendedRequest.getOID().equals( 2877 StartTLSExtendedRequest.STARTTLS_REQUEST_OID)) 2878 { 2879 startTLSRequest = extendedRequest.duplicate(); 2880 } 2881 2882 return extendedResult; 2883 } 2884 2885 2886 2887 /** 2888 * Applies the provided modification to the specified entry. 2889 * 2890 * @param dn The DN of the entry to modify. It must not be {@code null}. 2891 * @param mod The modification to apply to the target entry. It must not 2892 * be {@code null}. 2893 * 2894 * @return The result of processing the modify operation. 2895 * 2896 * @throws LDAPException If the server rejects the modify request, or if a 2897 * problem is encountered while sending the request or 2898 * reading the response. 2899 */ 2900 @Override() 2901 @NotNull() 2902 public LDAPResult modify(@NotNull final String dn, 2903 @NotNull final Modification mod) 2904 throws LDAPException 2905 { 2906 Validator.ensureNotNull(dn, mod); 2907 2908 return modify(new ModifyRequest(dn, mod)); 2909 } 2910 2911 2912 2913 /** 2914 * Applies the provided set of modifications to the specified entry. 2915 * 2916 * @param dn The DN of the entry to modify. It must not be {@code null}. 2917 * @param mods The set of modifications to apply to the target entry. It 2918 * must not be {@code null} or empty. * 2919 * @return The result of processing the modify operation. 2920 * 2921 * @throws LDAPException If the server rejects the modify request, or if a 2922 * problem is encountered while sending the request or 2923 * reading the response. 2924 */ 2925 @Override() 2926 @NotNull() 2927 public LDAPResult modify(@NotNull final String dn, 2928 @NotNull final Modification... mods) 2929 throws LDAPException 2930 { 2931 Validator.ensureNotNull(dn, mods); 2932 2933 return modify(new ModifyRequest(dn, mods)); 2934 } 2935 2936 2937 2938 /** 2939 * Applies the provided set of modifications to the specified entry. 2940 * 2941 * @param dn The DN of the entry to modify. It must not be {@code null}. 2942 * @param mods The set of modifications to apply to the target entry. It 2943 * must not be {@code null} or empty. 2944 * 2945 * @return The result of processing the modify operation. 2946 * 2947 * @throws LDAPException If the server rejects the modify request, or if a 2948 * problem is encountered while sending the request or 2949 * reading the response. 2950 */ 2951 @Override() 2952 @NotNull() 2953 public LDAPResult modify(@NotNull final String dn, 2954 @NotNull final List<Modification> mods) 2955 throws LDAPException 2956 { 2957 Validator.ensureNotNull(dn, mods); 2958 2959 return modify(new ModifyRequest(dn, mods)); 2960 } 2961 2962 2963 2964 /** 2965 * Processes a modify request from the provided LDIF representation of the 2966 * changes. 2967 * 2968 * @param ldifModificationLines The lines that comprise an LDIF 2969 * representation of a modify change record. 2970 * It must not be {@code null} or empty. 2971 * 2972 * @return The result of processing the modify operation. 2973 * 2974 * @throws LDIFException If the provided set of lines cannot be parsed as an 2975 * LDIF modify change record. 2976 * 2977 * @throws LDAPException If the server rejects the modify request, or if a 2978 * problem is encountered while sending the request or 2979 * reading the response. 2980 * 2981 */ 2982 @Override() 2983 @NotNull() 2984 public LDAPResult modify(@NotNull final String... ldifModificationLines) 2985 throws LDIFException, LDAPException 2986 { 2987 Validator.ensureNotNull(ldifModificationLines); 2988 2989 return modify(new ModifyRequest(ldifModificationLines)); 2990 } 2991 2992 2993 2994 /** 2995 * Processes the provided modify request. 2996 * 2997 * @param modifyRequest The modify request to be processed. It must not be 2998 * {@code null}. 2999 * 3000 * @return The result of processing the modify operation. 3001 * 3002 * @throws LDAPException If the server rejects the modify request, or if a 3003 * problem is encountered while sending the request or 3004 * reading the response. 3005 */ 3006 @Override() 3007 @NotNull() 3008 public LDAPResult modify(@NotNull final ModifyRequest modifyRequest) 3009 throws LDAPException 3010 { 3011 Validator.ensureNotNull(modifyRequest); 3012 3013 final LDAPResult ldapResult = modifyRequest.process(this, 1); 3014 3015 switch (ldapResult.getResultCode().intValue()) 3016 { 3017 case ResultCode.SUCCESS_INT_VALUE: 3018 case ResultCode.NO_OPERATION_INT_VALUE: 3019 return ldapResult; 3020 3021 default: 3022 throw new LDAPException(ldapResult); 3023 } 3024 } 3025 3026 3027 3028 /** 3029 * Processes the provided modify request. 3030 * 3031 * @param modifyRequest The modify request to be processed. It must not be 3032 * {@code null}. 3033 * 3034 * @return The result of processing the modify operation. 3035 * 3036 * @throws LDAPException If the server rejects the modify request, or if a 3037 * problem is encountered while sending the request or 3038 * reading the response. 3039 */ 3040 @Override() 3041 @NotNull() 3042 public LDAPResult modify(@NotNull final ReadOnlyModifyRequest modifyRequest) 3043 throws LDAPException 3044 { 3045 return modify((ModifyRequest) modifyRequest); 3046 } 3047 3048 3049 3050 /** 3051 * Processes the provided modify request as an asynchronous operation. 3052 * 3053 * @param modifyRequest The modify request to be processed. It must not be 3054 * {@code null}. 3055 * @param resultListener The async result listener to use to handle the 3056 * response for the modify operation. It may be 3057 * {@code null} if the result is going to be obtained 3058 * from the returned {@code AsyncRequestID} object via 3059 * the {@code Future} API. 3060 * 3061 * @return An async request ID that may be used to reference the operation. 3062 * 3063 * @throws LDAPException If a problem occurs while sending the request. 3064 */ 3065 @NotNull() 3066 public AsyncRequestID asyncModify(@NotNull final ModifyRequest modifyRequest, 3067 @Nullable final AsyncResultListener resultListener) 3068 throws LDAPException 3069 { 3070 Validator.ensureNotNull(modifyRequest); 3071 3072 if (synchronousMode()) 3073 { 3074 throw new LDAPException(ResultCode.NOT_SUPPORTED, 3075 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 3076 } 3077 3078 final AsyncResultListener listener; 3079 if (resultListener == null) 3080 { 3081 listener = DiscardAsyncListener.getInstance(); 3082 } 3083 else 3084 { 3085 listener = resultListener; 3086 } 3087 3088 return modifyRequest.processAsync(this, listener); 3089 } 3090 3091 3092 3093 /** 3094 * Processes the provided modify request as an asynchronous operation. 3095 * 3096 * @param modifyRequest The modify request to be processed. It must not be 3097 * {@code null}. 3098 * @param resultListener The async result listener to use to handle the 3099 * response for the modify operation. It may be 3100 * {@code null} if the result is going to be obtained 3101 * from the returned {@code AsyncRequestID} object via 3102 * the {@code Future} API. 3103 * 3104 * @return An async request ID that may be used to reference the operation. 3105 * 3106 * @throws LDAPException If a problem occurs while sending the request. 3107 */ 3108 @NotNull() 3109 public AsyncRequestID asyncModify( 3110 @NotNull final ReadOnlyModifyRequest modifyRequest, 3111 @Nullable final AsyncResultListener resultListener) 3112 throws LDAPException 3113 { 3114 if (synchronousMode()) 3115 { 3116 throw new LDAPException(ResultCode.NOT_SUPPORTED, 3117 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 3118 } 3119 3120 return asyncModify((ModifyRequest) modifyRequest, resultListener); 3121 } 3122 3123 3124 3125 /** 3126 * Performs a modify DN operation with the provided information. 3127 * 3128 * @param dn The current DN for the entry to rename. It must not 3129 * be {@code null}. 3130 * @param newRDN The new RDN to use for the entry. It must not be 3131 * {@code null}. 3132 * @param deleteOldRDN Indicates whether to delete the current RDN value 3133 * from the entry. 3134 * 3135 * @return The result of processing the modify DN operation. 3136 * 3137 * @throws LDAPException If the server rejects the modify DN request, or if 3138 * a problem is encountered while sending the request 3139 * or reading the response. 3140 */ 3141 @Override() 3142 @NotNull() 3143 public LDAPResult modifyDN(@NotNull final String dn, 3144 @NotNull final String newRDN, 3145 final boolean deleteOldRDN) 3146 throws LDAPException 3147 { 3148 Validator.ensureNotNull(dn, newRDN); 3149 3150 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN)); 3151 } 3152 3153 3154 3155 /** 3156 * Performs a modify DN operation with the provided information. 3157 * 3158 * @param dn The current DN for the entry to rename. It must not 3159 * be {@code null}. 3160 * @param newRDN The new RDN to use for the entry. It must not be 3161 * {@code null}. 3162 * @param deleteOldRDN Indicates whether to delete the current RDN value 3163 * from the entry. 3164 * @param newSuperiorDN The new superior DN for the entry. It may be 3165 * {@code null} if the entry is not to be moved below a 3166 * new parent. 3167 * 3168 * @return The result of processing the modify DN operation. 3169 * 3170 * @throws LDAPException If the server rejects the modify DN request, or if 3171 * a problem is encountered while sending the request 3172 * or reading the response. 3173 */ 3174 @Override() 3175 @NotNull() 3176 public LDAPResult modifyDN(@NotNull final String dn, 3177 @NotNull final String newRDN, 3178 final boolean deleteOldRDN, 3179 @Nullable final String newSuperiorDN) 3180 throws LDAPException 3181 { 3182 Validator.ensureNotNull(dn, newRDN); 3183 3184 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN, 3185 newSuperiorDN)); 3186 } 3187 3188 3189 3190 /** 3191 * Processes the provided modify DN request. 3192 * 3193 * @param modifyDNRequest The modify DN request to be processed. It must 3194 * not be {@code null}. 3195 * 3196 * @return The result of processing the modify DN operation. 3197 * 3198 * @throws LDAPException If the server rejects the modify DN request, or if 3199 * a problem is encountered while sending the request 3200 * or reading the response. 3201 */ 3202 @Override() 3203 @NotNull() 3204 public LDAPResult modifyDN(@NotNull final ModifyDNRequest modifyDNRequest) 3205 throws LDAPException 3206 { 3207 Validator.ensureNotNull(modifyDNRequest); 3208 3209 final LDAPResult ldapResult = modifyDNRequest.process(this, 1); 3210 3211 switch (ldapResult.getResultCode().intValue()) 3212 { 3213 case ResultCode.SUCCESS_INT_VALUE: 3214 case ResultCode.NO_OPERATION_INT_VALUE: 3215 return ldapResult; 3216 3217 default: 3218 throw new LDAPException(ldapResult); 3219 } 3220 } 3221 3222 3223 3224 /** 3225 * Processes the provided modify DN request. 3226 * 3227 * @param modifyDNRequest The modify DN request to be processed. It must 3228 * not be {@code null}. 3229 * 3230 * @return The result of processing the modify DN operation. 3231 * 3232 * @throws LDAPException If the server rejects the modify DN request, or if 3233 * a problem is encountered while sending the request 3234 * or reading the response. 3235 */ 3236 @Override() 3237 @NotNull() 3238 public LDAPResult modifyDN( 3239 @NotNull final ReadOnlyModifyDNRequest modifyDNRequest) 3240 throws LDAPException 3241 { 3242 return modifyDN((ModifyDNRequest) modifyDNRequest); 3243 } 3244 3245 3246 3247 /** 3248 * Processes the provided modify DN request as an asynchronous operation. 3249 * 3250 * @param modifyDNRequest The modify DN request to be processed. It must 3251 * not be {@code null}. 3252 * @param resultListener The async result listener to use to handle the 3253 * response for the modify DN operation. It may be 3254 * {@code null} if the result is going to be obtained 3255 * from the returned {@code AsyncRequestID} object via 3256 * the {@code Future} API. 3257 * 3258 * @return An async request ID that may be used to reference the operation. 3259 * 3260 * @throws LDAPException If a problem occurs while sending the request. 3261 */ 3262 @NotNull() 3263 public AsyncRequestID asyncModifyDN( 3264 @NotNull final ModifyDNRequest modifyDNRequest, 3265 @Nullable final AsyncResultListener resultListener) 3266 throws LDAPException 3267 { 3268 Validator.ensureNotNull(modifyDNRequest); 3269 3270 if (synchronousMode()) 3271 { 3272 throw new LDAPException(ResultCode.NOT_SUPPORTED, 3273 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 3274 } 3275 3276 final AsyncResultListener listener; 3277 if (resultListener == null) 3278 { 3279 listener = DiscardAsyncListener.getInstance(); 3280 } 3281 else 3282 { 3283 listener = resultListener; 3284 } 3285 3286 return modifyDNRequest.processAsync(this, listener); 3287 } 3288 3289 3290 3291 /** 3292 * Processes the provided modify DN request as an asynchronous operation. 3293 * 3294 * @param modifyDNRequest The modify DN request to be processed. It must 3295 * not be {@code null}. 3296 * @param resultListener The async result listener to use to handle the 3297 * response for the modify DN operation. It may be 3298 * {@code null} if the result is going to be obtained 3299 * from the returned {@code AsyncRequestID} object via 3300 * the {@code Future} API. 3301 * 3302 * @return An async request ID that may be used to reference the operation. 3303 * 3304 * @throws LDAPException If a problem occurs while sending the request. 3305 */ 3306 @NotNull() 3307 public AsyncRequestID asyncModifyDN( 3308 @NotNull final ReadOnlyModifyDNRequest modifyDNRequest, 3309 @Nullable final AsyncResultListener resultListener) 3310 throws LDAPException 3311 { 3312 if (synchronousMode()) 3313 { 3314 throw new LDAPException(ResultCode.NOT_SUPPORTED, 3315 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 3316 } 3317 3318 return asyncModifyDN((ModifyDNRequest) modifyDNRequest, resultListener); 3319 } 3320 3321 3322 3323 /** 3324 * Processes a search operation with the provided information. The search 3325 * result entries and references will be collected internally and included in 3326 * the {@code SearchResult} object that is returned. 3327 * <BR><BR> 3328 * Note that if the search does not complete successfully, an 3329 * {@code LDAPSearchException} will be thrown In some cases, one or more 3330 * search result entries or references may have been returned before the 3331 * failure response is received. In this case, the 3332 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3333 * {@code getSearchEntries}, {@code getReferenceCount}, and 3334 * {@code getSearchReferences} may be used to obtain information about those 3335 * entries and references. 3336 * 3337 * @param baseDN The base DN for the search request. It must not be 3338 * {@code null}. 3339 * @param scope The scope that specifies the range of entries that 3340 * should be examined for the search. 3341 * @param filter The string representation of the filter to use to 3342 * identify matching entries. It must not be 3343 * {@code null}. 3344 * @param attributes The set of attributes that should be returned in 3345 * matching entries. It may be {@code null} or empty if 3346 * the default attribute set (all user attributes) is to 3347 * be requested. 3348 * 3349 * @return A search result object that provides information about the 3350 * processing of the search, including the set of matching entries 3351 * and search references returned by the server. 3352 * 3353 * @throws LDAPSearchException If the search does not complete successfully, 3354 * or if a problem is encountered while parsing 3355 * the provided filter string, sending the 3356 * request, or reading the response. If one 3357 * or more entries or references were returned 3358 * before the failure was encountered, then the 3359 * {@code LDAPSearchException} object may be 3360 * examined to obtain information about those 3361 * entries and/or references. 3362 */ 3363 @Override() 3364 @NotNull() 3365 public SearchResult search(@NotNull final String baseDN, 3366 @NotNull final SearchScope scope, 3367 @NotNull final String filter, 3368 @Nullable final String... attributes) 3369 throws LDAPSearchException 3370 { 3371 Validator.ensureNotNull(baseDN, filter); 3372 3373 try 3374 { 3375 return search(new SearchRequest(baseDN, scope, filter, attributes)); 3376 } 3377 catch (final LDAPSearchException lse) 3378 { 3379 Debug.debugException(lse); 3380 throw lse; 3381 } 3382 catch (final LDAPException le) 3383 { 3384 Debug.debugException(le); 3385 throw new LDAPSearchException(le); 3386 } 3387 } 3388 3389 3390 3391 /** 3392 * Processes a search operation with the provided information. The search 3393 * result entries and references will be collected internally and included in 3394 * the {@code SearchResult} object that is returned. 3395 * <BR><BR> 3396 * Note that if the search does not complete successfully, an 3397 * {@code LDAPSearchException} will be thrown In some cases, one or more 3398 * search result entries or references may have been returned before the 3399 * failure response is received. In this case, the 3400 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3401 * {@code getSearchEntries}, {@code getReferenceCount}, and 3402 * {@code getSearchReferences} may be used to obtain information about those 3403 * entries and references. 3404 * 3405 * @param baseDN The base DN for the search request. It must not be 3406 * {@code null}. 3407 * @param scope The scope that specifies the range of entries that 3408 * should be examined for the search. 3409 * @param filter The filter to use to identify matching entries. It 3410 * must not be {@code null}. 3411 * @param attributes The set of attributes that should be returned in 3412 * matching entries. It may be {@code null} or empty if 3413 * the default attribute set (all user attributes) is to 3414 * be requested. 3415 * 3416 * @return A search result object that provides information about the 3417 * processing of the search, including the set of matching entries 3418 * and search references returned by the server. 3419 * 3420 * @throws LDAPSearchException If the search does not complete successfully, 3421 * or if a problem is encountered while sending 3422 * the request or reading the response. If one 3423 * or more entries or references were returned 3424 * before the failure was encountered, then the 3425 * {@code LDAPSearchException} object may be 3426 * examined to obtain information about those 3427 * entries and/or references. 3428 */ 3429 @Override() 3430 @NotNull() 3431 public SearchResult search(@NotNull final String baseDN, 3432 @NotNull final SearchScope scope, 3433 @NotNull final Filter filter, 3434 @Nullable final String... attributes) 3435 throws LDAPSearchException 3436 { 3437 Validator.ensureNotNull(baseDN, filter); 3438 3439 return search(new SearchRequest(baseDN, scope, filter, attributes)); 3440 } 3441 3442 3443 3444 /** 3445 * Processes a search operation with the provided information. 3446 * <BR><BR> 3447 * Note that if the search does not complete successfully, an 3448 * {@code LDAPSearchException} will be thrown In some cases, one or more 3449 * search result entries or references may have been returned before the 3450 * failure response is received. In this case, the 3451 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3452 * {@code getSearchEntries}, {@code getReferenceCount}, and 3453 * {@code getSearchReferences} may be used to obtain information about those 3454 * entries and references (although if a search result listener was provided, 3455 * then it will have been used to make any entries and references available, 3456 * and they will not be available through the {@code getSearchEntries} and 3457 * {@code getSearchReferences} methods). 3458 * 3459 * @param searchResultListener The search result listener that should be 3460 * used to return results to the client. It may 3461 * be {@code null} if the search results should 3462 * be collected internally and returned in the 3463 * {@code SearchResult} object. 3464 * @param baseDN The base DN for the search request. It must 3465 * not be {@code null}. 3466 * @param scope The scope that specifies the range of entries 3467 * that should be examined for the search. 3468 * @param filter The string representation of the filter to 3469 * use to identify matching entries. It must 3470 * not be {@code null}. 3471 * @param attributes The set of attributes that should be returned 3472 * in matching entries. It may be {@code null} 3473 * or empty if the default attribute set (all 3474 * user attributes) is to be requested. 3475 * 3476 * @return A search result object that provides information about the 3477 * processing of the search, potentially including the set of 3478 * matching entries and search references returned by the server. 3479 * 3480 * @throws LDAPSearchException If the search does not complete successfully, 3481 * or if a problem is encountered while parsing 3482 * the provided filter string, sending the 3483 * request, or reading the response. If one 3484 * or more entries or references were returned 3485 * before the failure was encountered, then the 3486 * {@code LDAPSearchException} object may be 3487 * examined to obtain information about those 3488 * entries and/or references. 3489 */ 3490 @Override() 3491 @NotNull() 3492 public SearchResult search( 3493 @Nullable final SearchResultListener searchResultListener, 3494 @NotNull final String baseDN, @NotNull final SearchScope scope, 3495 @NotNull final String filter, 3496 @Nullable final String... attributes) 3497 throws LDAPSearchException 3498 { 3499 Validator.ensureNotNull(baseDN, filter); 3500 3501 try 3502 { 3503 return search(new SearchRequest(searchResultListener, baseDN, scope, 3504 filter, attributes)); 3505 } 3506 catch (final LDAPSearchException lse) 3507 { 3508 Debug.debugException(lse); 3509 throw lse; 3510 } 3511 catch (final LDAPException le) 3512 { 3513 Debug.debugException(le); 3514 throw new LDAPSearchException(le); 3515 } 3516 } 3517 3518 3519 3520 /** 3521 * Processes a search operation with the provided information. 3522 * <BR><BR> 3523 * Note that if the search does not complete successfully, an 3524 * {@code LDAPSearchException} will be thrown In some cases, one or more 3525 * search result entries or references may have been returned before the 3526 * failure response is received. In this case, the 3527 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3528 * {@code getSearchEntries}, {@code getReferenceCount}, and 3529 * {@code getSearchReferences} may be used to obtain information about those 3530 * entries and references (although if a search result listener was provided, 3531 * then it will have been used to make any entries and references available, 3532 * and they will not be available through the {@code getSearchEntries} and 3533 * {@code getSearchReferences} methods). 3534 * 3535 * @param searchResultListener The search result listener that should be 3536 * used to return results to the client. It may 3537 * be {@code null} if the search results should 3538 * be collected internally and returned in the 3539 * {@code SearchResult} object. 3540 * @param baseDN The base DN for the search request. It must 3541 * not be {@code null}. 3542 * @param scope The scope that specifies the range of entries 3543 * that should be examined for the search. 3544 * @param filter The filter to use to identify matching 3545 * entries. It must not be {@code null}. 3546 * @param attributes The set of attributes that should be returned 3547 * in matching entries. It may be {@code null} 3548 * or empty if the default attribute set (all 3549 * user attributes) is to be requested. 3550 * 3551 * @return A search result object that provides information about the 3552 * processing of the search, potentially including the set of 3553 * matching entries and search references returned by the server. 3554 * 3555 * @throws LDAPSearchException If the search does not complete successfully, 3556 * or if a problem is encountered while sending 3557 * the request or reading the response. If one 3558 * or more entries or references were returned 3559 * before the failure was encountered, then the 3560 * {@code LDAPSearchException} object may be 3561 * examined to obtain information about those 3562 * entries and/or references. 3563 */ 3564 @Override() 3565 @NotNull() 3566 public SearchResult search( 3567 @Nullable final SearchResultListener searchResultListener, 3568 @NotNull final String baseDN, @NotNull final SearchScope scope, 3569 @NotNull final Filter filter, 3570 @Nullable final String... attributes) 3571 throws LDAPSearchException 3572 { 3573 Validator.ensureNotNull(baseDN, filter); 3574 3575 try 3576 { 3577 return search(new SearchRequest(searchResultListener, baseDN, scope, 3578 filter, attributes)); 3579 } 3580 catch (final LDAPSearchException lse) 3581 { 3582 Debug.debugException(lse); 3583 throw lse; 3584 } 3585 } 3586 3587 3588 3589 /** 3590 * Processes a search operation with the provided information. The search 3591 * result entries and references will be collected internally and included in 3592 * the {@code SearchResult} object that is returned. 3593 * <BR><BR> 3594 * Note that if the search does not complete successfully, an 3595 * {@code LDAPSearchException} will be thrown In some cases, one or more 3596 * search result entries or references may have been returned before the 3597 * failure response is received. In this case, the 3598 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3599 * {@code getSearchEntries}, {@code getReferenceCount}, and 3600 * {@code getSearchReferences} may be used to obtain information about those 3601 * entries and references. 3602 * 3603 * @param baseDN The base DN for the search request. It must not be 3604 * {@code null}. 3605 * @param scope The scope that specifies the range of entries that 3606 * should be examined for the search. 3607 * @param derefPolicy The dereference policy the server should use for any 3608 * aliases encountered while processing the search. 3609 * @param sizeLimit The maximum number of entries that the server should 3610 * return for the search. A value of zero indicates that 3611 * there should be no limit. 3612 * @param timeLimit The maximum length of time in seconds that the server 3613 * should spend processing this search request. A value 3614 * of zero indicates that there should be no limit. 3615 * @param typesOnly Indicates whether to return only attribute names in 3616 * matching entries, or both attribute names and values. 3617 * @param filter The string representation of the filter to use to 3618 * identify matching entries. It must not be 3619 * {@code null}. 3620 * @param attributes The set of attributes that should be returned in 3621 * matching entries. It may be {@code null} or empty if 3622 * the default attribute set (all user attributes) is to 3623 * be requested. 3624 * 3625 * @return A search result object that provides information about the 3626 * processing of the search, including the set of matching entries 3627 * and search references returned by the server. 3628 * 3629 * @throws LDAPSearchException If the search does not complete successfully, 3630 * or if a problem is encountered while parsing 3631 * the provided filter string, sending the 3632 * request, or reading the response. If one 3633 * or more entries or references were returned 3634 * before the failure was encountered, then the 3635 * {@code LDAPSearchException} object may be 3636 * examined to obtain information about those 3637 * entries and/or references. 3638 */ 3639 @Override() 3640 @NotNull() 3641 public SearchResult search(@NotNull final String baseDN, 3642 @NotNull final SearchScope scope, 3643 @NotNull final DereferencePolicy derefPolicy, 3644 final int sizeLimit, final int timeLimit, 3645 final boolean typesOnly, 3646 @NotNull final String filter, 3647 @Nullable final String... attributes) 3648 throws LDAPSearchException 3649 { 3650 Validator.ensureNotNull(baseDN, filter); 3651 3652 try 3653 { 3654 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 3655 timeLimit, typesOnly, filter, 3656 attributes)); 3657 } 3658 catch (final LDAPSearchException lse) 3659 { 3660 Debug.debugException(lse); 3661 throw lse; 3662 } 3663 catch (final LDAPException le) 3664 { 3665 Debug.debugException(le); 3666 throw new LDAPSearchException(le); 3667 } 3668 } 3669 3670 3671 3672 /** 3673 * Processes a search operation with the provided information. The search 3674 * result entries and references will be collected internally and included in 3675 * the {@code SearchResult} object that is returned. 3676 * <BR><BR> 3677 * Note that if the search does not complete successfully, an 3678 * {@code LDAPSearchException} will be thrown In some cases, one or more 3679 * search result entries or references may have been returned before the 3680 * failure response is received. In this case, the 3681 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3682 * {@code getSearchEntries}, {@code getReferenceCount}, and 3683 * {@code getSearchReferences} may be used to obtain information about those 3684 * entries and references. 3685 * 3686 * @param baseDN The base DN for the search request. It must not be 3687 * {@code null}. 3688 * @param scope The scope that specifies the range of entries that 3689 * should be examined for the search. 3690 * @param derefPolicy The dereference policy the server should use for any 3691 * aliases encountered while processing the search. 3692 * @param sizeLimit The maximum number of entries that the server should 3693 * return for the search. A value of zero indicates that 3694 * there should be no limit. 3695 * @param timeLimit The maximum length of time in seconds that the server 3696 * should spend processing this search request. A value 3697 * of zero indicates that there should be no limit. 3698 * @param typesOnly Indicates whether to return only attribute names in 3699 * matching entries, or both attribute names and values. 3700 * @param filter The filter to use to identify matching entries. It 3701 * must not be {@code null}. 3702 * @param attributes The set of attributes that should be returned in 3703 * matching entries. It may be {@code null} or empty if 3704 * the default attribute set (all user attributes) is to 3705 * be requested. 3706 * 3707 * @return A search result object that provides information about the 3708 * processing of the search, including the set of matching entries 3709 * and search references returned by the server. 3710 * 3711 * @throws LDAPSearchException If the search does not complete successfully, 3712 * or if a problem is encountered while sending 3713 * the request or reading the response. If one 3714 * or more entries or references were returned 3715 * before the failure was encountered, then the 3716 * {@code LDAPSearchException} object may be 3717 * examined to obtain information about those 3718 * entries and/or references. 3719 */ 3720 @Override() 3721 @NotNull() 3722 public SearchResult search(@NotNull final String baseDN, 3723 @NotNull final SearchScope scope, 3724 @NotNull final DereferencePolicy derefPolicy, 3725 final int sizeLimit, final int timeLimit, 3726 final boolean typesOnly, 3727 @NotNull final Filter filter, 3728 @Nullable final String... attributes) 3729 throws LDAPSearchException 3730 { 3731 Validator.ensureNotNull(baseDN, filter); 3732 3733 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 3734 timeLimit, typesOnly, filter, attributes)); 3735 } 3736 3737 3738 3739 /** 3740 * Processes a search operation with the provided information. 3741 * <BR><BR> 3742 * Note that if the search does not complete successfully, an 3743 * {@code LDAPSearchException} will be thrown In some cases, one or more 3744 * search result entries or references may have been returned before the 3745 * failure response is received. In this case, the 3746 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3747 * {@code getSearchEntries}, {@code getReferenceCount}, and 3748 * {@code getSearchReferences} may be used to obtain information about those 3749 * entries and references (although if a search result listener was provided, 3750 * then it will have been used to make any entries and references available, 3751 * and they will not be available through the {@code getSearchEntries} and 3752 * {@code getSearchReferences} methods). 3753 * 3754 * @param searchResultListener The search result listener that should be 3755 * used to return results to the client. It may 3756 * be {@code null} if the search results should 3757 * be collected internally and returned in the 3758 * {@code SearchResult} object. 3759 * @param baseDN The base DN for the search request. It must 3760 * not be {@code null}. 3761 * @param scope The scope that specifies the range of entries 3762 * that should be examined for the search. 3763 * @param derefPolicy The dereference policy the server should use 3764 * for any aliases encountered while processing 3765 * the search. 3766 * @param sizeLimit The maximum number of entries that the server 3767 * should return for the search. A value of 3768 * zero indicates that there should be no limit. 3769 * @param timeLimit The maximum length of time in seconds that 3770 * the server should spend processing this 3771 * search request. A value of zero indicates 3772 * that there should be no limit. 3773 * @param typesOnly Indicates whether to return only attribute 3774 * names in matching entries, or both attribute 3775 * names and values. 3776 * @param filter The string representation of the filter to 3777 * use to identify matching entries. It must 3778 * not be {@code null}. 3779 * @param attributes The set of attributes that should be returned 3780 * in matching entries. It may be {@code null} 3781 * or empty if the default attribute set (all 3782 * user attributes) is to be requested. 3783 * 3784 * @return A search result object that provides information about the 3785 * processing of the search, potentially including the set of 3786 * matching entries and search references returned by the server. 3787 * 3788 * @throws LDAPSearchException If the search does not complete successfully, 3789 * or if a problem is encountered while parsing 3790 * the provided filter string, sending the 3791 * request, or reading the response. If one 3792 * or more entries or references were returned 3793 * before the failure was encountered, then the 3794 * {@code LDAPSearchException} object may be 3795 * examined to obtain information about those 3796 * entries and/or references. 3797 */ 3798 @Override() 3799 @NotNull() 3800 public SearchResult search( 3801 @Nullable final SearchResultListener searchResultListener, 3802 @NotNull final String baseDN, 3803 @NotNull final SearchScope scope, 3804 @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, 3805 final int timeLimit, final boolean typesOnly, 3806 @NotNull final String filter, 3807 @Nullable final String... attributes) 3808 throws LDAPSearchException 3809 { 3810 Validator.ensureNotNull(baseDN, filter); 3811 3812 try 3813 { 3814 return search(new SearchRequest(searchResultListener, baseDN, scope, 3815 derefPolicy, sizeLimit, timeLimit, 3816 typesOnly, filter, attributes)); 3817 } 3818 catch (final LDAPSearchException lse) 3819 { 3820 Debug.debugException(lse); 3821 throw lse; 3822 } 3823 catch (final LDAPException le) 3824 { 3825 Debug.debugException(le); 3826 throw new LDAPSearchException(le); 3827 } 3828 } 3829 3830 3831 3832 /** 3833 * Processes a search operation with the provided information. 3834 * <BR><BR> 3835 * Note that if the search does not complete successfully, an 3836 * {@code LDAPSearchException} will be thrown In some cases, one or more 3837 * search result entries or references may have been returned before the 3838 * failure response is received. In this case, the 3839 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3840 * {@code getSearchEntries}, {@code getReferenceCount}, and 3841 * {@code getSearchReferences} may be used to obtain information about those 3842 * entries and references (although if a search result listener was provided, 3843 * then it will have been used to make any entries and references available, 3844 * and they will not be available through the {@code getSearchEntries} and 3845 * {@code getSearchReferences} methods). 3846 * 3847 * @param searchResultListener The search result listener that should be 3848 * used to return results to the client. It may 3849 * be {@code null} if the search results should 3850 * be collected internally and returned in the 3851 * {@code SearchResult} object. 3852 * @param baseDN The base DN for the search request. It must 3853 * not be {@code null}. 3854 * @param scope The scope that specifies the range of entries 3855 * that should be examined for the search. 3856 * @param derefPolicy The dereference policy the server should use 3857 * for any aliases encountered while processing 3858 * the search. 3859 * @param sizeLimit The maximum number of entries that the server 3860 * should return for the search. A value of 3861 * zero indicates that there should be no limit. 3862 * @param timeLimit The maximum length of time in seconds that 3863 * the server should spend processing this 3864 * search request. A value of zero indicates 3865 * that there should be no limit. 3866 * @param typesOnly Indicates whether to return only attribute 3867 * names in matching entries, or both attribute 3868 * names and values. 3869 * @param filter The filter to use to identify matching 3870 * entries. It must not be {@code null}. 3871 * @param attributes The set of attributes that should be returned 3872 * in matching entries. It may be {@code null} 3873 * or empty if the default attribute set (all 3874 * user attributes) is to be requested. 3875 * 3876 * @return A search result object that provides information about the 3877 * processing of the search, potentially including the set of 3878 * matching entries and search references returned by the server. 3879 * 3880 * @throws LDAPSearchException If the search does not complete successfully, 3881 * or if a problem is encountered while sending 3882 * the request or reading the response. If one 3883 * or more entries or references were returned 3884 * before the failure was encountered, then the 3885 * {@code LDAPSearchException} object may be 3886 * examined to obtain information about those 3887 * entries and/or references. 3888 */ 3889 @Override() 3890 @NotNull() 3891 public SearchResult search( 3892 @Nullable final SearchResultListener searchResultListener, 3893 @NotNull final String baseDN, 3894 @NotNull final SearchScope scope, 3895 @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, 3896 final int timeLimit, final boolean typesOnly, 3897 @NotNull final Filter filter, 3898 @Nullable final String... attributes) 3899 throws LDAPSearchException 3900 { 3901 Validator.ensureNotNull(baseDN, filter); 3902 3903 return search(new SearchRequest(searchResultListener, baseDN, scope, 3904 derefPolicy, sizeLimit, timeLimit, 3905 typesOnly, filter, attributes)); 3906 } 3907 3908 3909 3910 /** 3911 * Processes the provided search request. 3912 * <BR><BR> 3913 * Note that if the search does not complete successfully, an 3914 * {@code LDAPSearchException} will be thrown In some cases, one or more 3915 * search result entries or references may have been returned before the 3916 * failure response is received. In this case, the 3917 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3918 * {@code getSearchEntries}, {@code getReferenceCount}, and 3919 * {@code getSearchReferences} may be used to obtain information about those 3920 * entries and references (although if a search result listener was provided, 3921 * then it will have been used to make any entries and references available, 3922 * and they will not be available through the {@code getSearchEntries} and 3923 * {@code getSearchReferences} methods). 3924 * 3925 * @param searchRequest The search request to be processed. It must not be 3926 * {@code null}. 3927 * 3928 * @return A search result object that provides information about the 3929 * processing of the search, potentially including the set of 3930 * matching entries and search references returned by the server. 3931 * 3932 * @throws LDAPSearchException If the search does not complete successfully, 3933 * or if a problem is encountered while sending 3934 * the request or reading the response. If one 3935 * or more entries or references were returned 3936 * before the failure was encountered, then the 3937 * {@code LDAPSearchException} object may be 3938 * examined to obtain information about those 3939 * entries and/or references. 3940 */ 3941 @Override() 3942 @NotNull() 3943 public SearchResult search(@NotNull final SearchRequest searchRequest) 3944 throws LDAPSearchException 3945 { 3946 Validator.ensureNotNull(searchRequest); 3947 3948 final SearchResult searchResult; 3949 try 3950 { 3951 searchResult = searchRequest.process(this, 1); 3952 } 3953 catch (final LDAPSearchException lse) 3954 { 3955 Debug.debugException(lse); 3956 throw lse; 3957 } 3958 catch (final LDAPException le) 3959 { 3960 Debug.debugException(le); 3961 throw new LDAPSearchException(le); 3962 } 3963 3964 if (! searchResult.getResultCode().equals(ResultCode.SUCCESS)) 3965 { 3966 throw new LDAPSearchException(searchResult); 3967 } 3968 3969 return searchResult; 3970 } 3971 3972 3973 3974 /** 3975 * Processes the provided search request. 3976 * <BR><BR> 3977 * Note that if the search does not complete successfully, an 3978 * {@code LDAPSearchException} will be thrown In some cases, one or more 3979 * search result entries or references may have been returned before the 3980 * failure response is received. In this case, the 3981 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3982 * {@code getSearchEntries}, {@code getReferenceCount}, and 3983 * {@code getSearchReferences} may be used to obtain information about those 3984 * entries and references (although if a search result listener was provided, 3985 * then it will have been used to make any entries and references available, 3986 * and they will not be available through the {@code getSearchEntries} and 3987 * {@code getSearchReferences} methods). 3988 * 3989 * @param searchRequest The search request to be processed. It must not be 3990 * {@code null}. 3991 * 3992 * @return A search result object that provides information about the 3993 * processing of the search, potentially including the set of 3994 * matching entries and search references returned by the server. 3995 * 3996 * @throws LDAPSearchException If the search does not complete successfully, 3997 * or if a problem is encountered while sending 3998 * the request or reading the response. If one 3999 * or more entries or references were returned 4000 * before the failure was encountered, then the 4001 * {@code LDAPSearchException} object may be 4002 * examined to obtain information about those 4003 * entries and/or references. 4004 */ 4005 @Override() 4006 @NotNull() 4007 public SearchResult search(@NotNull final ReadOnlySearchRequest searchRequest) 4008 throws LDAPSearchException 4009 { 4010 return search((SearchRequest) searchRequest); 4011 } 4012 4013 4014 4015 /** 4016 * Processes a search operation with the provided information. It is expected 4017 * that at most one entry will be returned from the search, and that no 4018 * additional content from the successful search result (e.g., diagnostic 4019 * message or response controls) are needed. 4020 * <BR><BR> 4021 * Note that if the search does not complete successfully, an 4022 * {@code LDAPSearchException} will be thrown In some cases, one or more 4023 * search result entries or references may have been returned before the 4024 * failure response is received. In this case, the 4025 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4026 * {@code getSearchEntries}, {@code getReferenceCount}, and 4027 * {@code getSearchReferences} may be used to obtain information about those 4028 * entries and references. 4029 * 4030 * @param baseDN The base DN for the search request. It must not be 4031 * {@code null}. 4032 * @param scope The scope that specifies the range of entries that 4033 * should be examined for the search. 4034 * @param filter The string representation of the filter to use to 4035 * identify matching entries. It must not be 4036 * {@code null}. 4037 * @param attributes The set of attributes that should be returned in 4038 * matching entries. It may be {@code null} or empty if 4039 * the default attribute set (all user attributes) is to 4040 * be requested. 4041 * 4042 * @return The entry that was returned from the search, or {@code null} if no 4043 * entry was returned or the base entry does not exist. 4044 * 4045 * @throws LDAPSearchException If the search does not complete successfully, 4046 * if more than a single entry is returned, or 4047 * if a problem is encountered while parsing the 4048 * provided filter string, sending the request, 4049 * or reading the response. If one or more 4050 * entries or references were returned before 4051 * the failure was encountered, then the 4052 * {@code LDAPSearchException} object may be 4053 * examined to obtain information about those 4054 * entries and/or references. 4055 */ 4056 @Override() 4057 @Nullable() 4058 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 4059 @NotNull final SearchScope scope, 4060 @NotNull final String filter, 4061 @Nullable final String... attributes) 4062 throws LDAPSearchException 4063 { 4064 final SearchRequest r; 4065 try 4066 { 4067 r = new SearchRequest(baseDN, scope, DereferencePolicy.NEVER, 1, 0, false, 4068 filter, attributes); 4069 } 4070 catch (final LDAPException le) 4071 { 4072 Debug.debugException(le); 4073 throw new LDAPSearchException(le); 4074 } 4075 4076 return searchForEntry(r); 4077 } 4078 4079 4080 4081 /** 4082 * Processes a search operation with the provided information. It is expected 4083 * that at most one entry will be returned from the search, and that no 4084 * additional content from the successful search result (e.g., diagnostic 4085 * message or response controls) are needed. 4086 * <BR><BR> 4087 * Note that if the search does not complete successfully, an 4088 * {@code LDAPSearchException} will be thrown In some cases, one or more 4089 * search result entries or references may have been returned before the 4090 * failure response is received. In this case, the 4091 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4092 * {@code getSearchEntries}, {@code getReferenceCount}, and 4093 * {@code getSearchReferences} may be used to obtain information about those 4094 * entries and references. 4095 * 4096 * @param baseDN The base DN for the search request. It must not be 4097 * {@code null}. 4098 * @param scope The scope that specifies the range of entries that 4099 * should be examined for the search. 4100 * @param filter The string representation of the filter to use to 4101 * identify matching entries. It must not be 4102 * {@code null}. 4103 * @param attributes The set of attributes that should be returned in 4104 * matching entries. It may be {@code null} or empty if 4105 * the default attribute set (all user attributes) is to 4106 * be requested. 4107 * 4108 * @return The entry that was returned from the search, or {@code null} if no 4109 * entry was returned or the base entry does not exist. 4110 * 4111 * @throws LDAPSearchException If the search does not complete successfully, 4112 * if more than a single entry is returned, or 4113 * if a problem is encountered while parsing the 4114 * provided filter string, sending the request, 4115 * or reading the response. If one or more 4116 * entries or references were returned before 4117 * the failure was encountered, then the 4118 * {@code LDAPSearchException} object may be 4119 * examined to obtain information about those 4120 * entries and/or references. 4121 */ 4122 @Override() 4123 @Nullable() 4124 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 4125 @NotNull final SearchScope scope, 4126 @NotNull final Filter filter, 4127 @Nullable final String... attributes) 4128 throws LDAPSearchException 4129 { 4130 return searchForEntry(new SearchRequest(baseDN, scope, 4131 DereferencePolicy.NEVER, 1, 0, false, filter, attributes)); 4132 } 4133 4134 4135 4136 /** 4137 * Processes a search operation with the provided information. It is expected 4138 * that at most one entry will be returned from the search, and that no 4139 * additional content from the successful search result (e.g., diagnostic 4140 * message or response controls) are needed. 4141 * <BR><BR> 4142 * Note that if the search does not complete successfully, an 4143 * {@code LDAPSearchException} will be thrown In some cases, one or more 4144 * search result entries or references may have been returned before the 4145 * failure response is received. In this case, the 4146 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4147 * {@code getSearchEntries}, {@code getReferenceCount}, and 4148 * {@code getSearchReferences} may be used to obtain information about those 4149 * entries and references. 4150 * 4151 * @param baseDN The base DN for the search request. It must not be 4152 * {@code null}. 4153 * @param scope The scope that specifies the range of entries that 4154 * should be examined for the search. 4155 * @param derefPolicy The dereference policy the server should use for any 4156 * aliases encountered while processing the search. 4157 * @param timeLimit The maximum length of time in seconds that the server 4158 * should spend processing this search request. A value 4159 * of zero indicates that there should be no limit. 4160 * @param typesOnly Indicates whether to return only attribute names in 4161 * matching entries, or both attribute names and values. 4162 * @param filter The string representation of the filter to use to 4163 * identify matching entries. It must not be 4164 * {@code null}. 4165 * @param attributes The set of attributes that should be returned in 4166 * matching entries. It may be {@code null} or empty if 4167 * the default attribute set (all user attributes) is to 4168 * be requested. 4169 * 4170 * @return The entry that was returned from the search, or {@code null} if no 4171 * entry was returned or the base entry does not exist. 4172 * 4173 * @throws LDAPSearchException If the search does not complete successfully, 4174 * if more than a single entry is returned, or 4175 * if a problem is encountered while parsing the 4176 * provided filter string, sending the request, 4177 * or reading the response. If one or more 4178 * entries or references were returned before 4179 * the failure was encountered, then the 4180 * {@code LDAPSearchException} object may be 4181 * examined to obtain information about those 4182 * entries and/or references. 4183 */ 4184 @Override() 4185 @Nullable() 4186 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 4187 @NotNull final SearchScope scope, 4188 @NotNull final DereferencePolicy derefPolicy, 4189 final int timeLimit, final boolean typesOnly, 4190 @NotNull final String filter, 4191 @Nullable final String... attributes) 4192 throws LDAPSearchException 4193 { 4194 final SearchRequest r; 4195 try 4196 { 4197 r = new SearchRequest(baseDN, scope, derefPolicy, 1, timeLimit, typesOnly, 4198 filter, attributes); 4199 } 4200 catch (final LDAPException le) 4201 { 4202 Debug.debugException(le); 4203 throw new LDAPSearchException(le); 4204 } 4205 4206 return searchForEntry(r); 4207 } 4208 4209 4210 4211 /** 4212 * Processes a search operation with the provided information. It is expected 4213 * that at most one entry will be returned from the search, and that no 4214 * additional content from the successful search result (e.g., diagnostic 4215 * message or response controls) are needed. 4216 * <BR><BR> 4217 * Note that if the search does not complete successfully, an 4218 * {@code LDAPSearchException} will be thrown In some cases, one or more 4219 * search result entries or references may have been returned before the 4220 * failure response is received. In this case, the 4221 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4222 * {@code getSearchEntries}, {@code getReferenceCount}, and 4223 * {@code getSearchReferences} may be used to obtain information about those 4224 * entries and references. 4225 * 4226 * @param baseDN The base DN for the search request. It must not be 4227 * {@code null}. 4228 * @param scope The scope that specifies the range of entries that 4229 * should be examined for the search. 4230 * @param derefPolicy The dereference policy the server should use for any 4231 * aliases encountered while processing the search. 4232 * @param timeLimit The maximum length of time in seconds that the server 4233 * should spend processing this search request. A value 4234 * of zero indicates that there should be no limit. 4235 * @param typesOnly Indicates whether to return only attribute names in 4236 * matching entries, or both attribute names and values. 4237 * @param filter The filter to use to identify matching entries. It 4238 * must not be {@code null}. 4239 * @param attributes The set of attributes that should be returned in 4240 * matching entries. It may be {@code null} or empty if 4241 * the default attribute set (all user attributes) is to 4242 * be requested. 4243 * 4244 * @return The entry that was returned from the search, or {@code null} if no 4245 * entry was returned or the base entry does not exist. 4246 * 4247 * @throws LDAPSearchException If the search does not complete successfully, 4248 * if more than a single entry is returned, or 4249 * if a problem is encountered while parsing the 4250 * provided filter string, sending the request, 4251 * or reading the response. If one or more 4252 * entries or references were returned before 4253 * the failure was encountered, then the 4254 * {@code LDAPSearchException} object may be 4255 * examined to obtain information about those 4256 * entries and/or references. 4257 */ 4258 @Override() 4259 @Nullable() 4260 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 4261 @NotNull final SearchScope scope, 4262 @NotNull final DereferencePolicy derefPolicy, 4263 final int timeLimit, final boolean typesOnly, 4264 @NotNull final Filter filter, 4265 @Nullable final String... attributes) 4266 throws LDAPSearchException 4267 { 4268 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1, 4269 timeLimit, typesOnly, filter, attributes)); 4270 } 4271 4272 4273 4274 /** 4275 * Processes the provided search request. It is expected that at most one 4276 * entry will be returned from the search, and that no additional content from 4277 * the successful search result (e.g., diagnostic message or response 4278 * controls) are needed. 4279 * <BR><BR> 4280 * Note that if the search does not complete successfully, an 4281 * {@code LDAPSearchException} will be thrown In some cases, one or more 4282 * search result entries or references may have been returned before the 4283 * failure response is received. In this case, the 4284 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4285 * {@code getSearchEntries}, {@code getReferenceCount}, and 4286 * {@code getSearchReferences} may be used to obtain information about those 4287 * entries and references. 4288 * 4289 * @param searchRequest The search request to be processed. If it is 4290 * configured with a search result listener or a size 4291 * limit other than one, then the provided request will 4292 * be duplicated with the appropriate settings. 4293 * 4294 * @return The entry that was returned from the search, or {@code null} if no 4295 * entry was returned or the base entry does not exist. 4296 * 4297 * @throws LDAPSearchException If the search does not complete successfully, 4298 * if more than a single entry is returned, or 4299 * if a problem is encountered while parsing the 4300 * provided filter string, sending the request, 4301 * or reading the response. If one or more 4302 * entries or references were returned before 4303 * the failure was encountered, then the 4304 * {@code LDAPSearchException} object may be 4305 * examined to obtain information about those 4306 * entries and/or references. 4307 */ 4308 @Override() 4309 @Nullable() 4310 public SearchResultEntry searchForEntry( 4311 @NotNull final SearchRequest searchRequest) 4312 throws LDAPSearchException 4313 { 4314 final SearchRequest r; 4315 if ((searchRequest.getSearchResultListener() != null) || 4316 (searchRequest.getSizeLimit() != 1)) 4317 { 4318 r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(), 4319 searchRequest.getDereferencePolicy(), 1, 4320 searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(), 4321 searchRequest.getFilter(), searchRequest.getAttributes()); 4322 4323 r.setFollowReferrals(searchRequest.followReferralsInternal()); 4324 r.setReferralConnector(searchRequest.getReferralConnectorInternal()); 4325 r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null)); 4326 4327 if (searchRequest.hasControl()) 4328 { 4329 r.setControlsInternal(searchRequest.getControls()); 4330 } 4331 } 4332 else 4333 { 4334 r = searchRequest; 4335 } 4336 4337 final SearchResult result; 4338 try 4339 { 4340 result = search(r); 4341 } 4342 catch (final LDAPSearchException lse) 4343 { 4344 Debug.debugException(lse); 4345 4346 if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT) 4347 { 4348 return null; 4349 } 4350 4351 throw lse; 4352 } 4353 4354 if (result.getEntryCount() == 0) 4355 { 4356 return null; 4357 } 4358 else 4359 { 4360 return result.getSearchEntries().get(0); 4361 } 4362 } 4363 4364 4365 4366 /** 4367 * Processes the provided search request. It is expected that at most one 4368 * entry will be returned from the search, and that no additional content from 4369 * the successful search result (e.g., diagnostic message or response 4370 * controls) are needed. 4371 * <BR><BR> 4372 * Note that if the search does not complete successfully, an 4373 * {@code LDAPSearchException} will be thrown In some cases, one or more 4374 * search result entries or references may have been returned before the 4375 * failure response is received. In this case, the 4376 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4377 * {@code getSearchEntries}, {@code getReferenceCount}, and 4378 * {@code getSearchReferences} may be used to obtain information about those 4379 * entries and references. 4380 * 4381 * @param searchRequest The search request to be processed. If it is 4382 * configured with a search result listener or a size 4383 * limit other than one, then the provided request will 4384 * be duplicated with the appropriate settings. 4385 * 4386 * @return The entry that was returned from the search, or {@code null} if no 4387 * entry was returned or the base entry does not exist. 4388 * 4389 * @throws LDAPSearchException If the search does not complete successfully, 4390 * if more than a single entry is returned, or 4391 * if a problem is encountered while parsing the 4392 * provided filter string, sending the request, 4393 * or reading the response. If one or more 4394 * entries or references were returned before 4395 * the failure was encountered, then the 4396 * {@code LDAPSearchException} object may be 4397 * examined to obtain information about those 4398 * entries and/or references. 4399 */ 4400 @Override() 4401 @NotNull() 4402 public SearchResultEntry searchForEntry( 4403 @NotNull final ReadOnlySearchRequest searchRequest) 4404 throws LDAPSearchException 4405 { 4406 return searchForEntry((SearchRequest) searchRequest); 4407 } 4408 4409 4410 4411 /** 4412 * Processes the provided search request as an asynchronous operation. 4413 * 4414 * @param searchRequest The search request to be processed. It must not be 4415 * {@code null}, and it must be configured with a 4416 * search result listener that is also an 4417 * {@code AsyncSearchResultListener}. 4418 * 4419 * @return An async request ID that may be used to reference the operation. 4420 * 4421 * @throws LDAPException If the provided search request does not have a 4422 * search result listener that is an 4423 * {@code AsyncSearchResultListener}, or if a problem 4424 * occurs while sending the request. 4425 */ 4426 @NotNull() 4427 public AsyncRequestID asyncSearch(@NotNull final SearchRequest searchRequest) 4428 throws LDAPException 4429 { 4430 Validator.ensureNotNull(searchRequest); 4431 4432 final SearchResultListener searchListener = 4433 searchRequest.getSearchResultListener(); 4434 if (searchListener == null) 4435 { 4436 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 4437 ERR_ASYNC_SEARCH_NO_LISTENER.get()); 4438 Debug.debugCodingError(le); 4439 throw le; 4440 } 4441 else if (! (searchListener instanceof AsyncSearchResultListener)) 4442 { 4443 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 4444 ERR_ASYNC_SEARCH_INVALID_LISTENER.get()); 4445 Debug.debugCodingError(le); 4446 throw le; 4447 } 4448 4449 if (synchronousMode()) 4450 { 4451 throw new LDAPException(ResultCode.NOT_SUPPORTED, 4452 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 4453 } 4454 4455 return searchRequest.processAsync(this, 4456 (AsyncSearchResultListener) searchListener); 4457 } 4458 4459 4460 4461 /** 4462 * Processes the provided search request as an asynchronous operation. 4463 * 4464 * @param searchRequest The search request to be processed. It must not be 4465 * {@code null}, and it must be configured with a 4466 * search result listener that is also an 4467 * {@code AsyncSearchResultListener}. 4468 * 4469 * @return An async request ID that may be used to reference the operation. 4470 * 4471 * @throws LDAPException If the provided search request does not have a 4472 * search result listener that is an 4473 * {@code AsyncSearchResultListener}, or if a problem 4474 * occurs while sending the request. 4475 */ 4476 @NotNull() 4477 public AsyncRequestID asyncSearch( 4478 @NotNull final ReadOnlySearchRequest searchRequest) 4479 throws LDAPException 4480 { 4481 if (synchronousMode()) 4482 { 4483 throw new LDAPException(ResultCode.NOT_SUPPORTED, 4484 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 4485 } 4486 4487 return asyncSearch((SearchRequest) searchRequest); 4488 } 4489 4490 4491 4492 /** 4493 * Processes the provided generic request and returns the result. This may 4494 * be useful for cases in which it is not known what type of operation the 4495 * request represents. 4496 * 4497 * @param request The request to be processed. 4498 * 4499 * @return The result obtained from processing the request. 4500 * 4501 * @throws LDAPException If a problem occurs while sending the request or 4502 * reading the response. Note simply having a 4503 * non-success result code in the response will not 4504 * cause an exception to be thrown. 4505 */ 4506 @NotNull() 4507 public LDAPResult processOperation(@NotNull final LDAPRequest request) 4508 throws LDAPException 4509 { 4510 if (request instanceof BindRequest) 4511 { 4512 // Bind request special processing. 4513 return processBindOperation((BindRequest) request); 4514 } 4515 else 4516 { 4517 return request.process(this, 1); 4518 } 4519 } 4520 4521 4522 4523 /** 4524 * Processes the provided bind request and returns the result. This will also 4525 * ensure that any appropriate updates are made to the last bind request and 4526 * cached schema. 4527 * 4528 * @param bindRequest The bind request to be processed. 4529 * 4530 * @return The result obtained from processing the request. 4531 * 4532 * @throws LDAPException If a problem occurs while sending the request or 4533 * reading the response. Note simply having a 4534 * non-success result code in the response will not 4535 * cause an exception to be thrown. 4536 */ 4537 @NotNull() 4538 private BindResult processBindOperation( 4539 @NotNull final BindRequest bindRequest) 4540 throws LDAPException 4541 { 4542 // We don't want to update the last bind request or update the cached 4543 // schema for this connection if it included the retain identity control. 4544 boolean hasRetainIdentityControl = false; 4545 for (final Control c : bindRequest.getControls()) 4546 { 4547 if (c.getOID().equals( 4548 RetainIdentityRequestControl.RETAIN_IDENTITY_REQUEST_OID)) 4549 { 4550 hasRetainIdentityControl = true; 4551 break; 4552 } 4553 } 4554 4555 if (! hasRetainIdentityControl) 4556 { 4557 lastBindRequest = null; 4558 } 4559 4560 final BindResult bindResult = bindRequest.process(this, 1); 4561 if (bindResult.getResultCode().equals(ResultCode.SUCCESS)) 4562 { 4563 if (! hasRetainIdentityControl) 4564 { 4565 lastBindRequest = bindRequest; 4566 if (connectionOptions.useSchema()) 4567 { 4568 try 4569 { 4570 cachedSchema = getCachedSchema(this); 4571 } 4572 catch (final Exception e) 4573 { 4574 Debug.debugException(e); 4575 } 4576 } 4577 } 4578 } 4579 4580 return bindResult; 4581 } 4582 4583 4584 4585 /** 4586 * Retrieves the referral connector that should be used to establish 4587 * connections for use when following referrals. 4588 * 4589 * @return The referral connector that should be used to establish 4590 * connections for use when following referrals. 4591 */ 4592 @NotNull() 4593 public ReferralConnector getReferralConnector() 4594 { 4595 if (referralConnector == null) 4596 { 4597 return this; 4598 } 4599 else 4600 { 4601 return referralConnector; 4602 } 4603 } 4604 4605 4606 4607 /** 4608 * Specifies the referral connector that should be used to establish 4609 * connections for use when following referrals. 4610 * 4611 * @param referralConnector The referral connector that should be used to 4612 * establish connections for use when following 4613 * referrals. 4614 */ 4615 public void setReferralConnector( 4616 @Nullable final ReferralConnector referralConnector) 4617 { 4618 if (referralConnector == null) 4619 { 4620 this.referralConnector = this; 4621 } 4622 else 4623 { 4624 this.referralConnector = referralConnector; 4625 } 4626 } 4627 4628 4629 4630 /** 4631 * Sends the provided LDAP message to the server over this connection. 4632 * 4633 * @param message The LDAP message to send to the target server. 4634 * @param sendTimeoutMillis The maximum length of time, in milliseconds, to 4635 * block while trying to send the request. If this 4636 * is less than or equal to zero, then no send 4637 * timeout will be enforced. 4638 * 4639 * @throws LDAPException If a problem occurs while sending the request. 4640 */ 4641 void sendMessage(@NotNull final LDAPMessage message, 4642 final long sendTimeoutMillis) 4643 throws LDAPException 4644 { 4645 if (needsReconnect.compareAndSet(true, false)) 4646 { 4647 reconnect(); 4648 } 4649 4650 final LDAPConnectionInternals internals = connectionInternals; 4651 if (internals == null) 4652 { 4653 throw new LDAPException(ResultCode.SERVER_DOWN, 4654 ERR_CONN_NOT_ESTABLISHED.get()); 4655 } 4656 else 4657 { 4658 @SuppressWarnings("deprecation") 4659 final boolean autoReconnect = connectionOptions.autoReconnect(); 4660 internals.sendMessage(message, sendTimeoutMillis, autoReconnect); 4661 lastCommunicationTime = System.currentTimeMillis(); 4662 } 4663 } 4664 4665 4666 4667 /** 4668 * Retrieves the message ID that should be used for the next request sent 4669 * over this connection. 4670 * 4671 * @return The message ID that should be used for the next request sent over 4672 * this connection, or -1 if this connection is not established. 4673 */ 4674 int nextMessageID() 4675 { 4676 final LDAPConnectionInternals internals = connectionInternals; 4677 if (internals == null) 4678 { 4679 return -1; 4680 } 4681 else 4682 { 4683 return internals.nextMessageID(); 4684 } 4685 } 4686 4687 4688 4689 /** 4690 * Retrieves the disconnect info object for this connection, if available. 4691 * 4692 * @return The disconnect info for this connection, or {@code null} if none 4693 * is set. 4694 */ 4695 @Nullable() 4696 DisconnectInfo getDisconnectInfo() 4697 { 4698 return disconnectInfo.get(); 4699 } 4700 4701 4702 4703 /** 4704 * Sets the disconnect type, message, and cause for this connection, if those 4705 * values have not been previously set. It will not overwrite any values that 4706 * had been previously set. 4707 * <BR><BR> 4708 * This method may be called by code which is not part of the LDAP SDK to 4709 * provide additional information about the reason for the closure. In that 4710 * case, this method must be called before the call to 4711 * {@link LDAPConnection#close}. 4712 * 4713 * @param type The disconnect type. It must not be {@code null}. 4714 * @param message A message providing additional information about the 4715 * disconnect. It may be {@code null} if no message is 4716 * available. 4717 * @param cause The exception that was caught to trigger the disconnect. 4718 * It may be {@code null} if the disconnect was not triggered 4719 * by an exception. 4720 */ 4721 public void setDisconnectInfo(@NotNull final DisconnectType type, 4722 @Nullable final String message, 4723 @Nullable final Throwable cause) 4724 { 4725 disconnectInfo.compareAndSet(null, 4726 new DisconnectInfo(this, type, message, cause)); 4727 } 4728 4729 4730 4731 /** 4732 * Sets the disconnect info for this connection, if it is not already set. 4733 * 4734 * @param info The disconnect info to be set, if it is not already set. 4735 * 4736 * @return The disconnect info set for the connection, whether it was 4737 * previously or newly set. 4738 */ 4739 @Nullable() 4740 DisconnectInfo setDisconnectInfo(@Nullable final DisconnectInfo info) 4741 { 4742 disconnectInfo.compareAndSet(null, info); 4743 return disconnectInfo.get(); 4744 } 4745 4746 4747 4748 /** 4749 * {@inheritDoc} 4750 */ 4751 @Override() 4752 @Nullable() 4753 public DisconnectType getDisconnectType() 4754 { 4755 final DisconnectInfo di = disconnectInfo.get(); 4756 if (di == null) 4757 { 4758 return null; 4759 } 4760 else 4761 { 4762 return di.getType(); 4763 } 4764 } 4765 4766 4767 4768 /** 4769 * {@inheritDoc} 4770 */ 4771 @Override() 4772 @Nullable() 4773 public String getDisconnectMessage() 4774 { 4775 final DisconnectInfo di = disconnectInfo.get(); 4776 if (di == null) 4777 { 4778 return null; 4779 } 4780 else 4781 { 4782 return di.getMessage(); 4783 } 4784 } 4785 4786 4787 4788 /** 4789 * {@inheritDoc} 4790 */ 4791 @Override() 4792 @Nullable() 4793 public Throwable getDisconnectCause() 4794 { 4795 final DisconnectInfo di = disconnectInfo.get(); 4796 if (di == null) 4797 { 4798 return null; 4799 } 4800 else 4801 { 4802 return di.getCause(); 4803 } 4804 } 4805 4806 4807 4808 /** 4809 * Indicates that this connection has been closed and is no longer available 4810 * for use. 4811 */ 4812 void setClosed() 4813 { 4814 needsReconnect.set(false); 4815 4816 if (disconnectInfo.get() == null) 4817 { 4818 try 4819 { 4820 final StackTraceElement[] stackElements = 4821 Thread.currentThread().getStackTrace(); 4822 final StackTraceElement[] parentStackElements = 4823 new StackTraceElement[stackElements.length - 1]; 4824 System.arraycopy(stackElements, 1, parentStackElements, 0, 4825 parentStackElements.length); 4826 4827 setDisconnectInfo(DisconnectType.OTHER, 4828 ERR_CONN_CLOSED_BY_UNEXPECTED_CALL_PATH.get( 4829 StaticUtils.getStackTrace(parentStackElements)), 4830 null); 4831 } 4832 catch (final Exception e) 4833 { 4834 Debug.debugException(e); 4835 } 4836 } 4837 4838 connectionStatistics.incrementNumDisconnects(); 4839 final LDAPConnectionInternals internals = connectionInternals; 4840 if (internals != null) 4841 { 4842 internals.close(); 4843 connectionInternals = null; 4844 } 4845 4846 cachedSchema = null; 4847 lastCommunicationTime = -1L; 4848 4849 synchronized (this) 4850 { 4851 final Timer t = timer; 4852 timer = null; 4853 4854 if (t != null) 4855 { 4856 t.cancel(); 4857 } 4858 } 4859 } 4860 4861 4862 4863 /** 4864 * Registers the provided response acceptor with the connection reader. 4865 * 4866 * @param messageID The message ID for which the acceptor is to be 4867 * registered. 4868 * @param responseAcceptor The response acceptor to register. 4869 * 4870 * @throws LDAPException If another message acceptor is already registered 4871 * with the provided message ID. 4872 */ 4873 void registerResponseAcceptor(final int messageID, 4874 @NotNull final ResponseAcceptor responseAcceptor) 4875 throws LDAPException 4876 { 4877 if (needsReconnect.compareAndSet(true, false)) 4878 { 4879 reconnect(); 4880 } 4881 4882 final LDAPConnectionInternals internals = connectionInternals; 4883 if (internals == null) 4884 { 4885 throw new LDAPException(ResultCode.SERVER_DOWN, 4886 ERR_CONN_NOT_ESTABLISHED.get()); 4887 } 4888 else 4889 { 4890 internals.registerResponseAcceptor(messageID, responseAcceptor); 4891 } 4892 } 4893 4894 4895 4896 /** 4897 * Deregisters the response acceptor associated with the provided message ID. 4898 * 4899 * @param messageID The message ID for which to deregister the associated 4900 * response acceptor. 4901 */ 4902 void deregisterResponseAcceptor(final int messageID) 4903 { 4904 final LDAPConnectionInternals internals = connectionInternals; 4905 if (internals != null) 4906 { 4907 internals.deregisterResponseAcceptor(messageID); 4908 } 4909 } 4910 4911 4912 4913 /** 4914 * Retrieves a timer for use with this connection, creating one if necessary. 4915 * 4916 * @return A timer for use with this connection. 4917 * 4918 * @throws LDAPException If the connection has been closed. 4919 */ 4920 @NotNull() 4921 Timer getTimer() 4922 throws LDAPException 4923 { 4924 final Timer t = getTimerNullable(); 4925 if (t == null) 4926 { 4927 throw new LDAPException(ResultCode.SERVER_DOWN, 4928 ERR_CONN_NOT_ESTABLISHED.get()); 4929 } 4930 else 4931 { 4932 return t; 4933 } 4934 } 4935 4936 4937 4938 /** 4939 * Retrieves a timer for use with this connection, creating one if necessary 4940 * and the connection is established. 4941 * 4942 * @return A timer for use with this connection, or {@code null} if the 4943 * connection is not established. 4944 */ 4945 @Nullable() 4946 synchronized Timer getTimerNullable() 4947 { 4948 if (timer == null) 4949 { 4950 if (closeRequested || (connectionInternals == null)) 4951 { 4952 return null; 4953 } 4954 4955 timer = new Timer("Timer thread for " + toString(), true); 4956 } 4957 4958 return timer; 4959 } 4960 4961 4962 4963 /** 4964 * {@inheritDoc} 4965 */ 4966 @Override() 4967 @NotNull() 4968 public LDAPConnection getReferralConnection( 4969 @NotNull final LDAPURL referralURL, 4970 @NotNull final LDAPConnection connection) 4971 throws LDAPException 4972 { 4973 final String host = referralURL.getHost(); 4974 final int port = referralURL.getPort(); 4975 4976 BindRequest bindRequest = null; 4977 if (connection.lastBindRequest != null) 4978 { 4979 bindRequest = connection.lastBindRequest.getRebindRequest(host, port); 4980 if (bindRequest == null) 4981 { 4982 throw new LDAPException(ResultCode.REFERRAL, 4983 ERR_CONN_CANNOT_AUTHENTICATE_FOR_REFERRAL.get( 4984 host, port)); 4985 } 4986 } 4987 4988 final ExtendedRequest connStartTLSRequest = connection.startTLSRequest; 4989 4990 final LDAPConnection conn = new LDAPConnection(connection.socketFactory, 4991 connection.connectionOptions, host, port); 4992 4993 if (connStartTLSRequest != null) 4994 { 4995 try 4996 { 4997 final ExtendedResult startTLSResult = 4998 conn.processExtendedOperation(connStartTLSRequest); 4999 if (startTLSResult.getResultCode() != ResultCode.SUCCESS) 5000 { 5001 throw new LDAPException(startTLSResult); 5002 } 5003 } 5004 catch (final LDAPException le) 5005 { 5006 Debug.debugException(le); 5007 conn.setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le); 5008 conn.close(); 5009 5010 throw le; 5011 } 5012 } 5013 5014 if (bindRequest != null) 5015 { 5016 try 5017 { 5018 conn.bind(bindRequest); 5019 } 5020 catch (final LDAPException le) 5021 { 5022 Debug.debugException(le); 5023 conn.setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); 5024 conn.close(); 5025 5026 throw le; 5027 } 5028 } 5029 5030 return conn; 5031 } 5032 5033 5034 5035 /** 5036 * {@inheritDoc} 5037 */ 5038 @Override() 5039 @Nullable() 5040 public BindRequest getLastBindRequest() 5041 { 5042 return lastBindRequest; 5043 } 5044 5045 5046 5047 /** 5048 * {@inheritDoc} 5049 */ 5050 @Override() 5051 @Nullable() 5052 public ExtendedRequest getStartTLSRequest() 5053 { 5054 return startTLSRequest; 5055 } 5056 5057 5058 5059 /** 5060 * Retrieves an instance of the {@code LDAPConnectionInternals} object for 5061 * this connection. 5062 * 5063 * @param throwIfDisconnected Indicates whether to throw an 5064 * {@code LDAPException} if the connection is not 5065 * established. 5066 * 5067 * @return The {@code LDAPConnectionInternals} object for this connection, or 5068 * {@code null} if the connection is not established and no exception 5069 * should be thrown. 5070 * 5071 * @throws LDAPException If the connection is not established and 5072 * {@code throwIfDisconnected} is {@code true}. 5073 */ 5074 @Nullable() 5075 LDAPConnectionInternals getConnectionInternals( 5076 final boolean throwIfDisconnected) 5077 throws LDAPException 5078 { 5079 final LDAPConnectionInternals internals = connectionInternals; 5080 if ((internals == null) && throwIfDisconnected) 5081 { 5082 throw new LDAPException(ResultCode.SERVER_DOWN, 5083 ERR_CONN_NOT_ESTABLISHED.get()); 5084 } 5085 else 5086 { 5087 return internals; 5088 } 5089 } 5090 5091 5092 5093 /** 5094 * Retrieves the cached schema for this connection, if applicable. 5095 * 5096 * @return The cached schema for this connection, or {@code null} if it is 5097 * not available (e.g., because the connection is not established, 5098 * because {@link LDAPConnectionOptions#useSchema()} is false, or 5099 * because an error occurred when trying to read the server schema). 5100 */ 5101 @Nullable() 5102 Schema getCachedSchema() 5103 { 5104 return cachedSchema; 5105 } 5106 5107 5108 5109 /** 5110 * Sets the cached schema for this connection. 5111 * 5112 * @param cachedSchema The cached schema for this connection. It may be 5113 * {@code null} if no cached schema is available. 5114 */ 5115 void setCachedSchema(@Nullable final Schema cachedSchema) 5116 { 5117 this.cachedSchema = cachedSchema; 5118 } 5119 5120 5121 5122 /** 5123 * {@inheritDoc} 5124 */ 5125 @Override() 5126 public boolean synchronousMode() 5127 { 5128 final LDAPConnectionInternals internals = connectionInternals; 5129 if (internals == null) 5130 { 5131 return false; 5132 } 5133 else 5134 { 5135 return internals.synchronousMode(); 5136 } 5137 } 5138 5139 5140 5141 /** 5142 * Reads a response from the server, blocking if necessary until the response 5143 * has been received. This should only be used for connections operating in 5144 * synchronous mode. 5145 * 5146 * @param messageID The message ID for the response to be read. Any 5147 * response read with a different message ID will be 5148 * discarded, unless it is an unsolicited notification in 5149 * which case it will be provided to any registered 5150 * unsolicited notification handler. 5151 * 5152 * @return The response read from the server. 5153 * 5154 * @throws LDAPException If a problem occurs while reading the response. 5155 */ 5156 @NotNull() 5157 LDAPResponse readResponse(final int messageID) 5158 throws LDAPException 5159 { 5160 final LDAPConnectionInternals internals = connectionInternals; 5161 if (internals != null) 5162 { 5163 final LDAPResponse response = 5164 internals.getConnectionReader().readResponse(messageID); 5165 Debug.debugLDAPResult(response, this); 5166 internals.getConnectionReader().logResponse(response); 5167 return response; 5168 } 5169 else 5170 { 5171 final DisconnectInfo di = disconnectInfo.get(); 5172 if (di == null) 5173 { 5174 return new ConnectionClosedResponse(ResultCode.CONNECT_ERROR, 5175 ERR_CONN_READ_RESPONSE_NOT_ESTABLISHED.get()); 5176 } 5177 else 5178 { 5179 return new ConnectionClosedResponse(di.getType().getResultCode(), 5180 di.getMessage()); 5181 } 5182 } 5183 } 5184 5185 5186 5187 /** 5188 * {@inheritDoc} 5189 */ 5190 @Override() 5191 public long getConnectTime() 5192 { 5193 final LDAPConnectionInternals internals = connectionInternals; 5194 if (internals != null) 5195 { 5196 return internals.getConnectTime(); 5197 } 5198 else 5199 { 5200 return -1L; 5201 } 5202 } 5203 5204 5205 5206 /** 5207 * {@inheritDoc} 5208 */ 5209 @Override() 5210 public long getLastCommunicationTime() 5211 { 5212 if (lastCommunicationTime > 0L) 5213 { 5214 return lastCommunicationTime; 5215 } 5216 else 5217 { 5218 return getConnectTime(); 5219 } 5220 } 5221 5222 5223 5224 /** 5225 * Updates the last communication time for this connection to be the current 5226 * time. 5227 */ 5228 void setLastCommunicationTime() 5229 { 5230 lastCommunicationTime = System.currentTimeMillis(); 5231 } 5232 5233 5234 5235 /** 5236 * {@inheritDoc} 5237 */ 5238 @Override() 5239 @NotNull() 5240 public LDAPConnectionStatistics getConnectionStatistics() 5241 { 5242 return connectionStatistics; 5243 } 5244 5245 5246 5247 /** 5248 * {@inheritDoc} 5249 */ 5250 @Override() 5251 public int getActiveOperationCount() 5252 { 5253 final LDAPConnectionInternals internals = connectionInternals; 5254 5255 if (internals == null) 5256 { 5257 return -1; 5258 } 5259 else 5260 { 5261 if (internals.synchronousMode()) 5262 { 5263 return -1; 5264 } 5265 else 5266 { 5267 return internals.getConnectionReader().getActiveOperationCount(); 5268 } 5269 } 5270 } 5271 5272 5273 5274 /** 5275 * Retrieves the schema from the provided connection. If the retrieved schema 5276 * matches schema that's already in use by other connections, the common 5277 * schema will be used instead of the newly-retrieved version. 5278 * 5279 * @param c The connection for which to retrieve the schema. 5280 * 5281 * @return The schema retrieved from the given connection, or a cached 5282 * schema if it matched a schema that was already in use. 5283 * 5284 * @throws LDAPException If a problem is encountered while retrieving or 5285 * parsing the schema. 5286 */ 5287 @Nullable() 5288 private static Schema getCachedSchema(@NotNull final LDAPConnection c) 5289 throws LDAPException 5290 { 5291 final Schema s = c.getSchema(); 5292 5293 synchronized (SCHEMA_SET) 5294 { 5295 return SCHEMA_SET.addAndGet(s); 5296 } 5297 } 5298 5299 5300 5301 /** 5302 * Retrieves the connection attachment with the specified name. 5303 * 5304 * @param name The name of the attachment to retrieve. It must not be 5305 * {@code null}. 5306 * 5307 * @return The connection attachment with the specified name, or {@code null} 5308 * if there is no such attachment. 5309 */ 5310 @Nullable() 5311 synchronized Object getAttachment(@NotNull final String name) 5312 { 5313 if (attachments == null) 5314 { 5315 return null; 5316 } 5317 else 5318 { 5319 return attachments.get(name); 5320 } 5321 } 5322 5323 5324 5325 /** 5326 * Sets a connection attachment with the specified name and value. 5327 * 5328 * @param name The name of the attachment to set. It must not be 5329 * {@code null}. 5330 * @param value The value to use for the attachment. It may be {@code null} 5331 * if an attachment with the specified name should be cleared 5332 * rather than overwritten. 5333 */ 5334 synchronized void setAttachment(@NotNull final String name, 5335 @Nullable final Object value) 5336 { 5337 if (attachments == null) 5338 { 5339 attachments = new HashMap<>(StaticUtils.computeMapCapacity(10)); 5340 } 5341 5342 if (value == null) 5343 { 5344 attachments.remove(name); 5345 } 5346 else 5347 { 5348 attachments.put(name, value); 5349 } 5350 } 5351 5352 5353 5354 /** 5355 * Performs any necessary cleanup to ensure that this connection is properly 5356 * closed before it is garbage collected. 5357 * 5358 * @throws Throwable If the superclass finalizer throws an exception. 5359 */ 5360 @Override() 5361 protected void finalize() 5362 throws Throwable 5363 { 5364 super.finalize(); 5365 5366 setDisconnectInfo(DisconnectType.CLOSED_BY_FINALIZER, null, null); 5367 setClosed(); 5368 } 5369 5370 5371 5372 /** 5373 * {@inheritDoc} 5374 */ 5375 @Override() 5376 @NotNull() 5377 public String toString() 5378 { 5379 final StringBuilder buffer = new StringBuilder(); 5380 toString(buffer); 5381 return buffer.toString(); 5382 } 5383 5384 5385 5386 /** 5387 * {@inheritDoc} 5388 */ 5389 @Override() 5390 public void toString(@NotNull final StringBuilder buffer) 5391 { 5392 buffer.append("LDAPConnection("); 5393 5394 final String name = connectionName; 5395 final String poolName = connectionPoolName; 5396 if (name != null) 5397 { 5398 buffer.append("name='"); 5399 buffer.append(name); 5400 buffer.append("', "); 5401 } 5402 else if (poolName != null) 5403 { 5404 buffer.append("poolName='"); 5405 buffer.append(poolName); 5406 buffer.append("', "); 5407 } 5408 5409 final LDAPConnectionInternals internals = connectionInternals; 5410 if ((internals != null) && internals.isConnected()) 5411 { 5412 buffer.append("connected to "); 5413 buffer.append(internals.getHost()); 5414 buffer.append(':'); 5415 buffer.append(internals.getPort()); 5416 } 5417 else 5418 { 5419 buffer.append("not connected"); 5420 } 5421 5422 buffer.append(')'); 5423 } 5424}