001/*
002 * Copyright 2012-2017 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.data.cassandra;
018
019import java.util.Collections;
020import java.util.List;
021
022import com.datastax.driver.core.Cluster;
023import com.datastax.driver.core.Session;
024
025import org.springframework.beans.factory.BeanFactory;
026import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
027import org.springframework.boot.autoconfigure.AutoConfigureAfter;
028import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
029import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
030import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
031import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
032import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
033import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
034import org.springframework.boot.context.properties.EnableConfigurationProperties;
035import org.springframework.boot.context.properties.PropertyMapper;
036import org.springframework.boot.context.properties.bind.Binder;
037import org.springframework.context.annotation.Bean;
038import org.springframework.context.annotation.Configuration;
039import org.springframework.core.env.Environment;
040import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
041import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
042import org.springframework.data.cassandra.config.SchemaAction;
043import org.springframework.data.cassandra.core.CassandraAdminOperations;
044import org.springframework.data.cassandra.core.CassandraTemplate;
045import org.springframework.data.cassandra.core.convert.CassandraConverter;
046import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
047import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
048import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
049import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
050
051/**
052 * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra support.
053 *
054 * @author Julien Dubois
055 * @author EddĂș MelĂ©ndez
056 * @author Mark Paluch
057 * @author Madhura Bhave
058 * @since 1.3.0
059 */
060@Configuration
061@ConditionalOnClass({ Cluster.class, CassandraAdminOperations.class })
062@EnableConfigurationProperties(CassandraProperties.class)
063@AutoConfigureAfter(CassandraAutoConfiguration.class)
064public class CassandraDataAutoConfiguration {
065
066        private final BeanFactory beanFactory;
067
068        private final CassandraProperties properties;
069
070        private final Cluster cluster;
071
072        private final Environment environment;
073
074        public CassandraDataAutoConfiguration(BeanFactory beanFactory,
075                        CassandraProperties properties, Cluster cluster, Environment environment) {
076                this.beanFactory = beanFactory;
077                this.properties = properties;
078                this.cluster = cluster;
079                this.environment = environment;
080        }
081
082        @Bean
083        @ConditionalOnMissingBean
084        public CassandraMappingContext cassandraMapping(
085                        CassandraCustomConversions conversions) throws ClassNotFoundException {
086                CassandraMappingContext context = new CassandraMappingContext();
087                List<String> packages = EntityScanPackages.get(this.beanFactory)
088                                .getPackageNames();
089                if (packages.isEmpty() && AutoConfigurationPackages.has(this.beanFactory)) {
090                        packages = AutoConfigurationPackages.get(this.beanFactory);
091                }
092                if (!packages.isEmpty()) {
093                        context.setInitialEntitySet(CassandraEntityClassScanner.scan(packages));
094                }
095                PropertyMapper.get().from(this.properties::getKeyspaceName).whenHasText()
096                                .as(this::createSimpleUserTypeResolver).to(context::setUserTypeResolver);
097                context.setCustomConversions(conversions);
098                return context;
099        }
100
101        private SimpleUserTypeResolver createSimpleUserTypeResolver(String keyspaceName) {
102                return new SimpleUserTypeResolver(this.cluster, keyspaceName);
103        }
104
105        @Bean
106        @ConditionalOnMissingBean
107        public CassandraConverter cassandraConverter(CassandraMappingContext mapping,
108                        CassandraCustomConversions conversions) {
109                MappingCassandraConverter converter = new MappingCassandraConverter(mapping);
110                converter.setCustomConversions(conversions);
111                return converter;
112        }
113
114        @Bean
115        @ConditionalOnMissingBean(Session.class)
116        public CassandraSessionFactoryBean cassandraSession(CassandraConverter converter)
117                        throws Exception {
118                CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
119                session.setCluster(this.cluster);
120                session.setConverter(converter);
121                session.setKeyspaceName(this.properties.getKeyspaceName());
122                Binder binder = Binder.get(this.environment);
123                binder.bind("spring.data.cassandra.schema-action", SchemaAction.class)
124                                .ifBound(session::setSchemaAction);
125                return session;
126        }
127
128        @Bean
129        @ConditionalOnMissingBean
130        public CassandraTemplate cassandraTemplate(Session session,
131                        CassandraConverter converter) throws Exception {
132                return new CassandraTemplate(session, converter);
133        }
134
135        @Bean
136        @ConditionalOnMissingBean
137        public CassandraCustomConversions cassandraCustomConversions() {
138                return new CassandraCustomConversions(Collections.emptyList());
139        }
140
141}