Skip to content

Commit 577a6c7

Browse files
DATACOUCH-550 - Refactored the usage of CouchbasePersistentEntityIndexCreator.
pom.xml - updated CouchbaseMock dependency to the official release on maven central, which now includes the required commit. CouchbaseTemplate.java - remove creation of CouchbasePersistentEntityIndexCreator - there can only be a single CouchbaseMappingContext and CouchbasePersistentEntityIndexCreator, not sure why there was code dealing with multiples of each, and there was no corresponding tests for these assumptions. - no longer does the job of a @Configuation class by gluing beans together with their dependencies. CouchbaseMappingContext.java - removed references to auto index creation, that functionality should be a completely separate concern. CouchbasePersistentEntityIndexCreator.java - as well as implementing ApplicationListener, it now also implements InitializingBean - when afterPropertiesSet() is called it uses CouchbaseMappingContext#getPersistentEntities to retrieve the list of entity candidates for index creation. This will handle the creation of indices for entities known at @configuration time. - for entities not in the initialEntitySet of the MappingContext, the ApplicationListener will handle those entities at runtime. - this is needed because the AbstractMappingContext will emit events when it is initialized via InitializingBean, and any beans that depend on MappingContext and also implement ApplicationListener expecting to receive those events won't. - in our case because Spring will have fully initialised the CouchbaseMappingContext instance before passing it to the CouchbasePersistentEntityIndexCreator instance we won't get those events. - added a boolean flag to indicate if automatic index creation is to be enabled or now, passed in by the factory method that creates this bean. - minor logging cleanup, use property placeholders where appropriate AbstractCouchbaseConfiguration.java - added a new factory method for the CouchbasePersistentEntityIndexCreator bean. - CouchbaseMappingContext no longer has anything to do with index creation, other than supplying a candidate list of entities that may need indices. Prompted by: spring-projects/spring-boot#24525 and the discussion on #295
1 parent 9c9dde7 commit 577a6c7

File tree

5 files changed

+43
-126
lines changed

5 files changed

+43
-126
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@
150150
</dependency>
151151

152152
<dependency>
153-
<groupId>com.github.Couchbase</groupId>
153+
<groupId>com.couchbase.mock</groupId>
154154
<artifactId>CouchbaseMock</artifactId>
155-
<version>73e493d259</version>
155+
<version>1.5.25</version>
156156
<scope>test</scope>
157157
</dependency>
158158

src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@
3131
import org.springframework.data.convert.CustomConversions;
3232
import org.springframework.data.couchbase.CouchbaseClientFactory;
3333
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
34+
import org.springframework.data.couchbase.core.CouchbaseOperations;
3435
import org.springframework.data.couchbase.core.CouchbaseTemplate;
3536
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
3637
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
3738
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
3839
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
3940
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
41+
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
4042
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
4143
import org.springframework.data.couchbase.core.mapping.Document;
4244
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
@@ -268,7 +270,6 @@ public CouchbaseMappingContext couchbaseMappingContext(CustomConversions customC
268270
mappingContext.setInitialEntitySet(getInitialEntitySet());
269271
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
270272
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
271-
mappingContext.setAutoIndexCreation(autoIndexCreation());
272273

273274
return mappingContext;
274275
}
@@ -280,6 +281,18 @@ protected boolean autoIndexCreation() {
280281
return false;
281282
}
282283

284+
/**
285+
* Creates a {@link CouchbasePersistentEntityIndexCreator} bean that takes on the responsibility of automatically
286+
* creating indices.
287+
*
288+
* Does nothing if {@link #autoIndexCreation()} returns false.
289+
*/
290+
@Bean
291+
public CouchbasePersistentEntityIndexCreator couchbasePersistentEntityIndexCreator(CouchbaseMappingContext couchbaseMappingContext,
292+
CouchbaseOperations couchbaseOperations) {
293+
return new CouchbasePersistentEntityIndexCreator(couchbaseMappingContext, couchbaseOperations, autoIndexCreation());
294+
}
295+
283296
/**
284297
* Register custom Converters in a {@link CustomConversions} object if required. These {@link CustomConversions} will
285298
* be registered with the {@link #mappingCouchbaseConverter(CouchbaseMappingContext, CouchbaseCustomConversions)} )}

src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,8 @@
1919
import org.springframework.beans.BeansException;
2020
import org.springframework.context.ApplicationContext;
2121
import org.springframework.context.ApplicationContextAware;
22-
import org.springframework.context.ConfigurableApplicationContext;
2322
import org.springframework.data.couchbase.CouchbaseClientFactory;
2423
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
25-
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
26-
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
27-
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
28-
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
29-
import org.springframework.data.mapping.context.MappingContext;
30-
import org.springframework.lang.Nullable;
3124

3225
import com.couchbase.client.java.Collection;
3326

@@ -36,30 +29,21 @@
3629
*
3730
* @author Michael Nitschinger
3831
* @author Michael Reiche
32+
* @author Aaron Whiteside
3933
* @since 3.0
4034
*/
4135
public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContextAware {
4236

4337
private final CouchbaseClientFactory clientFactory;
4438
private final CouchbaseConverter converter;
4539
private final CouchbaseTemplateSupport templateSupport;
46-
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
4740
private final ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
48-
private @Nullable CouchbasePersistentEntityIndexCreator indexCreator;
4941

5042
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
5143
this.clientFactory = clientFactory;
5244
this.converter = converter;
5345
this.templateSupport = new CouchbaseTemplateSupport(converter);
5446
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter);
55-
56-
this.mappingContext = this.converter.getMappingContext();
57-
if (mappingContext instanceof CouchbaseMappingContext) {
58-
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
59-
if (cmc.isAutoIndexCreation()) {
60-
indexCreator = new CouchbasePersistentEntityIndexCreator(cmc, this);
61-
}
62-
}
6347
}
6448

6549
@Override
@@ -148,28 +132,7 @@ public ReactiveCouchbaseTemplate reactive() {
148132

149133
@Override
150134
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
151-
prepareIndexCreator(applicationContext);
152135
templateSupport.setApplicationContext(applicationContext);
153136
reactiveCouchbaseTemplate.setApplicationContext(applicationContext);
154137
}
155-
156-
private void prepareIndexCreator(final ApplicationContext context) {
157-
String[] indexCreators = context.getBeanNamesForType(CouchbasePersistentEntityIndexCreator.class);
158-
159-
for (String creator : indexCreators) {
160-
CouchbasePersistentEntityIndexCreator creatorBean = context.getBean(creator,
161-
CouchbasePersistentEntityIndexCreator.class);
162-
if (creatorBean.isIndexCreatorFor(mappingContext)) {
163-
return;
164-
}
165-
}
166-
167-
if (context instanceof ConfigurableApplicationContext && indexCreator != null) {
168-
((ConfigurableApplicationContext) context).addApplicationListener(indexCreator);
169-
if (mappingContext instanceof CouchbaseMappingContext) {
170-
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
171-
cmc.setIndexCreator(indexCreator);
172-
}
173-
}
174-
}
175138
}

src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,53 @@
2020

2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
23+
import org.springframework.beans.factory.InitializingBean;
2324
import org.springframework.context.ApplicationListener;
2425
import org.springframework.dao.DataIntegrityViolationException;
2526
import org.springframework.data.couchbase.core.CouchbaseOperations;
2627
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexResolver.IndexDefinitionHolder;
2728
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
2829
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
2930
import org.springframework.data.couchbase.core.mapping.Document;
30-
import org.springframework.data.mapping.PersistentEntity;
31-
import org.springframework.data.mapping.context.MappingContext;
32-
import org.springframework.data.mapping.context.MappingContextEvent;
3331

3432
import com.couchbase.client.core.error.IndexExistsException;
3533
import com.couchbase.client.java.Cluster;
34+
import org.springframework.data.mapping.PersistentEntity;
35+
import org.springframework.data.mapping.context.MappingContextEvent;
3636

