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.net.InetAddress; 026import java.net.Socket; 027import java.util.Collection; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031import java.util.Timer; 032import java.util.concurrent.atomic.AtomicBoolean; 033import java.util.concurrent.atomic.AtomicLong; 034import java.util.concurrent.atomic.AtomicReference; 035import java.util.logging.Level; 036import javax.net.SocketFactory; 037import javax.net.ssl.SSLSession; 038import javax.net.ssl.SSLSocket; 039import javax.net.ssl.SSLSocketFactory; 040import javax.security.sasl.SaslClient; 041 042import com.unboundid.asn1.ASN1OctetString; 043import com.unboundid.ldap.protocol.AbandonRequestProtocolOp; 044import com.unboundid.ldap.protocol.LDAPMessage; 045import com.unboundid.ldap.protocol.LDAPResponse; 046import com.unboundid.ldap.protocol.UnbindRequestProtocolOp; 047import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest; 048import com.unboundid.ldap.sdk.schema.Schema; 049import com.unboundid.ldif.LDIFException; 050import com.unboundid.util.DebugType; 051import com.unboundid.util.SynchronizedSocketFactory; 052import com.unboundid.util.SynchronizedSSLSocketFactory; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055import com.unboundid.util.WeakHashSet; 056 057import static com.unboundid.ldap.sdk.LDAPMessages.*; 058import static com.unboundid.util.Debug.*; 059import static com.unboundid.util.StaticUtils.*; 060import static com.unboundid.util.Validator.*; 061 062 063 064/** 065 * This class provides a facility for interacting with an LDAPv3 directory 066 * server. It provides a means of establishing a connection to the server, 067 * sending requests, and reading responses. See 068 * <A HREF="http://www.ietf.org/rfc/rfc4511.txt">RFC 4511</A> for the LDAPv3 069 * protocol specification and more information about the types of operations 070 * defined in LDAP. 071 * <BR><BR> 072 * <H2>Creating, Establishing, and Authenticating Connections</H2> 073 * An LDAP connection can be established either at the time that the object is 074 * created or as a separate step. Similarly, authentication can be performed on 075 * the connection at the time it is created, at the time it is established, or 076 * as a separate process. For example: 077 * <BR><BR> 078 * <PRE> 079 * // Create a new, unestablished connection. Then connect and perform a 080 * // simple bind as separate operations. 081 * LDAPConnection c = new LDAPConnection(); 082 * c.connect(address, port); 083 * BindResult bindResult = c.bind(bindDN, password); 084 * 085 * // Create a new connection that is established at creation time, and then 086 * // authenticate separately using simple authentication. 087 * LDAPConnection c = new LDAPConnection(address, port); 088 * BindResult bindResult = c.bind(bindDN, password); 089 * 090 * // Create a new connection that is established and bound using simple 091 * // authentication all in one step. 092 * LDAPConnection c = new LDAPConnection(address, port, bindDN, password); 093 * </PRE> 094 * <BR><BR> 095 * When authentication is performed at the time that the connection is 096 * established, it is only possible to perform a simple bind and it is not 097 * possible to include controls in the bind request, nor is it possible to 098 * receive response controls if the bind was successful. Therefore, it is 099 * recommended that authentication be performed as a separate step if the server 100 * may return response controls even in the event of a successful authentication 101 * (e.g., a control that may indicate that the user's password will soon 102 * expire). See the {@link BindRequest} class for more information about 103 * authentication in the UnboundID LDAP SDK for Java. 104 * <BR><BR> 105 * By default, connections will use standard unencrypted network sockets. 106 * However, it may be desirable to create connections that use SSL/TLS to 107 * encrypt communication. This can be done by specifying a 108 * {@link javax.net.SocketFactory} that should be used to create the socket to 109 * use to communicate with the directory server. The 110 * {@link javax.net.ssl.SSLSocketFactory#getDefault} method or the 111 * {@link javax.net.ssl.SSLContext#getSocketFactory} method may be used to 112 * obtain a socket factory for performing SSL communication. See the 113 * <A HREF= 114 * "http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html"> 115 * JSSE Reference Guide</A> for more information on using these classes. 116 * Alternately, you may use the {@link com.unboundid.util.ssl.SSLUtil} class to 117 * simplify the process. 118 * <BR><BR> 119 * Whenever the connection is no longer needed, it may be terminated using the 120 * {@link LDAPConnection#close} method. 121 * <BR><BR> 122 * <H2>Processing LDAP Operations</H2> 123 * This class provides a number of methods for processing the different types of 124 * operations. The types of operations that can be processed include: 125 * <UL> 126 * <LI>Abandon -- This may be used to request that the server stop processing 127 * on an operation that has been invoked asynchronously.</LI> 128 * <LI>Add -- This may be used to add a new entry to the directory 129 * server. See the {@link AddRequest} class for more information about 130 * processing add operations.</LI> 131 * <LI>Bind -- This may be used to authenticate to the directory server. See 132 * the {@link BindRequest} class for more information about processing 133 * bind operations.</LI> 134 * <LI>Compare -- This may be used to determine whether a specified entry has 135 * a given attribute value. See the {@link CompareRequest} class for more 136 * information about processing compare operations.</LI> 137 * <LI>Delete -- This may be used to remove an entry from the directory 138 * server. See the {@link DeleteRequest} class for more information about 139 * processing delete operations.</LI> 140 * <LI>Extended -- This may be used to process an operation which is not 141 * part of the core LDAP protocol but is a custom extension supported by 142 * the directory server. See the {@link ExtendedRequest} class for more 143 * information about processing extended operations.</LI> 144 * <LI>Modify -- This may be used to alter an entry in the directory 145 * server. See the {@link ModifyRequest} class for more information about 146 * processing modify operations.</LI> 147 * <LI>Modify DN -- This may be used to rename an entry or subtree and/or move 148 * that entry or subtree below a new parent in the directory server. See 149 * the {@link ModifyDNRequest} class for more information about processing 150 * modify DN operations.</LI> 151 * <LI>Search -- This may be used to retrieve a set of entries in the server 152 * that match a given set of criteria. See the {@link SearchRequest} 153 * class for more information about processing search operations.</LI> 154 * </UL> 155 * <BR><BR> 156 * Most of the methods in this class used to process operations operate in a 157 * synchronous manner. In these cases, the SDK will send a request to the 158 * server and wait for a response to arrive before returning to the caller. In 159 * these cases, the value returned will include the contents of that response, 160 * including the result code, diagnostic message, matched DN, referral URLs, and 161 * any controls that may have been included. However, it also possible to 162 * process operations asynchronously, in which case the SDK will return control 163 * back to the caller after the request has been sent to the server but before 164 * the response has been received. In this case, the SDK will return an 165 * {@link AsyncRequestID} object which may be used to later abandon or cancel 166 * that operation if necessary, and will notify the client when the response 167 * arrives via a listener interface. 168 * <BR><BR> 169 * This class is mostly threadsafe. It is possible to process multiple 170 * concurrent operations over the same connection as long as the methods being 171 * invoked will not change the state of the connection in a way that might 172 * impact other operations in progress in unexpected ways. In particular, the 173 * following should not be attempted while any other operations may be in 174 * progress on this connection: 175 * <UL> 176 * <LI> 177 * Using one of the {@code connect} methods to re-establish the connection. 178 * </LI> 179 * <LI> 180 * Using one of the {@code close} methods to terminate the connection. 181 * </LI> 182 * <LI> 183 * Using one of the {@code bind} methods to attempt to authenticate the 184 * connection (unless you are certain that the bind will not impact the 185 * identity of the associated connection, for example by including the 186 * retain identity request control in the bind request if using the 187 * Commercial Edition of the LDAP SDK in conjunction with an UnboundID 188 * Directory Server). 189 * </LI> 190 * <LI> 191 * Attempting to make a change to the way that the underlying communication 192 * is processed (e.g., by using the StartTLS extended operation to convert 193 * an insecure connection into a secure one). 194 * </LI> 195 * </UL> 196 */ 197@ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE) 198public final class LDAPConnection 199 implements LDAPInterface, ReferralConnector 200{ 201 /** 202 * The counter that will be used when assigning connection IDs to connections. 203 */ 204 private static final AtomicLong NEXT_CONNECTION_ID = new AtomicLong(0L); 205 206 207 208 /** 209 * The default socket factory that will be used if no alternate factory is 210 * provided. 211 */ 212 private static final SocketFactory DEFAULT_SOCKET_FACTORY = 213 SocketFactory.getDefault(); 214 215 216 217 /** 218 * A set of weak references to schema objects that can be shared across 219 * connections if they are identical. 220 */ 221 private static final WeakHashSet<Schema> SCHEMA_SET = 222 new WeakHashSet<Schema>(); 223 224 225 226 // The connection pool with which this connection is associated, if 227 // applicable. 228 private AbstractConnectionPool connectionPool; 229 230 // Indicates whether to perform a reconnect before the next write. 231 private final AtomicBoolean needsReconnect; 232 233 // The disconnect information for this connection. 234 private final AtomicReference<DisconnectInfo> disconnectInfo; 235 236 // The last successful bind request processed on this connection. 237 private volatile BindRequest lastBindRequest; 238 239 // Indicates whether a request has been made to close this connection. 240 private volatile boolean closeRequested; 241 242 // Indicates whether an unbind request has been sent over this connection. 243 private volatile boolean unbindRequestSent; 244 245 // The extended request used to initiate StartTLS on this connection. 246 private volatile ExtendedRequest startTLSRequest; 247 248 // The port of the server to which a connection should be re-established. 249 private int reconnectPort = -1; 250 251 // The connection internals used to actually perform the network 252 // communication. 253 private volatile LDAPConnectionInternals connectionInternals; 254 255 // The set of connection options for this connection. 256 private LDAPConnectionOptions connectionOptions; 257 258 // The set of statistics for this connection. 259 private final LDAPConnectionStatistics connectionStatistics; 260 261 // The unique identifier assigned to this connection when it was created. It 262 // will not change over the life of the connection, even if the connection is 263 // closed and re-established (or even re-established to a different server). 264 private final long connectionID; 265 266 // The time of the last rebind attempt. 267 private long lastReconnectTime; 268 269 // The most recent time that an LDAP message was sent or received on this 270 // connection. 271 private volatile long lastCommunicationTime; 272 273 // A map in which arbitrary attachments may be stored or managed. 274 private Map<String,Object> attachments; 275 276 // The referral connector that will be used to establish connections to remote 277 // servers when following a referral. 278 private volatile ReferralConnector referralConnector; 279 280 // The cached schema read from the server. 281 private volatile Schema cachedSchema; 282 283 // The socket factory used for the last connection attempt. 284 private SocketFactory lastUsedSocketFactory; 285 286 // The socket factory used to create sockets for subsequent connection 287 // attempts. 288 private volatile SocketFactory socketFactory; 289 290 // A stack trace of the thread that last established this connection. 291 private StackTraceElement[] connectStackTrace; 292 293 // The user-friendly name assigned to this connection. 294 private String connectionName; 295 296 // The user-friendly name assigned to the connection pool with which this 297 // connection is associated. 298 private String connectionPoolName; 299 300 // A string representation of the host and port to which the last connection 301 // attempt (whether successful or not, and whether it is still established) 302 // was made. 303 private String hostPort; 304 305 // The address of the server to which a connection should be re-established. 306 private String reconnectAddress; 307 308 // A timer that may be used to enforce timeouts for asynchronous operations. 309 private Timer timer; 310 311 312 313 /** 314 * Creates a new LDAP connection using the default socket factory and default 315 * set of connection options. No actual network connection will be 316 * established. 317 */ 318 public LDAPConnection() 319 { 320 this(null, null); 321 } 322 323 324 325 /** 326 * Creates a new LDAP connection using the default socket factory and provided 327 * set of connection options. No actual network connection will be 328 * established. 329 * 330 * @param connectionOptions The set of connection options to use for this 331 * connection. If it is {@code null}, then a 332 * default set of options will be used. 333 */ 334 public LDAPConnection(final LDAPConnectionOptions connectionOptions) 335 { 336 this(null, connectionOptions); 337 } 338 339 340 341 /** 342 * Creates a new LDAP connection using the specified socket factory. No 343 * actual network connection will be established. 344 * 345 * @param socketFactory The socket factory to use when establishing 346 * connections. If it is {@code null}, then a default 347 * socket factory will be used. 348 */ 349 public LDAPConnection(final SocketFactory socketFactory) 350 { 351 this(socketFactory, null); 352 } 353 354 355 356 /** 357 * Creates a new LDAP connection using the specified socket factory. No 358 * actual network connection will be established. 359 * 360 * @param socketFactory The socket factory to use when establishing 361 * connections. If it is {@code null}, then a 362 * default socket factory will be used. 363 * @param connectionOptions The set of connection options to use for this 364 * connection. If it is {@code null}, then a 365 * default set of options will be used. 366 */ 367 public LDAPConnection(final SocketFactory socketFactory, 368 final LDAPConnectionOptions connectionOptions) 369 { 370 needsReconnect = new AtomicBoolean(false); 371 disconnectInfo = new AtomicReference<DisconnectInfo>(); 372 lastCommunicationTime = -1L; 373 374 connectionID = NEXT_CONNECTION_ID.getAndIncrement(); 375 376 if (connectionOptions == null) 377 { 378 this.connectionOptions = new LDAPConnectionOptions(); 379 } 380 else 381 { 382 this.connectionOptions = connectionOptions.duplicate(); 383 } 384 385 final SocketFactory f; 386 if (socketFactory == null) 387 { 388 f = DEFAULT_SOCKET_FACTORY; 389 } 390 else 391 { 392 f = socketFactory; 393 } 394 395 if (this.connectionOptions.allowConcurrentSocketFactoryUse()) 396 { 397 this.socketFactory = f; 398 } 399 else 400 { 401 if (f instanceof SSLSocketFactory) 402 { 403 this.socketFactory = 404 new SynchronizedSSLSocketFactory((SSLSocketFactory) f); 405 } 406 else 407 { 408 this.socketFactory = new SynchronizedSocketFactory(f); 409 } 410 } 411 412 attachments = null; 413 connectionStatistics = new LDAPConnectionStatistics(); 414 connectionName = null; 415 connectionPoolName = null; 416 cachedSchema = null; 417 timer = null; 418 419 referralConnector = this.connectionOptions.getReferralConnector(); 420 if (referralConnector == null) 421 { 422 referralConnector = this; 423 } 424 } 425 426 427 428 /** 429 * Creates a new, unauthenticated LDAP connection that is established to the 430 * specified server. 431 * 432 * @param host The string representation of the address of the server to 433 * which the connection should be established. It may be a 434 * resolvable name or an IP address. It must not be 435 * {@code null}. 436 * @param port The port number of the server to which the connection should 437 * be established. It should be a value between 1 and 65535, 438 * inclusive. 439 * 440 * @throws LDAPException If a problem occurs while attempting to connect to 441 * the specified server. 442 */ 443 public LDAPConnection(final String host, final int port) 444 throws LDAPException 445 { 446 this(null, null, host, port); 447 } 448 449 450 451 /** 452 * Creates a new, unauthenticated LDAP connection that is established to the 453 * specified server. 454 * 455 * @param connectionOptions The set of connection options to use for this 456 * connection. If it is {@code null}, then a 457 * default set of options will be used. 458 * @param host The string representation of the address of the 459 * server to which the connection should be 460 * established. It may be a resolvable name or an 461 * IP address. It must not be {@code null}. 462 * @param port The port number of the server to which the 463 * connection should be established. It should be 464 * a value between 1 and 65535, inclusive. 465 * 466 * @throws LDAPException If a problem occurs while attempting to connect to 467 * the specified server. 468 */ 469 public LDAPConnection(final LDAPConnectionOptions connectionOptions, 470 final String host, final int port) 471 throws LDAPException 472 { 473 this(null, connectionOptions, host, port); 474 } 475 476 477 478 /** 479 * Creates a new, unauthenticated LDAP connection that is established to the 480 * specified server. 481 * 482 * @param socketFactory The socket factory to use when establishing 483 * connections. If it is {@code null}, then a default 484 * socket factory will be used. 485 * @param host The string representation of the address of the 486 * server to which the connection should be 487 * established. It may be a resolvable name or an IP 488 * address. It must not be {@code null}. 489 * @param port The port number of the server to which the 490 * connection should be established. It should be a 491 * value between 1 and 65535, inclusive. 492 * 493 * @throws LDAPException If a problem occurs while attempting to connect to 494 * the specified server. 495 */ 496 public LDAPConnection(final SocketFactory socketFactory, final String host, 497 final int port) 498 throws LDAPException 499 { 500 this(socketFactory, null, host, port); 501 } 502 503 504 505 /** 506 * Creates a new, unauthenticated LDAP connection that is established to the 507 * specified server. 508 * 509 * @param socketFactory The socket factory to use when establishing 510 * connections. If it is {@code null}, then a 511 * default socket factory will be used. 512 * @param connectionOptions The set of connection options to use for this 513 * connection. If it is {@code null}, then a 514 * default set of options will be used. 515 * @param host The string representation of the address of the 516 * server to which the connection should be 517 * established. It may be a resolvable name or an 518 * IP address. It must not be {@code null}. 519 * @param port The port number of the server to which the 520 * connection should be established. It should be 521 * a value between 1 and 65535, inclusive. 522 * 523 * @throws LDAPException If a problem occurs while attempting to connect to 524 * the specified server. 525 */ 526 public LDAPConnection(final SocketFactory socketFactory, 527 final LDAPConnectionOptions connectionOptions, 528 final String host, final int port) 529 throws LDAPException 530 { 531 this(socketFactory, connectionOptions); 532 533 connect(host, port); 534 } 535 536 537 538 /** 539 * Creates a new LDAP connection that is established to the specified server 540 * and is authenticated as the specified user (via LDAP simple 541 * authentication). 542 * 543 * @param host The string representation of the address of the 544 * server to which the connection should be established. 545 * It may be a resolvable name or an IP address. It 546 * must not be {@code null}. 547 * @param port The port number of the server to which the 548 * connection should be established. It should be a 549 * value between 1 and 65535, inclusive. 550 * @param bindDN The DN to use to authenticate to the directory 551 * server. 552 * @param bindPassword The password to use to authenticate to the directory 553 * server. 554 * 555 * @throws LDAPException If a problem occurs while attempting to connect to 556 * the specified server. 557 */ 558 public LDAPConnection(final String host, final int port, final String bindDN, 559 final String bindPassword) 560 throws LDAPException 561 { 562 this(null, null, host, port, bindDN, bindPassword); 563 } 564 565 566 567 /** 568 * Creates a new LDAP connection that is established to the specified server 569 * and is authenticated as the specified user (via LDAP simple 570 * authentication). 571 * 572 * @param connectionOptions The set of connection options to use for this 573 * connection. If it is {@code null}, then a 574 * default set of options will be used. 575 * @param host The string representation of the address of the 576 * server to which the connection should be 577 * established. It may be a resolvable name or an 578 * IP address. It must not be {@code null}. 579 * @param port The port number of the server to which the 580 * connection should be established. It should be 581 * a value between 1 and 65535, inclusive. 582 * @param bindDN The DN to use to authenticate to the directory 583 * server. 584 * @param bindPassword The password to use to authenticate to the 585 * directory server. 586 * 587 * @throws LDAPException If a problem occurs while attempting to connect to 588 * the specified server. 589 */ 590 public LDAPConnection(final LDAPConnectionOptions connectionOptions, 591 final String host, final int port, final String bindDN, 592 final String bindPassword) 593 throws LDAPException 594 { 595 this(null, connectionOptions, host, port, bindDN, bindPassword); 596 } 597 598 599 600 /** 601 * Creates a new LDAP connection that is established to the specified server 602 * and is authenticated as the specified user (via LDAP simple 603 * authentication). 604 * 605 * @param socketFactory The socket factory to use when establishing 606 * connections. If it is {@code null}, then a default 607 * socket factory will be used. 608 * @param host The string representation of the address of the 609 * server to which the connection should be 610 * established. It may be a resolvable name or an IP 611 * address. It must not be {@code null}. 612 * @param port The port number of the server to which the 613 * connection should be established. It should be a 614 * value between 1 and 65535, inclusive. 615 * @param bindDN The DN to use to authenticate to the directory 616 * server. 617 * @param bindPassword The password to use to authenticate to the directory 618 * server. 619 * 620 * @throws LDAPException If a problem occurs while attempting to connect to 621 * the specified server. 622 */ 623 public LDAPConnection(final SocketFactory socketFactory, final String host, 624 final int port, final String bindDN, 625 final String bindPassword) 626 throws LDAPException 627 { 628 this(socketFactory, null, host, port, bindDN, bindPassword); 629 } 630 631 632 633 /** 634 * Creates a new LDAP connection that is established to the specified server 635 * and is authenticated as the specified user (via LDAP simple 636 * authentication). 637 * 638 * @param socketFactory The socket factory to use when establishing 639 * connections. If it is {@code null}, then a 640 * default socket factory will be used. 641 * @param connectionOptions The set of connection options to use for this 642 * connection. If it is {@code null}, then a 643 * default set of options will be used. 644 * @param host The string representation of the address of the 645 * server to which the connection should be 646 * established. It may be a resolvable name or an 647 * IP address. It must not be {@code null}. 648 * @param port The port number of the server to which the 649 * connection should be established. It should be 650 * a value between 1 and 65535, inclusive. 651 * @param bindDN The DN to use to authenticate to the directory 652 * server. 653 * @param bindPassword The password to use to authenticate to the 654 * directory server. 655 * 656 * @throws LDAPException If a problem occurs while attempting to connect to 657 * the specified server. 658 */ 659 public LDAPConnection(final SocketFactory socketFactory, 660 final LDAPConnectionOptions connectionOptions, 661 final String host, final int port, final String bindDN, 662 final String bindPassword) 663 throws LDAPException 664 { 665 this(socketFactory, connectionOptions, host, port); 666 667 try 668 { 669 bind(new SimpleBindRequest(bindDN, bindPassword)); 670 } 671 catch (LDAPException le) 672 { 673 debugException(le); 674 setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); 675 close(); 676 throw le; 677 } 678 } 679 680 681 682 /** 683 * Establishes an unauthenticated connection to the directory server using the 684 * provided information. If the connection is already established, then it 685 * will be closed and re-established. 686 * <BR><BR> 687 * If this method is invoked while any operations are in progress on this 688 * connection, then the directory server may or may not abort processing for 689 * those operations, depending on the type of operation and how far along the 690 * server has already gotten while processing that operation. It is 691 * recommended that all active operations be abandoned, canceled, or allowed 692 * to complete before attempting to re-establish an active connection. 693 * 694 * @param host The string representation of the address of the server to 695 * which the connection should be established. It may be a 696 * resolvable name or an IP address. It must not be 697 * {@code null}. 698 * @param port The port number of the server to which the connection should 699 * be established. It should be a value between 1 and 65535, 700 * inclusive. 701 * 702 * @throws LDAPException If an error occurs while attempting to establish 703 * the connection. 704 */ 705 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 706 public void connect(final String host, final int port) 707 throws LDAPException 708 { 709 connect(host, port, connectionOptions.getConnectTimeoutMillis()); 710 } 711 712 713 714 /** 715 * Establishes an unauthenticated connection to the directory server using the 716 * provided information. If the connection is already established, then it 717 * will be closed and re-established. 718 * <BR><BR> 719 * If this method is invoked while any operations are in progress on this 720 * connection, then the directory server may or may not abort processing for 721 * those operations, depending on the type of operation and how far along the 722 * server has already gotten while processing that operation. It is 723 * recommended that all active operations be abandoned, canceled, or allowed 724 * to complete before attempting to re-establish an active connection. 725 * 726 * @param host The string representation of the address of the server to 727 * which the connection should be established. It may be a 728 * resolvable name or an IP address. It must not be 729 * {@code null}. 730 * @param port The port number of the server to which the connection 731 * should be established. It should be a value between 1 and 732 * 65535, inclusive. 733 * @param timeout The maximum length of time in milliseconds to wait for the 734 * connection to be established before failing, or zero to 735 * indicate that no timeout should be enforced (although if 736 * the attempt stalls long enough, then the underlying 737 * operating system may cause it to timeout). 738 * 739 * @throws LDAPException If an error occurs while attempting to establish 740 * the connection. 741 */ 742 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 743 public void connect(final String host, final int port, final int timeout) 744 throws LDAPException 745 { 746 final InetAddress inetAddress; 747 try 748 { 749 inetAddress = InetAddress.getByName(host); 750 } 751 catch (final Exception e) 752 { 753 debugException(e); 754 throw new LDAPException(ResultCode.CONNECT_ERROR, 755 ERR_CONN_RESOLVE_ERROR.get(host, getExceptionMessage(e)), 756 e); 757 } 758 759 connect(host, inetAddress, port, timeout); 760 } 761 762 763 764 /** 765 * Establishes an unauthenticated connection to the directory server using the 766 * provided information. If the connection is already established, then it 767 * will be closed and re-established. 768 * <BR><BR> 769 * If this method is invoked while any operations are in progress on this 770 * connection, then the directory server may or may not abort processing for 771 * those operations, depending on the type of operation and how far along the 772 * server has already gotten while processing that operation. It is 773 * recommended that all active operations be abandoned, canceled, or allowed 774 * to complete before attempting to re-establish an active connection. 775 * 776 * @param inetAddress The inet address of the server to which the connection 777 * should be established. It must not be {@code null}. 778 * @param port The port number of the server to which the connection 779 * should be established. It should be a value between 1 780 * and 65535, inclusive. 781 * @param timeout The maximum length of time in milliseconds to wait for 782 * the connection to be established before failing, or 783 * zero to indicate that no timeout should be enforced 784 * (although if the attempt stalls long enough, then the 785 * underlying operating system may cause it to timeout). 786 * 787 * @throws LDAPException If an error occurs while attempting to establish 788 * the connection. 789 */ 790 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 791 public void connect(final InetAddress inetAddress, final int port, 792 final int timeout) 793 throws LDAPException 794 { 795 connect(inetAddress.getHostName(), inetAddress, port, timeout); 796 } 797 798 799 800 /** 801 * Establishes an unauthenticated connection to the directory server using the 802 * provided information. If the connection is already established, then it 803 * will be closed and re-established. 804 * <BR><BR> 805 * If this method is invoked while any operations are in progress on this 806 * connection, then the directory server may or may not abort processing for 807 * those operations, depending on the type of operation and how far along the 808 * server has already gotten while processing that operation. It is 809 * recommended that all active operations be abandoned, canceled, or allowed 810 * to complete before attempting to re-establish an active connection. 811 * 812 * @param host The string representation of the address of the server 813 * to which the connection should be established. It may 814 * be a resolvable name or an IP address. It must not be 815 * {@code null}. 816 * @param inetAddress The inet address of the server to which the connection 817 * should be established. It must not be {@code null}. 818 * @param port The port number of the server to which the connection 819 * should be established. It should be a value between 1 820 * and 65535, inclusive. 821 * @param timeout The maximum length of time in milliseconds to wait for 822 * the connection to be established before failing, or 823 * zero to indicate that no timeout should be enforced 824 * (although if the attempt stalls long enough, then the 825 * underlying operating system may cause it to timeout). 826 * 827 * @throws LDAPException If an error occurs while attempting to establish 828 * the connection. 829 */ 830 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 831 public void connect(final String host, final InetAddress inetAddress, 832 final int port, final int timeout) 833 throws LDAPException 834 { 835 ensureNotNull(host, inetAddress, port); 836 837 needsReconnect.set(false); 838 hostPort = host + ':' + port; 839 lastCommunicationTime = -1L; 840 startTLSRequest = null; 841 842 if (isConnected()) 843 { 844 setDisconnectInfo(DisconnectType.RECONNECT, null, null); 845 close(); 846 } 847 848 lastUsedSocketFactory = socketFactory; 849 reconnectAddress = host; 850 reconnectPort = port; 851 cachedSchema = null; 852 unbindRequestSent = false; 853 854 disconnectInfo.set(null); 855 856 try 857 { 858 connectionStatistics.incrementNumConnects(); 859 connectionInternals = new LDAPConnectionInternals(this, connectionOptions, 860 lastUsedSocketFactory, host, inetAddress, port, timeout); 861 connectionInternals.startConnectionReader(); 862 lastCommunicationTime = System.currentTimeMillis(); 863 } 864 catch (Exception e) 865 { 866 debugException(e); 867 setDisconnectInfo(DisconnectType.LOCAL_ERROR, null, e); 868 connectionInternals = null; 869 throw new LDAPException(ResultCode.CONNECT_ERROR, 870 ERR_CONN_CONNECT_ERROR.get(getHostPort(), getExceptionMessage(e)), 871 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 an UnboundID Directory Server). It is 2070 * recommended that all active operations be abandoned, canceled, or allowed 2071 * to complete before attempting to perform a bind on an active connection. 2072 * 2073 * @param bindDN The bind DN for the bind operation. 2074 * @param password The password for the simple bind operation. 2075 * 2076 * @return The result of processing the bind operation. 2077 * 2078 * @throws LDAPException If the server rejects the bind request, or if a 2079 * problem occurs while sending the request or reading 2080 * the response. 2081 */ 2082 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2083 public BindResult bind(final String bindDN, final String password) 2084 throws LDAPException 2085 { 2086 return bind(new SimpleBindRequest(bindDN, password)); 2087 } 2088 2089 2090 2091 /** 2092 * Processes the provided bind request. 2093 * <BR><BR> 2094 * The LDAP protocol specification forbids clients from attempting to perform 2095 * a bind on a connection in which one or more other operations are already in 2096 * progress. If a bind is attempted while any operations are in progress, 2097 * then the directory server may or may not abort processing for those 2098 * operations, depending on the type of operation and how far along the 2099 * server has already gotten while processing that operation (unless the bind 2100 * request is one that will not cause the server to attempt to change the 2101 * identity of this connection, for example by including the retain identity 2102 * request control in the bind request if using the Commercial Edition of the 2103 * LDAP SDK in conjunction with an UnboundID Directory Server). It is 2104 * recommended that all active operations be abandoned, canceled, or allowed 2105 * to complete before attempting to perform a bind on an active connection. 2106 * 2107 * @param bindRequest The bind request to be processed. It must not be 2108 * {@code null}. 2109 * 2110 * @return The result of processing the bind operation. 2111 * 2112 * @throws LDAPException If the server rejects the bind request, or if a 2113 * problem occurs while sending the request or reading 2114 * the response. 2115 */ 2116 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2117 public BindResult bind(final BindRequest bindRequest) 2118 throws LDAPException 2119 { 2120 ensureNotNull(bindRequest); 2121 2122 // We don't want to update the last bind request or update the cached 2123 // schema for this connection if it included the retain identity control. 2124 // However, that's only available in the Commercial Edition, so just 2125 // reference it by OID here. 2126 boolean hasRetainIdentityControl = false; 2127 for (final Control c : bindRequest.getControls()) 2128 { 2129 if (c.getOID().equals("1.3.6.1.4.1.30221.2.5.3")) 2130 { 2131 hasRetainIdentityControl = true; 2132 break; 2133 } 2134 } 2135 2136 if (! hasRetainIdentityControl) 2137 { 2138 lastBindRequest = null; 2139 } 2140 2141 final BindResult bindResult = bindRequest.process(this, 1); 2142 if (bindResult.getResultCode().equals(ResultCode.SUCCESS)) 2143 { 2144 if (! hasRetainIdentityControl) 2145 { 2146 lastBindRequest = bindRequest; 2147 if (connectionOptions.useSchema()) 2148 { 2149 try 2150 { 2151 cachedSchema = getCachedSchema(this); 2152 } 2153 catch (Exception e) 2154 { 2155 debugException(e); 2156 } 2157 } 2158 } 2159 2160 return bindResult; 2161 } 2162 2163 if (bindResult.getResultCode().equals(ResultCode.SASL_BIND_IN_PROGRESS)) 2164 { 2165 throw new SASLBindInProgressException(bindResult); 2166 } 2167 else 2168 { 2169 throw new LDAPBindException(bindResult); 2170 } 2171 } 2172 2173 2174 2175 /** 2176 * Processes a compare operation with the provided information. 2177 * 2178 * @param dn The DN of the entry in which to make the 2179 * comparison. It must not be {@code null}. 2180 * @param attributeName The attribute name for which to make the 2181 * comparison. It must not be {@code null}. 2182 * @param assertionValue The assertion value to verify in the target entry. 2183 * It must not be {@code null}. 2184 * 2185 * @return The result of processing the compare operation. 2186 * 2187 * @throws LDAPException If the server rejects the compare request, or if a 2188 * problem is encountered while sending the request or 2189 * reading the response. 2190 */ 2191 public CompareResult compare(final String dn, final String attributeName, 2192 final String assertionValue) 2193 throws LDAPException 2194 { 2195 ensureNotNull(dn, attributeName, assertionValue); 2196 2197 return compare(new CompareRequest(dn, attributeName, assertionValue)); 2198 } 2199 2200 2201 2202 /** 2203 * Processes the provided compare request. 2204 * 2205 * @param compareRequest The compare request to be processed. It must not 2206 * be {@code null}. 2207 * 2208 * @return The result of processing the compare operation. 2209 * 2210 * @throws LDAPException If the server rejects the compare request, or if a 2211 * problem is encountered while sending the request or 2212 * reading the response. 2213 */ 2214 public CompareResult compare(final CompareRequest compareRequest) 2215 throws LDAPException 2216 { 2217 ensureNotNull(compareRequest); 2218 2219 final LDAPResult result = compareRequest.process(this, 1); 2220 switch (result.getResultCode().intValue()) 2221 { 2222 case ResultCode.COMPARE_FALSE_INT_VALUE: 2223 case ResultCode.COMPARE_TRUE_INT_VALUE: 2224 return new CompareResult(result); 2225 2226 default: 2227 throw new LDAPException(result); 2228 } 2229 } 2230 2231 2232 2233 /** 2234 * Processes the provided compare request. 2235 * 2236 * @param compareRequest The compare request to be processed. It must not 2237 * be {@code null}. 2238 * 2239 * @return The result of processing the compare operation. 2240 * 2241 * @throws LDAPException If the server rejects the compare request, or if a 2242 * problem is encountered while sending the request or 2243 * reading the response. 2244 */ 2245 public CompareResult compare(final ReadOnlyCompareRequest compareRequest) 2246 throws LDAPException 2247 { 2248 return compare((CompareRequest) compareRequest); 2249 } 2250 2251 2252 2253 /** 2254 * Processes the provided compare request as an asynchronous operation. 2255 * 2256 * @param compareRequest The compare request to be processed. It must not 2257 * be {@code null}. 2258 * @param resultListener The async result listener to use to handle the 2259 * response for the compare operation. It may be 2260 * {@code null} if the result is going to be obtained 2261 * from the returned {@code AsyncRequestID} object via 2262 * the {@code Future} API. 2263 * 2264 * @return An async request ID that may be used to reference the operation. 2265 * 2266 * @throws LDAPException If a problem occurs while sending the request. 2267 */ 2268 public AsyncRequestID asyncCompare(final CompareRequest compareRequest, 2269 final AsyncCompareResultListener resultListener) 2270 throws LDAPException 2271 { 2272 ensureNotNull(compareRequest); 2273 2274 if (synchronousMode()) 2275 { 2276 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2277 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2278 } 2279 2280 final AsyncCompareResultListener listener; 2281 if (resultListener == null) 2282 { 2283 listener = DiscardAsyncListener.getInstance(); 2284 } 2285 else 2286 { 2287 listener = resultListener; 2288 } 2289 2290 return compareRequest.processAsync(this, listener); 2291 } 2292 2293 2294 2295 /** 2296 * Processes the provided compare request as an asynchronous operation. 2297 * 2298 * @param compareRequest The compare request to be processed. It must not 2299 * be {@code null}. 2300 * @param resultListener The async result listener to use to handle the 2301 * response for the compare operation. It may be 2302 * {@code null} if the result is going to be obtained 2303 * from the returned {@code AsyncRequestID} object via 2304 * the {@code Future} API. 2305 * 2306 * @return An async request ID that may be used to reference the operation. 2307 * 2308 * @throws LDAPException If a problem occurs while sending the request. 2309 */ 2310 public AsyncRequestID asyncCompare( 2311 final ReadOnlyCompareRequest compareRequest, 2312 final AsyncCompareResultListener resultListener) 2313 throws LDAPException 2314 { 2315 if (synchronousMode()) 2316 { 2317 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2318 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2319 } 2320 2321 return asyncCompare((CompareRequest) compareRequest, resultListener); 2322 } 2323 2324 2325 2326 /** 2327 * Deletes the entry with the specified DN. 2328 * 2329 * @param dn The DN of the entry to delete. It must not be {@code null}. 2330 * 2331 * @return The result of processing the delete operation. 2332 * 2333 * @throws LDAPException If the server rejects the delete request, or if a 2334 * problem is encountered while sending the request or 2335 * reading the response. 2336 */ 2337 public LDAPResult delete(final String dn) 2338 throws LDAPException 2339 { 2340 return delete(new DeleteRequest(dn)); 2341 } 2342 2343 2344 2345 /** 2346 * Processes the provided delete request. 2347 * 2348 * @param deleteRequest The delete request to be processed. It must not be 2349 * {@code null}. 2350 * 2351 * @return The result of processing the delete operation. 2352 * 2353 * @throws LDAPException If the server rejects the delete request, or if a 2354 * problem is encountered while sending the request or 2355 * reading the response. 2356 */ 2357 public LDAPResult delete(final DeleteRequest deleteRequest) 2358 throws LDAPException 2359 { 2360 ensureNotNull(deleteRequest); 2361 2362 final LDAPResult ldapResult = deleteRequest.process(this, 1); 2363 2364 switch (ldapResult.getResultCode().intValue()) 2365 { 2366 case ResultCode.SUCCESS_INT_VALUE: 2367 case ResultCode.NO_OPERATION_INT_VALUE: 2368 return ldapResult; 2369 2370 default: 2371 throw new LDAPException(ldapResult); 2372 } 2373 } 2374 2375 2376 2377 /** 2378 * Processes the provided delete request. 2379 * 2380 * @param deleteRequest The delete request to be processed. It must not be 2381 * {@code null}. 2382 * 2383 * @return The result of processing the delete operation. 2384 * 2385 * @throws LDAPException If the server rejects the delete request, or if a 2386 * problem is encountered while sending the request or 2387 * reading the response. 2388 */ 2389 public LDAPResult delete(final ReadOnlyDeleteRequest deleteRequest) 2390 throws LDAPException 2391 { 2392 return delete((DeleteRequest) deleteRequest); 2393 } 2394 2395 2396 2397 /** 2398 * Processes the provided delete request as an asynchronous operation. 2399 * 2400 * @param deleteRequest The delete request to be processed. It must not be 2401 * {@code null}. 2402 * @param resultListener The async result listener to use to handle the 2403 * response for the delete operation. It may be 2404 * {@code null} if the result is going to be obtained 2405 * from the returned {@code AsyncRequestID} object via 2406 * the {@code Future} API. 2407 * 2408 * @return An async request ID that may be used to reference the operation. 2409 * 2410 * @throws LDAPException If a problem occurs while sending the request. 2411 */ 2412 public AsyncRequestID asyncDelete(final DeleteRequest deleteRequest, 2413 final AsyncResultListener resultListener) 2414 throws LDAPException 2415 { 2416 ensureNotNull(deleteRequest); 2417 2418 if (synchronousMode()) 2419 { 2420 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2421 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2422 } 2423 2424 final AsyncResultListener listener; 2425 if (resultListener == null) 2426 { 2427 listener = DiscardAsyncListener.getInstance(); 2428 } 2429 else 2430 { 2431 listener = resultListener; 2432 } 2433 2434 return deleteRequest.processAsync(this, listener); 2435 } 2436 2437 2438 2439 /** 2440 * Processes the provided delete request as an asynchronous operation. 2441 * 2442 * @param deleteRequest The delete request to be processed. It must not be 2443 * {@code null}. 2444 * @param resultListener The async result listener to use to handle the 2445 * response for the delete operation. It may be 2446 * {@code null} if the result is going to be obtained 2447 * from the returned {@code AsyncRequestID} object via 2448 * the {@code Future} API. 2449 * 2450 * @return An async request ID that may be used to reference the operation. 2451 * 2452 * @throws LDAPException If a problem occurs while sending the request. 2453 */ 2454 public AsyncRequestID asyncDelete(final ReadOnlyDeleteRequest deleteRequest, 2455 final AsyncResultListener resultListener) 2456 throws LDAPException 2457 { 2458 if (synchronousMode()) 2459 { 2460 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2461 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2462 } 2463 2464 return asyncDelete((DeleteRequest) deleteRequest, resultListener); 2465 } 2466 2467 2468 2469 /** 2470 * Processes an extended request with the provided request OID. Note that 2471 * because some types of extended operations return unusual result codes under 2472 * "normal" conditions, the server may not always throw an exception for a 2473 * failed extended operation like it does for other types of operations. It 2474 * will throw an exception under conditions where there appears to be a 2475 * problem with the connection or the server to which the connection is 2476 * established, but there may be many circumstances in which an extended 2477 * operation is not processed correctly but this method does not throw an 2478 * exception. In the event that no exception is thrown, it is the 2479 * responsibility of the caller to interpret the result to determine whether 2480 * the operation was processed as expected. 2481 * <BR><BR> 2482 * Note that extended operations which may change the state of this connection 2483 * (e.g., the StartTLS extended operation, which will add encryption to a 2484 * previously-unencrypted connection) should not be invoked while any other 2485 * operations are active on the connection. It is recommended that all active 2486 * operations be abandoned, canceled, or allowed to complete before attempting 2487 * to process an extended operation that may change the state of this 2488 * connection. 2489 * 2490 * @param requestOID The OID for the extended request to process. It must 2491 * not be {@code null}. 2492 * 2493 * @return The extended result object that provides information about the 2494 * result of the request processing. It may or may not indicate that 2495 * the operation was successful. 2496 * 2497 * @throws LDAPException If a problem occurs while sending the request or 2498 * reading the response. 2499 */ 2500 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2501 public ExtendedResult processExtendedOperation(final String requestOID) 2502 throws LDAPException 2503 { 2504 ensureNotNull(requestOID); 2505 2506 return processExtendedOperation(new ExtendedRequest(requestOID)); 2507 } 2508 2509 2510 2511 /** 2512 * Processes an extended request with the provided request OID and value. 2513 * Note that because some types of extended operations return unusual result 2514 * codes under "normal" conditions, the server may not always throw an 2515 * exception for a failed extended operation like it does for other types of 2516 * operations. It will throw an exception under conditions where there 2517 * appears to be a problem with the connection or the server to which the 2518 * connection is established, but there may be many circumstances in which an 2519 * extended operation is not processed correctly but this method does not 2520 * throw an exception. In the event that no exception is thrown, it is the 2521 * responsibility of the caller to interpret the result to determine whether 2522 * the operation was processed as expected. 2523 * <BR><BR> 2524 * Note that extended operations which may change the state of this connection 2525 * (e.g., the StartTLS extended operation, which will add encryption to a 2526 * previously-unencrypted connection) should not be invoked while any other 2527 * operations are active on the connection. It is recommended that all active 2528 * operations be abandoned, canceled, or allowed to complete before attempting 2529 * to process an extended operation that may change the state of this 2530 * connection. 2531 * 2532 * @param requestOID The OID for the extended request to process. It must 2533 * not be {@code null}. 2534 * @param requestValue The encoded value for the extended request to 2535 * process. It may be {@code null} if there does not 2536 * need to be a value for the requested operation. 2537 * 2538 * @return The extended result object that provides information about the 2539 * result of the request processing. It may or may not indicate that 2540 * the operation was successful. 2541 * 2542 * @throws LDAPException If a problem occurs while sending the request or 2543 * reading the response. 2544 */ 2545 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2546 public ExtendedResult processExtendedOperation(final String requestOID, 2547 final ASN1OctetString requestValue) 2548 throws LDAPException 2549 { 2550 ensureNotNull(requestOID); 2551 2552 return processExtendedOperation(new ExtendedRequest(requestOID, 2553 requestValue)); 2554 } 2555 2556 2557 2558 /** 2559 * Processes the provided extended request. Note that because some types of 2560 * extended operations return unusual result codes under "normal" conditions, 2561 * the server may not always throw an exception for a failed extended 2562 * operation like it does for other types of operations. It will throw an 2563 * exception under conditions where there appears to be a problem with the 2564 * connection or the server to which the connection is established, but there 2565 * may be many circumstances in which an extended operation is not processed 2566 * correctly but this method does not throw an exception. In the event that 2567 * no exception is thrown, it is the responsibility of the caller to interpret 2568 * the result to determine whether the operation was processed as expected. 2569 * <BR><BR> 2570 * Note that extended operations which may change the state of this connection 2571 * (e.g., the StartTLS extended operation, which will add encryption to a 2572 * previously-unencrypted connection) should not be invoked while any other 2573 * operations are active on the connection. It is recommended that all active 2574 * operations be abandoned, canceled, or allowed to complete before attempting 2575 * to process an extended operation that may change the state of this 2576 * connection. 2577 * 2578 * @param extendedRequest The extended request to be processed. It must not 2579 * be {@code null}. 2580 * 2581 * @return The extended result object that provides information about the 2582 * result of the request processing. It may or may not indicate that 2583 * the operation was successful. 2584 * 2585 * @throws LDAPException If a problem occurs while sending the request or 2586 * reading the response. 2587 */ 2588 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) 2589 public ExtendedResult processExtendedOperation( 2590 final ExtendedRequest extendedRequest) 2591 throws LDAPException 2592 { 2593 ensureNotNull(extendedRequest); 2594 2595 final ExtendedResult extendedResult = extendedRequest.process(this, 1); 2596 2597 if ((extendedResult.getOID() == null) && 2598 (extendedResult.getValue() == null)) 2599 { 2600 switch (extendedResult.getResultCode().intValue()) 2601 { 2602 case ResultCode.OPERATIONS_ERROR_INT_VALUE: 2603 case ResultCode.PROTOCOL_ERROR_INT_VALUE: 2604 case ResultCode.BUSY_INT_VALUE: 2605 case ResultCode.UNAVAILABLE_INT_VALUE: 2606 case ResultCode.OTHER_INT_VALUE: 2607 case ResultCode.SERVER_DOWN_INT_VALUE: 2608 case ResultCode.LOCAL_ERROR_INT_VALUE: 2609 case ResultCode.ENCODING_ERROR_INT_VALUE: 2610 case ResultCode.DECODING_ERROR_INT_VALUE: 2611 case ResultCode.TIMEOUT_INT_VALUE: 2612 case ResultCode.NO_MEMORY_INT_VALUE: 2613 case ResultCode.CONNECT_ERROR_INT_VALUE: 2614 throw new LDAPException(extendedResult); 2615 } 2616 } 2617 2618 if ((extendedResult.getResultCode() == ResultCode.SUCCESS) && 2619 extendedRequest.getOID().equals( 2620 StartTLSExtendedRequest.STARTTLS_REQUEST_OID)) 2621 { 2622 startTLSRequest = extendedRequest.duplicate(); 2623 } 2624 2625 return extendedResult; 2626 } 2627 2628 2629 2630 /** 2631 * Applies the provided modification to the specified entry. 2632 * 2633 * @param dn The DN of the entry to modify. It must not be {@code null}. 2634 * @param mod The modification to apply to the target entry. It must not 2635 * be {@code null}. 2636 * 2637 * @return The result of processing the modify operation. 2638 * 2639 * @throws LDAPException If the server rejects the modify request, or if a 2640 * problem is encountered while sending the request or 2641 * reading the response. 2642 */ 2643 public LDAPResult modify(final String dn, final Modification mod) 2644 throws LDAPException 2645 { 2646 ensureNotNull(dn, mod); 2647 2648 return modify(new ModifyRequest(dn, mod)); 2649 } 2650 2651 2652 2653 /** 2654 * Applies the provided set of modifications to the specified entry. 2655 * 2656 * @param dn The DN of the entry to modify. It must not be {@code null}. 2657 * @param mods The set of modifications to apply to the target entry. It 2658 * must not be {@code null} or empty. * 2659 * @return The result of processing the modify operation. 2660 * 2661 * @throws LDAPException If the server rejects the modify request, or if a 2662 * problem is encountered while sending the request or 2663 * reading the response. 2664 */ 2665 public LDAPResult modify(final String dn, final Modification... mods) 2666 throws LDAPException 2667 { 2668 ensureNotNull(dn, mods); 2669 2670 return modify(new ModifyRequest(dn, mods)); 2671 } 2672 2673 2674 2675 /** 2676 * Applies the provided set of modifications to the specified entry. 2677 * 2678 * @param dn The DN of the entry to modify. It must not be {@code null}. 2679 * @param mods The set of modifications to apply to the target entry. It 2680 * must not be {@code null} or empty. 2681 * 2682 * @return The result of processing the modify operation. 2683 * 2684 * @throws LDAPException If the server rejects the modify request, or if a 2685 * problem is encountered while sending the request or 2686 * reading the response. 2687 */ 2688 public LDAPResult modify(final String dn, final List<Modification> mods) 2689 throws LDAPException 2690 { 2691 ensureNotNull(dn, mods); 2692 2693 return modify(new ModifyRequest(dn, mods)); 2694 } 2695 2696 2697 2698 /** 2699 * Processes a modify request from the provided LDIF representation of the 2700 * changes. 2701 * 2702 * @param ldifModificationLines The lines that comprise an LDIF 2703 * representation of a modify change record. 2704 * It must not be {@code null} or empty. 2705 * 2706 * @return The result of processing the modify operation. 2707 * 2708 * @throws LDIFException If the provided set of lines cannot be parsed as an 2709 * LDIF modify change record. 2710 * 2711 * @throws LDAPException If the server rejects the modify request, or if a 2712 * problem is encountered while sending the request or 2713 * reading the response. 2714 * 2715 */ 2716 public LDAPResult modify(final String... ldifModificationLines) 2717 throws LDIFException, LDAPException 2718 { 2719 ensureNotNull(ldifModificationLines); 2720 2721 return modify(new ModifyRequest(ldifModificationLines)); 2722 } 2723 2724 2725 2726 /** 2727 * Processes the provided modify request. 2728 * 2729 * @param modifyRequest The modify request to be processed. It must not be 2730 * {@code null}. 2731 * 2732 * @return The result of processing the modify operation. 2733 * 2734 * @throws LDAPException If the server rejects the modify request, or if a 2735 * problem is encountered while sending the request or 2736 * reading the response. 2737 */ 2738 public LDAPResult modify(final ModifyRequest modifyRequest) 2739 throws LDAPException 2740 { 2741 ensureNotNull(modifyRequest); 2742 2743 final LDAPResult ldapResult = modifyRequest.process(this, 1); 2744 2745 switch (ldapResult.getResultCode().intValue()) 2746 { 2747 case ResultCode.SUCCESS_INT_VALUE: 2748 case ResultCode.NO_OPERATION_INT_VALUE: 2749 return ldapResult; 2750 2751 default: 2752 throw new LDAPException(ldapResult); 2753 } 2754 } 2755 2756 2757 2758 /** 2759 * Processes the provided modify request. 2760 * 2761 * @param modifyRequest The modify request to be processed. It must not be 2762 * {@code null}. 2763 * 2764 * @return The result of processing the modify operation. 2765 * 2766 * @throws LDAPException If the server rejects the modify request, or if a 2767 * problem is encountered while sending the request or 2768 * reading the response. 2769 */ 2770 public LDAPResult modify(final ReadOnlyModifyRequest modifyRequest) 2771 throws LDAPException 2772 { 2773 return modify((ModifyRequest) modifyRequest); 2774 } 2775 2776 2777 2778 /** 2779 * Processes the provided modify request as an asynchronous operation. 2780 * 2781 * @param modifyRequest The modify request to be processed. It must not be 2782 * {@code null}. 2783 * @param resultListener The async result listener to use to handle the 2784 * response for the modify operation. It may be 2785 * {@code null} if the result is going to be obtained 2786 * from the returned {@code AsyncRequestID} object via 2787 * the {@code Future} API. 2788 * 2789 * @return An async request ID that may be used to reference the operation. 2790 * 2791 * @throws LDAPException If a problem occurs while sending the request. 2792 */ 2793 public AsyncRequestID asyncModify(final ModifyRequest modifyRequest, 2794 final AsyncResultListener resultListener) 2795 throws LDAPException 2796 { 2797 ensureNotNull(modifyRequest); 2798 2799 if (synchronousMode()) 2800 { 2801 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2802 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2803 } 2804 2805 final AsyncResultListener listener; 2806 if (resultListener == null) 2807 { 2808 listener = DiscardAsyncListener.getInstance(); 2809 } 2810 else 2811 { 2812 listener = resultListener; 2813 } 2814 2815 return modifyRequest.processAsync(this, listener); 2816 } 2817 2818 2819 2820 /** 2821 * Processes the provided modify request as an asynchronous operation. 2822 * 2823 * @param modifyRequest The modify request to be processed. It must not be 2824 * {@code null}. 2825 * @param resultListener The async result listener to use to handle the 2826 * response for the modify operation. It may be 2827 * {@code null} if the result is going to be obtained 2828 * from the returned {@code AsyncRequestID} object via 2829 * the {@code Future} API. 2830 * 2831 * @return An async request ID that may be used to reference the operation. 2832 * 2833 * @throws LDAPException If a problem occurs while sending the request. 2834 */ 2835 public AsyncRequestID asyncModify(final ReadOnlyModifyRequest modifyRequest, 2836 final AsyncResultListener resultListener) 2837 throws LDAPException 2838 { 2839 if (synchronousMode()) 2840 { 2841 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2842 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2843 } 2844 2845 return asyncModify((ModifyRequest) modifyRequest, resultListener); 2846 } 2847 2848 2849 2850 /** 2851 * Performs a modify DN operation with the provided information. 2852 * 2853 * @param dn The current DN for the entry to rename. It must not 2854 * be {@code null}. 2855 * @param newRDN The new RDN to use for the entry. It must not be 2856 * {@code null}. 2857 * @param deleteOldRDN Indicates whether to delete the current RDN value 2858 * from the entry. 2859 * 2860 * @return The result of processing the modify DN operation. 2861 * 2862 * @throws LDAPException If the server rejects the modify DN request, or if 2863 * a problem is encountered while sending the request 2864 * or reading the response. 2865 */ 2866 public LDAPResult modifyDN(final String dn, final String newRDN, 2867 final boolean deleteOldRDN) 2868 throws LDAPException 2869 { 2870 ensureNotNull(dn, newRDN); 2871 2872 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN)); 2873 } 2874 2875 2876 2877 /** 2878 * Performs a modify DN operation with the provided information. 2879 * 2880 * @param dn The current DN for the entry to rename. It must not 2881 * be {@code null}. 2882 * @param newRDN The new RDN to use for the entry. It must not be 2883 * {@code null}. 2884 * @param deleteOldRDN Indicates whether to delete the current RDN value 2885 * from the entry. 2886 * @param newSuperiorDN The new superior DN for the entry. It may be 2887 * {@code null} if the entry is not to be moved below a 2888 * new parent. 2889 * 2890 * @return The result of processing the modify DN operation. 2891 * 2892 * @throws LDAPException If the server rejects the modify DN request, or if 2893 * a problem is encountered while sending the request 2894 * or reading the response. 2895 */ 2896 public LDAPResult modifyDN(final String dn, final String newRDN, 2897 final boolean deleteOldRDN, 2898 final String newSuperiorDN) 2899 throws LDAPException 2900 { 2901 ensureNotNull(dn, newRDN); 2902 2903 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN, 2904 newSuperiorDN)); 2905 } 2906 2907 2908 2909 /** 2910 * Processes the provided modify DN request. 2911 * 2912 * @param modifyDNRequest The modify DN request to be processed. It must 2913 * not be {@code null}. 2914 * 2915 * @return The result of processing the modify DN operation. 2916 * 2917 * @throws LDAPException If the server rejects the modify DN request, or if 2918 * a problem is encountered while sending the request 2919 * or reading the response. 2920 */ 2921 public LDAPResult modifyDN(final ModifyDNRequest modifyDNRequest) 2922 throws LDAPException 2923 { 2924 ensureNotNull(modifyDNRequest); 2925 2926 final LDAPResult ldapResult = modifyDNRequest.process(this, 1); 2927 2928 switch (ldapResult.getResultCode().intValue()) 2929 { 2930 case ResultCode.SUCCESS_INT_VALUE: 2931 case ResultCode.NO_OPERATION_INT_VALUE: 2932 return ldapResult; 2933 2934 default: 2935 throw new LDAPException(ldapResult); 2936 } 2937 } 2938 2939 2940 2941 /** 2942 * Processes the provided modify DN request. 2943 * 2944 * @param modifyDNRequest The modify DN request to be processed. It must 2945 * not be {@code null}. 2946 * 2947 * @return The result of processing the modify DN operation. 2948 * 2949 * @throws LDAPException If the server rejects the modify DN request, or if 2950 * a problem is encountered while sending the request 2951 * or reading the response. 2952 */ 2953 public LDAPResult modifyDN(final ReadOnlyModifyDNRequest modifyDNRequest) 2954 throws LDAPException 2955 { 2956 return modifyDN((ModifyDNRequest) modifyDNRequest); 2957 } 2958 2959 2960 2961 /** 2962 * Processes the provided modify DN request as an asynchronous operation. 2963 * 2964 * @param modifyDNRequest The modify DN request to be processed. It must 2965 * not be {@code null}. 2966 * @param resultListener The async result listener to use to handle the 2967 * response for the modify DN operation. It may be 2968 * {@code null} if the result is going to be obtained 2969 * from the returned {@code AsyncRequestID} object via 2970 * the {@code Future} API. 2971 * 2972 * @return An async request ID that may be used to reference the operation. 2973 * 2974 * @throws LDAPException If a problem occurs while sending the request. 2975 */ 2976 public AsyncRequestID asyncModifyDN(final ModifyDNRequest modifyDNRequest, 2977 final AsyncResultListener resultListener) 2978 throws LDAPException 2979 { 2980 ensureNotNull(modifyDNRequest); 2981 2982 if (synchronousMode()) 2983 { 2984 throw new LDAPException(ResultCode.NOT_SUPPORTED, 2985 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 2986 } 2987 2988 final AsyncResultListener listener; 2989 if (resultListener == null) 2990 { 2991 listener = DiscardAsyncListener.getInstance(); 2992 } 2993 else 2994 { 2995 listener = resultListener; 2996 } 2997 2998 return modifyDNRequest.processAsync(this, listener); 2999 } 3000 3001 3002 3003 /** 3004 * Processes the provided modify DN request as an asynchronous operation. 3005 * 3006 * @param modifyDNRequest The modify DN request to be processed. It must 3007 * not be {@code null}. 3008 * @param resultListener The async result listener to use to handle the 3009 * response for the modify DN operation. It may be 3010 * {@code null} if the result is going to be obtained 3011 * from the returned {@code AsyncRequestID} object via 3012 * the {@code Future} API. 3013 * 3014 * @return An async request ID that may be used to reference the operation. 3015 * 3016 * @throws LDAPException If a problem occurs while sending the request. 3017 */ 3018 public AsyncRequestID asyncModifyDN( 3019 final ReadOnlyModifyDNRequest modifyDNRequest, 3020 final AsyncResultListener resultListener) 3021 throws LDAPException 3022 { 3023 if (synchronousMode()) 3024 { 3025 throw new LDAPException(ResultCode.NOT_SUPPORTED, 3026 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 3027 } 3028 3029 return asyncModifyDN((ModifyDNRequest) modifyDNRequest, resultListener); 3030 } 3031 3032 3033 3034 /** 3035 * Processes a search operation with the provided information. The search 3036 * result entries and references will be collected internally and included in 3037 * the {@code SearchResult} object that is returned. 3038 * <BR><BR> 3039 * Note that if the search does not complete successfully, an 3040 * {@code LDAPSearchException} will be thrown In some cases, one or more 3041 * search result entries or references may have been returned before the 3042 * failure response is received. In this case, the 3043 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3044 * {@code getSearchEntries}, {@code getReferenceCount}, and 3045 * {@code getSearchReferences} may be used to obtain information about those 3046 * entries and references. 3047 * 3048 * @param baseDN The base DN for the search request. It must not be 3049 * {@code null}. 3050 * @param scope The scope that specifies the range of entries that 3051 * should be examined for the search. 3052 * @param filter The string representation of the filter to use to 3053 * identify matching entries. It must not be 3054 * {@code null}. 3055 * @param attributes The set of attributes that should be returned in 3056 * matching entries. It may be {@code null} or empty if 3057 * the default attribute set (all user attributes) is to 3058 * be requested. 3059 * 3060 * @return A search result object that provides information about the 3061 * processing of the search, including the set of matching entries 3062 * and search references returned by the server. 3063 * 3064 * @throws LDAPSearchException If the search does not complete successfully, 3065 * or if a problem is encountered while parsing 3066 * the provided filter string, sending the 3067 * request, or reading the response. If one 3068 * or more entries or references were returned 3069 * before the failure was encountered, then the 3070 * {@code LDAPSearchException} object may be 3071 * examined to obtain information about those 3072 * entries and/or references. 3073 */ 3074 public SearchResult search(final String baseDN, final SearchScope scope, 3075 final String filter, final String... attributes) 3076 throws LDAPSearchException 3077 { 3078 ensureNotNull(baseDN, filter); 3079 3080 try 3081 { 3082 return search(new SearchRequest(baseDN, scope, filter, attributes)); 3083 } 3084 catch (LDAPSearchException lse) 3085 { 3086 debugException(lse); 3087 throw lse; 3088 } 3089 catch (LDAPException le) 3090 { 3091 debugException(le); 3092 throw new LDAPSearchException(le); 3093 } 3094 } 3095 3096 3097 3098 /** 3099 * Processes a search operation with the provided information. The search 3100 * result entries and references will be collected internally and included in 3101 * the {@code SearchResult} object that is returned. 3102 * <BR><BR> 3103 * Note that if the search does not complete successfully, an 3104 * {@code LDAPSearchException} will be thrown In some cases, one or more 3105 * search result entries or references may have been returned before the 3106 * failure response is received. In this case, the 3107 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3108 * {@code getSearchEntries}, {@code getReferenceCount}, and 3109 * {@code getSearchReferences} may be used to obtain information about those 3110 * entries and references. 3111 * 3112 * @param baseDN The base DN for the search request. It must not be 3113 * {@code null}. 3114 * @param scope The scope that specifies the range of entries that 3115 * should be examined for the search. 3116 * @param filter The filter to use to identify matching entries. It 3117 * must not be {@code null}. 3118 * @param attributes The set of attributes that should be returned in 3119 * matching entries. It may be {@code null} or empty if 3120 * the default attribute set (all user attributes) is to 3121 * be requested. 3122 * 3123 * @return A search result object that provides information about the 3124 * processing of the search, including the set of matching entries 3125 * and search references returned by the server. 3126 * 3127 * @throws LDAPSearchException If the search does not complete successfully, 3128 * or if a problem is encountered while sending 3129 * the request or reading the response. If one 3130 * or more entries or references were returned 3131 * before the failure was encountered, then the 3132 * {@code LDAPSearchException} object may be 3133 * examined to obtain information about those 3134 * entries and/or references. 3135 */ 3136 public SearchResult search(final String baseDN, final SearchScope scope, 3137 final Filter filter, final String... attributes) 3138 throws LDAPSearchException 3139 { 3140 ensureNotNull(baseDN, filter); 3141 3142 return search(new SearchRequest(baseDN, scope, filter, attributes)); 3143 } 3144 3145 3146 3147 /** 3148 * Processes a search operation with the provided information. 3149 * <BR><BR> 3150 * Note that if the search does not complete successfully, an 3151 * {@code LDAPSearchException} will be thrown In some cases, one or more 3152 * search result entries or references may have been returned before the 3153 * failure response is received. In this case, the 3154 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3155 * {@code getSearchEntries}, {@code getReferenceCount}, and 3156 * {@code getSearchReferences} may be used to obtain information about those 3157 * entries and references (although if a search result listener was provided, 3158 * then it will have been used to make any entries and references available, 3159 * and they will not be available through the {@code getSearchEntries} and 3160 * {@code getSearchReferences} methods). 3161 * 3162 * @param searchResultListener The search result listener that should be 3163 * used to return results to the client. It may 3164 * be {@code null} if the search results should 3165 * be collected internally and returned in the 3166 * {@code SearchResult} object. 3167 * @param baseDN The base DN for the search request. It must 3168 * not be {@code null}. 3169 * @param scope The scope that specifies the range of entries 3170 * that should be examined for the search. 3171 * @param filter The string representation of the filter to 3172 * use to identify matching entries. It must 3173 * not be {@code null}. 3174 * @param attributes The set of attributes that should be returned 3175 * in matching entries. It may be {@code null} 3176 * or empty if the default attribute set (all 3177 * user attributes) is to be requested. 3178 * 3179 * @return A search result object that provides information about the 3180 * processing of the search, potentially including the set of 3181 * matching entries and search references returned by the server. 3182 * 3183 * @throws LDAPSearchException If the search does not complete successfully, 3184 * or if a problem is encountered while parsing 3185 * the provided filter string, sending the 3186 * request, or reading the response. If one 3187 * or more entries or references were returned 3188 * before the failure was encountered, then the 3189 * {@code LDAPSearchException} object may be 3190 * examined to obtain information about those 3191 * entries and/or references. 3192 */ 3193 public SearchResult search(final SearchResultListener searchResultListener, 3194 final String baseDN, final SearchScope scope, 3195 final String filter, final String... attributes) 3196 throws LDAPSearchException 3197 { 3198 ensureNotNull(baseDN, filter); 3199 3200 try 3201 { 3202 return search(new SearchRequest(searchResultListener, baseDN, scope, 3203 filter, attributes)); 3204 } 3205 catch (LDAPSearchException lse) 3206 { 3207 debugException(lse); 3208 throw lse; 3209 } 3210 catch (LDAPException le) 3211 { 3212 debugException(le); 3213 throw new LDAPSearchException(le); 3214 } 3215 } 3216 3217 3218 3219 /** 3220 * Processes a search operation with the provided information. 3221 * <BR><BR> 3222 * Note that if the search does not complete successfully, an 3223 * {@code LDAPSearchException} will be thrown In some cases, one or more 3224 * search result entries or references may have been returned before the 3225 * failure response is received. In this case, the 3226 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3227 * {@code getSearchEntries}, {@code getReferenceCount}, and 3228 * {@code getSearchReferences} may be used to obtain information about those 3229 * entries and references (although if a search result listener was provided, 3230 * then it will have been used to make any entries and references available, 3231 * and they will not be available through the {@code getSearchEntries} and 3232 * {@code getSearchReferences} methods). 3233 * 3234 * @param searchResultListener The search result listener that should be 3235 * used to return results to the client. It may 3236 * be {@code null} if the search results should 3237 * be collected internally and returned in the 3238 * {@code SearchResult} object. 3239 * @param baseDN The base DN for the search request. It must 3240 * not be {@code null}. 3241 * @param scope The scope that specifies the range of entries 3242 * that should be examined for the search. 3243 * @param filter The filter to use to identify matching 3244 * entries. It must not be {@code null}. 3245 * @param attributes The set of attributes that should be returned 3246 * in matching entries. It may be {@code null} 3247 * or empty if the default attribute set (all 3248 * user attributes) is to be requested. 3249 * 3250 * @return A search result object that provides information about the 3251 * processing of the search, potentially including the set of 3252 * matching entries and search references returned by the server. 3253 * 3254 * @throws LDAPSearchException If the search does not complete successfully, 3255 * or if a problem is encountered while sending 3256 * the request or reading the response. If one 3257 * or more entries or references were returned 3258 * before the failure was encountered, then the 3259 * {@code LDAPSearchException} object may be 3260 * examined to obtain information about those 3261 * entries and/or references. 3262 */ 3263 public SearchResult search(final SearchResultListener searchResultListener, 3264 final String baseDN, final SearchScope scope, 3265 final Filter filter, final String... attributes) 3266 throws LDAPSearchException 3267 { 3268 ensureNotNull(baseDN, filter); 3269 3270 try 3271 { 3272 return search(new SearchRequest(searchResultListener, baseDN, scope, 3273 filter, attributes)); 3274 } 3275 catch (LDAPSearchException lse) 3276 { 3277 debugException(lse); 3278 throw lse; 3279 } 3280 catch (LDAPException le) 3281 { 3282 debugException(le); 3283 throw new LDAPSearchException(le); 3284 } 3285 } 3286 3287 3288 3289 /** 3290 * Processes a search operation with the provided information. The search 3291 * result entries and references will be collected internally and included in 3292 * the {@code SearchResult} object that is returned. 3293 * <BR><BR> 3294 * Note that if the search does not complete successfully, an 3295 * {@code LDAPSearchException} will be thrown In some cases, one or more 3296 * search result entries or references may have been returned before the 3297 * failure response is received. In this case, the 3298 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3299 * {@code getSearchEntries}, {@code getReferenceCount}, and 3300 * {@code getSearchReferences} may be used to obtain information about those 3301 * entries and references. 3302 * 3303 * @param baseDN The base DN for the search request. It must not be 3304 * {@code null}. 3305 * @param scope The scope that specifies the range of entries that 3306 * should be examined for the search. 3307 * @param derefPolicy The dereference policy the server should use for any 3308 * aliases encountered while processing the search. 3309 * @param sizeLimit The maximum number of entries that the server should 3310 * return for the search. A value of zero indicates that 3311 * there should be no limit. 3312 * @param timeLimit The maximum length of time in seconds that the server 3313 * should spend processing this search request. A value 3314 * of zero indicates that there should be no limit. 3315 * @param typesOnly Indicates whether to return only attribute names in 3316 * matching entries, or both attribute names and values. 3317 * @param filter The string representation of the filter to use to 3318 * identify matching entries. It must not be 3319 * {@code null}. 3320 * @param attributes The set of attributes that should be returned in 3321 * matching entries. It may be {@code null} or empty if 3322 * the default attribute set (all user attributes) is to 3323 * be requested. 3324 * 3325 * @return A search result object that provides information about the 3326 * processing of the search, including the set of matching entries 3327 * and search references returned by the server. 3328 * 3329 * @throws LDAPSearchException If the search does not complete successfully, 3330 * or if a problem is encountered while parsing 3331 * the provided filter string, sending the 3332 * request, or reading the response. If one 3333 * or more entries or references were returned 3334 * before the failure was encountered, then the 3335 * {@code LDAPSearchException} object may be 3336 * examined to obtain information about those 3337 * entries and/or references. 3338 */ 3339 public SearchResult search(final String baseDN, final SearchScope scope, 3340 final DereferencePolicy derefPolicy, 3341 final int sizeLimit, final int timeLimit, 3342 final boolean typesOnly, final String filter, 3343 final String... attributes) 3344 throws LDAPSearchException 3345 { 3346 ensureNotNull(baseDN, filter); 3347 3348 try 3349 { 3350 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 3351 timeLimit, typesOnly, filter, 3352 attributes)); 3353 } 3354 catch (LDAPSearchException lse) 3355 { 3356 debugException(lse); 3357 throw lse; 3358 } 3359 catch (LDAPException le) 3360 { 3361 debugException(le); 3362 throw new LDAPSearchException(le); 3363 } 3364 } 3365 3366 3367 3368 /** 3369 * Processes a search operation with the provided information. The search 3370 * result entries and references will be collected internally and included in 3371 * the {@code SearchResult} object that is returned. 3372 * <BR><BR> 3373 * Note that if the search does not complete successfully, an 3374 * {@code LDAPSearchException} will be thrown In some cases, one or more 3375 * search result entries or references may have been returned before the 3376 * failure response is received. In this case, the 3377 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3378 * {@code getSearchEntries}, {@code getReferenceCount}, and 3379 * {@code getSearchReferences} may be used to obtain information about those 3380 * entries and references. 3381 * 3382 * @param baseDN The base DN for the search request. It must not be 3383 * {@code null}. 3384 * @param scope The scope that specifies the range of entries that 3385 * should be examined for the search. 3386 * @param derefPolicy The dereference policy the server should use for any 3387 * aliases encountered while processing the search. 3388 * @param sizeLimit The maximum number of entries that the server should 3389 * return for the search. A value of zero indicates that 3390 * there should be no limit. 3391 * @param timeLimit The maximum length of time in seconds that the server 3392 * should spend processing this search request. A value 3393 * of zero indicates that there should be no limit. 3394 * @param typesOnly Indicates whether to return only attribute names in 3395 * matching entries, or both attribute names and values. 3396 * @param filter The filter to use to identify matching entries. It 3397 * must not be {@code null}. 3398 * @param attributes The set of attributes that should be returned in 3399 * matching entries. It may be {@code null} or empty if 3400 * the default attribute set (all user attributes) is to 3401 * be requested. 3402 * 3403 * @return A search result object that provides information about the 3404 * processing of the search, including the set of matching entries 3405 * and search references returned by the server. 3406 * 3407 * @throws LDAPSearchException If the search does not complete successfully, 3408 * or if a problem is encountered while sending 3409 * the request or reading the response. If one 3410 * or more entries or references were returned 3411 * before the failure was encountered, then the 3412 * {@code LDAPSearchException} object may be 3413 * examined to obtain information about those 3414 * entries and/or references. 3415 */ 3416 public SearchResult search(final String baseDN, final SearchScope scope, 3417 final DereferencePolicy derefPolicy, 3418 final int sizeLimit, final int timeLimit, 3419 final boolean typesOnly, final Filter filter, 3420 final String... attributes) 3421 throws LDAPSearchException 3422 { 3423 ensureNotNull(baseDN, filter); 3424 3425 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 3426 timeLimit, typesOnly, filter, attributes)); 3427 } 3428 3429 3430 3431 /** 3432 * Processes a search operation with the provided information. 3433 * <BR><BR> 3434 * Note that if the search does not complete successfully, an 3435 * {@code LDAPSearchException} will be thrown In some cases, one or more 3436 * search result entries or references may have been returned before the 3437 * failure response is received. In this case, the 3438 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3439 * {@code getSearchEntries}, {@code getReferenceCount}, and 3440 * {@code getSearchReferences} may be used to obtain information about those 3441 * entries and references (although if a search result listener was provided, 3442 * then it will have been used to make any entries and references available, 3443 * and they will not be available through the {@code getSearchEntries} and 3444 * {@code getSearchReferences} methods). 3445 * 3446 * @param searchResultListener The search result listener that should be 3447 * used to return results to the client. It may 3448 * be {@code null} if the search results should 3449 * be collected internally and returned in the 3450 * {@code SearchResult} object. 3451 * @param baseDN The base DN for the search request. It must 3452 * not be {@code null}. 3453 * @param scope The scope that specifies the range of entries 3454 * that should be examined for the search. 3455 * @param derefPolicy The dereference policy the server should use 3456 * for any aliases encountered while processing 3457 * the search. 3458 * @param sizeLimit The maximum number of entries that the server 3459 * should return for the search. A value of 3460 * zero indicates that there should be no limit. 3461 * @param timeLimit The maximum length of time in seconds that 3462 * the server should spend processing this 3463 * search request. A value of zero indicates 3464 * that there should be no limit. 3465 * @param typesOnly Indicates whether to return only attribute 3466 * names in matching entries, or both attribute 3467 * names and values. 3468 * @param filter The string representation of the filter to 3469 * use to identify matching entries. It must 3470 * not be {@code null}. 3471 * @param attributes The set of attributes that should be returned 3472 * in matching entries. It may be {@code null} 3473 * or empty if the default attribute set (all 3474 * user attributes) is to be requested. 3475 * 3476 * @return A search result object that provides information about the 3477 * processing of the search, potentially including the set of 3478 * matching entries and search references returned by the server. 3479 * 3480 * @throws LDAPSearchException If the search does not complete successfully, 3481 * or if a problem is encountered while parsing 3482 * the provided filter string, sending the 3483 * request, or reading the response. If one 3484 * or more entries or references were returned 3485 * before the failure was encountered, then the 3486 * {@code LDAPSearchException} object may be 3487 * examined to obtain information about those 3488 * entries and/or references. 3489 */ 3490 public SearchResult search(final SearchResultListener searchResultListener, 3491 final String baseDN, final SearchScope scope, 3492 final DereferencePolicy derefPolicy, 3493 final int sizeLimit, final int timeLimit, 3494 final boolean typesOnly, final String filter, 3495 final String... attributes) 3496 throws LDAPSearchException 3497 { 3498 ensureNotNull(baseDN, filter); 3499 3500 try 3501 { 3502 return search(new SearchRequest(searchResultListener, baseDN, scope, 3503 derefPolicy, sizeLimit, timeLimit, 3504 typesOnly, filter, attributes)); 3505 } 3506 catch (LDAPSearchException lse) 3507 { 3508 debugException(lse); 3509 throw lse; 3510 } 3511 catch (LDAPException le) 3512 { 3513 debugException(le); 3514 throw new LDAPSearchException(le); 3515 } 3516 } 3517 3518 3519 3520 /** 3521 * Processes a search operation with the provided information. 3522 * <BR><BR> 3523 * Note that if the search does not complete successfully, an 3524 * {@code LDAPSearchException} will be thrown In some cases, one or more 3525 * search result entries or references may have been returned before the 3526 * failure response is received. In this case, the 3527 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3528 * {@code getSearchEntries}, {@code getReferenceCount}, and 3529 * {@code getSearchReferences} may be used to obtain information about those 3530 * entries and references (although if a search result listener was provided, 3531 * then it will have been used to make any entries and references available, 3532 * and they will not be available through the {@code getSearchEntries} and 3533 * {@code getSearchReferences} methods). 3534 * 3535 * @param searchResultListener The search result listener that should be 3536 * used to return results to the client. It may 3537 * be {@code null} if the search results should 3538 * be collected internally and returned in the 3539 * {@code SearchResult} object. 3540 * @param baseDN The base DN for the search request. It must 3541 * not be {@code null}. 3542 * @param scope The scope that specifies the range of entries 3543 * that should be examined for the search. 3544 * @param derefPolicy The dereference policy the server should use 3545 * for any aliases encountered while processing 3546 * the search. 3547 * @param sizeLimit The maximum number of entries that the server 3548 * should return for the search. A value of 3549 * zero indicates that there should be no limit. 3550 * @param timeLimit The maximum length of time in seconds that 3551 * the server should spend processing this 3552 * search request. A value of zero indicates 3553 * that there should be no limit. 3554 * @param typesOnly Indicates whether to return only attribute 3555 * names in matching entries, or both attribute 3556 * names and values. 3557 * @param filter The filter to use to identify matching 3558 * entries. It must not be {@code null}. 3559 * @param attributes The set of attributes that should be returned 3560 * in matching entries. It may be {@code null} 3561 * or empty if the default attribute set (all 3562 * user attributes) is to be requested. 3563 * 3564 * @return A search result object that provides information about the 3565 * processing of the search, potentially including the set of 3566 * matching entries and search references returned by the server. 3567 * 3568 * @throws LDAPSearchException If the search does not complete successfully, 3569 * or if a problem is encountered while sending 3570 * the request or reading the response. If one 3571 * or more entries or references were returned 3572 * before the failure was encountered, then the 3573 * {@code LDAPSearchException} object may be 3574 * examined to obtain information about those 3575 * entries and/or references. 3576 */ 3577 public SearchResult search(final SearchResultListener searchResultListener, 3578 final String baseDN, final SearchScope scope, 3579 final DereferencePolicy derefPolicy, 3580 final int sizeLimit, final int timeLimit, 3581 final boolean typesOnly, final Filter filter, 3582 final String... attributes) 3583 throws LDAPSearchException 3584 { 3585 ensureNotNull(baseDN, filter); 3586 3587 return search(new SearchRequest(searchResultListener, baseDN, scope, 3588 derefPolicy, sizeLimit, timeLimit, 3589 typesOnly, filter, attributes)); 3590 } 3591 3592 3593 3594 /** 3595 * Processes the provided search request. 3596 * <BR><BR> 3597 * Note that if the search does not complete successfully, an 3598 * {@code LDAPSearchException} will be thrown In some cases, one or more 3599 * search result entries or references may have been returned before the 3600 * failure response is received. In this case, the 3601 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3602 * {@code getSearchEntries}, {@code getReferenceCount}, and 3603 * {@code getSearchReferences} may be used to obtain information about those 3604 * entries and references (although if a search result listener was provided, 3605 * then it will have been used to make any entries and references available, 3606 * and they will not be available through the {@code getSearchEntries} and 3607 * {@code getSearchReferences} methods). 3608 * 3609 * @param searchRequest The search request to be processed. It must not be 3610 * {@code null}. 3611 * 3612 * @return A search result object that provides information about the 3613 * processing of the search, potentially including the set of 3614 * matching entries and search references returned by the server. 3615 * 3616 * @throws LDAPSearchException If the search does not complete successfully, 3617 * or if a problem is encountered while sending 3618 * the request or reading the response. If one 3619 * or more entries or references were returned 3620 * before the failure was encountered, then the 3621 * {@code LDAPSearchException} object may be 3622 * examined to obtain information about those 3623 * entries and/or references. 3624 */ 3625 public SearchResult search(final SearchRequest searchRequest) 3626 throws LDAPSearchException 3627 { 3628 ensureNotNull(searchRequest); 3629 3630 final SearchResult searchResult; 3631 try 3632 { 3633 searchResult = searchRequest.process(this, 1); 3634 } 3635 catch (LDAPSearchException lse) 3636 { 3637 debugException(lse); 3638 throw lse; 3639 } 3640 catch (LDAPException le) 3641 { 3642 debugException(le); 3643 throw new LDAPSearchException(le); 3644 } 3645 3646 if (! searchResult.getResultCode().equals(ResultCode.SUCCESS)) 3647 { 3648 throw new LDAPSearchException(searchResult); 3649 } 3650 3651 return searchResult; 3652 } 3653 3654 3655 3656 /** 3657 * Processes the provided search request. 3658 * <BR><BR> 3659 * Note that if the search does not complete successfully, an 3660 * {@code LDAPSearchException} will be thrown In some cases, one or more 3661 * search result entries or references may have been returned before the 3662 * failure response is received. In this case, the 3663 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3664 * {@code getSearchEntries}, {@code getReferenceCount}, and 3665 * {@code getSearchReferences} may be used to obtain information about those 3666 * entries and references (although if a search result listener was provided, 3667 * then it will have been used to make any entries and references available, 3668 * and they will not be available through the {@code getSearchEntries} and 3669 * {@code getSearchReferences} methods). 3670 * 3671 * @param searchRequest The search request to be processed. It must not be 3672 * {@code null}. 3673 * 3674 * @return A search result object that provides information about the 3675 * processing of the search, potentially including the set of 3676 * matching entries and search references returned by the server. 3677 * 3678 * @throws LDAPSearchException If the search does not complete successfully, 3679 * or if a problem is encountered while sending 3680 * the request or reading the response. If one 3681 * or more entries or references were returned 3682 * before the failure was encountered, then the 3683 * {@code LDAPSearchException} object may be 3684 * examined to obtain information about those 3685 * entries and/or references. 3686 */ 3687 public SearchResult search(final ReadOnlySearchRequest searchRequest) 3688 throws LDAPSearchException 3689 { 3690 return search((SearchRequest) searchRequest); 3691 } 3692 3693 3694 3695 /** 3696 * Processes a search operation with the provided information. It is expected 3697 * that at most one entry will be returned from the search, and that no 3698 * additional content from the successful search result (e.g., diagnostic 3699 * message or response controls) are needed. 3700 * <BR><BR> 3701 * Note that if the search does not complete successfully, an 3702 * {@code LDAPSearchException} will be thrown In some cases, one or more 3703 * search result entries or references may have been returned before the 3704 * failure response is received. In this case, the 3705 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3706 * {@code getSearchEntries}, {@code getReferenceCount}, and 3707 * {@code getSearchReferences} may be used to obtain information about those 3708 * entries and references. 3709 * 3710 * @param baseDN The base DN for the search request. It must not be 3711 * {@code null}. 3712 * @param scope The scope that specifies the range of entries that 3713 * should be examined for the search. 3714 * @param filter The string representation of the filter to use to 3715 * identify matching entries. It must not be 3716 * {@code null}. 3717 * @param attributes The set of attributes that should be returned in 3718 * matching entries. It may be {@code null} or empty if 3719 * the default attribute set (all user attributes) is to 3720 * be requested. 3721 * 3722 * @return The entry that was returned from the search, or {@code null} if no 3723 * entry was returned or the base entry does not exist. 3724 * 3725 * @throws LDAPSearchException If the search does not complete successfully, 3726 * if more than a single entry is returned, or 3727 * if a problem is encountered while parsing the 3728 * provided filter string, sending the request, 3729 * or reading the response. If one or more 3730 * entries or references were returned before 3731 * the failure was encountered, then the 3732 * {@code LDAPSearchException} object may be 3733 * examined to obtain information about those 3734 * entries and/or references. 3735 */ 3736 public SearchResultEntry searchForEntry(final String baseDN, 3737 final SearchScope scope, 3738 final String filter, 3739 final String... attributes) 3740 throws LDAPSearchException 3741 { 3742 final SearchRequest r; 3743 try 3744 { 3745 r = new SearchRequest(baseDN, scope, DereferencePolicy.NEVER, 1, 0, false, 3746 filter, attributes); 3747 } 3748 catch (final LDAPException le) 3749 { 3750 debugException(le); 3751 throw new LDAPSearchException(le); 3752 } 3753 3754 return searchForEntry(r); 3755 } 3756 3757 3758 3759 /** 3760 * Processes a search operation with the provided information. It is expected 3761 * that at most one entry will be returned from the search, and that no 3762 * additional content from the successful search result (e.g., diagnostic 3763 * message or response controls) are needed. 3764 * <BR><BR> 3765 * Note that if the search does not complete successfully, an 3766 * {@code LDAPSearchException} will be thrown In some cases, one or more 3767 * search result entries or references may have been returned before the 3768 * failure response is received. In this case, the 3769 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3770 * {@code getSearchEntries}, {@code getReferenceCount}, and 3771 * {@code getSearchReferences} may be used to obtain information about those 3772 * entries and references. 3773 * 3774 * @param baseDN The base DN for the search request. It must not be 3775 * {@code null}. 3776 * @param scope The scope that specifies the range of entries that 3777 * should be examined for the search. 3778 * @param filter The string representation of the filter to use to 3779 * identify matching entries. It must not be 3780 * {@code null}. 3781 * @param attributes The set of attributes that should be returned in 3782 * matching entries. It may be {@code null} or empty if 3783 * the default attribute set (all user attributes) is to 3784 * be requested. 3785 * 3786 * @return The entry that was returned from the search, or {@code null} if no 3787 * entry was returned or the base entry does not exist. 3788 * 3789 * @throws LDAPSearchException If the search does not complete successfully, 3790 * if more than a single entry is returned, or 3791 * if a problem is encountered while parsing the 3792 * provided filter string, sending the request, 3793 * or reading the response. If one or more 3794 * entries or references were returned before 3795 * the failure was encountered, then the 3796 * {@code LDAPSearchException} object may be 3797 * examined to obtain information about those 3798 * entries and/or references. 3799 */ 3800 public SearchResultEntry searchForEntry(final String baseDN, 3801 final SearchScope scope, 3802 final Filter filter, 3803 final String... attributes) 3804 throws LDAPSearchException 3805 { 3806 return searchForEntry(new SearchRequest(baseDN, scope, 3807 DereferencePolicy.NEVER, 1, 0, false, filter, attributes)); 3808 } 3809 3810 3811 3812 /** 3813 * Processes a search operation with the provided information. It is expected 3814 * that at most one entry will be returned from the search, and that no 3815 * additional content from the successful search result (e.g., diagnostic 3816 * message or response controls) are needed. 3817 * <BR><BR> 3818 * Note that if the search does not complete successfully, an 3819 * {@code LDAPSearchException} will be thrown In some cases, one or more 3820 * search result entries or references may have been returned before the 3821 * failure response is received. In this case, the 3822 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3823 * {@code getSearchEntries}, {@code getReferenceCount}, and 3824 * {@code getSearchReferences} may be used to obtain information about those 3825 * entries and references. 3826 * 3827 * @param baseDN The base DN for the search request. It must not be 3828 * {@code null}. 3829 * @param scope The scope that specifies the range of entries that 3830 * should be examined for the search. 3831 * @param derefPolicy The dereference policy the server should use for any 3832 * aliases encountered while processing the search. 3833 * @param timeLimit The maximum length of time in seconds that the server 3834 * should spend processing this search request. A value 3835 * of zero indicates that there should be no limit. 3836 * @param typesOnly Indicates whether to return only attribute names in 3837 * matching entries, or both attribute names and values. 3838 * @param filter The string representation of the filter to use to 3839 * identify matching entries. It must not be 3840 * {@code null}. 3841 * @param attributes The set of attributes that should be returned in 3842 * matching entries. It may be {@code null} or empty if 3843 * the default attribute set (all user attributes) is to 3844 * be requested. 3845 * 3846 * @return The entry that was returned from the search, or {@code null} if no 3847 * entry was returned or the base entry does not exist. 3848 * 3849 * @throws LDAPSearchException If the search does not complete successfully, 3850 * if more than a single entry is returned, or 3851 * if a problem is encountered while parsing the 3852 * provided filter string, sending the request, 3853 * or reading the response. If one or more 3854 * entries or references were returned before 3855 * the failure was encountered, then the 3856 * {@code LDAPSearchException} object may be 3857 * examined to obtain information about those 3858 * entries and/or references. 3859 */ 3860 public SearchResultEntry searchForEntry(final String baseDN, 3861 final SearchScope scope, 3862 final DereferencePolicy derefPolicy, 3863 final int timeLimit, 3864 final boolean typesOnly, 3865 final String filter, 3866 final String... attributes) 3867 throws LDAPSearchException 3868 { 3869 final SearchRequest r; 3870 try 3871 { 3872 r = new SearchRequest(baseDN, scope, derefPolicy, 1, timeLimit, typesOnly, 3873 filter, attributes); 3874 } 3875 catch (final LDAPException le) 3876 { 3877 debugException(le); 3878 throw new LDAPSearchException(le); 3879 } 3880 3881 return searchForEntry(r); 3882 } 3883 3884 3885 3886 /** 3887 * Processes a search operation with the provided information. It is expected 3888 * that at most one entry will be returned from the search, and that no 3889 * additional content from the successful search result (e.g., diagnostic 3890 * message or response controls) are needed. 3891 * <BR><BR> 3892 * Note that if the search does not complete successfully, an 3893 * {@code LDAPSearchException} will be thrown In some cases, one or more 3894 * search result entries or references may have been returned before the 3895 * failure response is received. In this case, the 3896 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3897 * {@code getSearchEntries}, {@code getReferenceCount}, and 3898 * {@code getSearchReferences} may be used to obtain information about those 3899 * entries and references. 3900 * 3901 * @param baseDN The base DN for the search request. It must not be 3902 * {@code null}. 3903 * @param scope The scope that specifies the range of entries that 3904 * should be examined for the search. 3905 * @param derefPolicy The dereference policy the server should use for any 3906 * aliases encountered while processing the search. 3907 * @param timeLimit The maximum length of time in seconds that the server 3908 * should spend processing this search request. A value 3909 * of zero indicates that there should be no limit. 3910 * @param typesOnly Indicates whether to return only attribute names in 3911 * matching entries, or both attribute names and values. 3912 * @param filter The filter to use to identify matching entries. It 3913 * must not be {@code null}. 3914 * @param attributes The set of attributes that should be returned in 3915 * matching entries. It may be {@code null} or empty if 3916 * the default attribute set (all user attributes) is to 3917 * be requested. 3918 * 3919 * @return The entry that was returned from the search, or {@code null} if no 3920 * entry was returned or the base entry does not exist. 3921 * 3922 * @throws LDAPSearchException If the search does not complete successfully, 3923 * if more than a single entry is returned, or 3924 * if a problem is encountered while parsing the 3925 * provided filter string, sending the request, 3926 * or reading the response. If one or more 3927 * entries or references were returned before 3928 * the failure was encountered, then the 3929 * {@code LDAPSearchException} object may be 3930 * examined to obtain information about those 3931 * entries and/or references. 3932 */ 3933 public SearchResultEntry searchForEntry(final String baseDN, 3934 final SearchScope scope, 3935 final DereferencePolicy derefPolicy, 3936 final int timeLimit, 3937 final boolean typesOnly, 3938 final Filter filter, 3939 final String... attributes) 3940 throws LDAPSearchException 3941 { 3942 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1, 3943 timeLimit, typesOnly, filter, attributes)); 3944 } 3945 3946 3947 3948 /** 3949 * Processes the provided search request. It is expected that at most one 3950 * entry will be returned from the search, and that no additional content from 3951 * the successful search result (e.g., diagnostic message or response 3952 * controls) are needed. 3953 * <BR><BR> 3954 * Note that if the search does not complete successfully, an 3955 * {@code LDAPSearchException} will be thrown In some cases, one or more 3956 * search result entries or references may have been returned before the 3957 * failure response is received. In this case, the 3958 * {@code LDAPSearchException} methods like {@code getEntryCount}, 3959 * {@code getSearchEntries}, {@code getReferenceCount}, and 3960 * {@code getSearchReferences} may be used to obtain information about those 3961 * entries and references. 3962 * 3963 * @param searchRequest The search request to be processed. If it is 3964 * configured with a search result listener or a size 3965 * limit other than one, then the provided request will 3966 * be duplicated with the appropriate settings. 3967 * 3968 * @return The entry that was returned from the search, or {@code null} if no 3969 * entry was returned or the base entry does not exist. 3970 * 3971 * @throws LDAPSearchException If the search does not complete successfully, 3972 * if more than a single entry is returned, or 3973 * if a problem is encountered while parsing the 3974 * provided filter string, sending the request, 3975 * or reading the response. If one or more 3976 * entries or references were returned before 3977 * the failure was encountered, then the 3978 * {@code LDAPSearchException} object may be 3979 * examined to obtain information about those 3980 * entries and/or references. 3981 */ 3982 public SearchResultEntry searchForEntry(final SearchRequest searchRequest) 3983 throws LDAPSearchException 3984 { 3985 final SearchRequest r; 3986 if ((searchRequest.getSearchResultListener() != null) || 3987 (searchRequest.getSizeLimit() != 1)) 3988 { 3989 r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(), 3990 searchRequest.getDereferencePolicy(), 1, 3991 searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(), 3992 searchRequest.getFilter(), searchRequest.getAttributes()); 3993 3994 r.setFollowReferrals(searchRequest.followReferralsInternal()); 3995 r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null)); 3996 3997 if (searchRequest.hasControl()) 3998 { 3999 r.setControlsInternal(searchRequest.getControls()); 4000 } 4001 } 4002 else 4003 { 4004 r = searchRequest; 4005 } 4006 4007 final SearchResult result; 4008 try 4009 { 4010 result = search(r); 4011 } 4012 catch (final LDAPSearchException lse) 4013 { 4014 debugException(lse); 4015 4016 if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT) 4017 { 4018 return null; 4019 } 4020 4021 throw lse; 4022 } 4023 4024 if (result.getEntryCount() == 0) 4025 { 4026 return null; 4027 } 4028 else 4029 { 4030 return result.getSearchEntries().get(0); 4031 } 4032 } 4033 4034 4035 4036 /** 4037 * Processes the provided search request. It is expected that at most one 4038 * entry will be returned from the search, and that no additional content from 4039 * the successful search result (e.g., diagnostic message or response 4040 * controls) are needed. 4041 * <BR><BR> 4042 * Note that if the search does not complete successfully, an 4043 * {@code LDAPSearchException} will be thrown In some cases, one or more 4044 * search result entries or references may have been returned before the 4045 * failure response is received. In this case, the 4046 * {@code LDAPSearchException} methods like {@code getEntryCount}, 4047 * {@code getSearchEntries}, {@code getReferenceCount}, and 4048 * {@code getSearchReferences} may be used to obtain information about those 4049 * entries and references. 4050 * 4051 * @param searchRequest The search request to be processed. If it is 4052 * configured with a search result listener or a size 4053 * limit other than one, then the provided request will 4054 * be duplicated with the appropriate settings. 4055 * 4056 * @return The entry that was returned from the search, or {@code null} if no 4057 * entry was returned or the base entry does not exist. 4058 * 4059 * @throws LDAPSearchException If the search does not complete successfully, 4060 * if more than a single entry is returned, or 4061 * if a problem is encountered while parsing the 4062 * provided filter string, sending the request, 4063 * or reading the response. If one or more 4064 * entries or references were returned before 4065 * the failure was encountered, then the 4066 * {@code LDAPSearchException} object may be 4067 * examined to obtain information about those 4068 * entries and/or references. 4069 */ 4070 public SearchResultEntry searchForEntry( 4071 final ReadOnlySearchRequest searchRequest) 4072 throws LDAPSearchException 4073 { 4074 return searchForEntry((SearchRequest) searchRequest); 4075 } 4076 4077 4078 4079 /** 4080 * Processes the provided search request as an asynchronous operation. 4081 * 4082 * @param searchRequest The search request to be processed. It must not be 4083 * {@code null}, and it must be configured with a 4084 * search result listener that is also an 4085 * {@code AsyncSearchResultListener}. 4086 * 4087 * @return An async request ID that may be used to reference the operation. 4088 * 4089 * @throws LDAPException If the provided search request does not have a 4090 * search result listener that is an 4091 * {@code AsyncSearchResultListener}, or if a problem 4092 * occurs while sending the request. 4093 */ 4094 public AsyncRequestID asyncSearch(final SearchRequest searchRequest) 4095 throws LDAPException 4096 { 4097 ensureNotNull(searchRequest); 4098 4099 final SearchResultListener searchListener = 4100 searchRequest.getSearchResultListener(); 4101 if (searchListener == null) 4102 { 4103 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 4104 ERR_ASYNC_SEARCH_NO_LISTENER.get()); 4105 debugCodingError(le); 4106 throw le; 4107 } 4108 else if (! (searchListener instanceof AsyncSearchResultListener)) 4109 { 4110 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 4111 ERR_ASYNC_SEARCH_INVALID_LISTENER.get()); 4112 debugCodingError(le); 4113 throw le; 4114 } 4115 4116 if (synchronousMode()) 4117 { 4118 throw new LDAPException(ResultCode.NOT_SUPPORTED, 4119 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 4120 } 4121 4122 return searchRequest.processAsync(this, 4123 (AsyncSearchResultListener) searchListener); 4124 } 4125 4126 4127 4128 /** 4129 * Processes the provided search request as an asynchronous operation. 4130 * 4131 * @param searchRequest The search request to be processed. It must not be 4132 * {@code null}, and it must be configured with a 4133 * search result listener that is also an 4134 * {@code AsyncSearchResultListener}. 4135 * 4136 * @return An async request ID that may be used to reference the operation. 4137 * 4138 * @throws LDAPException If the provided search request does not have a 4139 * search result listener that is an 4140 * {@code AsyncSearchResultListener}, or if a problem 4141 * occurs while sending the request. 4142 */ 4143 public AsyncRequestID asyncSearch(final ReadOnlySearchRequest searchRequest) 4144 throws LDAPException 4145 { 4146 if (synchronousMode()) 4147 { 4148 throw new LDAPException(ResultCode.NOT_SUPPORTED, 4149 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); 4150 } 4151 4152 return asyncSearch((SearchRequest) searchRequest); 4153 } 4154 4155 4156 4157 /** 4158 * Processes the provided generic request and returns the result. This may 4159 * be useful for cases in which it is not known what type of operation the 4160 * request represents. 4161 * 4162 * @param request The request to be processed. 4163 * 4164 * @return The result obtained from processing the request. 4165 * 4166 * @throws LDAPException If a problem occurs while sending the request or 4167 * reading the response. Note simply having a 4168 * non-success result code in the response will not 4169 * cause an exception to be thrown. 4170 */ 4171 public LDAPResult processOperation(final LDAPRequest request) 4172 throws LDAPException 4173 { 4174 return request.process(this, 1); 4175 } 4176 4177 4178 4179 /** 4180 * Retrieves the referral connector that should be used to establish 4181 * connections for use when following referrals. 4182 * 4183 * @return The referral connector that should be used to establish 4184 * connections for use when following referrals. 4185 */ 4186 public ReferralConnector getReferralConnector() 4187 { 4188 if (referralConnector == null) 4189 { 4190 return this; 4191 } 4192 else 4193 { 4194 return referralConnector; 4195 } 4196 } 4197 4198 4199 4200 /** 4201 * Specifies the referral connector that should be used to establish 4202 * connections for use when following referrals. 4203 * 4204 * @param referralConnector The referral connector that should be used to 4205 * establish connections for use when following 4206 * referrals. 4207 */ 4208 public void setReferralConnector(final ReferralConnector referralConnector) 4209 { 4210 if (referralConnector == null) 4211 { 4212 this.referralConnector = this; 4213 } 4214 else 4215 { 4216 this.referralConnector = referralConnector; 4217 } 4218 } 4219 4220 4221 4222 /** 4223 * Sends the provided LDAP message to the server over this connection. 4224 * 4225 * @param message The LDAP message to send to the target server. 4226 * 4227 * @throws LDAPException If a problem occurs while sending the request. 4228 */ 4229 void sendMessage(final LDAPMessage message) 4230 throws LDAPException 4231 { 4232 if (needsReconnect.compareAndSet(true, false)) 4233 { 4234 reconnect(); 4235 } 4236 4237 final LDAPConnectionInternals internals = connectionInternals; 4238 if (internals == null) 4239 { 4240 throw new LDAPException(ResultCode.SERVER_DOWN, 4241 ERR_CONN_NOT_ESTABLISHED.get()); 4242 } 4243 else 4244 { 4245 @SuppressWarnings("deprecation") 4246 final boolean autoReconnect = connectionOptions.autoReconnect(); 4247 internals.sendMessage(message, autoReconnect); 4248 lastCommunicationTime = System.currentTimeMillis(); 4249 } 4250 } 4251 4252 4253 4254 /** 4255 * Retrieves the message ID that should be used for the next request sent 4256 * over this connection. 4257 * 4258 * @return The message ID that should be used for the next request sent over 4259 * this connection, or -1 if this connection is not established. 4260 */ 4261 int nextMessageID() 4262 { 4263 final LDAPConnectionInternals internals = connectionInternals; 4264 if (internals == null) 4265 { 4266 return -1; 4267 } 4268 else 4269 { 4270 return internals.nextMessageID(); 4271 } 4272 } 4273 4274 4275 4276 /** 4277 * Retrieves the disconnect info object for this connection, if available. 4278 * 4279 * @return The disconnect info for this connection, or {@code null} if none 4280 * is set. 4281 */ 4282 DisconnectInfo getDisconnectInfo() 4283 { 4284 return disconnectInfo.get(); 4285 } 4286 4287 4288 4289 /** 4290 * Sets the disconnect type, message, and cause for this connection, if those 4291 * values have not been previously set. It will not overwrite any values that 4292 * had been previously set. 4293 * <BR><BR> 4294 * This method may be called by code which is not part of the LDAP SDK to 4295 * provide additional information about the reason for the closure. In that 4296 * case, this method must be called before the call to 4297 * {@link LDAPConnection#close}. 4298 * 4299 * @param type The disconnect type. It must not be {@code null}. 4300 * @param message A message providing additional information about the 4301 * disconnect. It may be {@code null} if no message is 4302 * available. 4303 * @param cause The exception that was caught to trigger the disconnect. 4304 * It may be {@code null} if the disconnect was not triggered 4305 * by an exception. 4306 */ 4307 public void setDisconnectInfo(final DisconnectType type, final String message, 4308 final Throwable cause) 4309 { 4310 disconnectInfo.compareAndSet(null, 4311 new DisconnectInfo(this, type, message, cause)); 4312 } 4313 4314 4315 4316 /** 4317 * Sets the disconnect info for this connection, if it is not already set. 4318 * 4319 * @param info The disconnect info to be set, if it is not already set. 4320 * 4321 * @return The disconnect info set for the connection, whether it was 4322 * previously or newly set. 4323 */ 4324 DisconnectInfo setDisconnectInfo(final DisconnectInfo info) 4325 { 4326 disconnectInfo.compareAndSet(null, info); 4327 return disconnectInfo.get(); 4328 } 4329 4330 4331 4332 /** 4333 * Retrieves the disconnect type for this connection, if available. 4334 * 4335 * @return The disconnect type for this connection, or {@code null} if no 4336 * disconnect type has been set. 4337 */ 4338 public DisconnectType getDisconnectType() 4339 { 4340 final DisconnectInfo di = disconnectInfo.get(); 4341 if (di == null) 4342 { 4343 return null; 4344 } 4345 else 4346 { 4347 return di.getType(); 4348 } 4349 } 4350 4351 4352 4353 /** 4354 * Retrieves the disconnect message for this connection, which may provide 4355 * additional information about the reason for the disconnect, if available. 4356 * 4357 * @return The disconnect message for this connection, or {@code null} if 4358 * no disconnect message has been set. 4359 */ 4360 public String getDisconnectMessage() 4361 { 4362 final DisconnectInfo di = disconnectInfo.get(); 4363 if (di == null) 4364 { 4365 return null; 4366 } 4367 else 4368 { 4369 return di.getMessage(); 4370 } 4371 } 4372 4373 4374 4375 /** 4376 * Retrieves the disconnect cause for this connection, which is an exception 4377 * or error that triggered the connection termination, if available. 4378 * 4379 * @return The disconnect cause for this connection, or {@code null} if no 4380 * disconnect cause has been set. 4381 */ 4382 public Throwable getDisconnectCause() 4383 { 4384 final DisconnectInfo di = disconnectInfo.get(); 4385 if (di == null) 4386 { 4387 return null; 4388 } 4389 else 4390 { 4391 return di.getCause(); 4392 } 4393 } 4394 4395 4396 4397 /** 4398 * Indicates that this connection has been closed and is no longer available 4399 * for use. 4400 */ 4401 void setClosed() 4402 { 4403 needsReconnect.set(false); 4404 4405 if (disconnectInfo.get() == null) 4406 { 4407 try 4408 { 4409 final StackTraceElement[] stackElements = 4410 Thread.currentThread().getStackTrace(); 4411 final StackTraceElement[] parentStackElements = 4412 new StackTraceElement[stackElements.length - 1]; 4413 System.arraycopy(stackElements, 1, parentStackElements, 0, 4414 parentStackElements.length); 4415 4416 setDisconnectInfo(DisconnectType.OTHER, 4417 ERR_CONN_CLOSED_BY_UNEXPECTED_CALL_PATH.get( 4418 getStackTrace(parentStackElements)), 4419 null); 4420 } 4421 catch (final Exception e) 4422 { 4423 debugException(e); 4424 } 4425 } 4426 4427 connectionStatistics.incrementNumDisconnects(); 4428 final LDAPConnectionInternals internals = connectionInternals; 4429 if (internals != null) 4430 { 4431 internals.close(); 4432 connectionInternals = null; 4433 } 4434 4435 cachedSchema = null; 4436 lastCommunicationTime = -1L; 4437 4438 synchronized (this) 4439 { 4440 final Timer t = timer; 4441 timer = null; 4442 4443 if (t != null) 4444 { 4445 t.cancel(); 4446 } 4447 } 4448 } 4449 4450 4451 4452 /** 4453 * Registers the provided response acceptor with the connection reader. 4454 * 4455 * @param messageID The message ID for which the acceptor is to be 4456 * registered. 4457 * @param responseAcceptor The response acceptor to register. 4458 * 4459 * @throws LDAPException If another message acceptor is already registered 4460 * with the provided message ID. 4461 */ 4462 void registerResponseAcceptor(final int messageID, 4463 final ResponseAcceptor responseAcceptor) 4464 throws LDAPException 4465 { 4466 if (needsReconnect.compareAndSet(true, false)) 4467 { 4468 reconnect(); 4469 } 4470 4471 final LDAPConnectionInternals internals = connectionInternals; 4472 if (internals == null) 4473 { 4474 throw new LDAPException(ResultCode.SERVER_DOWN, 4475 ERR_CONN_NOT_ESTABLISHED.get()); 4476 } 4477 else 4478 { 4479 internals.registerResponseAcceptor(messageID, responseAcceptor); 4480 } 4481 } 4482 4483 4484 4485 /** 4486 * Deregisters the response acceptor associated with the provided message ID. 4487 * 4488 * @param messageID The message ID for which to deregister the associated 4489 * response acceptor. 4490 */ 4491 void deregisterResponseAcceptor(final int messageID) 4492 { 4493 final LDAPConnectionInternals internals = connectionInternals; 4494 if (internals != null) 4495 { 4496 internals.deregisterResponseAcceptor(messageID); 4497 } 4498 } 4499 4500 4501 4502 /** 4503 * Retrieves a timer for use with this connection, creating one if necessary. 4504 * 4505 * @return A timer for use with this connection. 4506 */ 4507 synchronized Timer getTimer() 4508 { 4509 if (timer == null) 4510 { 4511 timer = new Timer("Timer thread for " + toString(), true); 4512 } 4513 4514 return timer; 4515 } 4516 4517 4518 4519 /** 4520 * {@inheritDoc} 4521 */ 4522 public LDAPConnection getReferralConnection(final LDAPURL referralURL, 4523 final LDAPConnection connection) 4524 throws LDAPException 4525 { 4526 final String host = referralURL.getHost(); 4527 final int port = referralURL.getPort(); 4528 4529 BindRequest bindRequest = null; 4530 if (connection.lastBindRequest != null) 4531 { 4532 bindRequest = connection.lastBindRequest.getRebindRequest(host, port); 4533 if (bindRequest == null) 4534 { 4535 throw new LDAPException(ResultCode.REFERRAL, 4536 ERR_CONN_CANNOT_AUTHENTICATE_FOR_REFERRAL.get( 4537 host, port)); 4538 } 4539 } 4540 4541 final ExtendedRequest connStartTLSRequest = connection.startTLSRequest; 4542 4543 final LDAPConnection conn = new LDAPConnection(connection.socketFactory, 4544 connection.connectionOptions, host, port); 4545 4546 if (connStartTLSRequest != null) 4547 { 4548 try 4549 { 4550 final ExtendedResult startTLSResult = 4551 conn.processExtendedOperation(connStartTLSRequest); 4552 if (startTLSResult.getResultCode() != ResultCode.SUCCESS) 4553 { 4554 throw new LDAPException(startTLSResult); 4555 } 4556 } 4557 catch (final LDAPException le) 4558 { 4559 debugException(le); 4560 conn.setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le); 4561 conn.close(); 4562 4563 throw le; 4564 } 4565 } 4566 4567 if (bindRequest != null) 4568 { 4569 try 4570 { 4571 conn.bind(bindRequest); 4572 } 4573 catch (final LDAPException le) 4574 { 4575 debugException(le); 4576 conn.setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); 4577 conn.close(); 4578 4579 throw le; 4580 } 4581 } 4582 4583 return conn; 4584 } 4585 4586 4587 4588 /** 4589 * Retrieves the last successful bind request processed on this connection. 4590 * 4591 * @return The last successful bind request processed on this connection. It 4592 * may be {@code null} if no bind has been performed, or if the last 4593 * bind attempt was not successful. 4594 */ 4595 public BindRequest getLastBindRequest() 4596 { 4597 return lastBindRequest; 4598 } 4599 4600 4601 4602 /** 4603 * Retrieves the StartTLS request used to secure this connection. 4604 * 4605 * @return The StartTLS request used to secure this connection, or 4606 * {@code null} if StartTLS has not been used to secure this 4607 * connection. 4608 */ 4609 public ExtendedRequest getStartTLSRequest() 4610 { 4611 return startTLSRequest; 4612 } 4613 4614 4615 4616 /** 4617 * Retrieves an instance of the {@code LDAPConnectionInternals} object for 4618 * this connection. 4619 * 4620 * @param throwIfDisconnected Indicates whether to throw an 4621 * {@code LDAPException} if the connection is not 4622 * established. 4623 * 4624 * @return The {@code LDAPConnectionInternals} object for this connection, or 4625 * {@code null} if the connection is not established and no exception 4626 * should be thrown. 4627 * 4628 * @throws LDAPException If the connection is not established and 4629 * {@code throwIfDisconnected} is {@code true}. 4630 */ 4631 LDAPConnectionInternals getConnectionInternals( 4632 final boolean throwIfDisconnected) 4633 throws LDAPException 4634 { 4635 final LDAPConnectionInternals internals = connectionInternals; 4636 if ((internals == null) && throwIfDisconnected) 4637 { 4638 throw new LDAPException(ResultCode.SERVER_DOWN, 4639 ERR_CONN_NOT_ESTABLISHED.get()); 4640 } 4641 else 4642 { 4643 return internals; 4644 } 4645 } 4646 4647 4648 4649 /** 4650 * Retrieves the cached schema for this connection, if applicable. 4651 * 4652 * @return The cached schema for this connection, or {@code null} if it is 4653 * not available (e.g., because the connection is not established, 4654 * because {@link LDAPConnectionOptions#useSchema()} is false, or 4655 * because an error occurred when trying to read the server schema). 4656 */ 4657 Schema getCachedSchema() 4658 { 4659 return cachedSchema; 4660 } 4661 4662 4663 4664 /** 4665 * Sets the cached schema for this connection. 4666 * 4667 * @param cachedSchema The cached schema for this connection. It may be 4668 * {@code null} if no cached schema is available. 4669 */ 4670 void setCachedSchema(final Schema cachedSchema) 4671 { 4672 this.cachedSchema = cachedSchema; 4673 } 4674 4675 4676 4677 /** 4678 * Indicates whether this connection is operating in synchronous mode. 4679 * 4680 * @return {@code true} if this connection is operating in synchronous mode, 4681 * or {@code false} if not. 4682 */ 4683 public boolean synchronousMode() 4684 { 4685 final LDAPConnectionInternals internals = connectionInternals; 4686 if (internals == null) 4687 { 4688 return false; 4689 } 4690 else 4691 { 4692 return internals.synchronousMode(); 4693 } 4694 } 4695 4696 4697 4698 /** 4699 * Reads a response from the server, blocking if necessary until the response 4700 * has been received. This should only be used for connections operating in 4701 * synchronous mode. 4702 * 4703 * @param messageID The message ID for the response to be read. Any 4704 * response read with a different message ID will be 4705 * discarded, unless it is an unsolicited notification in 4706 * which case it will be provided to any registered 4707 * unsolicited notification handler. 4708 * 4709 * @return The response read from the server. 4710 * 4711 * @throws LDAPException If a problem occurs while reading the response. 4712 */ 4713 LDAPResponse readResponse(final int messageID) 4714 throws LDAPException 4715 { 4716 final LDAPConnectionInternals internals = connectionInternals; 4717 if (internals != null) 4718 { 4719 final LDAPResponse response = 4720 internals.getConnectionReader().readResponse(messageID); 4721 debugLDAPResult(response, this); 4722 return response; 4723 } 4724 else 4725 { 4726 final DisconnectInfo di = disconnectInfo.get(); 4727 if (di == null) 4728 { 4729 return new ConnectionClosedResponse(ResultCode.CONNECT_ERROR, 4730 ERR_CONN_READ_RESPONSE_NOT_ESTABLISHED.get()); 4731 } 4732 else 4733 { 4734 return new ConnectionClosedResponse(di.getType().getResultCode(), 4735 di.getMessage()); 4736 } 4737 } 4738 } 4739 4740 4741 4742 /** 4743 * Retrieves the time that this connection was established in the number of 4744 * milliseconds since January 1, 1970 UTC (the same format used by 4745 * {@code System.currentTimeMillis}. 4746 * 4747 * @return The time that this connection was established, or -1 if the 4748 * connection is not currently established. 4749 */ 4750 public long getConnectTime() 4751 { 4752 final LDAPConnectionInternals internals = connectionInternals; 4753 if (internals != null) 4754 { 4755 return internals.getConnectTime(); 4756 } 4757 else 4758 { 4759 return -1L; 4760 } 4761 } 4762 4763 4764 4765 /** 4766 * Retrieves the time that this connection was last used to send or receive an 4767 * LDAP message. The value will represent the number of milliseconds since 4768 * January 1, 1970 UTC (the same format used by 4769 * {@code System.currentTimeMillis}. 4770 * 4771 * @return The time that this connection was last used to send or receive an 4772 * LDAP message. If the connection is not established, then -1 will 4773 * be returned. If the connection is established but no 4774 * communication has been performed over the connection since it was 4775 * established, then the value of {@link #getConnectTime()} will be 4776 * returned. 4777 */ 4778 public long getLastCommunicationTime() 4779 { 4780 if (lastCommunicationTime > 0L) 4781 { 4782 return lastCommunicationTime; 4783 } 4784 else 4785 { 4786 return getConnectTime(); 4787 } 4788 } 4789 4790 4791 4792 /** 4793 * Updates the last communication time for this connection to be the current 4794 * time. 4795 */ 4796 void setLastCommunicationTime() 4797 { 4798 lastCommunicationTime = System.currentTimeMillis(); 4799 } 4800 4801 4802 4803 /** 4804 * Retrieves the connection statistics for this LDAP connection. 4805 * 4806 * @return The connection statistics for this LDAP connection. 4807 */ 4808 public LDAPConnectionStatistics getConnectionStatistics() 4809 { 4810 return connectionStatistics; 4811 } 4812 4813 4814 4815 /** 4816 * Retrieves the number of outstanding operations on this LDAP connection 4817 * (i.e., the number of operations currently in progress). The value will 4818 * only be valid for connections not configured to use synchronous mode. 4819 * 4820 * @return The number of outstanding operations on this LDAP connection, or 4821 * -1 if it cannot be determined (e.g., because the connection is not 4822 * established or is operating in synchronous mode). 4823 */ 4824 public int getActiveOperationCount() 4825 { 4826 final LDAPConnectionInternals internals = connectionInternals; 4827 4828 if (internals == null) 4829 { 4830 return -1; 4831 } 4832 else 4833 { 4834 if (internals.synchronousMode()) 4835 { 4836 return -1; 4837 } 4838 else 4839 { 4840 return internals.getConnectionReader().getActiveOperationCount(); 4841 } 4842 } 4843 } 4844 4845 4846 4847 /** 4848 * Retrieves the schema from the provided connection. If the retrieved schema 4849 * matches schema that's already in use by other connections, the common 4850 * schema will be used instead of the newly-retrieved version. 4851 * 4852 * @param c The connection for which to retrieve the schema. 4853 * 4854 * @return The schema retrieved from the given connection, or a cached 4855 * schema if it matched a schema that was already in use. 4856 * 4857 * @throws LDAPException If a problem is encountered while retrieving or 4858 * parsing the schema. 4859 */ 4860 private static Schema getCachedSchema(final LDAPConnection c) 4861 throws LDAPException 4862 { 4863 final Schema s = c.getSchema(); 4864 4865 synchronized (SCHEMA_SET) 4866 { 4867 return SCHEMA_SET.addAndGet(s); 4868 } 4869 } 4870 4871 4872 4873 /** 4874 * Retrieves the connection attachment with the specified name. 4875 * 4876 * @param name The name of the attachment to retrieve. It must not be 4877 * {@code null}. 4878 * 4879 * @return The connection attachment with the specified name, or {@code null} 4880 * if there is no such attachment. 4881 */ 4882 synchronized Object getAttachment(final String name) 4883 { 4884 if (attachments == null) 4885 { 4886 return null; 4887 } 4888 else 4889 { 4890 return attachments.get(name); 4891 } 4892 } 4893 4894 4895 4896 /** 4897 * Sets a connection attachment with the specified name and value. 4898 * 4899 * @param name The name of the attachment to set. It must not be 4900 * {@code null}. 4901 * @param value The value to use for the attachment. It may be {@code null} 4902 * if an attachment with the specified name should be cleared 4903 * rather than overwritten. 4904 */ 4905 synchronized void setAttachment(final String name, final Object value) 4906 { 4907 if (attachments == null) 4908 { 4909 attachments = new HashMap<String,Object>(10); 4910 } 4911 4912 if (value == null) 4913 { 4914 attachments.remove(name); 4915 } 4916 else 4917 { 4918 attachments.put(name, value); 4919 } 4920 } 4921 4922 4923 4924 /** 4925 * Performs any necessary cleanup to ensure that this connection is properly 4926 * closed before it is garbage collected. 4927 * 4928 * @throws Throwable If the superclass finalizer throws an exception. 4929 */ 4930 @Override() 4931 protected void finalize() 4932 throws Throwable 4933 { 4934 super.finalize(); 4935 4936 setDisconnectInfo(DisconnectType.CLOSED_BY_FINALIZER, null, null); 4937 setClosed(); 4938 } 4939 4940 4941 4942 /** 4943 * Retrieves a string representation of this LDAP connection. 4944 * 4945 * @return A string representation of this LDAP connection. 4946 */ 4947 @Override() 4948 public String toString() 4949 { 4950 final StringBuilder buffer = new StringBuilder(); 4951 toString(buffer); 4952 return buffer.toString(); 4953 } 4954 4955 4956 4957 /** 4958 * Appends a string representation of this LDAP connection to the provided 4959 * buffer. 4960 * 4961 * @param buffer The buffer to which to append a string representation of 4962 * this LDAP connection. 4963 */ 4964 public void toString(final StringBuilder buffer) 4965 { 4966 buffer.append("LDAPConnection("); 4967 4968 final String name = connectionName; 4969 final String poolName = connectionPoolName; 4970 if (name != null) 4971 { 4972 buffer.append("name='"); 4973 buffer.append(name); 4974 buffer.append("', "); 4975 } 4976 else if (poolName != null) 4977 { 4978 buffer.append("poolName='"); 4979 buffer.append(poolName); 4980 buffer.append("', "); 4981 } 4982 4983 final LDAPConnectionInternals internals = connectionInternals; 4984 if ((internals != null) && internals.isConnected()) 4985 { 4986 buffer.append("connected to "); 4987 buffer.append(internals.getHost()); 4988 buffer.append(':'); 4989 buffer.append(internals.getPort()); 4990 } 4991 else 4992 { 4993 buffer.append("not connected"); 4994 } 4995 4996 buffer.append(')'); 4997 } 4998}