001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.cassandra;
018
019import java.time.Duration;
020
021import com.datastax.driver.core.Cluster;
022import com.datastax.driver.core.PoolingOptions;
023import com.datastax.driver.core.QueryOptions;
024import com.datastax.driver.core.SocketOptions;
025
026import org.springframework.beans.BeanUtils;
027import org.springframework.beans.factory.ObjectProvider;
028import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
029import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
030import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
031import org.springframework.boot.context.properties.EnableConfigurationProperties;
032import org.springframework.boot.context.properties.PropertyMapper;
033import org.springframework.context.annotation.Bean;
034import org.springframework.context.annotation.Configuration;
035import org.springframework.util.StringUtils;
036
037/**
038 * {@link EnableAutoConfiguration Auto-configuration} for Cassandra.
039 *
040 * @author Julien Dubois
041 * @author Phillip Webb
042 * @author Eddú Meléndez
043 * @author Stephane Nicoll
044 * @since 1.3.0
045 */
046@Configuration
047@ConditionalOnClass({ Cluster.class })
048@EnableConfigurationProperties(CassandraProperties.class)
049public class CassandraAutoConfiguration {
050
051        private final CassandraProperties properties;
052
053        private final ObjectProvider<ClusterBuilderCustomizer> builderCustomizers;
054
055        public CassandraAutoConfiguration(CassandraProperties properties,
056                        ObjectProvider<ClusterBuilderCustomizer> builderCustomizers) {
057                this.properties = properties;
058                this.builderCustomizers = builderCustomizers;
059        }
060
061        @Bean
062        @ConditionalOnMissingBean
063        @SuppressWarnings("deprecation")
064        public Cluster cassandraCluster() {
065                PropertyMapper map = PropertyMapper.get();
066                CassandraProperties properties = this.properties;
067                Cluster.Builder builder = Cluster.builder()
068                                .withClusterName(properties.getClusterName())
069                                .withPort(properties.getPort());
070                map.from(properties::getUsername).whenNonNull().to((username) -> builder
071                                .withCredentials(username, properties.getPassword()));
072                map.from(properties::getCompression).whenNonNull().to(builder::withCompression);
073                map.from(properties::getLoadBalancingPolicy).whenNonNull()
074                                .as(BeanUtils::instantiateClass).to(builder::withLoadBalancingPolicy);
075                map.from(this::getQueryOptions).to(builder::withQueryOptions);
076                map.from(properties::getReconnectionPolicy).whenNonNull()
077                                .as(BeanUtils::instantiateClass).to(builder::withReconnectionPolicy);
078                map.from(properties::getRetryPolicy).whenNonNull().as(BeanUtils::instantiateClass)
079                                .to(builder::withRetryPolicy);
080                map.from(this::getSocketOptions).to(builder::withSocketOptions);
081                map.from(properties::isSsl).whenTrue().toCall(builder::withSSL);
082                map.from(this::getPoolingOptions).to(builder::withPoolingOptions);
083                map.from(properties::getContactPoints).as(StringUtils::toStringArray)
084                                .to(builder::addContactPoints);
085                map.from(properties::isJmxEnabled).whenFalse()
086                                .toCall(builder::withoutJMXReporting);
087                customize(builder);
088                return builder.build();
089        }
090
091        private void customize(Cluster.Builder builder) {
092                this.builderCustomizers.orderedStream()
093                                .forEach((customizer) -> customizer.customize(builder));
094        }
095
096        private QueryOptions getQueryOptions() {
097                PropertyMapper map = PropertyMapper.get();
098                QueryOptions options = new QueryOptions();
099                CassandraProperties properties = this.properties;
100                map.from(properties::getConsistencyLevel).whenNonNull()
101                                .to(options::setConsistencyLevel);
102                map.from(properties::getSerialConsistencyLevel).whenNonNull()
103                                .to(options::setSerialConsistencyLevel);
104                map.from(properties::getFetchSize).to(options::setFetchSize);
105                return options;
106        }
107
108        private SocketOptions getSocketOptions() {
109                PropertyMapper map = PropertyMapper.get();
110                SocketOptions options = new SocketOptions();
111                map.from(this.properties::getConnectTimeout).whenNonNull()
112                                .asInt(Duration::toMillis).to(options::setConnectTimeoutMillis);
113                map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
114                                .to(options::setReadTimeoutMillis);
115                return options;
116        }
117
118        private PoolingOptions getPoolingOptions() {
119                PropertyMapper map = PropertyMapper.get();
120                CassandraProperties.Pool properties = this.properties.getPool();
121                PoolingOptions options = new PoolingOptions();
122                map.from(properties::getIdleTimeout).whenNonNull().asInt(Duration::getSeconds)
123                                .to(options::setIdleTimeoutSeconds);
124                map.from(properties::getPoolTimeout).whenNonNull().asInt(Duration::toMillis)
125                                .to(options::setPoolTimeoutMillis);
126                map.from(properties::getHeartbeatInterval).whenNonNull()
127                                .asInt(Duration::getSeconds).to(options::setHeartbeatIntervalSeconds);
128                map.from(properties::getMaxQueueSize).to(options::setMaxQueueSize);
129                return options;
130        }
131
132}