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