Complete revert of DATACOUCH-550.

The previous "Revert" only reverted CouchbaseTemplate resulting in compilation errors in master.

Closes #858
This commit is contained in:
mikereiche
2021-02-17 18:10:57 -08:00
committed by Michael Nitschinger
parent 8c6598271a
commit ed31a8dbaf
6 changed files with 111 additions and 75 deletions

View File

@@ -37,7 +37,6 @@ import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversion
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService; import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
import org.springframework.data.couchbase.core.convert.translation.TranslationService; import org.springframework.data.couchbase.core.convert.translation.TranslationService;
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.Document; import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping; import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
@@ -62,7 +61,6 @@ import com.couchbase.client.java.json.JacksonTransformers;
* @author Simon Baslé * @author Simon Baslé
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Subhashni Balakrishnan * @author Subhashni Balakrishnan
* @author Jorge Rodriguez Martin
*/ */
@Configuration @Configuration
public abstract class AbstractCouchbaseConfiguration { public abstract class AbstractCouchbaseConfiguration {
@@ -146,27 +144,15 @@ public abstract class AbstractCouchbaseConfiguration {
} }
@Bean(name = BeanNames.COUCHBASE_TEMPLATE) @Bean(name = BeanNames.COUCHBASE_TEMPLATE)
public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService couchbaseTranslationService) {
return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, couchbaseTranslationService);
}
public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory, public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter) { MappingCouchbaseConverter mappingCouchbaseConverter) {
return couchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, new JacksonTranslationService()); return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);
} }
@Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE) @Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)
public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService couchbaseTranslationService) {
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter,
couchbaseTranslationService);
}
public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory, public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter) { MappingCouchbaseConverter mappingCouchbaseConverter) {
return reactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);
new JacksonTranslationService());
} }
@Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING) @Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
@@ -282,6 +268,7 @@ public abstract class AbstractCouchbaseConfiguration {
mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
mappingContext.setAutoIndexCreation(autoIndexCreation());
return mappingContext; return mappingContext;
} }
@@ -293,18 +280,6 @@ public abstract class AbstractCouchbaseConfiguration {
return false; return false;
} }
/**
* Creates a {@link CouchbasePersistentEntityIndexCreator} bean that takes on the responsibility of automatically
* creating indices.
*
* Does nothing if {@link #autoIndexCreation()} returns false.
*/
@Bean
public CouchbasePersistentEntityIndexCreator couchbasePersistentEntityIndexCreator(CouchbaseMappingContext couchbaseMappingContext,
CouchbaseClientFactory clientFactory) {
return new CouchbasePersistentEntityIndexCreator(couchbaseMappingContext, clientFactory, typeKey(), autoIndexCreation());
}
/** /**
* Register custom Converters in a {@link CustomConversions} object if required. These {@link CustomConversions} will * Register custom Converters in a {@link CustomConversions} object if required. These {@link CustomConversions} will
* be registered with the {@link #mappingCouchbaseConverter(CouchbaseMappingContext, CouchbaseCustomConversions)} )} * be registered with the {@link #mappingCouchbaseConverter(CouchbaseMappingContext, CouchbaseCustomConversions)} )}

View File

@@ -38,7 +38,6 @@ import com.couchbase.client.java.Collection;
* *
* @author Michael Nitschinger * @author Michael Nitschinger
* @author Michael Reiche * @author Michael Reiche
* @author Aaron Whiteside
* @author Jorge Rodriguez Martin * @author Jorge Rodriguez Martin
* @since 3.0 * @since 3.0
*/ */
@@ -56,19 +55,19 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContex
} }
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter, public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter,
final TranslationService translationService) { final TranslationService translationService) {
this.clientFactory = clientFactory; this.clientFactory = clientFactory;
this.converter = converter; this.converter = converter;
this.templateSupport = new CouchbaseTemplateSupport(converter, translationService); this.templateSupport = new CouchbaseTemplateSupport(converter, translationService);
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter, translationService); this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter, translationService);
this.mappingContext = this.converter.getMappingContext(); this.mappingContext = this.converter.getMappingContext();
if (mappingContext instanceof CouchbaseMappingContext) { if (mappingContext instanceof CouchbaseMappingContext) {
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext; CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
if (cmc.isAutoIndexCreation()) { if (cmc.isAutoIndexCreation()) {
indexCreator = new CouchbasePersistentEntityIndexCreator(cmc, this); indexCreator = new CouchbasePersistentEntityIndexCreator(cmc, this);
} }
} }
} }
@Override @Override

View File

