001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017
018package org.forgerock.opendj.ldap;
019
020import static org.forgerock.opendj.ldap.RequestHandlerFactoryAdapter.adaptRequestHandler;
021import static org.forgerock.util.time.Duration.duration;
022
023import java.net.InetAddress;
024import java.net.InetSocketAddress;
025import java.util.Collection;
026import java.util.concurrent.ScheduledExecutorService;
027import java.util.concurrent.ThreadLocalRandom;
028import java.util.concurrent.TimeUnit;
029import java.util.concurrent.atomic.AtomicInteger;
030
031import org.forgerock.opendj.ldap.requests.AddRequest;
032import org.forgerock.opendj.ldap.requests.CRAMMD5SASLBindRequest;
033import org.forgerock.opendj.ldap.requests.CompareRequest;
034import org.forgerock.opendj.ldap.requests.DeleteRequest;
035import org.forgerock.opendj.ldap.requests.DigestMD5SASLBindRequest;
036import org.forgerock.opendj.ldap.requests.GSSAPISASLBindRequest;
037import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
038import org.forgerock.opendj.ldap.requests.ModifyRequest;
039import org.forgerock.opendj.ldap.requests.PasswordModifyExtendedRequest;
040import org.forgerock.opendj.ldap.requests.PlainSASLBindRequest;
041import org.forgerock.opendj.ldap.requests.Request;
042import org.forgerock.opendj.ldap.requests.SearchRequest;
043import org.forgerock.opendj.ldap.requests.SimpleBindRequest;
044import org.forgerock.util.Function;
045import org.forgerock.util.Option;
046import org.forgerock.util.Options;
047import org.forgerock.util.Reject;
048import org.forgerock.util.promise.NeverThrowsException;
049import org.forgerock.util.promise.Promise;
050import org.forgerock.util.time.Duration;
051
052/**
053 * This class contains methods for creating and manipulating connection
054 * factories and connections.
055 */
056public final class Connections {
057    /**
058     * Specifies the interval between successive attempts to reconnect to offline load-balanced connection factories.
059     * The default configuration is to attempt to reconnect every second.
060     */
061    public static final Option<Duration> LOAD_BALANCER_MONITORING_INTERVAL = Option.withDefault(duration("1 seconds"));
062
063    /**
064     * Specifies the event listener which should be notified whenever a load-balanced connection factory changes state
065     * from online to offline or vice-versa. By default events will be logged to the {@code LoadBalancingAlgorithm}
066     * logger using the {@link LoadBalancerEventListener#LOG_EVENTS} listener.
067     */
068    public static final Option<LoadBalancerEventListener> LOAD_BALANCER_EVENT_LISTENER =
069            Option.of(LoadBalancerEventListener.class, LoadBalancerEventListener.LOG_EVENTS);
070
071    /**
072     * Specifies the scheduler which will be used for periodically reconnecting to offline connection factories. A
073     * system-wide scheduler will be used by default.
074     */
075    public static final Option<ScheduledExecutorService> LOAD_BALANCER_SCHEDULER =
076            Option.of(ScheduledExecutorService.class, null);
077
078    /**
079     * Creates a new connection pool which creates new connections as needed
080     * using the provided connection factory, but will reuse previously
081     * allocated connections when they are available.
082     * <p>
083     * Connections which have not been used for sixty seconds are closed and
084     * removed from the pool. Thus, a pool that remains idle for long enough
085     * will not contain any cached connections.
086     * <p>
087     * Connections obtained from the connection pool are guaranteed to be valid
088     * immediately before being returned to the calling application. More
089     * specifically, connections which have remained idle in the connection pool
090     * for a long time and which have been remotely closed due to a time out
091     * will never be returned. However, once a pooled connection has been
092     * obtained it is the responsibility of the calling application to handle
093     * subsequent connection failures, these being signaled via a
094     * {@link ConnectionException}.
095     *
096     * @param factory
097     *            The connection factory to use for creating new connections.
098     * @return The new connection pool.
099     * @throws NullPointerException
100     *             If {@code factory} was {@code null}.
101     */
102    public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory) {
103        return new CachedConnectionPool(factory, 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, null);
104    }
105
106    /**
107     * Creates a new connection pool which creates new connections as needed
108     * using the provided connection factory, but will reuse previously
109     * allocated connections when they are available.
110     * <p>
111     * Attempts to use more than {@code maximumPoolSize} connections at once
112     * will block until a connection is released back to the pool. In other
113     * words, this pool will prevent applications from using more than
114     * {@code maximumPoolSize} connections at the same time.
115     * <p>
116     * Connections which have not been used for the provided {@code idleTimeout}
117     * period are closed and removed from the pool, until there are only
118     * {@code corePoolSize} connections remaining.
119     * <p>
120     * Connections obtained from the connection pool are guaranteed to be valid
121     * immediately before being returned to the calling application. More
122     * specifically, connections which have remained idle in the connection pool
123     * for a long time and which have been remotely closed due to a time out
124     * will never be returned. However, once a pooled connection has been
125     * obtained it is the responsibility of the calling application to handle
126     * subsequent connection failures, these being signaled via a
127     * {@link ConnectionException}.
128     *
129     * @param factory
130     *            The connection factory to use for creating new connections.
131     * @param corePoolSize
132     *            The minimum number of connections to keep in the pool, even if
133     *            they are idle.
134     * @param maximumPoolSize
135     *            The maximum number of connections to allow in the pool.
136     * @param idleTimeout
137     *            The time out period, after which unused non-core connections
138     *            will be closed.
139     * @param unit
140     *            The time unit for the {@code keepAliveTime} argument.
141     * @return The new connection pool.
142     * @throws IllegalArgumentException
143     *             If {@code corePoolSize}, {@code maximumPoolSize} are less
144     *             than or equal to zero, or if {@code idleTimeout} is negative,
145     *             or if {@code corePoolSize} is greater than
146     *             {@code maximumPoolSize}, or if {@code idleTimeout} is
147     *             non-zero and {@code unit} is {@code null}.
148     * @throws NullPointerException
149     *             If {@code factory} was {@code null}.
150     */
151    public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory,
152            final int corePoolSize, final int maximumPoolSize, final long idleTimeout,
153            final TimeUnit unit) {
154        return new CachedConnectionPool(factory, corePoolSize, maximumPoolSize, idleTimeout, unit,
155                null);
156    }
157
158    /**
159     * Creates a new connection pool which creates new connections as needed
160     * using the provided connection factory, but will reuse previously
161     * allocated connections when they are available.
162     * <p>
163     * Attempts to use more than {@code maximumPoolSize} connections at once
164     * will block until a connection is released back to the pool. In other
165     * words, this pool will prevent applications from using more than
166     * {@code maximumPoolSize} connections at the same time.
167     * <p>
168     * Connections which have not been used for the provided {@code idleTimeout}
169     * period are closed and removed from the pool, until there are only
170     * {@code corePoolSize} connections remaining.
171     * <p>
172     * Connections obtained from the connection pool are guaranteed to be valid
173     * immediately before being returned to the calling application. More
174     * specifically, connections which have remained idle in the connection pool
175     * for a long time and which have been remotely closed due to a time out
176     * will never be returned. However, once a pooled connection has been
177     * obtained it is the responsibility of the calling application to handle
178     * subsequent connection failures, these being signaled via a
179     * {@link ConnectionException}.
180     *
181     * @param factory
182     *            The connection factory to use for creating new connections.
183     * @param corePoolSize
184     *            The minimum number of connections to keep in the pool, even if
185     *            they are idle.
186     * @param maximumPoolSize
187     *            The maximum number of connections to allow in the pool.
188     * @param idleTimeout
189     *            The time out period, after which unused non-core connections
190     *            will be closed.
191     * @param unit
192     *            The time unit for the {@code keepAliveTime} argument.
193     * @param scheduler
194     *            The scheduler which should be used for periodically checking
195     *            for idle connections, or {@code null} if the default scheduler
196     *            should be used.
197     * @return The new connection pool.
198     * @throws IllegalArgumentException
199     *             If {@code corePoolSize}, {@code maximumPoolSize} are less
200     *             than or equal to zero, or if {@code idleTimeout} is negative,
201     *             or if {@code corePoolSize} is greater than
202     *             {@code maximumPoolSize}, or if {@code idleTimeout} is
203     *             non-zero and {@code unit} is {@code null}.
204     * @throws NullPointerException
205     *             If {@code factory} was {@code null}.
206     */
207    public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory,
208            final int corePoolSize, final int maximumPoolSize, final long idleTimeout,
209            final TimeUnit unit, final ScheduledExecutorService scheduler) {
210        return new CachedConnectionPool(factory, corePoolSize, maximumPoolSize, idleTimeout, unit,
211                scheduler);
212    }
213
214    /**
215     * Creates a new connection pool which will maintain {@code poolSize}
216     * connections created using the provided connection factory.
217     * <p>
218     * Attempts to use more than {@code poolSize} connections at once will block
219     * until a connection is released back to the pool. In other words, this
220     * pool will prevent applications from using more than {@code poolSize}
221     * connections at the same time.
222     * <p>
223     * Connections obtained from the connection pool are guaranteed to be valid
224     * immediately before being returned to the calling application. More
225     * specifically, connections which have remained idle in the connection pool
226     * for a long time and which have been remotely closed due to a time out
227     * will never be returned. However, once a pooled connection has been
228     * obtained it is the responsibility of the calling application to handle
229     * subsequent connection failures, these being signaled via a
230     * {@link ConnectionException}.
231     *
232     * @param factory
233     *            The connection factory to use for creating new connections.
234     * @param poolSize
235     *            The maximum size of the connection pool.
236     * @return The new connection pool.
237     * @throws IllegalArgumentException
238     *             If {@code poolSize} is negative.
239     * @throws NullPointerException
240     *             If {@code factory} was {@code null}.
241     */
242    public static ConnectionPool newFixedConnectionPool(final ConnectionFactory factory,
243            final int poolSize) {
244        return new CachedConnectionPool(factory, poolSize, poolSize, 0L, null, null);
245    }
246
247    /**
248     * Creates a new internal client connection which will route requests to the
249     * provided {@code RequestHandler}.
250     * <p>
251     * When processing requests, {@code RequestHandler} implementations are
252     * passed a {@code RequestContext} having a pseudo {@code requestID} which
253     * is incremented for each successive internal request on a per client
254     * connection basis. The request ID may be useful for logging purposes.
255     * <p>
256     * An internal connection does not require {@code RequestHandler}
257     * implementations to return a result when processing requests. However, it
258     * is recommended that implementations do always return results even for
259     * abandoned requests. This is because application client threads may block
260     * indefinitely waiting for results.
261     *
262     * @param requestHandler
263     *            The request handler which will be used for all client
264     *            connections.
265     * @return The new internal connection.
266     * @throws NullPointerException
267     *             If {@code requestHandler} was {@code null}.
268     */
269    public static Connection newInternalConnection(
270            final RequestHandler<RequestContext> requestHandler) {
271        Reject.ifNull(requestHandler);
272        return newInternalConnection(adaptRequestHandler(requestHandler));
273    }
274
275    /**
276     * Creates a new internal client connection which will route requests to the
277     * provided {@code ServerConnection}.
278     * <p>
279     * When processing requests, {@code ServerConnection} implementations are
280     * passed an integer as the first parameter. This integer represents a
281     * pseudo {@code requestID} which is incremented for each successive
282     * internal request on a per client connection basis. The request ID may be
283     * useful for logging purposes.
284     * <p>
285     * An internal connection does not require {@code ServerConnection}
286     * implementations to return a result when processing requests. However, it
287     * is recommended that implementations do always return results even for
288     * abandoned requests. This is because application client threads may block
289     * indefinitely waiting for results.
290     *
291     * @param serverConnection
292     *            The server connection.
293     * @return The new internal connection.
294     * @throws NullPointerException
295     *             If {@code serverConnection} was {@code null}.
296     */
297    public static Connection newInternalConnection(final ServerConnection<Integer> serverConnection) {
298        Reject.ifNull(serverConnection);
299        return new InternalConnection(serverConnection);
300    }
301
302    /**
303     * Creates a new connection factory which binds internal client connections
304     * to the provided {@link RequestHandler}s.
305     * <p>
306     * When processing requests, {@code RequestHandler} implementations are
307     * passed an integer as the first parameter. This integer represents a
308     * pseudo {@code requestID} which is incremented for each successive
309     * internal request on a per client connection basis. The request ID may be
310     * useful for logging purposes.
311     * <p>
312     * An internal connection factory does not require {@code RequestHandler}
313     * implementations to return a result when processing requests. However, it
314     * is recommended that implementations do always return results even for
315     * abandoned requests. This is because application client threads may block
316     * indefinitely waiting for results.
317     *
318     * @param requestHandler
319     *            The request handler which will be used for all client
320     *            connections.
321     * @return The new internal connection factory.
322     * @throws NullPointerException
323     *             If {@code requestHandler} was {@code null}.
324     */
325    public static ConnectionFactory newInternalConnectionFactory(
326            final RequestHandler<RequestContext> requestHandler) {
327        Reject.ifNull(requestHandler);
328        return new InternalConnectionFactory<>(
329            Connections.<Void> newServerConnectionFactory(requestHandler), null);
330    }
331
332    /**
333     * Creates a new connection factory which binds internal client connections
334     * to {@link RequestHandler}s created using the provided
335     * {@link RequestHandlerFactory}.
336     * <p>
337     * When processing requests, {@code RequestHandler} implementations are
338     * passed an integer as the first parameter. This integer represents a
339     * pseudo {@code requestID} which is incremented for each successive
340     * internal request on a per client connection basis. The request ID may be
341     * useful for logging purposes.
342     * <p>
343     * An internal connection factory does not require {@code RequestHandler}
344     * implementations to return a result when processing requests. However, it
345     * is recommended that implementations do always return results even for
346     * abandoned requests. This is because application client threads may block
347     * indefinitely waiting for results.
348     *
349     * @param <C>
350     *            The type of client context.
351     * @param factory
352     *            The request handler factory to use for creating connections.
353     * @param clientContext
354     *            The client context.
355     * @return The new internal connection factory.
356     * @throws NullPointerException
357     *             If {@code factory} was {@code null}.
358     */
359    public static <C> ConnectionFactory newInternalConnectionFactory(
360            final RequestHandlerFactory<C, RequestContext> factory, final C clientContext) {
361        Reject.ifNull(factory);
362        return new InternalConnectionFactory<>(newServerConnectionFactory(factory), clientContext);
363    }
364
365    /**
366     * Creates a new connection factory which binds internal client connections
367     * to {@link ServerConnection}s created using the provided
368     * {@link ServerConnectionFactory}.
369     * <p>
370     * When processing requests, {@code ServerConnection} implementations are
371     * passed an integer as the first parameter. This integer represents a
372     * pseudo {@code requestID} which is incremented for each successive
373     * internal request on a per client connection basis. The request ID may be
374     * useful for logging purposes.
375     * <p>
376     * An internal connection factory does not require {@code ServerConnection}
377     * implementations to return a result when processing requests. However, it
378     * is recommended that implementations do always return results even for
379     * abandoned requests. This is because application client threads may block
380     * indefinitely waiting for results.
381     *
382     * @param <C>
383     *            The type of client context.
384     * @param factory
385     *            The server connection factory to use for creating connections.
386     * @param clientContext
387     *            The client context.
388     * @return The new internal connection factory.
389     * @throws NullPointerException
390     *             If {@code factory} was {@code null}.
391     */
392    public static <C> ConnectionFactory newInternalConnectionFactory(
393            final ServerConnectionFactory<C, Integer> factory, final C clientContext) {
394        Reject.ifNull(factory);
395        return new InternalConnectionFactory<>(factory, clientContext);
396    }
397
398    /**
399     * Creates a new "round-robin" load-balancer which will load-balance connections across the provided set of
400     * connection factories. A round robin load balancing algorithm distributes connection requests across a list of
401     * connection factories one at a time. When the end of the list is reached, the algorithm starts again from the
402     * beginning.
403     * <p/>
404     * This algorithm is typically used for load-balancing <i>within</i> data centers, where load must be distributed
405     * equally across multiple data sources. This algorithm contrasts with the
406     * {@link #newFailoverLoadBalancer(Collection, Options)} which is used for load-balancing <i>between</i> data
407     * centers.
408     * <p/>
409     * If a problem occurs that temporarily prevents connections from being obtained for one of the connection
410     * factories, then this algorithm automatically "fails over" to the next operational connection factory in the list.
411     * If none of the connection factories are operational then a {@code ConnectionException} is returned to the
412     * client.
413     * <p/>
414     * The implementation periodically attempts to connect to failed connection factories in order to determine if they
415     * have become available again.
416     *
417     * @param factories
418     *         The connection factories.
419     * @param options
420     *         This configuration options for the load-balancer.
421     * @return The new round-robin load balancer.
422     * @see #newShardedRequestLoadBalancer(Collection, Options)
423     * @see #newFailoverLoadBalancer(Collection, Options)
424     * @see #LOAD_BALANCER_EVENT_LISTENER
425     * @see #LOAD_BALANCER_MONITORING_INTERVAL
426     * @see #LOAD_BALANCER_SCHEDULER
427     */
428    public static ConnectionFactory newRoundRobinLoadBalancer(
429            final Collection<? extends ConnectionFactory> factories, final Options options) {
430        return new ConnectionLoadBalancer("RoundRobinLoadBalancer", factories, options) {
431            private final int maxIndex = factories.size();
432            private final AtomicInteger nextIndex = new AtomicInteger(-1);
433
434            @Override
435            int getInitialConnectionFactoryIndex() {
436                // A round robin pool of one connection factories is unlikely in
437                // practice and requires special treatment.
438                if (maxIndex == 1) {
439                    return 0;
440                }
441
442                // Determine the next factory to use: avoid blocking algorithm.
443                int oldNextIndex;
444                int newNextIndex;
445                do {
446                    oldNextIndex = nextIndex.get();
447                    newNextIndex = oldNextIndex + 1;
448                    if (newNextIndex == maxIndex) {
449                        newNextIndex = 0;
450                    }
451                } while (!nextIndex.compareAndSet(oldNextIndex, newNextIndex));
452
453                // There's a potential, but benign, race condition here: other threads
454                // could jump in and rotate through the list before we return the
455                // connection factory.
456                return newNextIndex;
457            }
458        };
459    }
460
461    /**
462     * Creates a new "fail-over" load-balancer which will load-balance connections across the provided set of connection
463     * factories. A fail-over load balancing algorithm provides fault tolerance across multiple underlying connection
464     * factories.
465     * <p/>
466     * This algorithm is typically used for load-balancing <i>between</i> data centers, where there is preference to
467     * always forward connection requests to the <i>closest available</i> data center. This algorithm contrasts with the
468     * {@link #newRoundRobinLoadBalancer(Collection, Options)} which is used for load-balancing <i>within</i> a data
469     * center.
470     * <p/>
471     * This algorithm selects connection factories based on the order in which they were provided during construction.
472     * More specifically, an attempt to obtain a connection factory will always return the <i>first operational</i>
473     * connection factory in the list. Applications should, therefore, organize the connection factories such that the
474     * <i>preferred</i> (usually the closest) connection factories appear before those which are less preferred.
475     * <p/>
476     * If a problem occurs that temporarily prevents connections from being obtained for one of the connection
477     * factories, then this algorithm automatically "fails over" to the next operational connection factory in the list.
478     * If none of the connection factories are operational then a {@code ConnectionException} is returned to the
479     * client.
480     * <p/>
481     * The implementation periodically attempts to connect to failed connection factories in order to determine if they
482     * have become available again.
483     *
484     * @param factories
485     *         The connection factories.
486     * @param options
487     *         This configuration options for the load-balancer.
488     * @return The new fail-over load balancer.
489     * @see #newRoundRobinLoadBalancer(Collection, Options)
490     * @see #newShardedRequestLoadBalancer(Collection, Options)
491     * @see #LOAD_BALANCER_EVENT_LISTENER
492     * @see #LOAD_BALANCER_MONITORING_INTERVAL
493     * @see #LOAD_BALANCER_SCHEDULER
494     */
495    public static ConnectionFactory newFailoverLoadBalancer(
496            final Collection<? extends ConnectionFactory> factories, final Options options) {
497        return new ConnectionLoadBalancer("FailoverLoadBalancer", factories, options) {
498            @Override
499            int getInitialConnectionFactoryIndex() {
500                // Always start with the first connection factory.
501                return 0;
502            }
503        };
504    }
505
506    /**
507     * Creates a new "sharded" load-balancer which will load-balance individual requests across the provided set of
508     * connection factories, each typically representing a single replica, using an algorithm that ensures that requests
509     * targeting a given DN will always be routed to the same replica. In other words, this load-balancer increases
510     * consistency whilst maintaining read-scalability by simulating a "single master" replication topology, where each
511     * replica is responsible for a subset of the entries. When a replica is unavailable the load-balancer "fails over"
512     * by performing a linear probe in order to find the next available replica thus ensuring high-availability when a
513     * network partition occurs while sacrificing consistency, since the unavailable replica may still be visible to
514     * other clients.
515     * <p/>
516     * This load-balancer distributes requests based on the hash of their target DN and handles all core operations, as
517     * well as any password modify extended requests and SASL bind requests which use authentication IDs having the
518     * "dn:" form. Note that subtree operations (searches, subtree deletes, and modify DN) are likely to include entries
519     * which are "mastered" on different replicas, so client applications should be more tolerant of inconsistencies.
520     * Requests that are either unrecognized or that do not have a parameter that may be considered to be a target DN
521     * will be routed randomly.
522     * <p/>
523     * <b>NOTE:</b> this connection factory returns fake connections, since real connections are obtained for each
524     * request. Therefore, the returned fake connections have certain limitations: abandon requests will be ignored
525     * since they cannot be routed; connection event listeners can be registered, but will only be notified when the
526     * fake connection is closed or when all of the connection factories are unavailable.
527     * <p/>
528     * <b>NOTE:</b> in deployments where there are multiple client applications, care should be taken to ensure that
529     * the factories are configured using the same ordering, otherwise requests will not be routed consistently
530     * across the client applications.
531     * <p/>
532     * The implementation periodically attempts to connect to failed connection factories in order to determine if they
533     * have become available again.
534     *
535     * @param factories
536     *         The connection factories.
537     * @param options
538     *         This configuration options for the load-balancer.
539     * @return The new affinity load balancer.
540     * @see #newRoundRobinLoadBalancer(Collection, Options)
541     * @see #newFailoverLoadBalancer(Collection, Options)
542     * @see #LOAD_BALANCER_EVENT_LISTENER
543     * @see #LOAD_BALANCER_MONITORING_INTERVAL
544     * @see #LOAD_BALANCER_SCHEDULER
545     */
546    public static ConnectionFactory newShardedRequestLoadBalancer(
547            final Collection<? extends ConnectionFactory> factories, final Options options) {
548        return new RequestLoadBalancer("ShardedRequestLoadBalancer",
549                                       factories,
550                                       options,
551                                       newShardedRequestLoadBalancerFunction(factories));
552    }
553
554    // Package private for testing.
555    static Function<Request, Integer, NeverThrowsException> newShardedRequestLoadBalancerFunction(
556            final Collection<? extends ConnectionFactory> factories) {
557        return new Function<Request, Integer, NeverThrowsException>() {
558            private final int maxIndex = factories.size();
559
560            @Override
561            public Integer apply(final Request request) {
562                // Normalize the hash to a valid factory index, taking care of negative hash values and especially
563                // Integer.MIN_VALUE (see doc for Math.abs()).
564                final int index = computeIndexBasedOnDnHashCode(request);
565                return index == Integer.MIN_VALUE ? 0 : (Math.abs(index) % maxIndex);
566            }
567
568            private int computeIndexBasedOnDnHashCode(final Request request) {
569                // The following conditions are ordered such that the most common operations appear first in order to
570                // reduce the average number of branches. A better solution would be to use a visitor, but a visitor
571                // would only apply to the core operations, not extended operations or SASL binds.
572                if (request instanceof SearchRequest) {
573                    return ((SearchRequest) request).getName().hashCode();
574                } else if (request instanceof ModifyRequest) {
575                    return ((ModifyRequest) request).getName().hashCode();
576                } else if (request instanceof SimpleBindRequest) {
577                    return hashCodeOfDnString(((SimpleBindRequest) request).getName());
578                } else if (request instanceof AddRequest) {
579                    return ((AddRequest) request).getName().hashCode();
580                } else if (request instanceof DeleteRequest) {
581                    return ((DeleteRequest) request).getName().hashCode();
582                } else if (request instanceof CompareRequest) {
583                    return ((CompareRequest) request).getName().hashCode();
584                } else if (request instanceof ModifyDNRequest) {
585                    return ((ModifyDNRequest) request).getName().hashCode();
586                } else if (request instanceof PasswordModifyExtendedRequest) {
587                    return hashCodeOfAuthzid(((PasswordModifyExtendedRequest) request).getUserIdentityAsString());
588                } else if (request instanceof PlainSASLBindRequest) {
589                    return hashCodeOfAuthzid(((PlainSASLBindRequest) request).getAuthenticationID());
590                } else if (request instanceof DigestMD5SASLBindRequest) {
591                    return hashCodeOfAuthzid(((DigestMD5SASLBindRequest) request).getAuthenticationID());
592                } else if (request instanceof GSSAPISASLBindRequest) {
593                    return hashCodeOfAuthzid(((GSSAPISASLBindRequest) request).getAuthenticationID());
594                } else if (request instanceof CRAMMD5SASLBindRequest) {
595                    return hashCodeOfAuthzid(((CRAMMD5SASLBindRequest) request).getAuthenticationID());
596                } else {
597                    return distributeRequestAtRandom();
598                }
599            }
600
601            private int hashCodeOfAuthzid(final String authzid) {
602                if (authzid != null && authzid.startsWith("dn:")) {
603                    return hashCodeOfDnString(authzid.substring(3));
604                }
605                return distributeRequestAtRandom();
606            }
607
608            private int hashCodeOfDnString(final String dnString) {
609                try {
610                    return DN.valueOf(dnString).hashCode();
611                } catch (final IllegalArgumentException ignored) {
612                    return distributeRequestAtRandom();
613                }
614            }
615
616            private int distributeRequestAtRandom() {
617                return ThreadLocalRandom.current().nextInt(0, maxIndex);
618            }
619        };
620    }
621
622    /**
623     * Creates a new connection factory which forwards connection requests to
624     * the provided factory, but whose {@code toString} method will always
625     * return {@code name}.
626     * <p>
627     * This method may be useful for debugging purposes in order to more easily
628     * identity connection factories.
629     *
630     * @param factory
631     *            The connection factory to be named.
632     * @param name
633     *            The name of the connection factory.
634     * @return The named connection factory.
635     * @throws NullPointerException
636     *             If {@code factory} or {@code name} was {@code null}.
637     */
638    public static ConnectionFactory newNamedConnectionFactory(final ConnectionFactory factory,
639            final String name) {
640        Reject.ifNull(factory, name);
641
642        return new ConnectionFactory() {
643
644            @Override
645            public void close() {
646                factory.close();
647            }
648
649            @Override
650            public Connection getConnection() throws LdapException {
651                return factory.getConnection();
652            }
653
654            @Override
655            public Promise<Connection, LdapException> getConnectionAsync() {
656                return factory.getConnectionAsync();
657            }
658
659            @Override
660            public String toString() {
661                return name;
662            }
663
664        };
665    }
666
667    /**
668     * Creates a new server connection factory using the provided
669     * {@link RequestHandler}. The returned factory will manage connection and
670     * request life-cycle, including request cancellation.
671     * <p>
672     * When processing requests, {@link RequestHandler} implementations are
673     * passed a {@link RequestContext} as the first parameter which may be used
674     * for detecting whether the request should be aborted due to
675     * cancellation requests or other events, such as connection failure.
676     * <p>
677     * The returned factory maintains state information which includes a table
678     * of active requests. Therefore, {@code RequestHandler} implementations are
679     * required to always return results in order to avoid potential memory
680     * leaks.
681     *
682     * @param <C>
683     *            The type of client context.
684     * @param requestHandler
685     *            The request handler which will be used for all client
686     *            connections.
687     * @return The new server connection factory.
688     * @throws NullPointerException
689     *             If {@code requestHandler} was {@code null}.
690     */
691    public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory(
692            final RequestHandler<RequestContext> requestHandler) {
693        Reject.ifNull(requestHandler);
694        return new RequestHandlerFactoryAdapter<>(new RequestHandlerFactory<C, RequestContext>() {
695            @Override
696            public RequestHandler<RequestContext> handleAccept(final C clientContext) {
697                return requestHandler;
698            }
699        });
700    }
701
702    /**
703     * Creates a new server connection factory using the provided
704     * {@link RequestHandlerFactory}. The returned factory will manage
705     * connection and request life-cycle, including request cancellation.
706     * <p>
707     * When processing requests, {@link RequestHandler} implementations are
708     * passed a {@link RequestContext} as the first parameter which may be used
709     * for detecting whether the request should be aborted due to
710     * cancellation requests or other events, such as connection failure.
711     * <p>
712     * The returned factory maintains state information which includes a table
713     * of active requests. Therefore, {@code RequestHandler} implementations are
714     * required to always return results in order to avoid potential memory
715     * leaks.
716     *
717     * @param <C>
718     *            The type of client context.
719     * @param factory
720     *            The request handler factory to use for associating request
721     *            handlers with client connections.
722     * @return The new server connection factory.
723     * @throws NullPointerException
724     *             If {@code factory} was {@code null}.
725     */
726    public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory(
727            final RequestHandlerFactory<C, RequestContext> factory) {
728        Reject.ifNull(factory);
729        return new RequestHandlerFactoryAdapter<>(factory);
730    }
731
732    /**
733     * Returns an uncloseable view of the provided connection. Attempts to call
734     * {@link Connection#close()} or
735     * {@link Connection#close(org.forgerock.opendj.ldap.requests.UnbindRequest, String)}
736     * will be ignored.
737     *
738     * @param connection
739     *            The connection whose {@code close} methods are to be disabled.
740     * @return An uncloseable view of the provided connection.
741     */
742    public static Connection uncloseable(Connection connection) {
743        return new AbstractConnectionWrapper<Connection>(connection) {
744            @Override
745            public void close() {
746                // Do nothing.
747            }
748
749            @Override
750            public void close(org.forgerock.opendj.ldap.requests.UnbindRequest request,
751                    String reason) {
752                // Do nothing.
753            }
754        };
755    }
756
757    /**
758     * Returns an uncloseable view of the provided connection factory. Attempts
759     * to call {@link ConnectionFactory#close()} will be ignored.
760     *
761     * @param factory
762     *            The connection factory whose {@code close} method is to be
763     *            disabled.
764     * @return An uncloseable view of the provided connection factory.
765     */
766    public static ConnectionFactory uncloseable(final ConnectionFactory factory) {
767        return new ConnectionFactory() {
768
769            @Override
770            public Promise<Connection, LdapException> getConnectionAsync() {
771                return factory.getConnectionAsync();
772            }
773
774            @Override
775            public Connection getConnection() throws LdapException {
776                return factory.getConnection();
777            }
778
779            @Override
780            public void close() {
781                // Do nothing.
782            }
783        };
784    }
785
786    /**
787     * Returns the host name associated with the provided
788     * {@code InetSocketAddress}, without performing a DNS lookup. This method
789     * attempts to provide functionality which is compatible with
790     * {@code InetSocketAddress.getHostString()} in JDK7. It can be removed once
791     * we drop support for JDK6.
792     *
793     * @param socketAddress
794     *            The socket address which is expected to be an instance of
795     *            {@code InetSocketAddress}.
796     * @return The host name associated with the provided {@code SocketAddress},
797     *         or {@code null} if it is unknown.
798     */
799    public static String getHostString(final InetSocketAddress socketAddress) {
800        /*
801         * See OPENDJ-1270 for more information about slow DNS queries.
802         *
803         * We must avoid calling getHostName() in the case where it is likely to
804         * perform a blocking DNS query. Ideally we would call getHostString(),
805         * but the method was only added in JDK7.
806         */
807        if (socketAddress.isUnresolved()) {
808            /*
809             * Usually socket addresses are resolved on creation. If the address
810             * is unresolved then there must be a user provided hostname instead
811             * and getHostName will not perform a reverse lookup.
812             */
813            return socketAddress.getHostName();
814        } else {
815            /*
816             * Simulate getHostString() by parsing the toString()
817             * representation. This assumes that the toString() representation
818             * is stable, which I assume it is because it is documented.
819             */
820            final InetAddress address = socketAddress.getAddress();
821            final String hostSlashIp = address.toString();
822            final int slashPos = hostSlashIp.indexOf('/');
823            if (slashPos == 0) {
824                return hostSlashIp.substring(1);
825            } else {
826                return hostSlashIp.substring(0, slashPos);
827            }
828        }
829    }
830
831    /** Prevent instantiation. */
832    private Connections() {
833        // Do nothing.
834    }
835}