diff --git a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java index 4a7b59bb..798ed16e 100644 --- a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java @@ -25,10 +25,13 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +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.IndexStatistics; import com.gemstone.gemfire.cache.query.QueryService; /** @@ -47,6 +50,7 @@ import com.gemstone.gemfire.cache.query.QueryService; */ public class IndexFactoryBean implements InitializingBean, FactoryBean, BeanNameAware { + private boolean define = false; private boolean override = true; private Index index; @@ -61,6 +65,7 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B private String expression; private String from; private String imports; + private String indexName; private String name; public void afterPropertiesSet() throws Exception { @@ -68,15 +73,15 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B queryService = lookupQueryService(); - Assert.notNull(queryService, "A QueryService is required for Index creation!"); - Assert.hasText(expression, "The Index 'expression' is required!"); - Assert.hasText(from, "The Index 'from' clause (a Region's full-path) is required!"); + Assert.notNull(queryService, "QueryService is required to create an Index!"); + Assert.hasText(expression, "Index 'expression' is required!"); + Assert.hasText(from, "Index 'from' clause (a Region's full-path) is required!"); if (IndexType.isKey(indexType)) { Assert.isNull(imports, "The 'imports' property is not supported for a Key Index."); } - String indexName = (StringUtils.hasText(name) ? name : beanName); + indexName = (StringUtils.hasText(name) ? name : beanName); Assert.hasText(indexName, "The Index bean id or name is required!"); @@ -103,7 +108,13 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B try { if (IndexType.isKey(indexType)) { - return queryService.createKeyIndex(indexName, expression, from); + if (isDefine()) { + queryService.defineKeyIndex(indexName, expression, from); + return new IndexWrapper(queryService, indexName); + } + else { + return queryService.createKeyIndex(indexName, expression, from); + } } else if (IndexType.isHash(indexType)) { return createHashIndex(queryService, indexName, expression, from, imports); @@ -132,21 +143,45 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B Index createFunctionalIndex(QueryService queryService, String indexName, String expression, String from, String imports) throws Exception { if (StringUtils.hasText(imports)) { - return queryService.createIndex(indexName, expression, from, imports); + if (isDefine()) { + queryService.defineIndex(indexName, expression, from , imports); + } + else { + return queryService.createIndex(indexName, expression, from, imports); + } } else { - return queryService.createIndex(indexName, expression, from); + if (isDefine()) { + queryService.defineIndex(indexName, expression, from); + } + else { + return queryService.createIndex(indexName, expression, from); + } } + + return new IndexWrapper(queryService, indexName); } Index createHashIndex(QueryService queryService, String indexName, String expression, String from, String imports) throws Exception { if (StringUtils.hasText(imports)) { - return queryService.createHashIndex(indexName, expression, from, imports); + if (isDefine()) { + queryService.defineHashIndex(indexName, expression, from, imports); + } + else { + return queryService.createHashIndex(indexName, expression, from, imports); + } } else { - return queryService.createHashIndex(indexName, expression, from); + if (isDefine()) { + queryService.defineHashIndex(indexName, expression, from); + } + else { + return queryService.createHashIndex(indexName, expression, from); + } } + + return new IndexWrapper(queryService, indexName); } Index getExistingIndex(QueryService queryService, String indexName) { @@ -160,6 +195,7 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B } public Index getObject() { + index = (index != null ? index : getExistingIndex(queryService, indexName)); return index; } @@ -200,6 +236,25 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B 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. + * + * @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. + */ + public void setDefine(boolean define) { + this.define = define; + } + + /* (non-Javadoc) */ + protected boolean isDefine() { + return define; + } + /** * @param expression the expression to set */ @@ -221,6 +276,13 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B this.imports = imports; } + /** + * @param override the override to set + */ + public void setOverride(boolean override) { + this.override = override; + } + /** * @param type the type to set */ @@ -239,11 +301,103 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean, B this.indexType = indexType; } - /** - * @param override the override to set - */ - public void setOverride(boolean override) { - this.override = override; + /* (non-Javadoc) */ + protected static final class IndexWrapper implements Index { + + private Index index; + + private final QueryService queryService; + + 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!"); + this.queryService = queryService; + this.indexName = indexName; + + } + + protected synchronized Index getIndex() { + if (this.index == null) { + String localIndexName = getIndexName(); + + for (Index localIndex : getQueryService().getIndexes()) { + if (localIndex.getName().equals(localIndexName)) { + this.index = localIndex; + break; + } + } + + if (this.index == null) { + throw new GemfireIndexException(new IndexInvalidException(String.format( + "index with name (%1$s) was not found", localIndexName))); + } + } + + return index; + } + + protected String getIndexName() { + Assert.state(StringUtils.hasText(indexName), "The Index 'name' was not properly initialized!"); + return indexName; + } + + protected QueryService getQueryService() { + Assert.state(queryService != null, "The QueryService was not properly initialized!"); + return queryService; + } + + @Override + public String getName() { + return getIndex().getName(); + } + + @Override + public String getCanonicalizedFromClause() { + return getIndex().getCanonicalizedFromClause(); + } + + @Override + public String getCanonicalizedIndexedExpression() { + return getIndex().getCanonicalizedIndexedExpression(); + } + + @Override + public String getCanonicalizedProjectionAttributes() { + return getIndex().getCanonicalizedProjectionAttributes(); + } + + @Override + public String getFromClause() { + return getIndex().getFromClause(); + } + + @Override + public String getIndexedExpression() { + return getIndex().getIndexedExpression(); + } + + @Override + public String getProjectionAttributes() { + return getIndex().getProjectionAttributes(); + } + + @Override + public Region getRegion() { + return getIndex().getRegion(); + } + + @Override + public IndexStatistics getStatistics() { + return getIndex().getStatistics(); + } + + @Override + @SuppressWarnings("deprecation") + public com.gemstone.gemfire.cache.query.IndexType getType() { + return getIndex().getType(); + } } } diff --git a/src/main/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListener.java b/src/main/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListener.java new file mode 100644 index 00000000..d48ea472 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListener.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2013 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.config; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; + +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.GemFireCache; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.query.QueryService; + +/** + * The CreateDefinedIndexesApplicationListener class is a Spring ApplicationListener used to create + * all the GemFire Cache Region Indexes "defined" using the QueryService.defineXXXX(..) methods. + * + * @author John Blum + * @see org.springframework.context.ApplicationListener + * @see org.springframework.context.event.ContextRefreshedEvent + * @see com.gemstone.gemfire.cache.GemFireCache + * @see com.gemstone.gemfire.cache.client.ClientCache + * @see com.gemstone.gemfire.cache.query.QueryService + * @since 1.7.0 + */ +public class CreateDefinedIndexesApplicationListener implements ApplicationListener { + + protected final Log logger = initLogger(); + + /** + * Attempts to create all defined Indexes using the QueryService, defineXXXX(..) API once + * the Spring ApplicationContext has been refreshed. + * + * @param event the ContextRefreshedEvent fired when the Spring ApplicationContext gets refreshed. + * @see #getCache(org.springframework.context.event.ContextRefreshedEvent) + * @see org.springframework.context.event.ContextRefreshedEvent + * @see com.gemstone.gemfire.cache.Cache#getQueryService() + * @see com.gemstone.gemfire.cache.client.ClientCache#getLocalQueryService() + * @see com.gemstone.gemfire.cache.query.QueryService#createDefinedIndexes() + */ + @Override + public void onApplicationEvent(final ContextRefreshedEvent event) { + try { + GemFireCache cache = getCache(event); + + QueryService queryService = (cache instanceof ClientCache ? ((ClientCache) cache).getLocalQueryService() + : cache.getQueryService()); + + queryService.createDefinedIndexes(); + } + catch (Exception ignore) { + logger.warn(String.format("unable to create defined Indexes (if any): %1$s", ignore.getMessage())); + } + } + + /* (non-Javadoc) */ + Log initLogger() { + return LogFactory.getLog(getClass()); + } + + /* (non-Javadoc) */ + protected GemFireCache getCache(final ContextRefreshedEvent event) { + try { + return event.getApplicationContext().getBean(GemFireCache.class); + } + catch (BeansException e) { + return CacheFactory.getAnyInstance(); + } + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/IndexParser.java b/src/main/java/org/springframework/data/gemfire/config/IndexParser.java index 33e05afe..fac0b6a6 100644 --- a/src/main/java/org/springframework/data/gemfire/config/IndexParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/IndexParser.java @@ -16,7 +16,12 @@ package org.springframework.data.gemfire.config; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.gemfire.IndexFactoryBean; @@ -34,6 +39,20 @@ import org.w3c.dom.Element; */ class IndexParser extends AbstractSimpleBeanDefinitionParser { + private static final AtomicBoolean registered = new AtomicBoolean(false); + + protected static void registerCreateDefinedIndexesApplicationListener(ParserContext parserContext) { + if (registered.compareAndSet(false, true)) { + AbstractBeanDefinition createDefinedIndexesApplicationListener = BeanDefinitionBuilder + .genericBeanDefinition(CreateDefinedIndexesApplicationListener.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .getBeanDefinition(); + + BeanDefinitionReaderUtils.registerWithGeneratedName(createDefinedIndexesApplicationListener, + parserContext.getRegistry()); + } + + } protected Class getBeanClass(Element element) { return IndexFactoryBean.class; } @@ -45,6 +64,7 @@ class IndexParser extends AbstractSimpleBeanDefinitionParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + registerCreateDefinedIndexesApplicationListener(parserContext); ParsingUtils.setPropertyReference(element, builder, "cache-ref", "cache"); super.doParse(element, parserContext, builder); } diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd index 26bc15d5..6a42798a 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd @@ -2485,10 +2485,10 @@ The name of the index bean definition. If property 'name' is not set, it will be ]]> - + @@ -2499,6 +2499,21 @@ The name of the index. ]]> + + + + + + + + + + @@ -2515,17 +2530,10 @@ Indicates whether the index is created even if there is an index with the same n ]]> - + - - - - - diff --git a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java index aca92fb0..db5aab4a 100644 --- a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java @@ -16,13 +16,17 @@ package org.springframework.data.gemfire; +import static org.hamcrest.Matchers.startsWith; 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.eq; import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -34,15 +38,20 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.After; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +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.IndexStatistics; import com.gemstone.gemfire.cache.query.QueryService; /** @@ -60,15 +69,22 @@ import com.gemstone.gemfire.cache.query.QueryService; */ public class IndexFactoryBeanTest { - @Test - public void testAfterPropertiesSet() throws Exception { - QueryService mockQueryService = mock(QueryService.class, "testAfterPropertiesSet.MockQueryService"); + private IndexFactoryBean indexFactoryBean = new IndexFactoryBean(); - Cache mockCache = mock(Cache.class, "testAfterPropertiesSet.MockCache"); + @After + public void tearDown() { + indexFactoryBean.setDefine(false); + } + + @Test + public void afterPropertiesSetIsSuccessful() throws Exception { + Cache mockCache = mock(Cache.class, "afterPropertiesSet.MockCache"); + + QueryService mockQueryService = mock(QueryService.class, "afterPropertiesSet.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); - final Index mockIndex = mock(Index.class, "testAfterPropertiesSet.MockIndex"); + final Index mockIndex = mock(Index.class, "afterPropertiesSet.MockIndex"); IndexFactoryBean indexFactoryBean = new IndexFactoryBean() { @Override Index createIndex(final QueryService queryService, final String indexName) throws Exception { @@ -90,7 +106,7 @@ public class IndexFactoryBeanTest { } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithNullCache() throws Exception { + public void afterPropertiesSetWithNullCache() throws Exception { try { new IndexFactoryBean().afterPropertiesSet(); } @@ -101,9 +117,9 @@ public class IndexFactoryBeanTest { } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithNullQueryService() throws Exception { + public void afterPropertiesSetWithNullQueryService() throws Exception { try { - Cache mockCache = mock(Cache.class, "testAfterPropertiesSetWithNullQueryService.MockCache"); + Cache mockCache = mock(Cache.class, "afterPropertiesSetWithNullQueryService.MockCache"); when(mockCache.getQueryService()).thenReturn(null); @@ -113,18 +129,18 @@ public class IndexFactoryBeanTest { indexFactoryBean.afterPropertiesSet(); } catch (IllegalArgumentException expected) { - assertEquals("A QueryService is required for Index creation!", expected.getMessage()); + assertEquals("QueryService is required to create an Index!", expected.getMessage()); throw expected; } } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithUnspecifiedExpression() throws Exception { + public void afterPropertiesSetWithUnspecifiedExpression() throws Exception { try { - QueryService mockQueryService = mock(QueryService.class, - "testAfterPropertiesSetWithUnspecifiedExpression.MockQueryService"); + Cache mockCache = mock(Cache.class, "afterPropertiesSetWithUnspecifiedExpression.MockCache"); - Cache mockCache = mock(Cache.class, "testAfterPropertiesSetWithUnspecifiedExpression.MockCache"); + QueryService mockQueryService = mock(QueryService.class, + "afterPropertiesSetWithUnspecifiedExpression.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); @@ -134,18 +150,18 @@ public class IndexFactoryBeanTest { indexFactoryBean.afterPropertiesSet(); } catch (IllegalArgumentException expected) { - assertEquals("The Index 'expression' is required!", expected.getMessage()); + assertEquals("Index 'expression' is required!", expected.getMessage()); throw expected; } } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithUnspecifiedFromClause() throws Exception { + public void afterPropertiesSetWithUnspecifiedFromClause() throws Exception { try { - QueryService mockQueryService = mock(QueryService.class, - "testAfterPropertiesSetWithUnspecifiedFromClause.MockQueryService"); + Cache mockCache = mock(Cache.class, "afterPropertiesSetWithUnspecifiedFromClause.MockCache"); - Cache mockCache = mock(Cache.class, "testAfterPropertiesSetWithUnspecifiedFromClause.MockCache"); + QueryService mockQueryService = mock(QueryService.class, + "afterPropertiesSetWithUnspecifiedFromClause.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); @@ -156,18 +172,18 @@ public class IndexFactoryBeanTest { indexFactoryBean.afterPropertiesSet(); } catch (IllegalArgumentException expected) { - assertEquals("The Index 'from' clause (a Region's full-path) is required!", expected.getMessage()); + assertEquals("Index 'from' clause (a Region's full-path) is required!", expected.getMessage()); throw expected; } } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithUnspecifiedIndexName() throws Exception { + public void afterPropertiesSetWithUnspecifiedIndexName() throws Exception { try { - QueryService mockQueryService = mock(QueryService.class, - "testAfterPropertiesSetWithUnspecifiedIndexName.MockQueryService"); + Cache mockCache = mock(Cache.class, "afterPropertiesSetWithUnspecifiedIndexName.MockCache"); - Cache mockCache = mock(Cache.class, "testAfterPropertiesSetWithUnspecifiedIndexName.MockCache"); + QueryService mockQueryService = mock(QueryService.class, + "afterPropertiesSetWithUnspecifiedIndexName.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); @@ -187,12 +203,12 @@ public class IndexFactoryBeanTest { } @Test(expected = IllegalArgumentException.class) - public void testAfterPropertiesSetWithInvalidTypeUsingImports() throws Exception { + public void afterPropertiesSetWithInvalidTypeUsingImports() throws Exception { try { - QueryService mockQueryService = mock(QueryService.class, - "testAfterPropertiesSetWithInvalidTypeUsingImports.MockQueryService"); + Cache mockCache = mock(Cache.class, "afterPropertiesSetWithInvalidTypeUsingImports.MockCache"); - Cache mockCache = mock(Cache.class, "testAfterPropertiesSetWithInvalidTypeUsingImports.MockCache"); + QueryService mockQueryService = mock(QueryService.class, + "afterPropertiesSetWithInvalidTypeUsingImports.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); @@ -231,10 +247,10 @@ public class IndexFactoryBeanTest { } @Test - public void testLookupQueryServiceOnClientCache() { - QueryService mockQueryService = mock(QueryService.class, "testLookupQueryServiceOnClientCache.MockQueryService"); + public void lookupQueryServiceOnClientCache() { + ClientCache mockClientCache = mock(ClientCache.class, "lookupQueryServiceOnClientCache.MockClientCache"); - ClientCache mockClientCache = mock(ClientCache.class, "testLookupQueryServiceOnClientCache.MockClientCache"); + QueryService mockQueryService = mock(QueryService.class, "lookupQueryServiceOnClientCache.MockQueryService"); when(mockClientCache.getLocalQueryService()).thenReturn(mockQueryService); @@ -248,10 +264,10 @@ public class IndexFactoryBeanTest { } @Test - public void testLookupQueryServiceOnPeerCache() { - QueryService mockQueryService = mock(QueryService.class, "testLookupQueryServiceOnPeerCache.MockQueryService"); + public void lookupQueryServiceOnPeerCache() { + Cache mockCache = mock(Cache.class, "lookupQueryServiceOnPeerCache.MockCache"); - Cache mockCache = mock(Cache.class, "testLookupQueryServiceOnPeerCache.MockCache"); + QueryService mockQueryService = mock(QueryService.class, "lookupQueryServiceOnPeerCache.MockQueryService"); when(mockCache.getQueryService()).thenReturn(mockQueryService); @@ -266,10 +282,10 @@ public class IndexFactoryBeanTest { } @Test - public void testCreateIndexReturnsNewKeyIndex() throws Exception { - Index mockIndex = mock(Index.class, "testCreateIndexReturnsNewKeyIndex.MockIndex"); + public void createIndexReturningNewKeyIndex() throws Exception { + Index mockIndex = mock(Index.class, "createIndexReturningNewKeyIndex.MockIndex"); - QueryService mockQueryService = mock(QueryService.class, "testCreateIndexReturnsNewKeyIndex.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createIndexReturningNewKeyIndex.MockQueryService"); when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList()); when(mockQueryService.createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example"))).thenReturn(mockIndex); @@ -285,13 +301,15 @@ public class IndexFactoryBeanTest { Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "KeyIndex"); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createKeyIndex(eq("KeyIndex"), eq("id"), eq("/Example")); } @Test - public void testCreateIndexReturnsNewHashIndex() throws Exception { - Index mockIndex = mock(Index.class, "testCreateIndexReturnsNewHashIndex.MockIndex"); + public void createIndexReturningNewHashIndex() throws Exception { + Index mockIndex = mock(Index.class, "createIndexReturningNewHashIndex.MockIndex"); - QueryService mockQueryService = mock(QueryService.class, "testCreateIndexReturnsNewHashIndex.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createIndexReturningNewHashIndex.MockQueryService"); when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList()); when(mockQueryService.createHashIndex(eq("HashIndex"), eq("name"), eq("/Animals"), eq("org.example.Dog"))) @@ -309,14 +327,17 @@ public class IndexFactoryBeanTest { Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "HashIndex"); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createHashIndex(eq("HashIndex"), eq("name"), eq("/Animals"), + eq("org.example.Dog")); } @Test - public void testCreateIndexReturnsNewFunctionalIndex() throws Exception { - Index mockIndex = mock(Index.class, "testCreateIndexReturnsNewFunctionalIndex.MockIndex"); + public void createIndexReturningNewFunctionalIndex() throws Exception { + Index mockIndex = mock(Index.class, "createIndexReturningNewFunctionalIndex.MockIndex"); QueryService mockQueryService = mock(QueryService.class, - "testCreateIndexReturnsNewFunctionalIndex.MockQueryService"); + "createIndexReturningNewFunctionalIndex.MockQueryService"); when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList()); when(mockQueryService.createIndex(eq("FunctionalIndex"), eq("someField"), eq("/Example"))) @@ -334,14 +355,16 @@ public class IndexFactoryBeanTest { Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "FunctionalIndex"); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndex"), eq("someField"), eq("/Example")); } @Test - public void testCreateIndexReturnsExistingIndex() throws Exception { - Index mockExistingIndex = mock(Index.class, "testCreateIndexReturnsExistingIndex.MockIndex.Existing"); - Index mockIndexTwo = mock(Index.class, "testCreateIndexReturnsExistingIndex.MockIndex.Two"); + public void createIndexReturnsExistingIndex() throws Exception { + Index mockExistingIndex = mock(Index.class, "createIndexReturnsExistingIndex.MockIndex.Existing"); + Index mockIndexTwo = mock(Index.class, "createIndexReturnsExistingIndex.MockIndex.Two"); - QueryService mockQueryService = mock(QueryService.class, "testCreateIndexReturnsExistingIndex.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createIndexReturnsExistingIndex.MockQueryService"); when(mockExistingIndex.getName()).thenReturn("ExistingIndex"); when(mockIndexTwo.getName()).thenReturn("IndexTwo"); @@ -358,12 +381,12 @@ public class IndexFactoryBeanTest { } @Test - public void testCreateIndexReturnsExistingIndexForIndexExistsException() throws Exception { + public void createIndexReturnsExistingIndexAndThrowsIndexExistsExceptionOnCreate() throws Exception { Index mockExistingIndex = mock(Index.class, - "testCreateIndexReturnsExistingIndexForIndexExistsException.MockIndex.Existing"); + "createIndexReturnsExistingIndexAndThrowsIndexExistsExceptionOnCreate.MockIndex.Existing"); QueryService mockQueryService = mock(QueryService.class, - "testCreateIndexReturnsExistingIndexForIndexExistsException.MockQueryService"); + "createIndexReturnsExistingIndexAndThrowsIndexExistsExceptionOnCreate.MockQueryService"); when(mockExistingIndex.getName()).thenReturn("ExistingIndex"); when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockExistingIndex)); @@ -385,15 +408,15 @@ public class IndexFactoryBeanTest { verify(mockExistingIndex, times(2)).getName(); verify(mockQueryService, times(2)).getIndexes(); verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex)); + verify(mockQueryService, times(1)).createKeyIndex(eq("ExistingIndex"), eq("id"), eq("/Example")); } @Test - public void testCreateIndexOverridesExistingIndex() throws Exception { - Index mockExistingIndex = mock(Index.class, "testCreateIndexOverridesExistingIndex.MockIndex.Existing"); - Index mockOverridingIndex = mock(Index.class, "testCreateIndexOverridesExistingIndex.MockIndex.Overriding"); + public void createIndexOverridesExistingIndex() throws Exception { + Index mockExistingIndex = mock(Index.class, "createIndexOverridesExistingIndex.MockIndex.Existing"); + Index mockOverridingIndex = mock(Index.class, "createIndexOverridesExistingIndex.MockIndex.Overriding"); - QueryService mockQueryService = mock(QueryService.class, - "testCreateIndexOverridesExistingIndex.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createIndexOverridesExistingIndex.MockQueryService"); when(mockExistingIndex.getName()).thenReturn("ExistingIndex"); when(mockOverridingIndex.getName()).thenReturn("OverridingIndex"); @@ -415,19 +438,21 @@ public class IndexFactoryBeanTest { verify(mockQueryService, times(1)).getIndexes(); verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex)); + verify(mockQueryService, times(1)).createHashIndex(eq("ExistingIndex"), eq("someField"), eq("/Example"), + eq("org.example.DomainType")); } @Test - public void testCreateIndexAddsExistingIndexOnException() throws Exception { - final Index mockExistingIndex = mock(Index.class, "testCreateIndexAddsExistingIndexOnException.MockIndex.Existing"); - final Index mockIndexTwo = mock(Index.class, "testCreateIndexAddsExistingIndexOnException.MockIndex.Two"); + public void createIndexAddsExistingIndexOnException() throws Exception { + final Index mockExistingIndex = mock(Index.class, "createIndexAddsExistingIndexOnException.MockIndex.Existing"); + final Index mockIndexTwo = mock(Index.class, "createIndexAddsExistingIndexOnException.MockIndex.Two"); final List indexes = new ArrayList(1); indexes.add(mockIndexTwo); QueryService mockQueryService = mock(QueryService.class, - "testCreateIndexAddsExistingIndexOnException.MockQueryService"); + "createIndexAddsExistingIndexOnException.MockQueryService"); when(mockExistingIndex.getName()).thenReturn("ExistingIndex"); when(mockIndexTwo.getName()).thenReturn("IndexTwo"); @@ -469,13 +494,15 @@ public class IndexFactoryBeanTest { 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 testCreateIndexThrowsException() throws Exception { - Index mockExistingIndex = mock(Index.class, "testCreateIndexThrowsException.MockIndex.Existing"); + public void createIndexThrowsExceptionOnAbsoluteFailure() throws Exception { + Index mockExistingIndex = mock(Index.class, "createIndexThrowsExceptionOnAbsoluteFailure.MockIndex.Existing"); - QueryService mockQueryService = mock(QueryService.class, "testCreateIndexThrowsException.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, + "createIndexThrowsExceptionOnAbsoluteFailure.MockQueryService"); when(mockExistingIndex.getName()).thenReturn("ExistingIndex"); when(mockQueryService.getIndexes()).thenReturn(Collections.singletonList(mockExistingIndex)); @@ -498,83 +525,209 @@ public class IndexFactoryBeanTest { finally { verify(mockQueryService, times(2)).getIndexes(); verify(mockQueryService, times(1)).removeIndex(same(mockExistingIndex)); + verify(mockQueryService, times(1)).createIndex(eq("ExistingIndex"), eq("someField"), eq("/Example")); } } @Test - public void testCreateFunctionalIndex() throws Exception { - Index mockIndex = mock(Index.class, "testCreateFunctionalIndex.MockIndex"); + public void createIndexDefinesKeyIndex() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "createIndexDefinesKeyIndex.MockQueryService"); - QueryService mockQueryService = mock(QueryService.class, "testCreateFunctionalIndex.MockQueryService"); + when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList()); + + IndexFactoryBean indexFactoryBean = new IndexFactoryBean(); + + indexFactoryBean.setDefine(true); + indexFactoryBean.setExpression("id"); + indexFactoryBean.setFrom("/Example"); + indexFactoryBean.setName("MockIndex"); + indexFactoryBean.setType("key"); + + Index actualIndex = indexFactoryBean.createIndex(mockQueryService, "MockIndex"); + + assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper); + + IndexFactoryBean.IndexWrapper indexWrapper = (IndexFactoryBean.IndexWrapper) actualIndex; + + assertSame(mockQueryService, indexWrapper.getQueryService()); + assertEquals("MockIndex", indexWrapper.getIndexName()); + + verify(mockQueryService, times(1)).defineKeyIndex(eq("MockIndex"), eq("id"), eq("/Example")); + } + + @Test + public void createFunctionalIndex() throws Exception { + Index mockIndex = mock(Index.class, "createFunctionalIndex.MockIndex"); + + QueryService mockQueryService = mock(QueryService.class, "createFunctionalIndex.MockQueryService"); when(mockQueryService.createIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"))) .thenReturn(mockIndex); - Index actualIndex = new IndexFactoryBean().createFunctionalIndex(mockQueryService, "FunctionalIndex", + Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndex", "purchaseDate", "/Orders", null); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders")); } @Test - public void testCreateFunctionalIndexWithImports() throws Exception { - Index mockIndex = mock(Index.class, "testCreateFunctionalIndexWithImports.MockIndex"); + public void createFunctionalIndexWithImports() throws Exception { + Index mockIndex = mock(Index.class, "createFunctionalIndexWithImports.MockIndex"); - QueryService mockQueryService = mock(QueryService.class, "testCreateFunctionalIndexWithImports.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createFunctionalIndexWithImports.MockQueryService"); when(mockQueryService.createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"), eq("/Orders"), eq("org.example.Order"))).thenReturn(mockIndex); - Index actualIndex = new IndexFactoryBean().createFunctionalIndex(mockQueryService, "FunctionalIndexWithImports", + Index actualIndex = indexFactoryBean.createFunctionalIndex(mockQueryService, "FunctionalIndexWithImports", "purchaseDate", "/Orders", "org.example.Order"); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createIndex(eq("FunctionalIndexWithImports"), eq("purchaseDate"), + eq("/Orders"), eq("org.example.Order")); } @Test - public void testCreateHashIndex() throws Exception { - Index mockIndex = mock(Index.class, "testCreateHashIndex.MockIndex"); + public void defineFunctionalIndex() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "defineFunctionalIndex.MockQueryService"); - QueryService mockQueryService = mock(QueryService.class, "testCreateHashIndex.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()); + + verify(mockQueryService, times(1)).defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders")); + } + + @Test + public void defineFunctionalIndexWithImports() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "defineFunctionalIndexWithImports.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, "FunctionalIndex", + "purchaseDate", "/Orders", "org.example.Order"); + + assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper); + assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()); + assertEquals("FunctionalIndex", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()); + + verify(mockQueryService, times(1)).defineIndex(eq("FunctionalIndex"), eq("purchaseDate"), eq("/Orders"), + eq("org.example.Order")); + } + + @Test + public void createHashIndex() throws Exception { + Index mockIndex = mock(Index.class, "createHashIndex.MockIndex"); + + QueryService mockQueryService = mock(QueryService.class, "createHashIndex.MockQueryService"); when(mockQueryService.createHashIndex(eq("HashIndex"), eq("name"), eq("/People"))).thenReturn(mockIndex); - Index actualIndex = new IndexFactoryBean().createHashIndex(mockQueryService, "HashIndex", + Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndex", "name", "/People", " "); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createHashIndex(eq("HashIndex"), eq("name"), eq("/People")); } @Test - public void testCreateHashIndexWithImports() throws Exception { - Index mockIndex = mock(Index.class, "testCreateHashIndexWithImports.MockIndex"); + public void createHashIndexWithImports() throws Exception { + Index mockIndex = mock(Index.class, "createHashIndexWithImports.MockIndex"); - QueryService mockQueryService = mock(QueryService.class, "testCreateHashIndexWithImports.MockQueryService"); + QueryService mockQueryService = mock(QueryService.class, "createHashIndexWithImports.MockQueryService"); when(mockQueryService.createHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"), eq("org.example.Person"))).thenReturn(mockIndex); - Index actualIndex = new IndexFactoryBean().createHashIndex(mockQueryService, "HashIndexWithImports", + Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndexWithImports", "name", "/People", "org.example.Person"); assertSame(mockIndex, actualIndex); + + verify(mockQueryService, times(1)).createHashIndex(eq("HashIndexWithImports"), eq("name"), eq("/People"), + eq("org.example.Person")); } @Test - public void testGetExistingIndex() { - 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 defineHashIndex() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "defineHashIndex.MockQueryService"); - QueryService mockQueryService = mock(QueryService.class, "testGetExistingIndex.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()); + + verify(mockQueryService, times(1)).defineHashIndex(eq("HashIndex"), eq("name"), eq("/People")); + } + + @Test + public void defineHashIndexWithImports() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "defineHashIndex.MockQueryService"); + + doAnswer(new Answer() { + @Override public Void answer(final InvocationOnMock invocation) throws Throwable { + return null; + } + }).when(mockQueryService).defineHashIndex(eq("HashIndex"), eq("name"), eq("/People"), eq("org.example.Person")); + + indexFactoryBean.setDefine(true); + + Index actualIndex = indexFactoryBean.createHashIndex(mockQueryService, "HashIndex", + "name", "/People", "org.example.Person"); + + assertTrue(actualIndex instanceof IndexFactoryBean.IndexWrapper); + assertSame(mockQueryService, ((IndexFactoryBean.IndexWrapper) actualIndex).getQueryService()); + assertEquals("HashIndex", ((IndexFactoryBean.IndexWrapper) actualIndex).getIndexName()); + + verify(mockQueryService, times(1)).defineHashIndex(eq("HashIndex"), eq("name"), eq("/People"), + eq("org.example.Person")); + } + + @Test + public void getExistingIndex() { + Index mockIndexOne = mock(Index.class, "getExistingIndex.MockIndex.One"); + Index mockIndexTwo = mock(Index.class, "getExistingIndex.MockIndex.Two"); + Index mockIndexThree = mock(Index.class, "getExistingIndex.MockIndex.Two"); + + QueryService mockQueryService = mock(QueryService.class, "getExistingIndex.MockQueryService"); when(mockIndexOne.getName()).thenReturn("PrimaryIndex"); when(mockIndexTwo.getName()).thenReturn("SecondaryIndex"); when(mockIndexThree.getName()).thenReturn("TernaryIndex"); when(mockQueryService.getIndexes()).thenReturn(Arrays.asList(mockIndexOne, mockIndexTwo, mockIndexThree)); - IndexFactoryBean indexFactoryBean = new IndexFactoryBean(); - assertNull(indexFactoryBean.getExistingIndex(mockQueryService, null)); assertNull(indexFactoryBean.getExistingIndex(mockQueryService, "")); assertNull(indexFactoryBean.getExistingIndex(mockQueryService, " ")); @@ -586,4 +739,126 @@ public class IndexFactoryBeanTest { assertSame(mockIndexThree, indexFactoryBean.getExistingIndex(mockQueryService, "ternaryindex")); } + @Test + public void getObjectLooksUpIndex() throws Exception { + QueryService mockQueryService = mock(QueryService.class, "getObjectLooksUpIndex.MockQueryService"); + + 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); + } + }); + + IndexFactoryBean indexFactoryBean = new IndexFactoryBean(); + + indexFactoryBean.setQueryService(mockQueryService); + indexFactoryBean.setName("MockIndex1"); + ReflectionUtils.setField(IndexFactoryBean.class.getDeclaredField("indexName"), indexFactoryBean, "MockIndex1"); + + Index actualIndex = indexFactoryBean.getObject(); + + assertNotNull(actualIndex); + assertEquals("MockIndex1", actualIndex.getName()); + + Index sameIndex = indexFactoryBean.getObject(); + + assertSame(actualIndex, sameIndex); + } + + @Test + public void indexFactoryBeanCreatesSingleIndex() { + assertTrue(indexFactoryBean.isSingleton()); + } + + @Test + @SuppressWarnings("deprecation") + public void indexWrapperDelegation() { + Index mockIndex = mock(Index.class, "indexWrapperDelegation.MockIndex"); + + IndexStatistics mockIndexStats = mock(IndexStatistics.class, "indexWrapperDelegation.MockIndexStats"); + + QueryService mockQueryService = mock(QueryService.class, "indexWrapperDelegation.MockQueryService"); + + when(mockIndex.getCanonicalizedFromClause()).thenReturn("/Example"); + when(mockIndex.getCanonicalizedIndexedExpression()).thenReturn("ID"); + when(mockIndex.getCanonicalizedProjectionAttributes()).thenReturn("identifier"); + when(mockIndex.getFromClause()).thenReturn("Example"); + when(mockIndex.getIndexedExpression()).thenReturn("id"); + when(mockIndex.getName()).thenReturn("MockIndex"); + when(mockIndex.getProjectionAttributes()).thenReturn("id"); + when(mockIndex.getStatistics()).thenReturn(mockIndexStats); + 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"); + + assertNotNull(indexWrapper); + assertEquals("MockIndex", indexWrapper.getIndexName()); + assertSame(mockQueryService, indexWrapper.getQueryService()); + + Index actualIndex = indexWrapper.getIndex(); + + 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()); + + Index sameIndex = indexWrapper.getIndex(); + + assertSame(actualIndex, sameIndex); + } + + @Test(expected = IllegalArgumentException.class) + public void createIndexWrapperWithNullQueryService() { + try { + new IndexFactoryBean.IndexWrapper(null, "TestIndex"); + } + catch (IllegalArgumentException expected) { + assertEquals("QueryService must not be null", expected.getMessage()); + throw expected; + } + } + + @Test(expected = IllegalArgumentException.class) + public void createIndexWrapperWithUnspecifiedIndexName() { + try { + new IndexFactoryBean.IndexWrapper(mock(QueryService.class), " "); + } + catch (IllegalArgumentException expected) { + assertEquals("The name of the Index must be specified!", expected.getMessage()); + throw expected; + } + } + + @Test(expected = GemfireIndexException.class) + public void indexWrapperGetIndexWhenIndexNotFound() { + QueryService mockQueryService = mock(QueryService.class, "indexWrapperGetIndexWhenIndexNotFound.MockQueryService"); + + when(mockQueryService.getIndexes()).thenReturn(Collections.emptyList()); + + IndexFactoryBean.IndexWrapper indexWrapper = new IndexFactoryBean.IndexWrapper(mockQueryService, "NonExistingIndex"); + + assertNotNull(indexWrapper); + assertEquals("NonExistingIndex", indexWrapper.getIndexName()); + assertSame(mockQueryService, indexWrapper.getQueryService()); + + try { + indexWrapper.getIndex(); + } + catch (GemfireIndexException expected) { + assertThat(expected.getMessage(), startsWith("index with name (NonExistingIndex) was not found")); + assertTrue(expected.getCause() instanceof IndexInvalidException); + throw expected; + } + } + } diff --git a/src/test/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListenerTest.java b/src/test/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListenerTest.java new file mode 100644 index 00000000..47de3da2 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/CreateDefinedIndexesApplicationListenerTest.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010-2013 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.config; + +import static org.junit.Assert.assertSame; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.startsWith; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashMap; + +import org.apache.commons.logging.Log; +import org.junit.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; + +import com.gemstone.gemfire.cache.CacheClosedException; +import com.gemstone.gemfire.cache.GemFireCache; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.query.MultiIndexCreationException; +import com.gemstone.gemfire.cache.query.QueryService; + +/** + * The CreateDefinedIndexesApplicationListenerTest class is a test suite of test cases testing the contract + * and functionality of the CreateDefinedIndexesApplicationListener class. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.data.gemfire.config.CreateDefinedIndexesApplicationListener + * @see org.springframework.context.ApplicationContext + * @see org.springframework.context.event.ContextRefreshedEvent + * @see com.gemstone.gemfire.cache.GemFireCache + * @see com.gemstone.gemfire.cache.query.QueryService + * @since 1.7.0 + */ +public class CreateDefinedIndexesApplicationListenerTest { + + private CreateDefinedIndexesApplicationListener listener = new CreateDefinedIndexesApplicationListener(); + + @Test + public void getCacheWithApplicationContext() { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, + "getCacheWithApplicationContext.MockApplicationContext"); + + ContextRefreshedEvent mockEvent = mock(ContextRefreshedEvent.class, + "getCacheWithApplicationContext.MockContextRefreshedEvent"); + + GemFireCache mockGemFireCache = mock(GemFireCache.class, "getCacheWithApplicationContext.MockGemFireCache"); + + when(mockEvent.getApplicationContext()).thenReturn(mockApplicationContext); + when(mockApplicationContext.getBean(eq(GemFireCache.class))).thenReturn(mockGemFireCache); + + GemFireCache actualGemFireCache = listener.getCache(mockEvent); + + assertSame(mockGemFireCache, actualGemFireCache); + } + + @Test(expected = CacheClosedException.class) + public void getCacheWithApplicationContextThrowingABeansException() { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, + "getCacheWhenApplicationContextThrowsBeanException.MockApplicationContext"); + + ContextRefreshedEvent mockEvent = mock(ContextRefreshedEvent.class, + "getCacheWhenApplicationContextThrowsBeanException.MockContextRefreshedEvent"); + + when(mockEvent.getApplicationContext()).thenReturn(mockApplicationContext); + when(mockApplicationContext.getBean(eq(GemFireCache.class))).thenThrow( + new NoSuchBeanDefinitionException("gemfireCachce")); + + listener.getCache(mockEvent); + } + + @Test + public void createDefinedIndexesCalledOnContextRefreshedEvent() throws Exception { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, + "createDefinedIndexesCalledOnContextRefreshedEvent.MockApplicationContext"); + + ContextRefreshedEvent mockEvent = mock(ContextRefreshedEvent.class, + "createDefinedIndexesCalledOnContextRefreshedEvent.MockContextRefreshedEvent"); + + GemFireCache mockGemFireCache = mock(GemFireCache.class, + "createDefinedIndexesCalledOnContextRefreshedEvent.MockGemFireCache"); + + QueryService mockQueryService = mock(QueryService.class, + "createDefinedIndexesCalledOnContextRefreshedEvent.MockQueryService"); + + when(mockEvent.getApplicationContext()).thenReturn(mockApplicationContext); + when(mockApplicationContext.getBean(eq(GemFireCache.class))).thenReturn(mockGemFireCache); + when(mockGemFireCache.getQueryService()).thenReturn(mockQueryService); + + listener.onApplicationEvent(mockEvent); + + verify(mockQueryService, times(1)).createDefinedIndexes(); + } + + @Test + public void createDefinedIndexesThrowingAnExceptionIsLogged() throws Exception { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, + "createDefinedIndexesThrowingAnExceptionIsLogged.MockApplicationContext"); + + ContextRefreshedEvent mockEvent = mock(ContextRefreshedEvent.class, + "createDefinedIndexesThrowingAnExceptionIsLogged.MockContextRefreshedEvent"); + + GemFireCache mockGemFireCache = mock(GemFireCache.class, + "createDefinedIndexesThrowingAnExceptionIsLogged.MockGemFireCache"); + + QueryService mockQueryService = mock(QueryService.class, + "createDefinedIndexesThrowingAnExceptionIsLogged.MockQueryService"); + + when(mockEvent.getApplicationContext()).thenReturn(mockApplicationContext); + when(mockApplicationContext.getBean(eq(GemFireCache.class))).thenReturn(mockGemFireCache); + when(mockGemFireCache.getQueryService()).thenReturn(mockQueryService); + when(mockQueryService.createDefinedIndexes()).thenThrow(new MultiIndexCreationException( + new HashMap(Collections.singletonMap("TestKey", new RuntimeException("TEST"))))); + + final Log mockLog = mock(Log.class, "createDefinedIndexesThrowingAnExceptionIsLogged.MockLog"); + + CreateDefinedIndexesApplicationListener listener = new CreateDefinedIndexesApplicationListener() { + @Override Log initLogger() { + return mockLog; + } + }; + + listener.onApplicationEvent(mockEvent); + + verify(mockLog, times(1)).warn(startsWith("unable to create defined Indexes (if any):")); + } + + @Test + public void createDefinedIndexesUsingClientCacheLocalQueryService() throws Exception { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, + "createDefinedIndexesUsingClientCacheLocalQueryService.MockApplicationContext"); + + ContextRefreshedEvent mockEvent = mock(ContextRefreshedEvent.class, + "createDefinedIndexesUsingClientCacheLocalQueryService.MockContextRefreshedEvent"); + + ClientCache mockClientCache = mock(ClientCache.class, + "createDefinedIndexesUsingClientCacheLocalQueryService.MockGemFireCache"); + + QueryService mockQueryService = mock(QueryService.class, + "createDefinedIndexesUsingClientCacheLocalQueryService.MockQueryService"); + + when(mockEvent.getApplicationContext()).thenReturn(mockApplicationContext); + when(mockApplicationContext.getBean(eq(GemFireCache.class))).thenReturn(mockClientCache); + when(mockClientCache.getLocalQueryService()).thenReturn(mockQueryService); + + listener.onApplicationEvent(mockEvent); + + verify(mockQueryService, times(1)).createDefinedIndexes(); + } + +}