Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014-2024 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2014-2024 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2014-2024 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.net.SocketFactory;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.ObjectPair;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadLocalRandom;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import static com.unboundid.ldap.sdk.LDAPMessages.*;
/**
* This class provides a server set implementation that handles the case in
* which a given host name may resolve to multiple IP addresses. Note that
* while a setup like this is typically referred to as "round-robin DNS", this
* server set implementation does not strictly require DNS (as names may be
* resolved through alternate mechanisms like a hosts file or an alternate name
* service), and it does not strictly require round-robin use of those addresses
* (as alternate ordering mechanisms, like randomized or failover, may be used).
*
*
Example
* The following example demonstrates the process for creating a round-robin DNS
* server set for the case in which the hostname "directory.example.com" may be
* associated with multiple IP addresses, and the LDAP SDK should attempt to use
* them in a round robin manner.
*
* // Define a number of variables that will be used by the server set.
* String hostname = "directory.example.com";
* int port = 389;
* AddressSelectionMode selectionMode =
* AddressSelectionMode.ROUND_ROBIN;
* long cacheTimeoutMillis = 3600000L; // 1 hour
* String providerURL = "dns:"; // Default DNS config.
* SocketFactory socketFactory = null; // Default socket factory.
* LDAPConnectionOptions connectionOptions = null; // Default options.
*
* // Create the server set using the settings defined above.
* RoundRobinDNSServerSet serverSet = new RoundRobinDNSServerSet(hostname,
* port, selectionMode, cacheTimeoutMillis, providerURL, socketFactory,
* connectionOptions);
*
* // Verify that we can establish a single connection using the server set.
* LDAPConnection connection = serverSet.getConnection();
* RootDSE rootDSEFromConnection = connection.getRootDSE();
* connection.close();
*
* // Verify that we can establish a connection pool using the server set.
* SimpleBindRequest bindRequest =
* new SimpleBindRequest("uid=pool.user,dc=example,dc=com", "password");
* LDAPConnectionPool pool =
* new LDAPConnectionPool(serverSet, bindRequest, 10);
* RootDSE rootDSEFromPool = pool.getRootDSE();
* pool.close();
*
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class RoundRobinDNSServerSet
extends ServerSet
{
/**
* The name of a system property that can be used to specify a comma-delimited
* list of IP addresses to use if resolution fails. This is intended
* primarily for testing purposes.
*/
@NotNull static final String PROPERTY_DEFAULT_ADDRESSES =
RoundRobinDNSServerSet.class.getName() + ".defaultAddresses";
/**
* An enum that defines the modes that may be used to select the order in
* which addresses should be used in attempts to establish connections.
*/
public enum AddressSelectionMode
{
/**
* The address selection mode that will cause addresses to be consistently
* attempted in the order they are retrieved from the name service.
*/
FAILOVER,
/**
* The address selection mode that will cause the order of addresses to be
* randomized for each attempt.
*/
RANDOM,
/**
* The address selection mode that will cause connection attempts to be made
* in a round-robin order.
*/
ROUND_ROBIN;
/**
* Retrieves the address selection mode with the specified name.
*
* @param name The name of the address selection mode to retrieve. It
* must not be {@code null}.
*
* @return The requested address selection mode, or {@code null} if no such
* change mode is defined.
*/
@Nullable()
public static AddressSelectionMode forName(@NotNull final String name)
{
switch (StaticUtils.toLowerCase(name))
{
case "failover":
return FAILOVER;
case "random":
return RANDOM;
case "roundrobin":
case "round-robin":
case "round_robin":
return ROUND_ROBIN;
default:
return null;
}
}
}
// The address selection mode that should be used if the provided hostname
// resolves to multiple addresses.
@NotNull private final AddressSelectionMode selectionMode;
// A counter that will be used to handle round-robin ordering.
@NotNull private final AtomicLong roundRobinCounter;
// A reference to an object that combines the resolved addresses with a
// timestamp indicating when the value should no longer be trusted.
@NotNull private final AtomicReference>
resolvedAddressesWithTimeout;
// The bind request to use to authenticate connections created by this
// server set.
@Nullable private final BindRequest bindRequest;
// The properties that will be used to initialize the JNDI context, if any.
@Nullable private final Hashtable jndiProperties;
// The port number for the target server.
private final int port;
// The set of connection options to use for new connections.
@NotNull private final LDAPConnectionOptions connectionOptions;
// The maximum length of time, in milliseconds, to cache resolved addresses.
private final long cacheTimeoutMillis;
// The post-connect processor to invoke against connections created by this
// server set.
@Nullable private final PostConnectProcessor postConnectProcessor;
// The socket factory to use to establish connections.
@NotNull private final SocketFactory socketFactory;
// The hostname to be resolved.
@NotNull private final String hostname;
// The provider URL to use to resolve names, if any.
@Nullable private final String providerURL;
// The DNS record types that will be used to obtain the IP addresses for the
// specified hostname.
@NotNull private final String[] dnsRecordTypes;
/**
* Creates a new round-robin DNS server set with the provided information.
*
* @param hostname The hostname to be resolved to one or more
* addresses. It must not be {@code null}.
* @param port The port to use to connect to the server. Note
* that even if the provided hostname resolves to
* multiple addresses, the same port must be used
* for all addresses.
* @param selectionMode The selection mode that should be used if the
* hostname resolves to multiple addresses. It
* must not be {@code null}.
* @param cacheTimeoutMillis The maximum length of time in milliseconds to
* cache addresses resolved from the provided
* hostname. Caching resolved addresses can
* result in better performance and can reduce the
* number of requests to the name service. A
* that is less than or equal to zero indicates
* that no caching should be used.
* @param providerURL The JNDI provider URL that should be used when
* communicating with the DNS server. If this is
* {@code null}, then the underlying system's
* name service mechanism will be used (which may
* make use of other services instead of or in
* addition to DNS). If this is non-{@code null},
* then only DNS will be used to perform the name
* resolution. A value of "dns:" indicates that
* the underlying system's DNS configuration
* should be used.
* @param socketFactory The socket factory to use to establish the
* connections. It may be {@code null} if the
* JVM-default socket factory should be used.
* @param connectionOptions The set of connection options that should be
* used for the connections. It may be
* {@code null} if a default set of connection
* options should be used.
*/
public RoundRobinDNSServerSet(@NotNull final String hostname, final int port,
@NotNull final AddressSelectionMode selectionMode,
final long cacheTimeoutMillis,
@Nullable final String providerURL,
@Nullable final SocketFactory socketFactory,
@Nullable final LDAPConnectionOptions connectionOptions)
{
this(hostname, port, selectionMode, cacheTimeoutMillis, providerURL,
null, null, socketFactory, connectionOptions);
}
/**
* Creates a new round-robin DNS server set with the provided information.
*
* @param hostname The hostname to be resolved to one or more
* addresses. It must not be {@code null}.
* @param port The port to use to connect to the server. Note
* that even if the provided hostname resolves to
* multiple addresses, the same port must be used
* for all addresses.
* @param selectionMode The selection mode that should be used if the
* hostname resolves to multiple addresses. It
* must not be {@code null}.
* @param cacheTimeoutMillis The maximum length of time in milliseconds to
* cache addresses resolved from the provided
* hostname. Caching resolved addresses can
* result in better performance and can reduce the
* number of requests to the name service. A
* that is less than or equal to zero indicates
* that no caching should be used.
* @param providerURL The JNDI provider URL that should be used when
* communicating with the DNS server.If both
* {@code providerURL} and {@code jndiProperties}
* are {@code null}, then then JNDI will not be
* used to interact with DNS and the hostname
* resolution will be performed via the underlying
* system's name service mechanism (which may make
* use of other services instead of or in addition
* to DNS). If this is non-{@code null}, then
* only DNS will be used to perform the name
* resolution. A value of "dns:" indicates that
* the underlying system's DNS configuration
* should be used.
* @param jndiProperties A set of JNDI-related properties that should be
* be used when initializing the context for
* interacting with the DNS server via JNDI. If
* both {@code providerURL} and
* {@code jndiProperties} are {@code null}, then
* then JNDI will not be used to interact with
* DNS and the hostname resolution will be
* performed via the underlying system's name
* service mechanism (which may make use of other
* services instead of or in addition to DNS). If
* {@code providerURL} is {@code null} and
* {@code jndiProperties} is non-{@code null},
* then the provided properties must specify the
* URL.
* @param dnsRecordTypes Specifies the types of DNS records that will be
* used to obtain the addresses for the specified
* hostname. This will only be used if at least
* one of {@code providerURL} and
* {@code jndiProperties} is non-{@code null}. If
* this is {@code null} or empty, then a default
* record type of "A" (indicating IPv4 addresses)
* will be used.
* @param socketFactory The socket factory to use to establish the
* connections. It may be {@code null} if the
* JVM-default socket factory should be used.
* @param connectionOptions The set of connection options that should be
* used for the connections. It may be
* {@code null} if a default set of connection
* options should be used.
*/
public RoundRobinDNSServerSet(@NotNull final String hostname, final int port,
@NotNull final AddressSelectionMode selectionMode,
final long cacheTimeoutMillis,
@Nullable final String providerURL,
@Nullable final Properties jndiProperties,
@Nullable final String[] dnsRecordTypes,
@Nullable final SocketFactory socketFactory,
@Nullable final LDAPConnectionOptions connectionOptions)
{
this(hostname, port, selectionMode, cacheTimeoutMillis, providerURL,
jndiProperties, dnsRecordTypes, socketFactory, connectionOptions, null,
null);
}
/**
* Creates a new round-robin DNS server set with the provided information.
*
* @param hostname The hostname to be resolved to one or more
* addresses. It must not be {@code null}.
* @param port The port to use to connect to the server.
* Note that even if the provided hostname
* resolves to multiple addresses, the same
* port must be used for all addresses.
* @param selectionMode The selection mode that should be used if the
* hostname resolves to multiple addresses. It
* must not be {@code null}.
* @param cacheTimeoutMillis The maximum length of time in milliseconds to
* cache addresses resolved from the provided
* hostname. Caching resolved addresses can
* result in better performance and can reduce
* the number of requests to the name service.
* A that is less than or equal to zero
* indicates that no caching should be used.
* @param providerURL The JNDI provider URL that should be used
* when communicating with the DNS server. If
* both {@code providerURL} and
* {@code jndiProperties} are {@code null},
* then then JNDI will not be used to interact
* with DNS and the hostname resolution will be
* performed via the underlying system's name
* service mechanism (which may make use of
* other services instead of or in addition to
* DNS). If this is non-{@code null}, then only
* DNS will be used to perform the name
* resolution. A value of "dns:" indicates that
* the underlying system's DNS configuration
* should be used.
* @param jndiProperties A set of JNDI-related properties that should
* be used when initializing the context for
* interacting with the DNS server via JNDI. If
* both {@code providerURL} and
* {@code jndiProperties} are {@code null}, then
* JNDI will not be used to interact with DNS
* and the hostname resolution will be
* performed via the underlying system's name
* service mechanism (which may make use of
* other services instead of or in addition to
* DNS). If {@code providerURL} is
* {@code null} and {@code jndiProperties} is
* non-{@code null}, then the provided
* properties must specify the URL.
* @param dnsRecordTypes Specifies the types of DNS records that will
* be used to obtain the addresses for the
* specified hostname. This will only be used
* if at least one of {@code providerURL} and
* {@code jndiProperties} is non-{@code null}.
* If this is {@code null} or empty, then a
* default record type of "A" (indicating IPv4
* addresses) will be used.
* @param socketFactory The socket factory to use to establish the
* connections. It may be {@code null} if the
* JVM-default socket factory should be used.
* @param connectionOptions The set of connection options that should be
* used for the connections. It may be
* {@code null} if a default set of connection
* options should be used.
* @param bindRequest The bind request that should be used to
* authenticate newly-established connections.
* It may be {@code null} if this server set
* should not perform any authentication.
* @param postConnectProcessor The post-connect processor that should be
* invoked on newly-established connections. It
* may be {@code null} if this server set should
* not perform any post-connect processing.
*/
public RoundRobinDNSServerSet(@NotNull final String hostname, final int port,
@NotNull final AddressSelectionMode selectionMode,
final long cacheTimeoutMillis,
@Nullable final String providerURL,
@Nullable final Properties jndiProperties,
@Nullable final String[] dnsRecordTypes,
@Nullable final SocketFactory socketFactory,
@Nullable final LDAPConnectionOptions connectionOptions,
@Nullable final BindRequest bindRequest,
@Nullable final PostConnectProcessor postConnectProcessor)
{
Validator.ensureNotNull(hostname);
Validator.ensureTrue((port >= 1) && (port <= 65_535));
Validator.ensureNotNull(selectionMode);
this.hostname = hostname;
this.port = port;
this.selectionMode = selectionMode;
this.providerURL = providerURL;
this.bindRequest = bindRequest;
this.postConnectProcessor = postConnectProcessor;
if (jndiProperties == null)
{
if (providerURL == null)
{
this.jndiProperties = null;
}
else
{
this.jndiProperties = new Hashtable<>(2);
this.jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.dns.DnsContextFactory");
this.jndiProperties.put(Context.PROVIDER_URL, providerURL);
}
}
else
{
this.jndiProperties = new Hashtable<>(jndiProperties.size()+2);
for (final Map.Entry