diff --git a/src/main/asciidoc/reference/indexing.adoc b/src/main/asciidoc/reference/indexing.adoc
new file mode 100644
index 00000000..9476782c
--- /dev/null
+++ b/src/main/asciidoc/reference/indexing.adoc
@@ -0,0 +1,238 @@
+[[bootstrap:indexing]]
+= Configuring an Index
+
+Pivotal GemFire allows Indexes (or Indices) to be created on Region data to improve the performance of OQL queries.
+
+In _Spring Data GemFire_ (SDG), Indexes are declared with the `index` element:
+
+[source,xml]
+----
+
+----
+
+In _Spring Data GemFire's_ XML schema (a.k.a. SDG namespace), `Index` bean declarations are not bound to a _Region_,
+unlike GemFire's native `cache.xml`. Rather, they are top-level elements just like `<gfe:cache>`. This allows
+a developer to declare any number of Indexes on any _Region_ whether they were just created or already exist,
+a significant improvement over GemFire's native `cache.xml` format.
+
+An `Index` must have a name. A developer may give the `Index` an explicit name using the `name` attribute,
+otherwise the _bean name_ (i.e. value of the `id` attribute) of the `Index` bean definition is used as
+the `Index` name.
+
+The `expression` and `from` clause form the main components of an `Index`, identifying the data to index
+(i.e. the _Region_ identified in the `from` clause) along with what criteria (i.e. `expression`) is used
+to index the data. The `expression` should be based on what application domain object fields are used
+in the predicate of application-defined OQL queries used to query and lookup the objects stored
+in the _Region_.
+
+For example, if I have a `Customer` that has a `lastName` property...
+
+[source,java]
+----
+@Region("Customers")
+class Customer {
+
+ @Id
+ Long id;
+
+ String lastName;
+ String firstName;
+
+ ...
+}
+----
+
+And, I also have an application defined SD[G] _Repository_ to query for `Customers`...
+
+[source,java]
+----
+interface CustomerRepository extends GemfireRepository {
+
+ Customer findByLastName(String lastName);
+
+ ...
+}
+----
+
+Then, the SD[G] _Repository_ finder/query method would result in the following OQL statement being executed...
+
+[source,java]
+----
+SELECT * FROM /Customers c WHERE c.lastName = '$1'
+----
+
+Therefore, I might want to create an `Index` like so...
+
+[source,xml]
+----
+
+----
+
+The `from` clause must refer to a valid, existing _Region_ and is how an `Index` gets applied to a _Region_.
+This is *not* _Sprig Data GemFire_ specific; this is a feature of Pivotal GemFire.
+
+The `Index` `type` maybe 1 of 3 enumerated values defined by _Spring Data GemFire's_
+http://docs.spring.io/spring-data-gemfire/docs/current/api/org/springframework/data/gemfire/IndexType.html[IndexType]
+enumeration: `FUNCTIONAL`, `HASH` and `PRIMARY_KEY`.
+
+Each of the enumerated values correspond to one of the http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html[QueryService]
+`create[|Key|Hash]Index` methods invoked when the actual `Index` is to be created (or "defined"; more on "defining"
+Indexes below). For instance, if the `IndexType` is `PRIMARY_KEY`, then the
+http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#createKeyIndex-java.lang.String-java.lang.String-java.lang.String-[QueryService.createKeyIndex(..)]
+is invoked to create a `KEY` `Index`.
+
+The default is `FUNCTIONAL` and results in one of the `QueryService.createIndex(..)` methods
+being invoked.
+
+See the _Spring Data GemFire_ XML schema for a full set of options.
+
+For more information on Indexing in Pivotal GemFire, see http://gemfire90.docs.pivotal.io/geode/developing/query_index/query_index.html[Working with Indexes]
+in Pivotal GemFire's User Guide.
+
+== Defining Indexes
+
+In addition to creating Indexes upfront as `Index` bean definitions are processed by _Spring Data GemFire_
+on _Spring_ container initialization, you may also *define* all of your application Indexes prior to creating
+them by using the `define` attribute, like so...
+
+[source,xml]
+----
+
+----
+
+When `define` is set to `true` (defaults to `false`), this will not actually create the `Index` right then and there.
+All "defined" Indexes are created all at once, when the _Spring_ `ApplicationContext` is "refreshed", or, that is,
+when a `ContextRefreshedEvent` is published by the _Spring_ container. _Spring Data GemFire_ registers itself as
+an `ApplicationListener` listening for the `ContextRefreshedEvent`. When fired, _Spring Data GemFire_ will call
+http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#createDefinedIndexes--[QueryService.createDefinedIndexes()].
+
+Defining Indexes and creating them all at once helps promote speed and efficiency when creating Indexes.
+
+See http://gemfire90.docs.pivotal.io/geode/developing/query_index/create_multiple_indexes.html[Creating Multiple Indexes at Once]
+for more details.
+
+== `IgnoreIfExists` and `Override`
+
+Two _Spring Data GemFire_ `Index` configuration options warrant special mention here: `ignoreIfExists` and `override`.
+
+These options correspond to the `ignore-if-exists` and `override` attributes on the `<gfe:index>` element
+in _Spring Data GemFire's_ XML schema, respectively.
+
+WARNING: Make sure you absolutely understand what you are doing before using either of these options. These options can
+affect the performance and/or resources (e.g. memory) consumed by your application at runtime. As such, both of
+these options are disabled (i.e. set to `false`) in SDG by default.
+
+NOTE: These options are only available in _Spring Data GemFire_ and exist to workaround known limitations
+with Pivotal GemFire; there are no equivalent options or functionality available in GemFire itself.
+
+Each option significantly differs in behavior and entirely depends on the type of GemFire `Index` _Exception_ thrown.
+This also means that neither option has any effect if a GemFire Index-type _Exception_ is *not* thrown. These options
+are meant to specifically handle GemFire `IndexExistsExceptions` and `IndexNameConflictExceptions`, which can occur
+for various, sometimes obscure reasons. But, in general...
+
+* An http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/IndexExistsException.html[IndexExistsException]
+is thrown when there exists another `Index` with the same definition but different name when attempting to
+create an `Index`.
+
+* An http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/IndexNameConflictException.html[IndexNameConflictException]
+is thrown when there exists another `Index` with the same name but possibly different definition when attempting to
+create an `Index`.
+
+_Spring Data GemFire's_ default behavior is to *_fail-fast_*, always! So, neither `Index` _Exception_ will be "handled"
+by default; these `Index` _Exceptions_ are simply wrapped in a SDG `GemfireIndexException` and rethrown. If you wish
+for _Spring Data GemFire_ to handle them for you, then you can set either of these `Index` bean definition options.
+
+`IgnoreIfExists` always takes *precedence* over `Override`, primarily because it uses less resources given it returns
+the "existing" `Index` in both exceptional cases.
+
+=== `IgnoreIfExists` Behavior
+
+When an `IndexExistsException` is thrown and `ignoreIfExists` is set to `true` (or `<gfe:index ignore-if-exists="true">`),
+then the `Index` that would have been created by this `Index` bean definition / declaration will be "*ignored*",
+and the "existing" `Index` will be returned.
+
+There is very little consequence in returning the "existing" `Index` since the `Index` "definition" is the same,
+as deemed by GemFire itself, *not* SDG.
+
+However, this also means that *no* `Index` with the "`name`" specified in your `Index` bean definition / declaration
+will "actually" exist from GemFire's perspective either (i.e. with
+http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#getIndexes--[QueryService.getIndexes()]).
+Therefore, you should be careful when writing OQL query statements that use _Query Hints_, especially _Hints_ that refer
+to the application `Index` being "*ignored*". Those _Query Hints_ will need to be changed.
+
+Now, when an `IndexNameConflictException` is thrown and `ignoreIfExists` is set to `true` (or `<gfe:index ignore-if-exists="true">`),
+then the `Index` that would have been created by this `Index` bean definition / declaration will also be "*ignored*",
+and the "existing" Index will be returned, just like when an `IndexExistsException` is thrown.
+
+However, there is more risk in returning the "existing" `Index` and "*ignoring*" the application's definition
+of the `Index` when an `IndexNameConflictException` is thrown since, for a `IndexNameConflictException`, while the "names"
+of the conflicting Indexes are the same, the "definitions" could very well be different! This obviously could have
+implications for OQL queries specific to the application, where you would presume the Indexes were defined specifically
+with the application data access patterns and queries in mind. However, if like named Indexes differ in definition,
+this might not be the case. So, make sure you verify.
+
+NOTE: SDG makes a best effort to inform the user when the `Index` being ignored is significantly different
+in its definition from the "existing" `Index`. However, in order for SDG to accomplish this, it must be able to "find"
+the existing `Index`, which is looked up using the GemFire API (the only means available).
+
+
+=== `Override` Behavior
+
+When an `IndexExistsException` is thrown and `override` is set to `true` (or `<gfe:index override="true">`), then
+the `Index` is effectively "_renamed_". Remember, `IndexExistsExceptions` are thrown when multiple Indexes exist,
+all having the same "definition" but different "names".
+
+_Spring Data GemFire_ can only accomplish this using GemFire's API, by first "_removing_" the "existing" `Index`
+and then "_recreating_" the `Index` with the *new* name. It is possible that either the remove or subsequent
+create invocation could fail. There is no way to execute both actions atomically and rollback this joint operation
+if either fails.
+
+However, if it succeeds, then you have the same problem as before with the "_ignoreIfExists_" option. Any existing OQL
+query statement using "_Query Hints_" referring to the old `Index` by name must be changed.
+
+Now, when an `IndexNameConflictException` is thrown and `override` is set to `true` (or `<gfe:index override="true">`),
+then potentially the "existing" `Index` will be "_re-defined_". I say "potentially", because it is possible for the
+"like-named", "existing" `Index` to have exactly the same definition and name when an `IndexNameConflictException`
+is thrown.
+
+If so, SDG is *smart* and will just return the "existing" Index as is, even on `override`. There is no harm in this
+since both the "name" and the "definition" are exactly the same. Of course, SDG can only accomplish this when
+SDG is able to "find" the "existing" `Index`, which is dependent on GemFire's APIs. If it cannot find it,
+nothing happens and a SDG `GemfireIndexException` is thrown wrapping the `IndexNameConflictException`.
+
+However, when the "definition" of the "existing" `Index` is different, then SDG will attempt to "_recreate_" the `Index`
+using the `Index` definition specified in the `Index` bean definition /declaration. Make sure this is what you want
+and make sure the `Index` definition matches your expectations and application requirements.
+
+=== How does `IndexNameConflictExceptions` actually happen?
+
+It is probably not all that uncommon for `IndexExistsExceptions` to be thrown, especially when
+multiple configuration sources are used to configure GemFire (e.g. _Spring Data GemFire_, GemFire _Cluster Config_,
+maybe GemFire native `cache.xml`, the API, etc, etc). You should definitely prefer 1 configuration method here
+and stick with it.
+
+_However, when does an `IndexNameConflictException` get thrown?_
+
+One particular case is an `Index` defined on a `PARTITION` _Region_ (PR). When an `Index` is defined on
+a `PARTITION` _Region_ (e.g. "X"), GemFire distributes the `Index` definition (and name) to other peer members
+in the cluster that also host the same `PARTITION` _Region_ (i.e. "X"). The distribution of this `Index` definition
+to and subsequent creation of this `Index` by peer members on a "need-to-know" basis (i.e. those hosting the same PR)
+is performed asynchronously.
+
+During this window of time, it is possible that these "pending" PR `Indexes` will not be identifiable by GemFire,
+such as with a call to http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#getIndexes--[QueryService.getIndexes()]
+or with http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#getIndexes-org.apache.geode.cache.Region-[QueryService.getIndexes(:Region)],
+or even with http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/query/QueryService.html#getIndex-org.apache.geode.cache.Region-java.lang.String-[QueryService.getIndex(:Region, indexName:String)].
+
+As such, the only way for SDG or other GemFire cache client applications (not involving _Spring_) to know for sure,
+is to just attempt to create the `Index`. If it fails with either an `IndexNameConflictException`,
+or even an `IndexExistsException`, then you will know. This is because the `QueryService` `Index` creation waits on
+"pending" `Index` definitions, where as the other GemFire API calls do not.
+
+In any case, SDG makes a best effort and attempts to inform the user what has or is happening along with
+the corrective action. Given all GemFire `QueryService.createIndex(..)` methods are synchronous, "blocking" operations,
+then the state of GemFire should be consistent and accessible after either of these Index-type _Exceptions_ are thrown,
+in which case, SDG can inspect the state of the system and respond/act accordingly, based on the user's
+desired configuration.
+
+In all other cases, SDG will simply *_fail-fast_*!
diff --git a/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java b/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java
index b275452d..bf477a0b 100644
--- a/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java
+++ b/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java
@@ -38,6 +38,14 @@ import com.gemstone.gemfire.cache.query.IndexNameConflictException;
@SuppressWarnings({ "serial", "unused" })
public class GemfireIndexException extends DataIntegrityViolationException {
+ public GemfireIndexException(Exception cause) {
+ this(cause.getMessage(), cause);
+ }
+
+ public GemfireIndexException(String message, Exception cause) {
+ super(message, cause);
+ }
+
public GemfireIndexException(IndexCreationException cause) {
this(cause.getMessage(), cause);
}
@@ -77,5 +85,4 @@ public class GemfireIndexException extends DataIntegrityViolationException {
public GemfireIndexException(String message, IndexNameConflictException cause) {
super(message, cause);
}
-
}
diff --git a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java
index a346dad8..f733d54c 100644
--- a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java
+++ b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java
@@ -16,53 +16,55 @@
package org.springframework.data.gemfire;
-import java.util.Collection;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
-import org.springframework.beans.factory.BeanNameAware;
-import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.data.gemfire.config.xml.GemfireConstants;
-import org.springframework.data.gemfire.util.CollectionUtils;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
+import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
+import static org.springframework.data.gemfire.util.SpringUtils.defaultIfNull;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.query.Index;
import com.gemstone.gemfire.cache.query.IndexExistsException;
-import com.gemstone.gemfire.cache.query.IndexInvalidException;
import com.gemstone.gemfire.cache.query.IndexNameConflictException;
import com.gemstone.gemfire.cache.query.IndexStatistics;
import com.gemstone.gemfire.cache.query.QueryService;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.data.gemfire.config.xml.GemfireConstants;
+import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
/**
- * Spring FactoryBean for easy declarative creation of GemFire Indexes.
+ * Spring {@link FactoryBean} for simple and easy declarative creation of GemFire Indexes.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
- * @see org.springframework.beans.factory.BeanFactoryAware
- * @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
+ * @see org.springframework.beans.factory.config.ConfigurableBeanFactory
* @see org.springframework.data.gemfire.IndexFactoryBean.IndexWrapper
+ * @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
+ * @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.RegionService
* @see com.gemstone.gemfire.cache.query.Index
* @see com.gemstone.gemfire.cache.query.QueryService
* @since 1.0.0
*/
-public class IndexFactoryBean implements InitializingBean, FactoryBean, BeanNameAware, BeanFactoryAware {
+public class IndexFactoryBean extends AbstractFactoryBeanSupport implements InitializingBean {
+
+ public static final String BASIC_INDEX_DEFINITION = "{ expression = '%1$s', from = '%2$s', type = %3$s }";
+
+ public static final String DETAILED_INDEX_DEFINITION =
+ "{ name = '%1$s', expression = '%2$s', from = '%3$s', imports = '%4$s', type = %5$s }";
private boolean define = false;
- private boolean override = true;
-
- private BeanFactory beanFactory;
+ private boolean ignoreIfExists = false;
+ private boolean override = false;
private Index index;
@@ -72,72 +74,126 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
private RegionService cache;
- private String beanName;
private String expression;
private String from;
private String imports;
private String indexName;
private String name;
+ @Override
public void afterPropertiesSet() throws Exception {
- Assert.notNull(cache, "The GemFire Cache reference must not be null!");
- queryService = lookupQueryService();
+ this.cache = resolveCache();
+ this.indexName = resolveIndexName();
+ this.queryService = resolveQueryService();
- Assert.notNull(queryService, "QueryService is required to create an Index");
- Assert.hasText(expression, "Index 'expression' is required");
- Assert.hasText(from, "Index 'from clause' is required");
+ assertIndexDefinitionConfiguration();
- if (IndexType.isKey(indexType)) {
- Assert.isNull(imports, "'imports' are not supported with a KEY Index");
- }
+ this.index = createIndex(this.queryService, this.indexName);
- indexName = (StringUtils.hasText(name) ? name : beanName);
-
- Assert.hasText(indexName, "Index 'name' is required");
-
- index = createIndex(queryService, indexName);
+ registerAlias(getBeanName(), this.indexName);
}
/* (non-Javadoc) */
- QueryService doLookupQueryService() {
- return (queryService != null ? queryService
- : (cache instanceof ClientCache ? ((ClientCache) cache).getLocalQueryService() : cache.getQueryService()));
+ private void assertIndexDefinitionConfiguration() {
+
+ Assert.hasText(this.expression, "Index expression is required");
+ Assert.hasText(this.from, "Index from clause is required");
+
+ if (IndexType.isKey(this.indexType)) {
+ Assert.isTrue(StringUtils.isEmpty(this.imports), "Imports are not supported with a KEY Index");
+ }
+ }
+
+ /* (non-Javadoc) */
+ RegionService resolveCache() {
+
+ RegionService resolvedCache = (this.cache != null ? this.cache : GemfireUtils.resolveGemFireCache());
+
+ Assert.state(resolvedCache != null, "Cache is required");
+
+ return resolvedCache;
+ }
+
+ /* (non-Javadoc) */
+ String resolveIndexName() {
+
+ String resolvedIndexName = (StringUtils.hasText(this.name) ? this.name : getBeanName());
+
+ Assert.hasText(resolvedIndexName, "Index name is required");
+
+ return resolvedIndexName;
+ }
+
+ /* (non-Javadoc) */
+ QueryService resolveQueryService() {
+
+ QueryService resolvedQueryService = (this.queryService != null ? this.queryService : lookupQueryService());
+
+ Assert.state(resolvedQueryService != null, "QueryService is required to create an Index");
+
+ return resolvedQueryService;
}
/* (non-Javadoc) */
QueryService lookupQueryService() {
- if (getBeanFactory().containsBean(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE)) {
- return getBeanFactory().getBean(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE,
- QueryService.class);
- }
- else {
- return registerQueryServiceBean(doLookupQueryService());
- }
+
+ String queryServiceBeanName = GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE;
+
+ BeanFactory beanFactory = getBeanFactory();
+
+ return (beanFactory != null && beanFactory.containsBean(queryServiceBeanName)
+ ? beanFactory.getBean(queryServiceBeanName, QueryService.class)
+ : registerQueryServiceBean(queryServiceBeanName, doLookupQueryService()));
}
/* (non-Javadoc) */
- QueryService registerQueryServiceBean(QueryService queryService) {
- if (isDefine()) {
- ((ConfigurableBeanFactory) getBeanFactory()).registerSingleton(
- GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE, queryService);
+ QueryService doLookupQueryService() {
+
+ return (queryService != null ? queryService
+ : (cache instanceof ClientCache ? ((ClientCache) cache).getLocalQueryService()
+ : cache.getQueryService()));
+ }
+
+ /* (non-Javadoc) */
+ QueryService registerQueryServiceBean(String beanName, QueryService queryService) {
+
+ BeanFactory beanFactory = getBeanFactory();
+
+ if (beanFactory instanceof ConfigurableBeanFactory) {
+ if (isDefine()) {
+ ((ConfigurableBeanFactory) beanFactory).registerSingleton(beanName, queryService);
+ }
}
return queryService;
}
/* (non-Javadoc) */
- Index createIndex(QueryService queryService, String indexName) throws Exception {
- Index existingIndex = getExistingIndex(queryService, indexName);
+ void registerAlias(String beanName, String indexName) {
- if (existingIndex != null) {
- if (override) {
- queryService.removeIndex(existingIndex);
- }
- else {
- return existingIndex;
+ BeanFactory beanFactory = getBeanFactory();
+
+ if (beanFactory instanceof ConfigurableBeanFactory) {
+ if (beanName != null && !beanName.equals(indexName)) {
+ ((ConfigurableBeanFactory) beanFactory).registerAlias(beanName, indexName);
}
}
+ }
+
+ /* (non-Javadoc) */
+ Index createIndex(QueryService queryService, String indexName) throws Exception {
+ return createIndex(queryService, indexName, false);
+ }
+
+ /* (non-Javadoc) */
+ private Index createIndex(QueryService queryService, String indexName, boolean retryAttempted) throws Exception {
+
+ IndexType indexType = this.indexType;
+
+ String expression = this.expression;
+ String from = this.from;
+ String imports = this.imports;
try {
if (IndexType.isKey(indexType)) {
@@ -150,32 +206,174 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
return createFunctionalIndex(queryService, indexName, expression, from, imports);
}
}
- catch (IndexExistsException e) {
- throw new GemfireIndexException(String.format(
- "An Index with a different name having the same definition as this Index (%1$s) already exists",
- indexName), e);
- }
- catch (IndexNameConflictException e) {
- // NOTE technically, the only way for an IndexNameConflictException to be thrown is if
- // queryService.remove(existingIndex) above silently fails, since otherwise, when override is 'false',
- // the existingIndex is already being returned. Given this state of affairs, an Index with the provided
- // name is unresolvable based on what the user intended to happen, so just rethrow an Exception.
- throw new GemfireIndexException(String.format(
- "Failed to remove the existing Index%1$sbefore re-creating Index with name (%2$s)",
- (override ? " on override " : " "), indexName), e);
- }
- catch (Exception e) {
- if (existingIndex != null) {
- Collection indexes = queryService.getIndexes();
+ catch (IndexExistsException cause) {
- if (CollectionUtils.isEmpty(indexes) || !indexes.contains(existingIndex)) {
- queryService.getIndexes().add(existingIndex);
- return existingIndex;
- }
+ // Same definition, different name
+
+ Index existingIndexByDefinition =
+ tryToFindExistingIndexByDefinition(queryService, expression, from, indexType);
+
+ if (isIgnorable(existingIndexByDefinition)) {
+
+ logWarning("WARNING! You are choosing to ignore this Index [%1$s] and return the existing"
+ + " Index having the same basic definition [%2$s] but with a different name [%3$s];"
+ + " Make sure no OQL Query Hints refer to this Index by name [%1$s]",
+ indexName, toBasicIndexDefinition(), existingIndexByDefinition.getName());
+
+ return handleIgnore(existingIndexByDefinition);
}
+ else if (isOverridable(existingIndexByDefinition, retryAttempted)) {
- throw e;
+ // Log an informational warning to caution the user about using the override
+ logWarning("WARNING! You are attempting to 'override' an existing Index [%1$s]"
+ + " having the same basic definition [%2$s] as the Index that will be created"
+ + " by this IndexFactoryBean [%3$s]; 'Override' effectively 'renames' the existing"
+ + " Index [%1$s] by removing it then recreating it under the new name [%3$s] with"
+ + " the same definition; You should be careful to update any existing OQL Query"
+ + " Hints referring to the old Index name [%1$s] to now use the new name [%3$s]",
+ existingIndexByDefinition.getName(), toBasicIndexDefinition(), indexName);
+
+ return handleOverride(existingIndexByDefinition, queryService, indexName);
+ }
+ else {
+
+ String existingIndexName = (existingIndexByDefinition != null
+ ? existingIndexByDefinition.getName() : "unknown");
+
+ throw new GemfireIndexException(String.format(
+ "An Index with a different name [%1$s] having the same definition [%2$s] already exists;"
+ + " You may attempt to override the existing Index [%1$s] with the new name [%3$s]"
+ + " by setting the 'override' property to 'true'",
+ existingIndexName, toBasicIndexDefinition(), indexName), cause);
+ }
}
+ catch (IndexNameConflictException cause) {
+
+ // Same name; possibly different definition
+
+ Index existingIndexByName = tryToFindExistingIndexByName(queryService, indexName);
+
+ if (isIgnorable(existingIndexByName)) {
+ return handleIgnore(warnOnIndexDefinitionMismatch(existingIndexByName, indexName, "Returning"));
+ }
+ else if (isOverridable(existingIndexByName, retryAttempted)) {
+ return handleSmartOverride(warnOnIndexDefinitionMismatch(existingIndexByName, indexName,
+ "Overriding"), queryService, indexName);
+ }
+ else {
+
+ String existingIndexDefinition = (existingIndexByName != null
+ ? String.format(DETAILED_INDEX_DEFINITION, existingIndexByName.getName(),
+ existingIndexByName.getIndexedExpression(), existingIndexByName.getFromClause(), "unknown",
+ existingIndexByName.getType())
+ : "unknown");
+
+ throw new GemfireIndexException(String.format(
+ "An Index with the same name [%1$s] having possibly a different definition already exists;"
+ + " you may choose to ignore this Index definition [%2$s] and use the existing Index"
+ + " definition [%3$s] by setting the 'ignoreIfExists' property to 'true'",
+ indexName, toDetailedIndexDefinition(), existingIndexDefinition), cause);
+ }
+ }
+ catch (Exception cause) {
+ throw new GemfireIndexException(String.format("Failed to create Index [%s]",
+ toDetailedIndexDefinition()), cause);
+ }
+ }
+
+ /* (non-Javadoc) */
+ private boolean isIgnorable(Index existingIndex) {
+ return (isIgnoreIfExists() && existingIndex != null);
+ }
+
+ /* (non-Javadoc) */
+ @SuppressWarnings("all")
+ private boolean isIndexDefinitionMatch(Index index) {
+
+ boolean result = false;
+
+ if (index != null) {
+
+ IndexType thisIndexType = defaultIfNull(this.indexType, IndexType.FUNCTIONAL);
+
+ result = ObjectUtils.nullSafeEquals(index.getIndexedExpression(), this.expression)
+ && ObjectUtils.nullSafeEquals(index.getFromClause(), this.from)
+ && ObjectUtils.nullSafeEquals(IndexType.valueOf(index.getType()), thisIndexType);
+
+ }
+
+ return result;
+ }
+
+ /* (non-Javadoc) */
+ private boolean isNotIndexDefinitionMatch(Index index) {
+ return !isIndexDefinitionMatch(index);
+ }
+
+ /* (non-Javadoc) */
+ private boolean isOverridable(Index existingIndex, boolean retryAttempted) {
+ return (isOverride() && existingIndex != null && !retryAttempted);
+ }
+
+ /* (non-Javadoc) */
+ private Index warnOnIndexDefinitionMismatch(Index existingIndex, String indexName, String action) {
+
+ if (isNotIndexDefinitionMatch(existingIndex)) {
+
+ String existingIndexDefinition = String.format(BASIC_INDEX_DEFINITION, existingIndex.getIndexedExpression(),
+ existingIndex.getFromClause(), IndexType.valueOf(existingIndex.getType()));
+
+ logWarning("WARNING! %1$s existing Index [%2$s] having a definition [%3$s]"
+ + " that does not match the Index defined [%4$s] by this IndexFactoryBean [%5$s]",
+ action, existingIndex.getName(), existingIndexDefinition, toBasicIndexDefinition(), indexName);
+ }
+
+ return existingIndex;
+ }
+
+ /* (non-Javadoc) */
+ private Index handleIgnore(Index existingIndex) {
+
+ registerAlias(getBeanName(), existingIndex.getName());
+
+ return existingIndex;
+ }
+
+ /* (non-Javadoc) */
+ private Index handleOverride(Index existingIndex, QueryService queryService, String indexName) {
+ try {
+ // No way to tell whether the QueryService.remove(:Index) was successful or not! o.O
+ // Should return a boolean! Does it throw an RuntimeException? Javadoc is useless; #sigh
+ queryService.removeIndex(existingIndex);
+
+ return createIndex(queryService, indexName, true);
+ }
+ catch (Exception cause) {
+ throw new GemfireIndexException(String.format(
+ "Attempt to 'override' existing Index [%1$s] with the Index that would be created"
+ + " by this IndexFactoryBean [%2$s] failed; you should verify the state of"
+ + " your system and make sure the previously existing Index [%1$s] still exits",
+ existingIndex.getName(), indexName), cause);
+ }
+ }
+
+ /* (non-Javadoc) */
+ private Index handleSmartOverride(Index existingIndex, QueryService queryService, String indexName) {
+
+ return (existingIndex.getName().equalsIgnoreCase(indexName) && isIndexDefinitionMatch(existingIndex)
+ ? existingIndex
+ : handleOverride(existingIndex, queryService, indexName));
+ }
+
+ /* (non-Javadoc) */
+ String toBasicIndexDefinition() {
+ return String.format(BASIC_INDEX_DEFINITION, this.expression, this.from, this.indexType);
+ }
+
+ /* (non-Javadoc) */
+ String toDetailedIndexDefinition() {
+ return String.format(DETAILED_INDEX_DEFINITION,
+ this.name, this.expression, this.from, this.imports, this.indexType);
}
/* (non-Javadoc) */
@@ -190,8 +388,8 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
}
/* (non-Javadoc) */
- Index createHashIndex(QueryService queryService, String indexName, String expression, String from,
- String imports) throws Exception {
+ Index createHashIndex(QueryService queryService, String indexName, String expression, String from, String imports)
+ throws Exception {
boolean hasImports = StringUtils.hasText(imports);
@@ -242,8 +440,25 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
}
/* (non-Javadoc) */
- Index getExistingIndex(QueryService queryService, String indexName) {
- for (Index index : CollectionUtils.nullSafeCollection(queryService.getIndexes())) {
+ Index tryToFindExistingIndexByDefinition(QueryService queryService,
+ String expression, String fromClause, IndexType indexType) {
+
+ for (Index index : nullSafeCollection(queryService.getIndexes())) {
+ if (index.getIndexedExpression().equalsIgnoreCase(expression)
+ && index.getFromClause().equalsIgnoreCase(fromClause)
+ && indexType.equals(IndexType.valueOf(index.getType()))) {
+
+ return index;
+ }
+ }
+
+ return null;
+ }
+
+ /* (non-Javadoc) */
+ Index tryToFindExistingIndexByName(QueryService queryService, String indexName) {
+
+ for (Index index : nullSafeCollection(queryService.getIndexes())) {
if (index.getName().equalsIgnoreCase(indexName)) {
return index;
}
@@ -252,125 +467,258 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
return null;
}
- public Index getObject() {
- index = (index != null ? index : getExistingIndex(queryService, indexName));
- return index;
+ /**
+ * Returns a reference to the {@link Index} created by this {@link IndexFactoryBean}.
+ *
+ * @return a reference to the {@link Index} created by this {@link IndexFactoryBean}.
+ * @see com.gemstone.gemfire.cache.query.Index
+ */
+ public Index getIndex() {
+ return this.index;
}
+ /* (non-Javadoc) */
+ @Override
+ public Index getObject() {
+
+ this.index = (this.index != null ? this.index
+ : tryToFindExistingIndexByName(resolveQueryService(), resolveIndexName()));
+
+ return this.index;
+ }
+
+ /* (non-Javadoc) */
+ @Override
public Class> getObjectType() {
+ Index index = getIndex();
return (index != null ? index.getClass() : Index.class);
}
- public boolean isSingleton() {
- return true;
- }
-
/**
- * Sets the underlying cache used for creating indexes.
+ * Sets a reference to the {@link RegionService}.
*
- * @param cache cache used for creating indexes.
+ * @param cache reference to the {@link RegionService}.
+ * @see com.gemstone.gemfire.cache.RegionService
*/
public void setCache(RegionService cache) {
this.cache = cache;
}
/**
- * Sets the query service used for creating indexes.
+ * Sets the name of the {@link Index}.
*
- * @param service query service used for creating indexes.
- */
- public void setQueryService(QueryService service) {
- this.queryService = service;
- }
-
- /* (non-Javadoc) */
- @Override
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
- }
-
- /* (non-Javadoc) */
- protected BeanFactory getBeanFactory() {
- Assert.state(beanFactory != null, "'beanFactory' was not properly initialized");
- return beanFactory;
- }
-
- /* (non-Javadoc) */
- @Override
- public void setBeanName(String name) {
- this.beanName = name;
- }
-
- /**
- * @param name the name to set
+ * @param name {@link String} containing the name given to the {@link Index}.
*/
public void setName(String name) {
this.name = name;
}
/**
- * Sets a boolean condition to indicate whether the Index declared and defined by this FactoryBean will only be
- * defined initially, or defined and created. If defined-only, the IndexFactoryBean will receive a callback at
- * the end of the Spring container lifecycle to subsequently "create" all "defined-only" Indexes once, in a
- * single operation.
+ * Sets the {@link QueryService} used to create the {@link Index}.
*
- * @param define a boolean value indicating the define or define/create status. If true, the Index declared
- * by this FactoryBean will only be defined initially and subsequently created when this SmartLifecycle bean
- * receives an appropriate callback from the Spring container; if false, the Index will be created immediately.
+ * @param service {@link QueryService} used to create the {@link Index}.
+ * @see com.gemstone.gemfire.cache.query.QueryService
+ */
+ public void setQueryService(QueryService service) {
+ this.queryService = service;
+ }
+
+ /**
+ * Sets a boolean condition to indicate whether the {@link Index} declared and defined by this
+ * {@link IndexFactoryBean} will only be defined initially, or defined and created. If defined-only,
+ * the {@link IndexFactoryBean} will receive a callback at the end of the Spring container lifecycle
+ * to subsequently "create" all "defined-only" {@link Index Indexes} once, in a single operation.
+ *
+ * @param define a boolean value indicating the define or define/create status. If {@literal true},
+ * the {@link Index} declared by this {@link IndexFactoryBean} will only be defined initially
+ * and subsequently created when this bean receives an appropriate callback from the Spring container;
+ * if {@literal false}, the {@link Index} will be created immediately.
*/
public void setDefine(boolean define) {
this.define = define;
}
- /* (non-Javadoc) */
+ /**
+ * Returns a boolean indicating whether the {@link Index} declared and defined by this {@link IndexFactoryBean}
+ * will only be defined initially, or defined and created. If defined-only, the {@link IndexFactoryBean}
+ * will receive a callback at the end of the Spring container lifecycle to subsequently "create" all "defined-only"
+ * {@link Index Indexes} once, in a single operation.
+ *
+ * @return a boolean value indicating the define or define/create status. If {@literal true}, the {@link Index}
+ * declared by this {@link IndexFactoryBean} will only be defined initially and subsequently created when this bean
+ * receives an appropriate callback from the Spring container; if {@literal false}, the {@link Index}
+ * will be created immediately.
+ */
protected boolean isDefine() {
return define;
}
/**
- * @param expression the expression to set
+ * @param expression Index expression to set
*/
public void setExpression(String expression) {
this.expression = expression;
}
/**
- * @param from the from to set
+ * @param from Index from clause to set
*/
public void setFrom(String from) {
this.from = from;
}
/**
- * @param imports the imports to set
+ * @param imports Index imports to set
*/
public void setImports(String imports) {
this.imports = imports;
}
/**
- * @param override the override to set
+ * Configures whether to ignore the {@link Index} defined by this {@link IndexFactoryBean}
+ * when an {@link IndexExistsException} or {@link IndexNameConflictException} is thrown.
+ *
+ * An {@link IndexExistsException} is thrown when there exists another {@link Index} with the same definition
+ * but with another name.
+ *
+ * An {@link IndexNameConflictException} is thrown when there exists another {@link Index} with the same name
+ * but possibly a different definition.
+ *
+ * When {@literal ignoreIfExists} is set to {@literal true} and an {@link IndexExistsException} is thrown,
+ * then the existing {@link Index} will be returned as the object of this {@link IndexFactoryBean} creation
+ * and the name of the existing {@link Index} is added as an alias for this bean.
+ *
+ * When {@literal ignoreIfExists} is set to {@literal true} and {@link IndexNameConflictException} is thrown,
+ * then the existing {@link Index} will be returned as the object of this {@link IndexFactoryBean} creation.
+ * A warning is logged if the definition of this {@link IndexFactoryBean} and the existing {@link Index}
+ * are different.
+ *
+ * {@literal ignoreIfExists} takes precedence over {@link #isOverride() override}.
+ *
+ * Defaults to {@literal false}.
+ *
+ * @param ignore boolean value indicating whether to ignore the {@link Index} defined by
+ * this {@link IndexFactoryBean}. Default is {@literal false}.
+ * @see #setOverride(boolean)
+ */
+ public void setIgnoreIfExists(boolean ignore) {
+ this.ignoreIfExists = ignore;
+ }
+
+ /**
+ * Determines whether to ignore the {@link Index} defined by this {@link IndexFactoryBean}
+ * when an {@link IndexExistsException} or {@link IndexNameConflictException} is thrown.
+ *
+ * An {@link IndexExistsException} is thrown when there exists another {@link Index} with the same definition
+ * but with another name.
+ *
+ * An {@link IndexNameConflictException} is thrown when there exists another {@link Index} with the same name
+ * but possibly a different definition.
+ *
+ * When {@literal ignoreIfExists} is set to {@literal true} and an {@link IndexExistsException} is thrown,
+ * then the existing {@link Index} will be returned as the object of this {@link IndexFactoryBean} creation
+ * and the name of the existing {@link Index} is added as an alias for this bean.
+ *
+ * When {@literal ignoreIfExists} is set to {@literal true} and {@link IndexNameConflictException} is thrown,
+ * then the existing {@link Index} will be returned as the object of this {@link IndexFactoryBean} creation.
+ * A warning is logged if the definition of this {@link IndexFactoryBean} and the existing {@link Index}
+ * are different.
+ *
+ * {@literal ignoreIfExists} takes precedence over {@link #isOverride() override}.
+ *
+ * Defaults to {@literal false}.
+ *
+ * @return a boolean value indicating whether to ignore the {@link Index} defined by this {@link IndexFactoryBean}.
+ * Default is {@literal false}.
+ * @see #setIgnoreIfExists(boolean)
+ */
+ public boolean isIgnoreIfExists() {
+ return this.ignoreIfExists;
+ }
+
+ /**
+ * Configures whether to override an existing {@link Index} having the same definition but different name
+ * as the {@link Index} that would be created by this {@link IndexFactoryBean}.
+ *
+ * An {@link IndexExistsException} is thrown when there exists another {@link Index} with the same definition
+ * but with another name.
+ *
+ * An {@link IndexNameConflictException} is thrown when there exists another {@link Index} with the same name
+ * but possibly a different definition.
+ *
+ * With {@literal override} set to {@literal true} when an {@link IndexExistsException} is thrown, then override
+ * is effectively the same as "renaming" the existing {@link Index}. In other words, the existing {@link Index}
+ * will be {@link QueryService#removeIndex(Index) removed} and recreated by this {@link IndexFactoryBean}
+ * under the new {@link #resolveIndexName() name} having the same definition.
+ *
+ * With {@literal override} set to {@literal true} when an {@link IndexNameConflictException} is thrown,
+ * then overriding the existing {@link Index} is equivalent to changing the existing {@link Index} definition.
+ * When this happens, a warning is logged. If the existing {@link Index} definition is the same then overriding
+ * effectively just rebuilds the {@link Index}.
+ *
+ * {@literal ignoreIfExists} takes precedence over {@literal override}.
+ *
+ * Defaults to {@literal false}.
+ *
+ * @param override boolean value indicating whether an existing {@link Index} will be removed and recreated
+ * by this {@link IndexFactoryBean}. Default is {@literal false}.
+ * @see #setIgnoreIfExists(boolean)
*/
public void setOverride(boolean override) {
this.override = override;
}
/**
- * @param type the type to set
+ * Determines whether to override an existing {@link Index} having the same definition but different name
+ * as the {@link Index} that would be created by this {@link IndexFactoryBean}.
+ *
+ * An {@link IndexExistsException} is thrown when there exists another {@link Index} with the same definition
+ * but with another name.
+ *
+ * An {@link IndexNameConflictException} is thrown when there exists another {@link Index} with the same name
+ * but possibly a different definition.
+ *
+ * With {@literal override} set to {@literal true} when an {@link IndexExistsException} is thrown, then override
+ * is effectively the same as "renaming" the existing {@link Index}. In other words, the existing {@link Index}
+ * will be {@link QueryService#removeIndex(Index) removed} and recreated by this {@link IndexFactoryBean}
+ * under the new {@link #resolveIndexName() name} having the same definition.
+ *
+ * With {@literal override} set to {@literal true} when an {@link IndexNameConflictException} is thrown,
+ * then overriding the existing {@link Index} is equivalent to changing the existing {@link Index} definition.
+ * When this happens, a warning is logged. If the existing {@link Index} definition is the same then overriding
+ * effectively just rebuilds the {@link Index}.
+ *
+ * {@literal ignoreIfExists} takes precedence over {@literal override}.
+ *
+ * Defaults to {@literal false}.
+ *
+ * @return a boolean value indicating whether an existing {@link Index} will be removed and recreated
+ * by this {@link IndexFactoryBean}. Default is {@literal false}.
+ * @see #setOverride(boolean)
+ */
+ public boolean isOverride() {
+ return this.override;
+ }
+
+ /**
+ * Set the {@link IndexType type} of the {@link Index} as a {@link String}.
+ *
+ * @param type {@link String} specifying the {@link IndexType type} of the {@link Index}.
+ * @see org.springframework.data.gemfire.IndexType#valueOf(String)
+ * @see #setType(IndexType)
*/
public void setType(String type) {
setType(IndexType.valueOfIgnoreCase(type));
}
/**
- * Sets the type of GemFire Index to create.
+ * Set the {@link IndexType type} of the {@link Index}.
*
- * @param indexType the IndexType enumerated value indicating the type of GemFire Index
- * that will be created by this Spring FactoryBean.
+ * @param type {@link IndexType} indicating the type of the {@link Index}.
* @see org.springframework.data.gemfire.IndexType
*/
- public void setType(IndexType indexType) {
- this.indexType = indexType;
+ public void setType(IndexType type) {
+ this.indexType = type;
}
/* (non-Javadoc) */
@@ -382,19 +730,23 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
private final String indexName;
- protected IndexWrapper(final QueryService queryService, final String indexName) {
- Assert.notNull(queryService, "QueryService must not be null");
- Assert.hasText(indexName, "The name of the Index must be specified!");
+ protected IndexWrapper(QueryService queryService, String indexName) {
+
+ Assert.notNull(queryService, "QueryService is required");
+ Assert.hasText(indexName, "Name of Index is required");
+
this.queryService = queryService;
this.indexName = indexName;
-
}
- protected synchronized Index getIndex() {
+ /* (non-Javadoc) */
+ protected synchronized Index resolveIndex() {
+
if (this.index == null) {
+
String localIndexName = getIndexName();
- for (Index localIndex : getQueryService().getIndexes()) {
+ for (Index localIndex : nullSafeCollection(getQueryService().getIndexes())) {
if (localIndex.getName().equals(localIndexName)) {
this.index = localIndex;
break;
@@ -402,77 +754,85 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
}
if (this.index == null) {
- throw new GemfireIndexException(new IndexInvalidException(String.format(
- "index with name (%1$s) was not found", localIndexName)));
+ throw new GemfireIndexException(String.format("Index with name [%s] was not found", localIndexName),
+ (Exception) null);
}
}
return index;
}
- protected String getIndexName() {
- Assert.state(StringUtils.hasText(indexName), "The Index 'name' was not properly initialized!");
- return indexName;
+ /* (non-Javadoc) */
+ protected Index getIndex() {
+ return this.index;
}
+ /* (non-Javadoc) */
+ protected String getIndexName() {
+ Assert.state(StringUtils.hasText(this.indexName), "Index name is required");
+ return this.indexName;
+ }
+
+ /* (non-Javadoc) */
protected QueryService getQueryService() {
- return queryService;
+ return this.queryService;
}
@Override
public String getName() {
- return getIndex().getName();
+ return resolveIndex().getName();
}
@Override
public String getCanonicalizedFromClause() {
- return getIndex().getCanonicalizedFromClause();
+ return resolveIndex().getCanonicalizedFromClause();
}
@Override
public String getCanonicalizedIndexedExpression() {
- return getIndex().getCanonicalizedIndexedExpression();
+ return resolveIndex().getCanonicalizedIndexedExpression();
}
@Override
public String getCanonicalizedProjectionAttributes() {
- return getIndex().getCanonicalizedProjectionAttributes();
+ return resolveIndex().getCanonicalizedProjectionAttributes();
}
@Override
public String getFromClause() {
- return getIndex().getFromClause();
+ return resolveIndex().getFromClause();
}
@Override
public String getIndexedExpression() {
- return getIndex().getIndexedExpression();
+ return resolveIndex().getIndexedExpression();
}
@Override
public String getProjectionAttributes() {
- return getIndex().getProjectionAttributes();
+ return resolveIndex().getProjectionAttributes();
}
@Override
public Region, ?> getRegion() {
- return getIndex().getRegion();
+ return resolveIndex().getRegion();
}
@Override
public IndexStatistics getStatistics() {
- return getIndex().getStatistics();
+ return resolveIndex().getStatistics();
}
@Override
@SuppressWarnings("deprecation")
public com.gemstone.gemfire.cache.query.IndexType getType() {
- return getIndex().getType();
+ return resolveIndex().getType();
}
@Override
- public boolean equals(final Object obj) {
- if (obj == this) {
+ public boolean equals(Object obj) {
+
+ if (this == obj) {
return true;
}
@@ -484,21 +844,23 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B
return (getIndexName().equals(((IndexWrapper) obj).getIndexName()));
}
- return getIndex().equals(obj);
+ return resolveIndex().equals(obj);
}
@Override
public int hashCode() {
+
int hashValue = 37;
+
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getIndexName());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(index);
+
return hashValue;
}
@Override
public String toString() {
- return (index != null ? String.valueOf(index) : getIndexName());
+ return (this.index != null ? String.valueOf(this.index) : getIndexName());
}
}
-
}
diff --git a/src/main/java/org/springframework/data/gemfire/IndexType.java b/src/main/java/org/springframework/data/gemfire/IndexType.java
index d1a936eb..9acd503e 100644
--- a/src/main/java/org/springframework/data/gemfire/IndexType.java
+++ b/src/main/java/org/springframework/data/gemfire/IndexType.java
@@ -25,6 +25,7 @@ package org.springframework.data.gemfire;
*/
@SuppressWarnings({ "deprecation", "unused" })
public enum IndexType {
+
FUNCTIONAL(com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL),
HASH(com.gemstone.gemfire.cache.query.IndexType.HASH),
PRIMARY_KEY(com.gemstone.gemfire.cache.query.IndexType.PRIMARY_KEY),
@@ -49,7 +50,7 @@ public enum IndexType {
* @return a boolean value indicating whether the IndexType is a "FUNCTIONAL" Index.
* @see #isFunctional()
*/
- public static boolean isFunctional(final IndexType indexType) {
+ public static boolean isFunctional(IndexType indexType) {
return (indexType != null && indexType.isFunctional());
}
@@ -60,7 +61,7 @@ public enum IndexType {
* @return a boolean value indicating whether the IndexType is a "HASH" Index.
* @see #isHash()
*/
- public static boolean isHash(final IndexType indexType) {
+ public static boolean isHash(IndexType indexType) {
return (indexType != null && indexType.isHash());
}
@@ -71,7 +72,7 @@ public enum IndexType {
* @return a boolean value indicating whether the IndexType is a "KEY" Index.
* @see #isFunctional()
*/
- public static boolean isKey(final IndexType indexType) {
+ public static boolean isKey(IndexType indexType) {
return (indexType != null && indexType.isKey());
}
@@ -84,7 +85,8 @@ public enum IndexType {
* any IndexType in this enumeration.
* @see com.gemstone.gemfire.cache.query.IndexType
*/
- public static IndexType valueOf(final com.gemstone.gemfire.cache.query.IndexType gemfireIndexType) {
+ public static IndexType valueOf(com.gemstone.gemfire.cache.query.IndexType gemfireIndexType) {
+
for (IndexType indexType : values()) {
if (indexType.getGemfireIndexType().equals(gemfireIndexType)) {
return indexType;
@@ -101,7 +103,8 @@ public enum IndexType {
* @return an IndexType matching the given String.
* @see java.lang.String#equalsIgnoreCase(String)
*/
- public static IndexType valueOfIgnoreCase(final String value) {
+ public static IndexType valueOfIgnoreCase(String value) {
+
for (IndexType indexType : values()) {
if (indexType.name().equalsIgnoreCase(value)) {
return indexType;
@@ -147,5 +150,4 @@ public enum IndexType {
public boolean isKey() {
return (this.equals(KEY) || this.equals(PRIMARY_KEY));
}
-
}
diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java
index db6db076..0cdfe2dc 100644
--- a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java
+++ b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java
@@ -111,12 +111,15 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
super.postProcess(importingClassMetadata, registry, persistentEntity);
if (isAnnotationPresent(importingClassMetadata, getEnableIndexesAnnotationTypeName())) {
+
final AnnotationAttributes enableIndexesAttributes =
getAnnotationAttributes(importingClassMetadata, getEnableIndexesAnnotationTypeName());
localPersistentEntity.doWithProperties(new PropertyHandler() {
+
@Override
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
+
Id idAnnotation = persistentProperty.findAnnotation(Id.class);
if (idAnnotation != null) {
@@ -162,6 +165,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
IndexType indexType, Annotation indexAnnotation, BeanDefinitionRegistry registry) {
if (indexAnnotation != null) {
+
AnnotationAttributes indexAnnotationAttributes = AnnotationAttributes.fromMap(
AnnotationUtils.getAnnotationAttributes(indexAnnotation));
@@ -181,8 +185,12 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
indexFactoryBeanBuilder.addPropertyValue("from",
resolveFrom(persistentEntity, persistentProperty, indexAnnotationAttributes));
+ indexFactoryBeanBuilder.addPropertyValue("ignoreIfExists", Boolean.TRUE);
+
indexFactoryBeanBuilder.addPropertyValue("name", indexName);
+ indexFactoryBeanBuilder.addPropertyValue("override", Boolean.FALSE);
+
indexFactoryBeanBuilder.addPropertyValue("type",
resolveType(persistentEntity, persistentProperty, indexAnnotationAttributes, indexType).toString());
@@ -199,6 +207,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
/* (non-Javadoc) */
@SuppressWarnings("unused")
private String resolveExpression(GemfirePersistentEntity> persistentEntity,
+
GemfirePersistentProperty persistentProperty, AnnotationAttributes indexAnnotationAttributes) {
String expression = (indexAnnotationAttributes.containsKey("expression")
@@ -210,6 +219,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
/* (non-Javadoc) */
@SuppressWarnings("unused")
private String resolveFrom(GemfirePersistentEntity> persistentEntity,
+
GemfirePersistentProperty persistentProperty, AnnotationAttributes indexAnnotationAttributes) {
String from = (indexAnnotationAttributes.containsKey("from")
diff --git a/src/main/java/org/springframework/data/gemfire/config/xml/IndexParser.java b/src/main/java/org/springframework/data/gemfire/config/xml/IndexParser.java
index 8e92573e..0681e0c2 100644
--- a/src/main/java/org/springframework/data/gemfire/config/xml/IndexParser.java
+++ b/src/main/java/org/springframework/data/gemfire/config/xml/IndexParser.java
@@ -42,8 +42,10 @@ class IndexParser extends AbstractSimpleBeanDefinitionParser {
private static final AtomicBoolean REGISTERED = new AtomicBoolean(false);
/* (non-Javadoc) */
- protected static void registerDefinedIndexesApplicationListener(ParserContext parserContext) {
+ private static void registerDefinedIndexesApplicationListener(ParserContext parserContext) {
+
if (REGISTERED.compareAndSet(false, true)) {
+
AbstractBeanDefinition createDefinedIndexesApplicationListener = BeanDefinitionBuilder
.rootBeanDefinition(DefinedIndexesApplicationListener.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
diff --git a/src/main/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupport.java b/src/main/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupport.java
new file mode 100644
index 00000000..0e277ae3
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupport.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.gemfire.support;
+
+import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.util.Assert;
+
+/**
+ * The {@link AbstractFactoryBeanSupport} class is an abstract Spring {@link FactoryBean} base class implementation
+ * encapsulating operations common to SDG's {@link FactoryBean} implementations.
+ *
+ * @author John Blum
+ * @see org.springframework.beans.factory.BeanClassLoaderAware
+ * @see org.springframework.beans.factory.BeanFactory
+ * @see org.springframework.beans.factory.BeanFactoryAware
+ * @see org.springframework.beans.factory.BeanNameAware
+ * @see org.springframework.beans.factory.FactoryBean
+ * @since 1.0.0
+ */
+public abstract class AbstractFactoryBeanSupport implements FactoryBean,
+ BeanClassLoaderAware, BeanFactoryAware, BeanNameAware {
+
+ protected static final boolean DEFAULT_SINGLETON = true;
+
+ private ClassLoader beanClassLoader;
+
+ private BeanFactory beanFactory;
+
+ private final Log log = newLog();
+
+ private String beanName;
+
+ /**
+ * Constructs a new instance of {@link Log} to log statements printed by Spring Data GemFire/Geode.
+ *
+ * @return a new instance of {@link Log}.
+ * @see org.apache.commons.logging.LogFactory#getLog(Class)
+ * @see org.apache.commons.logging.Log
+ */
+ protected Log newLog() {
+ return LogFactory.getLog(getClass());
+ }
+
+ /**
+ * Sets a reference to the {@link ClassLoader} used by the Spring container to load and create bean classes.
+ *
+ * @param classLoader {@link ClassLoader} used by the Spring container to load and create bean classes.
+ * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
+ * @see java.lang.ClassLoader
+ */
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ /**
+ * Returns a reference to the {@link ClassLoader} used by the Spring container to load and create bean classes.
+ *
+ * @return the {@link ClassLoader} used by the Spring container to load and create bean classes.
+ * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
+ * @see java.lang.ClassLoader
+ */
+ public ClassLoader getBeanClassLoader() {
+ return this.beanClassLoader;
+ }
+
+ /**
+ * Sets a reference to the Spring {@link BeanFactory} in which this {@link FactoryBean} was declared.
+ *
+ * @param beanFactory reference to the declaring Spring {@link BeanFactory}.
+ * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(BeanFactory)
+ * @see org.springframework.beans.factory.BeanFactory
+ */
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
+ /**
+ * Returns a reference to the Spring {@link BeanFactory} in which this {@link FactoryBean} was declared.
+ *
+ * @return a reference to the declaring Spring {@link BeanFactory}.
+ * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(BeanFactory)
+ * @see org.springframework.beans.factory.BeanFactory
+ */
+ public BeanFactory getBeanFactory() {
+ return this.beanFactory;
+ }
+
+ /**
+ * Sets the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
+ *
+ * @param name {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
+ * @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
+ * @see java.lang.String
+ */
+ @Override
+ public void setBeanName(String name) {
+ this.beanName = name;
+ }
+
+ /**
+ * Returns the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
+ *
+ * @return the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
+ * @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
+ * @see java.lang.String
+ */
+ public String getBeanName() {
+ return this.beanName;
+ }
+
+ /**
+ * Returns a reference to the {@link Log} used by this {@link FactoryBean} to log {@link String messages}.
+ *
+ * @return a reference to the {@link Log} used by this {@link FactoryBean} to log {@link String messages}.
+ * @see org.apache.commons.logging.Log
+ */
+ protected Log getLog() {
+ return this.log;
+ }
+
+ /**
+ * Indicates that this {@link FactoryBean} produces a single bean instance.
+ *
+ * @return {@literal true} by default.
+ * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+ */
+ @Override
+ public boolean isSingleton() {
+ return DEFAULT_SINGLETON;
+ }
+
+ /**
+ * Logs the {@link String message} formatted with the array of {@link Object arguments} at debug level.
+ *
+ * @param message {@link String} containing the message to log.
+ * @param args array of {@link Object arguments} used to format the {@code message}.
+ * @see #logDebug(Supplier)
+ */
+ protected void logDebug(String message, Object... args) {
+ logDebug(StringFormatSupplier.of(message, args));
+ }
+
+ /**
+ * Logs the {@link String message} supplied by the given {@link Supplier} at debug level.
+ *
+ * @param message {@link Supplier} containing the {@link String message} and arguments to log.
+ * @see org.apache.commons.logging.Log#isDebugEnabled()
+ * @see org.apache.commons.logging.Log#debug(Object)
+ * @see #getLog()
+ */
+ protected void logDebug(Supplier message) {
+
+ Log log = getLog();
+
+ if (log.isDebugEnabled()) {
+ log.debug(message.get());
+ }
+ }
+
+ /**
+ * Logs the {@link String message} formatted with the array of {@link Object arguments} at info level.
+ *
+ * @param message {@link String} containing the message to log.
+ * @param args array of {@link Object arguments} used to format the {@code message}.
+ * @see #logInfo(Supplier)
+ */
+ protected void logInfo(String message, Object... args) {
+ logInfo(StringFormatSupplier.of(message, args));
+ }
+
+ /**
+ * Logs the {@link String message} supplied by the given {@link Supplier} at info level.
+ *
+ * @param message {@link Supplier} containing the {@link String message} and arguments to log.
+ * @see org.apache.commons.logging.Log#isInfoEnabled()
+ * @see org.apache.commons.logging.Log#info(Object)
+ * @see #getLog()
+ */
+ protected void logInfo(Supplier message) {
+
+ Log log = getLog();
+
+ if (log.isInfoEnabled()) {
+ log.info(message.get());
+ }
+ }
+
+ /**
+ * Logs the {@link String message} formatted with the array of {@link Object arguments} at warn level.
+ *
+ * @param message {@link String} containing the message to log.
+ * @param args array of {@link Object arguments} used to format the {@code message}.
+ * @see #logWarning(Supplier)
+ */
+ protected void logWarning(String message, Object... args) {
+ logWarning(StringFormatSupplier.of(message, args));
+ }
+
+ /**
+ * Logs the {@link String message} supplied by the given {@link Supplier} at warn level.
+ *
+ * @param message {@link Supplier} containing the {@link String message} and arguments to log.
+ * @see org.apache.commons.logging.Log#isWarnEnabled()
+ * @see org.apache.commons.logging.Log#warn(Object)
+ * @see #getLog()
+ */
+ protected void logWarning(Supplier message) {
+
+ Log log = getLog();
+
+ if (log.isWarnEnabled()) {
+ log.warn(message.get());
+ }
+ }
+
+ /**
+ * Logs the {@link String message} formatted with the array of {@link Object arguments} at error level.
+ *
+ * @param message {@link String} containing the message to log.
+ * @param args array of {@link Object arguments} used to format the {@code message}.
+ * @see #logError(Supplier)
+ */
+ protected void logError(String message, Object... args) {
+ logError(StringFormatSupplier.of(message, args));
+ }
+
+ /**
+ * Logs the {@link String message} supplied by the given {@link Supplier} at error level.
+ *
+ * @param message {@link Supplier} containing the {@link String message} and arguments to log.
+ * @see org.apache.commons.logging.Log#isErrorEnabled()
+ * @see org.apache.commons.logging.Log#error(Object)
+ * @see #getLog()
+ */
+ protected void logError(Supplier message) {
+
+ Log log = getLog();
+
+ if (log.isErrorEnabled()) {
+ log.error(message.get());
+ }
+ }
+
+ protected interface Supplier {
+
+ T get();
+
+ }
+
+ protected static class StringFormatSupplier implements Supplier {
+
+ private final Object[] args;
+
+ private final String message;
+
+ protected static StringFormatSupplier of(String message, Object... args) {
+ return new StringFormatSupplier(message, nullSafeArray(args, Object.class));
+ }
+
+ private StringFormatSupplier(String message, Object... args) {
+
+ Assert.hasText(message, "Message is required");
+
+ this.message = message;
+ this.args = args;
+ }
+
+ @Override
+ public String get() {
+ return String.format(this.message, this.args);
+ }
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java b/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java
index 17c681ab..8e994df0 100644
--- a/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java
+++ b/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java
@@ -17,20 +17,21 @@
package org.springframework.data.gemfire.util;
-import org.springframework.util.StringUtils;
-
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import org.springframework.util.StringUtils;
+
/**
- * CacheUtils is an abstract utility class encapsulating common operations for working with GemFire Cache
- * and ClientCache instances.
+ * {@link CacheUtils} is an abstract utility class encapsulating common operations for working with
+ * GemFire {@link Cache} and {@link ClientCache} instances.
*
* @author John Blum
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
@@ -52,6 +53,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isClient(GemFireCache cache) {
+
boolean client = (cache instanceof ClientCache);
if (cache instanceof GemFireCacheImpl) {
@@ -63,6 +65,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
public static boolean isDurable(ClientCache clientCache) {
+
DistributedSystem distributedSystem = getDistributedSystem(clientCache);
// NOTE technically the following code snippet would be more useful/valuable but is not "testable"!
@@ -75,6 +78,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isPeer(GemFireCache cache) {
+
boolean peer = (cache instanceof Cache);
if (cache instanceof GemFireCacheImpl) {
@@ -124,5 +128,21 @@ public abstract class CacheUtils extends DistributedSystemUtils {
catch (CacheClosedException ignore) {
return null;
}
+ catch (IllegalStateException ignore) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc) */
+ public static GemFireCache resolveGemFireCache() {
+
+ GemFireCache resolvedGemFireCache = getClientCache();
+
+ return (resolvedGemFireCache != null ? resolvedGemFireCache : getCache());
+ }
+
+ /* (non-Javadoc) */
+ public static String toRegionPath(String regionName) {
+ return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
}
}
diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.9.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.9.xsd
index 5b599ba4..67c24bfe 100644
--- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.9.xsd
+++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.9.xsd
@@ -2551,11 +2551,27 @@ Corresponds to the regionPath parameter in createIndex methods.
]]>
-
-
+
+
+
+
+
+
+
diff --git a/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java
index 4b385729..0be8c08c 100644
--- a/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java
+++ b/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java
@@ -16,22 +16,22 @@
package org.springframework.data.gemfire;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.junit.Assert.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.query.Index;
+import com.gemstone.gemfire.cache.query.IndexExistsException;
+import com.gemstone.gemfire.cache.query.IndexNameConflictException;
+import com.gemstone.gemfire.cache.query.QueryService;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -39,31 +39,50 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
-import com.gemstone.gemfire.cache.Cache;
-import com.gemstone.gemfire.cache.query.Index;
-import com.gemstone.gemfire.cache.query.IndexExistsException;
-
/**
- * The IndexConflictsIntegrationTest class...
+ * Integration tests with test cases testing the numerous conflicting {@link Index} configurations.
+ *
+ * An {@link IndexExistsException} is thrown when 2 or more {@link Index Indexes} share the same definition
+ * but have different names.
+ *
+ * An {@link IndexNameConflictException} is thrown when 2 or more {@link Index Indexes} share the same name
+ * but have potentially different definitions.
*
* @author John Blum
* @see org.junit.Test
- * @link https://jira.spring.io/browse/SGF-432
+ * @see org.springframework.context.ConfigurableApplicationContext
+ * @see org.springframework.context.annotation.Bean
+ * @see org.springframework.context.annotation.Configuration
+ * @see org.springframework.context.annotation.Import
+ * @see com.gemstone.gemfire.cache.GemFireCache
+ * @see com.gemstone.gemfire.cache.query.Index
+ * @see IndexFactoryBean traps IndexExistsException instead of IndexNameConflictException
+ * @see Improve IndexFactoryBean's resilience and options for handling GemFire IndexExistsExceptions and IndexNameConflictExceptions
* @since 1.6.3
*/
public class IndexConflictsIntegrationTest {
- protected void assertIndex(Index index, String expectedName, String expectedExpression, String expectedFromClause,
+ private static final AtomicBoolean IGNORE = new AtomicBoolean(false);
+ private static final AtomicBoolean OVERRIDE = new AtomicBoolean(false);
+
+ private ConfigurableApplicationContext applicationContext;
+
+ private void assertIndex(Index index, String expectedName, String expectedExpression, String expectedFromClause,
IndexType expectedType) {
- assertThat(index, is(notNullValue()));
- assertThat(index.getName(), is(equalTo(expectedName)));
- assertThat(index.getIndexedExpression(), is(equalTo(expectedExpression)));
- assertThat(index.getFromClause(), is(equalTo(expectedFromClause)));
- assertThat(IndexType.valueOf(index.getType()), is(equalTo(expectedType)));
+ assertThat(index).isNotNull();
+ assertThat(index.getName()).isEqualTo(expectedName);
+ assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression);
+ assertThat(index.getFromClause()).isEqualTo(expectedFromClause);
+ assertThat(IndexType.valueOf(index.getType())).isEqualTo(expectedType);
}
- protected boolean close(ConfigurableApplicationContext applicationContext) {
+ private void assertIndexCount(int count) {
+ assertThat(getIndexCount()).isEqualTo(count);
+ }
+
+ private boolean close(ConfigurableApplicationContext applicationContext) {
+
if (applicationContext != null) {
applicationContext.close();
return !(applicationContext.isActive() || applicationContext.isRunning());
@@ -72,185 +91,260 @@ public class IndexConflictsIntegrationTest {
return true;
}
+ private Index getIndex(String indexName) {
+
+ for (Index index : nullSafeCollection(getQueryService().getIndexes())) {
+ if (index.getName().equalsIgnoreCase(indexName)) {
+ return index;
+ }
+ }
+
+ return null;
+ }
+
+ private int getIndexCount() {
+ return nullSafeCollection(getQueryService().getIndexes()).size();
+ }
+
+ private QueryService getQueryService() {
+ return this.applicationContext.getBean("gemfireCache", GemFireCache.class).getQueryService();
+ }
+
+ private boolean hasIndex(String indexName) {
+ return (getIndex(indexName) != null);
+ }
+
+ private ConfigurableApplicationContext newApplicationContext(Class>... annotatedClasses) {
+ return new AnnotationConfigApplicationContext(annotatedClasses);
+ }
+
@Before
public void setup() {
- System.getProperties().remove("gemfire.cache.region.index.override");
-
- assertThat(System.getProperties().containsKey("gemfire.cache.region.index.override"), is(false));
+ assertThat(IGNORE.get()).isFalse();
+ assertThat(OVERRIDE.get()).isFalse();
}
- @Test(expected = BeanCreationException.class)
- public void indexDefinitionConflictThrowsException() {
- ConfigurableApplicationContext applicationContext = null;
+ @After
+ public void tearDown() {
+ OVERRIDE.set(false);
+ IGNORE.set(false);
+
+ assertThat(close(this.applicationContext)).isTrue();
+ }
+
+ @Test
+ public void indexDefinitionConflictIgnoresIndex() {
+
+ assertThat(IGNORE.compareAndSet(false, true)).isTrue();
+
+ this.applicationContext = newApplicationContext(IndexDefinitionConflictConfiguration.class);
+
+ assertThat(this.applicationContext.containsBean("customerIdIndex")).isTrue();
+ assertThat(this.applicationContext.containsBean("customerIdentifierIndex")).isTrue();
+ assertIndexCount(1);
+ assertThat(hasIndex("customerIdIndex")).isTrue();
+ assertThat(hasIndex("customerIdentifierIndex")).isFalse();
+
+ Index customersIdIndex = getIndex("customerIdIndex");
+
+ assertIndex(customersIdIndex, "customerIdIndex",
+ "id", "/Customers", IndexType.PRIMARY_KEY);
+ }
+
+ @Test
+ public void indexDefinitionConflictOverridesIndex() {
+
+ assertThat(OVERRIDE.compareAndSet(false, true)).isTrue();
+
+ this.applicationContext = newApplicationContext(IndexDefinitionConflictConfiguration.class);
+
+ assertThat(this.applicationContext.containsBean("customerIdIndex")).isTrue();
+ assertThat(this.applicationContext.containsBean("customerIdentifierIndex")).isTrue();
+ assertIndexCount(1);
+ assertThat(hasIndex("customerIdIndex")).isFalse();
+ assertThat(hasIndex("customerIdentifierIndex")).isTrue();
+
+ Index customersIdentifierIndex = getIndex("customerIdentifierIndex");
+
+ assertIndex(customersIdentifierIndex, "customerIdentifierIndex",
+ "id", "/Customers", IndexType.PRIMARY_KEY);
+ }
+
+ @Test(expected = IndexExistsException.class)
+ public void indexDefinitionConflictThrowsIndexExistsException() throws Throwable {
try {
- applicationContext = new AnnotationConfigApplicationContext(
- IndexDefinitionConflictGemFireConfiguration.class);
+ this.applicationContext = newApplicationContext(IndexDefinitionConflictConfiguration.class);
}
catch (BeanCreationException expected) {
- assertThat(expected.getMessage(), containsString("Error creating bean with name 'customerIdentityIndex'"
- + " defined in org.springframework.data.gemfire.IndexConflictsIntegrationTest$IndexDefinitionConflictGemFireConfiguration:"
- + " Invocation of init method failed"));
- assertThat(expected.getCause(), is(instanceOf(GemfireIndexException.class)));
- assertThat(expected.getCause().getMessage(),
- containsString("An Index with a different name having the same definition"
- + " as this Index (customerIdentityIndex) already exists"));
- assertThat(expected.getCause().getCause(), is(instanceOf(IndexExistsException.class)));
- assertThat(expected.getCause().getCause().getMessage(), is(equalTo("Similar Index Exists")));
- throw expected;
- }
- finally {
- assertThat(close(applicationContext), is(true));
+ assertThat(expected).hasMessageStartingWith("Error creating bean with name 'customerIdentifierIndex'");
+
+ assertThat(expected).hasCauseInstanceOf(GemfireIndexException.class);
+
+ String existingIndexDefinition = String.format(IndexFactoryBean.BASIC_INDEX_DEFINITION,
+ "id", "/Customers", IndexType.PRIMARY_KEY);
+
+ assertThat(expected.getCause()).hasMessageStartingWith(String.format(
+ "An Index with a different name [customerIdIndex] having the same definition [%s] already exists",
+ existingIndexDefinition));
+
+ assertThat(expected.getCause()).hasCauseInstanceOf(IndexExistsException.class);
+
+ assertThat(expected.getCause().getCause()).hasMessage("Similar Index Exists");
+
+ assertThat(expected.getCause().getCause()).hasNoCause();
+
+ throw expected.getCause().getCause();
}
}
@Test
- public void indexNameConflictOverridesExistingIndex() {
- ConfigurableApplicationContext applicationContext = null;
+ public void indexNameConflictIgnoresIndex() {
- try {
- applicationContext = new AnnotationConfigApplicationContext(IndexNameConflictGemFireConfiguration.class);
+ assertThat(IGNORE.compareAndSet(false, true)).isTrue();
- assertThat(applicationContext.getBeansOfType(Index.class).size(), is(equalTo(2)));
+ this.applicationContext = newApplicationContext(IndexNameConflictConfiguration.class);
- Cache gemfireCache = applicationContext.getBean("gemfireCache", Cache.class);
+ assertThat(this.applicationContext.containsBean("customerLastNameIndex")).isTrue();
+ assertThat(this.applicationContext.containsBean("customerFirstNameIndex")).isTrue();
+ assertIndexCount(1);
+ assertThat(hasIndex(IndexNameConflictConfiguration.INDEX_NAME)).isTrue();
- assertThat(gemfireCache.getQueryService().getIndexes().size(), is(equalTo(1)));
+ Index customerLastNameIndex = getIndex(IndexNameConflictConfiguration.INDEX_NAME);
- Index customerLastNameIndex = applicationContext.getBean("customerLastNameIndex", Index.class);
-
- assertIndex(customerLastNameIndex, IndexNameConflictGemFireConfiguration.INDEX_NAME,
- "lastName", "/Customers", IndexType.HASH);
-
- Index customerFirstNameIndex = applicationContext.getBean("customerFirstNameIndex", Index.class);
-
- assertIndex(customerFirstNameIndex, IndexNameConflictGemFireConfiguration.INDEX_NAME,
- "firstName", "/Customers", IndexType.FUNCTIONAL);
-
- assertThat(customerFirstNameIndex, is(not(sameInstance(customerLastNameIndex))));
- assertThat(gemfireCache.getQueryService().getIndexes().iterator().next(),
- is(sameInstance(customerFirstNameIndex)));
- }
- finally {
- assertThat(close(applicationContext), is(true));
- }
+ assertIndex(customerLastNameIndex, IndexNameConflictConfiguration.INDEX_NAME,
+ "lastName", "/Customers", IndexType.HASH);
}
@Test
- public void indexNameConflictReturnsExistingIndex() {
- ConfigurableApplicationContext applicationContext = null;
+ public void indexNameConflictOverridesIndex() {
+ assertThat(OVERRIDE.compareAndSet(false, true)).isTrue();
+
+ this.applicationContext = newApplicationContext(IndexNameConflictConfiguration.class);
+
+ assertThat(this.applicationContext.getBeansOfType(Index.class)).hasSize(2);
+ assertThat(this.applicationContext.containsBean("customerLastNameIndex")).isTrue();
+ assertThat(this.applicationContext.containsBean("customerFirstNameIndex")).isTrue();
+ assertIndexCount(1);
+ assertThat(hasIndex(IndexNameConflictConfiguration.INDEX_NAME)).isTrue();
+
+ Index customerFirstNameIndex = getIndex(IndexNameConflictConfiguration.INDEX_NAME);
+
+ assertIndex(customerFirstNameIndex, IndexNameConflictConfiguration.INDEX_NAME,
+ "firstName", "/Customers", IndexType.FUNCTIONAL);
+ }
+
+ @Test(expected = IndexNameConflictException.class)
+ public void indexNameConflictThrowsIndexNameConflictException() throws Throwable {
try {
- System.setProperty("gemfire.cache.region.index.override", Boolean.FALSE.toString());
-
- assertThat(System.getProperty("gemfire.cache.region.index.override", "true"),
- is(equalTo(Boolean.FALSE.toString())));
-
- applicationContext = new AnnotationConfigApplicationContext(IndexNameConflictGemFireConfiguration.class);
-
- assertThat(applicationContext.getBeansOfType(Index.class).size(), is(equalTo(2)));
-
- Cache gemfireCache = applicationContext.getBean("gemfireCache", Cache.class);
-
- assertThat(gemfireCache.getQueryService().getIndexes().size(), is(equalTo(1)));
-
- Index customerLastNameIndex = applicationContext.getBean("customerLastNameIndex", Index.class);
-
- assertIndex(customerLastNameIndex, IndexNameConflictGemFireConfiguration.INDEX_NAME,
- "lastName", "/Customers", IndexType.HASH);
-
- Index customerFirstNameIndex = applicationContext.getBean("customerFirstNameIndex", Index.class);
-
- assertIndex(customerFirstNameIndex, IndexNameConflictGemFireConfiguration.INDEX_NAME,
- "lastName", "/Customers", IndexType.HASH);
-
- assertThat(customerFirstNameIndex, is(sameInstance(customerLastNameIndex)));
- assertThat(gemfireCache.getQueryService().getIndexes().iterator().next(),
- is(sameInstance(customerLastNameIndex)));
+ this.applicationContext = newApplicationContext(IndexNameConflictConfiguration.class);
}
- finally {
- System.getProperties().remove("gemfire.cache.region.index.override");
+ catch (BeanCreationException expected) {
- if (applicationContext != null) {
- applicationContext.close();
- }
+ assertThat(expected).hasMessageStartingWith("Error creating bean with name 'customerFirstNameIndex'");
+
+ assertThat(expected).hasCauseInstanceOf(GemfireIndexException.class);
+
+ assertThat(expected.getCause()).hasMessageStartingWith(String.format(
+ "An Index with the same name [%s] having possibly a different definition already exists;",
+ IndexNameConflictConfiguration.INDEX_NAME));
+
+ assertThat(expected.getCause()).hasCauseInstanceOf(IndexNameConflictException.class);
+
+ assertThat(expected.getCause().getCause()).hasMessage(String.format("Index named ' %s ' already exists.",
+ IndexNameConflictConfiguration.INDEX_NAME));
+
+ assertThat(expected.getCause().getCause()).hasNoCause();
+
+ throw expected.getCause().getCause();
}
}
@Configuration
@SuppressWarnings("unused")
- public static class BaseGemFireConfiguration {
+ public static class GemFireConfiguration {
- @Bean
public Properties gemfireProperties() {
+
Properties gemfireProperties = new Properties();
+
gemfireProperties.setProperty("name", IndexConflictsIntegrationTest.class.getSimpleName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", "warning");
+
return gemfireProperties;
}
@Bean
public CacheFactoryBean gemfireCache() {
+
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean();
+
+ cacheFactoryBean.setClose(true);
cacheFactoryBean.setProperties(gemfireProperties());
- cacheFactoryBean.setUseBeanFactoryLocator(false);
+
return cacheFactoryBean;
}
@Bean(name = "Customers")
- public ReplicatedRegionFactoryBean customersRegion(Cache gemfireCache) {
+ public ReplicatedRegionFactoryBean customersRegion(GemFireCache gemfireCache) {
+
ReplicatedRegionFactoryBean customersRegionFactory = new ReplicatedRegionFactoryBean();
+
customersRegionFactory.setCache(gemfireCache);
- customersRegionFactory.setName("Customers");
+ customersRegionFactory.setClose(false);
customersRegionFactory.setPersistent(false);
+
return customersRegionFactory;
}
}
@Configuration
- @Import(BaseGemFireConfiguration.class)
+ @Import(GemFireConfiguration.class)
@SuppressWarnings("unused")
- public static class IndexDefinitionConflictGemFireConfiguration {
+ public static class IndexDefinitionConflictConfiguration {
@Bean
- public IndexFactoryBean customerIdIndex(Cache gemfireCache) {
+ public IndexFactoryBean customerIdIndex(GemFireCache gemfireCache) {
+
IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+
indexFactoryBean.setCache(gemfireCache);
indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Customers");
indexFactoryBean.setType(IndexType.PRIMARY_KEY);
+
return indexFactoryBean;
}
@Bean
@DependsOn("customerIdIndex")
- public IndexFactoryBean customerIdentityIndex(Cache gemfireCache) {
+ public IndexFactoryBean customerIdentifierIndex(GemFireCache gemfireCache) {
+
IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+
indexFactoryBean.setCache(gemfireCache);
indexFactoryBean.setExpression("id");
+ indexFactoryBean.setIgnoreIfExists(IGNORE.get());
indexFactoryBean.setFrom("/Customers");
+ indexFactoryBean.setOverride(OVERRIDE.get());
indexFactoryBean.setType(IndexType.PRIMARY_KEY);
+
return indexFactoryBean;
}
}
@Configuration
- @Import(BaseGemFireConfiguration.class)
+ @Import(GemFireConfiguration.class)
@SuppressWarnings("unused")
- public static class IndexNameConflictGemFireConfiguration {
+ public static class IndexNameConflictConfiguration {
protected static final String INDEX_NAME = "CustomerNameIdx";
@Bean
- public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
- return new PropertyPlaceholderConfigurer();
- }
-
- @Bean
- public IndexFactoryBean customerLastNameIndex(Cache gemfireCache,
- @Value("${gemfire.cache.region.index.override:true}") boolean override) {
+ public IndexFactoryBean customerLastNameIndex(GemFireCache gemfireCache) {
IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
@@ -258,7 +352,6 @@ public class IndexConflictsIntegrationTest {
indexFactoryBean.setExpression("lastName");
indexFactoryBean.setFrom("/Customers");
indexFactoryBean.setName(INDEX_NAME);
- indexFactoryBean.setOverride(override);
indexFactoryBean.setType(IndexType.HASH);
return indexFactoryBean;
@@ -266,20 +359,19 @@ public class IndexConflictsIntegrationTest {
@Bean
@DependsOn("customerLastNameIndex")
- public IndexFactoryBean customerFirstNameIndex(Cache gemfireCache,
- @Value("${gemfire.cache.region.index.override:true}") boolean override) {
+ public IndexFactoryBean customerFirstNameIndex(GemFireCache gemfireCache) {
IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
indexFactoryBean.setCache(gemfireCache);
indexFactoryBean.setExpression("firstName");
indexFactoryBean.setFrom("/Customers");
+ indexFactoryBean.setIgnoreIfExists(IGNORE.get());
indexFactoryBean.setName(INDEX_NAME);
- indexFactoryBean.setOverride(override);
+ indexFactoryBean.setOverride(OVERRIDE.get());
indexFactoryBean.setType(IndexType.FUNCTIONAL);
return indexFactoryBean;
}
}
-
}
diff --git a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java
index 5bc28f02..20c0075b 100644
--- a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java
+++ b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java
@@ -16,65 +16,59 @@
package org.springframework.data.gemfire;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.isA;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.hamcrest.Matchers.startsWith;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.data.gemfire.config.xml.GemfireConstants;
-import org.springframework.data.util.ReflectionUtils;
-
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.query.Index;
import com.gemstone.gemfire.cache.query.IndexExistsException;
-import com.gemstone.gemfire.cache.query.IndexInvalidException;
import com.gemstone.gemfire.cache.query.IndexNameConflictException;
import com.gemstone.gemfire.cache.query.IndexStatistics;
import com.gemstone.gemfire.cache.query.QueryService;
+import org.apache.commons.logging.Log;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.data.gemfire.config.xml.GemfireConstants;
+
/**
- * The IndexFactoryBeanTest class is a test suite of test cases testing the contract and functionality
- * of the IndexFactoryBean class.
+ * Unit tests for {@link IndexFactoryBean}.
*
* @author John Blum
* @see org.junit.Test
+ * @see org.junit.runner.RunWith
+ * @see org.mockito.Mock
+ * @see org.mockito.Mockito
+ * @see org.mockito.Spy
+ * @see org.mockito.runners.MockitoJUnitRunner
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see com.gemstone.gemfire.cache.Cache
* @see com.gemstone.gemfire.cache.client.ClientCache
@@ -82,27 +76,27 @@ import com.gemstone.gemfire.cache.query.QueryService;
* @see com.gemstone.gemfire.cache.query.QueryService
* @since 1.5.2
*/
+@RunWith(MockitoJUnitRunner.class)
public class IndexFactoryBeanTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
+ @Mock
+ private BeanFactory mockBeanFactory;
- private Cache mockCache = mock(Cache.class, "IndexFactoryBeanTest.MockCache");
+ @Mock
+ private Cache mockCache;
- private IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ @Spy
+ private IndexFactoryBean indexFactoryBean;
- private QueryService mockQueryService = mock(QueryService.class, "IndexFactoryBeanTest.MockQueryService");
+ @Mock
+ private Log mockLog;
- protected IndexFactoryBean newIndexFactoryBean() {
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean() {
- @Override QueryService lookupQueryService() {
- return mockQueryService;
- }
- };
+ @Mock
+ private QueryService mockQueryService;
- indexFactoryBean.setCache(mockCache);
-
- return indexFactoryBean;
+ @Before
+ public void setup() {
+ when(mockCache.getQueryService()).thenReturn(mockQueryService);
}
@After
@@ -110,26 +104,67 @@ public class IndexFactoryBeanTest {
indexFactoryBean.setBeanFactory(null);
indexFactoryBean.setCache(null);
indexFactoryBean.setDefine(false);
+ indexFactoryBean.setExpression(null);
+ indexFactoryBean.setFrom(null);
+ indexFactoryBean.setImports(null);
+ indexFactoryBean.setQueryService(null);
+ indexFactoryBean.setType((IndexType) null);
}
- @Test
- public void afterPropertiesSetIsSuccessful() throws Exception {
- BeanFactory mockBeanFactory = mock(BeanFactory.class, "testAfterPropertiesSetIsSuccessful.MockBeanFactory");
+ private Index mockIndex(String name) {
- Cache mockCache = mock(Cache.class, "testAfterPropertiesSetIsSuccessful.MockCache");
+ Index mockIndex = mock(Index.class, name);
- Index mockIndex = mock(Index.class, "testAfterPropertiesSetIsSuccessful.MockIndex");
+ when(mockIndex.getName()).thenReturn(name);
- QueryService mockQueryService = mock(QueryService.class, "testAfterPropertiesSetIsSuccessful.MockQueryService");
+ return mockIndex;
+ }
- when(mockBeanFactory.containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE))).thenReturn(false);
- when(mockCache.getQueryService()).thenReturn(mockQueryService);
- when(mockQueryService.createKeyIndex(eq("TestKeyIndex"), eq("id"), eq("/Example"))).thenReturn(mockIndex);
+ private Index mockIndexWithDefinition(String name, String expression, String fromClause, IndexType type) {
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ Index mockIndex = mockIndex(name);
+
+ when(mockIndex.getIndexedExpression()).thenReturn(expression);
+ when(mockIndex.getFromClause()).thenReturn(fromClause);
+ when(mockIndex.getType()).thenReturn(type.getGemfireIndexType());
+
+ return mockIndex;
+ }
+
+ private QueryService mockQueryService(String name) {
+ return mock(QueryService.class, name);
+ }
+
+ private IndexFactoryBean newIndexFactoryBean() {
+
+ IndexFactoryBean indexFactoryBean = spy(new IndexFactoryBean() {
+ @Override
+ protected Log newLog() {
+ return mockLog;
+ }
+ });
indexFactoryBean.setBeanFactory(mockBeanFactory);
indexFactoryBean.setCache(mockCache);
+ indexFactoryBean.setQueryService(mockQueryService);
+
+ return indexFactoryBean;
+ }
+
+ @Test
+ @SuppressWarnings("all")
+ public void afterPropertiesSetIsSuccessful() throws Exception {
+
+ ConfigurableBeanFactory mockConfigurableBeanFactory = mock(ConfigurableBeanFactory.class);
+
+ Index mockIndex = mock(Index.class, "testAfterPropertiesSetIsSuccessful.MockIndex");
+
+ when(mockQueryService.createKeyIndex(eq("TestKeyIndex"), eq("id"), eq("/Example"))).thenReturn(mockIndex);
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setBeanFactory(mockConfigurableBeanFactory);
+ indexFactoryBean.setBeanName("KeyIndexBean");
indexFactoryBean.setDefine(false);
indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Example");
@@ -137,133 +172,209 @@ public class IndexFactoryBeanTest {
indexFactoryBean.setType("key");
indexFactoryBean.afterPropertiesSet();
- assertEquals(mockIndex, indexFactoryBean.getObject());
- assertSame(mockIndex, indexFactoryBean.getObject()); // assert Index really is a 'Singleton'
- assertTrue(Index.class.isAssignableFrom(indexFactoryBean.getObjectType()));
- assertTrue(indexFactoryBean.isSingleton());
+ assertThat(indexFactoryBean.getIndex()).isEqualTo(mockIndex);
- verify(mockBeanFactory, times(1)).containsBean(
- eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
- verify(mockCache, times(1)).getQueryService();
- verify(mockQueryService, times(1)).createKeyIndex(eq("TestKeyIndex"), eq("id"), eq("/Example"));
+ Index actualIndex = indexFactoryBean.getObject();
+
+ assertThat(actualIndex).isEqualTo(mockIndex);
+ assertThat(indexFactoryBean.getObject()).isSameAs(actualIndex);
+ assertThat(Index.class).isAssignableFrom(indexFactoryBean.getObjectType());
+ assertThat(indexFactoryBean.isSingleton()).isTrue();
+
+ verify(indexFactoryBean, times(1)).getBeanName();
+ verify(indexFactoryBean, never()).lookupQueryService();
+ verify(mockConfigurableBeanFactory, times(1))
+ .registerAlias(eq("KeyIndexBean"), eq("TestKeyIndex"));
+ verify(mockQueryService, times(1))
+ .createKeyIndex(eq("TestKeyIndex"), eq("id"), eq("/Example"));
+ verifyZeroInteractions(mockCache);
}
@Test(expected = IllegalArgumentException.class)
+ public void afterPropertiesSetWithNoIndexName() throws Exception {
+ try {
+ newIndexFactoryBean().afterPropertiesSet();
+ }
+ catch (IllegalArgumentException expected) {
+ assertThat(expected).hasMessage("Index name is required");
+ assertThat(expected).hasNoCause();
+
+ throw expected;
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
public void afterPropertiesSetWithNullCache() throws Exception {
try {
new IndexFactoryBean().afterPropertiesSet();
}
- catch (IllegalArgumentException expected) {
- assertEquals("The GemFire Cache reference must not be null!", expected.getMessage());
+ catch (IllegalStateException expected) {
+ assertThat(expected).hasMessage("Cache is required");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = IllegalStateException.class)
public void afterPropertiesSetWithNullQueryService() throws Exception {
- try {
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean() {
- @Override QueryService lookupQueryService() {
- return null;
- }
- };
+ IndexFactoryBean indexFactoryBean = spy(new IndexFactoryBean());
+
+ doReturn(null).when(indexFactoryBean).lookupQueryService();
+
+ try {
indexFactoryBean.setCache(mockCache);
+ indexFactoryBean.setName("TestIndex");
indexFactoryBean.afterPropertiesSet();
}
- catch (IllegalArgumentException expected) {
- assertEquals("QueryService is required to create an Index", expected.getMessage());
+ catch (IllegalStateException expected) {
+ assertThat(expected).hasMessage("QueryService is required to create an Index");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
+ finally {
+ verify(indexFactoryBean, times(1)).lookupQueryService();
+ }
}
@Test(expected = IllegalArgumentException.class)
public void afterPropertiesSetWithUnspecifiedExpression() throws Exception {
try {
- newIndexFactoryBean().afterPropertiesSet();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
- assertEquals("Index 'expression' is required", expected.getMessage());
+ assertThat(expected).hasMessage("Index expression is required");
+ assertThat(expected).hasNoCause();
+
+ throw expected;
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void afterPropertiesSetWithUnspecifiedFromClause() throws Exception {
+ try {
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.afterPropertiesSet();
+ }
+ catch (Exception expected) {
+ assertThat(expected).hasMessage("Index from clause is required");
+ assertThat(expected).hasNoCause();
+
+ throw expected;
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void afterPropertiesSetUsingImportsWithInvalidIndexKeyType() throws Exception {
+ try {
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setImports("org.example.DomainType");
+ indexFactoryBean.setType("PriMary_Key");
+ indexFactoryBean.afterPropertiesSet();
+ }
+ catch (IllegalArgumentException expected) {
+ assertThat(expected).hasMessage("Imports are not supported with a KEY Index");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
@Test
- public void afterPropertiesSetWithUnspecifiedFromClause() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectCause(is(nullValue(Throwable.class)));
- expectedException.expectMessage("Index 'from clause' is required");
-
- IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
-
- indexFactoryBean.setExpression("id");
- indexFactoryBean.afterPropertiesSet();
+ public void resolveCacheFromCacheProperty() {
+ assertThat(newIndexFactoryBean().resolveCache()).isSameAs(mockCache);
}
- @Test(expected = IllegalArgumentException.class)
- public void afterPropertiesSetWithUnspecifiedIndexName() throws Exception {
+ @Test(expected = IllegalStateException.class)
+ public void resolveCacheThrowsExceptionForUnresolvableCache() {
try {
IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- indexFactoryBean.setExpression("id");
- indexFactoryBean.setFrom("/Example");
- indexFactoryBean.afterPropertiesSet();
+ indexFactoryBean.setCache(null);
+ indexFactoryBean.resolveCache();
}
- catch (IllegalArgumentException expected) {
- assertEquals("Index 'name' is required", expected.getMessage());
+ catch (IllegalStateException expected) {
+ assertThat(expected).hasMessage("Cache is required");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
+ @Test
+ public void resolveIndexNameFromBeanNameProperty() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setBeanName("TestIndexBeanName");
+ indexFactoryBean.setName(null);
+
+ assertThat(indexFactoryBean.resolveIndexName()).isEqualTo("TestIndexBeanName");
+ }
+
+ @Test
+ public void resolveIndexNameFromNameProperty() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setBeanName("TestIndexBeanName");
+ indexFactoryBean.setName("TestIndex");
+
+ assertThat(indexFactoryBean.resolveIndexName()).isEqualTo("TestIndex");
+ }
+
@Test(expected = IllegalArgumentException.class)
- public void afterPropertiesSetUsingImportsWithInvalidType() throws Exception {
+ public void resolveIndexNameThrowsExceptionForUnresolvableIndexName() {
try {
IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- indexFactoryBean.setExpression("id");
- indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setImports("org.example.DomainType");
- indexFactoryBean.setName("TestIndex");
- indexFactoryBean.setType("PriMary_Key");
- indexFactoryBean.afterPropertiesSet();
+ indexFactoryBean.setBeanName(null);
+ indexFactoryBean.setName(null);
+ indexFactoryBean.resolveIndexName();
}
catch (IllegalArgumentException expected) {
- assertEquals("'imports' are not supported with a KEY Index", expected.getMessage());
+ assertThat(expected).hasMessage("Index name is required");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
@Test
public void doLookupQueryService() {
- QueryService mockQueryServiceOne = mock(QueryService.class, "testLookupQueryService.MockQueryService.One");
- QueryService mockQueryServiceTwo = mock(QueryService.class, "testLookupQueryService.MockQueryService.Two");
- Cache mockCache = mock(Cache.class, "testDoLookupQueryService.MockCache");
+ QueryService mockQueryServiceOne = mockQueryService("testDoLookupQueryService.MockQueryService.One");
- when(mockCache.getQueryService()).thenReturn(mockQueryServiceTwo);
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
-
- indexFactoryBean.setCache(mockCache);
indexFactoryBean.setQueryService(mockQueryServiceOne);
- assertSame(mockQueryServiceOne, indexFactoryBean.doLookupQueryService());
+ assertThat(indexFactoryBean.doLookupQueryService()).isSameAs(mockQueryServiceOne);
verify(mockCache, never()).getQueryService();
}
@Test
public void doLookupQueryServiceOnClientCache() {
- ClientCache mockClientCache = mock(ClientCache.class, "testDoLookupQueryServiceOnClientCache.MockClientCache");
- QueryService mockQueryService = mock(QueryService.class, "testDoLookupQueryServiceOnClientCache.MockQueryService");
+ ClientCache mockClientCache = mock(ClientCache.class);
+ QueryService mockQueryService = mockQueryService("testDoLookupQueryServiceOnClientCache.MockQueryService");
when(mockClientCache.getLocalQueryService()).thenReturn(mockQueryService);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setCache(mockClientCache);
indexFactoryBean.setQueryService(null);
- assertSame(mockQueryService, indexFactoryBean.doLookupQueryService());
+ assertThat(indexFactoryBean.doLookupQueryService()).isSameAs(mockQueryService);
verify(mockClientCache, times(1)).getLocalQueryService();
verify(mockClientCache, never()).getQueryService();
@@ -271,399 +382,824 @@ public class IndexFactoryBeanTest {
@Test
public void doLookupQueryServiceOnPeerCache() {
- Cache mockCache = mock(Cache.class, "testDoLookupQueryServiceOnPeerCache.MockCache");
- QueryService mockQueryService = mock(QueryService.class, "testDoLookupQueryServiceOnPeerCache.MockQueryService");
-
- when(mockCache.getQueryService()).thenReturn(mockQueryService);
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setCache(mockCache);
indexFactoryBean.setQueryService(null);
- assertSame(mockQueryService, indexFactoryBean.doLookupQueryService());
+ assertThat(indexFactoryBean.doLookupQueryService()).isSameAs(mockQueryService);
verify(mockCache, times(1)).getQueryService();
}
@Test
public void lookupQueryServiceFromBeanFactory() {
- BeanFactory mockBeanFactory = mock(BeanFactory.class, "testLookupQueryServiceFromBeanFactory.MockBeanFactory");
- QueryService mockQueryService = mock(QueryService.class, "testLookupQueryServiceFromBeanFactory.MockQueryService");
+ QueryService mockQueryService =
+ mockQueryService("testLookupQueryServiceFromBeanFactory.MockQueryService");
when(mockBeanFactory.containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE)))
.thenReturn(true);
when(mockBeanFactory.getBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
eq(QueryService.class))).thenReturn(mockQueryService);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- indexFactoryBean.setBeanFactory(mockBeanFactory);
+ assertThat(indexFactoryBean.lookupQueryService()).isSameAs(mockQueryService);
- QueryService actualQueryService = indexFactoryBean.lookupQueryService();
-
- assertSame(mockQueryService, actualQueryService);
-
- verify(mockBeanFactory, times(1)).containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
- verify(mockBeanFactory, times(1)).getBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
- eq(QueryService.class));
+ verify(mockBeanFactory, times(1)).containsBean(
+ eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
+ verify(mockBeanFactory, times(1)).getBean(
+ eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE), eq(QueryService.class));
+ verify(mockCache, never()).getQueryService();
}
@Test
public void lookupQueryServiceFromCache() {
- BeanFactory mockBeanFactory = mock(BeanFactory.class, "testLookupQueryServiceFromCache.MockBeanFactory");
+
+ QueryService mockQueryService = mockQueryService("testLookupQueryServiceFromCache.MockQueryService");
when(mockBeanFactory.containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE)))
.thenReturn(false);
+ when(mockCache.getQueryService()).thenReturn(mockQueryService);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- indexFactoryBean.setBeanFactory(mockBeanFactory);
indexFactoryBean.setDefine(false);
- indexFactoryBean.setQueryService(mockQueryService);
+ indexFactoryBean.setQueryService(null);
- QueryService actualQueryService = indexFactoryBean.lookupQueryService();
+ assertThat(indexFactoryBean.lookupQueryService()).isSameAs(mockQueryService);
- assertSame(mockQueryService, actualQueryService);
+ verify(mockBeanFactory, times(1)).containsBean(
+ eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
+ verify(mockBeanFactory, never()).getBean(
+ eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE), eq(QueryService.class));
+ verify(mockCache, times(1)).getQueryService();
+ }
- verify(mockBeanFactory, times(1)).containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
- verify(mockBeanFactory, never()).getBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
- eq(QueryService.class));
+ @Test
+ public void resolveQueryServiceReturnsIndexFactoryBeanConfiguredQueryService() {
+ assertThat(newIndexFactoryBean().resolveQueryService()).isSameAs(mockQueryService);
+ }
+
+ @Test
+ public void resolveQueryServiceReturnsQueryServiceFromLookup() {
+
+ QueryService mockQueryService =
+ mockQueryService("testResolveQueryServiceReturnsQueryServiceFromLookup.MockQueryService");
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setQueryService(null);
+
+ doReturn(mockQueryService).when(indexFactoryBean).lookupQueryService();
+
+ assertThat(indexFactoryBean.resolveQueryService()).isSameAs(mockQueryService);
+
+ verify(indexFactoryBean, times(1)).lookupQueryService();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void resolveQueryServiceThrowsExceptionForUnresolvableQueryService() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ try {
+ indexFactoryBean.setQueryService(null);
+ doReturn(null).when(indexFactoryBean).lookupQueryService();
+ indexFactoryBean.resolveQueryService();
+ }
+ catch (IllegalStateException expected) {
+ assertThat(expected).hasMessage("QueryService is required to create an Index");
+ assertThat(expected).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+ verify(indexFactoryBean, times(1)).lookupQueryService();
+ }
}
@Test
public void registerQueryServiceBeanWhenIndexIsCreated() {
+
ConfigurableBeanFactory mockBeanFactory = mock(ConfigurableBeanFactory.class,
"testRegisterQueryServiceBeanWhenIndexIsCreated.MockBeanFactory");
- QueryService mockQueryService = mock(QueryService.class, "testRegisterQueryServiceBeanWhenIndexIsCreated.MockQueryService");
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setBeanFactory(mockBeanFactory);
indexFactoryBean.setDefine(false);
- assertSame(mockQueryService, indexFactoryBean.registerQueryServiceBean(mockQueryService));
+ assertThat(indexFactoryBean.registerQueryServiceBean("queryServiceBeanName", mockQueryService))
+ .isSameAs(mockQueryService);
- verify(mockBeanFactory, never()).registerSingleton(
- eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE), same(mockQueryService));
+ verify(mockBeanFactory, never()).registerSingleton(eq("queryServiceBeanName"), same(mockQueryService));
}
@Test
public void registerQueryServiceBeanWhenIndexIsDefined() {
+
ConfigurableBeanFactory mockBeanFactory = mock(ConfigurableBeanFactory.class,
"testRegisterQueryServiceBeanWhenIndexIsDefined.MockBeanFactory");
- QueryService mockQueryService = mock(QueryService.class, "testRegisterQueryServiceBeanWhenIndexIsDefined.MockQueryService");
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setBeanFactory(mockBeanFactory);
indexFactoryBean.setDefine(true);
- assertSame(mockQueryService, indexFactoryBean.registerQueryServiceBean(mockQueryService));
+ assertThat(indexFactoryBean.registerQueryServiceBean("queryServiceBeanName", mockQueryService))
+ .isSameAs(mockQueryService);
- verify(mockBeanFactory, times(1)).registerSingleton(
- eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE), same(mockQueryService));
+ verify(mockBeanFactory, times(1))
+ .registerSingleton(eq("queryServiceBeanName"), same(mockQueryService));
}
@Test
- public void createIndexReturningNewKeyIndex() throws Exception {
- Index mockIndex = mock(Index.class, "createIndexReturningNewKeyIndex.MockIndex");
+ public void registerAliasWhenBeanFactoryIsNull() {
- QueryService mockQueryService = mock(QueryService.class, "createIndexReturningNewKeyIndex.MockQueryService");
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
- when(mockQueryService.createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"))).thenReturn(mockIndex);
+ indexFactoryBean.setBeanFactory(null);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ indexFactoryBean.registerAlias("IndexBean", "TestIndex");
+ }
+
+ @Test
+ public void registerAliasWhenBeanFactoryIsNotConfigurable() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.registerAlias("IndexBean", "TestIndex");
+
+ verifyZeroInteractions(mockBeanFactory);
+ }
+
+ @Test
+ public void registerAliasWhenBeanNameAndIndexNameMatch() {
+
+ ConfigurableBeanFactory mockConfigurableBeanFactory = mock(ConfigurableBeanFactory.class);
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setBeanFactory(mockConfigurableBeanFactory);
+ indexFactoryBean.registerAlias("TestIndex", "TestIndex");
+
+ assertThat(indexFactoryBean.getBeanFactory()).isSameAs(mockConfigurableBeanFactory);
+
+ verifyZeroInteractions(mockConfigurableBeanFactory);
+ }
+
+ @Test
+ public void registerAliasWhenBeanNameAndIndexNameAreDifferent() {
+
+ ConfigurableBeanFactory mockConfigurableBeanFactory = mock(ConfigurableBeanFactory.class);
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setBeanFactory(mockConfigurableBeanFactory);
+ indexFactoryBean.registerAlias("IndexBean", "TestIndex");
+
+ assertThat(indexFactoryBean.getBeanFactory()).isSameAs(mockConfigurableBeanFactory);
+
+ verify(mockConfigurableBeanFactory, times(1))
+ .registerAlias(eq("IndexBean"), eq("TestIndex"));
+ }
+
+ @Test
+ public void createIndexReturnsNewKeyIndex() throws Exception {
+
+ Index mockIndex = mockIndex("testCreateIndexReturnsNewKeyIndex.MockIndex");
+
+ when(mockQueryService.createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example")))
+ .thenReturn(mockIndex);
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Example");
indexFactoryBean.setName("KeyIndex");
- indexFactoryBean.setOverride(false);
indexFactoryBean.setType("key");
Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "KeyIndex");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
- verify(mockQueryService, times(1)).createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"));
+ verify(mockQueryService, times(1))
+ .createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"));
}
@Test
- public void createIndexReturningNewHashIndex() throws Exception {
- Index mockIndex = mock(Index.class, "createIndexReturningNewHashIndex.MockIndex");
+ public void createIndexReturnsNewHashIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "createIndexReturningNewHashIndex.MockQueryService");
+ Index mockIndex = mockIndex("testCreateIndexReturnsNewHashIndex.MockIndex");
- when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
when(mockQueryService.createHashIndex(eq("HashIndex"), eq("name"), eq("/Animals"), eq("org.example.Dog")))
.thenReturn(mockIndex);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setExpression("name");
indexFactoryBean.setFrom("/Animals");
indexFactoryBean.setImports("org.example.Dog");
indexFactoryBean.setName("HashIndex");
- indexFactoryBean.setOverride(false);
indexFactoryBean.setType("HasH");
Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "HashIndex");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
- verify(mockQueryService, times(1)).createHashIndex(eq("HashIndex"), eq("name"), eq("/Animals"),
- eq("org.example.Dog"));
+ verify(mockQueryService, times(1))
+ .createHashIndex(eq("HashIndex"), eq("name"), eq("/Animals"), eq("org.example.Dog"));
}
@Test
- public void createIndexReturningNewFunctionalIndex() throws Exception {
- Index mockIndex = mock(Index.class, "createIndexReturningNewFunctionalIndex.MockIndex");
+ public void createIndexReturnsNewFunctionalIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class,
- "createIndexReturningNewFunctionalIndex.MockQueryService");
+ Index mockIndex = mockIndex("testCreateIndexReturnsNewFunctionalIndex.MockIndex");
- when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
when(mockQueryService.createIndex(eq("FunctionalIndex"), eq("someField"), eq("/Example")))
.thenReturn(mockIndex);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setExpression("someField");
indexFactoryBean.setFrom("/Example");
indexFactoryBean.setImports(" ");
indexFactoryBean.setName("FunctionalIndex");
- indexFactoryBean.setOverride(false);
indexFactoryBean.setType((String) null);
Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "FunctionalIndex");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
- verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndex"), eq("someField"), eq("/Example"));
+ verify(mockQueryService, times(1))
+ .createIndex(eq("FunctionalIndex"), eq("someField"), eq("/Example"));
}
- @Test
- public void createIndexOverridesExistingIndex() throws Exception {
- Index mockExistingIndex = mock(Index.class, "createIndexOverridesExistingIndex.MockExistingIndex");
- Index mockOverridingIndex = mock(Index.class, "createIndexOverridesExistingIndex.MockOverridingIndex");
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexExistsException() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "createIndexOverridesExistingIndex.MockQueryService");
+ Index mockIndex =
+ mockIndexWithDefinition("MockIndex", "id", "/Example", IndexType.PRIMARY_KEY);
- when(mockExistingIndex.getName()).thenReturn("ExistingIndex");
- when(mockOverridingIndex.getName()).thenReturn("OverridingIndex");
- when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockExistingIndex));
- when(mockQueryService.createHashIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"),
- eq("example.DomainType"))).thenReturn(mockOverridingIndex);
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- indexFactoryBean.setExpression("someField");
+ doThrow(new IndexExistsException("TEST")).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
+
+ indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setImports("example.DomainType");
- indexFactoryBean.setName("OverridingIndex");
- indexFactoryBean.setType("HASH");
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
- Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "ExistingIndex");
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isFalse();
- assertSame(mockOverridingIndex, actualIndex);
+ try {
+ indexFactoryBean.createIndex(mockQueryService, "TestIndex");
+ }
+ catch (GemfireIndexException expected) {
- verifyZeroInteractions(mockOverridingIndex);
- verify(mockExistingIndex, times(1)).getName();
- verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex));
- verify(mockQueryService, times(1)).createHashIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"),
- eq("example.DomainType"));
+ assertThat(expected).hasMessageStartingWith(String.format(
+ "An Index with a different name [MockIndex] having the same definition [%s] already exists;"
+ + " You may attempt to override the existing Index [MockIndex] with the new name [TestIndex]"
+ + " by setting the 'override' property to 'true'", indexFactoryBean.toBasicIndexDefinition()));
+
+ assertThat(expected).hasCauseInstanceOf(IndexExistsException.class);
+ assertThat(expected.getCause()).hasMessage("TEST");
+ assertThat(expected.getCause()).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+ verify(mockQueryService, times(1)).getIndexes();
+
+ verify(indexFactoryBean, times(1))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+ }
+ }
+
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexExistsExceptionAndCannotFindExistingIndexByDefinition() throws Exception {
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexExistsException("TEST")).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
+
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setIgnoreIfExists(true);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.KEY);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+
+ try {
+ indexFactoryBean.createIndex(mockQueryService, "TestIndex");
+ }
+ catch (GemfireIndexException expected) {
+
+ assertThat(expected).hasMessageStartingWith(String.format(
+ "An Index with a different name [unknown] having the same definition [%s] already exists;"
+ + " You may attempt to override the existing Index [unknown] with the new name [TestIndex]"
+ + " by setting the 'override' property to 'true'", indexFactoryBean.toBasicIndexDefinition()));
+
+ assertThat(expected).hasCauseInstanceOf(IndexExistsException.class);
+ assertThat(expected.getCause()).hasMessage("TEST");
+ assertThat(expected.getCause()).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+ verify(mockQueryService, times(1)).getIndexes();
+
+ verify(indexFactoryBean, times(1))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+ }
}
@Test
- public void createIndexReturnsExistingIndex() throws Exception {
- Index mockExistingIndex = mock(Index.class, "createIndexReturnsExistingIndex.MockExistingIndex");
- Index mockNewIndex = mock(Index.class, "createIndexReturnsExistingIndex.MockNewIndex");
+ public void createIndexThrowsIndexExistsExceptionAndIgnoresThisIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "createIndexReturnsExistingIndex.MockQueryService");
+ Index mockIndex =
+ mockIndexWithDefinition("MockIndex", "id", "/Example", IndexType.PRIMARY_KEY);
- when(mockExistingIndex.getName()).thenReturn("ExistingIndex");
- when(mockNewIndex.getName()).thenReturn("NewIndex");
- when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockExistingIndex, mockNewIndex));
+ when(mockLog.isWarnEnabled()).thenReturn(true);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
- indexFactoryBean.setName("ExistingIndex");
- indexFactoryBean.setOverride(false);
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "ExistingIndex");
+ doThrow(new IndexExistsException("TEST")).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
- assertSame(mockExistingIndex, actualIndex);
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setIgnoreIfExists(true);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(mockIndex);
+
+ verify(indexFactoryBean, times(1))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+
+ verify(mockLog, times(1)).warn(
+ eq(String.format("WARNING! You are choosing to ignore this Index [TestIndex] and return the existing Index"
+ + " having the same basic definition [%s] but with a different name [MockIndex];"
+ + " Make sure no OQL Query Hints refer to this Index by name [TestIndex]",
+ indexFactoryBean.toBasicIndexDefinition())));
- verify(mockExistingIndex, times(1)).getName();
- verify(mockNewIndex, never()).getName();
verify(mockQueryService, times(1)).getIndexes();
}
@Test
- public void createIndexThrowsIndexNameConflictExceptionOnOverride() throws Exception {
- Index mockExistingIndex = mock(Index.class,
- "createIndexThrowsIndexNameConflictExceptionOnOverride.MockExistingIndex");
+ public void createIndexThrowsIndexExistsExceptionAndOverridesExistingIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class,
- "createIndexThrowsIndexNameConflictExceptionOnOverride.MockQueryService");
+ Index mockIndex =
+ mockIndexWithDefinition("MockIndex", "id", "/Example", IndexType.PRIMARY_KEY);
- when(mockExistingIndex.getName()).thenReturn("ExistingIndex");
- when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockExistingIndex));
- when(mockQueryService.createIndex(any(String.class), any(String.class), any(String.class)))
- .thenThrow(new IndexNameConflictException("TEST"));
+ Index testIndex =
+ mockIndexWithDefinition("TestIndex", "id", "/Example", IndexType.PRIMARY_KEY);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ when(mockLog.isWarnEnabled()).thenReturn(true);
- indexFactoryBean.setExpression("someField");
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexExistsException("TEST")).doReturn(testIndex).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
+
+ indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setName("ExistingIndex");
- indexFactoryBean.setType("Functional");
-
- try {
- expectedException.expect(GemfireIndexException.class);
- expectedException.expectCause(isA(IndexNameConflictException.class));
- expectedException.expectMessage(
- "Failed to remove the existing Index on override before re-creating Index with name (ExistingIndex)");
-
- indexFactoryBean.createIndex(mockQueryService, "ExistingIndex");
- }
- finally {
- verify(mockExistingIndex, times(1)).getName();
- verify(mockQueryService, times(1)).getIndexes();
- verify(mockQueryService, times(1)).createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"));
- }
- }
-
- @Test
- public void createIndexThrowsIndexExistsException() throws Exception {
- QueryService mockQueryService = mock(QueryService.class,
- "createIndexThrowsIndexExistsException.MockQueryService");
-
- when(mockQueryService.getIndexes()).thenReturn(null);
- when(mockQueryService.createKeyIndex(eq("NewIndex"), eq("someField"), eq("/Example")))
- .thenThrow(new IndexExistsException("TEST"));
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
-
- indexFactoryBean.setExpression("someField");
- indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setName("NewIndex");
+ indexFactoryBean.setIgnoreIfExists(false);
+ indexFactoryBean.setName("TestIndex");
indexFactoryBean.setOverride(true);
- indexFactoryBean.setType("PRIMARY_KEY");
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
- try {
- expectedException.expect(GemfireIndexException.class);
- expectedException.expectCause(isA(IndexExistsException.class));
- expectedException.expectMessage(
- "An Index with a different name having the same definition as this Index (NewIndex) already exists");
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(testIndex);
- indexFactoryBean.createIndex(mockQueryService, "NewIndex");
- }
- finally {
- verify(mockQueryService, times(1)).getIndexes();
- verify(mockQueryService, never()).removeIndex(any(Index.class));
- verify(mockQueryService, times(1)).createKeyIndex(eq("NewIndex"), eq("someField"), eq("/Example"));
- }
+ verify(indexFactoryBean, times(2))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+
+ verify(mockLog, times(1)).warn(
+ eq(String.format("WARNING! You are attempting to 'override' an existing Index [MockIndex]"
+ + " having the same basic definition [%s] as the Index that will be created by this"
+ + " IndexFactoryBean [TestIndex]; 'Override' effectively 'renames' the existing Index [MockIndex]"
+ + " by removing it then recreating it under the new name [TestIndex] with the same definition;"
+ + " You should be careful to update any existing OQL Query Hints referring to the old"
+ + " Index name [MockIndex] to now use the new name [TestIndex]",
+ indexFactoryBean.toBasicIndexDefinition())));
+
+ verify(mockQueryService, times(1)).getIndexes();
}
- @Test
- public void createIndexAddsExistingIndexOnAnyException() throws Exception {
- final Index mockExistingIndex = mock(Index.class, "createIndexAddsExistingIndexOnAnyException.MockExistingIndex");
- final Index mockIndexTwo = mock(Index.class, "createIndexAddsExistingIndexOnException.MockIndexTwo");
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexExistsExceptionAndOverrideThrowsRuntimeException() throws Exception {
- final List indexes = new ArrayList(1);
+ Index mockIndex =
+ mockIndexWithDefinition("MockIndex", "id", "/Example", IndexType.PRIMARY_KEY);
- indexes.add(mockIndexTwo);
+ when(mockLog.isWarnEnabled()).thenReturn(true);
- QueryService mockQueryService = mock(QueryService.class,
- "createIndexAddsExistingIndexOnAnyException.MockQueryService");
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex))
+ .thenReturn(Collections.emptyList());
- when(mockExistingIndex.getName()).thenReturn("ExistingIndex");
- when(mockIndexTwo.getName()).thenReturn("NewIndex");
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
- when(mockQueryService.getIndexes()).then(new Answer>() {
- private boolean called = false;
+ doThrow(new IndexExistsException("TEST")).doThrow(new RuntimeException("RETRY")).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
- private synchronized boolean wasCalledOnce() {
- boolean localCalled = this.called;
- this.called = true;
- return localCalled;
- }
-
- @Override
- public Collection answer(final InvocationOnMock invocationOnMock) throws Throwable {
- return (wasCalledOnce() ? indexes : Collections.singletonList(mockExistingIndex));
- }
- });
-
- when(mockQueryService.createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example")))
- .thenThrow(new RuntimeException("TEST"));
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
-
- indexFactoryBean.setExpression("someField");
+ indexFactoryBean.setExpression("id");
indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setName("ExistingIndex");
+ indexFactoryBean.setIgnoreIfExists(false);
+ indexFactoryBean.setName("TestIndex");
indexFactoryBean.setOverride(true);
- indexFactoryBean.setType("FUNCTIONAL");
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
- assertEquals(1, indexes.size());
- assertFalse(indexes.contains(mockExistingIndex));
-
- Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "ExistingIndex");
-
- assertThat(actualIndex, is(sameInstance(mockExistingIndex)));
- assertThat(indexes.size(), is(equalTo(2)));
- assertThat(indexes.contains(mockExistingIndex), is(true));
- assertThat(indexes.contains(mockIndexTwo), is(true));
-
- verify(mockQueryService, times(3)).getIndexes();
- verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex));
- verify(mockQueryService, times(1)).createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"));
- }
-
- @Test(expected = RuntimeException.class)
- public void createIndexThrowsExceptionOnAbsoluteFailure() throws Exception {
- Index mockExistingIndex = mock(Index.class, "createIndexThrowsExceptionOnAbsoluteFailure.MockIndex.Existing");
-
- QueryService mockQueryService = mock(QueryService.class,
- "createIndexThrowsExceptionOnAbsoluteFailure.MockQueryService");
-
- when(mockExistingIndex.getName()).thenReturn("ExistingIndex");
- when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockExistingIndex));
- when(mockQueryService.createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example")))
- .thenThrow(new RuntimeException("test"));
-
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
-
- indexFactoryBean.setExpression("someField");
- indexFactoryBean.setFrom("/Example");
- indexFactoryBean.setName("ExistingIndex");
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
try {
- indexFactoryBean.createIndex(mockQueryService, "ExistingIndex");
+ indexFactoryBean.createIndex(mockQueryService, "TestIndex");
}
- catch (RuntimeException expected) {
- assertEquals("test", expected.getMessage());
+ catch (GemfireIndexException expected) {
+
+ assertThat(expected).hasMessageStartingWith(
+ "Attempt to 'override' existing Index [MockIndex] with the Index that would be created by this"
+ + " IndexFactoryBean [TestIndex] failed; you should verify the state of your system"
+ + " and make sure the previously existing Index [MockIndex] still exits");
+
+ assertThat(expected).hasCauseInstanceOf(GemfireIndexException.class);
+ assertThat(expected.getCause()).hasMessageStartingWith(
+ String.format("Failed to create Index [%s]", indexFactoryBean.toDetailedIndexDefinition()));
+ assertThat(expected.getCause()).hasCauseInstanceOf(RuntimeException.class);
+ assertThat(expected.getCause().getCause()).hasMessageStartingWith("RETRY");
+ assertThat(expected.getCause().getCause()).hasNoCause();
+
throw expected;
}
finally {
- verify(mockQueryService, times(2)).getIndexes();
- verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex));
- verify(mockQueryService, times(1)).createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"));
+
+ verify(indexFactoryBean, times(2))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+
+ verify(mockLog, times(1)).warn(
+ eq(String.format("WARNING! You are attempting to 'override' an existing Index [MockIndex]"
+ + " having the same basic definition [%s] as the Index that will be created by this"
+ + " IndexFactoryBean [TestIndex]; 'Override' effectively 'renames' the existing Index [MockIndex]"
+ + " by removing it then recreating it under the new name [TestIndex] with the same definition;"
+ + " You should be careful to update any existing OQL Query Hints referring to the old"
+ + " Index name [MockIndex] to now use the new name [TestIndex]",
+ indexFactoryBean.toBasicIndexDefinition())));
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+ }
+
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexNameConflictException() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("TestIndex", "purchaseDate", "/Orders", IndexType.HASH);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).when(indexFactoryBean)
+ .createFunctionalIndex(eq(mockQueryService), anyString(), anyString(), anyString(), any(String.class));
+
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setType(IndexType.FUNCTIONAL);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isFalse();
+
+ try {
+ indexFactoryBean.createIndex(mockQueryService, "TestIndex");
+ }
+ catch (GemfireIndexException expected) {
+
+ String existingIndexDefinition = String.format(IndexFactoryBean.DETAILED_INDEX_DEFINITION,
+ mockIndex.getName(), mockIndex.getIndexedExpression(), mockIndex.getFromClause(), "unknown",
+ IndexType.valueOf(mockIndex.getType()));
+
+ assertThat(expected).hasMessageStartingWith(String.format(
+ "An Index with the same name [TestIndex] having possibly a different definition already exists;"
+ + " you may choose to ignore this Index definition [%1$s] and use the existing Index"
+ + " definition [%2$s] by setting the 'ignoreIfExists' property to 'true'",
+ indexFactoryBean.toDetailedIndexDefinition(), existingIndexDefinition));
+
+ assertThat(expected).hasCauseInstanceOf(IndexNameConflictException.class);
+ assertThat(expected.getCause()).hasMessage("TEST");
+ assertThat(expected.getCause()).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+ verify(indexFactoryBean, times(1))
+ .createFunctionalIndex(eq(mockQueryService), eq("TestIndex"),
+ eq("id"), eq("/Example"), any(String.class));
+
+ verifyZeroInteractions(mockLog);
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+ }
+
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexNameConflictExceptionAndCannotFindExistingIndexByName() throws Exception {
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).when(indexFactoryBean)
+ .createFunctionalIndex(eq(mockQueryService), anyString(), anyString(), anyString(), any(String.class));
+
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setIgnoreIfExists(true);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.FUNCTIONAL);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+
+ try {
+ indexFactoryBean.createIndex(mockQueryService, "TestIndex");
+ }
+ catch (GemfireIndexException expected) {
+
+ assertThat(expected).hasMessageStartingWith(String.format(
+ "An Index with the same name [TestIndex] having possibly a different definition already exists;"
+ + " you may choose to ignore this Index definition [%s] and use the existing Index"
+ + " definition [unknown] by setting the 'ignoreIfExists' property to 'true'",
+ indexFactoryBean.toDetailedIndexDefinition()));
+
+ assertThat(expected).hasCauseInstanceOf(IndexNameConflictException.class);
+ assertThat(expected.getCause()).hasMessage("TEST");
+ assertThat(expected.getCause()).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+ verify(indexFactoryBean, times(1))
+ .createFunctionalIndex(eq(mockQueryService), eq("TestIndex"),
+ eq("id"), eq("/Example"), any(String.class));
+
+ verifyZeroInteractions(mockLog);
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+ }
+
+ @Test
+ public void createIndexThrowsIndexNameConflictExceptionAndIgnoresThisIndex() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("TestIndex", "price", "/Orders", IndexType.FUNCTIONAL);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).when(indexFactoryBean)
+ .createFunctionalIndex(eq(mockQueryService), anyString(), anyString(), anyString(), any(String.class));
+
+ indexFactoryBean.setExpression("price");
+ indexFactoryBean.setFrom("/Orders");
+ indexFactoryBean.setIgnoreIfExists(true);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.FUNCTIONAL);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(mockIndex);
+
+ verify(indexFactoryBean, times(1))
+ .createFunctionalIndex(eq(mockQueryService), eq("TestIndex"), eq("price"),
+ eq("/Orders"), any(String.class));
+
+ verifyZeroInteractions(mockLog);
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test
+ public void createIndexThrowsIndexNameConflictExceptionAndIgnoresThisIndexWithWarning() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("TestIndex", "id", "/Orders", IndexType.PRIMARY_KEY);
+
+ when(mockLog.isWarnEnabled()).thenReturn(true);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).when(indexFactoryBean)
+ .createFunctionalIndex(eq(mockQueryService), anyString(), anyString(), anyString(), any(String.class));
+
+ indexFactoryBean.setExpression("price");
+ indexFactoryBean.setFrom("/Orders");
+ indexFactoryBean.setIgnoreIfExists(true);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.FUNCTIONAL);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(mockIndex);
+
+ String existingIndexDefinition = String.format(IndexFactoryBean.BASIC_INDEX_DEFINITION,
+ "id", "/Orders", IndexType.PRIMARY_KEY);
+
+ verify(indexFactoryBean, times(1))
+ .createFunctionalIndex(eq(mockQueryService), eq("TestIndex"), eq("price"),
+ eq("/Orders"), any(String.class));
+
+ verify(mockLog, times(1)).warn(String.format(
+ "WARNING! Returning existing Index [TestIndex] having a definition [%1$s] that does not match"
+ + " the Index defined [%2$s] by this IndexFactoryBean [TestIndex]",
+ existingIndexDefinition, indexFactoryBean.toBasicIndexDefinition()));
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test
+ public void createIndexThrowsIndexNameConflictExceptionAndOverridesExistingIndex() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("TestIndex", "id", "/Example", IndexType.PRIMARY_KEY);
+
+ Index testIndex =
+ mockIndexWithDefinition("TestIndex", "id", "/Example", IndexType.PRIMARY_KEY);
+
+ assertThat(mockIndex).isNotSameAs(testIndex);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).doReturn(testIndex).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
+
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setIgnoreIfExists(false);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+
+ // NOTE: this test case is also testing the smart "override" handling logic, which just
+ // returns the existing Index if both the name and definition are the same on when an
+ // IndexNameConflictException is thrown.
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(mockIndex);
+
+ verify(indexFactoryBean, times(1))
+ .createKeyIndex(eq(mockQueryService), eq("TestIndex"), eq("id"), eq("/Example"));
+
+ verifyZeroInteractions(mockLog);
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test
+ public void createIndexThrowsIndexNameConflictExceptionAndOverridesExistingIndexWithWarning() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("TestIndex", "price", "/Orders", IndexType.FUNCTIONAL);
+
+ Index testIndex =
+ mockIndexWithDefinition("TestIndex", "purchaseDate", "/Orders", IndexType.HASH);
+
+ assertThat(mockIndex).isNotSameAs(testIndex);
+
+ when(mockLog.isWarnEnabled()).thenReturn(true);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).doReturn(testIndex).when(indexFactoryBean)
+ .createHashIndex(any(QueryService.class), anyString(), anyString(), anyString(), any(String.class));
+
+ indexFactoryBean.setExpression("purchaseDate");
+ indexFactoryBean.setFrom("/Orders");
+ indexFactoryBean.setIgnoreIfExists(false);
+ indexFactoryBean.setName("TestIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.HASH);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ assertThat(indexFactoryBean.createIndex(mockQueryService, "TestIndex")).isEqualTo(testIndex);
+
+ String existingIndexDefinition = String.format(IndexFactoryBean.BASIC_INDEX_DEFINITION,
+ mockIndex.getIndexedExpression(), mockIndex.getFromClause(), IndexType.valueOf(mockIndex.getType()));
+
+ verify(indexFactoryBean, times(2)).createHashIndex(eq(mockQueryService),
+ eq("TestIndex"), eq("purchaseDate"), eq("/Orders"), any(String.class));
+
+ verify(mockLog, times(1)).warn(eq(String.format(
+ "WARNING! Overriding existing Index [TestIndex] having a definition [%1$s] that does not match"
+ + " the Index defined [%2$s] by this IndexFactoryBean [TestIndex]",
+ existingIndexDefinition, indexFactoryBean.toBasicIndexDefinition())));
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test(expected = GemfireIndexException.class)
+ public void createIndexThrowsIndexNameConflictExceptionAndOverrideThrowsRuntimeException() throws Exception {
+
+ Index mockIndex =
+ mockIndexWithDefinition("MockIndex", "purchaseDate", "/Example",
+ IndexType.HASH);
+
+ when(mockLog.isWarnEnabled()).thenReturn(true);
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex))
+ .thenReturn(Collections.emptyList());
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doThrow(new IndexNameConflictException("TEST")).doThrow(new RuntimeException("RETRY")).when(indexFactoryBean)
+ .createKeyIndex(any(QueryService.class), anyString(), anyString(), anyString());
+
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Example");
+ indexFactoryBean.setIgnoreIfExists(false);
+ indexFactoryBean.setName("MockIndex");
+ indexFactoryBean.setOverride(true);
+ indexFactoryBean.setType(IndexType.PRIMARY_KEY);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+
+ try {
+ indexFactoryBean.createIndex(mockQueryService, "MockIndex");
+ }
+ catch (GemfireIndexException expected) {
+
+ assertThat(expected).hasMessageStartingWith(
+ "Attempt to 'override' existing Index [MockIndex] with the Index that would be created by this"
+ + " IndexFactoryBean [MockIndex] failed; you should verify the state of your system"
+ + " and make sure the previously existing Index [MockIndex] still exits");
+
+ assertThat(expected).hasCauseInstanceOf(GemfireIndexException.class);
+ assertThat(expected.getCause()).hasMessageStartingWith(
+ String.format("Failed to create Index [%s]", indexFactoryBean.toDetailedIndexDefinition()));
+ assertThat(expected.getCause()).hasCauseInstanceOf(RuntimeException.class);
+ assertThat(expected.getCause().getCause()).hasMessageStartingWith("RETRY");
+ assertThat(expected.getCause().getCause()).hasNoCause();
+
+ throw expected;
+ }
+ finally {
+
+ String existingIndexDefinition = String.format(IndexFactoryBean.BASIC_INDEX_DEFINITION,
+ mockIndex.getIndexedExpression(), mockIndex.getFromClause(), IndexType.valueOf(mockIndex.getType()));
+
+ verify(indexFactoryBean, times(2))
+ .createKeyIndex(eq(mockQueryService), eq("MockIndex"), eq("id"), eq("/Example"));
+
+ verify(mockLog, times(1)).warn(eq(String.format(
+ "WARNING! Overriding existing Index [MockIndex] having a definition [%1$s] that does not match"
+ + " the Index defined [%2$s] by this IndexFactoryBean [MockIndex]",
+ existingIndexDefinition, indexFactoryBean.toBasicIndexDefinition())));
+
+ verify(mockQueryService, times(1)).getIndexes();
}
}
@Test
public void createFunctionalIndex() throws Exception {
- Index mockIndex = mock(Index.class, "testCreateFunctionalIndex.MockIndex");
- QueryService mockQueryService = mock(QueryService.class, "testCreateFunctionalIndex.MockQueryService");
+ Index mockIndex = mockIndex("testCreateFunctionalIndex.MockIndex");
when(mockQueryService.createIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders")))
.thenReturn(mockIndex);
@@ -671,275 +1207,436 @@ public class IndexFactoryBeanTest {
Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndex",
"purchaseDate", "/Orders", null);
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
- verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"));
+ verify(mockQueryService, times(1))
+ .createIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"));
verify(mockQueryService, never()).defineIndex(anyString(), anyString(), anyString());
}
@Test
public void createFunctionalIndexWithImports() throws Exception {
- Index mockIndex = mock(Index.class, "testCreateFunctionalIndexWithImports.MockIndex");
- QueryService mockQueryService = mock(QueryService.class, "testCreateFunctionalIndexWithImports.MockQueryService");
+ Index mockIndex = mockIndex("testCreateFunctionalIndexWithImports.MockIndex");
- when(mockQueryService.createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"), eq("/Orders"),
- eq("org.example.Order"))).thenReturn(mockIndex);
+ when(mockQueryService.createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"),
+ eq("/Orders"), eq("example.Order"))).thenReturn(mockIndex);
Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndexWithImports",
- "purchaseDate", "/Orders", "org.example.Order");
+ "purchaseDate", "/Orders", "example.Order");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
+
+ verify(mockQueryService, times(1))
+ .createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"), eq("/Orders"),
+ eq("example.Order"));
- verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"),
- eq("/Orders"), eq("org.example.Order"));
verify(mockQueryService, never()).defineIndex(anyString(), anyString(), anyString(), anyString());
}
@Test
public void defineFunctionalIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testDefineFunctionalIndex.MockQueryService");
-
- doAnswer(new Answer() {
- @Override public Void answer(final InvocationOnMock invocation) throws Throwable {
- return null;
- }
- }).when(mockQueryService).defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"));
indexFactoryBean.setDefine(true);
Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndex",
"purchaseDate", "/Orders", null);
- assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper);
- assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService());
- assertEquals("FunctionalIndex", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName());
+ assertThat(actualIndex).isInstanceOf(IndexFactoryBean.IndexWrapper.class);
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()).isEqualTo("FunctionalIndex");
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()).isSameAs(mockQueryService);
verify(mockQueryService, never()).createIndex(anyString(), anyString(), anyString());
- verify(mockQueryService, times(1)).defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"));
+ verify(mockQueryService, times(1))
+ .defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"));
}
@Test
public void defineFunctionalIndexWithImports() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testDefineFunctionalIndexWithImports.MockQueryService");
-
- doAnswer(new Answer() {
- @Override public Void answer(final InvocationOnMock invocation) throws Throwable {
- return null;
- }
- }).when(mockQueryService).defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"),
- eq("org.example.Order"));
indexFactoryBean.setDefine(true);
- Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndexWithImports",
- "purchaseDate", "/Orders", "org.example.Order");
+ Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService,
+ "FunctionalIndexWithImports", "purchaseDate", "/Orders", "example.Order");
- assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper);
- assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService());
- assertEquals("FunctionalIndexWithImports", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName());
+ assertThat(actualIndex).isInstanceOf(IndexFactoryBean.IndexWrapper.class);
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()).isEqualTo("FunctionalIndexWithImports");
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()).isSameAs(mockQueryService);
verify(mockQueryService, never()).createIndex(anyString(), anyString(), anyString(), anyString());
- verify(mockQueryService, times(1)).defineIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"),
- eq("/Orders"), eq("org.example.Order"));
+ verify(mockQueryService, times(1)).defineIndex(eq("FunctionalIndexWithImports"),
+ eq("purchaseDate"), eq("/Orders"), eq("example.Order"));
}
@Test
public void createHashIndex() throws Exception {
- Index mockIndex = mock(Index.class, "testCreateHashIndex.MockIndex");
- QueryService mockQueryService = mock(QueryService.class, "testCreateHashIndex.MockQueryService");
+ Index mockIndex = mockIndex("testCreateHashIndex.MockIndex");
- when(mockQueryService.createHashIndex(eq("HashIndex"), eq("name"), eq("/People"))).thenReturn(mockIndex);
+ when(mockQueryService.createHashIndex(eq("HashIndex"), eq("name"), eq("/People")))
+ .thenReturn(mockIndex);
- Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndex", "name", "/People", " ");
+ Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndex",
+ "name", "/People", " ");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
+
+ verify(mockQueryService, times(1))
+ .createHashIndex(eq("HashIndex"), eq("name"), eq("/People"));
- verify(mockQueryService, times(1)).createHashIndex(eq("HashIndex"), eq("name"), eq("/People"));
verify(mockQueryService, never()).defineHashIndex(anyString(), anyString(), anyString());
}
@Test
public void createHashIndexWithImports() throws Exception {
- Index mockIndex = mock(Index.class, "testCreateHashIndexWithImports.MockIndex");
- QueryService mockQueryService = mock(QueryService.class, "testCreateHashIndexWithImports.MockQueryService");
+ Index mockIndex = mockIndex("testCreateHashIndexWithImports.MockIndex");
when(mockQueryService.createHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"),
- eq("org.example.Person"))).thenReturn(mockIndex);
+ eq("example.Person"))).thenReturn(mockIndex);
Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndexWithImports",
- "name", "/People", "org.example.Person");
+ "name", "/People", "example.Person");
- assertSame(mockIndex, actualIndex);
+ assertThat(actualIndex).isSameAs(mockIndex);
+
+ verify(mockQueryService, times(1)).createHashIndex(eq("HashIndexWithImports"),
+ eq("name"), eq("/People"), eq("example.Person"));
- verify(mockQueryService, times(1)).createHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"),
- eq("org.example.Person"));
verify(mockQueryService, never()).defineHashIndex(anyString(), anyString(), anyString(), anyString());
}
@Test
public void defineHashIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testDefineHashIndex.MockQueryService");
-
- doAnswer(new Answer() {
- @Override public Void answer(final InvocationOnMock invocation) throws Throwable {
- return null;
- }
- }).when(mockQueryService).defineHashIndex(eq("HashIndex"), eq("name"), eq("/People"));
indexFactoryBean.setDefine(true);
Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndex",
"name", "/People", " ");
- assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper);
- assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService());
- assertEquals("HashIndex", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName());
+ assertThat(actualIndex).isInstanceOf(IndexFactoryBean.IndexWrapper.class);
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()).isEqualTo("HashIndex");
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()).isSameAs(mockQueryService);
verify(mockQueryService, never()).createHashIndex(anyString(), anyString(), anyString());
- verify(mockQueryService, times(1)).defineHashIndex(eq("HashIndex"), eq("name"), eq("/People"));
+ verify(mockQueryService, times(1))
+ .defineHashIndex(eq("HashIndex"), eq("name"), eq("/People"));
}
@Test
- public void defineHashIndexWithImports() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testDefineHashIndexWithImports.MockQueryService");
-
- doAnswer(new Answer() {
- @Override public Void answer(final InvocationOnMock invocation) throws Throwable {
- return null;
- }
- }).when(mockQueryService).defineHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"),
- eq("org.example.Person"));
+ public void defineHashIndexWithImport() throws Exception {
indexFactoryBean.setDefine(true);
Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndexWithImports",
- "name", "/People", "org.example.Person");
+ "name", "/People", "example.Person");
- assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper);
- assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService());
- assertEquals("HashIndexWithImports", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName());
+ assertThat(actualIndex).isInstanceOf(IndexFactoryBean.IndexWrapper.class);
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()).isEqualTo("HashIndexWithImports");
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()).isSameAs(mockQueryService);
verify(mockQueryService, never()).createHashIndex(anyString(), anyString(), anyString(), anyString());
- verify(mockQueryService, times(1)).defineHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"),
- eq("org.example.Person"));
+ verify(mockQueryService, times(1)).defineHashIndex(eq("HashIndexWithImports"),
+ eq("name"), eq("/People"), eq("example.Person"));
}
@Test
public void createKeyIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testCreateKeyIndex.MockQueryService");
- Index mockIndex = mock(Index.class, "testCreateKeyIndex.MockKeyIndex");
+ Index mockIndex = mockIndex("testCreateKeyIndex.MockKeyIndex");
- when(mockQueryService.createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"))).thenReturn(mockIndex);
+ when(mockQueryService.createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example")))
+ .thenReturn(mockIndex);
- indexFactoryBean.setDefine(false);
+ Index actualIndex = indexFactoryBean.createKeyIndex(mockQueryService, "KeyIndex",
+ "id", "/Example");
- Index actualIndex = indexFactoryBean.createKeyIndex(mockQueryService, "KeyIndex", "id", "/Example");
+ assertThat(actualIndex).isSameAs(mockIndex);
- assertSame(mockIndex, actualIndex);
+ verify(mockQueryService, times(1))
+ .createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"));
- verify(mockQueryService, times(1)).createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"));
verify(mockQueryService, never()).defineKeyIndex(anyString(), anyString(), anyString());
}
@Test
public void defineKeyIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testDefineKeyIndex.MockQueryService");
indexFactoryBean.setDefine(true);
- Index actualIndex = indexFactoryBean.createKeyIndex(mockQueryService, "KeyIndex", "id", "/Example");
+ Index actualIndex = indexFactoryBean.createKeyIndex(mockQueryService, "KeyIndex",
+ "id", "/Example");
- assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper);
-
- IndexFactoryBean.IndexWrapper indexWrapper = (IndexFactoryBean.IndexWrapper) actualIndex;
-
- assertSame(mockQueryService, indexWrapper.getQueryService());
- assertEquals("KeyIndex", indexWrapper.getIndexName());
+ assertThat(actualIndex).isInstanceOf(IndexFactoryBean.IndexWrapper.class);
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()).isEqualTo("KeyIndex");
+ assertThat(((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()).isSameAs(mockQueryService);
verify(mockQueryService, never()).createKeyIndex(anyString(), anyString(), anyString());
- verify(mockQueryService, times(1)).defineKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"));
+ verify(mockQueryService, times(1)).defineKeyIndex(eq("KeyIndex"),
+ eq("id"), eq("/Example"));
}
@Test
- public void getExistingIndex() {
- Index mockIndexOne = mock(Index.class, "testGetExistingIndex.MockIndex.One");
- Index mockIndexTwo = mock(Index.class, "testGetExistingIndex.MockIndex.Two");
- Index mockIndexThree = mock(Index.class, "testGetExistingIndex.MockIndex.Two");
+ public void tryToFindExistingIndexByDefinitionReturnsIndex() {
- QueryService mockQueryService = mock(QueryService.class, "testGetExistingIndex.MockQueryService");
+ Index mockIndexOne =
+ mockIndexWithDefinition("PrimaryIndex", "id", "/People", IndexType.HASH);
+
+ Index mockIndexTwo =
+ mockIndexWithDefinition("SecondaryIndex", "id", "/People", IndexType.PRIMARY_KEY);
+
+ Index mockIndexThree =
+ mockIndexWithDefinition("TernaryIndex", "purchaseDate", "/Orders",
+ IndexType.FUNCTIONAL);
- when(mockIndexOne.getName()).thenReturn("PrimaryIndex");
- when(mockIndexTwo.getName()).thenReturn("SecondaryIndex");
- when(mockIndexThree.getName()).thenReturn("TernaryIndex");
when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockIndexOne, mockIndexTwo, mockIndexThree));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, null));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, ""));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, " "));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, "Primary Index"));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, "Secondary_Index"));
- assertNull(indexFactoryBean.getExistingIndex(mockQueryService, "QuadIndex"));
- assertSame(mockIndexOne, indexFactoryBean.getExistingIndex(mockQueryService, "PRIMARYINDEX"));
- assertSame(mockIndexTwo, indexFactoryBean.getExistingIndex(mockQueryService, "SecondaryIndex"));
- assertSame(mockIndexThree, indexFactoryBean.getExistingIndex(mockQueryService, "ternaryindex"));
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/People", IndexType.PRIMARY_KEY)).isSameAs(mockIndexTwo);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "purchaseDate", "/Orders", IndexType.FUNCTIONAL)).isSameAs(mockIndexThree);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/People", IndexType.HASH)).isSameAs(mockIndexOne);
+
+ verify(mockQueryService, times(3)).getIndexes();
}
@Test
- public void getObjectLooksUpIndex() throws Exception {
- QueryService mockQueryService = mock(QueryService.class, "testGetObjectLooksUpIndex.MockQueryService");
+ public void tryToFindExistingIndexByDefinitionReturnsNull() {
- when(mockQueryService.getIndexes()).then(new Answer>() {
- private final AtomicInteger counter = new AtomicInteger(1);
- @Override public Collection answer(final InvocationOnMock invocation) throws Throwable {
- Index mockIndex = mock(Index.class, "getObjectLooksUpIndex.MockIndex");
- when(mockIndex.getName()).thenReturn(String.format("MockIndex%1$s", counter.getAndIncrement()));
- return Collections.singletonList(mockIndex);
- }
- });
+ Index mockIndex =
+ mockIndexWithDefinition("PrimaryIndex", "id", "/People", IndexType.HASH);
- IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
+ when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
- indexFactoryBean.setQueryService(mockQueryService);
- indexFactoryBean.setName("MockIndex1");
- ReflectionUtils.setField(IndexFactoryBean.class.getDeclaredField("indexName"), indexFactoryBean, "MockIndex1");
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "key", "/People", IndexType.HASH)).isNull();
- Index actualIndex = indexFactoryBean.getObject();
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/Persons", IndexType.HASH)).isNull();
- assertNotNull(actualIndex);
- assertEquals("MockIndex1", actualIndex.getName());
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/People", IndexType.KEY)).isNull();
- Index sameIndex = indexFactoryBean.getObject();
-
- assertSame(actualIndex, sameIndex);
+ verify(mockQueryService, times(3)).getIndexes();
}
@Test
- public void indexFactoryBeanCreatesSingleIndex() {
- assertTrue(indexFactoryBean.isSingleton());
+ public void tryToFindExistingIndexByDefinitionWithQueryServiceHavingNoIndexesReturnsNull() {
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/People", IndexType.KEY)).isNull();
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test
+ public void tryToFindExistingIndexByDefinitionWithQueryServiceReturningNullIndexesReturnsNull() {
+
+ when(mockQueryService.getIndexes()).thenReturn(null);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByDefinition(mockQueryService,
+ "id", "/People", IndexType.KEY)).isNull();
+
+ verify(mockQueryService, times(1)).getIndexes();
+ }
+
+ @Test
+ public void tryToFindExistingIndexByNameReturnsIndex() {
+
+ Index mockIndexOne = mockIndex("PrimaryIndex");
+ Index mockIndexTwo = mockIndex("SecondaryIndex");
+ Index mockIndexThree = mockIndex("TernaryIndex");
+
+ when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockIndexOne, mockIndexTwo, mockIndexThree));
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "PRIMARYINDEX"))
+ .isSameAs(mockIndexOne);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "SecondaryIndex"))
+ .isSameAs(mockIndexTwo);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "ternaryindex"))
+ .isSameAs(mockIndexThree);
+
+ verify(mockQueryService, times(3)).getIndexes();
+ }
+
+ @Test
+ public void tryToFindExistingIndexByNameReturnsNull() {
+
+ Index mockIndexOne = mockIndex("PrimaryIndex");
+ Index mockIndexTwo = mockIndex("SecondaryIndex");
+ Index mockIndexThree = mockIndex("TernaryIndex");
+
+ when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockIndexOne, mockIndexTwo, mockIndexThree));
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, null)).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, " ")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "Primary Index")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "Secondary_Index")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "QuadIndex")).isNull();
+
+ verify(mockQueryService, times(6)).getIndexes();
+ }
+
+ @Test
+ public void tryToFindExistingIndexByNameWithQueryServiceHavingNoIndexesReturnsNull() {
+
+ when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "TestIndex")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "KeyIndex")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "IdIndex")).isNull();
+
+ verify(mockQueryService, times(3)).getIndexes();
+ }
+
+ @Test
+ public void tryToFindExistingIndexByNameWithQueryServiceReturningNullIndexesReturnsNull() {
+
+ when(mockQueryService.getIndexes()).thenReturn(null);
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "TestIndex")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "KeyIndex")).isNull();
+
+ assertThat(indexFactoryBean.tryToFindExistingIndexByName(mockQueryService, "IdIndex")).isNull();
+
+ verify(mockQueryService, times(3)).getIndexes();
+ }
+
+ @Test
+ public void getObjectReturnsFactoryIndex() throws Exception {
+
+ Index mockIndex = mockIndex("testGetObjectReturnsFactoryIndex.MockIndex");
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doReturn(mockIndex).when(indexFactoryBean).createIndex(eq(mockQueryService),
+ eq("testGetObjectReturnsFactoryIndex.MockIndex"));
+
+ indexFactoryBean.setName("testGetObjectReturnsFactoryIndex.MockIndex");
+ indexFactoryBean.setExpression("id");
+ indexFactoryBean.setFrom("/Mock");
+ indexFactoryBean.afterPropertiesSet();
+
+ assertThat(indexFactoryBean.getIndex()).isEqualTo(mockIndex);
+ assertThat(indexFactoryBean.getObject()).isEqualTo(mockIndex);
+ assertThat(indexFactoryBean.getObject()).isEqualTo(mockIndex);
+
+ verify(indexFactoryBean, times(1))
+ .createIndex(eq(mockQueryService), eq("testGetObjectReturnsFactoryIndex.MockIndex"));
+ }
+
+ @Test
+ public void getObjectReturnsLookedUpIndex() throws Exception {
+
+ Index mockIndexOne = mockIndex("MockIndexOne");
+ Index mockIndexTwo = mockIndex("MockIndexTwo");
+
+ when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockIndexOne, mockIndexTwo));
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setName("MockIndexTwo");
+
+ assertThat(indexFactoryBean.getObject()).isEqualTo(mockIndexTwo);
+ }
+
+ @Test
+ public void getObjectReturnsNull() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ indexFactoryBean.setName("TestIndex");
+
+ assertThat(indexFactoryBean.getObject()).isNull();
+ }
+
+ @Test
+ public void getObjectTypeReturnsIndexClassType() {
+ assertThat(newIndexFactoryBean().getObjectType()).isEqualTo(Index.class);
+ }
+
+ @Test
+ @SuppressWarnings("all")
+ public void getObjectTypeReturnsMockIndexClassType() throws Exception {
+
+ Index mockIndex = mockIndex("MockIndex");
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ doReturn(mockIndex).when(indexFactoryBean).getIndex();
+
+ assertThat(indexFactoryBean.getObjectType()).isEqualTo(mockIndex.getClass());
+ }
+
+ @Test
+ public void isSingletonReturnsTrue() {
+ assertThat(indexFactoryBean.isSingleton()).isTrue();
+ }
+
+ @Test
+ public void setAndIsIgnoreIfExists() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+
+ indexFactoryBean.setIgnoreIfExists(true);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+
+ indexFactoryBean.setIgnoreIfExists(false);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isFalse();
+ }
+
+ @Test
+ public void setAndIsOverride() {
+
+ IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
+
+ assertThat(indexFactoryBean.isOverride()).isFalse();
+
+ indexFactoryBean.setOverride(true);
+
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+
+ indexFactoryBean.setOverride(false);
+
+ assertThat(indexFactoryBean.isOverride()).isFalse();
}
@Test
public void defineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext() throws Exception {
+
ConfigurableBeanFactory mockBeanFactory = mock(ConfigurableBeanFactory.class,
"testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockBeanFactory");
- Cache mockCacheOne = mock(Cache.class, "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockCacheOne");
- Cache mockCacheTwo = mock(Cache.class, "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockCacheTwo");
+ Cache mockCacheOne =
+ mock(Cache.class, "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockCacheOne");
- QueryService mockQueryServiceOne = mock(QueryService.class,
- "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockQueryServiceOne");
-
- QueryService mockQueryServiceTwo = mock(QueryService.class,
- "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockQueryServiceTwo");
+ Cache mockCacheTwo =
+ mock(Cache.class, "testDefineMultipleIndexesWithSeparateIndexFactoryBeansSameSpringContext.MockCacheTwo");
final AtomicReference queryServiceReference = new AtomicReference(null);
doAnswer(new Answer() {
- @Override public Boolean answer(final InvocationOnMock invocation) throws Throwable {
+ @Override public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
return (queryServiceReference.get() != null);
}
}).when(mockBeanFactory).containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
@@ -961,8 +1658,7 @@ public class IndexFactoryBeanTest {
}).when(mockBeanFactory).registerSingleton(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
any(QueryService.class));
- when(mockCacheOne.getQueryService()).thenReturn(mockQueryServiceOne);
- when(mockCacheTwo.getQueryService()).thenReturn(mockQueryServiceTwo);
+ when(mockCacheOne.getQueryService()).thenReturn(mockQueryService);
IndexFactoryBean indexFactoryBeanOne = new IndexFactoryBean();
@@ -987,31 +1683,36 @@ public class IndexFactoryBeanTest {
indexFactoryBeanTwo.setType("HASH");
indexFactoryBeanTwo.afterPropertiesSet();
- verify(mockBeanFactory, times(2)).containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
- verify(mockBeanFactory, times(1)).getBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
- eq(QueryService.class));
- verify(mockBeanFactory, times(1)).registerSingleton(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
- same(mockQueryServiceOne));
+ verify(mockBeanFactory, times(2))
+ .containsBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE));
+
+ verify(mockBeanFactory, times(1))
+ .getBean(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE), eq(QueryService.class));
+
+ verify(mockBeanFactory, times(1))
+ .registerSingleton(eq(GemfireConstants.DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE),
+ same(mockQueryService));
+
verify(mockCacheOne, times(1)).getQueryService();
verify(mockCacheTwo, never()).getQueryService();
- verify(mockQueryServiceOne, times(1)).defineKeyIndex(eq("PersonIdIndex"), eq("id"), eq("/People"));
- verify(mockQueryServiceOne, times(1)).defineHashIndex(eq("PurchaseDateIndex"), eq("purchaseDate"), eq("/Orders"),
- eq("org.example.Order"));
- verify(mockQueryServiceTwo, never()).defineHashIndex(anyString(), anyString(), anyString());
- verify(mockQueryServiceTwo, never()).defineHashIndex(anyString(), anyString(), anyString());
- verify(mockQueryServiceTwo, never()).defineIndex(anyString(), anyString(), anyString());
- verify(mockQueryServiceTwo, never()).defineIndex(anyString(), anyString(), anyString(), anyString());
- verify(mockQueryServiceTwo, never()).defineKeyIndex(anyString(), anyString(), anyString());
+
+ verify(mockQueryService, times(1))
+ .defineKeyIndex(eq("PersonIdIndex"), eq("id"), eq("/People"));
+
+ verify(mockQueryService, times(1))
+ .defineHashIndex(eq("PurchaseDateIndex"), eq("purchaseDate"), eq("/Orders"),
+ eq("org.example.Order"));
}
@Test
@SuppressWarnings("deprecation")
public void indexWrapperDelegation() {
- Index mockIndex = mock(Index.class, "indexWrapperDelegation.MockIndex");
- IndexStatistics mockIndexStats = mock(IndexStatistics.class, "indexWrapperDelegation.MockIndexStats");
+ Index mockIndex = mockIndex("testIndexWrapperDelegation.MockIndex");
- QueryService mockQueryService = mock(QueryService.class, "indexWrapperDelegation.MockQueryService");
+ IndexStatistics mockIndexStats = mock(IndexStatistics.class, "testIndexWrapperDelegation.MockIndexStats");
+
+ QueryService mockQueryService = mock(QueryService.class, "testIndexWrapperDelegation.MockQueryService");
when(mockIndex.getCanonicalizedFromClause()).thenReturn("/Example");
when(mockIndex.getCanonicalizedIndexedExpression()).thenReturn("ID");
@@ -1024,28 +1725,30 @@ public class IndexFactoryBeanTest {
when(mockIndex.getType()).thenReturn(com.gemstone.gemfire.cache.query.IndexType.HASH);
when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockIndex));
- IndexFactoryBean.IndexWrapper indexWrapper = new IndexFactoryBean.IndexWrapper(mockQueryService, "MockIndex");
+ IndexFactoryBean.IndexWrapper indexWrapper =
+ new IndexFactoryBean.IndexWrapper(mockQueryService, "MockIndex");
- assertNotNull(indexWrapper);
- assertEquals("MockIndex", indexWrapper.getIndexName());
- assertSame(mockQueryService, indexWrapper.getQueryService());
+ assertThat(indexWrapper).isNotNull();
+ assertThat(indexWrapper.getIndexName()).isEqualTo("MockIndex");
+ assertThat(indexWrapper.getQueryService()).isEqualTo(mockQueryService);
- Index actualIndex = indexWrapper.getIndex();
+ Index actualIndex = indexWrapper.resolveIndex();
- assertSame(mockIndex, actualIndex);
- assertEquals("/Example", indexWrapper.getCanonicalizedFromClause());
- assertEquals("ID", indexWrapper.getCanonicalizedIndexedExpression());
- assertEquals("identifier", indexWrapper.getCanonicalizedProjectionAttributes());
- assertEquals("Example", indexWrapper.getFromClause());
- assertEquals("id", indexWrapper.getIndexedExpression());
- assertEquals("MockIndex", indexWrapper.getName());
- assertEquals("id", indexWrapper.getProjectionAttributes());
- assertSame(mockIndexStats, indexWrapper.getStatistics());
- assertEquals(com.gemstone.gemfire.cache.query.IndexType.HASH, indexWrapper.getType());
+ assertThat(actualIndex).isSameAs(mockIndex);
- Index sameIndex = indexWrapper.getIndex();
+ assertThat(indexWrapper.getCanonicalizedFromClause()).isEqualTo("/Example");
+ assertThat(indexWrapper.getCanonicalizedIndexedExpression()).isEqualTo("ID");
+ assertThat(indexWrapper.getCanonicalizedProjectionAttributes()).isEqualTo("identifier");
+ assertThat(indexWrapper.getFromClause()).isEqualTo("Example");
+ assertThat(indexWrapper.getIndexedExpression()).isEqualTo("id");
+ assertThat(indexWrapper.getName()).isEqualTo("MockIndex");
+ assertThat(indexWrapper.getProjectionAttributes()).isEqualTo("id");
+ assertThat(indexWrapper.getStatistics()).isSameAs(mockIndexStats);
+ assertThat(indexWrapper.getType()).isEqualTo(com.gemstone.gemfire.cache.query.IndexType.HASH);
- assertSame(actualIndex, sameIndex);
+ Index sameIndex = indexWrapper.resolveIndex();
+
+ assertThat(sameIndex).isSameAs(actualIndex);
}
@Test(expected = IllegalArgumentException.class)
@@ -1054,42 +1757,46 @@ public class IndexFactoryBeanTest {
new IndexFactoryBean.IndexWrapper(null, "TestIndex");
}
catch (IllegalArgumentException expected) {
- assertEquals("QueryService must not be null", expected.getMessage());
+ assertThat(expected).hasMessage("QueryService is required");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
@Test(expected = IllegalArgumentException.class)
- public void createIndexWrapperWithUnspecifiedIndexName() {
+ public void createIndexWrapperWithNoIndexName() {
try {
- new IndexFactoryBean.IndexWrapper(mock(QueryService.class), " ");
+ new IndexFactoryBean.IndexWrapper(mockQueryService, " ");
}
catch (IllegalArgumentException expected) {
- assertEquals("The name of the Index must be specified!", expected.getMessage());
+ assertThat(expected).hasMessage("Name of Index is required");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
@Test(expected = GemfireIndexException.class)
- public void indexWrapperGetIndexWhenIndexNotFound() {
- QueryService mockQueryService = mock(QueryService.class, "indexWrapperGetIndexWhenIndexNotFound.MockQueryService");
+ public void indexWrapperGetIndexThrowsExceptionWhenIndexNotFound() {
when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
- IndexFactoryBean.IndexWrapper indexWrapper = new IndexFactoryBean.IndexWrapper(mockQueryService, "NonExistingIndex");
+ IndexFactoryBean.IndexWrapper indexWrapper =
+ new IndexFactoryBean.IndexWrapper(mockQueryService, "NonExistingIndex");
- assertNotNull(indexWrapper);
- assertEquals("NonExistingIndex", indexWrapper.getIndexName());
- assertSame(mockQueryService, indexWrapper.getQueryService());
+ assertThat(indexWrapper).isNotNull();
+ assertThat(indexWrapper.getIndexName()).isEqualTo("NonExistingIndex");
+ assertThat(indexWrapper.getQueryService()).isSameAs(mockQueryService);
try {
- indexWrapper.getIndex();
+ indexWrapper.resolveIndex();
}
catch (GemfireIndexException expected) {
- assertThat(expected.getMessage(), startsWith("index with name (NonExistingIndex) was not found"));
- assertTrue(expected.getCause() instanceof IndexInvalidException);
+ assertThat(expected).hasMessage("Index with name [NonExistingIndex] was not found");
+ assertThat(expected).hasNoCause();
+
throw expected;
}
}
-
}
diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java
index b1d156dc..1fbfe4ed 100644
--- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java
+++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java
@@ -20,17 +20,21 @@ package org.springframework.data.gemfire.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Map;
+import java.util.Set;
import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionFactory;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.query.Index;
import com.gemstone.gemfire.cache.query.QueryService;
+import com.gemstone.gemfire.internal.concurrent.ConcurrentHashSet;
import org.junit.After;
import org.junit.Test;
@@ -42,6 +46,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
+import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.IndexType;
import org.springframework.data.gemfire.config.annotation.test.entities.ClientRegionEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity;
@@ -62,8 +67,22 @@ import org.springframework.data.gemfire.config.annotation.test.entities.Replicat
*/
public class EnableIndexesConfigurationUnitTests {
+ private static final Set indexes = new ConcurrentHashSet();
+
private ConfigurableApplicationContext applicationContext;
+ /* (non-Javadoc) */
+ private static Index findIndexByName(String indexName) {
+
+ for (Index index : indexes) {
+ if (index.getName().equalsIgnoreCase(indexName)) {
+ return index;
+ }
+ }
+
+ return null;
+ }
+
@After
public void tearDown() {
if (applicationContext != null) {
@@ -115,22 +134,46 @@ public class EnableIndexesConfigurationUnitTests {
assertThat(indexes.isEmpty()).isTrue();
}
+ @Test
+ public void indexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameDefinition() {
+
+ applicationContext = newApplicationContext(
+ IndexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameDefinitionConfiguration.class);
+
+ Index firstNameIndex = applicationContext.getBean("LoyalCustomersFirstNameFunctionalIdx", Index.class);
+
+ assertIndex(firstNameIndex, "LoyalCustomersFirstNameFunctionalIdx",
+ "first_name", "/LoyalCustomers", IndexType.FUNCTIONAL);
+
+ assertThat(findIndexByName("CustomersFirstNameFunctionalIdx")).isNull();
+ }
+
+ @Test
+ public void indexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameName() {
+
+ applicationContext = newApplicationContext(
+ IndexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameNameConfiguration.class);
+
+ Index lastNameIndex = applicationContext.getBean("LastNameIdx", Index.class);
+
+ assertIndex(lastNameIndex, "LastNameIdx", "last_name", "/People", IndexType.HASH);
+ }
+
@Configuration
@SuppressWarnings("unused")
- static class CacheConfiguration {
+ static class GemFireConfiguration {
@Bean
@SuppressWarnings("unchecked")
Cache gemfireCache() throws Exception {
- Cache mockCache = mock(Cache.class);
+ return mockQueryService(mockRegionFactory(mock(Cache.class, "MockGemFireCache")));
+ }
+
+ Cache mockQueryService(Cache mockCache) throws Exception {
+
QueryService mockQueryService = mock(QueryService.class);
- RegionFactory mockRegionFactory = mock(RegionFactory.class);
when(mockCache.getQueryService()).thenReturn(mockQueryService);
- when(mockCache.createRegionFactory()).thenReturn(mockRegionFactory);
- when(mockCache.createRegionFactory(any(RegionAttributes.class))).thenReturn(mockRegionFactory);
- when(mockCache.createRegionFactory(any(RegionShortcut.class))).thenReturn(mockRegionFactory);
- when(mockCache.createRegionFactory(anyString())).thenReturn(mockRegionFactory);
when(mockQueryService.createHashIndex(anyString(), anyString(), anyString()))
.thenAnswer(new HashIndexAnswer());
@@ -141,6 +184,34 @@ public class EnableIndexesConfigurationUnitTests {
when(mockQueryService.createKeyIndex(anyString(), anyString(), anyString()))
.thenAnswer(new KeyIndexAnswer());
+ when(mockQueryService.getIndexes()).thenReturn(indexes);
+
+ doAnswer(new Answer() {
+
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Index indexToRemove = invocation.getArgumentAt(0, Index.class);
+
+ indexes.remove(findIndexByName(indexToRemove.getName()));
+
+ return null;
+ }
+
+ }).when(mockQueryService).removeIndex(any(Index.class));
+
+ return mockCache;
+ }
+
+ @SuppressWarnings("unchecked")
+ Cache mockRegionFactory(Cache mockCache) {
+
+ RegionFactory mockRegionFactory = mock(RegionFactory.class);
+
+ when(mockCache.createRegionFactory()).thenReturn(mockRegionFactory);
+ when(mockCache.createRegionFactory(any(RegionAttributes.class))).thenReturn(mockRegionFactory);
+ when(mockCache.createRegionFactory(any(RegionShortcut.class))).thenReturn(mockRegionFactory);
+ when(mockCache.createRegionFactory(anyString())).thenReturn(mockRegionFactory);
+
return mockCache;
}
}
@@ -196,7 +267,7 @@ public class EnableIndexesConfigurationUnitTests {
excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class,
LocalRegionEntity.class, ReplicateRegionEntity.class }))
- static class IndexedPersistentEntityConfiguration extends CacheConfiguration {
+ static class IndexedPersistentEntityConfiguration extends GemFireConfiguration {
}
@@ -204,7 +275,55 @@ public class EnableIndexesConfigurationUnitTests {
excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class,
LocalRegionEntity.class, ReplicateRegionEntity.class }))
- static class NoIndexesCreatedForIndexedPersistentEntityConfiguration extends CacheConfiguration {
+ static class NoIndexesCreatedForIndexedPersistentEntityConfiguration extends GemFireConfiguration {
}
+
+ @EnableIndexes
+ @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
+ excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
+ ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class,
+ LocalRegionEntity.class, ReplicateRegionEntity.class }))
+ static class IndexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameDefinitionConfiguration
+ extends GemFireConfiguration {
+
+ @Bean
+ @SuppressWarnings("unused")
+ IndexFactoryBean firstNameIndex(GemFireCache gemfireCache) {
+
+ IndexFactoryBean firstNameIndex = new IndexFactoryBean();
+
+ firstNameIndex.setCache(gemfireCache);
+ firstNameIndex.setName("LoyalCustomersFirstNameFunctionalIdx");
+ firstNameIndex.setExpression("first_name");
+ firstNameIndex.setFrom("/LoyalCustomers");
+ firstNameIndex.setType(IndexType.FUNCTIONAL);
+
+ return firstNameIndex;
+ }
+ }
+
+ @EnableIndexes
+ @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
+ excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
+ ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class,
+ LocalRegionEntity.class, ReplicateRegionEntity.class }))
+ static class IndexAnnotatedEntityPropertyIsIgnoredWithExistingIndexHavingSameNameConfiguration
+ extends GemFireConfiguration {
+
+ @Bean
+ @SuppressWarnings("unused")
+ IndexFactoryBean lastNameIndex(GemFireCache gemfireCache) {
+
+ IndexFactoryBean lastNameIndex = new IndexFactoryBean();
+
+ lastNameIndex.setCache(gemfireCache);
+ lastNameIndex.setName("LastNameIdx");
+ lastNameIndex.setExpression("last_name");
+ lastNameIndex.setFrom("/People");
+ lastNameIndex.setType(IndexType.HASH);
+
+ return lastNameIndex;
+ }
+ }
}
diff --git a/src/test/java/org/springframework/data/gemfire/config/xml/IndexNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/xml/IndexNamespaceTest.java
index 2d0be669..0bdf3a81 100644
--- a/src/test/java/org/springframework/data/gemfire/config/xml/IndexNamespaceTest.java
+++ b/src/test/java/org/springframework/data/gemfire/config/xml/IndexNamespaceTest.java
@@ -16,6 +16,7 @@
package org.springframework.data.gemfire.config.xml;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import javax.annotation.Resource;
@@ -25,13 +26,16 @@ import com.gemstone.gemfire.cache.query.Index;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit4.SpringRunner;
/**
- * The IndexNamespaceTest is a test suite of test cases testing the functionality of GemFire Index creation using
- * the Spring Data GemFire XML namespace (XSD).
+ * Integration tests with test cases testing the functionality of GemFire Index creation using
+ * the Spring Data GemFire XML namespace (XSD) and the {@link IndexParser}.
*
* @author Costin Leau
* @author David Turanski
@@ -43,30 +47,42 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @since 1.1.0
*/
-@RunWith(SpringJUnit4ClassRunner.class)
+@RunWith(SpringRunner.class)
@ContextConfiguration(locations="index-ns.xml", initializers=GemfireTestApplicationContextInitializer.class)
@SuppressWarnings({ "deprecation", "unused" })
public class IndexNamespaceTest {
private static final String TEST_REGION_NAME = "IndexedRegion";
- @Resource(name = "simple")
- private Index simple;
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Resource(name = "basic")
+ private Index basic;
@Resource(name = "complex")
private Index complex;
@Test
- public void testBasicIndex() throws Exception {
- assertEquals("simple", simple.getName());
- assertEquals("status", simple.getIndexedExpression());
- assertEquals(Region.SEPARATOR + TEST_REGION_NAME, simple.getFromClause());
- assertEquals(TEST_REGION_NAME, simple.getRegion().getName());
- assertEquals(com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, simple.getType());
+ public void basicIndexIsCorrect() throws Exception {
+ assertEquals("basic", basic.getName());
+ assertEquals("status", basic.getIndexedExpression());
+ assertEquals(Region.SEPARATOR + TEST_REGION_NAME, basic.getFromClause());
+ assertEquals(TEST_REGION_NAME, basic.getRegion().getName());
+ assertEquals(com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, basic.getType());
}
@Test
- public void testComplexIndex() throws Exception {
+ public void basicIndexFactoryBeanIsCorrect() {
+
+ IndexFactoryBean basicIndexFactoryBean = applicationContext.getBean("&basic", IndexFactoryBean.class);
+
+ assertThat(basicIndexFactoryBean.isIgnoreIfExists()).isFalse();
+ assertThat(basicIndexFactoryBean.isOverride()).isFalse();
+ }
+
+ @Test
+ public void complexIndexIsCorrect() throws Exception {
assertEquals("complex-index", complex.getName());
assertEquals("tsi.name", complex.getIndexedExpression());
assertEquals(Region.SEPARATOR + TEST_REGION_NAME + " tsi", complex.getFromClause());
@@ -74,4 +90,13 @@ public class IndexNamespaceTest {
assertEquals(com.gemstone.gemfire.cache.query.IndexType.HASH, complex.getType());
}
+ @Test
+ public void indexWithIgnoreAndOverrideIsCorrect() {
+
+ IndexFactoryBean indexFactoryBean =
+ applicationContext.getBean("&index-with-ignore-and-override", IndexFactoryBean.class);
+
+ assertThat(indexFactoryBean.isIgnoreIfExists()).isTrue();
+ assertThat(indexFactoryBean.isOverride()).isTrue();
+ }
}
diff --git a/src/test/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupportUnitTests.java b/src/test/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupportUnitTests.java
new file mode 100644
index 00000000..0f086965
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/support/AbstractFactoryBeanSupportUnitTests.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.gemfire.support;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.logging.Log;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.beans.factory.BeanFactory;
+
+/**
+ * Unit tests for {@link AbstractFactoryBeanSupport}.
+ *
+ * @author John Blum
+ * @see org.junit.Test
+ * @see org.mockito.Mock
+ * @see org.mockito.Mockito
+ * @see org.mockito.Spy
+ * @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
+ * @since 1.0.0
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class AbstractFactoryBeanSupportUnitTests {
+
+ @Mock
+ private Log mockLog;
+
+ @Spy
+ private TestFactoryBeanSupport> factoryBeanSupport;
+
+ @Before
+ public void setup() {
+ when(factoryBeanSupport.getLog()).thenReturn(mockLog);
+ }
+
+ @Test
+ public void setAndGetBeanClassLoader() {
+ assertThat(factoryBeanSupport.getBeanClassLoader()).isNull();
+
+ ClassLoader mockClassLoader = mock(ClassLoader.class);
+
+ factoryBeanSupport.setBeanClassLoader(mockClassLoader);
+
+ assertThat(factoryBeanSupport.getBeanClassLoader()).isSameAs(mockClassLoader);
+
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+
+ factoryBeanSupport.setBeanClassLoader(systemClassLoader);
+
+ assertThat(factoryBeanSupport.getBeanClassLoader()).isSameAs(systemClassLoader);
+
+ factoryBeanSupport.setBeanClassLoader(null);
+
+ assertThat(factoryBeanSupport.getBeanClassLoader()).isNull();
+ }
+
+ @Test
+ public void setAndGetBeanFactory() {
+ assertThat(factoryBeanSupport.getBeanFactory()).isNull();
+
+ BeanFactory mockBeanFactory = mock(BeanFactory.class);
+
+ factoryBeanSupport.setBeanFactory(mockBeanFactory);
+
+ assertThat(factoryBeanSupport.getBeanFactory()).isSameAs(mockBeanFactory);
+
+ factoryBeanSupport.setBeanFactory(null);
+
+ assertThat(factoryBeanSupport.getBeanFactory()).isNull();
+ }
+
+ @Test
+ public void setAndGetBeanName() {
+ assertThat(factoryBeanSupport.getBeanName()).isNullOrEmpty();
+
+ factoryBeanSupport.setBeanName("test");
+
+ assertThat(factoryBeanSupport.getBeanName()).isEqualTo("test");
+
+ factoryBeanSupport.setBeanName(null);
+
+ assertThat(factoryBeanSupport.getBeanName()).isNullOrEmpty();
+ }
+
+ @Test
+ public void isSingletonDefaultsToTrue() {
+ assertThat(factoryBeanSupport.isSingleton()).isTrue();
+ }
+
+ @Test
+ public void logsDebugWhenDebugIsEnabled() {
+ when(mockLog.isDebugEnabled()).thenReturn(true);
+
+ factoryBeanSupport.logDebug("%s log test", "debug");
+
+ verify(mockLog, times(1)).isDebugEnabled();
+ verify(mockLog, times(1)).debug(eq("debug log test"));
+ }
+
+ @Test
+ public void logsInfoWhenInfoIsEnabled() {
+ when(mockLog.isInfoEnabled()).thenReturn(true);
+
+ factoryBeanSupport.logInfo("%s log test", "info");
+
+ verify(mockLog, times(1)).isInfoEnabled();
+ verify(mockLog, times(1)).info(eq("info log test"));
+ }
+
+ @Test
+ public void logsWarningWhenWarnIsEnabled() {
+ when(mockLog.isWarnEnabled()).thenReturn(true);
+
+ factoryBeanSupport.logWarning("%s log test", "warn");
+
+ verify(mockLog, times(1)).isWarnEnabled();
+ verify(mockLog, times(1)).warn(eq("warn log test"));
+ }
+
+ @Test
+ public void logsWarningWhenErrorIsEnabled() {
+ when(mockLog.isErrorEnabled()).thenReturn(true);
+
+ factoryBeanSupport.logError("%s log test", "error");
+
+ verify(mockLog, times(1)).isErrorEnabled();
+ verify(mockLog, times(1)).error(eq("error log test"));
+ }
+
+ @Test
+ public void suppressesDebugLoggingWhenDebugIsDisabled() {
+ when(mockLog.isDebugEnabled()).thenReturn(false);
+
+ factoryBeanSupport.logDebug("test");
+
+ verify(mockLog, times(1)).isDebugEnabled();
+ verify(mockLog, never()).debug(any());
+ }
+
+ @Test
+ public void suppressesInfoLoggingWhenInfoIsDisabled() {
+ when(mockLog.isInfoEnabled()).thenReturn(false);
+
+ factoryBeanSupport.logInfo("test");
+
+ verify(mockLog, times(1)).isInfoEnabled();
+ verify(mockLog, never()).info(any());
+ }
+
+ @Test
+ public void suppressesWarnLoggingWhenWarnIsDisabled() {
+ when(mockLog.isWarnEnabled()).thenReturn(false);
+
+ factoryBeanSupport.logWarning("test");
+
+ verify(mockLog, times(1)).isWarnEnabled();
+ verify(mockLog, never()).warn(any());
+ }
+
+ @Test
+ public void suppressesErrorLoggingWhenInfoIsDisabled() {
+ when(mockLog.isErrorEnabled()).thenReturn(false);
+
+ factoryBeanSupport.logError("test");
+
+ verify(mockLog, times(1)).isErrorEnabled();
+ verify(mockLog, never()).error(any());
+ }
+
+ private static class TestFactoryBeanSupport extends AbstractFactoryBeanSupport {
+
+ @Override
+ public T getObject() throws Exception {
+ return null;
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return Object.class;
+ }
+ }
+}
diff --git a/src/test/resources/org/springframework/data/gemfire/config/xml/index-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/xml/index-ns.xml
index 0835a84c..9181829c 100644
--- a/src/test/resources/org/springframework/data/gemfire/config/xml/index-ns.xml
+++ b/src/test/resources/org/springframework/data/gemfire/config/xml/index-ns.xml
@@ -30,9 +30,12 @@
-
+
+
+