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