All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zalando.boot.cassandra.autoconfig.CassandraAutoConfiguration Maven / Gradle / Ivy

There is a newer version: 2.2
Show newest version
package org.zalando.boot.cassandra.autoconfig;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.zalando.boot.cassandra.CassandraClusterFactoryBean;
import org.zalando.boot.cassandra.CassandraMappingManagerFactoryBean;
import org.zalando.boot.cassandra.CassandraSessionFactoryBean;
import org.zalando.boot.etcd.EtcdClient;
import org.zalando.boot.etcd.EtcdException;
import org.zalando.boot.etcd.EtcdNode;
import org.zalando.boot.etcd.EtcdResponse;

import com.datastax.driver.core.AuthProvider;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.SSLOptions;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.TimestampGenerator;
import com.datastax.driver.core.policies.AddressTranslator;
import com.datastax.driver.core.policies.LoadBalancingPolicy;
import com.datastax.driver.core.policies.ReconnectionPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.core.policies.SpeculativeExecutionPolicy;
import com.datastax.driver.mapping.MappingManager;

/**
 *
 */
@Configuration
@EnableConfigurationProperties(CassandraProperties.class)
@ConditionalOnMissingBean({ Cluster.class, Session.class })
@ConditionalOnProperty(prefix = "zalando.cassandra", name = "enabled", matchIfMissing = true)
public class CassandraAutoConfiguration {

	/**
	 * Resolves the contact points using the given etcd client and etcd key. The
	 * key is a directory node under which the seed nodes are listed.
	 * 
	 * @param etcdClient
	 *            the etcd client
	 * @param keyName
	 *            the name of the etcd directory node having the cassandra seeds
	 *            as child nodes
	 * @return the list of contact points
	 * @throws EtcdException
	 *             in case an error occured during communication with etcd
	 */
	private static List resolveContactPoints(EtcdClient etcdClient, String keyName) throws EtcdException {
		List contactPoints = new ArrayList<>();
		EtcdResponse response = etcdClient.get(keyName, true);
		for (EtcdNode node : response.getNode().getNodes()) {
			String addressString = node.getValue();
			contactPoints.add(addressString);
		}
		return contactPoints;
	}

	/**
	 * properties
	 */
	@Autowired
	private CassandraProperties properties;

	/**
	 * conversion service used to convert between 
	 */
	private ConversionService conversionService = new DefaultConversionService();

	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/**
	 * Creates a new factory bean for a cassandra cluster.
	 * 
	 * @return the cassandra cluster factory bean
	 * @throws Exception
	 *             in case cluster creation fails
	 */
	@Bean
	@ConditionalOnMissingBean(CassandraClusterFactoryBean.class)
	@ConditionalOnProperty(prefix = "zalando.cassandra", value = "contact-points", matchIfMissing = true)
	public CassandraClusterFactoryBean cassandraClusterFactoryBean() throws Exception {
		return createClusterFactoryBean(properties.getContactPoints());
	}

	@Bean
	@ConditionalOnMissingBean(CassandraClusterFactoryBean.class)
	@ConditionalOnProperty(prefix = "zalando.cassandra", value = "etcd-key-name")
	public CassandraClusterFactoryBean cassandraClusterFactoryBean(EtcdClient etcdClient) throws Exception {
		// resolve and set contact points
		String contactPoints = StringUtils
				.collectionToCommaDelimitedString(resolveContactPoints(etcdClient, properties.getEtcdKeyName()));
		properties.setContactPoints(contactPoints);

		return createClusterFactoryBean(contactPoints);
	}

