/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.provider; import org.ldaptive.ConnectionFactoryMetadata; import org.ldaptive.ConnectionStrategy; import org.ldaptive.LdapException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Provides a basic implementation for other connection factories to inherit. * * @param <T> type of provider config for this connection factory * * @author Middleware Services */ public abstract class AbstractProviderConnectionFactory<T extends ProviderConfig> implements ProviderConnectionFactory<T> { /** Logger for this class. */ protected final Logger logger = LoggerFactory.getLogger(getClass()); /** Provider configuration. */ private final T providerConfig; /** Factory metadata. */ private final DefaultConnectionFactoryMetadata metadata; /** Connection strategy. */ private final ConnectionStrategy connectionStrategy; /** * Creates a new abstract connection factory. Once invoked the supplied provider config is made immutable. See {@link * ProviderConfig#makeImmutable()}. * * @param url of the ldap to connect to * @param strategy connection strategy * @param config provider configuration */ public AbstractProviderConnectionFactory(final String url, final ConnectionStrategy strategy, final T config) { metadata = new DefaultConnectionFactoryMetadata(url); connectionStrategy = strategy; providerConfig = config; providerConfig.makeImmutable(); } @Override public T getProviderConfig() { return providerConfig; } /** * Returns the connection factory metadata. * * @return metadata */ protected ConnectionFactoryMetadata getMetadata() { return metadata; } @Override public ProviderConnection create() throws LdapException { LdapException lastThrown = null; final String[] urls = connectionStrategy.getLdapUrls(metadata); if (urls == null || urls.length == 0) { throw new ConnectionException( "Connection strategy " + connectionStrategy + " did not produce any LDAP URLs for " + metadata); } ProviderConnection conn = null; for (String url : urls) { try { logger.trace("[{}] Attempting connection to {} for strategy {}", metadata, url, connectionStrategy); conn = createInternal(url); metadata.incrementCount(); lastThrown = null; break; } catch (ConnectionException e) { lastThrown = e; logger.debug("Error connecting to LDAP URL: {}", url, e); } } if (lastThrown != null) { throw lastThrown; } return conn; } /** * Create the provider connection and prepare the connection for use. * * @param url to connect to * * @return provider connection * * @throws LdapException if a connection cannot be established */ protected abstract ProviderConnection createInternal(final String url) throws LdapException; @Override public String toString() { return String.format( "[%s@%d::metadata=%s, providerConfig=%s]", getClass().getName(), hashCode(), metadata, providerConfig); } /** Provides an object to track the connection count. */ private class DefaultConnectionFactoryMetadata implements ConnectionFactoryMetadata { /** ldap url. */ private final String ldapUrl; /** connection count. */ private int count; /** * Creates a new default connection factory metadata. * * @param s ldap url */ DefaultConnectionFactoryMetadata(final String s) { ldapUrl = s; } @Override public String getLdapUrl() { return ldapUrl; } @Override public int getConnectionCount() { return count; } /** Increments the connection count. */ private void incrementCount() { count++; // reset the count if it exceeds the size of an integer if (count < 0) { count = 0; } } @Override public String toString() { return String.format("[ldapUrl=%s, count=%s]", ldapUrl, count); } } }