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