diff --git a/src/main/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBean.java b/src/main/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBean.java index 50736415..8284484d 100644 --- a/src/main/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBean.java @@ -39,13 +39,13 @@ import org.apache.geode.cache.lucene.LuceneIndexFactory; import org.apache.geode.cache.lucene.LuceneService; import org.apache.geode.cache.lucene.LuceneServiceProvider; import org.apache.lucene.analysis.Analyzer; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.gemfire.config.annotation.IndexConfigurer; import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport; import org.springframework.data.gemfire.util.CacheUtils; +import org.springframework.data.gemfire.util.SpringUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -118,19 +118,26 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport indexConfigurers) { stream(nullSafeIterable(indexConfigurers).spliterator(), false) .forEach(indexConfigurer -> indexConfigurer.configure(indexName, this)); } + /** + * Creates a {@link LuceneIndex} with the given {@code indexName} on the {@link GemFireCache} {@link Region} + * identified by the given {@code regionPath}. + * + * @param indexName {@link String} containing the name for the {@link LuceneIndex}. + * @param regionPath {@link String} containing the fully-qualified pathname to + * the {@link GemFireCache} {@link Region}. + * @return a new instance of {@link LuceneIndex} with the given {@code indexName} on the named {@link Region}. + * @see org.apache.geode.cache.lucene.LuceneService#createIndexFactory() + * @see org.apache.geode.cache.lucene.LuceneService#getIndex(String, String) + * @see org.apache.geode.cache.lucene.LuceneIndexFactory#create(String, String) + * @see #resolveLuceneService() + * @see #postProcess(LuceneIndexFactory) + * @see #getFieldAnalyzers() + * @see #getFields() + * @see #resolveFields(List) + */ + protected LuceneIndex createLuceneIndex(String indexName, String regionPath) { + + LuceneService luceneService = resolveLuceneService(); + + LuceneIndexFactory indexFactory = luceneService.createIndexFactory(); + + Map fieldAnalyzers = getFieldAnalyzers(); + + if (isEmpty(fieldAnalyzers)) { + indexFactory.setFields(asArray(resolveFields(getFields()))); + } + else { + indexFactory.setFields(fieldAnalyzers); + } + + indexFactory = postProcess(indexFactory); + indexFactory.create(indexName, regionPath); + + return luceneService.getIndex(indexName, regionPath); + } + + /** + * Converts the {@link List} of {@link String Strings} into an {@link String[]} array. + * + * @param list {@link List} to convert into a typed array. + * @return a {@link String[]} array for the {@link List} of {@link String Strings}. + * @see java.util.List#toArray(Object[]) + */ + private String[] asArray(List list) { + return list.toArray(new String[list.size()]); + } + + /** + * Performs additional post processing to the newly created {@link LuceneIndexFactory}. + * + * @param luceneIndexFactory {@link LuceneIndexFactory} to post process. + * @return the given {@link LuceneIndexFactory}. + * @see org.apache.geode.cache.lucene.LuceneIndexFactory + */ + protected LuceneIndexFactory postProcess(LuceneIndexFactory luceneIndexFactory) { + return luceneIndexFactory; + } + + /** + * Performs additional post processing to the newly created {@link LuceneIndex}. + * + * @param luceneIndex {@link LuceneIndex} created by this {@link LuceneIndexFactoryBean}. + * @return the given {@link LuceneIndex}. + * @see org.apache.geode.cache.lucene.LuceneIndex + */ + protected LuceneIndex postProcess(LuceneIndex luceneIndex) { + return luceneIndex; + } + /** * Attempts to resolve a {@link LuceneIndex} by the given {@link String indexName} first then attempts to create * the {@link LuceneIndex} with the given {@link Region#getFullPath() Region path}. @@ -169,60 +247,16 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport luceneIndexSupplier = () -> Optional.ofNullable(resolveLuceneService()) .map(luceneService -> luceneService.getIndex(indexName, regionPath)) - .orElseGet(() -> createLuceneIndex(indexName, regionPath)); + .orElseGet(() -> postProcess(createLuceneIndex(indexName, regionPath))); return getLuceneIndex().orElseGet(luceneIndexSupplier); } - /** - * Creates a {@link LuceneIndex} with the given {@code indexName} on the {@link GemFireCache} {@link Region} - * identified by the given {@code regionPath}. - * - * @param indexName {@link String} containing the name for the {@link LuceneIndex}. - * @param regionPath {@link String} containing the fully-qualified pathname to - * the {@link GemFireCache} {@link Region}. - * @return a new instance of {@link LuceneIndex} with the given {@code indexName} on the named {@link Region}. - * @see org.apache.geode.cache.lucene.LuceneIndexFactory#create(String, String) - * @see org.apache.geode.cache.lucene.LuceneService#getIndex(String, String) - * @see #resolveLuceneService() - * @see #getFieldAnalyzers() - * @see #getFields() - * @see #resolveFields(List) - */ - protected LuceneIndex createLuceneIndex(String indexName, String regionPath) { - - LuceneService luceneService = resolveLuceneService(); - - LuceneIndexFactory indexFactory = luceneService.createIndexFactory(); - - Map fieldAnalyzers = getFieldAnalyzers(); - - if (isEmpty(fieldAnalyzers)) { - indexFactory.setFields(asArray(resolveFields(getFields()))).create(indexName, regionPath); - } - else { - indexFactory.setFields(fieldAnalyzers).create(indexName, regionPath); - } - - return luceneService.getIndex(indexName, regionPath); - } - - /** - * Converts the {@link List} of {@link String Strings} into an {@link String[]} array. - * - * @param list {@link List} to convert into a typed array. - * @return a {@link String[]} array for the {@link List} of {@link String Strings}. - * @see java.util.List#toArray(Object[]) - */ - private String[] asArray(List list) { - return list.toArray(new String[list.size()]); - } - /** * @inheritDoc */ @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("all") public void destroy() throws Exception { LuceneIndex luceneIndex = getObject(); @@ -242,7 +276,7 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport luceneService.getIndex(getIndexName(), resolveRegionPath())) - .orElse(null)); + .orElse(null)); } return this.luceneIndex; @@ -265,7 +299,10 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport getObjectType() { - return Optional.ofNullable(this.luceneIndex).>map(LuceneIndex::getClass).orElse(LuceneIndex.class); + + return Optional.ofNullable(this.luceneIndex) + .>map(LuceneIndex::getClass) + .orElse(LuceneIndex.class); } /** @@ -287,7 +324,7 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport resolveFields(List fields) { - return (!isEmpty(fields) ? fields : Collections.singletonList(LuceneService.REGION_VALUE_FIELD)); + return !isEmpty(fields) ? fields : Collections.singletonList(LuceneService.REGION_VALUE_FIELD); } /** @@ -313,15 +350,10 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport - Optional.ofNullable(getBeanFactory()).map(beanFactory -> { - try { - return beanFactory.getBean(LuceneService.class); - } - catch (BeansException ignore) { - return null; - } - }).orElseGet(() -> resolveLuceneService(resolveCache()))); + return Optional.ofNullable(getLuceneService()) + .orElseGet(() -> Optional.ofNullable(getBeanFactory()) + .map(it -> SpringUtils.safeGetValue(() -> it.getBean(LuceneService.class), (LuceneService) null)) + .orElseGet(() -> resolveLuceneService(resolveCache()))); } /** @@ -334,7 +366,9 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport resolveRegion() { return Optional.ofNullable(getRegion()).orElseGet(() -> { + GemFireCache cache = resolveCache(); + String regionPath = getRegionPath(); - return (cache != null && StringUtils.hasText(regionPath) ? cache.getRegion(regionPath) : null); + return cache != null && StringUtils.hasText(regionPath) ? cache.getRegion(regionPath) : null; }); } @@ -371,7 +407,8 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport fieldAnalyzers = Collections.singletonMap("fieldOne", mockAnalyzer); factoryBean.setFieldAnalyzers(fieldAnalyzers); @@ -171,6 +176,7 @@ public class LuceneIndexFactoryBeanUnitTests { assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService); assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex); + verify(factoryBean, times(1)).postProcess(eq(mockLuceneIndexFactory)); verify(mockLuceneService, times(1)).createIndexFactory(); verify(mockLuceneIndexFactory, times(1)).setFields(eq(fieldAnalyzers)); verify(mockLuceneIndexFactory, times(1)) @@ -181,6 +187,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void createLuceneIndexWithTargetedFields() { + factoryBean.setFields("fieldOne", "fieldTwo"); factoryBean.setLuceneService(mockLuceneService); @@ -191,6 +198,7 @@ public class LuceneIndexFactoryBeanUnitTests { assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService); assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex); + verify(factoryBean, times(1)).postProcess(eq(mockLuceneIndexFactory)); verify(mockLuceneService, times(1)).createIndexFactory(); verify(mockLuceneIndexFactory, times(1)) .setFields(eq("fieldOne"), eq("fieldTwo")); @@ -200,9 +208,30 @@ public class LuceneIndexFactoryBeanUnitTests { .getIndex(eq("ExampleIndex"), eq("/Example")); } + @Test + public void resolveLuceneIndexPostProcessesLuceneIndexOnCreate() { + + doReturn(mockLuceneService).when(factoryBean).resolveLuceneService(); + when(mockLuceneService.getIndex(anyString(), anyString())).thenReturn(null); + doReturn(mockLuceneIndex).when(factoryBean).createLuceneIndex(anyString(), anyString()); + + assertThat(factoryBean.resolveLuceneIndex("TestIndex", + GemfireUtils.toRegionPath("TestRegion"))) + .isEqualTo(mockLuceneIndex); + + verify(factoryBean, times(1)).resolveLuceneService(); + verify(mockLuceneService, times(1)) + .getIndex(eq("TestIndex"), eq(GemfireUtils.toRegionPath("TestRegion"))); + verify(factoryBean, times(1)) + .createLuceneIndex(eq("TestIndex"), eq(GemfireUtils.toRegionPath("TestRegion"))); + verify(factoryBean, times(1)).postProcess(eq(mockLuceneIndex)); + verify(factoryBean, times(1)).getLuceneIndex(); + } + @Test @SuppressWarnings("deprecation") public void destroyIsSuccessful() throws Exception { + factoryBean.setDestroy(true); factoryBean.setLuceneService(mockLuceneService); @@ -223,6 +252,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("deprecation") public void destroyDoesNothingWhenDestroyIsFalse() throws Exception { + factoryBean.setDestroy(false); factoryBean.setLuceneService(mockLuceneService); @@ -240,6 +270,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("deprecation") public void destroyDoesNothingWhenLuceneIndexIsNull() throws Exception { + factoryBean.setDestroy(true); factoryBean.setLuceneService(mockLuceneService); @@ -256,6 +287,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void isLuceneIndexDestroyableReturnsTrue() { + factoryBean.setDestroy(true); assertThat(factoryBean.isDestroy()).isTrue(); @@ -264,6 +296,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void isLuceneIndexDestroyableWhenDestroyIsFalseReturnsFalse() { + factoryBean.setDestroy(false); assertThat(factoryBean.isDestroy()).isFalse(); @@ -272,6 +305,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void isLuceneIndexDestroyableWhenLuceneIndexIsNullReturnsFalse() { + factoryBean.setDestroy(true); assertThat(factoryBean.isDestroy()).isTrue(); @@ -280,6 +314,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void getObjectReturnsLuceneIndexFromLuceneService() throws Exception { + factoryBean.setCache(mockCache); factoryBean.setIndexName("ExampleIndex"); factoryBean.setLuceneService(mockLuceneService); @@ -299,6 +334,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void getObjectReturnsExistingLuceneIndex() throws Exception { + factoryBean.setLuceneIndex(mockLuceneIndex); factoryBean.setLuceneService(mockLuceneService); @@ -309,6 +345,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void getObjectReturnsNullWhenLuceneServiceIsNull() throws Exception { + factoryBean.setCache(mockCache); factoryBean.setRegionPath("/Example"); @@ -340,6 +377,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveCacheReturnsConfiguredCache() { + factoryBean.setCache(mockCache); assertThat(factoryBean.getCache()).isSameAs(mockCache); @@ -348,6 +386,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveFieldsReturnsGivenFields() { + List expectedFields = Arrays.asList("fieldOne", "fieldTwo"); assertThat(factoryBean.resolveFields(expectedFields)).isSameAs(expectedFields); @@ -367,6 +406,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveLuceneIndexFactoryCallsLuceneServiceCreateIndexFactory() { + factoryBean.setCache(mockCache); doReturn(mockLuceneIndexFactory).when(mockLuceneService).createIndexFactory(); @@ -378,6 +418,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveLuceneServiceReturnsConfiguredLuceneService() { + factoryBean.setBeanFactory(mockBeanFactory); factoryBean.setCache(mockCache); factoryBean.setLuceneService(mockLuceneService); @@ -394,6 +435,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveLuceneServiceFromBeanFactory() { + factoryBean.setBeanFactory(mockBeanFactory); factoryBean.setCache(mockCache); @@ -411,6 +453,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void resolveLuceneServiceFromGemFireCache() { + factoryBean.setCache(mockCache); doReturn(mockLuceneService).when(factoryBean).resolveLuceneService(eq(mockCache)); @@ -427,6 +470,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("unchecked") public void resolveLuceneServiceFromGemFireCacheWithBeanFactoryThrowinBeansException() { + factoryBean.setBeanFactory(mockBeanFactory); factoryBean.setCache(mockCache); @@ -443,18 +487,25 @@ public class LuceneIndexFactoryBeanUnitTests { verify(factoryBean, times(1)).resolveLuceneService(eq(mockCache)); } - @Test + @Test(expected = IllegalArgumentException.class) public void resolveLuceneServiceThrowsIllegalArgumentExceptionWhenGemFireCacheIsNotConfigured() { - exception.expect(IllegalArgumentException.class); - exception.expectCause(is(nullValue(Throwable.class))); - exception.expectMessage("A reference to the GemFireCache was not properly configured"); - factoryBean.resolveLuceneService(null); + try { + factoryBean.resolveLuceneService(null); + } + catch (IllegalArgumentException expected) { + + assertThat(expected).hasMessageContaining("A reference to the GemFireCache was not properly configured"); + assertThat(expected).hasNoCause(); + + throw expected; + } } @Test @SuppressWarnings("all") public void resolveRegionReturnsConfiguredRegion() { + factoryBean.setRegion(mockRegion); assertThat(factoryBean.resolveRegion()).isSameAs(mockRegion); @@ -467,6 +518,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("all") public void resolveRegionReturnsRegionFromCache() { + factoryBean.setRegionPath("/Example"); doReturn(mockCache).when(factoryBean).resolveCache(); @@ -483,6 +535,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("all") public void resolveRegionReturnsNullWhenCacheNotConfigured() { + factoryBean.setRegionPath("/Example"); doReturn(null).when(factoryBean).resolveCache(); @@ -497,6 +550,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("all") public void resolveRegionReturnsNullWhenRegionPathNotConfigured() { + factoryBean.setCache(mockCache); factoryBean.setRegionPath(" "); @@ -511,6 +565,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("all") public void resolveRegionPathReturnsConfiguredRegionPath() { + factoryBean.setRegionPath("/Example"); doReturn(null).when(factoryBean).resolveRegion(); @@ -524,6 +579,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test @SuppressWarnings("all") public void resolveRegionPathReturnsRegionFullPath() { + doReturn(mockRegion).when(factoryBean).resolveRegion(); when(mockRegion.getFullPath()).thenReturn("/Example"); @@ -534,20 +590,24 @@ public class LuceneIndexFactoryBeanUnitTests { verify(mockRegion, times(1)).getFullPath(); } - @Test + @Test(expected = IllegalStateException.class) @SuppressWarnings("all") public void resolveRegionPathThrowsIllegalStateException() { + doReturn(null).when(factoryBean).resolveRegion(); factoryBean.setRegionPath(null); try { - exception.expect(IllegalStateException.class); - exception.expectCause(is(nullValue(Throwable.class))); - exception.expectMessage("Either Region or regionPath must be specified"); - factoryBean.resolveRegionPath(); } + catch (IllegalStateException expected) { + + assertThat(expected).hasMessageContaining("Either Region or regionPath must be specified"); + assertThat(expected).hasNoCause(); + + throw expected; + } finally { verify(factoryBean, times(1)).resolveRegion(); verify(factoryBean, times(1)).getRegionPath(); @@ -556,6 +616,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void setAndGetFieldAnalyzers() { + Map fieldAnalyzers = factoryBean.getFieldAnalyzers(); assertThat(fieldAnalyzers).isNotNull(); @@ -575,6 +636,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void setAndGetFields() { + List fields = factoryBean.getFields(); assertThat(fields).isNotNull(); @@ -593,6 +655,7 @@ public class LuceneIndexFactoryBeanUnitTests { @Test public void setAndGetIndexName() { + factoryBean.setBeanName("IndexOne"); assertThat(factoryBean.getIndexName()).isEqualTo("IndexOne"); @@ -604,17 +667,24 @@ public class LuceneIndexFactoryBeanUnitTests { factoryBean.setIndexName(null); } - @Test + @Test(expected = IllegalStateException.class) public void getUninitializedIndexName() { - exception.expect(IllegalStateException.class); - exception.expectCause(is(nullValue(Throwable.class))); - exception.expectMessage("indexName was not properly initialized"); - factoryBean.getIndexName(); + try { + factoryBean.getIndexName(); + } + catch (IllegalStateException expected) { + + assertThat(expected).hasMessageContaining("indexName was not properly initialized"); + assertThat(expected).hasNoCause(); + + throw expected; + } } @Test public void factoryBeanInitializationIsSuccessful() { + factoryBean.setCache(mockCache); factoryBean.setDestroy(true); factoryBean.setFieldAnalyzers(Collections.singletonMap("fieldThree", mockAnalyzer));