@@ -20,56 +20,39 @@ import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.couchbase.CouchbaseClientFactory; import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexResolver.IndexDefinitionHolder; import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexResolver.IndexDefinitionHolder;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.Document; import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.MappingContextEvent;
import com.couchbase.client.core.error.IndexExistsException; import com.couchbase.client.core.error.IndexExistsException;
import com.couchbase.client.java.Cluster; import com.couchbase.client.java.Cluster;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.MappingContextEvent;
/** public class CouchbasePersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent<?, ?>> {
* Encapsulates the logic of creating indices.
*
* @author Michael Nitschinger
* @author Aaron Whiteside
*/
public class CouchbasePersistentEntityIndexCreator implements InitializingBean, ApplicationListener<MappingContextEvent<?, ?>> {
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbasePersistentEntityIndexCreator.class); private static final Logger LOGGER = LoggerFactory.getLogger(CouchbasePersistentEntityIndexCreator.class);
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<>(); private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<>();
private final CouchbaseMappingContext mappingContext; private final CouchbaseMappingContext mappingContext;
private final QueryIndexResolver indexResolver; private final QueryIndexResolver indexResolver;
private final CouchbaseClientFactory clientFactory; private final CouchbaseOperations couchbaseOperations;
private final boolean enabled;
public CouchbasePersistentEntityIndexCreator(final CouchbaseMappingContext mappingContext, public CouchbasePersistentEntityIndexCreator(final CouchbaseMappingContext mappingContext,
final CouchbaseClientFactory clientFactory, final String typeKey, final boolean enabled) { final CouchbaseOperations operations) {
this.mappingContext = mappingContext; this.mappingContext = mappingContext;
this.clientFactory = clientFactory; this.couchbaseOperations = operations;
this.enabled = enabled; this.indexResolver = QueryIndexResolver.create(mappingContext, operations);
this.indexResolver = QueryIndexResolver.create(mappingContext, typeKey);
}
@Override
public void afterPropertiesSet() throws Exception {
if (enabled) {
mappingContext.getPersistentEntities().forEach(this::checkForIndexes);
} else {
LOGGER.debug("Automatic index creation not enabled.");
}
} }
@Override @Override
public void onApplicationEvent(final MappingContextEvent<?, ?> event) { public void onApplicationEvent(final MappingContextEvent<?, ?> event) {
if (!enabled || !event.wasEmittedBy(mappingContext)) { if (!event.wasEmittedBy(mappingContext)) {
return; return;
} }
@@ -88,7 +71,7 @@ public class CouchbasePersistentEntityIndexCreator implements InitializingBean,
this.classesSeen.put(type, Boolean.TRUE); this.classesSeen.put(type, Boolean.TRUE);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Analyzing class {} for index information.", type); LOGGER.debug("Analyzing class " + type + " for index information.");
} }
checkForAndCreateIndexes(entity); checkForAndCreateIndexes(entity);
@@ -110,10 +93,10 @@ public class CouchbasePersistentEntityIndexCreator implements InitializingBean,
} }
private void createIndex(final IndexDefinitionHolder indexToCreate) { private void createIndex(final IndexDefinitionHolder indexToCreate) {
Cluster cluster = clientFactory.getCluster(); Cluster cluster = couchbaseOperations.getCouchbaseClientFactory().getCluster();
StringBuilder statement = new StringBuilder("CREATE INDEX ").append(indexToCreate.getIndexName()).append(" ON `") StringBuilder statement = new StringBuilder("CREATE INDEX ").append(indexToCreate.getIndexName()).append(" ON `")
.append(clientFactory.getBucket().name()).append("` (") .append(couchbaseOperations.getBucketName()).append("` (")
.append(String.join(",", indexToCreate.getIndexFields())).append(")"); .append(String.join(",", indexToCreate.getIndexFields())).append(")");
if (indexToCreate.getIndexPredicate() != null && !indexToCreate.getIndexPredicate().isEmpty()) { if (indexToCreate.getIndexPredicate() != null && !indexToCreate.getIndexPredicate().isEmpty()) {
@@ -124,10 +107,21 @@ public class CouchbasePersistentEntityIndexCreator implements InitializingBean,
cluster.query(statement.toString()); cluster.query(statement.toString());
} catch (IndexExistsException ex) { } catch (IndexExistsException ex) {
// ignored on purpose, rest is propagated // ignored on purpose, rest is propagated
LOGGER.debug("Index \"{}\" already exists, ignoring.", indexToCreate.getIndexName()); LOGGER.debug("Index \"" + indexToCreate.getIndexName() + "\" already exists, ignoring.");
} catch (Exception ex) { } catch (Exception ex) {
throw new DataIntegrityViolationException("Could not auto-create index with statement: " + statement.toString(), throw new DataIntegrityViolationException("Could not auto-create index with statement: " + statement.toString(),
ex); ex);
} }
} }
/**
* Returns whether the current index creator was registered for the given {@link MappingContext}.
*/
public boolean isIndexCreatorFor(final MappingContext<?, ?> context) {
return this.mappingContext.equals(context);
}
public boolean hasSeen(CouchbasePersistentEntity<?> entity) {
return classesSeen.containsKey(entity.getType());
}
} }

View File