37-
public class CouchbasePersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent<?, ?>> {
37+
/**
38+
* Encapsulates the logic of creating indices.
39+
*
40+
* @author Michael Nitschinger
41+
* @author Aaron Whiteside
42+
*/
43+
public class CouchbasePersistentEntityIndexCreator implements InitializingBean, ApplicationListener<MappingContextEvent<?, ?>> {
3844

3945
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbasePersistentEntityIndexCreator.class);
4046

4147
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<>();
4248
private final CouchbaseMappingContext mappingContext;
4349
private final QueryIndexResolver indexResolver;
4450
private final CouchbaseOperations couchbaseOperations;
51+
private final boolean enabled;
4552

4653
public CouchbasePersistentEntityIndexCreator(final CouchbaseMappingContext mappingContext,
47-
final CouchbaseOperations operations) {
54+
final CouchbaseOperations operations, final boolean enabled) {
4855
this.mappingContext = mappingContext;
4956
this.couchbaseOperations = operations;
57+
this.enabled = enabled;
5058
this.indexResolver = QueryIndexResolver.create(mappingContext, operations);
5159
}
5260

61+
@Override
62+
public void afterPropertiesSet() throws Exception {
63+
if (enabled) {
64+
mappingContext.getPersistentEntities().forEach(this::checkForIndexes);
65+
} else {
66+
LOGGER.debug("Automatic index creation not enabled.");
67+
}
68+
}
69+
5370
@Override
5471
public void onApplicationEvent(final MappingContextEvent<?, ?> event) {
5572
if (!event.wasEmittedBy(mappingContext)) {
@@ -71,7 +88,7 @@ private void checkForIndexes(final CouchbasePersistentEntity<?> entity) {
7188
this.classesSeen.put(type, Boolean.TRUE);
7289

7390
if (LOGGER.isDebugEnabled()) {
74-
LOGGER.debug("Analyzing class " + type + " for index information.");
91+
LOGGER.debug("Analyzing class {} for index information.", type);
7592
}
7693

7794
checkForAndCreateIndexes(entity);
@@ -107,21 +124,10 @@ private void createIndex(final IndexDefinitionHolder indexToCreate) {
107124
cluster.query(statement.toString());
108125
} catch (IndexExistsException ex) {
109126
// ignored on purpose, rest is propagated
110-
LOGGER.debug("Index \"" + indexToCreate.getIndexName() + "\" already exists, ignoring.");
127+
LOGGER.debug("Index \"{}\" already exists, ignoring.", indexToCreate.getIndexName());
111128
} catch (Exception ex) {
112129
throw new DataIntegrityViolationException("Could not auto-create index with statement: " + statement.toString(),
113130
ex);
114131
}
115132
}
116-
117-
/**
118-
* Returns whether the current index creator was registered for the given {@link MappingContext}.
119-
*/
120-
public boolean isIndexCreatorFor(final MappingContext<?, ?> context) {
121-
return this.mappingContext.equals(context);
122-
}
123-
124-
public boolean hasSeen(CouchbasePersistentEntity<?> entity) {
125-
return classesSeen.containsKey(entity.getType());
126-
}
127133
}

src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@
1616

1717
package org.springframework.data.couchbase.core.mapping;
1818

19-
import java.util.Optional;
20-
2119
import org.springframework.beans.BeansException;
2220
import org.springframework.context.ApplicationContext;
2321
import org.springframework.context.ApplicationContextAware;
24-
import org.springframework.context.ApplicationEventPublisher;
25-
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
2622
import org.springframework.data.mapping.context.AbstractMappingContext;
27-
import org.springframework.data.mapping.context.MappingContextEvent;
2823
import org.springframework.data.mapping.model.FieldNamingStrategy;
2924
import org.springframework.data.mapping.model.Property;
3025
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
@@ -37,6 +32,7 @@
3732
*
3833
* @author Michael Nitschinger
3934
* @author Michael Reiche
35+
* @author Aaron Whiteside
4036
*/
4137
public class CouchbaseMappingContext
4238
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
@@ -55,10 +51,6 @@ public class CouchbaseMappingContext
5551
*/
5652
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
5753

58-
private boolean autoIndexCreation = true;
59-
private ApplicationEventPublisher eventPublisher;
60-
private CouchbasePersistentEntityIndexCreator indexCreator = null;
61-
6254
/**
6355
* Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied.
6456
* Defaults to a strategy using the plain property name.
@@ -108,65 +100,8 @@ protected CouchbasePersistentProperty createPersistentProperty(Property property
108100
*/
109101
@Override
110102
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
111-
context = applicationContext;
112103
super.setApplicationContext(applicationContext);
104+
context = applicationContext;
113105
}
114106

115-
@Override
116-
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
117-
eventPublisher = applicationEventPublisher;
118-
if (this.eventPublisher == null) {
119-
this.eventPublisher = context;
120-
}
121-
}
122-
123-
public boolean isAutoIndexCreation() {
124-
return autoIndexCreation;
125-
}
126-
127-
public void setAutoIndexCreation(boolean autoCreateIndexes) {
128-
this.autoIndexCreation = autoCreateIndexes;
129-
}
130-
131-
/**
132-
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
133-
* already been cached
134-
*
135-
* @param typeInformation - entity type
136-
*/
137-
@Override
138-
protected Optional<BasicCouchbasePersistentEntity<?>> addPersistentEntity(TypeInformation<?> typeInformation) {
139-
Optional<BasicCouchbasePersistentEntity<?>> entity = super.addPersistentEntity(typeInformation);
140-
141-
if (this.eventPublisher != null && entity.isPresent()) {
142-
if (this.indexCreator != null) {
143-
if (!indexCreator.hasSeen(entity.get())) {
144-
this.eventPublisher.publishEvent(new MappingContextEvent(this, entity.get()));
145-
}
146-
}
147-
}
148-
return entity;
149-
}
150-
151-
/**
152-
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
153-
* already been cached. Instead, user our own addPersistEntity that will.
154-
*
155-
* @param typeInformation - entity type
156-
*/
157-
@Override
158-
public BasicCouchbasePersistentEntity<?> getPersistentEntity(TypeInformation<?> typeInformation) {
159-
Optional<BasicCouchbasePersistentEntity<?>> entity = addPersistentEntity(typeInformation);
160-
return entity.isPresent() ? entity.get() : null;
161-
}
162-
163-
/**
164-
* capture the indexCreator when it has been added as a listener. only publishEvent() if the indexCreator hasn't
165-
* already seen the class.
166-
*
167-
* @param indexCreator
168-
*/
169-
public void setIndexCreator(CouchbasePersistentEntityIndexCreator indexCreator) {
170-
this.indexCreator = indexCreator;
171-
}
172107
}

0 commit comments

Comments
 (0)