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