You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by to...@apache.org on 2019/06/30 03:29:02 UTC

[lucene-solr] branch branch_8x updated: LUCENE-8894: Add APIs to tokenizer/charfilter/tokenfilter factories to get their SPI names from concrete classes

This is an automated email from the ASF dual-hosted git repository.

tomoko pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new 7e05bd7  LUCENE-8894: Add APIs to tokenizer/charfilter/tokenfilter factories to get their SPI names from concrete classes
7e05bd7 is described below

commit 7e05bd717309088d3b35cba6be0f70fd14b3c8d0
Author: Tomoko Uchida <to...@apache.org>
AuthorDate: Sun Jun 30 12:19:48 2019 +0900

    LUCENE-8894: Add APIs to tokenizer/charfilter/tokenfilter factories to get their SPI names from concrete classes
---
 lucene/CHANGES.txt                                 |  2 ++
 .../analysis/util/AbstractAnalysisFactory.java     | 22 ++++++++++++
 .../lucene/analysis/util/AnalysisSPILoader.java    | 22 ++++--------
 .../lucene/analysis/util/CharFilterFactory.java    |  9 +++++
 .../lucene/analysis/util/TokenFilterFactory.java   | 11 +++++-
 .../lucene/analysis/util/TokenizerFactory.java     | 11 +++++-
 .../analysis/util/TestAbstractAnalysisFactory.java | 41 ++++++++++++++++++++++
 7 files changed, 100 insertions(+), 18 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index d8c2b62..5916656 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -111,6 +111,8 @@ Improvements
 
 * LUCENE-8855: Add Accountable to some Query implementations (ab, Adrien Grand)
 
+* LUCENE-8894: Add APIs to find SPI names for Tokenizer/CharFilter/TokenFilter factory classes. (Tomoko Uchida)
+
 Optimizations
 
 * LUCENE-8796: Use exponential search instead of binary search in
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AbstractAnalysisFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AbstractAnalysisFactory.java
index 954f300..4253018 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AbstractAnalysisFactory.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AbstractAnalysisFactory.java
@@ -21,6 +21,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
@@ -32,6 +34,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -336,4 +339,23 @@ public abstract class AbstractAnalysisFactory {
   public void setExplicitLuceneMatchVersion(boolean isExplicitLuceneMatchVersion) {
     this.isExplicitLuceneMatchVersion = isExplicitLuceneMatchVersion;
   }
+
+  /**
+   * Looks up SPI name (static "NAME" field) with appropriate modifiers.
+   * Also it must be a String class and declared in the concrete class.
+   * @return the SPI name
+   * @throws NoSuchFieldException - if the "NAME" field is not defined.
+   * @throws IllegalAccessException - if the "NAME" field is inaccessible.
+   * @throws IllegalStateException - if the "NAME" field does not have appropriate modifiers or isn't a String field.
+   */
+  static String lookupSPIName(Class<? extends AbstractAnalysisFactory> service) throws NoSuchFieldException, IllegalAccessException, IllegalStateException {
+    final Field field = service.getField("NAME");
+    int modifier = field.getModifiers();
+    if (Modifier.isStatic(modifier) && Modifier.isFinal(modifier) &&
+        field.getType().equals(String.class) &&
+        Objects.equals(field.getDeclaringClass(), service)) {
+      return ((String) field.get(null));
+      }
+    throw new IllegalStateException("No SPI name defined.");
+  }
 }
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java
index 57c4250..39c2c5a 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java
@@ -17,9 +17,7 @@
 package org.apache.lucene.analysis.util;
 
 
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Locale;
@@ -83,21 +81,13 @@ public final class AnalysisSPILoader<S extends AbstractAnalysisFactory> {
       String originalName = null;
       Throwable cause = null;
       try {
-        // Lookup "NAME" field with appropriate modifiers.
-        // Also it must be a String class and declared in the service class.
-        final Field field = service.getField("NAME");
-        int modifier = field.getModifiers();
-        if (Modifier.isStatic(modifier) && Modifier.isFinal(modifier) &&
-            field.getType().equals(String.class) &&
-            Objects.equals(field.getDeclaringClass(), service)) {
-          originalName = ((String)field.get(null));
-          name = originalName.toLowerCase(Locale.ROOT);
-          if (!isValidName(originalName)) {
-            throw new ServiceConfigurationError("The name " + originalName + " for " + service.getName() +
-                " is invalid: Allowed characters are (English) alphabet, digits, and underscore. It should be started with an alphabet.");
-          }
+        originalName = AbstractAnalysisFactory.lookupSPIName(service);
+        name = originalName.toLowerCase(Locale.ROOT);
+        if (!isValidName(originalName)) {
+          throw new ServiceConfigurationError("The name " + originalName + " for " + service.getName() +
+              " is invalid: Allowed characters are (English) alphabet, digits, and underscore. It should be started with an alphabet.");
         }
-      } catch (NoSuchFieldException | IllegalAccessException e) {
+      } catch (NoSuchFieldException | IllegalAccessException | IllegalStateException e) {
         cause = e;
       }
       if (name == null) {
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/CharFilterFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/CharFilterFactory.java
index 7a5eccb..722025c 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/CharFilterFactory.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/CharFilterFactory.java
@@ -49,6 +49,15 @@ public abstract class CharFilterFactory extends AbstractAnalysisFactory {
     return loader.availableServices();
   }
 
+  /** looks up a SPI name for the specified char filter factory */
+  public static String findSPIName(Class<? extends CharFilterFactory> serviceClass) {
+    try {
+      return lookupSPIName(serviceClass);
+    } catch (NoSuchFieldException | IllegalAccessException | IllegalStateException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   /** 
    * Reloads the factory list from the given {@link ClassLoader}.
    * Changes to the factories are visible after the method ends, all
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenFilterFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenFilterFactory.java
index 72c4070..1d7d5c7 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenFilterFactory.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenFilterFactory.java
@@ -47,7 +47,16 @@ public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
   public static Set<String> availableTokenFilters() {
     return loader.availableServices();
   }
-  
+
+  /** looks up a SPI name for the specified token filter factory */
+  public static String findSPIName(Class<? extends TokenFilterFactory> serviceClass) {
+    try {
+      return lookupSPIName(serviceClass);
+    } catch (NoSuchFieldException | IllegalAccessException | IllegalStateException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   /** 
    * Reloads the factory list from the given {@link ClassLoader}.
    * Changes to the factories are visible after the method ends, all
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenizerFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenizerFactory.java
index 8b3e1f9..2cd3a15 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenizerFactory.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/TokenizerFactory.java
@@ -49,7 +49,16 @@ public abstract class TokenizerFactory extends AbstractAnalysisFactory {
   public static Set<String> availableTokenizers() {
     return loader.availableServices();
   }
-  
+
+  /** looks up a SPI name for the specified tokenizer factory */
+  public static String findSPIName(Class<? extends TokenizerFactory> serviceClass) {
+    try {
+      return lookupSPIName(serviceClass);
+    } catch (NoSuchFieldException | IllegalAccessException | IllegalStateException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   /** 
    * Reloads the factory list from the given {@link ClassLoader}.
    * Changes to the factories are visible after the method ends, all
diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/util/TestAbstractAnalysisFactory.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/util/TestAbstractAnalysisFactory.java
new file mode 100644
index 0000000..b8d028e
--- /dev/null
+++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/util/TestAbstractAnalysisFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.lucene.analysis.util;
+
+import org.apache.lucene.analysis.charfilter.HTMLStripCharFilterFactory;
+import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
+import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestAbstractAnalysisFactory extends LuceneTestCase {
+
+  public void testLookupTokenizerSPIName() throws NoSuchFieldException, IllegalAccessException {
+    assertEquals("whitespace", AbstractAnalysisFactory.lookupSPIName(WhitespaceTokenizerFactory.class));
+    assertEquals("whitespace", TokenizerFactory.findSPIName(WhitespaceTokenizerFactory.class));
+  }
+
+  public void testLookupCharFilterSPIName() throws NoSuchFieldException, IllegalAccessException {
+    assertEquals("htmlStrip", AbstractAnalysisFactory.lookupSPIName(HTMLStripCharFilterFactory.class));
+    assertEquals("htmlStrip", CharFilterFactory.findSPIName(HTMLStripCharFilterFactory.class));
+  }
+
+  public void testLookupTokenFilterSPIName() throws NoSuchFieldException, IllegalAccessException{
+    assertEquals("lowercase", AbstractAnalysisFactory.lookupSPIName(LowerCaseFilterFactory.class));
+    assertEquals("lowercase", TokenFilterFactory.findSPIName(LowerCaseFilterFactory.class));
+  }
+}