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}