	private CassandraClusterFactoryBean createClusterFactoryBean(String contactPoints) throws Exception {
		CassandraClusterFactoryBean bean = new CassandraClusterFactoryBean();

		bean.setClusterName(properties.getClusterName());
		bean.setContactPoints(contactPoints);
		bean.setPort(properties.getPort());
		bean.setProtocolVersion(properties.getProtocolVersion());
		bean.setCompression(properties.getCompression());

		// policies
		if (StringUtils.hasText(properties.getLoadBalancingPolicy())) {
			LoadBalancingPolicy policy = instantiate(LoadBalancingPolicy.class,
					StringUtils.commaDelimitedListToStringArray(properties.getLoadBalancingPolicy()));
			bean.setLoadBalancingPolicy(policy);
		}

		if (StringUtils.hasText(properties.getReconnectionPolicy())) {
			ReconnectionPolicy policy = instantiate(ReconnectionPolicy.class,
					StringUtils.commaDelimitedListToStringArray(properties.getReconnectionPolicy()));
			bean.setReconnectionPolicy(policy);
		}

		if (StringUtils.hasText(properties.getSpeculativeExecutionPolicy())) {
			SpeculativeExecutionPolicy policy = instantiate(SpeculativeExecutionPolicy.class,
					StringUtils.commaDelimitedListToStringArray(properties.getSpeculativeExecutionPolicy()));
			bean.setSpeculativeExecutionPolicy(policy);
		}

		if (StringUtils.hasText(properties.getRetryPolicy())) {
			RetryPolicy policy = instantiate(RetryPolicy.class,
					StringUtils.commaDelimitedListToStringArray(properties.getRetryPolicy()));
			bean.setRetryPolicy(policy);
		}

		if (StringUtils.hasText(properties.getAddressTranslator())) {
			AddressTranslator translator = instantiate(AddressTranslator.class,
					StringUtils.commaDelimitedListToStringArray(properties.getAddressTranslator()));
			bean.setAddressTranslator(translator);
		}

		// options
		if (properties.getQueryOptions() != null) {
			bean.setQueryOptions(properties.getQueryOptions());
		}
		if (properties.getPoolingOptions() != null) {
			bean.setPoolingOptions(properties.getPoolingOptions());
		}
		if (properties.getSocketOptions() != null) {
			bean.setSocketOptions(properties.getSocketOptions());
		}
		if (properties.getNettyOptions() != null) {
			bean.setNettyOptions(properties.getNettyOptions());
		}

		if (StringUtils.hasText(properties.getTimestampGenerator())) {
			TimestampGenerator generator = instantiate(TimestampGenerator.class,
					StringUtils.commaDelimitedListToStringArray(properties.getTimestampGenerator()));
			bean.setTimestampGenerator(generator);
		}

		if (StringUtils.hasText(properties.getAuthProvider())) {
			AuthProvider provider = instantiate(AuthProvider.class,
					StringUtils.commaDelimitedListToStringArray(properties.getAuthProvider()));
			bean.setAuthProvider(provider);
		}

		bean.setUsername(properties.getUsername());
		bean.setPassword(properties.getPassword());

		bean.setMetricsEnabled(properties.isMetricsEnabled());
		bean.setJmxEnabled(properties.isJmxEnabled());

		if (properties.isSslEnabled()) {
			bean.setSslEnabled(properties.isSslEnabled());

			if (StringUtils.hasText(properties.getSslOptions())) {
				SSLOptions options = instantiate(SSLOptions.class,
						StringUtils.commaDelimitedListToStringArray(properties.getSslOptions()));
				bean.setSslOptions(options);
			}
		}

		return bean;
	}

	@SuppressWarnings("unchecked")
	private  T instantiate(Class type, String[] nameAndParams) throws ReflectiveOperationException {
		Class clazz = beanClassLoader.loadClass(nameAndParams[0]);

		Field singleton = null;
		try {
			singleton = clazz.getField("INSTANCE");
		} catch (NoSuchFieldException e) {
			// can be ignored
		}
		if (singleton != null) {
			return (T) singleton.get(null);
		} else {

			// identify constructor and convert parameters
			Constructor constructor = null;
			int paramCount = nameAndParams.length - 1;
			Object[] paramValues = new Object[paramCount];

			for (Constructor c : clazz.getConstructors()) {
				if (c.getParameterCount() == paramCount) {
					constructor = c;
					Parameter[] params = c.getParameters();
					for (int i = 0; i < paramCount; i++) {
						Parameter param = params[i];
						paramValues[i] = conversionService.convert(nameAndParams[i + 1], param.getType());
					}

					break;
				}
			}

			return (T) BeanUtils.instantiateClass(constructor, paramValues);
		}
	}

	/**
	 * Creates a new factory bean for a cassandra session.
	 * 
	 * @param cluster
	 *            the cluster to use
	 * @return cassandra the session factory bean
	 */
	@Bean
	@ConditionalOnMissingBean(CassandraSessionFactoryBean.class)
	public CassandraSessionFactoryBean cassandraSessionFactoryBean(Cluster cluster) {
		CassandraSessionFactoryBean bean = new CassandraSessionFactoryBean(cluster);

		if (StringUtils.hasText(properties.getKeyspace())) {
			bean.setKeyspace(properties.getKeyspace());
		}

		return bean;
	}

	/**
	 * Creates a new factory bean for a cassandra mapping manager.
	 * 
	 * @param session
	 *            the cassandra session
	 * @return the cassandra mapping manager
	 */
	@Bean
	@ConditionalOnMissingBean({ MappingManager.class, CassandraMappingManagerFactoryBean.class })
	public CassandraMappingManagerFactoryBean cassandraMappingManagerFactoryBean(Session session) {
		CassandraMappingManagerFactoryBean bean = new CassandraMappingManagerFactoryBean(session);
		return bean;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy