From d16bbc8d2800e7068cc98114de319afc36827747 Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 27 Apr 2018 14:08:58 -0700 Subject: [PATCH] DATAGEODE-101 - Add support for setting a LuceneSerializer on LuceneIndex creation. --- .../gemfire/config/xml/LuceneIndexParser.java | 17 +++-- .../search/lucene/LuceneIndexFactoryBean.java | 35 ++++++++- .../data/gemfire/config/spring-geode-2.1.xsd | 11 ++- .../config/xml/LuceneNamespaceUnitTests.java | 76 ++++++++++++++++--- .../LuceneIndexFactoryBeanUnitTests.java | 22 +++++- .../xml/LuceneNamespaceUnitTests-context.xml | 6 ++ 6 files changed, 148 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/springframework/data/gemfire/config/xml/LuceneIndexParser.java b/src/main/java/org/springframework/data/gemfire/config/xml/LuceneIndexParser.java index 96ce537d..07e4ec6a 100644 --- a/src/main/java/org/springframework/data/gemfire/config/xml/LuceneIndexParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/xml/LuceneIndexParser.java @@ -53,22 +53,27 @@ class LuceneIndexParser extends AbstractSingleBeanDefinitionParser { */ @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); ParsingUtils.setCacheReference(element, builder); - ParsingUtils.setPropertyValue(element, builder, "name", "indexName"); ParsingUtils.setPropertyValue(element, builder, "destroy"); ParsingUtils.setPropertyReference(element, builder, "lucene-service-ref", "luceneService"); + ParsingUtils.setPropertyValue(element, builder, "name", "indexName"); ParsingUtils.setPropertyReference(element, builder, "region-ref", "region"); ParsingUtils.setPropertyValue(element, builder, "region-path"); - Optional.ofNullable(element.getAttribute("fields")).filter(StringUtils::hasText).ifPresent((fields) -> { - builder.addPropertyValue("fields", Arrays.stream(fields.split(",")) - .map(String::trim).collect(Collectors.toList())); - }); + Optional.ofNullable(element.getAttribute("fields")) + .filter(StringUtils::hasText) + .ifPresent(fields -> builder.addPropertyValue("fields", + Arrays.stream(fields.split(",")).map(String::trim).collect(Collectors.toList()))); Optional.ofNullable(DomUtils.getChildElementByTagName(element, "field-analyzers")) - .ifPresent((fieldAnalyzersElement) -> builder.addPropertyValue("fieldAnalyzers", + .ifPresent(fieldAnalyzersElement -> builder.addPropertyValue("fieldAnalyzers", ParsingUtils.parseRefOrSingleNestedBeanDeclaration(fieldAnalyzersElement, parserContext, builder))); + + Optional.ofNullable(DomUtils.getChildElementByTagName(element, "lucene-serializer")) + .ifPresent(luceneSerializerElement -> builder.addPropertyValue("luceneSerializer", + ParsingUtils.parseRefOrSingleNestedBeanDeclaration(luceneSerializerElement, parserContext, builder))); } } 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 556ec1f8..e8f67bc8 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 @@ -36,6 +36,7 @@ import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.Region; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneIndexFactory; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.cache.lucene.LuceneService; import org.apache.geode.cache.lucene.LuceneServiceProvider; import org.apache.lucene.analysis.Analyzer; @@ -84,7 +85,8 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport indexConfigurer.configure(beanName, bean)); + nullSafeCollection(indexConfigurers) + .forEach(indexConfigurer -> indexConfigurer.configure(beanName, bean)); } }; @@ -92,6 +94,8 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport fieldAnalyzers; @@ -190,6 +194,8 @@ public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport + + + + + diff --git a/src/test/java/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests.java index 2e7ca02e..e0eae61e 100644 --- a/src/test/java/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests.java @@ -34,10 +34,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneIndexFactory; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.cache.lucene.LuceneService; import org.apache.lucene.analysis.Analyzer; import org.junit.Test; @@ -50,6 +52,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; @@ -93,12 +96,17 @@ public class LuceneNamespaceUnitTests { @Qualifier("IndexFour") private LuceneIndex luceneIndexFour; + @Autowired + private LuceneSerializer luceneSerializer; + private static String[] asArray(List list) { return list.toArray(new String[list.size()]); } private static String[] toStringArray(Object[] array) { + String[] stringArray = new String[array.length]; + int index = 0; for (Object element : array) { @@ -108,13 +116,14 @@ public class LuceneNamespaceUnitTests { return stringArray; } - protected void assertLuceneIndex(LuceneIndex index, String name, String regionPath) { + private void assertLuceneIndex(LuceneIndex index, String name, String regionPath) { + assertThat(index).isNotNull(); assertThat(index.getName()).isEqualTo(name); assertThat(index.getRegionPath()).isEqualTo(regionPath); } - protected void assertLuceneIndexWithFieldAnalyzers(LuceneIndex index, String name, String regionPath, + private void assertLuceneIndexWithFieldAnalyzers(LuceneIndex index, String name, String regionPath, String... keys) { assertLuceneIndex(index, name, regionPath); @@ -123,7 +132,8 @@ public class LuceneNamespaceUnitTests { assertThat(index.getFieldNames()).isEmpty(); } - protected void assertLuceneIndexWithFields(LuceneIndex index, String name, String regionPath, String... fieldNames) { + private void assertLuceneIndexWithFields(LuceneIndex index, String name, String regionPath, String... fieldNames) { + assertLuceneIndex(index, name, regionPath); assertThat(index.getFieldAnalyzers()).isEmpty(); assertThat(index.getFieldNames()).contains(fieldNames); @@ -131,6 +141,7 @@ public class LuceneNamespaceUnitTests { @Test public void luceneServiceConfigurationAndInteractionsAreCorrect() { + assertThat(this.luceneService).isNotNull(); verify(this.luceneService, times(4)).createIndexFactory(); verify(this.luceneService, never()).destroyIndex(anyString(), anyString()); @@ -138,26 +149,38 @@ public class LuceneNamespaceUnitTests { @Test public void luceneIndexOneIsConfiguredCorrectly() { + assertLuceneIndexWithFields(this.luceneIndexOne, "IndexOne", "/Example", "fieldOne", "fieldTwo"); + + assertThat(this.luceneIndexOne.getLuceneSerializer()).isNull(); } @Test public void luceneIndexTwoIsConfiguredCorrectly() { + assertLuceneIndexWithFieldAnalyzers(this.luceneIndexTwo, "IndexTwo", "/AnotherExample", "fieldOne", "fieldTwo"); + + assertThat(this.luceneIndexTwo.getLuceneSerializer()).isInstanceOf(LuceneSerializer.class); } @Test public void luceneIndexThreeIsConfiguredCorrectly() { + assertLuceneIndexWithFields(this.luceneIndexThree, "IndexThree", "/Example", "singleField"); + + assertThat(this.luceneIndexThree.getLuceneSerializer()).isNull(); } @Test public void luceneIndexFourIsConfiguredCorrectly() { + assertLuceneIndexWithFieldAnalyzers(this.luceneIndexFour, "IndexFour", "/YetAnotherExample", "singleField"); + + assertThat(this.luceneIndexFour.getLuceneSerializer()).isEqualTo(luceneSerializer); } public static class LuceneNamespaceUnitTestsBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @@ -183,10 +206,13 @@ public class LuceneNamespaceUnitTests { @Override @SuppressWarnings("unchecked") public LuceneService getObject() throws Exception { + return Optional.ofNullable(this.luceneService).orElseGet(() -> { + this.luceneService = mock(LuceneService.class); when(this.luceneService.createIndexFactory()).thenAnswer(invocation -> { + LuceneIndexFactory mockLuceneIndexFactory = mock(LuceneIndexFactory.class); List fieldNames = new ArrayList<>(); @@ -203,8 +229,15 @@ public class LuceneNamespaceUnitTests { return mockLuceneIndexFactory; }); - Answer mockLuceneIndex = - mockLuceneIndex(this.luceneService, fieldAnalyzers, fieldNames); + AtomicReference luceneSerializer = new AtomicReference<>(null); + + when(mockLuceneIndexFactory.setLuceneSerializer(any())).thenAnswer(setLuceneSerializerInvocation -> { + luceneSerializer.set(setLuceneSerializerInvocation.getArgument(0)); + return mockLuceneIndexFactory; + }); + + Answer mockLuceneIndex = + mockLuceneIndex(this.luceneService, fieldAnalyzers, fieldNames, luceneSerializer); doAnswer(mockLuceneIndex).when(mockLuceneIndexFactory).create(anyString(), anyString()); @@ -217,18 +250,21 @@ public class LuceneNamespaceUnitTests { @SuppressWarnings("unchecked") private Answer mockLuceneIndex(LuceneService mockLuceneService, - Map fieldAnalyzers, List fieldNames) { + Map fieldAnalyzers, List fieldNames, + AtomicReference luceneSerializer) { return invocation -> { + String indexName = invocation.getArgument(0); String regionPath = invocation.getArgument(1); LuceneIndex mockLuceneIndex = mock(LuceneIndex.class, indexName); - when(mockLuceneIndex.getName()).thenReturn(indexName); - when(mockLuceneIndex.getRegionPath()).thenReturn(regionPath); when(mockLuceneIndex.getFieldAnalyzers()).thenReturn(fieldAnalyzers); when(mockLuceneIndex.getFieldNames()).thenReturn(asArray(fieldNames)); + when(mockLuceneIndex.getLuceneSerializer()).thenAnswer(it -> luceneSerializer.get()); + when(mockLuceneIndex.getName()).thenReturn(indexName); + when(mockLuceneIndex.getRegionPath()).thenReturn(regionPath); when(mockLuceneService.getIndex(eq(indexName), eq(regionPath))).thenReturn(mockLuceneIndex); return mockLuceneIndex; @@ -237,7 +273,9 @@ public class LuceneNamespaceUnitTests { @Override public Class getObjectType() { - return Optional.ofNullable(this.luceneService).>map(LuceneService::getClass) + + return Optional.ofNullable(this.luceneService) + .>map(LuceneService::getClass) .orElse(LuceneService.class); } @@ -271,4 +309,24 @@ public class LuceneNamespaceUnitTests { return this.name; } } + + public static class MockLuceneSerializerFactoryBean implements FactoryBean { + + private LuceneSerializer luceneSerializer; + + @Nullable @Override + public LuceneSerializer getObject() throws Exception { + + return Optional.ofNullable(this.luceneSerializer) + .orElseGet(() -> this.luceneSerializer = mock(LuceneSerializer.class)); + } + + @Nullable @Override + public Class getObjectType() { + + return Optional.ofNullable(this.luceneSerializer) + .>map(LuceneSerializer::getClass) + .orElse(LuceneSerializer.class); + } + } } diff --git a/src/test/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBeanUnitTests.java b/src/test/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBeanUnitTests.java index 057acbe9..ca646183 100644 --- a/src/test/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBeanUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/search/lucene/LuceneIndexFactoryBeanUnitTests.java @@ -38,6 +38,7 @@ import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.Region; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneIndexFactory; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.cache.lucene.LuceneService; import org.apache.lucene.analysis.Analyzer; import org.junit.Before; @@ -81,6 +82,9 @@ public class LuceneIndexFactoryBeanUnitTests { @Mock private LuceneIndexFactory mockLuceneIndexFactory; + @Mock + private LuceneSerializer mockLuceneSerializer; + @Mock private LuceneService mockLuceneService; @@ -155,6 +159,7 @@ public class LuceneIndexFactoryBeanUnitTests { verify(mockLuceneService, times(1)).createIndexFactory(); verify(mockLuceneIndexFactory, times(1)) .setFields(eq(LuceneService.REGION_VALUE_FIELD)); + verify(mockLuceneIndexFactory, never()).setLuceneSerializer(any(LuceneSerializer.class)); verify(mockLuceneIndexFactory, times(1)) .create(eq("ExampleIndex"), eq("/Example")); verify(mockLuceneService, times(1)) @@ -167,6 +172,7 @@ public class LuceneIndexFactoryBeanUnitTests { Map fieldAnalyzers = Collections.singletonMap("fieldOne", mockAnalyzer); factoryBean.setFieldAnalyzers(fieldAnalyzers); + factoryBean.setLuceneSerializer(mockLuceneSerializer); factoryBean.setLuceneService(mockLuceneService); when(mockLuceneService.getIndex(eq("ExampleIndex"), eq("/Example"))).thenReturn(mockLuceneIndex); @@ -174,11 +180,13 @@ public class LuceneIndexFactoryBeanUnitTests { assertThat(factoryBean.getFieldAnalyzers()).isEqualTo(fieldAnalyzers); assertThat(factoryBean.getFields()).isEmpty(); assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService); - assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex); + 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)).setLuceneSerializer(eq(mockLuceneSerializer)); verify(mockLuceneIndexFactory, times(1)) .create(eq("ExampleIndex"), eq("/Example")); verify(mockLuceneService, times(1)) @@ -189,6 +197,7 @@ public class LuceneIndexFactoryBeanUnitTests { public void createLuceneIndexWithTargetedFields() { factoryBean.setFields("fieldOne", "fieldTwo"); + factoryBean.setLuceneSerializer(mockLuceneSerializer); factoryBean.setLuceneService(mockLuceneService); when(mockLuceneService.getIndex(eq("ExampleIndex"), eq("/Example"))).thenReturn(mockLuceneIndex); @@ -202,6 +211,7 @@ public class LuceneIndexFactoryBeanUnitTests { verify(mockLuceneService, times(1)).createIndexFactory(); verify(mockLuceneIndexFactory, times(1)) .setFields(eq("fieldOne"), eq("fieldTwo")); + verify(mockLuceneIndexFactory, times(1)).setLuceneSerializer(eq(mockLuceneSerializer)); verify(mockLuceneIndexFactory, times(1)) .create(eq("ExampleIndex"), eq("/Example")); verify(mockLuceneService, times(1)) @@ -667,6 +677,16 @@ public class LuceneIndexFactoryBeanUnitTests { factoryBean.setIndexName(null); } + @Test + public void setAndGetLuceneSerializer() { + + assertThat(factoryBean.getLuceneSerializer()).isNull(); + + factoryBean.setLuceneSerializer(mockLuceneSerializer); + + assertThat(factoryBean.getLuceneSerializer()).isEqualTo(mockLuceneSerializer); + } + @Test(expected = IllegalStateException.class) public void getUninitializedIndexName() { diff --git a/src/test/resources/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests-context.xml b/src/test/resources/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests-context.xml index bac6b0e3..4da653bb 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/xml/LuceneNamespaceUnitTests-context.xml @@ -41,6 +41,9 @@ + + + @@ -52,8 +55,11 @@ + + +