All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.LDAPConnection Maven / Gradle / Ivy

/*
 * Copyright 2007-2024 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2007-2024 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2007-2024 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk;



import java.io.Closeable;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.sasl.SaslClient;

import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.protocol.AbandonRequestProtocolOp;
import com.unboundid.ldap.protocol.LDAPMessage;
import com.unboundid.ldap.protocol.LDAPResponse;
import com.unboundid.ldap.protocol.UnbindRequestProtocolOp;
import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
import com.unboundid.ldap.sdk.schema.Schema;
import com.unboundid.ldap.sdk.unboundidds.controls.RetainIdentityRequestControl;
import com.unboundid.ldif.LDIFException;
import com.unboundid.util.Debug;
import com.unboundid.util.DebugType;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.SynchronizedSocketFactory;
import com.unboundid.util.SynchronizedSSLSocketFactory;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import com.unboundid.util.WeakHashSet;
import com.unboundid.util.ssl.SSLUtil;

import static com.unboundid.ldap.sdk.LDAPMessages.*;



/**
 * This class provides a facility for interacting with an LDAPv3 directory
 * server.  It provides a means of establishing a connection to the server,
 * sending requests, and reading responses.  See
 * RFC 4511 for the LDAPv3
 * protocol specification and more information about the types of operations
 * defined in LDAP.
 * 

*

Creating, Establishing, and Authenticating Connections

* An LDAP connection can be established either at the time that the object is * created or as a separate step. Similarly, authentication can be performed on * the connection at the time it is created, at the time it is established, or * as a separate process. For example: *

*
 *   // Create a new, unestablished connection.  Then connect and perform a
 *   // simple bind as separate operations.
 *   LDAPConnection c = new LDAPConnection();
 *   c.connect(address, port);
 *   BindResult bindResult = c.bind(bindDN, password);
 *
 *   // Create a new connection that is established at creation time, and then
 *   // authenticate separately using simple authentication.
 *   c = new LDAPConnection(address, port);
 *   BindResult bindResult = c.bind(bindDN, password);
 *
 *   // Create a new connection that is established and bound using simple
 *   // authentication all in one step.
 *   c = new LDAPConnection(address, port, bindDN, password);
 * 
*

* When authentication is performed at the time that the connection is * established, it is only possible to perform a simple bind and it is not * possible to include controls in the bind request, nor is it possible to * receive response controls if the bind was successful. Therefore, it is * recommended that authentication be performed as a separate step if the server * may return response controls even in the event of a successful authentication * (e.g., a control that may indicate that the user's password will soon * expire). See the {@link BindRequest} class for more information about * authentication in the UnboundID LDAP SDK for Java. *

* The above examples all result in insecure connections that communicate over * standard unencrypted network sockets. However, this is strongly discouraged * because anyone who can intercept that communication can see all of the data * transferred (including things like authentication credentials and other * sensitive information), and may even be able to alter it in an undetectible * manner. Instead, you should instead establish secure connections that are * protected with TLS. The javadoc documentation for the {@link SSLUtil} class * provides a more complete description of this process, but the highlights are * that you should create an {@code SSLUtil} instance with an appropriate trust * store, create an {@link LDAPConnectionOptions} instance with certificate * host name verification enabled, and then use them to establish a secure * connection as follows: *

*
 *   AggregateTrustManager trustManager = new AggregateTrustManager(false,
 *        JVMDefaultTrustManager.getInstance(),
 *        new TrustStoreTrustManager(trustStorePath, trustStorePIN,
 *             "PKCS12", true));
 *   SSLUtil sslUtil = new SSLUtil(trustManager);
 *
 *   LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
 *   connectionOptions.setSSLSocketVerifier(
 *        new HostNameSSLSocketVerifier(true));
 *
 *   try (LDAPConnection connection = new LDAPConnection(
 *             sslUtil.createSSLSocketFactory(), connectionOptions,
 *             serverAddress, serverLDAPSPort))
 *   {
 *     // Use the connection here.
 *     RootDSE rootDSE = connection.getRootDSE();
 *   }
 * 
*

* Whenever the connection is no longer needed, it may be terminated using the * {@link LDAPConnection#close} method. Alternatively, you can use Java's * try-with-resources mechanism to establish a connection in a {@code try} * block, which will cause the connection to be closed at the end of that block, * even if an unexpected error occurs. It is very important to ensure that * connections are not leaked (by creating them and forgetting to close them, * or by creating a connection pool, checking out connections, and forgetting to * release them back to the pool), as that may eventually interfere with the * ability to establish new connections. *

*

Processing LDAP Operations

* This class provides a number of methods for processing the different types of * operations. The types of operations that can be processed include: *
    *
  • Abandon -- This may be used to request that the server stop processing * on an operation that has been invoked asynchronously.
  • *
  • Add -- This may be used to add a new entry to the directory * server. See the {@link AddRequest} class for more information about * processing add operations.
  • *
  • Bind -- This may be used to authenticate to the directory server. See * the {@link BindRequest} class for more information about processing * bind operations.
  • *
  • Compare -- This may be used to determine whether a specified entry has * a given attribute value. See the {@link CompareRequest} class for more * information about processing compare operations.
  • *
  • Delete -- This may be used to remove an entry from the directory * server. See the {@link DeleteRequest} class for more information about * processing delete operations.
  • *
  • Extended -- This may be used to process an operation which is not * part of the core LDAP protocol but is a custom extension supported by * the directory server. See the {@link ExtendedRequest} class for more * information about processing extended operations.
  • *
  • Modify -- This may be used to alter an entry in the directory * server. See the {@link ModifyRequest} class for more information about * processing modify operations.
  • *
  • Modify DN -- This may be used to rename an entry or subtree and/or move * that entry or subtree below a new parent in the directory server. See * the {@link ModifyDNRequest} class for more information about processing * modify DN operations.
  • *
  • Search -- This may be used to retrieve a set of entries in the server * that match a given set of criteria. See the {@link SearchRequest} * class for more information about processing search operations.
  • *
*

* Most of the methods in this class used to process operations operate in a * synchronous manner. In these cases, the SDK will send a request to the * server and wait for a response to arrive before returning to the caller. In * these cases, the value returned will include the contents of that response, * including the result code, diagnostic message, matched DN, referral URLs, and * any controls that may have been included. However, it also possible to * process operations asynchronously, in which case the SDK will return control * back to the caller after the request has been sent to the server but before * the response has been received. In this case, the SDK will return an * {@link AsyncRequestID} object which may be used to later abandon or cancel * that operation if necessary, and will notify the client when the response * arrives via a listener interface. *

* This class is mostly threadsafe. It is possible to process multiple * concurrent operations over the same connection as long as the methods being * invoked will not change the state of the connection in a way that might * impact other operations in progress in unexpected ways. In particular, the * following should not be attempted while any other operations may be in * progress on this connection: *
    *
  • * Using one of the {@code connect} methods to re-establish the connection. *
  • *
  • * Using one of the {@code close} methods to terminate the connection. *
  • *
  • * Using one of the {@code bind} methods to attempt to authenticate the * connection (unless you are certain that the bind will not impact the * identity of the associated connection, for example by including the * retain identity request control in the bind request if using the * LDAP SDK in conjunction with a Ping Identity, UnboundID, or * Nokia/Alcatel-Lucent 8661 Directory Server). *
  • *
  • * Attempting to make a change to the way that the underlying communication * is processed (e.g., by using the StartTLS extended operation to convert * an insecure connection into a secure one). *
  • *
*/ @ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE) public final class LDAPConnection implements FullLDAPInterface, LDAPConnectionInfo, ReferralConnector, Closeable { /** * The counter that will be used when assigning connection IDs to connections. */ @NotNull private static final AtomicLong NEXT_CONNECTION_ID = new AtomicLong(0L); /** * The default socket factory that will be used if no alternate factory is * provided. */ @NotNull private static final SocketFactory DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault(); /** * A set of weak references to schema objects that can be shared across * connections if they are identical. */ @NotNull private static final WeakHashSet SCHEMA_SET = new WeakHashSet<>(); // The connection pool with which this connection is associated, if // applicable. @Nullable private AbstractConnectionPool connectionPool; // Indicates whether to perform a reconnect before the next write. @NotNull private final AtomicBoolean needsReconnect; // The disconnect information for this connection. @NotNull private final AtomicReference disconnectInfo; // The last successful bind request processed on this connection. @Nullable private volatile BindRequest lastBindRequest; // Indicates whether a request has been made to close this connection. private volatile boolean closeRequested; // Indicates whether an unbind request has been sent over this connection. private volatile boolean unbindRequestSent; // The extended request used to initiate StartTLS on this connection. @Nullable private volatile ExtendedRequest startTLSRequest; // The port of the server to which a connection should be re-established. private int reconnectPort = -1; // The connection internals used to actually perform the network // communication. @Nullable private volatile LDAPConnectionInternals connectionInternals; // The set of connection options for this connection. @NotNull private LDAPConnectionOptions connectionOptions; // The set of statistics for this connection. @NotNull private final LDAPConnectionStatistics connectionStatistics; // The unique identifier assigned to this connection when it was created. It // will not change over the life of the connection, even if the connection is // closed and re-established (or even re-established to a different server). private final long connectionID; // The time of the last rebind attempt. private long lastReconnectTime; // The most recent time that an LDAP message was sent or received on this // connection. private volatile long lastCommunicationTime; // A map in which arbitrary attachments may be stored or managed. @Nullable private Map attachments; // The referral connector that will be used to establish connections to remote // servers when following a referral. @Nullable private volatile ReferralConnector referralConnector; // The cached schema read from the server. @Nullable private volatile Schema cachedSchema; // The server set that was used to create this connection, if available. @Nullable private volatile ServerSet serverSet; // The socket factory used for the last connection attempt. @Nullable private SocketFactory lastUsedSocketFactory; // The socket factory used to create sockets for subsequent connection // attempts. @NotNull private volatile SocketFactory socketFactory; // A stack trace of the thread that last established this connection. @Nullable private StackTraceElement[] connectStackTrace; // The user-friendly name assigned to this connection. @Nullable private String connectionName; // The user-friendly name assigned to the connection pool with which this // connection is associated. @Nullable private String connectionPoolName; // A string representation of the host and port to which the last connection // attempt (whether successful or not, and whether it is still established) // was made. @Nullable private String hostPort; // The address of the server to which a connection should be re-established. @Nullable private String reconnectAddress; // A timer that may be used to enforce timeouts for asynchronous operations. @Nullable private Timer timer; /** * Creates a new LDAP connection using the default socket factory and default * set of connection options. No actual network connection will be * established. */ public LDAPConnection() { this(null, null); } /** * Creates a new LDAP connection using the default socket factory and provided * set of connection options. No actual network connection will be * established. * * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. */ public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions) { this(null, connectionOptions); } /** * Creates a new LDAP connection using the specified socket factory. No * actual network connection will be established. * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a default * socket factory will be used. */ public LDAPConnection(@Nullable final SocketFactory socketFactory) { this(socketFactory, null); } /** * Creates a new LDAP connection using the specified socket factory. No * actual network connection will be established. * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a * default socket factory will be used. * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. */ public LDAPConnection(@Nullable final SocketFactory socketFactory, @Nullable final LDAPConnectionOptions connectionOptions) { needsReconnect = new AtomicBoolean(false); disconnectInfo = new AtomicReference<>(); lastCommunicationTime = -1L; connectionID = NEXT_CONNECTION_ID.getAndIncrement(); if (connectionOptions == null) { this.connectionOptions = new LDAPConnectionOptions(); } else { this.connectionOptions = connectionOptions.duplicate(); } final SocketFactory f; if (socketFactory == null) { f = DEFAULT_SOCKET_FACTORY; } else { f = socketFactory; } if (this.connectionOptions.allowConcurrentSocketFactoryUse()) { this.socketFactory = f; } else { if (f instanceof SSLSocketFactory) { this.socketFactory = new SynchronizedSSLSocketFactory((SSLSocketFactory) f); } else { this.socketFactory = new SynchronizedSocketFactory(f); } } attachments = null; connectionStatistics = new LDAPConnectionStatistics(); connectionName = null; connectionPoolName = null; cachedSchema = null; timer = null; serverSet = null; referralConnector = this.connectionOptions.getReferralConnector(); if (referralConnector == null) { referralConnector = this; } } /** * Creates a new, unauthenticated LDAP connection that is established to the * specified server. * * @param host The string representation of the address of the server to * which the connection should be established. It may be a * resolvable name or an IP address. It must not be * {@code null}. * @param port The port number of the server to which the connection should * be established. It should be a value between 1 and 65535, * inclusive. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@NotNull final String host, final int port) throws LDAPException { this(null, null, host, port); } /** * Creates a new, unauthenticated LDAP connection that is established to the * specified server. * * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an * IP address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be * a value between 1 and 65535, inclusive. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions, @NotNull final String host, final int port) throws LDAPException { this(null, connectionOptions, host, port); } /** * Creates a new, unauthenticated LDAP connection that is established to the * specified server. * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a default * socket factory will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an IP * address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be a * value between 1 and 65535, inclusive. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final SocketFactory socketFactory, @NotNull final String host, final int port) throws LDAPException { this(socketFactory, null, host, port); } /** * Creates a new, unauthenticated LDAP connection that is established to the * specified server. * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a * default socket factory will be used. * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an * IP address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be * a value between 1 and 65535, inclusive. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final SocketFactory socketFactory, @Nullable final LDAPConnectionOptions connectionOptions, @NotNull final String host, final int port) throws LDAPException { this(socketFactory, connectionOptions); connect(host, port); } /** * Creates a new LDAP connection that is established to the specified server * and is authenticated as the specified user (via LDAP simple * authentication). * * @param host The string representation of the address of the * server to which the connection should be established. * It may be a resolvable name or an IP address. It * must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be a * value between 1 and 65535, inclusive. * @param bindDN The DN to use to authenticate to the directory * server. * @param bindPassword The password to use to authenticate to the directory * server. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@NotNull final String host, final int port, @Nullable final String bindDN, @Nullable final String bindPassword) throws LDAPException { this(null, null, host, port, bindDN, bindPassword); } /** * Creates a new LDAP connection that is established to the specified server * and is authenticated as the specified user (via LDAP simple * authentication). * * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an * IP address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be * a value between 1 and 65535, inclusive. * @param bindDN The DN to use to authenticate to the directory * server. * @param bindPassword The password to use to authenticate to the * directory server. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final LDAPConnectionOptions connectionOptions, @NotNull final String host, final int port, @Nullable final String bindDN, @Nullable final String bindPassword) throws LDAPException { this(null, connectionOptions, host, port, bindDN, bindPassword); } /** * Creates a new LDAP connection that is established to the specified server * and is authenticated as the specified user (via LDAP simple * authentication). * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a default * socket factory will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an IP * address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be a * value between 1 and 65535, inclusive. * @param bindDN The DN to use to authenticate to the directory * server. * @param bindPassword The password to use to authenticate to the directory * server. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final SocketFactory socketFactory, @NotNull final String host, final int port, @Nullable final String bindDN, @Nullable final String bindPassword) throws LDAPException { this(socketFactory, null, host, port, bindDN, bindPassword); } /** * Creates a new LDAP connection that is established to the specified server * and is authenticated as the specified user (via LDAP simple * authentication). * * @param socketFactory The socket factory to use when establishing * connections. If it is {@code null}, then a * default socket factory will be used. * @param connectionOptions The set of connection options to use for this * connection. If it is {@code null}, then a * default set of options will be used. * @param host The string representation of the address of the * server to which the connection should be * established. It may be a resolvable name or an * IP address. It must not be {@code null}. * @param port The port number of the server to which the * connection should be established. It should be * a value between 1 and 65535, inclusive. * @param bindDN The DN to use to authenticate to the directory * server. * @param bindPassword The password to use to authenticate to the * directory server. * * @throws LDAPException If a problem occurs while attempting to connect to * the specified server. */ public LDAPConnection(@Nullable final SocketFactory socketFactory, @Nullable final LDAPConnectionOptions connectionOptions, @NotNull final String host, final int port, @Nullable final String bindDN, @Nullable final String bindPassword) throws LDAPException { this(socketFactory, connectionOptions, host, port); try { bind(new SimpleBindRequest(bindDN, bindPassword)); } catch (final LDAPException le) { Debug.debugException(le); setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); close(); throw le; } } /** * Establishes an unauthenticated connection to the directory server using the * provided information. If the connection is already established, then it * will be closed and re-established. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to re-establish an active connection. * * @param host The string representation of the address of the server to * which the connection should be established. It may be a * resolvable name or an IP address. It must not be * {@code null}. * @param port The port number of the server to which the connection should * be established. It should be a value between 1 and 65535, * inclusive. * * @throws LDAPException If an error occurs while attempting to establish * the connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void connect(@NotNull final String host, final int port) throws LDAPException { connect(host, port, connectionOptions.getConnectTimeoutMillis()); } /** * Establishes an unauthenticated connection to the directory server using the * provided information. If the connection is already established, then it * will be closed and re-established. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to re-establish an active connection. * * @param host The string representation of the address of the server to * which the connection should be established. It may be a * resolvable name or an IP address. It must not be * {@code null}. * @param port The port number of the server to which the connection * should be established. It should be a value between 1 and * 65535, inclusive. * @param timeout The maximum length of time in milliseconds to wait for the * connection to be established before failing, or zero to * indicate that no timeout should be enforced (although if * the attempt stalls long enough, then the underlying * operating system may cause it to timeout). * * @throws LDAPException If an error occurs while attempting to establish * the connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void connect(@NotNull final String host, final int port, final int timeout) throws LDAPException { final InetAddress inetAddress; try { inetAddress = connectionOptions.getNameResolver().getByName(host); } catch (final Exception e) { Debug.debugException(e); final LDAPException connectException = new LDAPException( ResultCode.CONNECT_ERROR, ERR_CONN_RESOLVE_ERROR.get(host, StaticUtils.getExceptionMessage(e)), e); final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); if (logger != null) { logger.logConnectFailure(this, host, port, connectException); } throw connectException; } connect(host, inetAddress, port, timeout); } /** * Establishes an unauthenticated connection to the directory server using the * provided information. If the connection is already established, then it * will be closed and re-established. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to re-establish an active connection. * * @param inetAddress The inet address of the server to which the connection * should be established. It must not be {@code null}. * @param port The port number of the server to which the connection * should be established. It should be a value between 1 * and 65535, inclusive. * @param timeout The maximum length of time in milliseconds to wait for * the connection to be established before failing, or * zero to indicate that no timeout should be enforced * (although if the attempt stalls long enough, then the * underlying operating system may cause it to timeout). * * @throws LDAPException If an error occurs while attempting to establish * the connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void connect(@NotNull final InetAddress inetAddress, final int port, final int timeout) throws LDAPException { connect(connectionOptions.getNameResolver().getHostName(inetAddress), inetAddress, port, timeout); } /** * Establishes an unauthenticated connection to the directory server using the * provided information. If the connection is already established, then it * will be closed and re-established. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to re-establish an active connection. * * @param host The string representation of the address of the server * to which the connection should be established. It may * be a resolvable name or an IP address. It must not be * {@code null}. * @param inetAddress The inet address of the server to which the connection * should be established. It must not be {@code null}. * @param port The port number of the server to which the connection * should be established. It should be a value between 1 * and 65535, inclusive. * @param timeout The maximum length of time in milliseconds to wait for * the connection to be established before failing, or * zero to indicate that no timeout should be enforced * (although if the attempt stalls long enough, then the * underlying operating system may cause it to timeout). * * @throws LDAPException If an error occurs while attempting to establish * the connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void connect(@NotNull final String host, @NotNull final InetAddress inetAddress, final int port, final int timeout) throws LDAPException { Validator.ensureNotNull(host, inetAddress, port); needsReconnect.set(false); hostPort = host + ':' + port; lastCommunicationTime = -1L; startTLSRequest = null; if (isConnected()) { setDisconnectInfo(DisconnectType.RECONNECT, null, null); close(); } lastUsedSocketFactory = socketFactory; reconnectAddress = host; reconnectPort = port; cachedSchema = null; closeRequested = false; unbindRequestSent = false; disconnectInfo.set(null); try { connectionStatistics.incrementNumConnects(); connectionInternals = new LDAPConnectionInternals(this, connectionOptions, lastUsedSocketFactory, host, inetAddress, port, timeout); connectionInternals.startConnectionReader(); lastCommunicationTime = System.currentTimeMillis(); } catch (final Exception e) { Debug.debugException(e); setDisconnectInfo(DisconnectType.LOCAL_ERROR, null, e); connectionInternals = null; final LDAPException connectException = new LDAPException( ResultCode.CONNECT_ERROR, ERR_CONN_CONNECT_ERROR.get(getHostPort(), StaticUtils.getExceptionMessage(e)), e); final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); if (logger != null) { logger.logConnectFailure(this, host, port, connectException); } throw connectException; } if (connectionOptions.useSchema()) { try { cachedSchema = getCachedSchema(this); } catch (final Exception e) { Debug.debugException(e); } } } /** * Attempts to re-establish a connection to the server and re-authenticate if * appropriate. * * @throws LDAPException If a problem occurs while attempting to re-connect * or re-authenticate. */ public void reconnect() throws LDAPException { needsReconnect.set(false); if ((System.currentTimeMillis() - lastReconnectTime) < 1000L) { // If the last reconnect attempt was less than 1 second ago, then abort. throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_MULTIPLE_FAILURES.get()); } BindRequest bindRequest = null; if (lastBindRequest != null) { bindRequest = lastBindRequest.getRebindRequest(reconnectAddress, reconnectPort); if (bindRequest == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_CANNOT_REAUTHENTICATE.get(getHostPort())); } } final ExtendedRequest startTLSExtendedRequest = startTLSRequest; setDisconnectInfo(DisconnectType.RECONNECT, null, null); terminate(null); try { Thread.sleep(1000L); } catch (final Exception e) { Debug.debugException(e); if (e instanceof InterruptedException) { Thread.currentThread().interrupt(); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_CONN_INTERRUPTED_DURING_RECONNECT.get(), e); } } connect(reconnectAddress, reconnectPort); if (startTLSExtendedRequest != null) { try { final ExtendedResult startTLSResult = processExtendedOperation(startTLSExtendedRequest); if (startTLSResult.getResultCode() != ResultCode.SUCCESS) { throw new LDAPException(startTLSResult); } } catch (final LDAPException le) { Debug.debugException(le); setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le); terminate(null); throw le; } } if (bindRequest != null) { try { bind(bindRequest); } catch (final LDAPException le) { Debug.debugException(le); setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); terminate(null); throw le; } } lastReconnectTime = System.currentTimeMillis(); } /** * Sets a flag indicating that the connection should be re-established before * sending the next request. */ void setNeedsReconnect() { needsReconnect.set(true); } /** * {@inheritDoc} */ @Override() public boolean isConnected() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return false; } if (! internals.isConnected()) { setClosed(); return false; } return (! needsReconnect.get()); } /** * Converts this clear-text connection to one that encrypts all communication * using Transport Layer Security. This method is intended for use as a * helper for processing in the course of the StartTLS extended operation and * should not be used for other purposes. * * @param sslSocketFactory The SSL socket factory to use to convert an * insecure connection into a secure connection. It * must not be {@code null}. * * @throws LDAPException If a problem occurs while converting this * connection to use TLS. */ void convertToTLS(@NotNull final SSLSocketFactory sslSocketFactory) throws LDAPException { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { internals.convertToTLS(sslSocketFactory); } } /** * Applies a communication security layer that has been negotiated using the * provided {@code SaslClient} object to this connection. The connection must * be established and must not have any other security layer already in place. * * @param saslClient The SASL client that will be used to secure the * communication. It must not be {@code null}. * * @throws LDAPException If a problem occurs while attempting to convert the * connection to use SASL QoP. */ public void applySASLSecurityLayer(@NotNull final SaslClient saslClient) throws LDAPException { applySASLQoP(saslClient); } /** * Applies a communication security layer that has been negotiated using the * provided {@code SaslClient} object to this connection. The connection must * be established and must not have any other security layer already in place. * * @param saslClient The SASL client that will be used to secure the * communication. It must not be {@code null}. * * @throws LDAPException If a problem occurs while attempting to convert the * connection to use SASL QoP. */ void applySASLQoP(@NotNull final SaslClient saslClient) throws LDAPException { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { internals.applySASLQoP(saslClient); } } /** * Retrieves the set of connection options for this connection. Changes to * the object that is returned will directly impact this connection. * * @return The set of connection options for this connection. */ @NotNull() public LDAPConnectionOptions getConnectionOptions() { return connectionOptions; } /** * Specifies the set of connection options for this connection. Some changes * may not take effect for operations already in progress, and some changes * may not take effect for a connection that is already established. * * @param connectionOptions The set of connection options for this * connection. It may be {@code null} if a default * set of options is to be used. */ public void setConnectionOptions( @Nullable final LDAPConnectionOptions connectionOptions) { if (connectionOptions == null) { this.connectionOptions = new LDAPConnectionOptions(); } else { final LDAPConnectionOptions newOptions = connectionOptions.duplicate(); if (Debug.debugEnabled(DebugType.LDAP) && newOptions.useSynchronousMode() && (! connectionOptions.useSynchronousMode()) && isConnected()) { Debug.debug(Level.WARNING, DebugType.LDAP, "A call to LDAPConnection.setConnectionOptions() with " + "useSynchronousMode=true will have no effect for this " + "connection because it is already established. The " + "useSynchronousMode option must be set before the " + "connection is established to have any effect."); } this.connectionOptions = newOptions; } final ReferralConnector rc = this.connectionOptions.getReferralConnector(); if (rc == null) { referralConnector = this; } else { referralConnector = rc; } } /** * {@inheritDoc} */ @Override() @Nullable() public SocketFactory getLastUsedSocketFactory() { return lastUsedSocketFactory; } /** * {@inheritDoc} */ @Override() @NotNull() public SocketFactory getSocketFactory() { return socketFactory; } /** * Specifies the socket factory to use to create the socket for subsequent * connection attempts. This will not impact any established connection. * * @param socketFactory The socket factory to use to create the socket for * subsequent connection attempts. */ public void setSocketFactory(@Nullable final SocketFactory socketFactory) { if (socketFactory == null) { this.socketFactory = DEFAULT_SOCKET_FACTORY; } else { this.socketFactory = socketFactory; } } /** * {@inheritDoc} */ @Override() @Nullable() public SSLSession getSSLSession() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return null; } final Socket socket = internals.getSocket(); if ((socket != null) && (socket instanceof SSLSocket)) { final SSLSocket sslSocket = (SSLSocket) socket; return sslSocket.getSession(); } else { return null; } } /** * {@inheritDoc} */ @Override() public long getConnectionID() { return connectionID; } /** * {@inheritDoc} */ @Override() @Nullable() public String getConnectionName() { return connectionName; } /** * Specifies the user-friendly name that should be used for this connection. * This name may be used in debugging to help identify the purpose of this * connection. This will have no effect for connections which are part of a * connection pool. * * @param connectionName The user-friendly name that should be used for this * connection. */ public void setConnectionName(@Nullable final String connectionName) { if (connectionPool == null) { this.connectionName = connectionName; if (connectionInternals != null) { final LDAPConnectionReader reader = connectionInternals.getConnectionReader(); reader.updateThreadName(); } } } /** * Retrieves the connection pool with which this connection is associated, if * any. * * @return The connection pool with which this connection is associated, or * {@code null} if it is not associated with any connection pool. */ @Nullable() public AbstractConnectionPool getConnectionPool() { return connectionPool; } /** * {@inheritDoc} */ @Override() @Nullable() public String getConnectionPoolName() { return connectionPoolName; } /** * Specifies the user-friendly name that should be used for the connection * pool with which this connection is associated. * * @param connectionPoolName The user-friendly name that should be used for * the connection pool with which this connection * is associated. */ void setConnectionPoolName(@Nullable final String connectionPoolName) { this.connectionPoolName = connectionPoolName; if (connectionInternals != null) { final LDAPConnectionReader reader = connectionInternals.getConnectionReader(); reader.updateThreadName(); } } /** * Retrieves the server set that was used to create this connection. * * @return The server set that was used to create this connection, or * {@code null} if it is not associated with any server set. */ @Nullable() ServerSet getServerSet() { return serverSet; } /** * Specifies the server set that was used to create this connection. * * @param serverSet The server set that was used to create this connection, * or {@code null} if it was not created by a server set. */ void setServerSet(@Nullable final ServerSet serverSet) { this.serverSet = serverSet; } /** * {@inheritDoc} */ @Override() @NotNull() public String getHostPort() { if (hostPort == null) { return ""; } else { return hostPort; } } /** * {@inheritDoc} */ @Override() @Nullable() public String getConnectedAddress() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return null; } else { return internals.getHost(); } } /** * {@inheritDoc} */ @Override() @Nullable() public String getConnectedIPAddress() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return null; } else { return internals.getInetAddress().getHostAddress(); } } /** * {@inheritDoc} */ @Override() @Nullable() public InetAddress getConnectedInetAddress() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return null; } else { return internals.getInetAddress(); } } /** * {@inheritDoc} */ @Override() public int getConnectedPort() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return -1; } else { return internals.getPort(); } } /** * {@inheritDoc} */ @Override() @Nullable() public StackTraceElement[] getConnectStackTrace() { return connectStackTrace; } /** * Provides a stack trace for the thread that last attempted to establish this * connection. * * @param connectStackTrace A stack trace for the thread that last attempted * to establish this connection. */ void setConnectStackTrace( @Nullable final StackTraceElement[] connectStackTrace) { this.connectStackTrace = connectStackTrace; } /** * Unbinds from the server and closes the connection. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to close an active connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @Override() public void close() { close(StaticUtils.NO_CONTROLS); } /** * Unbinds from the server and closes the connection, optionally including * the provided set of controls in the unbind request. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to close an active connection. * * @param controls The set of controls to include in the unbind request. It * may be {@code null} if there are not to be any controls * sent in the unbind request. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void close(@Nullable final Control[] controls) { closeRequested = true; setDisconnectInfo(DisconnectType.UNBIND, null, null); if (connectionPool == null) { terminate(controls); } else { connectionPool.releaseDefunctConnection(this); } } /** * Closes the connection without first sending an unbind request. Using this * method is generally discouraged, although it may be useful under certain * circumstances, like when it is known or suspected that an attempt to write * data over the connection will fail or block for some period of time. *

* If this method is invoked while any operations are in progress on this * connection, then the directory server may or may not abort processing for * those operations, depending on the type of operation and how far along the * server has already gotten while processing that operation. It is * recommended that all active operations be abandoned, canceled, or allowed * to complete before attempting to close an active connection. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) public void closeWithoutUnbind() { closeRequested = true; setDisconnectInfo(DisconnectType.CLOSED_WITHOUT_UNBIND, null, null); if (connectionPool == null) { setClosed(); } else { connectionPool.releaseDefunctConnection(this); } } /** * Unbinds from the server and closes the connection, optionally including the * provided set of controls in the unbind request. This method is only * intended for internal use, since it does not make any attempt to release * the connection back to its associated connection pool, if there is one. * * @param controls The set of controls to include in the unbind request. It * may be {@code null} if there are not to be any controls * sent in the unbind request. */ void terminate(@Nullable final Control[] controls) { if (isConnected() && (! unbindRequestSent)) { try { unbindRequestSent = true; setDisconnectInfo(DisconnectType.UNBIND, null, null); final int messageID = nextMessageID(); if (Debug.debugEnabled(DebugType.LDAP)) { Debug.debugLDAPRequest(Level.INFO, createUnbindRequestString(controls), messageID, this); } final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); if (logger != null) { final List controlList; if (controls == null) { controlList = Collections.emptyList(); } else { controlList = Arrays.asList(controls); } logger.logUnbindRequest(this, messageID, controlList); } connectionStatistics.incrementNumUnbindRequests(); sendMessage( new LDAPMessage(messageID, new UnbindRequestProtocolOp(), controls), connectionOptions.getResponseTimeoutMillis(OperationType.UNBIND)); } catch (final Exception e) { Debug.debugException(e); } } setClosed(); } /** * Creates a string representation of an unbind request with the provided * information. * * @param controls The set of controls included in the unbind request, if * any. * * @return The string representation of the unbind request. */ @NotNull() private static String createUnbindRequestString( @Nullable final Control... controls) { final StringBuilder buffer = new StringBuilder(); buffer.append("UnbindRequest("); if ((controls != null) && (controls.length > 0)) { buffer.append("controls={"); for (int i=0; i < controls.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(controls[i]); } buffer.append('}'); } buffer.append(')'); return buffer.toString(); } /** * Indicates whether a request has been made to close this connection. * * @return {@code true} if a request has been made to close this connection, * or {@code false} if not. */ boolean closeRequested() { return closeRequested; } /** * Indicates whether an unbind request has been sent over this connection. * * @return {@code true} if an unbind request has been sent over this * connection, or {@code false} if not. */ boolean unbindRequestSent() { return unbindRequestSent; } /** * Indicates that this LDAP connection is part of the specified * connection pool. * * @param connectionPool The connection pool with which this LDAP connection * is associated. */ void setConnectionPool(@Nullable final AbstractConnectionPool connectionPool) { this.connectionPool = connectionPool; } /** * Retrieves the directory server root DSE, which provides information about * the directory server, including the capabilities that it provides and the * type of data that it is configured to handle. * * @return The directory server root DSE, or {@code null} if it is not * available. * * @throws LDAPException If a problem occurs while attempting to retrieve * the server root DSE. */ @Override() @Nullable() public RootDSE getRootDSE() throws LDAPException { return RootDSE.getRootDSE(this); } /** * Retrieves the directory server schema definitions, using the subschema * subentry DN contained in the server's root DSE. For directory servers * containing a single schema, this should be sufficient for all purposes. * For servers with multiple schemas, it may be necessary to specify the DN * of the target entry for which to obtain the associated schema. * * @return The directory server schema definitions, or {@code null} if the * schema information could not be retrieved (e.g, the client does * not have permission to read the server schema). * * @throws LDAPException If a problem occurs while attempting to retrieve * the server schema. */ @Override() @Nullable() public Schema getSchema() throws LDAPException { return Schema.getSchema(this, ""); } /** * Retrieves the directory server schema definitions that govern the specified * entry. The subschemaSubentry attribute will be retrieved from the target * entry, and then the appropriate schema definitions will be loaded from the * entry referenced by that attribute. This may be necessary to ensure * correct behavior in servers that support multiple schemas. * * @param entryDN The DN of the entry for which to retrieve the associated * schema definitions. It may be {@code null} or an empty * string if the subschemaSubentry attribute should be * retrieved from the server's root DSE. * * @return The directory server schema definitions, or {@code null} if the * schema information could not be retrieved (e.g, the client does * not have permission to read the server schema). * * @throws LDAPException If a problem occurs while attempting to retrieve * the server schema. */ @Override() @Nullable() public Schema getSchema(@Nullable final String entryDN) throws LDAPException { return Schema.getSchema(this, entryDN); } /** * Retrieves the entry with the specified DN. All user attributes will be * requested in the entry to return. * * @param dn The DN of the entry to retrieve. It must not be {@code null}. * * @return The requested entry, or {@code null} if the target entry does not * exist or no entry was returned (e.g., if the authenticated user * does not have permission to read the target entry). * * @throws LDAPException If a problem occurs while sending the request or * reading the response. */ @Override() @Nullable() public SearchResultEntry getEntry(@NotNull final String dn) throws LDAPException { return getEntry(dn, (String[]) null); } /** * Retrieves the entry with the specified DN. * * @param dn The DN of the entry to retrieve. It must not be * {@code null}. * @param attributes The set of attributes to request for the target entry. * If it is {@code null}, then all user attributes will be * requested. * * @return The requested entry, or {@code null} if the target entry does not * exist or no entry was returned (e.g., if the authenticated user * does not have permission to read the target entry). * * @throws LDAPException If a problem occurs while sending the request or * reading the response. */ @Override() @Nullable() public SearchResultEntry getEntry(@NotNull final String dn, @Nullable final String... attributes) throws LDAPException { final Filter filter = Filter.createPresenceFilter("objectClass"); final SearchResult result; try { final SearchRequest searchRequest = new SearchRequest(dn, SearchScope.BASE, DereferencePolicy.NEVER, 1, 0, false, filter, attributes); result = search(searchRequest); } catch (final LDAPException le) { if (le.getResultCode().equals(ResultCode.NO_SUCH_OBJECT)) { return null; } else { throw le; } } if (! result.getResultCode().equals(ResultCode.SUCCESS)) { throw new LDAPException(result); } final List entryList = result.getSearchEntries(); if (entryList.isEmpty()) { return null; } else { return entryList.get(0); } } /** * Processes an abandon request with the provided information. * * @param requestID The async request ID for the request to abandon. * * @throws LDAPException If a problem occurs while sending the request to * the server. */ public void abandon(@NotNull final AsyncRequestID requestID) throws LDAPException { abandon(requestID, null); } /** * Processes an abandon request with the provided information. * * @param requestID The async request ID for the request to abandon. * @param controls The set of controls to include in the abandon request. * It may be {@code null} or empty if there are no * controls. * * @throws LDAPException If a problem occurs while sending the request to * the server. */ public void abandon(@NotNull final AsyncRequestID requestID, @Nullable final Control[] controls) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ABANDON_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final int messageID = requestID.getMessageID(); try { connectionInternals.getConnectionReader().deregisterResponseAcceptor( messageID); } catch (final Exception e) { Debug.debugException(e); } connectionStatistics.incrementNumAbandonRequests(); final int abandonMessageID = nextMessageID(); if (Debug.debugEnabled(DebugType.LDAP)) { Debug.debugLDAPRequest(Level.INFO, createAbandonRequestString(messageID, controls), abandonMessageID, this); } final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); if (logger != null) { final List controlList; if (controls == null) { controlList = Collections.emptyList(); } else { controlList = Arrays.asList(controls); } logger.logAbandonRequest(this, abandonMessageID, messageID, controlList); } sendMessage( new LDAPMessage(abandonMessageID, new AbandonRequestProtocolOp(messageID), controls), connectionOptions.getResponseTimeoutMillis(OperationType.ABANDON)); } /** * Sends an abandon request with the provided information. * * @param messageID The message ID for the request to abandon. * @param controls The set of controls to include in the abandon request. * It may be {@code null} or empty if there are no * controls. * * @throws LDAPException If a problem occurs while sending the request to * the server. */ void abandon(final int messageID, @Nullable final Control... controls) throws LDAPException { try { connectionInternals.getConnectionReader().deregisterResponseAcceptor( messageID); } catch (final Exception e) { Debug.debugException(e); } connectionStatistics.incrementNumAbandonRequests(); final int abandonMessageID = nextMessageID(); if (Debug.debugEnabled(DebugType.LDAP)) { Debug.debugLDAPRequest(Level.INFO, createAbandonRequestString(messageID, controls), abandonMessageID, this); } final LDAPConnectionLogger logger = connectionOptions.getConnectionLogger(); if (logger != null) { final List controlList; if (controls == null) { controlList = Collections.emptyList(); } else { controlList = Arrays.asList(controls); } logger.logAbandonRequest(this, abandonMessageID, messageID, controlList); } sendMessage( new LDAPMessage(abandonMessageID, new AbandonRequestProtocolOp(messageID), controls), connectionOptions.getResponseTimeoutMillis(OperationType.ABANDON)); } /** * Creates a string representation of an abandon request with the provided * information. * * @param idToAbandon The message ID of the operation to abandon. * @param controls The set of controls included in the abandon request, * if any. * * @return The string representation of the abandon request. */ @NotNull() private static String createAbandonRequestString(final int idToAbandon, @Nullable final Control... controls) { final StringBuilder buffer = new StringBuilder(); buffer.append("AbandonRequest(idToAbandon="); buffer.append(idToAbandon); if ((controls != null) && (controls.length > 0)) { buffer.append(", controls={"); for (int i=0; i < controls.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(controls[i]); } buffer.append('}'); } buffer.append(')'); return buffer.toString(); } /** * Processes an add operation with the provided information. * * @param dn The DN of the entry to add. It must not be * {@code null}. * @param attributes The set of attributes to include in the entry to add. * It must not be {@code null}. * * @return The result of processing the add operation. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult add(@NotNull final String dn, @NotNull final Attribute... attributes) throws LDAPException { Validator.ensureNotNull(dn, attributes); return add(new AddRequest(dn, attributes)); } /** * Processes an add operation with the provided information. * * @param dn The DN of the entry to add. It must not be * {@code null}. * @param attributes The set of attributes to include in the entry to add. * It must not be {@code null}. * * @return The result of processing the add operation. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult add(@NotNull final String dn, @NotNull final Collection attributes) throws LDAPException { Validator.ensureNotNull(dn, attributes); return add(new AddRequest(dn, attributes)); } /** * Processes an add operation with the provided information. * * @param entry The entry to add. It must not be {@code null}. * * @return The result of processing the add operation. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult add(@NotNull final Entry entry) throws LDAPException { Validator.ensureNotNull(entry); return add(new AddRequest(entry)); } /** * Processes an add operation with the provided information. * * @param ldifLines The lines that comprise an LDIF representation of the * entry to add. It must not be empty or {@code null}. * * @return The result of processing the add operation. * * @throws LDIFException If the provided entry lines cannot be decoded as an * entry in LDIF form. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult add(@NotNull final String... ldifLines) throws LDIFException, LDAPException { return add(new AddRequest(ldifLines)); } /** * Processes the provided add request. * * @param addRequest The add request to be processed. It must not be * {@code null}. * * @return The result of processing the add operation. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult add(@NotNull final AddRequest addRequest) throws LDAPException { Validator.ensureNotNull(addRequest); final LDAPResult ldapResult = addRequest.process(this, 1); switch (ldapResult.getResultCode().intValue()) { case ResultCode.SUCCESS_INT_VALUE: case ResultCode.NO_OPERATION_INT_VALUE: return ldapResult; default: throw new LDAPException(ldapResult); } } /** * Processes the provided add request. * * @param addRequest The add request to be processed. It must not be * {@code null}. * * @return The result of processing the add operation. * * @throws LDAPException If the server rejects the add request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull public LDAPResult add(@NotNull final ReadOnlyAddRequest addRequest) throws LDAPException { return add((AddRequest) addRequest); } /** * Processes the provided add request as an asynchronous operation. * * @param addRequest The add request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the add operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncAdd(@NotNull final AddRequest addRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { Validator.ensureNotNull(addRequest); if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final AsyncResultListener listener; if (resultListener == null) { listener = DiscardAsyncListener.getInstance(); } else { listener = resultListener; } return addRequest.processAsync(this, listener); } /** * Processes the provided add request as an asynchronous operation. * * @param addRequest The add request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the add operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncAdd(@NotNull final ReadOnlyAddRequest addRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncAdd((AddRequest) addRequest, resultListener); } /** * Processes a simple bind request with the provided DN and password. *

* The LDAP protocol specification forbids clients from attempting to perform * a bind on a connection in which one or more other operations are already in * progress. If a bind is attempted while any operations are in progress, * then the directory server may or may not abort processing for those * operations, depending on the type of operation and how far along the * server has already gotten while processing that operation (unless the bind * request is one that will not cause the server to attempt to change the * identity of this connection, for example by including the retain identity * request control in the bind request if using the LDAP SDK in conjunction * with a Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 Directory * Server). It is recommended that all active operations be abandoned, * canceled, or allowed to complete before attempting to perform a bind on an * active connection. * * @param bindDN The bind DN for the bind operation. * @param password The password for the simple bind operation. * * @return The result of processing the bind operation. * * @throws LDAPException If the server rejects the bind request, or if a * problem occurs while sending the request or reading * the response. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @NotNull() public BindResult bind(@Nullable final String bindDN, @Nullable final String password) throws LDAPException { return bind(new SimpleBindRequest(bindDN, password)); } /** * Processes the provided bind request. *

* The LDAP protocol specification forbids clients from attempting to perform * a bind on a connection in which one or more other operations are already in * progress. If a bind is attempted while any operations are in progress, * then the directory server may or may not abort processing for those * operations, depending on the type of operation and how far along the * server has already gotten while processing that operation (unless the bind * request is one that will not cause the server to attempt to change the * identity of this connection, for example by including the retain identity * request control in the bind request if using the LDAP SDK in conjunction * with a Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 Directory * Server). It is recommended that all active operations be abandoned, * canceled, or allowed to complete before attempting to perform a bind on an * active connection. * * @param bindRequest The bind request to be processed. It must not be * {@code null}. * * @return The result of processing the bind operation. * * @throws LDAPException If the server rejects the bind request, or if a * problem occurs while sending the request or reading * the response. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @NotNull() public BindResult bind(@NotNull final BindRequest bindRequest) throws LDAPException { Validator.ensureNotNull(bindRequest); final BindResult bindResult = processBindOperation(bindRequest); switch (bindResult.getResultCode().intValue()) { case ResultCode.SUCCESS_INT_VALUE: return bindResult; case ResultCode.SASL_BIND_IN_PROGRESS_INT_VALUE: throw new SASLBindInProgressException(bindResult); default: throw new LDAPBindException(bindResult); } } /** * Processes a compare operation with the provided information. * * @param dn The DN of the entry in which to make the * comparison. It must not be {@code null}. * @param attributeName The attribute name for which to make the * comparison. It must not be {@code null}. * @param assertionValue The assertion value to verify in the target entry. * It must not be {@code null}. * * @return The result of processing the compare operation. * * @throws LDAPException If the server rejects the compare request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public CompareResult compare(@NotNull final String dn, @NotNull final String attributeName, @NotNull final String assertionValue) throws LDAPException { Validator.ensureNotNull(dn, attributeName, assertionValue); return compare(new CompareRequest(dn, attributeName, assertionValue)); } /** * Processes the provided compare request. * * @param compareRequest The compare request to be processed. It must not * be {@code null}. * * @return The result of processing the compare operation. * * @throws LDAPException If the server rejects the compare request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public CompareResult compare(@NotNull final CompareRequest compareRequest) throws LDAPException { Validator.ensureNotNull(compareRequest); final LDAPResult result = compareRequest.process(this, 1); switch (result.getResultCode().intValue()) { case ResultCode.COMPARE_FALSE_INT_VALUE: case ResultCode.COMPARE_TRUE_INT_VALUE: return new CompareResult(result); default: throw new LDAPException(result); } } /** * Processes the provided compare request. * * @param compareRequest The compare request to be processed. It must not * be {@code null}. * * @return The result of processing the compare operation. * * @throws LDAPException If the server rejects the compare request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public CompareResult compare( @NotNull final ReadOnlyCompareRequest compareRequest) throws LDAPException { return compare((CompareRequest) compareRequest); } /** * Processes the provided compare request as an asynchronous operation. * * @param compareRequest The compare request to be processed. It must not * be {@code null}. * @param resultListener The async result listener to use to handle the * response for the compare operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncCompare( @NotNull final CompareRequest compareRequest, @Nullable final AsyncCompareResultListener resultListener) throws LDAPException { Validator.ensureNotNull(compareRequest); if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final AsyncCompareResultListener listener; if (resultListener == null) { listener = DiscardAsyncListener.getInstance(); } else { listener = resultListener; } return compareRequest.processAsync(this, listener); } /** * Processes the provided compare request as an asynchronous operation. * * @param compareRequest The compare request to be processed. It must not * be {@code null}. * @param resultListener The async result listener to use to handle the * response for the compare operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncCompare( @NotNull final ReadOnlyCompareRequest compareRequest, @Nullable final AsyncCompareResultListener resultListener) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncCompare((CompareRequest) compareRequest, resultListener); } /** * Deletes the entry with the specified DN. * * @param dn The DN of the entry to delete. It must not be {@code null}. * * @return The result of processing the delete operation. * * @throws LDAPException If the server rejects the delete request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult delete(@NotNull final String dn) throws LDAPException { return delete(new DeleteRequest(dn)); } /** * Processes the provided delete request. * * @param deleteRequest The delete request to be processed. It must not be * {@code null}. * * @return The result of processing the delete operation. * * @throws LDAPException If the server rejects the delete request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult delete(@NotNull final DeleteRequest deleteRequest) throws LDAPException { Validator.ensureNotNull(deleteRequest); final LDAPResult ldapResult = deleteRequest.process(this, 1); switch (ldapResult.getResultCode().intValue()) { case ResultCode.SUCCESS_INT_VALUE: case ResultCode.NO_OPERATION_INT_VALUE: return ldapResult; default: throw new LDAPException(ldapResult); } } /** * Processes the provided delete request. * * @param deleteRequest The delete request to be processed. It must not be * {@code null}. * * @return The result of processing the delete operation. * * @throws LDAPException If the server rejects the delete request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult delete(@NotNull final ReadOnlyDeleteRequest deleteRequest) throws LDAPException { return delete((DeleteRequest) deleteRequest); } /** * Processes the provided delete request as an asynchronous operation. * * @param deleteRequest The delete request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the delete operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncDelete(@NotNull final DeleteRequest deleteRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { Validator.ensureNotNull(deleteRequest); if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final AsyncResultListener listener; if (resultListener == null) { listener = DiscardAsyncListener.getInstance(); } else { listener = resultListener; } return deleteRequest.processAsync(this, listener); } /** * Processes the provided delete request as an asynchronous operation. * * @param deleteRequest The delete request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the delete operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncDelete( @NotNull final ReadOnlyDeleteRequest deleteRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncDelete((DeleteRequest) deleteRequest, resultListener); } /** * Processes an extended request with the provided request OID. Note that * because some types of extended operations return unusual result codes under * "normal" conditions, the server may not always throw an exception for a * failed extended operation like it does for other types of operations. It * will throw an exception under conditions where there appears to be a * problem with the connection or the server to which the connection is * established, but there may be many circumstances in which an extended * operation is not processed correctly but this method does not throw an * exception. In the event that no exception is thrown, it is the * responsibility of the caller to interpret the result to determine whether * the operation was processed as expected. *

* Note that extended operations which may change the state of this connection * (e.g., the StartTLS extended operation, which will add encryption to a * previously-unencrypted connection) should not be invoked while any other * operations are active on the connection. It is recommended that all active * operations be abandoned, canceled, or allowed to complete before attempting * to process an extended operation that may change the state of this * connection. * * @param requestOID The OID for the extended request to process. It must * not be {@code null}. * * @return The extended result object that provides information about the * result of the request processing. It may or may not indicate that * the operation was successful. * * @throws LDAPException If a problem occurs while sending the request or * reading the response. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @NotNull() public ExtendedResult processExtendedOperation( @NotNull final String requestOID) throws LDAPException { Validator.ensureNotNull(requestOID); return processExtendedOperation(new ExtendedRequest(requestOID)); } /** * Processes an extended request with the provided request OID and value. * Note that because some types of extended operations return unusual result * codes under "normal" conditions, the server may not always throw an * exception for a failed extended operation like it does for other types of * operations. It will throw an exception under conditions where there * appears to be a problem with the connection or the server to which the * connection is established, but there may be many circumstances in which an * extended operation is not processed correctly but this method does not * throw an exception. In the event that no exception is thrown, it is the * responsibility of the caller to interpret the result to determine whether * the operation was processed as expected. *

* Note that extended operations which may change the state of this connection * (e.g., the StartTLS extended operation, which will add encryption to a * previously-unencrypted connection) should not be invoked while any other * operations are active on the connection. It is recommended that all active * operations be abandoned, canceled, or allowed to complete before attempting * to process an extended operation that may change the state of this * connection. * * @param requestOID The OID for the extended request to process. It must * not be {@code null}. * @param requestValue The encoded value for the extended request to * process. It may be {@code null} if there does not * need to be a value for the requested operation. * * @return The extended result object that provides information about the * result of the request processing. It may or may not indicate that * the operation was successful. * * @throws LDAPException If a problem occurs while sending the request or * reading the response. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @NotNull() public ExtendedResult processExtendedOperation( @NotNull final String requestOID, @Nullable final ASN1OctetString requestValue) throws LDAPException { Validator.ensureNotNull(requestOID); return processExtendedOperation(new ExtendedRequest(requestOID, requestValue)); } /** * Processes the provided extended request. Note that because some types of * extended operations return unusual result codes under "normal" conditions, * the server may not always throw an exception for a failed extended * operation like it does for other types of operations. It will throw an * exception under conditions where there appears to be a problem with the * connection or the server to which the connection is established, but there * may be many circumstances in which an extended operation is not processed * correctly but this method does not throw an exception. In the event that * no exception is thrown, it is the responsibility of the caller to interpret * the result to determine whether the operation was processed as expected. *

* Note that extended operations which may change the state of this connection * (e.g., the StartTLS extended operation, which will add encryption to a * previously-unencrypted connection) should not be invoked while any other * operations are active on the connection. It is recommended that all active * operations be abandoned, canceled, or allowed to complete before attempting * to process an extended operation that may change the state of this * connection. * * @param extendedRequest The extended request to be processed. It must not * be {@code null}. * * @return The extended result object that provides information about the * result of the request processing. It may or may not indicate that * the operation was successful. * * @throws LDAPException If a problem occurs while sending the request or * reading the response. */ @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE) @NotNull() public ExtendedResult processExtendedOperation( @NotNull final ExtendedRequest extendedRequest) throws LDAPException { Validator.ensureNotNull(extendedRequest); final ExtendedResult extendedResult = extendedRequest.process(this, 1); if ((extendedResult.getOID() == null) && (extendedResult.getValue() == null)) { switch (extendedResult.getResultCode().intValue()) { case ResultCode.OPERATIONS_ERROR_INT_VALUE: case ResultCode.PROTOCOL_ERROR_INT_VALUE: case ResultCode.BUSY_INT_VALUE: case ResultCode.UNAVAILABLE_INT_VALUE: case ResultCode.OTHER_INT_VALUE: case ResultCode.SERVER_DOWN_INT_VALUE: case ResultCode.LOCAL_ERROR_INT_VALUE: case ResultCode.ENCODING_ERROR_INT_VALUE: case ResultCode.DECODING_ERROR_INT_VALUE: case ResultCode.TIMEOUT_INT_VALUE: case ResultCode.NO_MEMORY_INT_VALUE: case ResultCode.CONNECT_ERROR_INT_VALUE: throw new LDAPException(extendedResult); } } if ((extendedResult.getResultCode() == ResultCode.SUCCESS) && extendedRequest.getOID().equals( StartTLSExtendedRequest.STARTTLS_REQUEST_OID)) { startTLSRequest = extendedRequest.duplicate(); } return extendedResult; } /** * Applies the provided modification to the specified entry. * * @param dn The DN of the entry to modify. It must not be {@code null}. * @param mod The modification to apply to the target entry. It must not * be {@code null}. * * @return The result of processing the modify operation. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult modify(@NotNull final String dn, @NotNull final Modification mod) throws LDAPException { Validator.ensureNotNull(dn, mod); return modify(new ModifyRequest(dn, mod)); } /** * Applies the provided set of modifications to the specified entry. * * @param dn The DN of the entry to modify. It must not be {@code null}. * @param mods The set of modifications to apply to the target entry. It * must not be {@code null} or empty. * * @return The result of processing the modify operation. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult modify(@NotNull final String dn, @NotNull final Modification... mods) throws LDAPException { Validator.ensureNotNull(dn, mods); return modify(new ModifyRequest(dn, mods)); } /** * Applies the provided set of modifications to the specified entry. * * @param dn The DN of the entry to modify. It must not be {@code null}. * @param mods The set of modifications to apply to the target entry. It * must not be {@code null} or empty. * * @return The result of processing the modify operation. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult modify(@NotNull final String dn, @NotNull final List mods) throws LDAPException { Validator.ensureNotNull(dn, mods); return modify(new ModifyRequest(dn, mods)); } /** * Processes a modify request from the provided LDIF representation of the * changes. * * @param ldifModificationLines The lines that comprise an LDIF * representation of a modify change record. * It must not be {@code null} or empty. * * @return The result of processing the modify operation. * * @throws LDIFException If the provided set of lines cannot be parsed as an * LDIF modify change record. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. * */ @Override() @NotNull() public LDAPResult modify(@NotNull final String... ldifModificationLines) throws LDIFException, LDAPException { Validator.ensureNotNull(ldifModificationLines); return modify(new ModifyRequest(ldifModificationLines)); } /** * Processes the provided modify request. * * @param modifyRequest The modify request to be processed. It must not be * {@code null}. * * @return The result of processing the modify operation. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult modify(@NotNull final ModifyRequest modifyRequest) throws LDAPException { Validator.ensureNotNull(modifyRequest); final LDAPResult ldapResult = modifyRequest.process(this, 1); switch (ldapResult.getResultCode().intValue()) { case ResultCode.SUCCESS_INT_VALUE: case ResultCode.NO_OPERATION_INT_VALUE: return ldapResult; default: throw new LDAPException(ldapResult); } } /** * Processes the provided modify request. * * @param modifyRequest The modify request to be processed. It must not be * {@code null}. * * @return The result of processing the modify operation. * * @throws LDAPException If the server rejects the modify request, or if a * problem is encountered while sending the request or * reading the response. */ @Override() @NotNull() public LDAPResult modify(@NotNull final ReadOnlyModifyRequest modifyRequest) throws LDAPException { return modify((ModifyRequest) modifyRequest); } /** * Processes the provided modify request as an asynchronous operation. * * @param modifyRequest The modify request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the modify operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncModify(@NotNull final ModifyRequest modifyRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { Validator.ensureNotNull(modifyRequest); if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final AsyncResultListener listener; if (resultListener == null) { listener = DiscardAsyncListener.getInstance(); } else { listener = resultListener; } return modifyRequest.processAsync(this, listener); } /** * Processes the provided modify request as an asynchronous operation. * * @param modifyRequest The modify request to be processed. It must not be * {@code null}. * @param resultListener The async result listener to use to handle the * response for the modify operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncModify( @NotNull final ReadOnlyModifyRequest modifyRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncModify((ModifyRequest) modifyRequest, resultListener); } /** * Performs a modify DN operation with the provided information. * * @param dn The current DN for the entry to rename. It must not * be {@code null}. * @param newRDN The new RDN to use for the entry. It must not be * {@code null}. * @param deleteOldRDN Indicates whether to delete the current RDN value * from the entry. * * @return The result of processing the modify DN operation. * * @throws LDAPException If the server rejects the modify DN request, or if * a problem is encountered while sending the request * or reading the response. */ @Override() @NotNull() public LDAPResult modifyDN(@NotNull final String dn, @NotNull final String newRDN, final boolean deleteOldRDN) throws LDAPException { Validator.ensureNotNull(dn, newRDN); return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN)); } /** * Performs a modify DN operation with the provided information. * * @param dn The current DN for the entry to rename. It must not * be {@code null}. * @param newRDN The new RDN to use for the entry. It must not be * {@code null}. * @param deleteOldRDN Indicates whether to delete the current RDN value * from the entry. * @param newSuperiorDN The new superior DN for the entry. It may be * {@code null} if the entry is not to be moved below a * new parent. * * @return The result of processing the modify DN operation. * * @throws LDAPException If the server rejects the modify DN request, or if * a problem is encountered while sending the request * or reading the response. */ @Override() @NotNull() public LDAPResult modifyDN(@NotNull final String dn, @NotNull final String newRDN, final boolean deleteOldRDN, @Nullable final String newSuperiorDN) throws LDAPException { Validator.ensureNotNull(dn, newRDN); return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN, newSuperiorDN)); } /** * Processes the provided modify DN request. * * @param modifyDNRequest The modify DN request to be processed. It must * not be {@code null}. * * @return The result of processing the modify DN operation. * * @throws LDAPException If the server rejects the modify DN request, or if * a problem is encountered while sending the request * or reading the response. */ @Override() @NotNull() public LDAPResult modifyDN(@NotNull final ModifyDNRequest modifyDNRequest) throws LDAPException { Validator.ensureNotNull(modifyDNRequest); final LDAPResult ldapResult = modifyDNRequest.process(this, 1); switch (ldapResult.getResultCode().intValue()) { case ResultCode.SUCCESS_INT_VALUE: case ResultCode.NO_OPERATION_INT_VALUE: return ldapResult; default: throw new LDAPException(ldapResult); } } /** * Processes the provided modify DN request. * * @param modifyDNRequest The modify DN request to be processed. It must * not be {@code null}. * * @return The result of processing the modify DN operation. * * @throws LDAPException If the server rejects the modify DN request, or if * a problem is encountered while sending the request * or reading the response. */ @Override() @NotNull() public LDAPResult modifyDN( @NotNull final ReadOnlyModifyDNRequest modifyDNRequest) throws LDAPException { return modifyDN((ModifyDNRequest) modifyDNRequest); } /** * Processes the provided modify DN request as an asynchronous operation. * * @param modifyDNRequest The modify DN request to be processed. It must * not be {@code null}. * @param resultListener The async result listener to use to handle the * response for the modify DN operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncModifyDN( @NotNull final ModifyDNRequest modifyDNRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { Validator.ensureNotNull(modifyDNRequest); if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } final AsyncResultListener listener; if (resultListener == null) { listener = DiscardAsyncListener.getInstance(); } else { listener = resultListener; } return modifyDNRequest.processAsync(this, listener); } /** * Processes the provided modify DN request as an asynchronous operation. * * @param modifyDNRequest The modify DN request to be processed. It must * not be {@code null}. * @param resultListener The async result listener to use to handle the * response for the modify DN operation. It may be * {@code null} if the result is going to be obtained * from the returned {@code AsyncRequestID} object via * the {@code Future} API. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If a problem occurs while sending the request. */ @NotNull() public AsyncRequestID asyncModifyDN( @NotNull final ReadOnlyModifyDNRequest modifyDNRequest, @Nullable final AsyncResultListener resultListener) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncModifyDN((ModifyDNRequest) modifyDNRequest, resultListener); } /** * Processes a search operation with the provided information. The search * result entries and references will be collected internally and included in * the {@code SearchResult} object that is returned. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param filter The string representation of the filter to use to * identify matching entries. It must not be * {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return A search result object that provides information about the * processing of the search, including the set of matching entries * and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while parsing * the provided filter string, sending the * request, or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); try { return search(new SearchRequest(baseDN, scope, filter, attributes)); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } } /** * Processes a search operation with the provided information. The search * result entries and references will be collected internally and included in * the {@code SearchResult} object that is returned. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param filter The filter to use to identify matching entries. It * must not be {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return A search result object that provides information about the * processing of the search, including the set of matching entries * and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); return search(new SearchRequest(baseDN, scope, filter, attributes)); } /** * Processes a search operation with the provided information. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchResultListener The search result listener that should be * used to return results to the client. It may * be {@code null} if the search results should * be collected internally and returned in the * {@code SearchResult} object. * @param baseDN The base DN for the search request. It must * not be {@code null}. * @param scope The scope that specifies the range of entries * that should be examined for the search. * @param filter The string representation of the filter to * use to identify matching entries. It must * not be {@code null}. * @param attributes The set of attributes that should be returned * in matching entries. It may be {@code null} * or empty if the default attribute set (all * user attributes) is to be requested. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while parsing * the provided filter string, sending the * request, or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search( @Nullable final SearchResultListener searchResultListener, @NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); try { return search(new SearchRequest(searchResultListener, baseDN, scope, filter, attributes)); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } } /** * Processes a search operation with the provided information. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchResultListener The search result listener that should be * used to return results to the client. It may * be {@code null} if the search results should * be collected internally and returned in the * {@code SearchResult} object. * @param baseDN The base DN for the search request. It must * not be {@code null}. * @param scope The scope that specifies the range of entries * that should be examined for the search. * @param filter The filter to use to identify matching * entries. It must not be {@code null}. * @param attributes The set of attributes that should be returned * in matching entries. It may be {@code null} * or empty if the default attribute set (all * user attributes) is to be requested. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search( @Nullable final SearchResultListener searchResultListener, @NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); try { return search(new SearchRequest(searchResultListener, baseDN, scope, filter, attributes)); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } } /** * Processes a search operation with the provided information. The search * result entries and references will be collected internally and included in * the {@code SearchResult} object that is returned. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param derefPolicy The dereference policy the server should use for any * aliases encountered while processing the search. * @param sizeLimit The maximum number of entries that the server should * return for the search. A value of zero indicates that * there should be no limit. * @param timeLimit The maximum length of time in seconds that the server * should spend processing this search request. A value * of zero indicates that there should be no limit. * @param typesOnly Indicates whether to return only attribute names in * matching entries, or both attribute names and values. * @param filter The string representation of the filter to use to * identify matching entries. It must not be * {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return A search result object that provides information about the * processing of the search, including the set of matching entries * and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while parsing * the provided filter string, sending the * request, or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, final int timeLimit, final boolean typesOnly, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); try { return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes)); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } } /** * Processes a search operation with the provided information. The search * result entries and references will be collected internally and included in * the {@code SearchResult} object that is returned. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param derefPolicy The dereference policy the server should use for any * aliases encountered while processing the search. * @param sizeLimit The maximum number of entries that the server should * return for the search. A value of zero indicates that * there should be no limit. * @param timeLimit The maximum length of time in seconds that the server * should spend processing this search request. A value * of zero indicates that there should be no limit. * @param typesOnly Indicates whether to return only attribute names in * matching entries, or both attribute names and values. * @param filter The filter to use to identify matching entries. It * must not be {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return A search result object that provides information about the * processing of the search, including the set of matching entries * and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, final int timeLimit, final boolean typesOnly, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes)); } /** * Processes a search operation with the provided information. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchResultListener The search result listener that should be * used to return results to the client. It may * be {@code null} if the search results should * be collected internally and returned in the * {@code SearchResult} object. * @param baseDN The base DN for the search request. It must * not be {@code null}. * @param scope The scope that specifies the range of entries * that should be examined for the search. * @param derefPolicy The dereference policy the server should use * for any aliases encountered while processing * the search. * @param sizeLimit The maximum number of entries that the server * should return for the search. A value of * zero indicates that there should be no limit. * @param timeLimit The maximum length of time in seconds that * the server should spend processing this * search request. A value of zero indicates * that there should be no limit. * @param typesOnly Indicates whether to return only attribute * names in matching entries, or both attribute * names and values. * @param filter The string representation of the filter to * use to identify matching entries. It must * not be {@code null}. * @param attributes The set of attributes that should be returned * in matching entries. It may be {@code null} * or empty if the default attribute set (all * user attributes) is to be requested. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while parsing * the provided filter string, sending the * request, or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search( @Nullable final SearchResultListener searchResultListener, @NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, final int timeLimit, final boolean typesOnly, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); try { return search(new SearchRequest(searchResultListener, baseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes)); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } } /** * Processes a search operation with the provided information. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchResultListener The search result listener that should be * used to return results to the client. It may * be {@code null} if the search results should * be collected internally and returned in the * {@code SearchResult} object. * @param baseDN The base DN for the search request. It must * not be {@code null}. * @param scope The scope that specifies the range of entries * that should be examined for the search. * @param derefPolicy The dereference policy the server should use * for any aliases encountered while processing * the search. * @param sizeLimit The maximum number of entries that the server * should return for the search. A value of * zero indicates that there should be no limit. * @param timeLimit The maximum length of time in seconds that * the server should spend processing this * search request. A value of zero indicates * that there should be no limit. * @param typesOnly Indicates whether to return only attribute * names in matching entries, or both attribute * names and values. * @param filter The filter to use to identify matching * entries. It must not be {@code null}. * @param attributes The set of attributes that should be returned * in matching entries. It may be {@code null} * or empty if the default attribute set (all * user attributes) is to be requested. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search( @Nullable final SearchResultListener searchResultListener, @NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, final int timeLimit, final boolean typesOnly, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { Validator.ensureNotNull(baseDN, filter); return search(new SearchRequest(searchResultListener, baseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes)); } /** * Processes the provided search request. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchRequest The search request to be processed. It must not be * {@code null}. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final SearchRequest searchRequest) throws LDAPSearchException { Validator.ensureNotNull(searchRequest); final SearchResult searchResult; try { searchResult = searchRequest.process(this, 1); } catch (final LDAPSearchException lse) { Debug.debugException(lse); throw lse; } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } if (! searchResult.getResultCode().equals(ResultCode.SUCCESS)) { throw new LDAPSearchException(searchResult); } return searchResult; } /** * Processes the provided search request. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references (although if a search result listener was provided, * then it will have been used to make any entries and references available, * and they will not be available through the {@code getSearchEntries} and * {@code getSearchReferences} methods). * * @param searchRequest The search request to be processed. It must not be * {@code null}. * * @return A search result object that provides information about the * processing of the search, potentially including the set of * matching entries and search references returned by the server. * * @throws LDAPSearchException If the search does not complete successfully, * or if a problem is encountered while sending * the request or reading the response. If one * or more entries or references were returned * before the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResult search(@NotNull final ReadOnlySearchRequest searchRequest) throws LDAPSearchException { return search((SearchRequest) searchRequest); } /** * Processes a search operation with the provided information. It is expected * that at most one entry will be returned from the search, and that no * additional content from the successful search result (e.g., diagnostic * message or response controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param filter The string representation of the filter to use to * identify matching entries. It must not be * {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @Nullable() public SearchResultEntry searchForEntry(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { final SearchRequest r; try { r = new SearchRequest(baseDN, scope, DereferencePolicy.NEVER, 1, 0, false, filter, attributes); } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } return searchForEntry(r); } /** * Processes a search operation with the provided information. It is expected * that at most one entry will be returned from the search, and that no * additional content from the successful search result (e.g., diagnostic * message or response controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param filter The string representation of the filter to use to * identify matching entries. It must not be * {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @Nullable() public SearchResultEntry searchForEntry(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { return searchForEntry(new SearchRequest(baseDN, scope, DereferencePolicy.NEVER, 1, 0, false, filter, attributes)); } /** * Processes a search operation with the provided information. It is expected * that at most one entry will be returned from the search, and that no * additional content from the successful search result (e.g., diagnostic * message or response controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param derefPolicy The dereference policy the server should use for any * aliases encountered while processing the search. * @param timeLimit The maximum length of time in seconds that the server * should spend processing this search request. A value * of zero indicates that there should be no limit. * @param typesOnly Indicates whether to return only attribute names in * matching entries, or both attribute names and values. * @param filter The string representation of the filter to use to * identify matching entries. It must not be * {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @Nullable() public SearchResultEntry searchForEntry(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int timeLimit, final boolean typesOnly, @NotNull final String filter, @Nullable final String... attributes) throws LDAPSearchException { final SearchRequest r; try { r = new SearchRequest(baseDN, scope, derefPolicy, 1, timeLimit, typesOnly, filter, attributes); } catch (final LDAPException le) { Debug.debugException(le); throw new LDAPSearchException(le); } return searchForEntry(r); } /** * Processes a search operation with the provided information. It is expected * that at most one entry will be returned from the search, and that no * additional content from the successful search result (e.g., diagnostic * message or response controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param baseDN The base DN for the search request. It must not be * {@code null}. * @param scope The scope that specifies the range of entries that * should be examined for the search. * @param derefPolicy The dereference policy the server should use for any * aliases encountered while processing the search. * @param timeLimit The maximum length of time in seconds that the server * should spend processing this search request. A value * of zero indicates that there should be no limit. * @param typesOnly Indicates whether to return only attribute names in * matching entries, or both attribute names and values. * @param filter The filter to use to identify matching entries. It * must not be {@code null}. * @param attributes The set of attributes that should be returned in * matching entries. It may be {@code null} or empty if * the default attribute set (all user attributes) is to * be requested. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @Nullable() public SearchResultEntry searchForEntry(@NotNull final String baseDN, @NotNull final SearchScope scope, @NotNull final DereferencePolicy derefPolicy, final int timeLimit, final boolean typesOnly, @NotNull final Filter filter, @Nullable final String... attributes) throws LDAPSearchException { return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1, timeLimit, typesOnly, filter, attributes)); } /** * Processes the provided search request. It is expected that at most one * entry will be returned from the search, and that no additional content from * the successful search result (e.g., diagnostic message or response * controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param searchRequest The search request to be processed. If it is * configured with a search result listener or a size * limit other than one, then the provided request will * be duplicated with the appropriate settings. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @Nullable() public SearchResultEntry searchForEntry( @NotNull final SearchRequest searchRequest) throws LDAPSearchException { final SearchRequest r; if ((searchRequest.getSearchResultListener() != null) || (searchRequest.getSizeLimit() != 1)) { r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(), searchRequest.getDereferencePolicy(), 1, searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(), searchRequest.getFilter(), searchRequest.getAttributes()); r.setFollowReferrals(searchRequest.followReferralsInternal()); r.setReferralConnector(searchRequest.getReferralConnectorInternal()); r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null)); if (searchRequest.hasControl()) { r.setControlsInternal(searchRequest.getControls()); } } else { r = searchRequest; } final SearchResult result; try { result = search(r); } catch (final LDAPSearchException lse) { Debug.debugException(lse); if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT) { return null; } throw lse; } if (result.getEntryCount() == 0) { return null; } else { return result.getSearchEntries().get(0); } } /** * Processes the provided search request. It is expected that at most one * entry will be returned from the search, and that no additional content from * the successful search result (e.g., diagnostic message or response * controls) are needed. *

* Note that if the search does not complete successfully, an * {@code LDAPSearchException} will be thrown In some cases, one or more * search result entries or references may have been returned before the * failure response is received. In this case, the * {@code LDAPSearchException} methods like {@code getEntryCount}, * {@code getSearchEntries}, {@code getReferenceCount}, and * {@code getSearchReferences} may be used to obtain information about those * entries and references. * * @param searchRequest The search request to be processed. If it is * configured with a search result listener or a size * limit other than one, then the provided request will * be duplicated with the appropriate settings. * * @return The entry that was returned from the search, or {@code null} if no * entry was returned or the base entry does not exist. * * @throws LDAPSearchException If the search does not complete successfully, * if more than a single entry is returned, or * if a problem is encountered while parsing the * provided filter string, sending the request, * or reading the response. If one or more * entries or references were returned before * the failure was encountered, then the * {@code LDAPSearchException} object may be * examined to obtain information about those * entries and/or references. */ @Override() @NotNull() public SearchResultEntry searchForEntry( @NotNull final ReadOnlySearchRequest searchRequest) throws LDAPSearchException { return searchForEntry((SearchRequest) searchRequest); } /** * Processes the provided search request as an asynchronous operation. * * @param searchRequest The search request to be processed. It must not be * {@code null}, and it must be configured with a * search result listener that is also an * {@code AsyncSearchResultListener}. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If the provided search request does not have a * search result listener that is an * {@code AsyncSearchResultListener}, or if a problem * occurs while sending the request. */ @NotNull() public AsyncRequestID asyncSearch(@NotNull final SearchRequest searchRequest) throws LDAPException { Validator.ensureNotNull(searchRequest); final SearchResultListener searchListener = searchRequest.getSearchResultListener(); if (searchListener == null) { final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, ERR_ASYNC_SEARCH_NO_LISTENER.get()); Debug.debugCodingError(le); throw le; } else if (! (searchListener instanceof AsyncSearchResultListener)) { final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, ERR_ASYNC_SEARCH_INVALID_LISTENER.get()); Debug.debugCodingError(le); throw le; } if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return searchRequest.processAsync(this, (AsyncSearchResultListener) searchListener); } /** * Processes the provided search request as an asynchronous operation. * * @param searchRequest The search request to be processed. It must not be * {@code null}, and it must be configured with a * search result listener that is also an * {@code AsyncSearchResultListener}. * * @return An async request ID that may be used to reference the operation. * * @throws LDAPException If the provided search request does not have a * search result listener that is an * {@code AsyncSearchResultListener}, or if a problem * occurs while sending the request. */ @NotNull() public AsyncRequestID asyncSearch( @NotNull final ReadOnlySearchRequest searchRequest) throws LDAPException { if (synchronousMode()) { throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get()); } return asyncSearch((SearchRequest) searchRequest); } /** * Processes the provided generic request and returns the result. This may * be useful for cases in which it is not known what type of operation the * request represents. * * @param request The request to be processed. * * @return The result obtained from processing the request. * * @throws LDAPException If a problem occurs while sending the request or * reading the response. Note simply having a * non-success result code in the response will not * cause an exception to be thrown. */ @NotNull() public LDAPResult processOperation(@NotNull final LDAPRequest request) throws LDAPException { if (request instanceof BindRequest) { // Bind request special processing. return processBindOperation((BindRequest) request); } else { return request.process(this, 1); } } /** * Processes the provided bind request and returns the result. This will also * ensure that any appropriate updates are made to the last bind request and * cached schema. * * @param bindRequest The bind request to be processed. * * @return The result obtained from processing the request. * * @throws LDAPException If a problem occurs while sending the request or * reading the response. Note simply having a * non-success result code in the response will not * cause an exception to be thrown. */ @NotNull() private BindResult processBindOperation( @NotNull final BindRequest bindRequest) throws LDAPException { // We don't want to update the last bind request or update the cached // schema for this connection if it included the retain identity control. boolean hasRetainIdentityControl = false; for (final Control c : bindRequest.getControls()) { if (c.getOID().equals( RetainIdentityRequestControl.RETAIN_IDENTITY_REQUEST_OID)) { hasRetainIdentityControl = true; break; } } if (! hasRetainIdentityControl) { lastBindRequest = null; } final BindResult bindResult = bindRequest.process(this, 1); if (bindResult.getResultCode().equals(ResultCode.SUCCESS)) { if (! hasRetainIdentityControl) { lastBindRequest = bindRequest; if (connectionOptions.useSchema()) { try { cachedSchema = getCachedSchema(this); } catch (final Exception e) { Debug.debugException(e); } } } } return bindResult; } /** * Retrieves the referral connector that should be used to establish * connections for use when following referrals. * * @return The referral connector that should be used to establish * connections for use when following referrals. */ @NotNull() public ReferralConnector getReferralConnector() { if (referralConnector == null) { return this; } else { return referralConnector; } } /** * Specifies the referral connector that should be used to establish * connections for use when following referrals. * * @param referralConnector The referral connector that should be used to * establish connections for use when following * referrals. */ public void setReferralConnector( @Nullable final ReferralConnector referralConnector) { if (referralConnector == null) { this.referralConnector = this; } else { this.referralConnector = referralConnector; } } /** * Sends the provided LDAP message to the server over this connection. * * @param message The LDAP message to send to the target server. * @param sendTimeoutMillis The maximum length of time, in milliseconds, to * block while trying to send the request. If this * is less than or equal to zero, then no send * timeout will be enforced. * * @throws LDAPException If a problem occurs while sending the request. */ void sendMessage(@NotNull final LDAPMessage message, final long sendTimeoutMillis) throws LDAPException { if (needsReconnect.compareAndSet(true, false)) { reconnect(); } final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { @SuppressWarnings("deprecation") final boolean autoReconnect = connectionOptions.autoReconnect(); internals.sendMessage(message, sendTimeoutMillis, autoReconnect); lastCommunicationTime = System.currentTimeMillis(); } } /** * Retrieves the message ID that should be used for the next request sent * over this connection. * * @return The message ID that should be used for the next request sent over * this connection, or -1 if this connection is not established. */ int nextMessageID() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return -1; } else { return internals.nextMessageID(); } } /** * Retrieves the disconnect info object for this connection, if available. * * @return The disconnect info for this connection, or {@code null} if none * is set. */ @Nullable() DisconnectInfo getDisconnectInfo() { return disconnectInfo.get(); } /** * Sets the disconnect type, message, and cause for this connection, if those * values have not been previously set. It will not overwrite any values that * had been previously set. *

* This method may be called by code which is not part of the LDAP SDK to * provide additional information about the reason for the closure. In that * case, this method must be called before the call to * {@link LDAPConnection#close}. * * @param type The disconnect type. It must not be {@code null}. * @param message A message providing additional information about the * disconnect. It may be {@code null} if no message is * available. * @param cause The exception that was caught to trigger the disconnect. * It may be {@code null} if the disconnect was not triggered * by an exception. */ public void setDisconnectInfo(@NotNull final DisconnectType type, @Nullable final String message, @Nullable final Throwable cause) { disconnectInfo.compareAndSet(null, new DisconnectInfo(this, type, message, cause)); } /** * Sets the disconnect info for this connection, if it is not already set. * * @param info The disconnect info to be set, if it is not already set. * * @return The disconnect info set for the connection, whether it was * previously or newly set. */ @Nullable() DisconnectInfo setDisconnectInfo(@Nullable final DisconnectInfo info) { disconnectInfo.compareAndSet(null, info); return disconnectInfo.get(); } /** * {@inheritDoc} */ @Override() @Nullable() public DisconnectType getDisconnectType() { final DisconnectInfo di = disconnectInfo.get(); if (di == null) { return null; } else { return di.getType(); } } /** * {@inheritDoc} */ @Override() @Nullable() public String getDisconnectMessage() { final DisconnectInfo di = disconnectInfo.get(); if (di == null) { return null; } else { return di.getMessage(); } } /** * {@inheritDoc} */ @Override() @Nullable() public Throwable getDisconnectCause() { final DisconnectInfo di = disconnectInfo.get(); if (di == null) { return null; } else { return di.getCause(); } } /** * Indicates that this connection has been closed and is no longer available * for use. */ void setClosed() { needsReconnect.set(false); if (disconnectInfo.get() == null) { try { final StackTraceElement[] stackElements = Thread.currentThread().getStackTrace(); final StackTraceElement[] parentStackElements = new StackTraceElement[stackElements.length - 1]; System.arraycopy(stackElements, 1, parentStackElements, 0, parentStackElements.length); setDisconnectInfo(DisconnectType.OTHER, ERR_CONN_CLOSED_BY_UNEXPECTED_CALL_PATH.get( StaticUtils.getStackTrace(parentStackElements)), null); } catch (final Exception e) { Debug.debugException(e); } } connectionStatistics.incrementNumDisconnects(); final LDAPConnectionInternals internals = connectionInternals; if (internals != null) { internals.close(); connectionInternals = null; } cachedSchema = null; lastCommunicationTime = -1L; synchronized (this) { final Timer t = timer; timer = null; if (t != null) { t.cancel(); } } } /** * Registers the provided response acceptor with the connection reader. * * @param messageID The message ID for which the acceptor is to be * registered. * @param responseAcceptor The response acceptor to register. * * @throws LDAPException If another message acceptor is already registered * with the provided message ID. */ void registerResponseAcceptor(final int messageID, @NotNull final ResponseAcceptor responseAcceptor) throws LDAPException { if (needsReconnect.compareAndSet(true, false)) { reconnect(); } final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { internals.registerResponseAcceptor(messageID, responseAcceptor); } } /** * Deregisters the response acceptor associated with the provided message ID. * * @param messageID The message ID for which to deregister the associated * response acceptor. */ void deregisterResponseAcceptor(final int messageID) { final LDAPConnectionInternals internals = connectionInternals; if (internals != null) { internals.deregisterResponseAcceptor(messageID); } } /** * Retrieves a timer for use with this connection, creating one if necessary. * * @return A timer for use with this connection. * * @throws LDAPException If the connection has been closed. */ @NotNull() Timer getTimer() throws LDAPException { final Timer t = getTimerNullable(); if (t == null) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { return t; } } /** * Retrieves a timer for use with this connection, creating one if necessary * and the connection is established. * * @return A timer for use with this connection, or {@code null} if the * connection is not established. */ @Nullable() synchronized Timer getTimerNullable() { if (timer == null) { if (closeRequested || (connectionInternals == null)) { return null; } timer = new Timer("Timer thread for " + toString(), true); } return timer; } /** * {@inheritDoc} */ @Override() @NotNull() public LDAPConnection getReferralConnection( @NotNull final LDAPURL referralURL, @NotNull final LDAPConnection connection) throws LDAPException { final String host = referralURL.getHost(); final int port = referralURL.getPort(); BindRequest bindRequest = null; if (connection.lastBindRequest != null) { bindRequest = connection.lastBindRequest.getRebindRequest(host, port); if (bindRequest == null) { throw new LDAPException(ResultCode.REFERRAL, ERR_CONN_CANNOT_AUTHENTICATE_FOR_REFERRAL.get( host, port)); } } final ExtendedRequest connStartTLSRequest = connection.startTLSRequest; final LDAPConnection conn = new LDAPConnection(connection.socketFactory, connection.connectionOptions, host, port); if (connStartTLSRequest != null) { try { final ExtendedResult startTLSResult = conn.processExtendedOperation(connStartTLSRequest); if (startTLSResult.getResultCode() != ResultCode.SUCCESS) { throw new LDAPException(startTLSResult); } } catch (final LDAPException le) { Debug.debugException(le); conn.setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le); conn.close(); throw le; } } if (bindRequest != null) { try { conn.bind(bindRequest); } catch (final LDAPException le) { Debug.debugException(le); conn.setDisconnectInfo(DisconnectType.BIND_FAILED, null, le); conn.close(); throw le; } } return conn; } /** * {@inheritDoc} */ @Override() @Nullable() public BindRequest getLastBindRequest() { return lastBindRequest; } /** * {@inheritDoc} */ @Override() @Nullable() public ExtendedRequest getStartTLSRequest() { return startTLSRequest; } /** * Retrieves an instance of the {@code LDAPConnectionInternals} object for * this connection. * * @param throwIfDisconnected Indicates whether to throw an * {@code LDAPException} if the connection is not * established. * * @return The {@code LDAPConnectionInternals} object for this connection, or * {@code null} if the connection is not established and no exception * should be thrown. * * @throws LDAPException If the connection is not established and * {@code throwIfDisconnected} is {@code true}. */ @Nullable() LDAPConnectionInternals getConnectionInternals( final boolean throwIfDisconnected) throws LDAPException { final LDAPConnectionInternals internals = connectionInternals; if ((internals == null) && throwIfDisconnected) { throw new LDAPException(ResultCode.SERVER_DOWN, ERR_CONN_NOT_ESTABLISHED.get()); } else { return internals; } } /** * Retrieves the cached schema for this connection, if applicable. * * @return The cached schema for this connection, or {@code null} if it is * not available (e.g., because the connection is not established, * because {@link LDAPConnectionOptions#useSchema()} is false, or * because an error occurred when trying to read the server schema). */ @Nullable() Schema getCachedSchema() { return cachedSchema; } /** * Sets the cached schema for this connection. * * @param cachedSchema The cached schema for this connection. It may be * {@code null} if no cached schema is available. */ void setCachedSchema(@Nullable final Schema cachedSchema) { this.cachedSchema = cachedSchema; } /** * {@inheritDoc} */ @Override() public boolean synchronousMode() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return false; } else { return internals.synchronousMode(); } } /** * Reads a response from the server, blocking if necessary until the response * has been received. This should only be used for connections operating in * synchronous mode. * * @param messageID The message ID for the response to be read. Any * response read with a different message ID will be * discarded, unless it is an unsolicited notification in * which case it will be provided to any registered * unsolicited notification handler. * * @return The response read from the server. * * @throws LDAPException If a problem occurs while reading the response. */ @NotNull() LDAPResponse readResponse(final int messageID) throws LDAPException { final LDAPConnectionInternals internals = connectionInternals; if (internals != null) { final LDAPResponse response = internals.getConnectionReader().readResponse(messageID); Debug.debugLDAPResult(response, this); internals.getConnectionReader().logResponse(response); return response; } else { final DisconnectInfo di = disconnectInfo.get(); if (di == null) { return new ConnectionClosedResponse(ResultCode.CONNECT_ERROR, ERR_CONN_READ_RESPONSE_NOT_ESTABLISHED.get()); } else { return new ConnectionClosedResponse(di.getType().getResultCode(), di.getMessage()); } } } /** * {@inheritDoc} */ @Override() public long getConnectTime() { final LDAPConnectionInternals internals = connectionInternals; if (internals != null) { return internals.getConnectTime(); } else { return -1L; } } /** * {@inheritDoc} */ @Override() public long getLastCommunicationTime() { if (lastCommunicationTime > 0L) { return lastCommunicationTime; } else { return getConnectTime(); } } /** * Updates the last communication time for this connection to be the current * time. */ void setLastCommunicationTime() { lastCommunicationTime = System.currentTimeMillis(); } /** * {@inheritDoc} */ @Override() @NotNull() public LDAPConnectionStatistics getConnectionStatistics() { return connectionStatistics; } /** * {@inheritDoc} */ @Override() public int getActiveOperationCount() { final LDAPConnectionInternals internals = connectionInternals; if (internals == null) { return -1; } else { if (internals.synchronousMode()) { return -1; } else { return internals.getConnectionReader().getActiveOperationCount(); } } } /** * Retrieves the schema from the provided connection. If the retrieved schema * matches schema that's already in use by other connections, the common * schema will be used instead of the newly-retrieved version. * * @param c The connection for which to retrieve the schema. * * @return The schema retrieved from the given connection, or a cached * schema if it matched a schema that was already in use. * * @throws LDAPException If a problem is encountered while retrieving or * parsing the schema. */ @Nullable() private static Schema getCachedSchema(@NotNull final LDAPConnection c) throws LDAPException { final Schema s = c.getSchema(); synchronized (SCHEMA_SET) { return SCHEMA_SET.addAndGet(s); } } /** * Retrieves the connection attachment with the specified name. * * @param name The name of the attachment to retrieve. It must not be * {@code null}. * * @return The connection attachment with the specified name, or {@code null} * if there is no such attachment. */ @Nullable() synchronized Object getAttachment(@NotNull final String name) { if (attachments == null) { return null; } else { return attachments.get(name); } } /** * Sets a connection attachment with the specified name and value. * * @param name The name of the attachment to set. It must not be * {@code null}. * @param value The value to use for the attachment. It may be {@code null} * if an attachment with the specified name should be cleared * rather than overwritten. */ synchronized void setAttachment(@NotNull final String name, @Nullable final Object value) { if (attachments == null) { attachments = new HashMap<>(StaticUtils.computeMapCapacity(10)); } if (value == null) { attachments.remove(name); } else { attachments.put(name, value); } } /** * Performs any necessary cleanup to ensure that this connection is properly * closed before it is garbage collected. * * @throws Throwable If the superclass finalizer throws an exception. */ @Override() protected void finalize() throws Throwable { super.finalize(); setDisconnectInfo(DisconnectType.CLOSED_BY_FINALIZER, null, null); setClosed(); } /** * {@inheritDoc} */ @Override() @NotNull() public String toString() { final StringBuilder buffer = new StringBuilder(); toString(buffer); return buffer.toString(); } /** * {@inheritDoc} */ @Override() public void toString(@NotNull final StringBuilder buffer) { buffer.append("LDAPConnection("); final String name = connectionName; final String poolName = connectionPoolName; if (name != null) { buffer.append("name='"); buffer.append(name); buffer.append("', "); } else if (poolName != null) { buffer.append("poolName='"); buffer.append(poolName); buffer.append("', "); } final LDAPConnectionInternals internals = connectionInternals; if ((internals != null) && internals.isConnected()) { buffer.append("connected to "); buffer.append(internals.getHost()); buffer.append(':'); buffer.append(internals.getPort()); } else { buffer.append("not connected"); } buffer.append(')'); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy