From 00953133425675b71128d28f83c27c40d367bee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Basl=C3=A9?= Date: Fri, 5 Feb 2016 17:57:26 +0100 Subject: [PATCH] DATACOUCH-199 - Make automatic index creation opt-in In addition to annotating the repository with xxxIndexed annotations, user must now opt-in to the feature by redefining the indexManager bean in the configuration. This is so production use of this feature is actively discouraged. --- .../IntegrationTestApplicationConfig.java | 7 +++++ .../extending/base/RepositoryBaseTest.java | 7 +++++ .../method/RepositoryCustomMethodTest.java | 7 +++++ ...FeatureDetectionTestApplicationConfig.java | 7 +++++ .../index/AnotherIndexedUserRepository.java | 2 +- .../index/IndexedRepositoryTests.java | 2 +- .../wiring/RepositoryTemplateWiringTests.java | 7 +++++ src/main/asciidoc/repository.adoc | 28 ++++++++++++++++--- .../AbstractCouchbaseConfiguration.java | 13 +++++---- .../config/CouchbaseIndexManagerParser.java | 13 +++++---- .../repository/support/IndexManager.java | 18 ++++++------ .../couchbase/config/spring-couchbase-2.0.xsd | 6 ++-- .../couchbase/UnitTestApplicationConfig.java | 7 +++++ 13 files changed, 95 insertions(+), 29 deletions(-) diff --git a/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java index 37b7090e..a6a62847 100644 --- a/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java +++ b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java @@ -14,6 +14,7 @@ import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.WriteResultChecking; import org.springframework.data.couchbase.core.query.Consistency; +import org.springframework.data.couchbase.repository.support.IndexManager; @Configuration public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfiguration { @@ -66,6 +67,12 @@ public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfigura return template; } + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } + @Override protected Consistency getDefaultConsistency() { return Consistency.READ_YOUR_OWN_WRITES; diff --git a/src/integration/java/org/springframework/data/couchbase/repository/extending/base/RepositoryBaseTest.java b/src/integration/java/org/springframework/data/couchbase/repository/extending/base/RepositoryBaseTest.java index c85ae9fb..3494223e 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/extending/base/RepositoryBaseTest.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/extending/base/RepositoryBaseTest.java @@ -42,6 +42,7 @@ import org.springframework.data.couchbase.repository.UserRepository; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; import org.springframework.data.couchbase.repository.extending.base.impl.MyRepository; import org.springframework.data.couchbase.repository.extending.base.impl.MyRepositoryImpl; +import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -104,6 +105,12 @@ public class RepositoryBaseTest { public CouchbaseOperations couchbaseOperations() { return mockOpsA; } + + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } } @Test diff --git a/src/integration/java/org/springframework/data/couchbase/repository/extending/method/RepositoryCustomMethodTest.java b/src/integration/java/org/springframework/data/couchbase/repository/extending/method/RepositoryCustomMethodTest.java index 0a0d6fa3..c6f9b72e 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/extending/method/RepositoryCustomMethodTest.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/extending/method/RepositoryCustomMethodTest.java @@ -33,6 +33,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.core.query.Consistency; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; +import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -68,6 +69,12 @@ public class RepositoryCustomMethodTest { return ""; } + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } + @Override protected Consistency getDefaultConsistency() { return Consistency.STRONGLY_CONSISTENT; diff --git a/src/integration/java/org/springframework/data/couchbase/repository/feature/FeatureDetectionTestApplicationConfig.java b/src/integration/java/org/springframework/data/couchbase/repository/feature/FeatureDetectionTestApplicationConfig.java index 0b591b95..dd5d7bf3 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/feature/FeatureDetectionTestApplicationConfig.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/feature/FeatureDetectionTestApplicationConfig.java @@ -16,6 +16,7 @@ import org.springframework.core.env.Environment; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.WriteResultChecking; +import org.springframework.data.couchbase.repository.support.IndexManager; @Configuration public class FeatureDetectionTestApplicationConfig extends AbstractCouchbaseConfiguration { @@ -71,6 +72,12 @@ public class FeatureDetectionTestApplicationConfig extends AbstractCouchbaseConf return new DefaultClusterInfo(JsonObject.empty()); } + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } + //change the name of the field that will hold type information @Override public String typeKey() { diff --git a/src/integration/java/org/springframework/data/couchbase/repository/index/AnotherIndexedUserRepository.java b/src/integration/java/org/springframework/data/couchbase/repository/index/AnotherIndexedUserRepository.java index 529b8d58..f1c02b37 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/index/AnotherIndexedUserRepository.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/index/AnotherIndexedUserRepository.java @@ -8,8 +8,8 @@ import org.springframework.data.couchbase.repository.CouchbaseRepository; import org.springframework.data.couchbase.repository.User; @N1qlSecondaryIndexed(indexName = IndexedRepositoryTests.IGNORED_SECONDARY) +@ViewIndexed(designDoc = IndexedRepositoryTests.VIEW_DOC, viewName = IndexedRepositoryTests.IGNORED_VIEW_NAME) public interface AnotherIndexedUserRepository extends CouchbaseRepository { - @ViewIndexed(designDoc = IndexedRepositoryTests.VIEW_DOC, viewName = IndexedRepositoryTests.IGNORED_VIEW_NAME) public List findByAge(int age); } diff --git a/src/integration/java/org/springframework/data/couchbase/repository/index/IndexedRepositoryTests.java b/src/integration/java/org/springframework/data/couchbase/repository/index/IndexedRepositoryTests.java index 452b60ce..99fcc432 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/index/IndexedRepositoryTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/index/IndexedRepositoryTests.java @@ -67,7 +67,7 @@ public class IndexedRepositoryTests { private RepositoryFactorySupport factory; private RepositoryFactorySupport ignoringIndexFactory; - private IndexManager ignoringIndexManager = new IndexManager(true, true, true); + private IndexManager ignoringIndexManager = new IndexManager(false, false, false); @Before public void setup() throws Exception { diff --git a/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java b/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java index a7723513..7e305854 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java @@ -22,6 +22,7 @@ import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.repository.CouchbaseRepository; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping; +import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.stereotype.Repository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -105,6 +106,12 @@ public class RepositoryTemplateWiringTests { return mockOpsC; } + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } + @Override public void configureRepositoryOperationsMapping(RepositoryOperationsMapping base) { base.setDefault(templateC()) diff --git a/src/main/asciidoc/repository.adoc b/src/main/asciidoc/repository.adoc index de149f70..7304122e 100644 --- a/src/main/asciidoc/repository.adoc +++ b/src/main/asciidoc/repository.adoc @@ -10,7 +10,7 @@ There are three backing mechanisms in Couchbase for repositories, described in t - <> CRUD operations are still mostly backed by Couchbase views (see <>). -Such views (and, for N1QL, equivalent indexes) can be automatically built, but note this is an **expensive operation** (see <>). +Such views (and, for N1QL, equivalent indexes) can be automatically built, but note this is **discouraged in production** and can be an **expensive operation** (see <>). Note that you can tune the consistency you want for your queries (see <>) and have different repositories backed by different buckets (see <>) @@ -284,15 +284,35 @@ Also make sure to publish your design documents into production so that they can [[couchbase.repository.indexing]] === Automatic Index Management We've seen that the repositories default methods can be backed by two broad kind of features: views and N1QL (in the case of paging and sorting). -In order for the CRUD operations to work, the adequate view must have been created beforehand, and this is usually left for the user to do because view creation (and index creation) is an expensive operation that can take quite some time if the quantity of documents is high. +In order for the CRUD operations to work, the adequate view must have been created beforehand, and this is usually left for the user to do. First because view creation (and index creation) is an expensive operation that can take quite some time if the quantity of documents is high. Second, because in production it is considered best practice to avoid administration of the cluster elements like buckets, indexes and view by an application code. -In the case where the index creation cost isn't considered too high, it can be triggered automatically instead. You just need to annotate the repositories you want managed with the relevant annotation(s): +In the case where the index creation cost isn't considered too high and you are not in a production environment, it can be triggered automatically instead, in two steps. You will first need to annotate the repositories you want managed with the relevant annotation(s): - `@ViewIndexed` will create a view like the "all" view previously seen, to list all entities in the bucket. - `@N1qlPrimaryIndexed` can be used to ensure a general-purpose PRIMARY INDEX is available in N1QL. - `@N1qlSecondaryIndexed` will create a more specific N1QL index that does the same kind of filtering on entity type that the view does. It'll allow for efficient listing of all documents that correspond to a Repository's associated domain object. -Note that sometimes you only want this automatic creation in certain contexts (eg. in Dev but not in Production). To that end, you can customize the `IndexManager` bean in an env-specific `AbstractCouchbaseConfiguration` (eg. via `@Profile`) to ignore certain types of index creation annotations. This is done through the `IndexManager(boolean ignoreView, boolean ignoreN1qlPrimary, boolean ignoreN1qlSecondary)` constructor. You can even declare multiple beans and differentiate them using Spring annotations. +Secondly, you'll need to opt-in to this feature by customizing the `indexManager()` bean of your env-specific `AbstractCouchbaseConfiguration` to take certain types of annotations into account. This is done through the `IndexManager(boolean processViews, boolean processN1qlPrimary, boolean processN1qlSecondary)` constructor. Set the flags for the category of annotations you want processed to true, or false to deactivate the automatic creation feature. + +The `@Profile` annotation is one possible Spring annotation to be used to differentiate configurations (or individual beans) per environment. + +.A Dev configuration where only @ViewIndexed annotations will be processed. +==== +[source,java] +---- +@Configuration +public class ExampleDevApplicationConfig extends AbstractCouchbaseConfiguration { + + // note a few other overrides are actually needed + + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(true, false, false); + } +} +---- +==== [[couchbase.repository.views.querying]] === View based querying diff --git a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java index b9549b13..f48cc0c7 100644 --- a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java +++ b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java @@ -249,15 +249,18 @@ public abstract class AbstractCouchbaseConfiguration { /** * Register an {@link IndexManager} bean that will be used to process {@link ViewIndexed}, * {@link N1qlPrimaryIndexed} and {@link N1qlSecondaryIndexed} annotations on repositories - * to automatically create indexes. + * to automatically create indexes. By default, since such automatic creations are discouraged in + * production envrironment, the configuration will assume the worst and will ignore these annotations. *

- * If this configuration is used in a context where such automatic creations are not desired (eg. - * you want automatic index creation in Dev but not in Prod, and this configuration is the Prod one), - * override the bean and use the {@link IndexManager#IndexManager(boolean, boolean, boolean)} constructor. + * If you are sure this configuration used in a context where such automatic creations are desired (eg. + * you want automatic index creation in Dev, just not in Prod, and this configuration is the Dev one), + * override the bean and use the {@link IndexManager#IndexManager()} constructor (or + * {@link IndexManager#IndexManager(boolean, boolean, boolean)} constructor with appropriate flags set to true to + * activate). */ @Bean(name = BeanNames.COUCHBASE_INDEX_MANAGER) public IndexManager indexManager() { - return new IndexManager(); + return new IndexManager(false, false, false); //this ignores view, N1QL primary and secondary annotations } /** diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseIndexManagerParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseIndexManagerParser.java index 94182bc5..4d0655c7 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseIndexManagerParser.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseIndexManagerParser.java @@ -65,13 +65,14 @@ public class CouchbaseIndexManagerParser extends AbstractSingleBeanDefinitionPar */ @Override protected void doParse(final Element element, final BeanDefinitionBuilder bean) { - boolean ignoreViews = Boolean.parseBoolean(element.getAttribute("ignoreViews")); - boolean ignorePrimary = Boolean.parseBoolean(element.getAttribute("ignorePrimary")); - boolean ignoreSecondary = Boolean.parseBoolean(element.getAttribute("ignoreSecondary")); + //the following values default to false, so you must opt-in by providing them + boolean processViews = Boolean.parseBoolean(element.getAttribute("processViews")); + boolean processPrimary = Boolean.parseBoolean(element.getAttribute("processPrimary")); + boolean processSecondary = Boolean.parseBoolean(element.getAttribute("processSecondary")); - bean.addConstructorArgValue(ignoreViews); - bean.addConstructorArgValue(ignorePrimary); - bean.addConstructorArgValue(ignoreSecondary); + bean.addConstructorArgValue(processViews); + bean.addConstructorArgValue(processPrimary); + bean.addConstructorArgValue(processSecondary); } } diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/IndexManager.java b/src/main/java/org/springframework/data/couchbase/repository/support/IndexManager.java index 27177a73..e455318d 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/IndexManager.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/IndexManager.java @@ -70,24 +70,24 @@ public class IndexManager { /** * Construct an IndexManager that can be used as a Bean in a {@link Profile @Profile} annotated configuration - * in order to ignore all or part of automatic index creations in some contexts (like activating it in Dev but + * in order to activate only all or part of automatic index creations in some contexts (like activating it in Dev but * not in Prod). * - * @param ignoreViews true to ignore {@link ViewIndexed} annotations. - * @param ignoreN1qlPrimary true to ignore {@link N1qlPrimaryIndexed} annotations. - * @param ignoreN1qlSecondary true to ignore {@link N1qlSecondaryIndexed} annotations. + * @param processViews true to process, false to ignore {@link ViewIndexed} annotations. + * @param processN1qlPrimary true to process, false to ignore {@link N1qlPrimaryIndexed} annotations. + * @param processN1qlSecondary true to process, false to ignore {@link N1qlSecondaryIndexed} annotations. */ - public IndexManager(boolean ignoreViews, boolean ignoreN1qlPrimary, boolean ignoreN1qlSecondary) { - this.ignoreViews = ignoreViews; - this.ignoreN1qlPrimary = ignoreN1qlPrimary; - this.ignoreN1qlSecondary = ignoreN1qlSecondary; + public IndexManager(boolean processViews, boolean processN1qlPrimary, boolean processN1qlSecondary) { + this.ignoreViews = !processViews; + this.ignoreN1qlPrimary = !processN1qlPrimary; + this.ignoreN1qlSecondary = !processN1qlSecondary; } /** * Construct a default IndexManager that process all three types of automatic index creations. */ public IndexManager() { - this(false, false, false); + this(true, true, true); } /** diff --git a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd index 53ffe07e..d33e3b65 100644 --- a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd +++ b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd @@ -182,9 +182,9 @@ The name of the CouchbaseBucket object that determines what connection to monito - - - + + + diff --git a/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java b/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java index 7275fc5a..973be872 100644 --- a/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java +++ b/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java @@ -21,6 +21,7 @@ import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.WriteResultChecking; import org.springframework.data.couchbase.core.query.Consistency; +import org.springframework.data.couchbase.repository.support.IndexManager; @Configuration public class UnitTestApplicationConfig extends AbstractCouchbaseConfiguration { @@ -75,6 +76,12 @@ public class UnitTestApplicationConfig extends AbstractCouchbaseConfiguration { return template; } + //this is for dev so it is ok to auto-create indexes + @Override + public IndexManager indexManager() { + return new IndexManager(); + } + @Override protected Consistency getDefaultConsistency() { return Consistency.READ_YOUR_OWN_WRITES;