@@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.couchbase.core.mapping.Document; import org.springframework.data.couchbase.core.mapping.Document;
@@ -34,13 +35,13 @@ import org.springframework.util.StringUtils;
public class CouchbasePersistentEntityIndexResolver implements QueryIndexResolver { public class CouchbasePersistentEntityIndexResolver implements QueryIndexResolver {
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext; private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
private final String typeKey; private final CouchbaseOperations operations;
public CouchbasePersistentEntityIndexResolver( public CouchbasePersistentEntityIndexResolver(
final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext, final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext,
final String typeKey) { CouchbaseOperations operations) {
this.mappingContext = mappingContext; this.mappingContext = mappingContext;
this.typeKey = typeKey; this.operations = operations;
} }
@Override @Override
@@ -134,6 +135,7 @@ public class CouchbasePersistentEntityIndexResolver implements QueryIndexResolve
} }
private String getPredicate(final MappingCouchbaseEntityInformation<?, Object> entityInfo) { private String getPredicate(final MappingCouchbaseEntityInformation<?, Object> entityInfo) {
String typeKey = operations.getConverter().getTypeKey();
String typeValue = entityInfo.getJavaType().getName(); String typeValue = entityInfo.getJavaType().getName();
return "`" + typeKey + "` = \"" + typeValue + "\""; return "`" + typeKey + "` = \"" + typeValue + "\"";
} }

View File

@@ -15,6 +15,7 @@
*/ */
package org.springframework.data.couchbase.core.index; package org.springframework.data.couchbase.core.index;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
@@ -42,9 +43,9 @@ public interface QueryIndexResolver {
*/ */
static QueryIndexResolver create( static QueryIndexResolver create(
MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext, MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext,
String typeKey) { CouchbaseOperations operations) {
Assert.notNull(mappingContext, "CouchbaseMappingContext must not be null!"); Assert.notNull(mappingContext, "CouchbaseMappingContext must not be null!");
return new CouchbasePersistentEntityIndexResolver(mappingContext, typeKey); return new CouchbasePersistentEntityIndexResolver(mappingContext, operations);
} }
/** /**

View File

@@ -16,10 +16,15 @@
package org.springframework.data.couchbase.core.mapping; package org.springframework.data.couchbase.core.mapping;
import java.util.Optional;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.context.MappingContextEvent;
import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
@@ -32,7 +37,6 @@ import org.springframework.data.util.TypeInformation;
* *
* @author Michael Nitschinger * @author Michael Nitschinger
* @author Michael Reiche * @author Michael Reiche
* @author Aaron Whiteside
*/ */
public class CouchbaseMappingContext public class CouchbaseMappingContext
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty> extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
@@ -51,6 +55,10 @@ public class CouchbaseMappingContext
*/ */
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY; private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
private boolean autoIndexCreation = true;
private ApplicationEventPublisher eventPublisher;
private CouchbasePersistentEntityIndexCreator indexCreator = null;
/** /**
* Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied. * Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied.
* Defaults to a strategy using the plain property name. * Defaults to a strategy using the plain property name.
@@ -100,8 +108,65 @@ public class CouchbaseMappingContext
*/ */
@Override @Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
super.setApplicationContext(applicationContext);
context = applicationContext; context = applicationContext;
super.setApplicationContext(applicationContext);
} }
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
eventPublisher = applicationEventPublisher;
if (this.eventPublisher == null) {
this.eventPublisher = context;
}
}
public boolean isAutoIndexCreation() {
return autoIndexCreation;
}
public void setAutoIndexCreation(boolean autoCreateIndexes) {
this.autoIndexCreation = autoCreateIndexes;
}
/**
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
* already been cached
*
* @param typeInformation - entity type
*/
@Override
protected Optional<BasicCouchbasePersistentEntity<?>> addPersistentEntity(TypeInformation<?> typeInformation) {
Optional<BasicCouchbasePersistentEntity<?>> entity = super.addPersistentEntity(typeInformation);
if (this.eventPublisher != null && entity.isPresent()) {
if (this.indexCreator != null) {
if (!indexCreator.hasSeen(entity.get())) {
this.eventPublisher.publishEvent(new MappingContextEvent(this, entity.get()));
}
}
}
return entity;
}
/**
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
* already been cached. Instead, user our own addPersistEntity that will.
*
* @param typeInformation - entity type
*/
@Override
public BasicCouchbasePersistentEntity<?> getPersistentEntity(TypeInformation<?> typeInformation) {
Optional<BasicCouchbasePersistentEntity<?>> entity = addPersistentEntity(typeInformation);
return entity.isPresent() ? entity.get() : null;
}
/**
* capture the indexCreator when it has been added as a listener. only publishEvent() if the indexCreator hasn't
* already seen the class.
*
* @param indexCreator
*/
public void setIndexCreator(CouchbasePersistentEntityIndexCreator indexCreator) {
this.indexCreator = indexCreator;
}
} }