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

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

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2007-2022 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2007-2022 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-2022 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