com.unboundid.ldap.sdk.RoundRobinDNSServerSet Maven / Gradle / Ivy
                 Go to download
                
        
                    Show more of this group  Show more artifacts with this name
Show all versions of unboundid-ldapsdk-commercial-edition Show documentation
                Show all versions of unboundid-ldapsdk-commercial-edition Show documentation
      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 Commercial Edition of the LDAP SDK, which includes
      all of the general-purpose functionality contained in the Standard
      Edition, plus additional functionality specific to UnboundID server
      products.
    
                
            /*
 * Copyright 2014-2016 UnboundID Corp.
 * All Rights Reserved.
 */
/*
 * Copyright (C) 2014-2016 UnboundID Corp.
 *
 * 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.ObjectPair;
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.
   */
  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,
  }
  // The address selection mode that should be used if the provided hostname
  // resolves to multiple addresses.
  private final AddressSelectionMode selectionMode;
  // A counter that will be used to handle round-robin ordering.
  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.
  private final AtomicReference>
       resolvedAddressesWithTimeout;
  // The properties that will be used to initialize the JNDI context, if any.
  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.
  private final LDAPConnectionOptions connectionOptions;
  // The maximum length of time, in milliseconds, to cache resolved addresses.
  private final long cacheTimeoutMillis;
  // The socket factory to use to establish connections.
  private final SocketFactory socketFactory;
  // The hostname to be resolved.
  private final String hostname;
  // The provider URL to use to resolve names, if any.
  private final String providerURL;
  // The DNS record types that will be used to obtain the IP addresses for the
  // specified hostname.
  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(final String hostname, final int port,
                                final AddressSelectionMode selectionMode,
                                final long cacheTimeoutMillis,
                                final String providerURL,
                                final SocketFactory socketFactory,
                                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(final String hostname, final int port,
                                final AddressSelectionMode selectionMode,
                                final long cacheTimeoutMillis,
                                final String providerURL,
                                final Properties jndiProperties,
                                final String[] dnsRecordTypes,
                                final SocketFactory socketFactory,
                                final LDAPConnectionOptions connectionOptions)
  {
    Validator.ensureNotNull(hostname);
    Validator.ensureTrue((port >= 1) && (port <= 65535));
    Validator.ensureNotNull(selectionMode);
    this.hostname      = hostname;
    this.port          = port;
    this.selectionMode = selectionMode;
    this.providerURL   = providerURL;
    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         © 2015 - 2025 Weber Informatics LLC | Privacy Policy