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

janhoy pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/branch_9x by this push:
     new 61bc965f60d SOLR-16203: Initialize schema plugins loaded by SPI name 
(#2175)
61bc965f60d is described below

commit 61bc965f60d4cc3885f048db386104109ff5725a
Author: Jan Høydahl <[email protected]>
AuthorDate: Fri Jan 5 21:02:49 2024 +0100

    SOLR-16203: Initialize schema plugins loaded by SPI name (#2175)
    
    (cherry picked from commit 8201bf81d79b638f281c3d075ba7c5e240ee9e08)
---
 solr/CHANGES.txt                                   |  2 +
 .../java/org/apache/solr/schema/IndexSchema.java   | 77 +++++++++++++++++++-
 .../org/apache/solr/schema/ManagedIndexSchema.java | 85 ----------------------
 .../solr/schema/ResolveAnalyzerByNameTest.java     | 10 +++
 4 files changed, 88 insertions(+), 86 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 18b8ee99b57..16c6eb32971 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -94,6 +94,8 @@ Bug Fixes
 * SOLR-17098: ZK Credentials and ACLs are no longer sent to all ZK Servers 
when using Streaming Expressions.
   They will only be used when sent to the default ZK Host. (Houston Putman, 
Jan Høydahl, David Smiley, Gus Heck, Qing Xu)
 
+* SOLR-16203: Properly initialize schema plugins loaded by SPI name (janhoy, 
hossman, Uwe Schindler)
+
 Dependency Upgrades
 ---------------------
 * SOLR-17012: Update Apache Hadoop to 3.3.6 and Apache Curator to 5.5.0 (Kevin 
Risden)
diff --git a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java 
b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
index c395a2c8928..06dad3175dc 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -45,12 +45,17 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.CharFilterFactory;
 import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
+import org.apache.lucene.analysis.TokenFilterFactory;
+import org.apache.lucene.analysis.TokenizerFactory;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.queries.payloads.PayloadDecoder;
 import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.ResourceLoaderAware;
 import org.apache.lucene.util.Version;
+import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.common.ConfigNode;
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.SolrDocument;
@@ -652,7 +657,6 @@ public class IndexSchema {
       loadCopyFields(rootNode);
 
       postReadInform();
-
     } catch (SolrException e) {
       throw new SolrException(
           ErrorCode.getErrorCode(e.code()),
@@ -677,6 +681,8 @@ public class IndexSchema {
     for (SchemaAware aware : schemaAware) {
       aware.inform(this);
     }
+    // Make sure all analyzers have resource loaders, even SPI loaded ones
+    
fieldTypes.values().forEach(this::informResourceLoaderAwareObjectsForFieldType);
   }
 
   /**
@@ -1991,6 +1997,37 @@ public class IndexSchema {
     throw new SolrException(ErrorCode.SERVER_ERROR, msg);
   }
 
+  /** Informs analyzers used by a fieldType. */
+  private void informResourceLoaderAwareObjectsForFieldType(FieldType 
fieldType) {
+    // must inform any sub-components used in the
+    // tokenizer chain if they are ResourceLoaderAware
+    if (!fieldType.supportsAnalyzers()) return;
+
+    Analyzer indexAnalyzer = fieldType.getIndexAnalyzer();
+    if (indexAnalyzer != null && indexAnalyzer instanceof TokenizerChain)
+      informResourceLoaderAwareObjectsInChain((TokenizerChain) indexAnalyzer);
+
+    Analyzer queryAnalyzer = fieldType.getQueryAnalyzer();
+    // ref comparison is correct here (vs. equals) as they may be the same
+    // object in which case, we don't need to inform twice ... however, it's
+    // actually safe to call inform multiple times on an object anyway
+    if (queryAnalyzer != null
+        && queryAnalyzer != indexAnalyzer
+        && queryAnalyzer instanceof TokenizerChain)
+      informResourceLoaderAwareObjectsInChain((TokenizerChain) queryAnalyzer);
+
+    // if fieldType is a TextField, it might have a multi-term analyzer
+    if (fieldType instanceof TextField) {
+      TextField textFieldType = (TextField) fieldType;
+      Analyzer multiTermAnalyzer = textFieldType.getMultiTermAnalyzer();
+      if (multiTermAnalyzer != null
+          && multiTermAnalyzer != indexAnalyzer
+          && multiTermAnalyzer != queryAnalyzer
+          && multiTermAnalyzer instanceof TokenizerChain)
+        informResourceLoaderAwareObjectsInChain((TokenizerChain) 
multiTermAnalyzer);
+    }
+  }
+
   /**
    * Returns a SchemaField if the given fieldName does not already exist in 
this schema, and does
    * not match any dynamic fields in this schema. The resulting SchemaField 
can be used in a call to
@@ -2026,6 +2063,44 @@ public class IndexSchema {
     throw new SolrException(ErrorCode.SERVER_ERROR, msg);
   }
 
+  /**
+   * After creating a new FieldType, it may contain components that implement 
the
+   * ResourceLoaderAware interface, which need to be informed after they are 
loaded (as they depend
+   * on this callback to complete initialization work)
+   */
+  private void informResourceLoaderAwareObjectsInChain(TokenizerChain chain) {
+    CharFilterFactory[] charFilters = chain.getCharFilterFactories();
+    for (CharFilterFactory next : charFilters) {
+      if (next instanceof ResourceLoaderAware) {
+        try {
+          SolrResourceLoader.informAware(loader, (ResourceLoaderAware) next);
+        } catch (IOException e) {
+          throw new SolrException(ErrorCode.SERVER_ERROR, e);
+        }
+      }
+    }
+
+    TokenizerFactory tokenizerFactory = chain.getTokenizerFactory();
+    if (tokenizerFactory instanceof ResourceLoaderAware) {
+      try {
+        SolrResourceLoader.informAware(loader, (ResourceLoaderAware) 
tokenizerFactory);
+      } catch (IOException e) {
+        throw new SolrException(ErrorCode.SERVER_ERROR, e);
+      }
+    }
+
+    TokenFilterFactory[] filters = chain.getTokenFilterFactories();
+    for (TokenFilterFactory next : filters) {
+      if (next instanceof ResourceLoaderAware) {
+        try {
+          SolrResourceLoader.informAware(loader, (ResourceLoaderAware) next);
+        } catch (IOException e) {
+          throw new SolrException(ErrorCode.SERVER_ERROR, e);
+        }
+      }
+    }
+  }
+
   /**
    * Returns the schema update lock that should be synchronized on to update 
the schema. Only
    * applicable to mutable schemas.
diff --git a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java 
b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
index d495a90fae6..b41728e1264 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
@@ -16,8 +16,6 @@
  */
 package org.apache.solr.schema;
 
-import static org.apache.solr.core.SolrResourceLoader.informAware;
-
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -40,14 +38,8 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.CharFilterFactory;
-import org.apache.lucene.analysis.TokenFilterFactory;
-import org.apache.lucene.analysis.TokenizerFactory;
 import org.apache.lucene.util.IOUtils;
-import org.apache.lucene.util.ResourceLoaderAware;
 import org.apache.lucene.util.Version;
-import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrResponse;
@@ -1299,45 +1291,6 @@ public final class ManagedIndexSchema extends 
IndexSchema {
     return newSchema;
   }
 
-  @Override
-  protected void postReadInform() {
-    super.postReadInform();
-    for (FieldType fieldType : fieldTypes.values()) {
-      informResourceLoaderAwareObjectsForFieldType(fieldType);
-    }
-  }
-
-  /** Informs analyzers used by a fieldType. */
-  private void informResourceLoaderAwareObjectsForFieldType(FieldType 
fieldType) {
-    // must inform any sub-components used in the
-    // tokenizer chain if they are ResourceLoaderAware
-    if (!fieldType.supportsAnalyzers()) return;
-
-    Analyzer indexAnalyzer = fieldType.getIndexAnalyzer();
-    if (indexAnalyzer != null && indexAnalyzer instanceof TokenizerChain)
-      informResourceLoaderAwareObjectsInChain((TokenizerChain) indexAnalyzer);
-
-    Analyzer queryAnalyzer = fieldType.getQueryAnalyzer();
-    // ref comparison is correct here (vs. equals) as they may be the same
-    // object in which case, we don't need to inform twice ... however, it's
-    // actually safe to call inform multiple times on an object anyway
-    if (queryAnalyzer != null
-        && queryAnalyzer != indexAnalyzer
-        && queryAnalyzer instanceof TokenizerChain)
-      informResourceLoaderAwareObjectsInChain((TokenizerChain) queryAnalyzer);
-
-    // if fieldType is a TextField, it might have a multi-term analyzer
-    if (fieldType instanceof TextField) {
-      TextField textFieldType = (TextField) fieldType;
-      Analyzer multiTermAnalyzer = textFieldType.getMultiTermAnalyzer();
-      if (multiTermAnalyzer != null
-          && multiTermAnalyzer != indexAnalyzer
-          && multiTermAnalyzer != queryAnalyzer
-          && multiTermAnalyzer instanceof TokenizerChain)
-        informResourceLoaderAwareObjectsInChain((TokenizerChain) 
multiTermAnalyzer);
-    }
-  }
-
   @Override
   public SchemaField newField(String fieldName, String fieldType, Map<String, 
?> options) {
     SchemaField sf;
@@ -1436,44 +1389,6 @@ public final class ManagedIndexSchema extends 
IndexSchema {
     return ft;
   }
 
-  /**
-   * After creating a new FieldType, it may contain components that implement 
the
-   * ResourceLoaderAware interface, which need to be informed after they are 
loaded (as they depend
-   * on this callback to complete initialization work)
-   */
-  private void informResourceLoaderAwareObjectsInChain(TokenizerChain chain) {
-    CharFilterFactory[] charFilters = chain.getCharFilterFactories();
-    for (CharFilterFactory next : charFilters) {
-      if (next instanceof ResourceLoaderAware) {
-        try {
-          informAware(loader, (ResourceLoaderAware) next);
-        } catch (IOException e) {
-          throw new SolrException(ErrorCode.SERVER_ERROR, e);
-        }
-      }
-    }
-
-    TokenizerFactory tokenizerFactory = chain.getTokenizerFactory();
-    if (tokenizerFactory instanceof ResourceLoaderAware) {
-      try {
-        informAware(loader, (ResourceLoaderAware) tokenizerFactory);
-      } catch (IOException e) {
-        throw new SolrException(ErrorCode.SERVER_ERROR, e);
-      }
-    }
-
-    TokenFilterFactory[] filters = chain.getTokenFilterFactories();
-    for (TokenFilterFactory next : filters) {
-      if (next instanceof ResourceLoaderAware) {
-        try {
-          informAware(loader, (ResourceLoaderAware) next);
-        } catch (IOException e) {
-          throw new SolrException(ErrorCode.SERVER_ERROR, e);
-        }
-      }
-    }
-  }
-
   private ManagedIndexSchema(
       Version luceneVersion,
       SolrResourceLoader loader,
diff --git 
a/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java 
b/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
index b64a098b82f..f21aa618a58 100644
--- a/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
@@ -35,6 +35,16 @@ public class ResolveAnalyzerByNameTest extends 
SolrTestCaseJ4 {
     initCore("solrconfig-basic.xml", "schema-analyzer-by-name.xml");
   }
 
+  @Test
+  public void testAnalyzerUsableForQueries() throws Exception {
+    assertQ(req("text2:bogus"), "//*[@numFound='0']");
+  }
+
+  public void testAnalyzerUsableForIndexing() throws Exception {
+    assertU(adoc("text2", "fat cat"));
+    assertU(commit());
+  }
+
   @Test
   public void testSchemaLoadingSimpleAnalyzer() {
     SolrCore core = h.getCore();

Reply via email to