/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Connection strategy that attempts each URL in the order they are configured. The next attempt uses the next URL in * the list. The class orders the URLs by computing a modulus with the connection count. Since metadata is stored per * connection, computing the URL based on connection count may not give the desired result when using a connection pool. * Set {@link #useConnectionCount} to false if using this strategy with a connection pool. * * @author Middleware Services */ public class RoundRobinConnectionStrategy implements ConnectionStrategy { /** Internal method invocation counter. */ private int invocationCount; /** * Whether {@link #getLdapUrls(ConnectionFactoryMetadata)} should use the connectionCount parameter or the {@link * #invocationCount}. */ private final boolean useConnectionCount; /** Creates a new round robin connection strategy. */ public RoundRobinConnectionStrategy() { this(true); } /** * Creates a new round robin connection strategy. * * @param b whether {@link #getLdapUrls(ConnectionFactoryMetadata)} should use the connectionCount parameter */ public RoundRobinConnectionStrategy(final boolean b) { useConnectionCount = b; } /** * Return a list of URLs that cycles the list order. The first entry is moved to the end of the list for each * invocation. * * @param metadata which can be used to produce the URL list * * @return list of URLs to attempt connections to */ @Override public String[] getLdapUrls(final ConnectionFactoryMetadata metadata) { if (metadata == null || metadata.getLdapUrl() == null) { return null; } final List<String> l = new ArrayList<>(Arrays.asList(metadata.getLdapUrl().split(" "))); final int count = getCount(metadata.getConnectionCount()); for (int i = 0; i < count % l.size(); i++) { l.add(l.remove(0)); } return l.toArray(new String[l.size()]); } /** * Returns the supplied connection count if {@link #useConnectionCount} is true. Otherwise returns {@link * #invocationCount}. * * @param connectionCount as reported by the connection * * @return count used to reorder the URL list */ protected int getCount(final int connectionCount) { if (useConnectionCount) { return connectionCount; } return returnAndIncrementInvocationCount(); } /** * Increments the internal invocation count and returns the previous value. * * @return previous invocation count */ private int returnAndIncrementInvocationCount() { final int i = invocationCount; invocationCount++; // reset the count if it exceeds the size of an integer if (invocationCount < 0) { invocationCount = 0; } return i; } }