This is an automated email from the ASF dual-hosted git repository. ladyvader pushed a commit to branch feature/GEODE-3239 in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/feature/GEODE-3239 by this push: new 76f64fa GEODE-3241: User can set a LuceneSerializer through XML 76f64fa is described below commit 76f64fa2557d822b66a1bb3b8249818a18e1d8fc Author: Lynn Hughes-Godfrey <lhughesgodf...@pivotal.io> AuthorDate: Wed Sep 13 17:14:38 2017 -0700 GEODE-3241: User can set a LuceneSerializer through XML * Added Xml Parsing and Generation for LuceneSerializer --- .../internal/cache/xmlcache/CacheXmlParser.java | 14 +++- .../internal/cache/xmlcache/XmlGeneratorUtils.java | 60 ++++++++++++++++ .../org/apache/geode/cache/lucene/LuceneIndex.java | 5 ++ .../geode/cache/lucene/LuceneSerializer.java | 3 +- .../cache/lucene/internal/LuceneIndexImpl.java | 10 +++ .../cache/lucene/internal/LuceneServiceImpl.java | 1 + .../lucene/internal/xml/LuceneIndexCreation.java | 17 ++++- .../internal/xml/LuceneIndexXmlGenerator.java | 20 ++++-- .../lucene/internal/xml/LuceneXmlConstants.java | 3 +- .../cache/lucene/internal/xml/LuceneXmlParser.java | 41 ++++++++++- .../geode.apache.org/schema/lucene/lucene-1.0.xsd | 8 +++ ...uceneIndexXmlGeneratorIntegrationJUnitTest.java | 78 ++++++++++++++++++-- .../xml/LuceneIndexXmlGeneratorJUnitTest.java | 82 +++++++++++++++++++++- .../LuceneIndexXmlParserIntegrationJUnitTest.java | 59 ++++++++++++++++ .../test/LuceneDeclarable2TestSerializer.java} | 26 +++---- .../cache/lucene/test/LuceneTestSerializer.java | 65 +++++++++++++++++ ...ionJUnitTest.parseIndexWithSerializer.cache.xml | 37 ++++++++++ ...exWithSerializerAndDeclarableProperty.cache.xml | 45 ++++++++++++ ...eIndexWithSerializerAndStringProperty.cache.xml | 40 +++++++++++ 19 files changed, 579 insertions(+), 35 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParser.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParser.java index ca0b170..022f289 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParser.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParser.java @@ -1919,6 +1919,18 @@ public class CacheXmlParser extends CacheXml implements ContentHandler { * declarable */ private Declarable createDeclarable() { + return createDeclarable(cache, stack); + } + + /** + * Creates and initializes an instance of {@link Declarable} from the contents of the stack. + * + * @throws CacheXmlException Something goes wrong while instantiating or initializing the + * declarable + * @param cache + * @param stack + */ + public static Declarable createDeclarable(CacheCreation cache, Stack<Object> stack) { Properties props = new Properties(); Object top = stack.pop(); while (top instanceof Parameter) { @@ -1948,7 +1960,7 @@ public class CacheXmlParser extends CacheXml implements ContentHandler { Declarable d = (Declarable) o; d.init(props); - this.cache.addDeclarableProperties(d, props); + cache.addDeclarableProperties(d, props); return d; } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/XmlGeneratorUtils.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/XmlGeneratorUtils.java index 5a4a052..864cbce 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/XmlGeneratorUtils.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/XmlGeneratorUtils.java @@ -17,11 +17,22 @@ package org.apache.geode.internal.cache.xmlcache; import javax.xml.XMLConstants; +import org.apache.geode.cache.Declarable; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import static org.apache.geode.internal.cache.xmlcache.CacheXml.CLASS_NAME; +import static org.apache.geode.internal.cache.xmlcache.CacheXml.DECLARABLE; +import static org.apache.geode.internal.cache.xmlcache.CacheXml.NAME; +import static org.apache.geode.internal.cache.xmlcache.CacheXml.PARAMETER; +import static org.apache.geode.internal.cache.xmlcache.CacheXml.STRING; + /** * Utilities for use in {@link XmlGenerator} implementation to provide common helper methods. * @@ -124,4 +135,53 @@ public class XmlGeneratorUtils { endElement(contentHandler, prefix, localName); } + + + static public void addDeclarable(final ContentHandler handler, Declarable declarable) + throws SAXException { + AttributesImpl EMPTY = new AttributesImpl(); + + String className = declarable.getClass().getName(); + handler.startElement("", CLASS_NAME, CLASS_NAME, EMPTY); + handler.characters(className.toCharArray(), 0, className.length()); + handler.endElement("", CLASS_NAME, CLASS_NAME); + + if (!(declarable instanceof Declarable2)) { + return; + } + + Properties props = ((Declarable2) declarable).getConfig(); + if (props == null) { + return; + } + + for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + Object value = entry.getValue(); + + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "", NAME, "", name); + + handler.startElement("", PARAMETER, PARAMETER, atts); + + if (value instanceof String) { + String sValue = (String) value; + handler.startElement("", STRING, STRING, EMPTY); + handler.characters(sValue.toCharArray(), 0, sValue.length()); + handler.endElement("", STRING, STRING); + + } else if (value instanceof Declarable) { + handler.startElement("", DECLARABLE, DECLARABLE, EMPTY); + addDeclarable(handler, (Declarable) value); + handler.endElement("", DECLARABLE, DECLARABLE); + + } else { + // Ignore it + } + + handler.endElement("", PARAMETER, PARAMETER); + } + } + } diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneIndex.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneIndex.java index 07b5c89..92370b7 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneIndex.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneIndex.java @@ -78,4 +78,9 @@ public interface LuceneIndex { */ public Map<String, Analyzer> getFieldAnalyzers(); + /** + * Return the {@link LuceneSerializer} associated with this index + */ + public LuceneSerializer getLuceneSerializer(); + } diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java index 49617d7..f1c530d 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java @@ -17,6 +17,7 @@ package org.apache.geode.cache.lucene; import java.util.Collection; +import org.apache.geode.cache.Declarable; import org.apache.lucene.document.Document; import org.apache.geode.annotations.Experimental; @@ -25,7 +26,7 @@ import org.apache.geode.annotations.Experimental; * An interface for writing the fields of an object into a lucene document */ @Experimental -public interface LuceneSerializer { +public interface LuceneSerializer extends Declarable { /** * Add the fields of the given value to a set of documents diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexImpl.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexImpl.java index b32042b..a8ba555 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexImpl.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexImpl.java @@ -53,6 +53,7 @@ public abstract class LuceneIndexImpl implements InternalLuceneIndex { protected String[] searchableFieldNames; protected RepositoryManager repositoryManager; protected Analyzer analyzer; + protected LuceneSerializer luceneSerializer; protected LocalRegion dataRegion; protected LuceneIndexImpl(String indexName, String regionPath, InternalCache cache) { @@ -115,6 +116,14 @@ public abstract class LuceneIndexImpl implements InternalLuceneIndex { return this.analyzer; } + public LuceneSerializer getLuceneSerializer() { + return this.luceneSerializer; + } + + public void setLuceneSerializer(LuceneSerializer serializer) { + this.luceneSerializer = serializer; + } + public Cache getCache() { return this.cache; } @@ -209,6 +218,7 @@ public abstract class LuceneIndexImpl implements InternalLuceneIndex { creation.addFieldNames(this.getFieldNames()); creation.setRegion(dataRegion); creation.setFieldAnalyzers(this.getFieldAnalyzers()); + creation.setLuceneSerializer(this.getLuceneSerializer()); dataRegion.getExtensionPoint().addExtension(creation); } diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java index 6af9a07..3dbd673 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java @@ -241,6 +241,7 @@ public class LuceneServiceImpl implements InternalLuceneService { index.setSearchableFields(fields); index.setAnalyzer(analyzer); index.setFieldAnalyzers(fieldAnalyzers); + index.setLuceneSerializer(serializer); index.setupRepositoryManager(serializer); index.setupAEQ(attributes, aeqId); return index; diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexCreation.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexCreation.java index e98fb41..7af43fb 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexCreation.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexCreation.java @@ -17,7 +17,9 @@ package org.apache.geode.cache.lucene.internal.xml; import java.util.*; +import org.apache.geode.cache.Declarable; import org.apache.geode.cache.lucene.LuceneIndexExistsException; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.logging.log4j.Logger; @@ -41,6 +43,7 @@ public class LuceneIndexCreation implements LuceneIndex, Extension<Region<?, ?>> private Map<String, Analyzer> fieldAnalyzers; private static Logger logger = LogService.getLogger(); + private LuceneSerializer luceneSerializer; public void setRegion(Region region) { @@ -77,6 +80,15 @@ public class LuceneIndexCreation implements LuceneIndex, Extension<Region<?, ?>> } @Override + public LuceneSerializer getLuceneSerializer() { + return this.luceneSerializer; + } + + public void setLuceneSerializer(LuceneSerializer luceneSerializer) { + this.luceneSerializer = luceneSerializer; + } + + @Override public XmlGenerator<Region<?, ?>> getXmlGenerator() { return new LuceneIndexXmlGenerator(this); } @@ -87,9 +99,8 @@ public class LuceneIndexCreation implements LuceneIndex, Extension<Region<?, ?>> Analyzer analyzer = this.fieldAnalyzers == null ? new StandardAnalyzer() : new PerFieldAnalyzerWrapper(new StandardAnalyzer(), this.fieldAnalyzers); try { - // TODO: the null should be replaced with real serializer - service.createIndex(getName(), getRegionPath(), analyzer, this.fieldAnalyzers, null, - getFieldNames()); + service.createIndex(getName(), getRegionPath(), analyzer, this.fieldAnalyzers, + getLuceneSerializer(), getFieldNames()); } catch (LuceneIndexExistsException e) { logger .info(LocalizedStrings.LuceneIndexCreation_IGNORING_DUPLICATE_INDEX_CREATION_0_ON_REGION_1 diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGenerator.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGenerator.java index 292d52a..8628f43 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGenerator.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGenerator.java @@ -17,6 +17,9 @@ package org.apache.geode.cache.lucene.internal.xml; import static org.apache.geode.cache.lucene.internal.xml.LuceneXmlConstants.*; +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.lucene.LuceneSerializer; +import org.apache.geode.internal.cache.xmlcache.*; import org.apache.lucene.analysis.Analyzer; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; @@ -24,11 +27,14 @@ import org.xml.sax.helpers.AttributesImpl; import org.apache.geode.cache.Region; import org.apache.geode.cache.lucene.LuceneIndex; -import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator; -import org.apache.geode.internal.cache.xmlcache.XmlGenerator; -import org.apache.geode.internal.cache.xmlcache.XmlGeneratorUtils; + +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; public class LuceneIndexXmlGenerator implements XmlGenerator<Region<?, ?>> { + private static final AttributesImpl EMPTY = new AttributesImpl(); + private final LuceneIndex index; public LuceneIndexXmlGenerator(LuceneIndex index) { @@ -59,7 +65,13 @@ public class LuceneIndexXmlGenerator implements XmlGenerator<Region<?, ?>> { } XmlGeneratorUtils.emptyElement(handler, PREFIX, FIELD, fieldAttr); } + + LuceneSerializer serializer = index.getLuceneSerializer(); + if (serializer != null) { + XmlGeneratorUtils.startElement(handler, PREFIX, SERIALIZER, EMPTY); + XmlGeneratorUtils.addDeclarable(handler, serializer); + XmlGeneratorUtils.endElement(handler, PREFIX, SERIALIZER); + } XmlGeneratorUtils.endElement(handler, PREFIX, INDEX); } - } diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlConstants.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlConstants.java index e1f538c..5d9fa6d 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlConstants.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlConstants.java @@ -18,11 +18,10 @@ package org.apache.geode.cache.lucene.internal.xml; public class LuceneXmlConstants { public static final String NAMESPACE = "http://geode.apache.org/schema/lucene"; public static final String PREFIX = "lucene"; - public static final String SERVICE = "service"; public static final String NAME = "name"; - public static final String REGION = "index"; public static final String INDEX = "index"; public static final String FIELD = "field"; public static final String ANALYZER = "analyzer"; + public static final String SERIALIZER = "serializer"; } diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlParser.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlParser.java index c891283..e46a46f 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlParser.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/xml/LuceneXmlParser.java @@ -18,16 +18,17 @@ package org.apache.geode.cache.lucene.internal.xml; import static org.apache.geode.cache.lucene.internal.xml.LuceneXmlConstants.*; import org.apache.geode.cache.CacheXmlException; +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.internal.InternalDataSerializer; +import org.apache.geode.internal.cache.xmlcache.*; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.lucene.analysis.Analyzer; import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import org.apache.geode.internal.cache.xmlcache.AbstractXmlParser; -import org.apache.geode.internal.cache.xmlcache.RegionCreation; - public class LuceneXmlParser extends AbstractXmlParser { + private CacheCreation cache; @Override public String getNamespaceUri() { @@ -47,6 +48,23 @@ public class LuceneXmlParser extends AbstractXmlParser { if (FIELD.equals(localName)) { startField(atts); } + if (SERIALIZER.equals(localName)) { + startSerializer(atts); + } + + } + + private void startSerializer(Attributes atts) { + // Ignore any whitespace noise between fields + if (stack.peek() instanceof StringBuffer) { + stack.pop(); + } + + if (!(stack.peek() instanceof LuceneIndexCreation)) { + throw new CacheXmlException( + "lucene <serializer> elements must occur within lucene <index> elements"); + } + LuceneIndexCreation creation = (LuceneIndexCreation) stack.peek(); } private void startField(Attributes atts) { @@ -81,6 +99,7 @@ public class LuceneXmlParser extends AbstractXmlParser { indexCreation.setRegion(region); region.getExtensionPoint().addExtension(indexCreation); stack.push(indexCreation); + cache = (CacheCreation) region.getCache(); } @Override @@ -91,6 +110,10 @@ public class LuceneXmlParser extends AbstractXmlParser { if (INDEX.equals(localName)) { endIndex(); } + + if (SERIALIZER.equals(localName)) { + endSerializer(); + } } private void endIndex() { @@ -103,6 +126,18 @@ public class LuceneXmlParser extends AbstractXmlParser { stack.pop(); } + private void endSerializer() { + Declarable d = CacheXmlParser.createDeclarable(cache, stack); + if (!(d instanceof LuceneSerializer)) { + throw new CacheXmlException( + d.getClass().getName() + " is not an instance of LuceneSerializer"); + } + + LuceneIndexCreation indexCreation = (LuceneIndexCreation) stack.peek(); + indexCreation.setLuceneSerializer((LuceneSerializer) d); + + } + private Analyzer createAnalyzer(String className) { Object obj; try { diff --git a/geode-lucene/src/main/resources/META-INF/schemas/geode.apache.org/schema/lucene/lucene-1.0.xsd b/geode-lucene/src/main/resources/META-INF/schemas/geode.apache.org/schema/lucene/lucene-1.0.xsd index ec82c2f..f8920f5 100644 --- a/geode-lucene/src/main/resources/META-INF/schemas/geode.apache.org/schema/lucene/lucene-1.0.xsd +++ b/geode-lucene/src/main/resources/META-INF/schemas/geode.apache.org/schema/lucene/lucene-1.0.xsd @@ -17,6 +17,7 @@ limitations under the License. --> <xsd:schema targetNamespace="http://geode.apache.org/schema/lucene" + xmlns:gf="http://geode.apache.org/schema/cache" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" @@ -51,6 +52,13 @@ XML schema for Lucene indexes in Geode. <xsd:attribute name="analyzer" type="xsd:string" /> </xsd:complexType> </xsd:element> + <xsd:element name="serializer" minOccurs="0" maxOccurs="1" type="gf:declarable-type"> + <xsd:annotation> + <xsd:documentation> + A serializer controls how objects are converted to lucene documents + </xsd:documentation> + </xsd:annotation> + </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string"/> </xsd:complexType> diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorIntegrationJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorIntegrationJUnitTest.java index 361b7a9..a6bb291 100644 --- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorIntegrationJUnitTest.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorIntegrationJUnitTest.java @@ -17,10 +17,11 @@ package org.apache.geode.cache.lucene.internal.xml; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.Declarable; import org.apache.geode.cache.RegionShortcut; -import org.apache.geode.cache.lucene.LuceneIndex; -import org.apache.geode.cache.lucene.LuceneService; -import org.apache.geode.cache.lucene.LuceneServiceProvider; +import org.apache.geode.cache.lucene.*; +import org.apache.geode.cache.lucene.test.LuceneDeclarable2TestSerializer; +import org.apache.geode.cache.lucene.test.LuceneTestSerializer; import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator; import org.apache.geode.test.junit.categories.IntegrationTest; import org.junit.After; @@ -31,9 +32,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.nio.charset.Charset; +import java.util.Properties; import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.*; @Category(IntegrationTest.class) public class LuceneIndexXmlGeneratorIntegrationJUnitTest { @@ -56,6 +59,72 @@ public class LuceneIndexXmlGeneratorIntegrationJUnitTest { cache.createRegionFactory(RegionShortcut.PARTITION).create("region"); + LuceneIndex index = generateAndParseXml(service); + + assertArrayEquals(new String[] {"a", "b", "c"}, index.getFieldNames()); + } + + @Test + public void generateWithDeclarable2SerializerWithStringProperty() { + LuceneDeclarable2TestSerializer luceneSerializer = new LuceneDeclarable2TestSerializer(); + luceneSerializer.getConfig().setProperty("param", "value"); + Properties p = generateAndParseDeclarable2Serializer(luceneSerializer); + assertEquals("value", p.getProperty("param")); + } + + @Test + public void generateWithDeclarable2SerializerWithNoProperties() { + LuceneDeclarable2TestSerializer luceneSerializer = new LuceneDeclarable2TestSerializer(); + Properties p = generateAndParseDeclarable2Serializer(luceneSerializer); + assertEquals(new Properties(), p); + } + + @Test + public void generateWithDeclarable2SerializerWithDeclarableProperty() { + LuceneDeclarable2TestSerializer luceneSerializer = new LuceneDeclarable2TestSerializer(); + luceneSerializer.getConfig().put("param", new LuceneTestSerializer()); + Properties p = generateAndParseDeclarable2Serializer(luceneSerializer); + assertThat(p.get("param")).isInstanceOf(LuceneTestSerializer.class); + } + + private Properties generateAndParseDeclarable2Serializer( + LuceneDeclarable2TestSerializer luceneSerializer) { + cache = new CacheFactory().set(MCAST_PORT, "0").create(); + LuceneService service = LuceneServiceProvider.get(cache); + service.createIndexFactory().setLuceneSerializer(luceneSerializer).setFields("a", "b", "c") + .create("index", "region"); + cache.createRegionFactory(RegionShortcut.PARTITION).create("region"); + + LuceneIndex index = generateAndParseXml(service); + + assertArrayEquals(new String[] {"a", "b", "c"}, index.getFieldNames()); + + LuceneSerializer testSerializer = index.getLuceneSerializer(); + return ((LuceneDeclarable2TestSerializer) testSerializer).getConfig(); + } + + + @Test + public void generateWithSerializer() { + cache = new CacheFactory().set(MCAST_PORT, "0").create(); + LuceneService service = LuceneServiceProvider.get(cache); + service.createIndexFactory().setLuceneSerializer(new LuceneTestSerializer()) + .setFields("a", "b", "c").create("index", "region"); + cache.createRegionFactory(RegionShortcut.PARTITION).create("region"); + + LuceneIndex index = generateAndParseXml(service); + + assertArrayEquals(new String[] {"a", "b", "c"}, index.getFieldNames()); + + LuceneSerializer testSerializer = index.getLuceneSerializer(); + assertThat(testSerializer).isInstanceOf(LuceneTestSerializer.class); + } + + /** + * Generate an xml configuration from the LuceneService and parse it, returning the index that was + * created from the xml. + */ + private LuceneIndex generateAndParseXml(LuceneService service) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); CacheXmlGenerator.generate(cache, pw, true, false, false); @@ -75,8 +144,7 @@ public class LuceneIndexXmlGeneratorIntegrationJUnitTest { LuceneIndex index = service2.getIndex("index", "region"); assertNotNull(index); - - assertArrayEquals(new String[] {"a", "b", "c"}, index.getFieldNames()); + return index; } } diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorJUnitTest.java index 672b10a..878bee2 100644 --- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorJUnitTest.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlGeneratorJUnitTest.java @@ -19,11 +19,17 @@ import static org.mockito.Mockito.*; import java.util.Arrays; import java.util.HashSet; +import java.util.Properties; import java.util.Set; +import org.apache.geode.cache.lucene.LuceneSerializer; +import org.apache.geode.cache.lucene.test.LuceneDeclarable2TestSerializer; +import org.apache.geode.cache.lucene.test.LuceneTestSerializer; +import org.apache.geode.internal.cache.xmlcache.Declarable2; import org.junit.Test; import org.junit.experimental.categories.Category; import org.mockito.ArgumentCaptor; +import org.mockito.MockSettings; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; @@ -35,7 +41,7 @@ import org.apache.geode.test.junit.categories.UnitTest; public class LuceneIndexXmlGeneratorJUnitTest { /** - * Test of generating and reading cache configuration back in. + * Test of generating cache configuration. */ @Test public void generateWithFields() throws Exception { @@ -70,4 +76,78 @@ public class LuceneIndexXmlGeneratorJUnitTest { verify(handler).endElement(eq(""), eq("index"), eq("lucene:index")); } + /** + * Test generating lucene xml with serializer + */ + @Test + public void generateWithSerializer() throws Exception { + LuceneIndex index = mock(LuceneIndex.class); + LuceneSerializer mySerializer = + mock(LuceneSerializer.class, withSettings().extraInterfaces(Declarable2.class)); + Properties props = new Properties(); + props.put("param", "value"); + when(index.getName()).thenReturn("index"); + String[] fields = new String[] {"field1", "field2"}; + when(index.getFieldNames()).thenReturn(fields); + when(index.getLuceneSerializer()).thenReturn(mySerializer); + when(((Declarable2) mySerializer).getConfig()).thenReturn(props); + + LuceneIndexXmlGenerator generator = new LuceneIndexXmlGenerator(index); + CacheXmlGenerator cacheXmlGenerator = mock(CacheXmlGenerator.class); + ContentHandler handler = mock(ContentHandler.class); + when(cacheXmlGenerator.getContentHandler()).thenReturn(handler); + generator.generate(cacheXmlGenerator); + + ArgumentCaptor<Attributes> captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler).startElement(eq(""), eq("index"), eq("lucene:index"), captor.capture()); + Attributes value = captor.getValue(); + assertEquals("index", value.getValue(LuceneXmlConstants.NAME)); + + // fields + captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler, times(2)).startElement(eq(""), eq("field"), eq("lucene:field"), + captor.capture()); + Set<String> foundFields = new HashSet<String>(); + for (Attributes fieldAttr : captor.getAllValues()) { + foundFields.add(fieldAttr.getValue(LuceneXmlConstants.NAME)); + } + + HashSet<String> expected = new HashSet<String>(Arrays.asList(fields)); + assertEquals(expected, foundFields); + + verify(handler, times(2)).endElement(eq(""), eq("field"), eq("lucene:field")); + + // serializer + captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler, times(1)).startElement(eq(""), eq("serializer"), eq("lucene:serializer"), + captor.capture()); + + captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler, times(1)).startElement(eq(""), eq("class-name"), eq("class-name"), + captor.capture()); + + String expectedString = mySerializer.getClass().getName(); + verify(handler).characters(eq(expectedString.toCharArray()), eq(0), + eq(expectedString.length())); + verify(handler).endElement(eq(""), eq("class-name"), eq("class-name")); + + // properties as parameters + captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler, times(1)).startElement(eq(""), eq("parameter"), eq("parameter"), + captor.capture()); + value = captor.getValue(); + assertEquals("param", value.getValue(LuceneXmlConstants.NAME)); + + captor = ArgumentCaptor.forClass(Attributes.class); + verify(handler, times(1)).startElement(eq(""), eq("string"), eq("string"), captor.capture()); + String expectedValue = "value"; + verify(handler).characters(eq(expectedValue.toCharArray()), eq(0), eq(expectedValue.length())); + verify(handler).endElement(eq(""), eq("string"), eq("string")); + verify(handler).endElement(eq(""), eq("parameter"), eq("parameter")); + + // endElement invocations + verify(handler).endElement(eq(""), eq("serializer"), eq("lucene:serializer")); + verify(handler).endElement(eq(""), eq("index"), eq("lucene:index")); + } + } diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.java index fef0684..2d46e5e 100644 --- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.java @@ -19,8 +19,10 @@ import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.CacheXmlException; import org.apache.geode.cache.lucene.LuceneIndex; +import org.apache.geode.cache.lucene.LuceneSerializer; import org.apache.geode.cache.lucene.LuceneService; import org.apache.geode.cache.lucene.LuceneServiceProvider; +import org.apache.geode.cache.lucene.test.LuceneTestSerializer; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.extension.Extension; import org.apache.geode.internal.cache.xmlcache.CacheCreation; @@ -43,8 +45,10 @@ import java.io.FileNotFoundException; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Properties; import static org.apache.geode.distributed.ConfigurationProperties.*; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -117,6 +121,52 @@ public class LuceneIndexXmlParserIntegrationJUnitTest { validateExpectedAnalyzers(region, expectedIndexAnalyzers); } + @Test + public void parseIndexWithSerializerAndStringProperty() throws FileNotFoundException { + RegionCreation region = createRegionCreation("region"); + + // Validate expected indexes + Map<String, String[]> expectedIndexes = new HashMap<String, String[]>(); + expectedIndexes.put("index", new String[] {"a"}); + validateExpectedIndexes(region, expectedIndexes); + + // Validate expected serializer + Properties expected = new Properties(); + expected.setProperty("param_from_xml", "value_from_xml"); + validateExpectedSerializer(region, expected); + } + + @Test + public void parseIndexWithSerializerAndDeclarableProperty() throws FileNotFoundException { + RegionCreation region = createRegionCreation("region"); + + // Validate expected indexes + Map<String, String[]> expectedIndexes = new HashMap<String, String[]>(); + expectedIndexes.put("index", new String[] {"a"}); + validateExpectedIndexes(region, expectedIndexes); + + // Validate expected serializer + LuceneTestSerializer nestedSerializer = new LuceneTestSerializer(); + nestedSerializer.getProperties().setProperty("nested_param", "nested_value"); + Properties expected = new Properties(); + expected.put("param_from_xml", nestedSerializer); + validateExpectedSerializer(region, expected); + } + + @Test + public void parseIndexWithSerializer() throws FileNotFoundException { + RegionCreation region = createRegionCreation("region"); + + // Validate expected indexes + Map<String, String[]> expectedIndexes = new HashMap<String, String[]>(); + expectedIndexes.put("index", new String[] {"a"}); + validateExpectedIndexes(region, expectedIndexes); + + // Validate expected serializer + Properties expected = new Properties(); + validateExpectedSerializer(region, expected); + } + private RegionCreation createRegionCreation(String regionName) throws FileNotFoundException { CacheXmlParser parser = CacheXmlParser.parse(new FileInputStream(getXmlFileForTest())); CacheCreation cache = parser.getCacheCreation(); @@ -142,6 +192,15 @@ public class LuceneIndexXmlParserIntegrationJUnitTest { assertEquals(Collections.emptyMap(), expectedIndexAnalyzers); } + private void validateExpectedSerializer(RegionCreation region, Properties expectedProps) { + Extension extension = region.getExtensionPoint().getExtensions().iterator().next(); + LuceneIndexCreation index = (LuceneIndexCreation) extension; + LuceneSerializer testSerializer = index.getLuceneSerializer(); + assertThat(testSerializer).isInstanceOf(LuceneTestSerializer.class); + Properties p = ((LuceneTestSerializer) testSerializer).getProperties(); + assertEquals(expectedProps, p); + } + /** * Test that the Index creation objects get appropriately translated into a real index. * diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneDeclarable2TestSerializer.java similarity index 65% copy from geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java copy to geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneDeclarable2TestSerializer.java index 49617d7..6c5737d 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneDeclarable2TestSerializer.java @@ -4,31 +4,27 @@ * copyright ownership. The ASF licenses this file to you 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.apache.geode.cache.lucene.test; -package org.apache.geode.cache.lucene; +import org.apache.geode.internal.cache.xmlcache.Declarable2; -import java.util.Collection; - -import org.apache.lucene.document.Document; - -import org.apache.geode.annotations.Experimental; +import java.util.Properties; /** - * An interface for writing the fields of an object into a lucene document + * A Test LuceneSerializer that takes properties during construction (init) */ -@Experimental -public interface LuceneSerializer { +public class LuceneDeclarable2TestSerializer extends LuceneTestSerializer implements Declarable2 { - /** - * Add the fields of the given value to a set of documents - */ - Collection<Document> toDocuments(Object value); + @Override + public Properties getConfig() { + return super.getProperties(); + } } diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneTestSerializer.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneTestSerializer.java new file mode 100644 index 0000000..7466b7a --- /dev/null +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/LuceneTestSerializer.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to you 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.apache.geode.cache.lucene.test; + +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.lucene.LuceneSerializer; +import org.apache.geode.internal.cache.xmlcache.Declarable2; +import org.apache.lucene.document.Document; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * A Test LuceneSerializer that takes properties during construction (init) + */ +public class LuceneTestSerializer implements LuceneSerializer { + + protected final Properties props = new Properties(); + + @Override + public void init(Properties props) { + this.props.putAll(props); + } + + public Properties getProperties() { + return this.props; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LuceneTestSerializer that = (LuceneTestSerializer) o; + + return props.equals(that.props); + } + + @Override + public int hashCode() { + return props.hashCode(); + } + + @Override + public Collection<Document> toDocuments(Object value) { + return Collections.emptyList(); + } +} diff --git a/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializer.cache.xml b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializer.cache.xml new file mode 100644 index 0000000..bd0bf2e --- /dev/null +++ b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializer.cache.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> + +<cache + xmlns="http://geode.apache.org/schema/cache" + xmlns:lucene="http://geode.apache.org/schema/lucene" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://geode.apache.org/schema/cache + http://geode.apache.org/schema/cache/cache-1.0.xsd + http://geode.apache.org/schema/lucene + http://geode.apache.org/schema/lucene/lucene-1.0.xsd" + version="1.0"> + + <region name="region" refid="PARTITION"> + <lucene:index name="index"> + <lucene:field name="a"/> + <lucene:serializer> + <class-name>org.apache.geode.cache.lucene.test.LuceneTestSerializer</class-name> + </lucene:serializer> + </lucene:index> + </region> +</cache> diff --git a/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndDeclarableProperty.cache.xml b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndDeclarableProperty.cache.xml new file mode 100644 index 0000000..13b3067 --- /dev/null +++ b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndDeclarableProperty.cache.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> + +<cache + xmlns="http://geode.apache.org/schema/cache" + xmlns:lucene="http://geode.apache.org/schema/lucene" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://geode.apache.org/schema/cache + http://geode.apache.org/schema/cache/cache-1.0.xsd + http://geode.apache.org/schema/lucene + http://geode.apache.org/schema/lucene/lucene-1.0.xsd" + version="1.0"> + + <region name="region" refid="PARTITION"> + <lucene:index name="index"> + <lucene:field name="a"/> + <lucene:serializer> + <class-name>org.apache.geode.cache.lucene.test.LuceneTestSerializer</class-name> + <parameter name="param_from_xml"> + <declarable> + <class-name>org.apache.geode.cache.lucene.test.LuceneTestSerializer</class-name> + <parameter name="nested_param"> + <string>nested_value</string> + </parameter> + </declarable> + </parameter> + </lucene:serializer> + </lucene:index> + </region> +</cache> diff --git a/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndStringProperty.cache.xml b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndStringProperty.cache.xml new file mode 100644 index 0000000..fccb105 --- /dev/null +++ b/geode-lucene/src/test/resources/org/apache/geode/cache/lucene/internal/xml/LuceneIndexXmlParserIntegrationJUnitTest.parseIndexWithSerializerAndStringProperty.cache.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> + +<cache + xmlns="http://geode.apache.org/schema/cache" + xmlns:lucene="http://geode.apache.org/schema/lucene" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://geode.apache.org/schema/cache + http://geode.apache.org/schema/cache/cache-1.0.xsd + http://geode.apache.org/schema/lucene + http://geode.apache.org/schema/lucene/lucene-1.0.xsd" + version="1.0"> + + <region name="region" refid="PARTITION"> + <lucene:index name="index"> + <lucene:field name="a"/> + <lucene:serializer> + <class-name>org.apache.geode.cache.lucene.test.LuceneTestSerializer</class-name> + <parameter name="param_from_xml"> + <string>value_from_xml</string> + </parameter> + </lucene:serializer> + </lucene:index> + </region> +</cache> -- To stop receiving notification emails like this one, please contact ['"commits@geode.apache.org" <commits@geode.apache.org>'].