You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dw...@apache.org on 2021/03/10 09:45:41 UTC

[lucene] branch jira/solr14155 created (now f3e3d9c)

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

dweiss pushed a change to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git.


      at f3e3d9c  WIP commit

This branch includes the following new commits:

     new 2302629  initial commit
     new 2bec9e3  SOLR-14151: Support for packages in schema.xml
     new eacbc1c  added tests
     new a7947ae  formatting
     new 945606f  bug fix
     new 58197f2  more tests. improved schema API to emit package details
     new 69b5a59  precommit errs
     new 3f47d8b  use final variable
     new 25aec79  javadoc
     new 97b1331  javadoc
     new 76e0203  javadoc
     new ac95a57  removed SOP
     new 61ee4d8  renamed PluginLoader to SolrClassLoader
     new e501ef5  fixed SolrCOreAware and ResourceLoaderAware bugs
     new 3303e0b  refactored our The PackageAwareSolrClassLoader
     new 16f6f4a  more javadocs
     new 4803c08  more javadocs and class rename
     new b31996c  sync with master
     new 455a23a  test failures fixed
     new ffae329  load packageloader first
     new f3e3d9c  WIP commit

The 21 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[lucene] 20/21: load packageloader first

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit ffae3290994402b464cb122771e080159fb74b38
Author: noble <no...@apache.org>
AuthorDate: Tue Dec 31 12:09:10 2019 +1100

    load packageloader first
---
 solr/core/src/java/org/apache/solr/core/CoreContainer.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index f494f50..b084751 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -647,6 +647,9 @@ public class CoreContainer {
 
     zkSys.initZooKeeper(this, solrHome, cfg.getCloudConfig());
     if (isZooKeeperAware()) {
+      packageLoader = new PackageLoader(this);
+      containerHandlers.getApiBag().register(new AnnotatedApi(packageLoader.getPackageAPI().editAPI), Collections.EMPTY_MAP);
+      containerHandlers.getApiBag().register(new AnnotatedApi(packageLoader.getPackageAPI().readAPI), Collections.EMPTY_MAP);
       pkiAuthenticationPlugin = new PKIAuthenticationPlugin(this, zkSys.getZkController().getNodeName(),
           (PublicKeyHandler) containerHandlers.get(PublicKeyHandler.PATH));
       // use deprecated API for back-compat, remove in 9.0
@@ -744,9 +747,6 @@ public class CoreContainer {
 
     if (isZooKeeperAware()) {
       metricManager.loadClusterReporters(metricReporters, this);
-      packageLoader = new PackageLoader(this);
-      containerHandlers.getApiBag().register(new AnnotatedApi(packageLoader.getPackageAPI().editAPI), Collections.EMPTY_MAP);
-      containerHandlers.getApiBag().register(new AnnotatedApi(packageLoader.getPackageAPI().readAPI), Collections.EMPTY_MAP);
     }
 
 


[lucene] 06/21: more tests. improved schema API to emit package details

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 58197f20e3ee2c686433326c4b442341815cbd65
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 26 19:40:43 2019 +1100

    more tests. improved schema API to emit package details
---
 .../src/java/org/apache/solr/core/PluginInfo.java  | 26 +++++++-----
 .../src/java/org/apache/solr/core/SolrCore.java    |  1 +
 .../org/apache/solr/handler/SchemaHandler.java     | 39 ++++++++++++++++++
 .../solr/handler/component/SearchHandler.java      |  3 +-
 .../java/org/apache/solr/pkg/PackageListeners.java | 10 ++++-
 .../java/org/apache/solr/pkg/PackageLoader.java    |  4 ++
 .../org/apache/solr/pkg/PackagePluginHolder.java   | 43 +++++++++++---------
 .../java/org/apache/solr/schema/IndexSchema.java   | 33 +++++++++++-----
 .../src/test/org/apache/solr/pkg/TestPackages.java | 46 ++++++++++++++++++++++
 9 files changed, 166 insertions(+), 39 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/PluginInfo.java b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
index afe4073..cfef933 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -41,6 +41,7 @@ import static org.apache.solr.schema.FieldType.CLASS_NAME;
  */
 public class PluginInfo implements MapSerializable {
   public final String name, className, type, pkgName;
+  public final ClassName cName;
   public final NamedList initArgs;
   public final Map<String, String> attributes;
   public final List<PluginInfo> children;
@@ -51,9 +52,9 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(String type, Map<String, String> attrs, NamedList initArgs, List<PluginInfo> children) {
     this.type = type;
     this.name = attrs.get(NAME);
-    ClassName parsed = new ClassName(attrs.get(CLASS_NAME));
-    this.className = parsed.klas;
-    this.pkgName = parsed.pkg;
+    cName = new ClassName(attrs.get(CLASS_NAME));
+    this.className = cName.klas;
+    this.pkgName = cName.pkg;
     this.initArgs = initArgs;
     attributes = unmodifiableMap(attrs);
     this.children = children == null ? Collections.<PluginInfo>emptyList(): unmodifiableList(children);
@@ -67,8 +68,10 @@ public class PluginInfo implements MapSerializable {
   public static class ClassName {
     public final String pkg;
     public final String klas;
+    private final String actual;
 
     public ClassName(String name) {
+      this.actual = name;
       String pkgName = null;
       String className = name;
       if (name != null) {
@@ -82,15 +85,20 @@ public class PluginInfo implements MapSerializable {
       this.klas = className;
       this.pkg = pkgName;
     }
+
+    @Override
+    public String toString() {
+      return actual;
+    }
   }
 
 
   public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
     type = node.getNodeName();
     name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
-    ClassName parsed = new ClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
-    className = parsed.klas;
-    pkgName = parsed.pkg;
+    cName = new ClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
+    className = cName.klas;
+    pkgName = cName.pkg;
     initArgs = DOMUtil.childNodesToNamedList(node);
     attributes = unmodifiableMap(DOMUtil.toMap(node.getAttributes()));
     children = loadSubPlugins(node);
@@ -120,9 +128,9 @@ public class PluginInfo implements MapSerializable {
     }
     this.type = type;
     this.name = (String) m.get(NAME);
-    ClassName parsed = new ClassName((String) m.get(CLASS_NAME));
-    this.className = parsed.klas;
-    this.pkgName = parsed.pkg;
+    cName = new ClassName((String) m.get(CLASS_NAME));
+    this.className = cName.klas;
+    this.pkgName = cName.pkg;
     attributes = unmodifiableMap(m);
     this.children =  Collections.<PluginInfo>emptyList();
     isFromSolrConfig = true;
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index e7c1be5..284bf66 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -909,6 +909,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   }
 
   public void refreshSchema() {
+    log.info("Reloading schema...");
     IndexSchema old = schema;
     schema = schemaSupplier.get();
     closeWhileHandlingException(old);
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index 5cbe9aa..c625534 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -24,7 +24,10 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
@@ -32,10 +35,13 @@ import org.apache.solr.cloud.ZkSolrResourceLoader;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.SolrQueryResponse;
@@ -179,6 +185,7 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
                     SimpleOrderedMap simpleOrderedMap = (SimpleOrderedMap) obj;
                     if(name.equals(simpleOrderedMap.get("name"))) {
                       rsp.add(fieldName.substring(0, realName.length() - 1), simpleOrderedMap);
+                      insertPackageInfo(rsp.getValues(), req);
                       return;
                     }
                   }
@@ -188,6 +195,7 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
             } else {
               rsp.add(fieldName, o);
             }
+            insertPackageInfo(rsp.getValues(), req);
             return;
           }
 
@@ -200,6 +208,37 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
     }
   }
 
+  private  void insertPackageInfo(Object o, SolrQueryRequest req) {
+    if(!req.getParams().getBool("meta")) return;
+    if (o instanceof List) {
+      List l = (List) o;
+      for (Object o1 : l) {
+        if (o1 instanceof NamedList || o1 instanceof List) insertPackageInfo(o1, req);
+      }
+
+    } else if (o instanceof NamedList) {
+      NamedList nl = (NamedList) o;
+      nl.forEach((BiConsumer) (n, v) -> {
+        if (v instanceof NamedList || v instanceof List) insertPackageInfo(v, req);
+      });
+      Object v = nl.get("class");
+      if (v instanceof String) {
+        String klas = (String) v;
+        PluginInfo.ClassName className = new PluginInfo.ClassName(klas);
+        if (className.pkg != null) {
+          req.getCore().getPackageListeners().forEachListener(listener -> {
+            if (listener.pluginInfo() == null) return;
+            if (Objects.equals(listener.pluginInfo().cName.toString(), className.toString())) {
+              nl.add("_packageinfo_", listener.getPackageVersion());
+            }
+          });
+        }
+      }
+
+    }
+
+  }
+
   private static Set<String> subPaths = new HashSet<>(Arrays.asList(
       "version",
       "uniquekey",
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index 5e48262..7bcb165 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -40,6 +40,7 @@ import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.pkg.PackageAPI;
 import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.pkg.PackageLoader;
 import org.apache.solr.request.SolrQueryRequest;
@@ -161,7 +162,7 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
         }
 
         @Override
-        public PackageLoader.Package.Version getPackageVersion() {
+        public PackageAPI.PkgVersion getPackageVersion() {
           return null;
         }
       });
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index 5802ee0..3d13ad8 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
@@ -96,6 +97,13 @@ public class PackageListeners {
     }
   }
 
+  public void forEachListener(Consumer<Listener> listenerConsumer){
+    listeners.forEach(ref -> {
+      Listener l = ref.get();
+      if (l != null) listenerConsumer.accept(l);
+    });
+  }
+
   public List<Listener> getListeners() {
     List<Listener> result = new ArrayList<>();
     for (Reference<Listener> ref : listeners) {
@@ -131,7 +139,7 @@ public class PackageListeners {
 
     void changed(PackageLoader.Package pkg, Ctx ctx);
 
-    PackageLoader.Package.Version getPackageVersion();
+    PackageAPI.PkgVersion  getPackageVersion();
 
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
index 8783d9b..b7a88d1 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
@@ -244,6 +244,10 @@ public class PackageLoader implements Closeable {
         version.writeMap(ew);
       }
 
+      public PackageAPI.PkgVersion getVersionInfo(){
+        return version;
+      }
+
       Version(Package parent, PackageAPI.PkgVersion v) {
         this.parent = parent;
         this.version = v;
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
index 50bf567..b15c524 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
@@ -62,30 +62,48 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
       }
 
       @Override
-      public PackageLoader.Package.Version getPackageVersion() {
-        return pkgVersion;
+      public PackageAPI.PkgVersion getPackageVersion() {
+        return pkgVersion.getVersionInfo();
       }
 
     });
   }
 
-  private String maxVersion() {
+  private static String maxAllowedVersion(SolrCore core , String pkgName) {
     RequestParams.ParamSet p = core.getSolrConfig().getRequestParams().getParams(PackageListeners.PACKAGE_VERSIONS);
     if (p == null) {
       return null;
     }
-    Object o = p.get().get(info.pkgName);
+    Object o = p.get().get(pkgName);
     if (o == null || LATEST.equals(o)) return null;
     return o.toString();
   }
 
 
   private synchronized void reload(PackageLoader.Package pkg) {
-    String lessThan = maxVersion();
+    PackageLoader.Package.Version rightVersion = getRightVersion(pkg, core);
+    if (pkgVersion != null) {
+      if (rightVersion == pkgVersion) {
+        //I'm already using the latest classloader in the package. nothing to do
+        return ;
+      }
+    }
+    if (rightVersion == null) return;
+
+    log.info("loading plugin: {} -> {} using  package {}:{}",
+        pluginInfo.type, pluginInfo.name, pkg.name(), rightVersion.getVersion());
+
+    initNewInstance(rightVersion);
+    pkgVersion = rightVersion;
+
+  }
+
+  public static PackageLoader.Package.Version getRightVersion(PackageLoader.Package pkg, SolrCore core ) {
+    String lessThan = maxAllowedVersion(core, pkg.name);
     PackageLoader.Package.Version newest = pkg.getLatest(lessThan);
     if (newest == null) {
       log.error("No latest version available for package : {}", pkg.name());
-      return;
+      return null;
     }
     if (lessThan != null) {
       PackageLoader.Package.Version pkgLatest = pkg.getLatest();
@@ -94,19 +112,8 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
       }
     }
 
-    if (pkgVersion != null) {
-      if (newest == pkgVersion) {
-        //I'm already using the latest classloder in the package. nothing to do
-        return;
-      }
-    }
-
-    log.info("loading plugin: {} -> {} using  package {}:{}",
-        pluginInfo.type, pluginInfo.name, pkg.name(), newest.getVersion());
-
-    initNewInstance(newest);
-    pkgVersion = newest;
 
+    return newest;
   }
 
   protected void initNewInstance(PackageLoader.Package.Version newest) {
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 d4273a8..35ecdfd 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -62,13 +62,16 @@ import org.apache.solr.common.util.Cache;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.core.PluginBag;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.PluginLoader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.core.XmlConfigFile;
+import org.apache.solr.pkg.PackageAPI;
 import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.pkg.PackageLoader;
+import org.apache.solr.pkg.PackagePluginHolder;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.response.SchemaXmlWriter;
 import org.apache.solr.response.SolrQueryResponse;
@@ -78,6 +81,7 @@ import org.apache.solr.util.ConcurrentLRUCache;
 import org.apache.solr.util.DOMUtil;
 import org.apache.solr.util.PayloadUtils;
 import org.apache.solr.util.plugin.SolrCoreAware;
+import org.codehaus.janino.Java;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -164,6 +168,8 @@ public class IndexSchema implements Closeable {
 
   private Map<FieldType, PayloadDecoder> decoders = new HashMap<>();  // cache to avoid scanning token filters repeatedly, unnecessarily
 
+  private Map<String, PackageAPI.PkgVersion> classNameVsPkg = new HashMap<>();
+
   /**
    * keys are all fields copied to, count is num of copyField
    * directives that target them.
@@ -203,7 +209,7 @@ public class IndexSchema implements Closeable {
     }
   }
 
-  class PackageAwarePluginLoader implements PluginLoader, Closeable {
+  public class PackageAwarePluginLoader implements PluginLoader, Closeable {
     final SolrCore core;
     private final List<PackageListeners.Listener> listeners = new ArrayList<>();
     Runnable reloadSchemaRunnable = () -> getCore().refreshSchema();
@@ -219,19 +225,22 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
-      return getIt(cname, expectedType,
+      return loadWithRightPackageLoader(cname, expectedType,
           (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
     }
 
-    private <T> T getIt(String cname, Class expectedType, BiFunction<SolrResourceLoader, String, T> fun) {
+    private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrResourceLoader, String, T> fun) {
       PluginInfo.ClassName className = new PluginInfo.ClassName(cname);
       if (className.pkg == null) {
         return  fun.apply(loader, className.klas);
       } else {
-        SolrResourceLoader pkgloader = core.getResourceLoader(className.pkg);
-        T inst = fun.apply(pkgloader,className.klas);
+        PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(className.pkg);
+        PackageLoader.Package.Version ver = PackagePluginHolder.getRightVersion(pkg, core);
+        T inst = fun.apply(ver.getLoader(),className.klas);
+        classNameVsPkg.put(cname, ver.getVersionInfo());
         PackageListeners.Listener listener = new PackageListeners.Listener() {
-          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", className.klas));
+
+          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
 
           @Override
           public String packageName() {
@@ -245,13 +254,17 @@ public class IndexSchema implements Closeable {
 
           @Override
           public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
+            PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
+            if (rightVersion == null ) return;
+            PackageAPI.PkgVersion v = classNameVsPkg.get(className.toString());
+            if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
             Runnable old = ctx.getPostProcessor(PackageAwarePluginLoader.class.getName());// just want to do one refresh for every package laod
             if (old == null) ctx.addPostProcessor(PackageAwarePluginLoader.class.getName(), reloadSchemaRunnable);
           }
 
           @Override
-          public PackageLoader.Package.Version getPackageVersion() {
-            return null;
+          public PackageAPI.PkgVersion getPackageVersion() {
+            return classNameVsPkg.get(cname);
           }
         };
         listeners.add(listener);
@@ -262,12 +275,12 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
-      return getIt(cname, expectedType, (BiFunction<SolrResourceLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
+      return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrResourceLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
     }
 
     @Override
     public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
-      return getIt(cName, expectedType, (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subPackages, params, args));
+      return loadWithRightPackageLoader(cName, expectedType, (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subPackages, params, args));
     }
 
 
diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
index fe46ef1..4a3ff7b 100644
--- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
+++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
@@ -18,6 +18,7 @@
 package org.apache.solr.pkg;
 
 import java.io.IOException;
+import java.io.StringWriter;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collections;
@@ -52,6 +53,7 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.filestore.TestDistribPackageStore;
 import org.apache.solr.util.LogLevel;
@@ -169,7 +171,35 @@ public class TestPackages extends SolrCloudTestCase {
           return new SolrResponseBase();
         }
       });
+      verifySchemaComponent(cluster.getSolrClient(), COLLECTION_NAME, "/schema/fieldtypes/myNewTextFieldWithAnalyzerClass",
+          Utils.makeMap(":fieldType:analyzer:charFilters[0]:_packageinfo_:version" ,"1.0",
+                                  ":fieldType:analyzer:tokenizer:_packageinfo_:version","1.0",
+                                  ":fieldType:_packageinfo_:version","1.0"));
 
+      add = new Package.AddVersion();
+      add.version = "2.0";
+      add.pkg = "schemapkg";
+      add.files = Arrays.asList(new String[]{FILE1});
+      req = new V2Request.Builder("/cluster/package")
+          .forceV2(true)
+          .withMethod(SolrRequest.METHOD.POST)
+          .withPayload(Collections.singletonMap("add", add))
+          .build();
+      req.process(cluster.getSolrClient());
+
+      TestDistribPackageStore.assertResponseValues(10,
+          () -> new V2Request.Builder("/cluster/package").
+              withMethod(SolrRequest.METHOD.GET)
+              .build().process(cluster.getSolrClient()),
+          Utils.makeMap(
+              ":result:packages:schemapkg[0]:version", "2.0",
+              ":result:packages:schemapkg[0]:files[0]", FILE1
+          ));
+
+      verifySchemaComponent(cluster.getSolrClient(), COLLECTION_NAME, "/schema/fieldtypes/myNewTextFieldWithAnalyzerClass",
+          Utils.makeMap(":fieldType:analyzer:charFilters[0]:_packageinfo_:version" ,"2.0",
+              ":fieldType:analyzer:tokenizer:_packageinfo_:version","2.0",
+              ":fieldType:_packageinfo_:version","2.0"));
 
     } finally {
       cluster.shutdown();
@@ -499,6 +529,22 @@ public class TestPackages extends SolrCloudTestCase {
     }
   }
 
+  private void verifySchemaComponent(SolrClient client, String COLLECTION_NAME, String path,
+                              Map expected) throws Exception {
+    SolrParams params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
+        WT, JAVABIN,
+        "meta", "true"));
+
+    GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET,path
+        , params);
+    NamedList<Object> rsp = client.request(req);
+    System.out.println( Utils.writeJson(rsp, new StringWriter(), true).toString());
+    TestDistribPackageStore.assertResponseValues(10,
+        client,
+        req, expected);
+  }
+
+
   private void verifyCmponent(SolrClient client, String COLLECTION_NAME,
   String componentType, String componentName, String pkg, String version) throws Exception {
     SolrParams params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,


[lucene] 01/21: initial commit

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 2302629ee40c632ad9c3a5dd507b6425ac5db779
Author: noble <no...@apache.org>
AuthorDate: Wed Dec 25 11:46:55 2019 +1100

    initial commit
---
 .../solr/handler/component/SearchHandler.java      |  2 +-
 .../java/org/apache/solr/pkg/PackageListeners.java | 40 ++++++++++++++++++----
 .../org/apache/solr/pkg/PackagePluginHolder.java   |  2 +-
 3 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index 2d4d63d..5e48262 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -154,7 +154,7 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
         }
 
         @Override
-        public void changed(PackageLoader.Package pkg) {
+        public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
           //we could optimize this by listening to only relevant packages,
           // but it is not worth optimizing as these are lightweight objects
           components = null;
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index 0287f5e..5802ee0 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -21,8 +21,10 @@ import java.lang.invoke.MethodHandles;
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
@@ -75,11 +77,21 @@ public class PackageListeners {
   }
 
   private synchronized void invokeListeners(PackageLoader.Package pkg) {
-    for (Reference<Listener> ref : listeners) {
-      Listener listener = ref.get();
-      if(listener == null) continue;
-      if (listener.packageName() == null || listener.packageName().equals(pkg.name())) {
-        listener.changed(pkg);
+    Ctx ctx = new Ctx();
+
+    try {
+      for (Reference<Listener> ref : listeners) {
+        Listener listener = ref.get();
+        if(listener == null) continue;
+        if (listener.packageName() == null || listener.packageName().equals(pkg.name())) {
+          listener.changed(pkg, ctx);
+        }
+      }
+    } finally {
+      if(ctx.postProcessors != null){
+        for (Runnable value : ctx.postProcessors.values()) {
+          value.run();
+        }
       }
     }
   }
@@ -96,14 +108,28 @@ public class PackageListeners {
   }
 
 
+  public class Ctx {
+    private Map<String, Runnable > postProcessors;
+    public void addPostProcessor(String name, Runnable runnable){
+      if(postProcessors == null) postProcessors = new HashMap<>();
+      postProcessors.put(name, runnable);
+    }
+
+    public Runnable getPostProcessor(String name){
+      if(postProcessors == null) return null;
+      return postProcessors.get(name);
+    }
+
+
+  }
   public interface Listener {
-    /**Name of the package or null to loisten to all package changes
+    /**Name of the package or null to listen to all package changes
      */
     String packageName();
 
     PluginInfo pluginInfo();
 
-    void changed(PackageLoader.Package pkg);
+    void changed(PackageLoader.Package pkg, Ctx ctx);
 
     PackageLoader.Package.Version getPackageVersion();
 
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
index c6ddd4f..50bf567 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
@@ -56,7 +56,7 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
       }
 
       @Override
-      public void changed(PackageLoader.Package pkg) {
+      public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
         reload(pkg);
 
       }


[lucene] 21/21: WIP commit

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit f3e3d9c18f6a568063f6aa7fcacdc637b960b1a8
Author: noble <no...@apache.org>
AuthorDate: Tue Dec 31 13:14:20 2019 +1100

    WIP commit
---
 .../java/org/apache/solr/core/CoreContainer.java   |  4 +-
 .../org/apache/solr/core/DirectoryFactory.java     |  6 +--
 .../java/org/apache/solr/core/SolrClassLoader.java |  8 ++++
 .../src/java/org/apache/solr/core/SolrCore.java    | 33 ++++++++++++-----
 .../solr/pkg/PackageAwareSolrClassLoader.java      | 43 +++++++++++-----------
 5 files changed, 58 insertions(+), 36 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index b084751..c5f9f66 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -1319,7 +1319,7 @@ public class CoreContainer {
         return core.getDirectoryFactory().isSharedStorage();
       } else {
         ConfigSet configSet = getConfigSet(cd);
-        return DirectoryFactory.loadDirectoryFactory(configSet.getSolrConfig(), this, null).isSharedStorage();
+        return DirectoryFactory.loadDirectoryFactory(configSet.getSolrConfig(), this, null, configSet.getSolrConfig().getResourceLoader()).isSharedStorage();
       }
     }
   }
@@ -1393,7 +1393,7 @@ public class CoreContainer {
     SolrConfig config = coreConfig.getSolrConfig();
 
     String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, dcore.getName());
-    DirectoryFactory df = DirectoryFactory.loadDirectoryFactory(config, this, registryName);
+    DirectoryFactory df = DirectoryFactory.loadDirectoryFactory(config, this, registryName, config.getResourceLoader());
     String dataDir = SolrCore.findDataDir(df, null, config, dcore);
 
     String tmpIdxDirName = "index." + new SimpleDateFormat(SnapShooter.DATE_FMT, Locale.ROOT).format(new Date());
diff --git a/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java b/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java
index fab3300..37bda19 100644
--- a/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java
+++ b/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java
@@ -23,9 +23,9 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.NoSuchFileException;
-import java.util.Arrays;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -415,12 +415,12 @@ public abstract class DirectoryFactory implements NamedListInitializedPlugin,
   /**
    * Create a new DirectoryFactory instance from the given SolrConfig and tied to the specified core container.
    */
-  static DirectoryFactory loadDirectoryFactory(SolrConfig config, CoreContainer cc, String registryName) {
+  static DirectoryFactory loadDirectoryFactory(SolrConfig config, CoreContainer cc, String registryName , SolrClassLoader loader) {
     final PluginInfo info = config.getPluginInfo(DirectoryFactory.class.getName());
     final DirectoryFactory dirFactory;
     if (info != null) {
       log.debug(info.className);
-      dirFactory = config.getResourceLoader().newInstance(info.className, DirectoryFactory.class);
+      dirFactory = loader.newInstance(info, DirectoryFactory.class);
       // allow DirectoryFactory instances to access the CoreContainer
       dirFactory.initCoreContainer(cc);
       dirFactory.init(info.initArgs);
diff --git a/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
index 8995c80..0bb8f47 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
@@ -29,7 +29,15 @@ public interface SolrClassLoader extends Closeable, ResourceLoader {
 
   <T> T newInstance(String cname, Class<T> expectedType, String... subpackages);
 
+  default <T> T newInstance(PluginInfo info, Class<T> expectedType) {
+   return newInstance(info.className, expectedType);
+  }
+
   <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args);
 
   <T> Class<? extends T> findClass(String cname, Class<T> expectedType);
+
+  default  <T> Class<? extends T> findClass(PluginInfo info, Class<T> expectedType){
+    return findClass(info.className, expectedType);
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 2af1421..e520646 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -109,6 +109,7 @@ import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.solr.metrics.SolrCoreMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
 import org.apache.solr.metrics.SolrMetricsContext;
+import org.apache.solr.pkg.PackageAwareSolrClassLoader;
 import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.pkg.PackageLoader;
 import org.apache.solr.request.SolrQueryRequest;
@@ -197,6 +198,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
   private final SolrConfig solrConfig;
   private final SolrResourceLoader resourceLoader;
+  private final SolrClassLoader packageClassLoader;
   private volatile IndexSchema schema;
   private final NamedList configSetProperties;
   private final String dataDir;
@@ -284,6 +286,10 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     return resourceLoader;
   }
 
+  public SolrClassLoader getPackageClassLoader(){
+    return packageClassLoader;
+  }
+
   /** Gets the SolrResourceLoader for a given package
    * @param pkg The package name
    */
@@ -520,7 +526,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     final PluginInfo info = solrConfig.getPluginInfo(IndexDeletionPolicy.class.getName());
     final IndexDeletionPolicy delPolicy;
     if (info != null) {
-      delPolicy = createInstance(info.className, IndexDeletionPolicy.class, "Deletion Policy for SOLR", this, getResourceLoader());
+      delPolicy = createInstance(info, IndexDeletionPolicy.class, "Deletion Policy for SOLR", this, getPackageClassLoader());
       if (delPolicy instanceof NamedListInitializedPlugin) {
         ((NamedListInitializedPlugin) delPolicy).init(info.initArgs);
       }
@@ -709,7 +715,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   }
 
   private DirectoryFactory initDirectoryFactory() {
-    return DirectoryFactory.loadDirectoryFactory(solrConfig, coreContainer, coreMetricManager.getRegistryName());
+    return DirectoryFactory.loadDirectoryFactory(solrConfig, coreContainer, coreMetricManager.getRegistryName(), packageClassLoader);
   }
 
   private RecoveryStrategy.Builder initRecoveryStrategyBuilder() {
@@ -717,7 +723,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     final RecoveryStrategy.Builder rsBuilder;
     if (info != null && info.className != null) {
       log.info(info.className);
-      rsBuilder = getResourceLoader().newInstance(info.className, RecoveryStrategy.Builder.class);
+      rsBuilder = getPackageClassLoader ().newInstance(info, RecoveryStrategy.Builder.class);
     } else {
       log.debug("solr.RecoveryStrategy.Builder");
       rsBuilder = new RecoveryStrategy.Builder();
@@ -732,7 +738,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     IndexReaderFactory indexReaderFactory;
     PluginInfo info = solrConfig.getPluginInfo(IndexReaderFactory.class.getName());
     if (info != null) {
-      indexReaderFactory = resourceLoader.newInstance(info.className, IndexReaderFactory.class);
+      indexReaderFactory =  packageClassLoader.newInstance(info, IndexReaderFactory.class);
       indexReaderFactory.init(info.initArgs);
     } else {
       indexReaderFactory = new StandardIndexReaderFactory();
@@ -806,23 +812,27 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     cleanupOldIndexDirectories(reload);
   }
 
+  public static <T> T createInstance(String className, Class<T> cast, String msg, SolrCore core, SolrClassLoader resourceLoader) {
+    return createInstance(new PluginInfo(cast.getSimpleName(), Collections.singletonMap("class", className)) , cast, msg, core,  resourceLoader);
+
+  }
 
   /**
    * Creates an instance by trying a constructor that accepts a SolrCore before
    * trying the default (no arg) constructor.
    *
-   * @param className the instance class to create
+   * @param info the instance class to create
    * @param cast      the class or interface that the instance should extend or implement
    * @param msg       a message helping compose the exception error if any occurs.
    * @param core      The SolrCore instance for which this object needs to be loaded
    * @return the desired instance
    * @throws SolrException if the object could not be instantiated
    */
-  public static <T> T createInstance(String className, Class<T> cast, String msg, SolrCore core, SolrClassLoader resourceLoader) {
+  public static <T> T createInstance(PluginInfo info, Class<T> cast, String msg, SolrCore core, SolrClassLoader resourceLoader) {
     Class<? extends T> clazz = null;
     if (msg == null) msg = "SolrCore Object";
     try {
-      clazz = resourceLoader.findClass(className, cast);
+      clazz = resourceLoader.findClass(info, cast);
       //most of the classes do not have constructors which takes SolrCore argument. It is recommended to obtain SolrCore by implementing SolrCoreAware.
       // So invariably always it will cause a  NoSuchMethodException. So iterate though the list of available constructors
       Constructor<?>[] cons = clazz.getConstructors();
@@ -832,7 +842,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
           return cast.cast(con.newInstance(core));
         }
       }
-      return resourceLoader.newInstance(className, cast);//use the empty constructor
+      return resourceLoader.newInstance(info, cast);//use the empty constructor
     } catch (SolrException e) {
       throw e;
     } catch (Exception e) {
@@ -843,7 +853,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
         throw inner;
       }
 
-      throw new SolrException(ErrorCode.SERVER_ERROR, "Error Instantiating " + msg + ", " + className + " failed to instantiate " + cast.getName(), e);
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Error Instantiating " + msg + ", " + info.className + " failed to instantiate " + cast.getName(), e);
     }
   }
 
@@ -945,6 +955,9 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
       resourceLoader = config.getResourceLoader();
       resourceLoader.core = this;
+      packageClassLoader = coreContainer.isZooKeeperAware()?
+          new PackageAwareSolrClassLoader(this, () -> new Thread(() -> getCoreContainer().reload(name)).start()) :
+          resourceLoader;
       this.solrConfig = config;
       this.configSetProperties = configSetProperties;
       // Initialize the metrics manager
@@ -1423,7 +1436,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     final PluginInfo info = solrConfig.getPluginInfo(CodecFactory.class.getName());
     final CodecFactory factory;
     if (info != null) {
-      factory = resourceLoader.newInstance(info.className, CodecFactory.class);
+      factory = packageClassLoader.newInstance(info, CodecFactory.class);
       factory.init(info.initArgs);
     } else {
       factory = new CodecFactory() {
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
index 90052e7..f9ef156 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
@@ -20,6 +20,7 @@ package org.apache.solr.pkg;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -32,8 +33,6 @@ import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.plugin.SolrCoreAware;
 
-import static java.util.Collections.singletonMap;
-
 /**
  * This class implements a {@link SolrClassLoader} that can  identify the correct packages
  * and load classes from that. This also listens to any changes to the relevant packages and
@@ -64,6 +63,11 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
   }
 
   @Override
+  public <T> T newInstance(PluginInfo info, Class<T> expectedType) {
+    return null;
+  }
+
+  @Override
   public InputStream openResource(String resource) throws IOException {
     return loader.openResource(resource);
   }
@@ -79,26 +83,28 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
     return loadWithRightPackageLoader(cname, expectedType,
         (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
   }
-
-  private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
-    PluginInfo.ParsedClassName parsedClassName = new PluginInfo.ParsedClassName(cname);
-    if (parsedClassName.pkg == null) {
-      return  fun.apply(loader, parsedClassName.klas);
+  private <T> T loadWithRightPackageLoader(PluginInfo info, BiFunction<SolrClassLoader, String, T> fun) {
+    if (info.pkgName == null) {
+      return  fun.apply(loader, info.className);
     } else {
-      PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(parsedClassName.pkg);
+      PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(info.pkgName);
       PackageLoader.Package.Version ver = PackagePluginHolder.getRightVersion(pkg, core);
-      T result = fun.apply(ver.getLoader(), parsedClassName.klas);
+      T result = fun.apply(ver.getLoader(), info.className);
       if (result instanceof SolrCoreAware) {
         loader.registerSolrCoreAware((SolrCoreAware) result);
       }
-      classNameVsPkg.put(cname, ver.getVersionInfo());
-      PackageListeners.Listener listener = new PackageListener(expectedType, cname, parsedClassName);
+      classNameVsPkg.put(info.cName.toString(), ver.getVersionInfo());
+      PackageListeners.Listener listener = new PackageListener(info);
       listeners.add(listener);
       core.getPackageListeners().addListener(listener);
       return result;
     }
   }
 
+  private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
+    return loadWithRightPackageLoader(new PluginInfo(expectedType.getSimpleName(), Collections.singletonMap("class", cname)), fun);
+  }
+
   @Override
   public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
     return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrClassLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
@@ -119,20 +125,15 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
   }
 
   private class PackageListener implements PackageListeners.Listener {
-
-    private final String cname;
-    private final PluginInfo.ParsedClassName parsedClassName;
     PluginInfo info;
 
-    public PackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
-      this.cname = cname;
-      this.parsedClassName = parsedClassName;
-      info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
+    public PackageListener(PluginInfo pluginInfo) {
+      this.info = pluginInfo;
     }
 
     @Override
     public String packageName() {
-      return parsedClassName.pkg;
+      return info.pkgName;
     }
 
     @Override
@@ -144,7 +145,7 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
     public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
       PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
       if (rightVersion == null ) return;
-      PackageAPI.PkgVersion v = classNameVsPkg.get(parsedClassName.toString());
+      PackageAPI.PkgVersion v = classNameVsPkg.get(info.cName.toString());
       if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
       Runnable old = ctx.getPostProcessor(PackageAwareSolrClassLoader.class.getName());// just want to do one refresh for every package laod
       if (old == null) ctx.addPostProcessor(PackageAwareSolrClassLoader.class.getName(), reloadRunnable);
@@ -152,7 +153,7 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
 
     @Override
     public PackageAPI.PkgVersion getPackageVersion() {
-      return classNameVsPkg.get(cname);
+      return classNameVsPkg.get(info.cName.toString());
     }
   }
 }


[lucene] 15/21: refactored our The PackageAwareSolrClassLoader

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 3303e0bcae4f01d3c0ab7f7df4d69e8c6f665ce5
Author: noble <no...@apache.org>
AuthorDate: Sat Dec 28 10:23:24 2019 +1100

    refactored our The PackageAwareSolrClassLoader
---
 .../solr/pkg/PackageAwareSolrClassLoader.java      | 154 +++++++++++++++++++++
 .../java/org/apache/solr/schema/IndexSchema.java   | 127 +----------------
 2 files changed, 158 insertions(+), 123 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
new file mode 100644
index 0000000..2eb8913
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
@@ -0,0 +1,154 @@
+/*
+ * 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.solr.pkg;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiFunction;
+
+import org.apache.solr.core.PluginInfo;
+import org.apache.solr.core.SolrClassLoader;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.util.plugin.SolrCoreAware;
+
+import static java.util.Collections.singletonMap;
+
+/**
+ * This class implements a SolrClassLoader that can  identify the correct packages
+ * and load classes from that. This also listens to any changes to the relevant packages and
+ * invoke a callback if anything is modified
+ */
+public class PackageAwareSolrClassLoader implements SolrClassLoader {
+  final SolrCore core;
+  final SolrResourceLoader loader;
+  private Map<String, PackageAPI.PkgVersion> classNameVsPkg = new HashMap<>();
+
+  private final List<PackageListeners.Listener> listeners = new ArrayList<>();
+  private final Runnable reloadRunnable;
+
+
+  public PackageAwareSolrClassLoader(SolrCore core, SolrResourceLoader loader, Runnable runnable) {
+    this.core = core;
+    this.loader = loader;
+    this.reloadRunnable = runnable;
+  }
+
+  SolrCore getCore() {
+    return core;
+  }
+
+  @Override
+  public InputStream openResource(String resource) throws IOException {
+    return loader.openResource(resource);
+  }
+
+  @Override
+  public <T> T newInstance(String cname, Class<T> expectedType) {
+    return loadWithRightPackageLoader(cname, expectedType,
+        (pkgloader, name) -> pkgloader.newInstance(name, expectedType));
+  }
+
+  @Override
+  public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
+    return loadWithRightPackageLoader(cname, expectedType,
+        (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
+  }
+
+  private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
+    PluginInfo.ParsedClassName parsedClassName = new PluginInfo.ParsedClassName(cname);
+    if (parsedClassName.pkg == null) {
+      return  fun.apply(loader, parsedClassName.klas);
+    } else {
+      PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(parsedClassName.pkg);
+      PackageLoader.Package.Version ver = PackagePluginHolder.getRightVersion(pkg, core);
+      T result = fun.apply(ver.getLoader(), parsedClassName.klas);
+      if (result instanceof SolrCoreAware) {
+        loader.registerSolrCoreAware((SolrCoreAware) result);
+      }
+      classNameVsPkg.put(cname, ver.getVersionInfo());
+      PackageListeners.Listener listener = new SchemaPluginPackageListener(expectedType, cname, parsedClassName);
+      listeners.add(listener);
+      core.getPackageListeners().addListener(listener);
+      return result;
+    }
+  }
+
+  @Override
+  public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
+    return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrClassLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
+  }
+
+  @Override
+  public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
+    return loadWithRightPackageLoader(cName, expectedType, (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subPackages, params, args));
+  }
+
+
+
+  @Override
+  public void close() throws IOException {
+    for (PackageListeners.Listener l : listeners) {
+      core.getPackageListeners().removeListener(l);
+    }
+
+  }
+
+  private class SchemaPluginPackageListener implements PackageListeners.Listener {
+
+    private final String cname;
+    private final PluginInfo.ParsedClassName parsedClassName;
+    PluginInfo info;
+
+    public SchemaPluginPackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
+      this.cname = cname;
+      this.parsedClassName = parsedClassName;
+      info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
+    }
+
+    @Override
+    public String packageName() {
+      return parsedClassName.pkg;
+    }
+
+    @Override
+    public PluginInfo pluginInfo() {
+      return info;
+    }
+
+    @Override
+    public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
+      PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
+      if (rightVersion == null ) return;
+      PackageAPI.PkgVersion v = classNameVsPkg.get(parsedClassName.toString());
+      if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
+      Runnable old = ctx.getPostProcessor(PackageAwareSolrClassLoader.class.getName());// just want to do one refresh for every package laod
+      if (old == null) ctx.addPostProcessor(PackageAwareSolrClassLoader.class.getName(), reloadRunnable);
+    }
+
+    @Override
+    public PackageAPI.PkgVersion getPackageVersion() {
+      return classNameVsPkg.get(cname);
+    }
+  }
+}
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 8650b6d..74e20b3 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -21,7 +21,6 @@ import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import java.io.Closeable;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.Writer;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
@@ -40,7 +39,6 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -63,15 +61,11 @@ import org.apache.solr.common.util.Cache;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.core.XmlConfigFile;
-import org.apache.solr.pkg.PackageAPI;
-import org.apache.solr.pkg.PackageListeners;
-import org.apache.solr.pkg.PackageLoader;
-import org.apache.solr.pkg.PackagePluginHolder;
+import org.apache.solr.pkg.PackageAwareSolrClassLoader;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.response.SchemaXmlWriter;
 import org.apache.solr.response.SolrQueryResponse;
@@ -174,8 +168,6 @@ public class IndexSchema implements Closeable {
 
   private Map<FieldType, PayloadDecoder> decoders = new HashMap<>();  // cache to avoid scanning token filters repeatedly, unnecessarily
 
-  private Map<String, PackageAPI.PkgVersion> classNameVsPkg = new HashMap<>();
-
   /**
    * keys are all fields copied to, count is num of copyField
    * directives that target them.
@@ -210,118 +202,7 @@ public class IndexSchema implements Closeable {
     if(loader.getCore() == null) {
       this.classLoader = loader;
     } else {
-      this.classLoader = new PackageAwarePluginLoader(loader.getCore());
-    }
-  }
-
-  public class PackageAwarePluginLoader implements SolrClassLoader {
-    final SolrCore core;
-    private final List<PackageListeners.Listener> listeners = new ArrayList<>();
-    Runnable reloadSchemaRunnable = () -> getCore().refreshSchema();
-
-
-    PackageAwarePluginLoader(SolrCore core) {
-      this.core = core;
-    }
-
-    SolrCore getCore() {
-      return core;
-    }
-
-    @Override
-    public InputStream openResource(String resource) throws IOException {
-      return loader.openResource(resource);
-    }
-
-    @Override
-    public <T> T newInstance(String cname, Class<T> expectedType) {
-      return loadWithRightPackageLoader(cname, expectedType,
-          (pkgloader, name) -> pkgloader.newInstance(name, expectedType));
-    }
-
-    @Override
-    public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
-      return loadWithRightPackageLoader(cname, expectedType,
-          (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
-    }
-
-    private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
-      PluginInfo.ParsedClassName parsedClassName = new PluginInfo.ParsedClassName(cname);
-      if (parsedClassName.pkg == null) {
-        return  fun.apply(loader, parsedClassName.klas);
-      } else {
-        PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(parsedClassName.pkg);
-        PackageLoader.Package.Version ver = PackagePluginHolder.getRightVersion(pkg, core);
-        T result = fun.apply(ver.getLoader(), parsedClassName.klas);
-        if (result instanceof SolrCoreAware) {
-          loader.registerSolrCoreAware((SolrCoreAware) result);
-        }
-        classNameVsPkg.put(cname, ver.getVersionInfo());
-        PackageListeners.Listener listener = new SchemaPluginPackageListener(expectedType, cname, parsedClassName);
-        listeners.add(listener);
-        core.getPackageListeners().addListener(listener);
-        return result;
-      }
-    }
-
-    @Override
-    public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
-      return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrClassLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
-    }
-
-    @Override
-    public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
-      return loadWithRightPackageLoader(cName, expectedType, (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subPackages, params, args));
-    }
-
-
-
-    @Override
-    public void close() throws IOException {
-      for (PackageListeners.Listener l : listeners) {
-        core.getPackageListeners().removeListener(l);
-      }
-
-    }
-
-    private class SchemaPluginPackageListener implements PackageListeners.Listener {
-
-      private final Class expectedType;
-      private final String cname;
-      private final PluginInfo.ParsedClassName parsedClassName;
-      PluginInfo info;
-
-      public SchemaPluginPackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
-        this.expectedType = expectedType;
-        this.cname = cname;
-        this.parsedClassName = parsedClassName;
-        info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
-      }
-
-      @Override
-      public String packageName() {
-        return parsedClassName.pkg;
-      }
-
-      @Override
-      public PluginInfo pluginInfo() {
-        return info;
-      }
-
-      @Override
-      public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
-        PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
-        if (rightVersion == null ) return;
-        PackageAPI.PkgVersion v = classNameVsPkg.get(parsedClassName.toString());
-        if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
-        Runnable old = ctx.getPostProcessor(PackageAwarePluginLoader.class.getName());// just want to do one refresh for every package laod
-        if (old == null) ctx.addPostProcessor(PackageAwarePluginLoader.class.getName(), reloadSchemaRunnable);
-      }
-
-      @Override
-      public PackageAPI.PkgVersion getPackageVersion() {
-        return classNameVsPkg.get(cname);
-      }
+      this.classLoader = new PackageAwareSolrClassLoader(loader.getCore(), loader,  () ->  loader.getCore().refreshSchema());
     }
   }
 
@@ -2122,8 +2003,8 @@ public class IndexSchema implements Closeable {
 
   @Override
   public void close() throws IOException {
-    if (classLoader instanceof PackageAwarePluginLoader) {
-      ((PackageAwarePluginLoader) classLoader).close();
+    if (classLoader instanceof PackageAwareSolrClassLoader) {
+      ((PackageAwareSolrClassLoader) classLoader).close();
     }
   }
 }


[lucene] 17/21: more javadocs and class rename

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 4803c08f026138e7cb99b486642ec47345a92eda
Author: noble <no...@apache.org>
AuthorDate: Sun Dec 29 11:30:42 2019 +1100

    more javadocs and class rename
---
 .../java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
index 5820439..90052e7 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
@@ -35,7 +35,7 @@ import org.apache.solr.util.plugin.SolrCoreAware;
 import static java.util.Collections.singletonMap;
 
 /**
- * This class implements a SolrClassLoader that can  identify the correct packages
+ * This class implements a {@link SolrClassLoader} that can  identify the correct packages
  * and load classes from that. This also listens to any changes to the relevant packages and
  * invoke a callback if anything is modified
  */
@@ -51,7 +51,7 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
   /**
    *
    * @param core The core where this belong to
-   * @param runnable run a task if somethingis modified, say reload schema or reload core, refresh cache or something else
+   * @param runnable run a task if something is modified, say reload schema or reload core, refresh cache or something else
    */
   public PackageAwareSolrClassLoader(SolrCore core,  Runnable runnable) {
     this.core = core;
@@ -92,7 +92,7 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
         loader.registerSolrCoreAware((SolrCoreAware) result);
       }
       classNameVsPkg.put(cname, ver.getVersionInfo());
-      PackageListeners.Listener listener = new SchemaPluginPackageListener(expectedType, cname, parsedClassName);
+      PackageListeners.Listener listener = new PackageListener(expectedType, cname, parsedClassName);
       listeners.add(listener);
       core.getPackageListeners().addListener(listener);
       return result;
@@ -116,16 +116,15 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
     for (PackageListeners.Listener l : listeners) {
       core.getPackageListeners().removeListener(l);
     }
-
   }
 
-  private class SchemaPluginPackageListener implements PackageListeners.Listener {
+  private class PackageListener implements PackageListeners.Listener {
 
     private final String cname;
     private final PluginInfo.ParsedClassName parsedClassName;
     PluginInfo info;
 
-    public SchemaPluginPackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
+    public PackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
       this.cname = cname;
       this.parsedClassName = parsedClassName;
       info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));


[lucene] 13/21: renamed PluginLoader to SolrClassLoader

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 61ee4d8327ecb07cffd5463e59e584fa3e8c24d8
Author: noble <no...@apache.org>
AuthorDate: Sat Dec 28 00:11:38 2019 +1100

    renamed PluginLoader to SolrClassLoader
---
 .../java/org/apache/solr/core/MemClassLoader.java  | 14 ++++++++--
 .../src/java/org/apache/solr/core/PluginBag.java   |  7 +++--
 .../{PluginLoader.java => SolrClassLoader.java}    |  4 ++-
 .../src/java/org/apache/solr/core/SolrCore.java    |  7 +++--
 .../org/apache/solr/core/SolrResourceLoader.java   |  9 ++++---
 .../org/apache/solr/handler/SolrConfigHandler.java |  5 ++--
 .../java/org/apache/solr/pkg/PackageLoader.java    | 12 ++++++---
 .../org/apache/solr/schema/CurrencyFieldType.java  |  2 +-
 .../apache/solr/schema/FieldTypePluginLoader.java  | 12 ++++-----
 .../java/org/apache/solr/schema/IndexSchema.java   | 31 +++++++++++-----------
 .../org/apache/solr/schema/ManagedIndexSchema.java |  2 +-
 .../org/apache/solr/schema/PreAnalyzedField.java   |  2 +-
 .../solr/util/plugin/AbstractPluginLoader.java     |  8 +++---
 13 files changed, 67 insertions(+), 48 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/MemClassLoader.java b/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
index cf6bb4d..60942f5 100644
--- a/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
@@ -39,7 +39,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
-public class MemClassLoader extends ClassLoader implements AutoCloseable, ResourceLoader {
+public class MemClassLoader extends ClassLoader implements ResourceLoader, SolrClassLoader {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private boolean allJarsLoaded = false;
   private final SolrResourceLoader parentLoader;
@@ -53,6 +53,16 @@ public class MemClassLoader extends ClassLoader implements AutoCloseable, Resour
     this.libs = libs;
   }
 
+  @Override
+  public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
+    return null;
+  }
+
+  @Override
+  public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
+    return null;
+  }
+
   synchronized void loadRemoteJars() {
     if (allJarsLoaded) return;
     int count = 0;
@@ -149,7 +159,7 @@ public class MemClassLoader extends ClassLoader implements AutoCloseable, Resour
   }
 
   @Override
-  public void close() throws Exception {
+  public void close() {
     for (PluginBag.RuntimeLib lib : libs) {
       try {
         lib.close();
diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java
index b26b987..708910b 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginBag.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java
@@ -34,7 +34,6 @@ import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
-import org.apache.lucene.analysis.util.ResourceLoader;
 import org.apache.lucene.analysis.util.ResourceLoaderAware;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
@@ -144,7 +143,7 @@ public class PluginBag<T> implements AutoCloseable {
         PackagePluginHolder<T> holder = new PackagePluginHolder<>(info, core, meta);
         return holder;
       } else {
-        T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.getCleanTag(), null, core.getResourceLoader(info.pkgName));
+        T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.getCleanTag(), null, core.getSolrClassLoader(info.pkgName));
         initInstance(inst, info);
         return new PluginHolder<>(info, inst);
       }
@@ -403,11 +402,11 @@ public class PluginBag<T> implements AutoCloseable {
     private final SolrConfig.SolrPluginInfo pluginMeta;
     protected SolrException solrException;
     private final SolrCore core;
-    protected ResourceLoader resourceLoader;
+    protected SolrClassLoader resourceLoader;
     private final boolean isRuntimeLib;
 
 
-    LazyPluginHolder(SolrConfig.SolrPluginInfo pluginMeta, PluginInfo pluginInfo, SolrCore core, ResourceLoader loader, boolean isRuntimeLib) {
+    LazyPluginHolder(SolrConfig.SolrPluginInfo pluginMeta, PluginInfo pluginInfo, SolrCore core, SolrClassLoader loader, boolean isRuntimeLib) {
       super(pluginInfo);
       this.pluginMeta = pluginMeta;
       this.isRuntimeLib = isRuntimeLib;
diff --git a/solr/core/src/java/org/apache/solr/core/PluginLoader.java b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
similarity index 93%
rename from solr/core/src/java/org/apache/solr/core/PluginLoader.java
rename to solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
index ef0bd94..b260e07 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
@@ -17,10 +17,12 @@
 
 package org.apache.solr.core;
 
+import java.io.Closeable;
+
 /**A generic interface to load classes
  *
  */
-public interface PluginLoader {
+public interface SolrClassLoader extends Closeable {
 
   <T> T newInstance(String cname, Class<T> expectedType, String... subpackages);
 
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 284bf66..b1c38ba 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -63,7 +63,6 @@ import com.codahale.metrics.Timer;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.MapMaker;
 import org.apache.commons.io.FileUtils;
-import org.apache.lucene.analysis.util.ResourceLoader;
 import org.apache.lucene.codecs.Codec;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexDeletionPolicy;
@@ -288,7 +287,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   /** Gets the SolrResourceLoader for a given package
    * @param pkg The package name
    */
-  public SolrResourceLoader getResourceLoader(String pkg) {
+  public SolrClassLoader getSolrClassLoader(String pkg) {
     if (pkg == null) {
       return resourceLoader;
     }
@@ -819,7 +818,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
    * @return the desired instance
    * @throws SolrException if the object could not be instantiated
    */
-  public static <T> T createInstance(String className, Class<T> cast, String msg, SolrCore core, ResourceLoader resourceLoader) {
+  public static <T> T createInstance(String className, Class<T> cast, String msg, SolrCore core, SolrClassLoader resourceLoader) {
     Class<? extends T> clazz = null;
     if (msg == null) msg = "SolrCore Object";
     try {
@@ -879,7 +878,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
   public <T extends Object> T createInitInstance(PluginInfo info, Class<T> cast, String msg, String defClassName) {
     if (info == null) return null;
-    T o = createInstance(info.className == null ? defClassName : info.className, cast, msg, this, getResourceLoader(info.pkgName));
+    T o = createInstance(info.className == null ? defClassName : info.className, cast, msg, this, getSolrClassLoader(info.pkgName));
     if (o instanceof PluginInfoInitialized) {
       ((PluginInfoInitialized) o).init(info);
     } else if (o instanceof NamedListInitializedPlugin) {
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index 46e2ecf..2ad001b 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -20,7 +20,6 @@ import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.naming.NoInitialContextException;
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -83,7 +82,7 @@ import org.slf4j.LoggerFactory;
 /**
  * @since solr 1.3
  */
-public class SolrResourceLoader implements ResourceLoader, PluginLoader, Closeable {
+public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   static final String project = "solr";
@@ -190,6 +189,11 @@ public class SolrResourceLoader implements ResourceLoader, PluginLoader, Closeab
     }
     this.classLoader = URLClassLoader.newInstance(new URL[0], parent);
 
+    initSPI();
+    this.coreProperties = coreProperties;
+  }
+
+  protected void initSPI() {
     /*
      * Skip the lib subdirectory when we are loading from the solr home.
      * Otherwise load it, so core lib directories still get loaded.
@@ -207,7 +211,6 @@ public class SolrResourceLoader implements ResourceLoader, PluginLoader, Closeab
         reloadLuceneSPI();
       }
     }
-    this.coreProperties = coreProperties;
   }
 
   /**
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index 09f2778..fe97744 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -66,6 +66,7 @@ import org.apache.solr.core.ConfigOverlay;
 import org.apache.solr.core.PluginBag;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.RequestParams;
+import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
@@ -593,9 +594,9 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
         //this is not dynamically loaded so we can verify the class right away
         try {
           if(expected == Expressible.class) {
-            SolrResourceLoader resourceLoader = info.pkgName == null ?
+            SolrClassLoader resourceLoader = info.pkgName == null ?
                 req.getCore().getResourceLoader() :
-                req.getCore().getResourceLoader(info.pkgName);
+                req.getCore().getSolrClassLoader(info.pkgName);
             resourceLoader.findClass(info.className, expected);
           } else {
             req.getCore().createInitInstance(info, expected, clz, "");
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
index b7a88d1..c9ef000 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
@@ -37,6 +37,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.slf4j.Logger;
@@ -234,7 +235,7 @@ public class PackageLoader implements Closeable {
 
     public class Version implements MapWriter, Closeable {
       private final Package parent;
-      private SolrResourceLoader loader;
+      private SolrClassLoader loader;
 
       private final PackageAPI.PkgVersion version;
 
@@ -263,7 +264,12 @@ public class PackageLoader implements Closeable {
               "PACKAGE_LOADER: " + parent.name() + ":" + version,
               paths,
               coreContainer.getResourceLoader().getInstancePath(),
-              coreContainer.getResourceLoader().getClassLoader());
+              coreContainer.getResourceLoader().getClassLoader()){
+            @Override
+            protected void initSPI() {
+              //no op
+            }
+          };
         } catch (MalformedURLException e) {
           log.error("Could not load classloader ", e);
         }
@@ -277,7 +283,7 @@ public class PackageLoader implements Closeable {
         return Collections.unmodifiableList(version.files);
       }
 
-      public SolrResourceLoader getLoader() {
+      public SolrClassLoader getLoader() {
         return loader;
       }
 
diff --git a/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java b/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
index 0511830..c0f82ee 100644
--- a/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
+++ b/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
@@ -121,7 +121,7 @@ public class CurrencyFieldType extends FieldType implements SchemaAware, Resourc
     }
     try {
       Class<? extends ExchangeRateProvider> c
-          = schema.getPluginLoader().findClass(exchangeRateProviderClass, ExchangeRateProvider.class);
+          = schema.getSolrClassLoader().findClass(exchangeRateProviderClass, ExchangeRateProvider.class);
       provider = c.getConstructor().newInstance();
       provider.init(args);
     } catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
index 89c6ff2..af72660 100644
--- a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
@@ -34,7 +34,7 @@ import org.apache.lucene.analysis.util.TokenizerFactory;
 import org.apache.lucene.util.Version;
 import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.common.SolrException;
-import org.apache.solr.core.PluginLoader;
+import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.util.DOMUtil;
 import org.apache.solr.util.plugin.AbstractPluginLoader;
@@ -78,7 +78,7 @@ public final class FieldTypePluginLoader
 
 
   @Override
-  protected FieldType create( PluginLoader loader,
+  protected FieldType create( SolrClassLoader loader,
                               String name, 
                               String className,
                               Node node ) throws Exception {
@@ -191,7 +191,7 @@ public final class FieldTypePluginLoader
   //
   private Analyzer readAnalyzer(Node node) throws XPathExpressionException {
                                 
-    final PluginLoader loader = schema.getPluginLoader();
+    final SolrClassLoader loader = schema.getSolrClassLoader();
 
     // parent node used to be passed in as "fieldtype"
     // if (!fieldtype.hasChildNodes()) return null;
@@ -256,7 +256,7 @@ public final class FieldTypePluginLoader
       ("[schema.xml] analyzer/charFilter", CharFilterFactory.class, false, false) {
 
       @Override
-      protected CharFilterFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
+      protected CharFilterFactory create(SolrClassLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, CharFilterFactory.class.getSimpleName()).toString());
@@ -306,7 +306,7 @@ public final class FieldTypePluginLoader
       ("[schema.xml] analyzer/tokenizer", TokenizerFactory.class, false, false) {
       
       @Override
-      protected TokenizerFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
+      protected TokenizerFactory create(SolrClassLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenizerFactory.class.getSimpleName()).toString());
@@ -360,7 +360,7 @@ public final class FieldTypePluginLoader
       new AbstractPluginLoader<TokenFilterFactory>("[schema.xml] analyzer/filter", TokenFilterFactory.class, false, false)
     {
       @Override
-      protected TokenFilterFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
+      protected TokenFilterFactory create(SolrClassLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenFilterFactory.class.getSimpleName()).toString());
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 09f6341..ab8d49b 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -63,7 +63,7 @@ import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.core.PluginInfo;
-import org.apache.solr.core.PluginLoader;
+import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.core.XmlConfigFile;
@@ -144,11 +144,11 @@ public class IndexSchema implements Closeable {
    */
   protected final SolrResourceLoader loader;
 
-  /**Classes for all plugins should be loaded using this.
+  /** Classes for all plugins should be loaded using this.
    * If resources need to be loaded from packages, use the classloader of one of the classes
    * loaded from this package
    */
-  protected final PluginLoader pluginLoader;
+  protected final SolrClassLoader classLoader;
 
   protected Map<String,SchemaField> fields = new HashMap<>();
   protected Map<String,FieldType> fieldTypes = new HashMap<>();
@@ -200,21 +200,20 @@ public class IndexSchema implements Closeable {
     }
   }
 
-  public PluginLoader getPluginLoader(){
-    return pluginLoader;
+  public SolrClassLoader getSolrClassLoader(){
+    return classLoader;
   }
   protected IndexSchema(Version luceneVersion, SolrResourceLoader loader) {
     this.luceneVersion = Objects.requireNonNull(luceneVersion);
     this.loader = loader;
     if(loader.getCore() == null) {
-      this.pluginLoader = loader;
+      this.classLoader = loader;
     } else {
-      PackageAwarePluginLoader papl = new PackageAwarePluginLoader(loader.getCore());
-      this.pluginLoader = papl;
+      this.classLoader = new PackageAwarePluginLoader(loader.getCore());
     }
   }
 
-  public class PackageAwarePluginLoader implements PluginLoader, Closeable {
+  public class PackageAwarePluginLoader implements SolrClassLoader {
     final SolrCore core;
     private final List<PackageListeners.Listener> listeners = new ArrayList<>();
     Runnable reloadSchemaRunnable = () -> getCore().refreshSchema();
@@ -234,7 +233,7 @@ public class IndexSchema implements Closeable {
           (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
     }
 
-    private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrResourceLoader, String, T> fun) {
+    private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
       PluginInfo.ClassName className = new PluginInfo.ClassName(cname);
       if (className.pkg == null) {
         return  fun.apply(loader, className.klas);
@@ -280,7 +279,7 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
-      return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrResourceLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
+      return loadWithRightPackageLoader(cname, expectedType, (BiFunction<SolrClassLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
     }
 
     @Override
@@ -599,7 +598,7 @@ public class IndexSchema implements Closeable {
       final FieldTypePluginLoader typeLoader = new FieldTypePluginLoader(this, fieldTypes, schemaAware);
       expression = getFieldTypeXPathExpressions();
       NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
-      typeLoader.load(pluginLoader, nodes);
+      typeLoader.load(classLoader, nodes);
 
       // load the fields
       Map<String,Boolean> explicitRequiredProp = loadFields(document, xpath);
@@ -610,7 +609,7 @@ public class IndexSchema implements Closeable {
       if (similarityFactory == null) {
         final Class<?> simClass = SchemaSimilarityFactory.class;
         // use the loader to ensure proper SolrCoreAware handling
-        similarityFactory = pluginLoader.newInstance(simClass.getName(), SimilarityFactory.class);
+        similarityFactory = classLoader.newInstance(simClass.getName(), SimilarityFactory.class);
         similarityFactory.init(new ModifiableSolrParams());
       } else {
         isExplicitSimilarity = true;
@@ -1084,7 +1083,7 @@ public class IndexSchema implements Closeable {
     dynamicCopyFields = temp;
   }
 
-  static SimilarityFactory readSimilarity(PluginLoader loader, Node node) {
+  static SimilarityFactory readSimilarity(SolrClassLoader loader, Node node) {
     if (node==null) {
       return null;
     } else {
@@ -2096,8 +2095,8 @@ public class IndexSchema implements Closeable {
 
   @Override
   public void close() throws IOException {
-    if (pluginLoader instanceof PackageAwarePluginLoader) {
-      ((PackageAwarePluginLoader) pluginLoader).close();
+    if (classLoader instanceof PackageAwarePluginLoader) {
+      ((PackageAwarePluginLoader) classLoader).close();
     }
   }
 }
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 d65ece9..3256ff2 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
@@ -1272,7 +1272,7 @@ public final class ManagedIndexSchema extends IndexSchema {
     Map<String,FieldType> newFieldTypes = new HashMap<>();
     List<SchemaAware> schemaAwareList = new ArrayList<>();
     FieldTypePluginLoader typeLoader = new FieldTypePluginLoader(this, newFieldTypes, schemaAwareList);
-    typeLoader.loadSingle(pluginLoader, FieldTypeXmlAdapter.toNode(options));
+    typeLoader.loadSingle(classLoader, FieldTypeXmlAdapter.toNode(options));
     FieldType ft = newFieldTypes.get(typeName);
     if (!schemaAwareList.isEmpty())
       schemaAware.addAll(schemaAwareList);
diff --git a/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java b/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
index 9a5683f..e9979306 100644
--- a/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
+++ b/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
@@ -80,7 +80,7 @@ public class PreAnalyzedField extends TextField implements HasImplicitIndexAnaly
         parser = new SimplePreAnalyzedParser();
       } else {
         try {
-          Class<? extends PreAnalyzedParser> implClazz = schema.getPluginLoader().findClass(implName, PreAnalyzedParser.class);
+          Class<? extends PreAnalyzedParser> implClazz = schema.getSolrClassLoader().findClass(implName, PreAnalyzedParser.class);
           Constructor<?> c = implClazz.getConstructor(new Class<?>[0]);
           parser = (PreAnalyzedParser) c.newInstance(new Object[0]);
         } catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java b/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
index 5be8ab4..a1081b4 100644
--- a/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
@@ -23,7 +23,7 @@ import java.util.Objects;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.core.PluginLoader;
+import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.util.DOMUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -86,7 +86,7 @@ public abstract class AbstractPluginLoader<T>
    * @param node - the XML node defining this plugin
    */
   @SuppressWarnings("unchecked")
-  protected T create(PluginLoader loader, String name, String className, Node node ) throws Exception
+  protected T create(SolrClassLoader loader, String name, String className, Node node ) throws Exception
   {
     return loader.newInstance(className, pluginClassType, getDefaultPackages());
   }
@@ -135,7 +135,7 @@ public abstract class AbstractPluginLoader<T>
    * If a default element is defined, it will be returned from this function.
    * 
    */
-  public T load(PluginLoader loader, NodeList nodes )
+  public T load(SolrClassLoader loader, NodeList nodes )
   {
     List<PluginInitInfo> info = new ArrayList<>();
     T defaultPlugin = null;
@@ -223,7 +223,7 @@ public abstract class AbstractPluginLoader<T>
    * The created class for the plugin will be returned from this function.
    * 
    */
-  public T loadSingle(PluginLoader loader, Node node) {
+  public T loadSingle(SolrClassLoader loader, Node node) {
     List<PluginInitInfo> info = new ArrayList<>();
     T plugin = null;
 


[lucene] 03/21: added tests

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit eacbc1c10c6c02d7f12e76a55cda0a3d17e9a3fe
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 26 16:38:04 2019 +1100

    added tests
---
 .../apache/solr/schema/FieldTypePluginLoader.java  |   6 +-
 .../java/org/apache/solr/schema/IndexSchema.java   |  20 ++--
 .../test-files/runtimecode/schema-plugins.jar.bin  | Bin 0 -> 6814 bytes
 solr/core/src/test-files/runtimecode/sig.txt       |  10 +-
 .../src/test/org/apache/solr/pkg/TestPackages.java | 114 ++++++++++++++++++---
 5 files changed, 121 insertions(+), 29 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
index b72b835..89c6ff2 100644
--- a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
@@ -36,7 +36,6 @@ import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.core.PluginLoader;
 import org.apache.solr.core.SolrConfig;
-import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.DOMUtil;
 import org.apache.solr.util.plugin.AbstractPluginLoader;
 import org.slf4j.Logger;
@@ -192,8 +191,7 @@ public final class FieldTypePluginLoader
   //
   private Analyzer readAnalyzer(Node node) throws XPathExpressionException {
                                 
-    final SolrResourceLoader loader = schema.getResourceLoader();
-    final PluginLoader pluginLoader = schema.getPluginLoader();
+    final PluginLoader loader = schema.getPluginLoader();
 
     // parent node used to be passed in as "fieldtype"
     // if (!fieldtype.hasChildNodes()) return null;
@@ -228,7 +226,7 @@ public final class FieldTypePluginLoader
 
       try {
         // No need to be core-aware as Analyzers are not in the core-aware list
-        final Class<? extends Analyzer> clazz =  pluginLoader.findClass(analyzerName, Analyzer.class);
+        final Class<? extends Analyzer> clazz =  loader.findClass(analyzerName, Analyzer.class);
         Analyzer analyzer = clazz.getConstructor().newInstance();
 
         final String matchVersionStr = DOMUtil.getAttr(attrs, LUCENE_MATCH_VERSION_PARAM);
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 407c4d1..24f7a64 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -39,6 +39,7 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -218,18 +219,21 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
-      return getIt(cname, expectedType, pkgloader -> pkgloader.newInstance(cname, expectedType, subpackages));
+      return getIt(cname, expectedType,
+          (pkgloader, name) -> {
+            return pkgloader.newInstance(name, expectedType, subpackages);
+          });
     }
 
-    private <T> T getIt(String cname, Class expectedType, Function<SolrResourceLoader, T> fun) {
+    private <T> T getIt(String cname, Class expectedType, BiFunction<SolrResourceLoader, String, T> fun) {
       PluginInfo.ClassName className = new PluginInfo.ClassName(cname);
       if (className.pkg == null) {
-        return  fun.apply(loader);
+        return  fun.apply(loader, className.klas);
       } else {
         SolrResourceLoader pkgloader = core.getResourceLoader(className.pkg);
-        T inst = fun.apply(pkgloader);
+        T inst = fun.apply(pkgloader,className.klas);
         PackageListeners.Listener listener = new PackageListeners.Listener() {
-          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
+          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", className.klas));
 
           @Override
           public String packageName() {
@@ -260,12 +264,12 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
-      return getIt(cname, expectedType, (Function<SolrResourceLoader, Class<? extends T>>) loader -> loader.findClass(cname, expectedType));
+      return getIt(cname, expectedType, (BiFunction<SolrResourceLoader, String ,Class<? extends T>>) (loader, name) -> loader.findClass(name, expectedType));
     }
 
     @Override
     public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
-      return getIt(cName, expectedType, loader -> loader.newInstance(cName, expectedType, subPackages, params, args));
+      return getIt(cName, expectedType, (pkgloader, name) -> loader.newInstance(name, expectedType, subPackages, params, args));
     }
 
 
@@ -579,7 +583,7 @@ public class IndexSchema implements Closeable {
       final FieldTypePluginLoader typeLoader = new FieldTypePluginLoader(this, fieldTypes, schemaAware);
       expression = getFieldTypeXPathExpressions();
       NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
-      typeLoader.load(loader, nodes);
+      typeLoader.load(pluginLoader, nodes);
 
       // load the fields
       Map<String,Boolean> explicitRequiredProp = loadFields(document, xpath);
diff --git a/solr/core/src/test-files/runtimecode/schema-plugins.jar.bin b/solr/core/src/test-files/runtimecode/schema-plugins.jar.bin
new file mode 100644
index 0000000..4effbba
Binary files /dev/null and b/solr/core/src/test-files/runtimecode/schema-plugins.jar.bin differ
diff --git a/solr/core/src/test-files/runtimecode/sig.txt b/solr/core/src/test-files/runtimecode/sig.txt
index 74bb942..b32204e 100644
--- a/solr/core/src/test-files/runtimecode/sig.txt
+++ b/solr/core/src/test-files/runtimecode/sig.txt
@@ -65,10 +65,14 @@ openssl dgst -sha1 -sign ../cryptokeys/priv_key512.pem testurp_v2.jar.bin | open
 
 P/ptFXRvQMd4oKPvadSpd+A9ffwY3gcex5GVFVRy3df0/OF8XT5my8rQz7FZva+2ORbWxdXS8NKwNrbPVHLGXw==
 
-openssl dgst -sha1 -sign ../cryptokeys/priv_key512.pem expressible.jar.bin | openssl enc -base64 | openssl enc -base64 | tr -d \\n | sed
+openssl dgst -sha1 -sign ../cryptokeys/priv_key512.pem expressible.jar.bin | openssl enc -base64 | tr -d \\n | sed
 
 ZOT11arAiPmPZYOHzqodiNnxO9pRyRozWZEBX8XGjU1/HJptFnZK+DI7eXnUtbNaMcbXE2Ze8hh4M/eGyhY8BQ==
 
+openssl dgst -sha1 -sign ../cryptokeys/priv_key512.pem schema-plugins.jar.bin | openssl enc -base64 | tr -d \\n | sed
+
+iSRhrogDyt9P1htmSf/krh1kx9oty3TYyWm4GKHQGlb8a+X4tKCe9kKk+3tGs+bU9zq5JBZ5txNXsn96aZem5A==
+
 ====================sha512====================
 
 openssl dgst -sha512 runtimelibs.jar.bin
@@ -104,6 +108,10 @@ openssl dgst -sha512 expressible.jar.bin
 
 3474a1414c8329c71ef5db2d3eb6e870363bdd7224a836aab561dccf5e8bcee4974ac799e72398c7e0b0c01972bab1c7454c8a4e791a8865bb676c0440627388
 
+openssl dgst -sha512 schema-plugins.jar.bin
+
+9299d8d5f8b358b66f113a0a91a0f55db09a41419872cb56e6e4ee402645487b75b17ec515f8035352e7fdcfac9e2e861f371d1e601869859384807b19abc2fb
+
 =============sha256============================
 
 openssl dgst -sha256 runtimelibs.jar.bin
diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
index d37fdf4..fe46ef1 100644
--- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
+++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
@@ -28,6 +28,7 @@ import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrResponse;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.impl.BaseHttpSolrClient;
@@ -39,6 +40,7 @@ import org.apache.solr.client.solrj.request.UpdateRequest;
 import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.client.solrj.request.beans.Package;
 import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.SolrResponseBase;
 import org.apache.solr.client.solrj.util.ClientUtils;
 import org.apache.solr.cloud.ConfigRequest;
 import org.apache.solr.cloud.MiniSolrCloudCluster;
@@ -46,6 +48,7 @@ import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.MapWriterMap;
 import org.apache.solr.common.NavigableObject;
 import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
@@ -78,7 +81,101 @@ public class TestPackages extends SolrCloudTestCase {
   public void teardown() {
     System.clearProperty("enable.packages");
   }
-  
+
+
+  public void testSchemaPlugins() throws Exception {
+    String COLLECTION_NAME = "testSchemaLoadingColl";
+    System.setProperty("managed.schema.mutable", "true");
+
+
+    MiniSolrCloudCluster cluster =
+        configureCluster(4)
+            .withJettyConfig(jetty -> jetty.enableV2(true))
+            .addConfig("conf", configset("cloud-managed"))
+            .configure();
+    try {
+      String FILE1 = "/schemapkg/schema-plugins.jar";
+      byte[] derFile = readFile("cryptokeys/pub_key512.der");
+      cluster.getZkClient().makePath("/keys/exe", true);
+      cluster.getZkClient().create("/keys/exe/pub_key512.der", derFile, CreateMode.PERSISTENT, true);
+      postFileAndWait(cluster, "runtimecode/schema-plugins.jar.bin", FILE1,
+          "iSRhrogDyt9P1htmSf/krh1kx9oty3TYyWm4GKHQGlb8a+X4tKCe9kKk+3tGs+bU9zq5JBZ5txNXsn96aZem5A==");
+
+      Package.AddVersion add = new Package.AddVersion();
+      add.version = "1.0";
+      add.pkg = "schemapkg";
+      add.files = Arrays.asList(new String[]{FILE1});
+      V2Request req = new V2Request.Builder("/cluster/package")
+          .forceV2(true)
+          .withMethod(SolrRequest.METHOD.POST)
+          .withPayload(Collections.singletonMap("add", add))
+          .build();
+      req.process(cluster.getSolrClient());
+
+      TestDistribPackageStore.assertResponseValues(10,
+          () -> new V2Request.Builder("/cluster/package").
+              withMethod(SolrRequest.METHOD.GET)
+              .build().process(cluster.getSolrClient()),
+          Utils.makeMap(
+              ":result:packages:schemapkg[0]:version", "1.0",
+              ":result:packages:schemapkg[0]:files[0]", FILE1
+          ));
+
+      CollectionAdminRequest
+          .createCollection(COLLECTION_NAME, "conf", 2, 2)
+          .setMaxShardsPerNode(100)
+          .process(cluster.getSolrClient());
+      cluster.waitForActiveCollection(COLLECTION_NAME, 2, 4);
+
+      String addFieldTypeAnalyzerWithClass = "{\n" +
+          "'add-field-type' : {" +
+          "    'name' : 'myNewTextFieldWithAnalyzerClass',\n" +
+          "    'class':'schemapkg:my.pkg.MyTextField',\n" +
+          "    'analyzer' : {\n" +
+          "        'luceneMatchVersion':'5.0.0'" ;
+//          + ",\n" +
+//          "        'class':'schemapkg:my.pkg.MyWhitespaceAnalyzer'\n";
+      String charFilters =
+          "        'charFilters' : [{\n" +
+              "            'class':'schemapkg:my.pkg.MyPatternReplaceCharFilterFactory',\n" +
+              "            'replacement':'$1$1',\n" +
+              "            'pattern':'([a-zA-Z])\\\\\\\\1+'\n" +
+              "        }],\n";
+      String tokenizer =
+          "        'tokenizer' : { 'class':'schemapkg:my.pkg.MyWhitespaceTokenizerFactory' },\n";
+      String filters =
+          "        'filters' : [{ 'class':'solr.ASCIIFoldingFilterFactory' }]\n";
+      String suffix = "    }\n" +
+          "}}";
+      cluster.getSolrClient().request(new SolrRequest(SolrRequest.METHOD.POST, "/schema") {
+
+        @Override
+        public RequestWriter.ContentWriter getContentWriter(String expectedType) {
+          return new RequestWriter.StringPayloadContentWriter(addFieldTypeAnalyzerWithClass + ',' + charFilters + tokenizer + filters + suffix, CommonParams.JSON_MIME);
+        }
+
+        @Override
+        public SolrParams getParams() {
+          return null;
+        }
+
+        @Override
+        public String getCollection() {
+          return COLLECTION_NAME;
+        }
+
+        @Override
+        public SolrResponse createResponse(SolrClient client) {
+          return new SolrResponseBase();
+        }
+      });
+
+
+    } finally {
+      cluster.shutdown();
+    }
+
+  }
   @Test
   public void testPluginLoading() throws Exception {
     MiniSolrCloudCluster cluster =
@@ -387,21 +484,6 @@ public class TestPackages extends SolrCloudTestCase {
     }
 
   }
-   /* new V2Request.Builder("/c/"+COLLECTIONORALIAS+"/config").withMethod(SolrRequest.METHOD.POST)
-        .withPayload("{add-expressible: {name: mincopy , class: org.apache.solr.client.solrj.io.stream.metrics.MinCopyMetric}}")
-    .build().process(cluster.getSolrClient());
-
-  ModifiableSolrParams _params = new ModifiableSolrParams();
-  QueryRequest query = new QueryRequest(new MapSolrParams("action","plugins", "collection", COLLECTIONORALIAS, "wt", "javabin"));
-    query.setPath("/stream");
-  NamedList<Object> rsp = cluster.getSolrClient().request(query);
-  assertEquals("org.apache.solr.client.solrj.io.stream.metrics.MinCopyMetric", rsp._getStr("/plugins/mincopy", null));
-  _params = new ModifiableSolrParams();
-  query = new QueryRequest(new MapSolrParams("componentName","mincopy", "meta" ,"true", "collection", COLLECTIONORALIAS, "wt", "javabin"));
-    query.setPath("/config/expressible");
-  rsp = cluster.getSolrClient().request(query);
-
-    System.out.println();*/
 
   private void executeReq(String uri, JettySolrRunner jetty, Utils.InputStreamConsumer parser, Map expected) throws Exception {
     try(HttpSolrClient client = (HttpSolrClient) jetty.newClient()){


[lucene] 08/21: use final variable

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 3f47d8ba0f4e8e55d34ba4b1763a513043ffc0bd
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 11:50:11 2019 +1100

    use final variable
---
 solr/core/src/java/org/apache/solr/core/ConfigSet.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/solr/core/src/java/org/apache/solr/core/ConfigSet.java b/solr/core/src/java/org/apache/solr/core/ConfigSet.java
index bfd5867..4154d49 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigSet.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigSet.java
@@ -30,7 +30,7 @@ public class ConfigSet {
 
   private final SolrConfig solrconfig;
 
-  private volatile Supplier<IndexSchema> indexSchemaSupplier;
+  private final Supplier<IndexSchema> indexSchemaSupplier;
 
   private final NamedList properties;
 


[lucene] 04/21: formatting

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit a7947ae106d92c2ffec64dfd5134738ed3e509d3
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 26 16:38:54 2019 +1100

    formatting
---
 solr/core/src/java/org/apache/solr/schema/IndexSchema.java | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

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 24f7a64..1c51581 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -220,9 +220,7 @@ public class IndexSchema implements Closeable {
     @Override
     public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
       return getIt(cname, expectedType,
-          (pkgloader, name) -> {
-            return pkgloader.newInstance(name, expectedType, subpackages);
-          });
+          (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
     }
 
     private <T> T getIt(String cname, Class expectedType, BiFunction<SolrResourceLoader, String, T> fun) {


[lucene] 19/21: test failures fixed

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 455a23a13d9153a5cbc631218170265d1a48bc86
Author: noble <no...@apache.org>
AuthorDate: Sun Dec 29 22:54:29 2019 +1100

    test failures fixed
---
 .../src/java/org/apache/solr/core/SolrCore.java    | 26 +++++++++++------
 .../org/apache/solr/handler/SchemaHandler.java     |  2 +-
 .../org/apache/solr/handler/SolrConfigHandler.java |  9 ++----
 .../java/org/apache/solr/pkg/PackageListeners.java | 33 +++++++---------------
 4 files changed, 32 insertions(+), 38 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index b1c38ba..2af1421 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -969,7 +969,14 @@ public final class SolrCore implements SolrInfoBean, Closeable {
       log.info("[{}] Opening new SolrCore at [{}], dataDir=[{}]", logid, resourceLoader.getInstancePath(),
           this.dataDir);
 
-      IndexSchema schema = schemaSupplier.get();
+      IndexSchema schema = null;
+      try {
+        schema = schemaSupplier.get();
+      } catch (SolrException se){
+        throw se;
+      } catch (Exception e) {
+        throw new SolrException ( ErrorCode.SERVER_ERROR, "could not create schema", e);
+      }
       checkVersionFieldExistsInSchema(schema, coreDescriptor);
 
       // initialize core metrics
@@ -1567,6 +1574,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     log.info("{} CLOSING SolrCore {}", logid, this);
 
     ExecutorUtil.shutdownAndAwaitTermination(coreAsyncTaskExecutor);
+    closeWhileHandlingException(schema);
 
     // stop reporting metrics
     try {
@@ -1677,13 +1685,15 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     }
 
     // Close the snapshots meta-data directory.
-    Directory snapshotsDir = snapshotMgr.getSnapshotsDir();
-    try {
-      this.directoryFactory.release(snapshotsDir);
-    } catch (Throwable e) {
-      SolrException.log(log, e);
-      if (e instanceof Error) {
-        throw (Error) e;
+    if(snapshotMgr !=null) {
+      Directory snapshotsDir = snapshotMgr.getSnapshotsDir();
+      try {
+        this.directoryFactory.release(snapshotsDir);
+      } catch (Throwable e) {
+        SolrException.log(log, e);
+        if (e instanceof Error) {
+          throw (Error) e;
+        }
       }
     }
 
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index b33629b..2297aa8 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -211,7 +211,7 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
    *
    */
   private  void insertPackageInfo(Object o, SolrQueryRequest req) {
-    if(!req.getParams().getBool("meta")) return;
+    if(!req.getParams().getBool("meta",false)) return;
     if (o instanceof List) {
       List l = (List) o;
       for (Object o1 : l) {
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index fe97744..4c1612c 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -70,7 +70,6 @@ import org.apache.solr.core.SolrClassLoader;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
@@ -253,18 +252,16 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
                 if (req.getParams().getBool("meta", false)) {
                   // meta=true is asking for the package info of the plugin
                   // We go through all the listeners and see if there is one registered for this plugin
-                  List<PackageListeners.Listener> listeners = req.getCore().getPackageListeners().getListeners();
-                  for (PackageListeners.Listener listener :
-                      listeners) {
+                  req.getCore().getPackageListeners().forEachListener(listener -> {
                     PluginInfo info = listener.pluginInfo();
-                    if(info == null) continue;
+                    if(info == null) return;
                     if (info.type.equals(parts.get(1)) && info.name.equals(componentName)) {
                       if (o instanceof Map) {
                         Map m1 = (Map) o;
                         m1.put("_packageinfo_", listener.getPackageVersion());
                       }
                     }
-                  }
+                  });
                 }
               }
             }
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index 45baa04..87507a4 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -20,12 +20,11 @@ package org.apache.solr.pkg;
 import java.lang.invoke.MethodHandles;
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Consumer;
 
 import org.apache.solr.core.PluginInfo;
@@ -44,9 +43,9 @@ public class PackageListeners {
     this.core = core;
   }
 
-  // this registry only keeps a weak reference because it does not want to
+  // this registry only keeps a soft reference because it does not want to
   // cause a memory leak if the listener forgets to unregister itself
-  private List<Reference<Listener>> listeners = new ArrayList<>();
+  private final List<Reference<Listener>> listeners = new CopyOnWriteArrayList<>();
 
   public synchronized void addListener(Listener listener) {
     listeners.add(new SoftReference<>(listener));
@@ -63,7 +62,6 @@ public class PackageListeners {
       }
 
     }
-
   }
 
   synchronized void packagesUpdated(List<PackageLoader.Package> pkgs) {
@@ -78,17 +76,15 @@ public class PackageListeners {
     }
   }
 
-  private synchronized void invokeListeners(PackageLoader.Package pkg) {
+  private void invokeListeners(PackageLoader.Package pkg) {
     Ctx ctx = new Ctx();
-
     try {
-      for (Reference<Listener> ref : listeners) {
-        Listener listener = ref.get();
-        if(listener == null) continue;
-        if (listener.packageName() == null || listener.packageName().equals(pkg.name())) {
+      forEachListener(listener -> {
+        if (listener.packageName() == null ||
+            listener.packageName().equals(pkg.name())) {
           listener.changed(pkg, ctx);
         }
-      }
+      });
     } finally {
       if(ctx.postProcessors != null){
         for (Runnable value : ctx.postProcessors.values()) {
@@ -98,22 +94,13 @@ public class PackageListeners {
     }
   }
 
-  public void forEachListener(Consumer<Listener> listenerConsumer){
-    listeners.stream()
-        .map(Reference::get)
-        .filter(Objects::nonNull)
-        .forEach(listenerConsumer);
-  }
-
-  public List<Listener> getListeners() {
-    List<Listener> result = new ArrayList<>();
+  public synchronized void forEachListener(Consumer<Listener> listenerConsumer) {
     for (Reference<Listener> ref : listeners) {
       Listener l = ref.get();
       if (l != null) {
-        result.add(l);
+        listenerConsumer.accept(l);
       }
     }
-    return result;
   }
 
 


[lucene] 14/21: fixed SolrCOreAware and ResourceLoaderAware bugs

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit e501ef59ec0f1a21193eead845c773d6307d3409
Author: noble <no...@apache.org>
AuthorDate: Sat Dec 28 01:16:31 2019 +1100

    fixed SolrCOreAware and ResourceLoaderAware bugs
---
 .../src/java/org/apache/solr/core/PluginInfo.java  | 18 ++--
 .../java/org/apache/solr/core/SolrClassLoader.java |  7 +-
 .../org/apache/solr/core/SolrResourceLoader.java   | 24 +++++-
 .../org/apache/solr/handler/SchemaHandler.java     |  6 +-
 .../java/org/apache/solr/pkg/PackageLoader.java    | 14 ++++
 .../org/apache/solr/pkg/PackagePluginHolder.java   |  4 +
 .../java/org/apache/solr/schema/IndexSchema.java   | 97 ++++++++++++++--------
 7 files changed, 117 insertions(+), 53 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/PluginInfo.java b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
index cfef933..021fcea 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -41,7 +41,7 @@ import static org.apache.solr.schema.FieldType.CLASS_NAME;
  */
 public class PluginInfo implements MapSerializable {
   public final String name, className, type, pkgName;
-  public final ClassName cName;
+  public final ParsedClassName cName;
   public final NamedList initArgs;
   public final Map<String, String> attributes;
   public final List<PluginInfo> children;
@@ -52,7 +52,7 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(String type, Map<String, String> attrs, NamedList initArgs, List<PluginInfo> children) {
     this.type = type;
     this.name = attrs.get(NAME);
-    cName = new ClassName(attrs.get(CLASS_NAME));
+    cName = new ParsedClassName(attrs.get(CLASS_NAME));
     this.className = cName.klas;
     this.pkgName = cName.pkg;
     this.initArgs = initArgs;
@@ -65,13 +65,13 @@ public class PluginInfo implements MapSerializable {
    * This checks if it is a package name prefixed classname.
    */
 
-  public static class ClassName {
+  public static class ParsedClassName {
     public final String pkg;
     public final String klas;
-    private final String actual;
+    public final String original;
 
-    public ClassName(String name) {
-      this.actual = name;
+    public ParsedClassName(String name) {
+      this.original = name;
       String pkgName = null;
       String className = name;
       if (name != null) {
@@ -88,7 +88,7 @@ public class PluginInfo implements MapSerializable {
 
     @Override
     public String toString() {
-      return actual;
+      return original;
     }
   }
 
@@ -96,7 +96,7 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
     type = node.getNodeName();
     name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
-    cName = new ClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
+    cName = new ParsedClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
     className = cName.klas;
     pkgName = cName.pkg;
     initArgs = DOMUtil.childNodesToNamedList(node);
@@ -128,7 +128,7 @@ public class PluginInfo implements MapSerializable {
     }
     this.type = type;
     this.name = (String) m.get(NAME);
-    cName = new ClassName((String) m.get(CLASS_NAME));
+    cName = new ParsedClassName((String) m.get(CLASS_NAME));
     this.className = cName.klas;
     this.pkgName = cName.pkg;
     attributes = unmodifiableMap(m);
diff --git a/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
index b260e07..8995c80 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrClassLoader.java
@@ -19,10 +19,13 @@ package org.apache.solr.core;
 
 import java.io.Closeable;
 
-/**A generic interface to load classes
+import org.apache.lucene.analysis.util.ResourceLoader;
+
+/**
+ * A generic interface to load classes and resources. This helps us to avoid using {@link SolrResourceLoader} directly
  *
  */
-public interface SolrClassLoader extends Closeable {
+public interface SolrClassLoader extends Closeable, ResourceLoader {
 
   <T> T newInstance(String cname, Class<T> expectedType, String... subpackages);
 
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index 2ad001b..3927911 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -82,7 +82,7 @@ import org.slf4j.LoggerFactory;
 /**
  * @since solr 1.3
  */
-public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
+public class SolrResourceLoader implements SolrClassLoader {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   static final String project = "solr";
@@ -698,6 +698,12 @@ public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
           "Error instantiating class: '" + clazz.getName() + "'", e);
     }
 
+    registerForCallbacks(obj);
+
+    return obj;
+  }
+
+  protected <T> void registerForCallbacks(T obj) {
     if (!live) {
       if (obj instanceof SolrCoreAware) {
         assertAwareCompatibility(SolrCoreAware.class, obj);
@@ -712,8 +718,6 @@ public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
         infoMBeans.add((SolrInfoBean) obj);
       }
     }
-
-    return obj;
   }
 
 
@@ -742,6 +746,18 @@ public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
     live = true;
   }
 
+  public void registerSolrCoreAware(SolrCoreAware obj) {
+    assertAwareCompatibility(SolrCoreAware.class, obj);
+    if (live) {
+      //this core is already live
+      if (this.core != null) {
+        obj.inform(this.core);
+      }
+    } else {
+      waitingForCore.add(obj);
+    }
+  }
+
   /**
    * Tell all {@link ResourceLoaderAware} instances about the loader
    */
@@ -924,7 +940,7 @@ public class SolrResourceLoader implements ResourceLoader, SolrClassLoader {
   /**
    * Utility function to throw an exception if the class is invalid
    */
-  static void assertAwareCompatibility(Class aware, Object obj) {
+  public static void assertAwareCompatibility(Class aware, Object obj) {
     Class[] valid = awareCompatibility.get(aware);
     if (valid == null) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index f6a7c95..b33629b 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -226,12 +226,12 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
       Object v = nl.get("class");
       if (v instanceof String) {
         String klas = (String) v;
-        PluginInfo.ClassName className = new PluginInfo.ClassName(klas);
-        if (className.pkg != null) {
+        PluginInfo.ParsedClassName parsedClassName = new PluginInfo.ParsedClassName(klas);
+        if (parsedClassName.pkg != null) {
           req.getCore().getPackageListeners().forEachListener(listener -> {
             PluginInfo pluginInfo = listener.pluginInfo();
             if (pluginInfo == null) return;
-            if (Objects.equals(pluginInfo.cName.toString(), className.toString())) {
+            if (Objects.equals(pluginInfo.cName.toString(), parsedClassName.toString())) {
               nl.add("_packageinfo_", listener.getPackageVersion());
             }
           });
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
index c9ef000..178d3a5 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
@@ -34,6 +34,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import org.apache.lucene.analysis.util.ResourceLoaderAware;
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
@@ -269,6 +270,19 @@ public class PackageLoader implements Closeable {
             protected void initSPI() {
               //no op
             }
+
+            @Override
+            protected <T> void registerForCallbacks(T obj) {
+              if (obj instanceof ResourceLoaderAware) {
+                assertAwareCompatibility(ResourceLoaderAware.class, obj);
+                try {
+                  ((ResourceLoaderAware) obj).inform(this);
+                } catch (IOException e) {
+                  throw new RuntimeException(e);
+                }
+
+              }
+            }
           };
         } catch (MalformedURLException e) {
           log.error("Could not load classloader ", e);
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
index b15c524..1cdd104 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
@@ -24,6 +24,7 @@ import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.RequestParams;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.util.plugin.SolrCoreAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -120,6 +121,9 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
     Object instance = SolrCore.createInstance(pluginInfo.className,
         pluginMeta.clazz, pluginMeta.getCleanTag(), core, newest.getLoader());
     PluginBag.initInstance(instance, pluginInfo);
+    if (instance instanceof SolrCoreAware) {
+      core.getResourceLoader().registerSolrCoreAware((SolrCoreAware) instance);
+    }
     T old = inst;
     inst = (T) instance;
     if (old instanceof AutoCloseable) {
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 ab8d49b..8650b6d 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -21,6 +21,7 @@ import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import java.io.Closeable;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Writer;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
@@ -228,52 +229,38 @@ public class IndexSchema implements Closeable {
     }
 
     @Override
+    public InputStream openResource(String resource) throws IOException {
+      return loader.openResource(resource);
+    }
+
+    @Override
+    public <T> T newInstance(String cname, Class<T> expectedType) {
+      return loadWithRightPackageLoader(cname, expectedType,
+          (pkgloader, name) -> pkgloader.newInstance(name, expectedType));
+    }
+
+    @Override
     public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
       return loadWithRightPackageLoader(cname, expectedType,
           (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subpackages));
     }
 
     private <T> T loadWithRightPackageLoader(String cname, Class expectedType, BiFunction<SolrClassLoader, String, T> fun) {
-      PluginInfo.ClassName className = new PluginInfo.ClassName(cname);
-      if (className.pkg == null) {
-        return  fun.apply(loader, className.klas);
+      PluginInfo.ParsedClassName parsedClassName = new PluginInfo.ParsedClassName(cname);
+      if (parsedClassName.pkg == null) {
+        return  fun.apply(loader, parsedClassName.klas);
       } else {
-        PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(className.pkg);
+        PackageLoader.Package pkg = core.getCoreContainer().getPackageLoader().getPackage(parsedClassName.pkg);
         PackageLoader.Package.Version ver = PackagePluginHolder.getRightVersion(pkg, core);
-        T inst = fun.apply(ver.getLoader(),className.klas);
+        T result = fun.apply(ver.getLoader(), parsedClassName.klas);
+        if (result instanceof SolrCoreAware) {
+          loader.registerSolrCoreAware((SolrCoreAware) result);
+        }
         classNameVsPkg.put(cname, ver.getVersionInfo());
-        PackageListeners.Listener listener = new PackageListeners.Listener() {
-
-          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
-
-          @Override
-          public String packageName() {
-            return className.pkg;
-          }
-
-          @Override
-          public PluginInfo pluginInfo() {
-            return info;
-          }
-
-          @Override
-          public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
-            PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
-            if (rightVersion == null ) return;
-            PackageAPI.PkgVersion v = classNameVsPkg.get(className.toString());
-            if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
-            Runnable old = ctx.getPostProcessor(PackageAwarePluginLoader.class.getName());// just want to do one refresh for every package laod
-            if (old == null) ctx.addPostProcessor(PackageAwarePluginLoader.class.getName(), reloadSchemaRunnable);
-          }
-
-          @Override
-          public PackageAPI.PkgVersion getPackageVersion() {
-            return classNameVsPkg.get(cname);
-          }
-        };
+        PackageListeners.Listener listener = new SchemaPluginPackageListener(expectedType, cname, parsedClassName);
         listeners.add(listener);
         core.getPackageListeners().addListener(listener);
-        return inst;
+        return result;
       }
     }
 
@@ -296,6 +283,46 @@ public class IndexSchema implements Closeable {
       }
 
     }
+
+    private class SchemaPluginPackageListener implements PackageListeners.Listener {
+
+      private final Class expectedType;
+      private final String cname;
+      private final PluginInfo.ParsedClassName parsedClassName;
+      PluginInfo info;
+
+      public SchemaPluginPackageListener(Class expectedType, String cname, PluginInfo.ParsedClassName parsedClassName) {
+        this.expectedType = expectedType;
+        this.cname = cname;
+        this.parsedClassName = parsedClassName;
+        info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
+      }
+
+      @Override
+      public String packageName() {
+        return parsedClassName.pkg;
+      }
+
+      @Override
+      public PluginInfo pluginInfo() {
+        return info;
+      }
+
+      @Override
+      public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
+        PackageLoader.Package.Version rightVersion = PackagePluginHolder.getRightVersion(pkg, core);
+        if (rightVersion == null ) return;
+        PackageAPI.PkgVersion v = classNameVsPkg.get(parsedClassName.toString());
+        if(Objects.equals(v.version ,rightVersion.getVersionInfo().version)) return; //nothing has changed no need to reload
+        Runnable old = ctx.getPostProcessor(PackageAwarePluginLoader.class.getName());// just want to do one refresh for every package laod
+        if (old == null) ctx.addPostProcessor(PackageAwarePluginLoader.class.getName(), reloadSchemaRunnable);
+      }
+
+      @Override
+      public PackageAPI.PkgVersion getPackageVersion() {
+        return classNameVsPkg.get(cname);
+      }
+    }
   }
 
   /**


[lucene] 07/21: precommit errs

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 69b5a59a18df9474a1334740d25c48271c18bcdc
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 00:40:22 2019 +1100

    precommit errs
---
 solr/core/src/java/org/apache/solr/handler/SchemaHandler.java | 7 +++----
 solr/core/src/java/org/apache/solr/schema/IndexSchema.java    | 2 --
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index c625534..6c68eb9 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
@@ -41,7 +40,6 @@ import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
-import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.SolrQueryResponse;
@@ -227,8 +225,9 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
         PluginInfo.ClassName className = new PluginInfo.ClassName(klas);
         if (className.pkg != null) {
           req.getCore().getPackageListeners().forEachListener(listener -> {
-            if (listener.pluginInfo() == null) return;
-            if (Objects.equals(listener.pluginInfo().cName.toString(), className.toString())) {
+            PluginInfo pluginInfo = listener.pluginInfo();
+            if (pluginInfo == null) return;
+            if (Objects.equals(pluginInfo.cName.toString(), className.toString())) {
               nl.add("_packageinfo_", listener.getPackageVersion());
             }
           });
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 35ecdfd..dec7fc3 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -62,7 +62,6 @@ import org.apache.solr.common.util.Cache;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.PluginBag;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.PluginLoader;
 import org.apache.solr.core.SolrCore;
@@ -81,7 +80,6 @@ import org.apache.solr.util.ConcurrentLRUCache;
 import org.apache.solr.util.DOMUtil;
 import org.apache.solr.util.PayloadUtils;
 import org.apache.solr.util.plugin.SolrCoreAware;
-import org.codehaus.janino.Java;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;


[lucene] 05/21: bug fix

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 945606f1fd1cf4c13aa447128542fbfe8051129b
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 26 17:11:31 2019 +1100

    bug fix
---
 solr/core/src/java/org/apache/solr/schema/IndexSchema.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 1c51581..d4273a8 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -267,7 +267,7 @@ public class IndexSchema implements Closeable {
 
     @Override
     public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
-      return getIt(cName, expectedType, (pkgloader, name) -> loader.newInstance(name, expectedType, subPackages, params, args));
+      return getIt(cName, expectedType, (pkgloader, name) -> pkgloader.newInstance(name, expectedType, subPackages, params, args));
     }
 
 


[lucene] 16/21: more javadocs

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 16f6f4a4246ba3633d6403134b841b81e8ba11f1
Author: noble <no...@apache.org>
AuthorDate: Sun Dec 29 09:58:45 2019 +1100

    more javadocs
---
 .../java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java    | 9 +++++++--
 solr/core/src/java/org/apache/solr/pkg/PackageListeners.java     | 9 +++++----
 solr/core/src/java/org/apache/solr/schema/IndexSchema.java       | 3 ++-
 3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
index 2eb8913..5820439 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageAwareSolrClassLoader.java
@@ -48,9 +48,14 @@ public class PackageAwareSolrClassLoader implements SolrClassLoader {
   private final Runnable reloadRunnable;
 
 
-  public PackageAwareSolrClassLoader(SolrCore core, SolrResourceLoader loader, Runnable runnable) {
+  /**
+   *
+   * @param core The core where this belong to
+   * @param runnable run a task if somethingis modified, say reload schema or reload core, refresh cache or something else
+   */
+  public PackageAwareSolrClassLoader(SolrCore core,  Runnable runnable) {
     this.core = core;
-    this.loader = loader;
+    this.loader = core.getResourceLoader();
     this.reloadRunnable = runnable;
   }
 
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index 59c10d5..45baa04 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Consumer;
 
 import org.apache.solr.core.PluginInfo;
@@ -98,10 +99,10 @@ public class PackageListeners {
   }
 
   public void forEachListener(Consumer<Listener> listenerConsumer){
-    listeners.forEach(ref -> {
-      Listener l = ref.get();
-      if (l != null) listenerConsumer.accept(l);
-    });
+    listeners.stream()
+        .map(Reference::get)
+        .filter(Objects::nonNull)
+        .forEach(listenerConsumer);
   }
 
   public List<Listener> getListeners() {
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 74e20b3..2205cf8 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -202,7 +202,8 @@ public class IndexSchema implements Closeable {
     if(loader.getCore() == null) {
       this.classLoader = loader;
     } else {
-      this.classLoader = new PackageAwareSolrClassLoader(loader.getCore(), loader,  () ->  loader.getCore().refreshSchema());
+      SolrCore core = loader.getCore();
+      this.classLoader = new PackageAwareSolrClassLoader(loader.getCore(), core::refreshSchema);
     }
   }
 


[lucene] 12/21: removed SOP

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit ac95a578a8c81a7e97dcf820bebdcfc046d767e3
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 12:05:58 2019 +1100

    removed SOP
---
 solr/core/src/test/org/apache/solr/pkg/TestPackages.java | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
index 4a3ff7b..70ae783 100644
--- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
+++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
@@ -18,7 +18,6 @@
 package org.apache.solr.pkg;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collections;
@@ -53,7 +52,6 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.filestore.TestDistribPackageStore;
 import org.apache.solr.util.LogLevel;
@@ -537,8 +535,6 @@ public class TestPackages extends SolrCloudTestCase {
 
     GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET,path
         , params);
-    NamedList<Object> rsp = client.request(req);
-    System.out.println( Utils.writeJson(rsp, new StringWriter(), true).toString());
     TestDistribPackageStore.assertResponseValues(10,
         client,
         req, expected);


[lucene] 09/21: javadoc

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 25aec79b3bddd6eac5065a5562b9e3205b39469b
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 11:52:53 2019 +1100

    javadoc
---
 solr/core/src/java/org/apache/solr/handler/SchemaHandler.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index 6c68eb9..f6a7c95 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -206,6 +206,10 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware,
     }
   }
 
+  /**If a plugin is loaded from a package, the version of the package being used should be added
+   * to the response
+   *
+   */
   private  void insertPackageInfo(Object o, SolrQueryRequest req) {
     if(!req.getParams().getBool("meta")) return;
     if (o instanceof List) {


[lucene] 10/21: javadoc

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 97b1331c507bbd0d0dda4fac7cddae5c931ca61f
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 11:55:43 2019 +1100

    javadoc
---
 solr/core/src/java/org/apache/solr/pkg/PackageListeners.java | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index 3d13ad8..59c10d5 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -118,6 +118,12 @@ public class PackageListeners {
 
   public class Ctx {
     private Map<String, Runnable > postProcessors;
+
+    /**A post processor will be run after all the listeners are invoked. This is particularly helpful
+     * if a group of plugins need to be reloaded all at once.  The case in point is schema plugins.
+     * If there are multiple plugins loade from packages in a schema, we would like to reload it only once
+     *
+     */
     public void addPostProcessor(String name, Runnable runnable){
       if(postProcessors == null) postProcessors = new HashMap<>();
       postProcessors.put(name, runnable);


[lucene] 18/21: sync with master

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit b31996ce0aa6da8a31adfdc5e1e175768c45b486
Author: noble <no...@apache.org>
AuthorDate: Sun Dec 29 12:30:25 2019 +1100

    sync with master
---
 lucene/CHANGES.txt                                 |  12 +++
 .../apache/lucene/TestMergeSchedulerExternal.java  |  21 ++---
 .../lucene/index/TestConcurrentMergeScheduler.java |  16 +---
 .../lucene/index/TestDirectoryReaderReopen.java    |  15 ++-
 .../apache/lucene/index/TestIndexFileDeleter.java  |  26 +++---
 .../org/apache/lucene/index/TestIndexWriter.java   |  24 ++---
 .../apache/lucene/index/TestIndexWriterDelete.java |  26 ++----
 .../lucene/index/TestIndexWriterExceptions.java    | 104 +++++----------------
 .../lucene/index/TestIndexWriterOnDiskFull.java    |  17 ++--
 .../lucene/index/TestIndexWriterOnVMError.java     |  31 ++----
 .../apache/lucene/index/TestIndexWriterReader.java |  17 ++--
 .../lucene/index/TestIndexWriterWithThreads.java   |  38 ++------
 .../TestPersistentSnapshotDeletionPolicy.java      |   7 +-
 .../uhighlight/TestUnifiedHighlighterTermVec.java  |  12 +--
 .../lucene/index/BaseFieldInfoFormatTestCase.java  |  24 ++---
 .../index/BaseSegmentInfoFormatTestCase.java       |  24 ++---
 .../org/apache/lucene/util/LuceneTestCase.java     |  82 ++++++++++------
 .../apache/lucene/util/TestSecurityManager.java    |  75 ++++++---------
 solr/CHANGES.txt                                   |   4 +
 .../org/apache/solr/search/BoolQParserPlugin.java  |  14 ++-
 .../apache/solr/search/json/TestJsonRequest.java   |  80 +++++++++++++---
 solr/server/etc/security.policy                    |  15 +--
 solr/solr-ref-guide/src/other-parsers.adoc         |   2 +-
 23 files changed, 303 insertions(+), 383 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 442aefd..8001ad7 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -62,6 +62,12 @@ Improvements
   previously treated as beginning a line-ending comment (Satoshi Kato and Masaru Hasegawa via
   Michael Sokolov)
 
+* LUCENE-9109: Use StackWalker to implement TestSecurityManager's detection
+  of JVM exit (Uwe Schindler)
+
+* LUCENE-9110: Refactor stack analysis in tests to use generalized LuceneTestCase
+  methods that use StackWalker (Uwe Schindler)
+
 Bug fixes
 
 * LUCENE-8663: NRTCachingDirectory.slowFileExists may open a file while 
@@ -90,6 +96,12 @@ Improvements
 
 * LUCENE-9091: UnifiedHighlighter HTML escaping should only escape essentials (Nándor Mátravölgyi)
 
+* LUCENE-9109: Backport some changes from master (except StackWalker) to improve
+  TestSecurityManager (Uwe Schindler)
+
+* LUCENE-9110: Backport refactored stack analysis in tests to use generalized
+  LuceneTestCase methods (Uwe Schindler)
+
 Optimizations
 ---------------------
 (No changes)
diff --git a/lucene/core/src/test/org/apache/lucene/TestMergeSchedulerExternal.java b/lucene/core/src/test/org/apache/lucene/TestMergeSchedulerExternal.java
index ef82685..69fbc4d 100644
--- a/lucene/core/src/test/org/apache/lucene/TestMergeSchedulerExternal.java
+++ b/lucene/core/src/test/org/apache/lucene/TestMergeSchedulerExternal.java
@@ -30,8 +30,8 @@ import org.apache.lucene.index.ConcurrentMergeScheduler;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.LogMergePolicy;
-import org.apache.lucene.index.MergePolicy.OneMerge;
 import org.apache.lucene.index.MergePolicy;
+import org.apache.lucene.index.MergePolicy.OneMerge;
 import org.apache.lucene.index.MergeScheduler;
 import org.apache.lucene.index.MergeTrigger;
 import org.apache.lucene.store.ByteBuffersDirectory;
@@ -89,18 +89,15 @@ public class TestMergeSchedulerExternal extends LuceneTestCase {
   private static class FailOnlyOnMerge extends MockDirectoryWrapper.Failure {
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
-      StackTraceElement[] trace = new Exception().getStackTrace();
-      for (int i = 0; i < trace.length; i++) {
-        if ("doMerge".equals(trace[i].getMethodName())) {
-          IOException ioe = new IOException("now failing during merge");
-          StringWriter sw = new StringWriter();
-          PrintWriter pw = new PrintWriter(sw);
-          ioe.printStackTrace(pw);
-          if (infoStream.isEnabled("IW")) {
-            infoStream.message("IW", "TEST: now throw exc:\n" + sw.toString());
-          }
-          throw ioe;
+      if (callStackContainsAnyOf("doMerge")) {
+        IOException ioe = new IOException("now failing during merge");
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        ioe.printStackTrace(pw);
+        if (infoStream.isEnabled("IW")) {
+          infoStream.message("IW", "TEST: now throw exc:\n" + sw.toString());
         }
+        throw ioe;
       }
     }
   }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestConcurrentMergeScheduler.java b/lucene/core/src/test/org/apache/lucene/index/TestConcurrentMergeScheduler.java
index fad831f..4683a51 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestConcurrentMergeScheduler.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestConcurrentMergeScheduler.java
@@ -54,21 +54,7 @@ public class TestConcurrentMergeScheduler extends LuceneTestCase {
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
       if (doFail && isTestThread()) {
-        boolean isDoFlush = false;
-        boolean isClose = false;
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if (isDoFlush && isClose) {
-            break;
-          }
-          if ("flush".equals(trace[i].getMethodName())) {
-            isDoFlush = true;
-          }
-          if ("close".equals(trace[i].getMethodName())) {
-            isClose = true;
-          }
-        }
-        if (isDoFlush && !isClose && random().nextBoolean()) {
+        if (callStackContainsAnyOf("flush") && false == callStackContainsAnyOf("close") && random().nextBoolean()) {
           hitExc = true;
           throw new IOException(Thread.currentThread().getName() + ": now failing during flush");
         }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestDirectoryReaderReopen.java b/lucene/core/src/test/org/apache/lucene/index/TestDirectoryReaderReopen.java
index 7a7a160..2723f7f 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestDirectoryReaderReopen.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestDirectoryReaderReopen.java
@@ -659,16 +659,13 @@ public class TestDirectoryReaderReopen extends LuceneTestCase {
         }
         //System.out.println("failOn: ");
         //new Throwable().printStackTrace(System.out);
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if ("readLiveDocs".equals(trace[i].getMethodName())) {
-            if (VERBOSE) {
-              System.out.println("TEST: now fail; exc:");
-              new Throwable().printStackTrace(System.out);
-            }
-            failed = true;
-            throw new FakeIOException();
+        if (callStackContainsAnyOf("readLiveDocs")) {
+          if (VERBOSE) {
+            System.out.println("TEST: now fail; exc:");
+            new Throwable().printStackTrace(System.out);
           }
+          failed = true;
+          throw new FakeIOException();
         }
       }
     });
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java
index eedcfdb..d523b21 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java
@@ -17,9 +17,15 @@
 package org.apache.lucene.index;
 
 
-import java.io.*;
+import java.io.IOException;
 import java.nio.file.Path;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.lucene.analysis.MockAnalyzer;
@@ -414,12 +420,8 @@ public class TestIndexFileDeleter extends LuceneTestCase {
         @Override
         public void eval(MockDirectoryWrapper dir) throws IOException {
           if (doFailExc.get() && random().nextInt(4) == 1) {
-            Exception e = new Exception();
-            StackTraceElement stack[] = e.getStackTrace();
-            for (int i = 0; i < stack.length; i++) {
-              if (stack[i].getClassName().equals(IndexFileDeleter.class.getName()) && stack[i].getMethodName().equals("decRef")) {
-                throw new RuntimeException("fake fail");
-              }
+            if (callStackContains(IndexFileDeleter.class, "decRef")) {
+              throw new RuntimeException("fake fail");
             }
           }
         }
@@ -497,12 +499,8 @@ public class TestIndexFileDeleter extends LuceneTestCase {
           @Override
           public void eval(MockDirectoryWrapper dir) throws IOException {
             if (doFailExc.get() && random().nextInt(4) == 1) {
-              Exception e = new Exception();
-              StackTraceElement stack[] = e.getStackTrace();
-              for (int i = 0; i < stack.length; i++) {
-                if (stack[i].getClassName().equals(MockDirectoryWrapper.class.getName()) && stack[i].getMethodName().equals("deleteFile")) {
-                  throw new MockDirectoryWrapper.FakeIOException();
-                }
+              if (callStackContains(MockDirectoryWrapper.class, "deleteFile")) {
+                throw new MockDirectoryWrapper.FakeIOException();
               }
             }
           }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java
index 027ef69..dc70a63 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java
@@ -3048,13 +3048,8 @@ public class TestIndexWriter extends LuceneTestCase {
     dir.failOn(new MockDirectoryWrapper.Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if ("flush".equals(trace[i].getMethodName())
-              && "org.apache.lucene.index.DocumentsWriterPerThread".equals(trace[i].getClassName())) {
-            flushingThreads.add(Thread.currentThread().getName());
-            break;
-          }
+        if (callStackContains(DocumentsWriterPerThread.class, "flush")) {
+          flushingThreads.add(Thread.currentThread().getName());
         }
       }
     });
@@ -3384,15 +3379,12 @@ public class TestIndexWriter extends LuceneTestCase {
     try (Directory dir = new FilterDirectory(newDirectory()) {
       @Override
       public IndexOutput createOutput(String name, IOContext context) throws IOException {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if ("flush".equals(trace[i].getMethodName()) && DefaultIndexingChain.class.getName().equals(trace[i].getClassName())) {
-            try {
-              inFlush.countDown();
-              latch.await();
-            } catch (InterruptedException e) {
-              throw new AssertionError(e);
-            }
+        if (callStackContains(DefaultIndexingChain.class, "flush")) {
+          try {
+            inFlush.countDown();
+            latch.await();
+          } catch (InterruptedException e) {
+            throw new AssertionError(e);
           }
         }
         return super.createOutput(name, context);
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterDelete.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterDelete.java
index 4c9a4e0..aedccef 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterDelete.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterDelete.java
@@ -43,8 +43,8 @@ import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.MockDirectoryWrapper;
 import org.apache.lucene.util.IOUtils;
-import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
 import org.apache.lucene.util.TestUtil;
 import org.junit.Ignore;
 
@@ -731,15 +731,7 @@ public class TestIndexWriterDelete extends LuceneTestCase {
           }
           new Throwable().printStackTrace(System.out);
           if (sawMaybe && !failed) {
-            boolean seen = false;
-            StackTraceElement[] trace = new Exception().getStackTrace();
-            for (int i = 0; i < trace.length; i++) {
-              if ("applyDeletesAndUpdates".equals(trace[i].getMethodName()) ||
-                  "slowFileExists".equals(trace[i].getMethodName())) {
-                seen = true;
-                break;
-              }
-            }
+            boolean seen = callStackContainsAnyOf("applyDeletesAndUpdates", "slowFileExists");
             if (!seen) {
               // Only fail once we are no longer in applyDeletes
               failed = true;
@@ -751,16 +743,12 @@ public class TestIndexWriterDelete extends LuceneTestCase {
             }
           }
           if (!failed) {
-            StackTraceElement[] trace = new Exception().getStackTrace();
-            for (int i = 0; i < trace.length; i++) {
-              if ("applyDeletesAndUpdates".equals(trace[i].getMethodName())) {
-                if (VERBOSE) {
-                  System.out.println("TEST: mock failure: saw applyDeletes");
-                  new Throwable().printStackTrace(System.out);
-                }
-                sawMaybe = true;
-                break;
+            if (callStackContainsAnyOf("applyDeletesAndUpdates")) {
+              if (VERBOSE) {
+                System.out.println("TEST: mock failure: saw applyDeletes");
+                new Throwable().printStackTrace(System.out);
               }
+              sawMaybe = true;
             }
           }
         }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
index 0bfa1e1..b449764 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
@@ -567,19 +567,7 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
       if (doFail) {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        boolean sawFlush = false;
-        boolean sawFinishDocument = false;
-        for (int i = 0; i < trace.length; i++) {
-          if ("flush".equals(trace[i].getMethodName())) {
-            sawFlush = true;
-          }
-          if ("finishDocument".equals(trace[i].getMethodName())) {
-            sawFinishDocument = true;
-          }
-        }
-
-        if (sawFlush && sawFinishDocument == false && count++ >= 30) {
+        if (callStackContainsAnyOf("flush") && false == callStackContainsAnyOf("finishDocument") && count++ >= 30) {
           doFail = false;
           throw new IOException("now failing during flush");
         }
@@ -872,16 +860,14 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
       if (doFail) {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if (doFail && MockDirectoryWrapper.class.getName().equals(trace[i].getClassName()) && "sync".equals(trace[i].getMethodName())) {
-            didFail = true;
-            if (VERBOSE) {
-              System.out.println("TEST: now throw exc:");
-              new Throwable().printStackTrace(System.out);
-            }
-            throw new IOException("now failing on purpose during sync");
+        if (callStackContains(MockDirectoryWrapper.class, "sync")) {
+          didFail = true;
+          if (VERBOSE) {
+            System.out.println("TEST: now throw exc:");
+            new Throwable().printStackTrace(System.out);
           }
+          throw new IOException("now failing on purpose during sync");
+          
         }
       }
     }
@@ -949,28 +935,10 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
 
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
-      StackTraceElement[] trace = new Exception().getStackTrace();
-      boolean isCommit = false;
-      boolean isDelete = false;
-      boolean isSyncMetadata = false;
-      boolean isInGlobalFieldMap = false;
-      for (int i = 0; i < trace.length; i++) {
-        if (isCommit && isDelete && isInGlobalFieldMap && isSyncMetadata) {
-          break;
-        }
-        if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) {
-          isCommit = true;
-        }
-        if (MockDirectoryWrapper.class.getName().equals(trace[i].getClassName()) && "deleteFile".equals(trace[i].getMethodName())) {
-          isDelete = true;
-        }
-        if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && "writeGlobalFieldMap".equals(trace[i].getMethodName())) {
-          isInGlobalFieldMap = true;
-        }
-        if (MockDirectoryWrapper.class.getName().equals(trace[i].getClassName()) && "syncMetaData".equals(trace[i].getMethodName())) {
-          isSyncMetadata = true;
-        }
-      }
+      boolean isCommit = callStackContains(SegmentInfos.class, stage);
+      boolean isDelete = callStackContains(MockDirectoryWrapper.class, "deleteFile");
+      boolean isSyncMetadata = callStackContains(MockDirectoryWrapper.class, "syncMetaData");
+      boolean isInGlobalFieldMap = callStackContains(SegmentInfos.class, "writeGlobalFieldMap");
       if (isInGlobalFieldMap && dontFailDuringGlobalFieldMap) {
         isCommit = false;
       }
@@ -1384,17 +1352,7 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
 
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
-
-      StackTraceElement[] trace = new Exception().getStackTrace();
-      boolean fail = false;
-      for (int i = 0; i < trace.length; i++) {
-        if (TermVectorsConsumer.class.getName().equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) {
-          fail = true;
-          break;
-        }
-      }
-      
-      if (fail) {
+      if (callStackContains(TermVectorsConsumer.class, stage)) {
         throw new RuntimeException(EXC_MSG);
       }
     }
@@ -1726,11 +1684,8 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
     @Override
     public IndexInput openInput(String name, IOContext context) throws IOException {
       if (doFail && name.startsWith("segments_")) {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if ("readCommit".equals(trace[i].getMethodName()) || "readLatestCommit".equals(trace[i].getMethodName())) {
-            throw new UnsupportedOperationException("expected UOE");
-          }
+        if (callStackContainsAnyOf("readCommit", "readLatestCommit")) {
+          throw new UnsupportedOperationException("expected UOE");
         }
       }
       return super.openInput(name, context);
@@ -1946,17 +1901,7 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
           if (random().nextInt(10) != 0) {
             return;
           }
-          boolean maybeFail = false;
-          StackTraceElement[] trace = Thread.currentThread().getStackTrace();
-          
-          for (int i = 0; i < trace.length; i++) {
-            if ("rollbackInternal".equals(trace[i].getMethodName())) {
-              maybeFail = true;
-              break;
-            }
-          }
-          
-          if (maybeFail) {
+          if (callStackContainsAnyOf("rollbackInternal")) {
             if (VERBOSE) {
               System.out.println("TEST: now fail; thread=" + Thread.currentThread().getName() + " exc:");
               new Throwable().printStackTrace(System.out);
@@ -2019,17 +1964,14 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
             // Already failed
             return;
           }
-          StackTraceElement[] trace = Thread.currentThread().getStackTrace();
-          
-          for (int i = 0; i < trace.length; i++) {
-            if ("merge".equals(trace[i].getMethodName())) {
-              if (VERBOSE) {
-                System.out.println("TEST: now fail; thread=" + Thread.currentThread().getName() + " exc:");
-                new Throwable().printStackTrace(System.out);
-              }
-              didFail.set(true);
-              throw new FakeIOException();
+
+          if (callStackContainsAnyOf("merge")) {
+            if (VERBOSE) {
+              System.out.println("TEST: now fail; thread=" + Thread.currentThread().getName() + " exc:");
+              new Throwable().printStackTrace(System.out);
             }
+            didFail.set(true);
+            throw new FakeIOException();
           }
         }
       });
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnDiskFull.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnDiskFull.java
index cd97703..2c01212 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnDiskFull.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnDiskFull.java
@@ -478,16 +478,13 @@ public class TestIndexWriterOnDiskFull extends LuceneTestCase {
       if (!doFail) {
         return;
       }
-      StackTraceElement[] trace = new Exception().getStackTrace();
-      for (int i = 0; i < trace.length; i++) {
-        if (SegmentMerger.class.getName().equals(trace[i].getClassName()) && "mergeTerms".equals(trace[i].getMethodName()) && !didFail1) {
-          didFail1 = true;
-          throw new IOException("fake disk full during mergeTerms");
-        }
-        if (LiveDocsFormat.class.getName().equals(trace[i].getClassName()) && "writeLiveDocs".equals(trace[i].getMethodName()) && !didFail2) {
-          didFail2 = true;
-          throw new IOException("fake disk full while writing LiveDocs");
-        }
+      if (callStackContains(SegmentMerger.class, "mergeTerms") && !didFail1) {
+        didFail1 = true;
+        throw new IOException("fake disk full during mergeTerms");
+      }
+      if (callStackContains(LiveDocsFormat.class, "writeLiveDocs") && !didFail2) {
+        didFail2 = true;
+        throw new IOException("fake disk full while writing LiveDocs");
       }
     }
   }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnVMError.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnVMError.java
index 99f7d53..6aff1cc 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnVMError.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnVMError.java
@@ -39,8 +39,8 @@ import org.apache.lucene.document.SortedSetDocValuesField;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.document.TextField;
 import org.apache.lucene.store.AlreadyClosedException;
-import org.apache.lucene.store.MockDirectoryWrapper.Failure;
 import org.apache.lucene.store.MockDirectoryWrapper;
+import org.apache.lucene.store.MockDirectoryWrapper.Failure;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.IOUtils;
 import org.apache.lucene.util.LuceneTestCase;
@@ -238,14 +238,7 @@ public class TestIndexWriterOnVMError extends LuceneTestCase {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
         if (r.nextInt(3000) == 0) {
-          StackTraceElement stack[] = Thread.currentThread().getStackTrace();
-          boolean ok = false;
-          for (int i = 0; i < stack.length; i++) {
-            if (stack[i].getClassName().equals(IndexWriter.class.getName())) {
-              ok = true;
-            }
-          }
-          if (ok) {
+          if (callStackContains(IndexWriter.class)) {
             throw new OutOfMemoryError("Fake OutOfMemoryError");
           }
         }
@@ -259,14 +252,7 @@ public class TestIndexWriterOnVMError extends LuceneTestCase {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
         if (r.nextInt(3000) == 0) {
-          StackTraceElement stack[] = Thread.currentThread().getStackTrace();
-          boolean ok = false;
-          for (int i = 0; i < stack.length; i++) {
-            if (stack[i].getClassName().equals(IndexWriter.class.getName())) {
-              ok = true;
-            }
-          }
-          if (ok) {
+          if (callStackContains(IndexWriter.class)) {
             throw new UnknownError("Fake UnknownError");
           }
         }
@@ -281,16 +267,11 @@ public class TestIndexWriterOnVMError extends LuceneTestCase {
     doTest(new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        StackTraceElement stack[] = Thread.currentThread().getStackTrace();
-        boolean ok = false;
-        for (int i = 0; i < stack.length; i++) {
-          if (stack[i].getClassName().equals(IndexFileDeleter.class.getName()) && stack[i].getMethodName().equals("checkpoint")) {
-            ok = true;
+        if (r.nextInt(4) == 0) {
+          if (callStackContains(IndexFileDeleter.class, "checkpoint")) {
+            throw new OutOfMemoryError("Fake OutOfMemoryError");
           }
         }
-        if (ok && r.nextInt(4) == 0) {
-          throw new OutOfMemoryError("Fake OutOfMemoryError");
-        }
       }
     });
   }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java
index 5996d7e..2b4943d 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java
@@ -35,8 +35,8 @@ import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.lucene.store.ByteBuffersDirectory;
 import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.MockDirectoryWrapper.FakeIOException;
 import org.apache.lucene.store.MockDirectoryWrapper;
+import org.apache.lucene.store.MockDirectoryWrapper.FakeIOException;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.InfoStream;
@@ -1067,17 +1067,14 @@ public class TestIndexWriterReader extends LuceneTestCase {
     dir.failOn(new MockDirectoryWrapper.Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        StackTraceElement[] trace = new Exception().getStackTrace();
         if (shouldFail.get()) {
-          for (int i = 0; i < trace.length; i++) {
-            if ("getReadOnlyClone".equals(trace[i].getMethodName())) {
-              if (VERBOSE) {
-                System.out.println("TEST: now fail; exc:");
-                new Throwable().printStackTrace(System.out);
-              }
-              shouldFail.set(false);
-              throw new FakeIOException();
+          if (callStackContainsAnyOf("getReadOnlyClone")) {
+            if (VERBOSE) {
+              System.out.println("TEST: now fail; exc:");
+              new Throwable().printStackTrace(System.out);
             }
+            shouldFail.set(false);
+            throw new FakeIOException();
           }
         }
       }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterWithThreads.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterWithThreads.java
index 48e42bd..2b7c7ad 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterWithThreads.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterWithThreads.java
@@ -43,9 +43,9 @@ import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.LineFileDocs;
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.lucene.util.TestUtil;
 import org.apache.lucene.util.ThreadInterruptedException;
-import org.apache.lucene.util.LuceneTestCase.Slow;
 
 /**
  * MultiThreaded IndexWriter tests
@@ -407,26 +407,7 @@ public class TestIndexWriterWithThreads extends LuceneTestCase {
       dir.setAssertNoUnrefencedFilesOnClose(false);
 
       if (doFail) {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        boolean sawAbortOrFlushDoc = false;
-        boolean sawClose = false;
-        boolean sawMerge = false;
-        for (int i = 0; i < trace.length; i++) {
-          if (sawAbortOrFlushDoc && sawMerge && sawClose) {
-            break;
-          }
-          if ("abort".equals(trace[i].getMethodName()) ||
-              "finishDocument".equals(trace[i].getMethodName())) {
-            sawAbortOrFlushDoc = true;
-          }
-          if ("merge".equals(trace[i].getMethodName())) {
-            sawMerge = true;
-          }
-          if ("close".equals(trace[i].getMethodName())) {
-            sawClose = true;
-          }
-        }
-        if (sawAbortOrFlushDoc && !sawClose && !sawMerge) {
+        if (callStackContainsAnyOf("abort", "finishDocument") && false == callStackContainsAnyOf("merge", "close")) {
           if (onlyOnce) {
             doFail = false;
           }
@@ -473,15 +454,12 @@ public class TestIndexWriterWithThreads extends LuceneTestCase {
     @Override
     public void eval(MockDirectoryWrapper dir)  throws IOException {
       if (doFail) {
-        StackTraceElement[] trace = new Exception().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if ("flush".equals(trace[i].getMethodName()) && DefaultIndexingChain.class.getName().equals(trace[i].getClassName())) {
-            if (onlyOnce)
-              doFail = false;
-            //System.out.println(Thread.currentThread().getName() + ": NOW FAIL: onlyOnce=" + onlyOnce);
-            //new Throwable().printStackTrace(System.out);
-            throw new IOException("now failing on purpose");
-          }
+        if (callStackContains(DefaultIndexingChain.class, "flush")) {
+          if (onlyOnce)
+            doFail = false;
+          //System.out.println(Thread.currentThread().getName() + ": NOW FAIL: onlyOnce=" + onlyOnce);
+          //new Throwable().printStackTrace(System.out);
+          throw new IOException("now failing on purpose");
         }
       }
     }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java b/lucene/core/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java
index 21424cc..e244cd0 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java
@@ -116,11 +116,8 @@ public class TestPersistentSnapshotDeletionPolicy extends TestSnapshotDeletionPo
     dir.failOn(new MockDirectoryWrapper.Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
-        for (int i = 0; i < trace.length; i++) {
-          if (PersistentSnapshotDeletionPolicy.class.getName().equals(trace[i].getClassName()) && "persist".equals(trace[i].getMethodName())) {
-            throw new IOException("now fail on purpose");
-          }
+        if (callStackContains(PersistentSnapshotDeletionPolicy.class, "persist")) {
+          throw new IOException("now fail on purpose");
         }
       }
       });
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterTermVec.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterTermVec.java
index 6a92546..b2319d1 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterTermVec.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterTermVec.java
@@ -133,8 +133,8 @@ public class TestUnifiedHighlighterTermVec extends LuceneTestCase {
           @Override
           public Fields getTermVectors(int docID) throws IOException {
             // if we're invoked by ParallelLeafReader then we can't do our assertion. TODO see LUCENE-6868
-            if (calledBy(ParallelLeafReader.class) == false
-                && calledBy(CheckIndex.class) == false) {
+            if (callStackContains(ParallelLeafReader.class) == false
+                && callStackContains(CheckIndex.class) == false) {
               assertFalse("Should not request TVs for doc more than once.", seenDocIDs.get(docID));
               seenDocIDs.set(docID);
             }
@@ -170,14 +170,6 @@ public class TestUnifiedHighlighterTermVec extends LuceneTestCase {
     }
   }
 
-  private static boolean calledBy(Class<?> clazz) {
-    for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
-      if (stackTraceElement.getClassName().equals(clazz.getName()))
-        return true;
-    }
-    return false;
-  }
-
   @Test(expected = IllegalArgumentException.class)
   public void testUserFailedToIndexOffsets() throws IOException {
     FieldType fieldType = new FieldType(UHTestHelper.tvType); // note: it's indexed too
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/BaseFieldInfoFormatTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/index/BaseFieldInfoFormatTestCase.java
index 3cd7fcd..ed21126 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/BaseFieldInfoFormatTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/BaseFieldInfoFormatTestCase.java
@@ -102,10 +102,8 @@ public abstract class BaseFieldInfoFormatTestCase extends BaseIndexFileFormatTes
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "createOutput".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("createOutput")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -137,10 +135,8 @@ public abstract class BaseFieldInfoFormatTestCase extends BaseIndexFileFormatTes
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "close".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("close")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -172,10 +168,8 @@ public abstract class BaseFieldInfoFormatTestCase extends BaseIndexFileFormatTes
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "openInput".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("openInput")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -208,10 +202,8 @@ public abstract class BaseFieldInfoFormatTestCase extends BaseIndexFileFormatTes
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "close".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("close")) {
+          throw new FakeIOException();
         }
       }
     };
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/BaseSegmentInfoFormatTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/index/BaseSegmentInfoFormatTestCase.java
index 91eb971..a3a5391 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/BaseSegmentInfoFormatTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/BaseSegmentInfoFormatTestCase.java
@@ -292,10 +292,8 @@ public abstract class BaseSegmentInfoFormatTestCase extends BaseIndexFileFormatT
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "createOutput".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("createOutput")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -325,10 +323,8 @@ public abstract class BaseSegmentInfoFormatTestCase extends BaseIndexFileFormatT
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "close".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("close")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -358,10 +354,8 @@ public abstract class BaseSegmentInfoFormatTestCase extends BaseIndexFileFormatT
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "openInput".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("openInput")) {
+          throw new FakeIOException();
         }
       }
     };
@@ -392,10 +386,8 @@ public abstract class BaseSegmentInfoFormatTestCase extends BaseIndexFileFormatT
     Failure fail = new Failure() {
       @Override
       public void eval(MockDirectoryWrapper dir) throws IOException {
-        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
-          if (doFail && "close".equals(e.getMethodName())) {
-            throw new FakeIOException();
-          }
+        if (doFail && callStackContainsAnyOf("close")) {
+          throw new FakeIOException();
         }
       }
     };
diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
index 0b99904..2901cd8 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
@@ -21,6 +21,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
+import java.lang.StackWalker.StackFrame;
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Inherited;
@@ -67,11 +68,37 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
+import com.carrotsearch.randomizedtesting.JUnit4MethodProvider;
+import com.carrotsearch.randomizedtesting.LifecycleScope;
+import com.carrotsearch.randomizedtesting.MixWithSuiteName;
+import com.carrotsearch.randomizedtesting.RandomizedContext;
+import com.carrotsearch.randomizedtesting.RandomizedRunner;
+import com.carrotsearch.randomizedtesting.RandomizedTest;
+import com.carrotsearch.randomizedtesting.annotations.Listeners;
+import com.carrotsearch.randomizedtesting.annotations.SeedDecorators;
+import com.carrotsearch.randomizedtesting.annotations.TestGroup;
+import com.carrotsearch.randomizedtesting.annotations.TestMethodProviders;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakAction;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakAction.Action;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakGroup;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakGroup.Group;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies.Consequence;
+import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
+import com.carrotsearch.randomizedtesting.generators.RandomPicks;
+import com.carrotsearch.randomizedtesting.rules.NoClassHooksShadowingRule;
+import com.carrotsearch.randomizedtesting.rules.NoInstanceHooksOverridesRule;
+import com.carrotsearch.randomizedtesting.rules.StaticFieldsInvariantRule;
+import junit.framework.AssertionFailedError;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.MockAnalyzer;
 import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field.Store;
 import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Store;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.StringField;
 import org.apache.lucene.document.TextField;
@@ -97,8 +124,8 @@ import org.apache.lucene.store.IOContext;
 import org.apache.lucene.store.LockFactory;
 import org.apache.lucene.store.MMapDirectory;
 import org.apache.lucene.store.MergeInfo;
-import org.apache.lucene.store.MockDirectoryWrapper.Throttling;
 import org.apache.lucene.store.MockDirectoryWrapper;
+import org.apache.lucene.store.MockDirectoryWrapper.Throttling;
 import org.apache.lucene.store.NRTCachingDirectory;
 import org.apache.lucene.store.RawDirectoryWrapper;
 import org.apache.lucene.util.automaton.AutomatonTestUtil;
@@ -112,38 +139,10 @@ import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
-import org.junit.internal.AssumptionViolatedException;
-
-import com.carrotsearch.randomizedtesting.JUnit4MethodProvider;
-import com.carrotsearch.randomizedtesting.LifecycleScope;
-import com.carrotsearch.randomizedtesting.MixWithSuiteName;
-import com.carrotsearch.randomizedtesting.RandomizedContext;
-import com.carrotsearch.randomizedtesting.RandomizedRunner;
-import com.carrotsearch.randomizedtesting.RandomizedTest;
-import com.carrotsearch.randomizedtesting.annotations.Listeners;
-import com.carrotsearch.randomizedtesting.annotations.SeedDecorators;
-import com.carrotsearch.randomizedtesting.annotations.TestGroup;
-import com.carrotsearch.randomizedtesting.annotations.TestMethodProviders;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakAction.Action;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakAction;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakGroup.Group;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakGroup;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies.Consequence;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies;
-import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
-import com.carrotsearch.randomizedtesting.generators.RandomPicks;
-import com.carrotsearch.randomizedtesting.rules.NoClassHooksShadowingRule;
-import com.carrotsearch.randomizedtesting.rules.NoInstanceHooksOverridesRule;
-import com.carrotsearch.randomizedtesting.rules.StaticFieldsInvariantRule;
-
-import junit.framework.AssertionFailedError;
 
 import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean;
 import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsInt;
@@ -2707,6 +2706,27 @@ public abstract class LuceneTestCase extends Assert {
       }
     }
   }
+  
+  /** Inspects stack trace to figure out if a method of a specific class called us. */
+  public static boolean callStackContains(Class<?> clazz, String methodName) {
+    final String className = clazz.getName();
+    return StackWalker.getInstance().walk(s -> s.skip(1) // exclude this utility method
+        .anyMatch(f -> className.equals(f.getClassName()) && methodName.equals(f.getMethodName())));
+  }
+
+  /** Inspects stack trace to figure out if one of the given method names (no class restriction) called us. */
+  public static boolean callStackContainsAnyOf(String... methodNames) {
+    return StackWalker.getInstance().walk(s -> s.skip(1) // exclude this utility method
+        .map(StackFrame::getMethodName)
+        .anyMatch(Set.of(methodNames)::contains));
+  }
+
+  /** Inspects stack trace if the given class called us. */
+  public static boolean callStackContains(Class<?> clazz) {
+    return StackWalker.getInstance().walk(s -> s.skip(1) // exclude this utility method
+        .map(StackFrame::getClassName)
+        .anyMatch(clazz.getName()::equals));
+  }
 
   /** A runnable that can throw any checked exception. */
   @FunctionalInterface
diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/TestSecurityManager.java b/lucene/test-framework/src/java/org/apache/lucene/util/TestSecurityManager.java
index a164a9c..2eaccbe 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/util/TestSecurityManager.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/util/TestSecurityManager.java
@@ -16,8 +16,9 @@
  */
 package org.apache.lucene.util;
 
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.lang.StackWalker.StackFrame;
+import java.util.Locale;
+import java.util.function.Predicate;
 
 /**
  * A {@link SecurityManager} that prevents tests calling {@link System#exit(int)}.
@@ -28,11 +29,14 @@ import java.security.PrivilegedAction;
  */ 
 public final class TestSecurityManager extends SecurityManager {
   
-  static final String JUNIT4_TEST_RUNNER_PACKAGE = "com.carrotsearch.ant.tasks.junit4.";
-  static final String ECLIPSE_TEST_RUNNER_PACKAGE = "org.eclipse.jdt.internal.junit.runner.";
-  static final String IDEA_TEST_RUNNER_PACKAGE = "com.intellij.rt.execution.junit.";
-  static final String GRADLE_TEST_RUNNER_PACKAGE = "worker.org.gradle.process.internal.worker";
+  private static final String JUNIT4_TEST_RUNNER_PACKAGE = "com.carrotsearch.ant.tasks.junit4.";
+  private static final String ECLIPSE_TEST_RUNNER_PACKAGE = "org.eclipse.jdt.internal.junit.runner.";
+  private static final String IDEA_TEST_RUNNER_PACKAGE = "com.intellij.rt.execution.junit.";
+  private static final String GRADLE_TEST_RUNNER_PACKAGE = "worker.org.gradle.process.internal.worker.";
 
+  private static final String SYSTEM_CLASS_NAME = System.class.getName();
+  private static final String RUNTIME_CLASS_NAME = Runtime.class.getName();
+  
   /**
    * Creates a new TestSecurityManager. This ctor is called on JVM startup,
    * when {@code -Djava.security.manager=org.apache.lucene.util.TestSecurityManager}
@@ -41,7 +45,7 @@ public final class TestSecurityManager extends SecurityManager {
   public TestSecurityManager() {
     super();
   }
-
+  
   /**
    * {@inheritDoc}
    * <p>This method inspects the stack trace and checks who is calling
@@ -50,46 +54,27 @@ public final class TestSecurityManager extends SecurityManager {
    */
   @Override
   public void checkExit(final int status) {
-    AccessController.doPrivileged(new PrivilegedAction<Void>() {
-      @Override
-      public Void run() {
-        final String systemClassName = System.class.getName(),
-            runtimeClassName = Runtime.class.getName();
-        String exitMethodHit = null;
-        for (final StackTraceElement se : Thread.currentThread().getStackTrace()) {
-          final String className = se.getClassName(), methodName = se.getMethodName();
-          if (
-            ("exit".equals(methodName) || "halt".equals(methodName)) &&
-            (systemClassName.equals(className) || runtimeClassName.equals(className))
-          ) {
-            exitMethodHit = className + '#' + methodName + '(' + status + ')';
-            continue;
-          }
-          
-          if (exitMethodHit != null) {
-            if (className.startsWith(JUNIT4_TEST_RUNNER_PACKAGE) || 
-                className.startsWith(ECLIPSE_TEST_RUNNER_PACKAGE) ||
-                className.startsWith(IDEA_TEST_RUNNER_PACKAGE) ||
-                className.startsWith(GRADLE_TEST_RUNNER_PACKAGE)) {
-              // this exit point is allowed, we return normally from closure:
-              return /*void*/ null;
-            } else {
-              // anything else in stack trace is not allowed, break and throw SecurityException below:
-              break;
-            }
-          }
-        }
-        
-        if (exitMethodHit == null) {
-          // should never happen, only if JVM hides stack trace - replace by generic:
-          exitMethodHit = "JVM exit method";
-        }
-        throw new SecurityException(exitMethodHit + " calls are not allowed because they terminate the test runner's JVM.");
-      }
-    });
-    
+    if (StackWalker.getInstance().walk(s -> s
+        .dropWhile(Predicate.not(TestSecurityManager::isExitStackFrame)) // skip all internal stack frames
+        .dropWhile(TestSecurityManager::isExitStackFrame)                // skip all exit()/halt() stack frames
+        .limit(1)                                                        // only look at one more frame (caller of exit)
+        .map(StackFrame::getClassName)
+        .noneMatch(c -> c.startsWith(JUNIT4_TEST_RUNNER_PACKAGE) || 
+            c.startsWith(ECLIPSE_TEST_RUNNER_PACKAGE) ||
+            c.startsWith(IDEA_TEST_RUNNER_PACKAGE) ||
+            c.startsWith(GRADLE_TEST_RUNNER_PACKAGE)))) {
+      throw new SecurityException(String.format(Locale.ENGLISH,
+          "System/Runtime.exit(%1$d) or halt(%1$d) calls are not allowed because they terminate the test runner's JVM.",
+          status));
+    }
     // we passed the stack check, delegate to super, so default policy can still deny permission:
     super.checkExit(status);
   }
 
+  private static boolean isExitStackFrame(StackFrame f) {
+    final String methodName = f.getMethodName(), className = f.getClassName();
+    return ("exit".equals(methodName) || "halt".equals(methodName)) &&
+        (SYSTEM_CLASS_NAME.equals(className) || RUNTIME_CLASS_NAME.equals(className));
+  }
+  
 }
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 02933b7..5c6649d 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -150,6 +150,8 @@ Upgrade Notes
   If you prefer to keep the old (but insecure) serialization strategy, you can start your nodes using the
   property: `-Dsolr.useUnsafeOverseerResponse=true`. Keep in mind that this will be removed in future version of Solr.
  
+ * SOLR-13808: add cache=false into uderneath BoolQParser's filter clause or {"bool":{"filter":..}} to avoid caching in
+   filterCache. (Mikhail Khludnev)
 
 New Features
 ---------------------
@@ -178,6 +180,8 @@ Improvements
 * SOLR-13984: Java's SecurityManager sandbox can be enabled via environment variable,
   SOLR_SECURITY_MANAGER_ENABLED=true. (rmuir)
 
+* SOLR-13808: filter in BoolQParser and {"bool":{"filter":..}} in Query DSL are cached by default (Mikhail Khludnev)
+
 Optimizations
 ---------------------
 (No changes)
diff --git a/solr/core/src/java/org/apache/solr/search/BoolQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/BoolQParserPlugin.java
index c0bebe5..04a9d5a 100644
--- a/solr/core/src/java/org/apache/solr/search/BoolQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/BoolQParserPlugin.java
@@ -21,6 +21,7 @@ import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.Query;
 import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.query.FilterQuery;
 import org.apache.solr.request.SolrQueryRequest;
 
 /**
@@ -49,7 +50,18 @@ public class BoolQParserPlugin extends QParserPlugin {
       private void addQueries(BooleanQuery.Builder builder, String[] subQueries, BooleanClause.Occur occur) throws SyntaxError {
         if (subQueries != null) {
           for (String subQuery : subQueries) {
-            builder.add(subQuery(subQuery, null).parse(), occur);
+            final QParser subParser = subQuery(subQuery, null);
+            Query extQuery;
+            if (BooleanClause.Occur.FILTER.equals(occur)) {
+              extQuery = subParser.getQuery();
+              if (!(extQuery instanceof ExtendedQuery) || (
+                  ((ExtendedQuery) extQuery).getCache())) {
+                  extQuery = new FilterQuery(extQuery);
+              }
+            } else {
+              extQuery = subParser.parse();
+            }
+            builder.add(extQuery, occur);
           }
         }
       }
diff --git a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java
index 9f34db0..2ab19e9 100644
--- a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java
+++ b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java
@@ -16,11 +16,17 @@
  */
 package org.apache.solr.search.json;
 
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.solr.JSONTestUtil;
 import org.apache.solr.SolrTestCaseHS;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.CaffeineCache;
+import org.apache.solr.search.DocSet;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -31,6 +37,7 @@ public class TestJsonRequest extends SolrTestCaseHS {
 
   private static SolrInstances servers;  // for distributed testing
 
+  @SuppressWarnings("deprecation")
   @BeforeClass
   public static void beforeTests() throws Exception {
     systemSetPropertySolrDisableShardsWhitelist("true");
@@ -44,6 +51,7 @@ public class TestJsonRequest extends SolrTestCaseHS {
     }
   }
 
+  @SuppressWarnings("deprecation")
   @AfterClass
   public static void afterTests() throws Exception {
     JSONTestUtil.failRepeatedKeys = false;
@@ -303,17 +311,9 @@ public class TestJsonRequest extends SolrTestCaseHS {
         , "response/numFound==1"
     );
 
-    client.testJQ( params("json","{ " +
-            " query : {" +
-            "  bool : {" +
-            "   must : '{!lucene q.op=AND df=cat_s}A'" +
-            "   must_not : '{!lucene v=\\'id:1\\'}'" +
-            "  }" +
-            " }" +
-            "}")
-        , "response/numFound==1"
-    );
-
+    assertCatANot1(client, "must");
+    
+    testFilterCachingLocally(client);
 
     client.testJQ( params("json","{" +
             " query : '*:*'," +
@@ -407,6 +407,64 @@ public class TestJsonRequest extends SolrTestCaseHS {
 
   }
 
+  private static void testFilterCachingLocally(Client client) throws Exception {
+    if(client.getClientProvider()==null) {
+      final SolrQueryRequest request = req();
+      try {
+        final CaffeineCache<Query,DocSet> filterCache = (CaffeineCache<Query,DocSet>) request.getSearcher().getFilterCache();
+        filterCache.clear();
+        final TermQuery catA = new TermQuery(new Term("cat_s", "A"));
+        assertNull("cache is empty",filterCache.get(catA));
+
+        if(random().nextBoolean()) {
+          if(random().nextBoolean()) {
+            if(random().nextBoolean()) {
+              assertCatANot1(client, "must");
+            }else {
+              assertCatANot1(client, "must", "cat_s:A");
+            }
+          } else {
+            assertCatANot1(client, "must","{!lucene q.op=AND df=cat_s "+"cache="+random().nextBoolean()+"}A" );
+          }   
+        } else {
+          assertCatANot1(client, "filter", "{!lucene q.op=AND df=cat_s cache=false}A");
+        }
+        assertNull("no cache still",filterCache.get(catA));
+
+        if (random().nextBoolean()) {
+          if (random().nextBoolean()) {
+            assertCatANot1(client, "filter", "cat_s:A");
+          } else {
+            assertCatANot1(client, "filter");
+          }
+        } else {
+          assertCatANot1(client, "filter","{!lucene q.op=AND df=cat_s cache=true}A");
+        }
+        assertNotNull("got cached ",filterCache.get(catA));
+
+      } finally {
+        request.close();
+      }
+    }
+  }
+
+  private static void assertCatANot1(Client client, final String occur) throws Exception {
+    assertCatANot1(client, occur,  "{!lucene q.op=AND df=cat_s}A");
+  }
+
+  private static void assertCatANot1(Client client, final String occur, String catAclause) throws Exception {
+    client.testJQ( params("json","{ " +
+            " query : {" +
+            "  bool : {" +
+            "   " + occur + " : '"+ catAclause+ "'" +
+            "   must_not : '{!lucene v=\\'id:1\\'}'" +
+            "  }" +
+            " }" +
+            "}")
+        , "response/numFound==1"
+    );
+  }
+
   public static void doJsonRequestWithTag(Client client) throws Exception {
     addDocs(client);
 
diff --git a/solr/server/etc/security.policy b/solr/server/etc/security.policy
index bcf82b9..57229f0 100644
--- a/solr/server/etc/security.policy
+++ b/solr/server/etc/security.policy
@@ -20,20 +20,23 @@
 // permissions needed for tests to pass, based on properties set by the build system
 // NOTE: if the property is not set, the permission entry is ignored.
 grant {
-  // contain read access to only what we need:
   // 3rd party jar resources (where symlinks are not supported), test-files/ resources
   permission java.io.FilePermission "${common.dir}${/}-", "read";
   permission java.io.FilePermission "${common.dir}${/}..${/}solr${/}-", "read";
-  // 3rd party jar resources (where symlinks are supported)
-  permission java.io.FilePermission "${user.home}${/}.ivy2${/}cache${/}-", "read";
+
   // system jar resources
   permission java.io.FilePermission "${java.home}${/}-", "read";
+
+  // Test launchers (randomizedtesting, etc.)
   permission java.io.FilePermission "${junit4.childvm.cwd}", "read";
   permission java.io.FilePermission "${junit4.childvm.cwd}${/}temp", "read,write,delete";
   permission java.io.FilePermission "${junit4.childvm.cwd}${/}temp${/}-", "read,write,delete";
   permission java.io.FilePermission "${junit4.childvm.cwd}${/}jacoco.db", "write";
   permission java.io.FilePermission "${junit4.tempDir}${/}*", "read,write,delete";
   permission java.io.FilePermission "${clover.db.dir}${/}-", "read,write,delete";
+  // 3rd party jar resources (where symlinks are supported)
+  permission java.io.FilePermission "${user.home}${/}.ivy2${/}cache${/}-", "read";
+
   permission java.io.FilePermission "${tests.linedocsfile}", "read";
   // DirectoryFactoryTest messes with these (wtf?)
   permission java.io.FilePermission "/tmp/inst1/conf/solrcore.properties", "read";
@@ -42,7 +45,7 @@ grant {
   permission java.io.FilePermission "/path/to/solr/home/lib", "read";
 
   permission java.nio.file.LinkPermission "hard";
-  
+
   // all possibilities of accepting/binding/connections on localhost with ports >=1024:
   permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect,resolve";
   permission java.net.SocketPermission "127.0.0.1:1024-", "accept,listen,connect,resolve";
@@ -55,10 +58,10 @@ grant {
   // Basic permissions needed for Lucene to work:
   permission java.util.PropertyPermission "*", "read,write";
 
-  // needed by gson serialization of junit4 runner: TODO clean that up
+  // needed by randomizedtesting runner to identify test methods.
   permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
   permission java.lang.RuntimePermission "accessDeclaredMembers";
-  // needed by junit4 runner to capture sysout/syserr:
+  // needed by certain tests to redirect sysout/syserr:
   permission java.lang.RuntimePermission "setIO";
   // needed by randomized runner to catch failures from other threads:
   permission java.lang.RuntimePermission "setDefaultUncaughtExceptionHandler";
diff --git a/solr/solr-ref-guide/src/other-parsers.adoc b/solr/solr-ref-guide/src/other-parsers.adoc
index 3996a9f..389138c 100644
--- a/solr/solr-ref-guide/src/other-parsers.adoc
+++ b/solr/solr-ref-guide/src/other-parsers.adoc
@@ -188,7 +188,7 @@ A list of queries that *must not* appear in matching documents.
 A list of queries *should* appear in matching documents. For a BooleanQuery with no `must` queries, one or more `should` queries must match a document for the BooleanQuery to match.
 
 `filter`::
-A list of queries that *must* appear in matching documents. However, unlike `must`, the score of filter queries is ignored.
+A list of queries that *must* appear in matching documents. However, unlike `must`, the score of filter queries is ignored. Also, these queries are cached in filter cache. To avoid caching add either `cache=false` as local parameter, or `"cache":"false"` property to underneath Query DLS Object.  
 
 *Examples*
 


[lucene] 11/21: javadoc

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 76e02032dc740f5202f8b0103d3158fa9ca4e2c0
Author: noble <no...@apache.org>
AuthorDate: Fri Dec 27 12:01:24 2019 +1100

    javadoc
---
 solr/core/src/java/org/apache/solr/schema/IndexSchema.java | 7 +++++++
 1 file changed, 7 insertions(+)

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 dec7fc3..09f6341 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -140,7 +140,14 @@ public class IndexSchema implements Closeable {
   protected String name;
   protected final Version luceneVersion;
   protected float version;
+  /**All resources and other files should be loaded using this
+   */
   protected final SolrResourceLoader loader;
+
+  /**Classes for all plugins should be loaded using this.
+   * If resources need to be loaded from packages, use the classloader of one of the classes
+   * loaded from this package
+   */
   protected final PluginLoader pluginLoader;
 
   protected Map<String,SchemaField> fields = new HashMap<>();


[lucene] 02/21: SOLR-14151: Support for packages in schema.xml

Posted by dw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch jira/solr14155
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 2bec9e348d78032e739614c806bc58aac47c635b
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 26 12:37:48 2019 +1100

    SOLR-14151: Support for packages in schema.xml
---
 .../src/java/org/apache/solr/core/ConfigSet.java   |  15 ++-
 .../org/apache/solr/core/ConfigSetService.java     |   3 +-
 .../src/java/org/apache/solr/core/PluginInfo.java  |  47 ++++-----
 .../java/org/apache/solr/core/PluginLoader.java    |  30 ++++++
 .../src/java/org/apache/solr/core/SolrCore.java    |  19 +++-
 .../org/apache/solr/core/SolrResourceLoader.java   |  15 ++-
 .../org/apache/solr/schema/CurrencyFieldType.java  |   2 +-
 .../apache/solr/schema/FieldTypePluginLoader.java  |  12 ++-
 .../java/org/apache/solr/schema/IndexSchema.java   | 105 ++++++++++++++++++++-
 .../org/apache/solr/schema/ManagedIndexSchema.java |   2 +-
 .../org/apache/solr/schema/PreAnalyzedField.java   |   5 +-
 .../solr/util/plugin/AbstractPluginLoader.java     |  11 ++-
 .../org/apache/solr/core/TestCodecSupport.java     |   4 +-
 13 files changed, 217 insertions(+), 53 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/ConfigSet.java b/solr/core/src/java/org/apache/solr/core/ConfigSet.java
index e0c9fe4..bfd5867 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigSet.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigSet.java
@@ -16,6 +16,8 @@
  */
 package org.apache.solr.core;
 
+import java.util.function.Supplier;
+
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.schema.IndexSchema;
 
@@ -28,17 +30,17 @@ public class ConfigSet {
 
   private final SolrConfig solrconfig;
 
-  private final IndexSchema indexSchema;
+  private volatile Supplier<IndexSchema> indexSchemaSupplier;
 
   private final NamedList properties;
 
   private final boolean trusted;
 
-  public ConfigSet(String name, SolrConfig solrConfig, IndexSchema indexSchema,
-      NamedList properties, boolean trusted) {
+  public ConfigSet(String name, SolrConfig solrConfig, Supplier<IndexSchema> indexSchemaSupplier,
+                   NamedList properties, boolean trusted) {
     this.name = name;
     this.solrconfig = solrConfig;
-    this.indexSchema = indexSchema;
+    this.indexSchemaSupplier = indexSchemaSupplier;
     this.properties = properties;
     this.trusted = trusted;
   }
@@ -51,8 +53,11 @@ public class ConfigSet {
     return solrconfig;
   }
 
+  public Supplier<IndexSchema> getIndexSchemaSupplier() {
+    return indexSchemaSupplier;
+  }
   public IndexSchema getIndexSchema() {
-    return indexSchema;
+    return indexSchemaSupplier.get();
   }
 
   public NamedList getProperties() {
diff --git a/solr/core/src/java/org/apache/solr/core/ConfigSetService.java b/solr/core/src/java/org/apache/solr/core/ConfigSetService.java
index bc0d4a9..9fa2f12 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigSetService.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigSetService.java
@@ -88,8 +88,7 @@ public abstract class ConfigSetService {
               ) ? false: true;
 
       SolrConfig solrConfig = createSolrConfig(dcore, coreLoader, trusted);
-      IndexSchema schema = createIndexSchema(dcore, solrConfig);
-      return new ConfigSet(configName(dcore), solrConfig, schema, properties, trusted);
+      return new ConfigSet(configName(dcore), solrConfig, () -> createIndexSchema(dcore, solrConfig), properties, trusted);
     } catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
           "Could not load conf for core " + dcore.getName() +
diff --git a/solr/core/src/java/org/apache/solr/core/PluginInfo.java b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
index bb290e1..afe4073 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -25,7 +25,6 @@ import java.util.Map;
 
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.Pair;
 import org.apache.solr.util.DOMUtil;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -52,9 +51,9 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(String type, Map<String, String> attrs, NamedList initArgs, List<PluginInfo> children) {
     this.type = type;
     this.name = attrs.get(NAME);
-    Pair<String, String> parsed = parseClassName(attrs.get(CLASS_NAME));
-    this.className = parsed.second();
-    this.pkgName = parsed.first();
+    ClassName parsed = new ClassName(attrs.get(CLASS_NAME));
+    this.className = parsed.klas;
+    this.pkgName = parsed.pkg;
     this.initArgs = initArgs;
     attributes = unmodifiableMap(attrs);
     this.children = children == null ? Collections.<PluginInfo>emptyList(): unmodifiableList(children);
@@ -63,29 +62,35 @@ public class PluginInfo implements MapSerializable {
 
   /** class names can be prefixed with package name e.g: my_package:my.pkg.Class
    * This checks if it is a package name prefixed classname.
-   * the return value has first = package name & second = class name
    */
-  static Pair<String,String > parseClassName(String name) {
-    String pkgName = null;
-    String className = name;
-    if (name != null) {
-      int colonIdx = name.indexOf(':');
-      if (colonIdx > -1) {
-        pkgName = name.substring(0, colonIdx);
-        className = name.substring(colonIdx + 1);
+
+  public static class ClassName {
+    public final String pkg;
+    public final String klas;
+
+    public ClassName(String name) {
+      String pkgName = null;
+      String className = name;
+      if (name != null) {
+        int colonIdx = name.indexOf(':');
+        if (colonIdx > -1) {
+          pkgName = name.substring(0, colonIdx);
+          className = name.substring(colonIdx + 1);
+        }
       }
-    }
-    return new Pair<>(pkgName, className);
 
+      this.klas = className;
+      this.pkg = pkgName;
+    }
   }
 
 
   public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
     type = node.getNodeName();
     name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
-    Pair<String, String> parsed = parseClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
-    className = parsed.second();
-    pkgName = parsed.first();
+    ClassName parsed = new ClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
+    className = parsed.klas;
+    pkgName = parsed.pkg;
     initArgs = DOMUtil.childNodesToNamedList(node);
     attributes = unmodifiableMap(DOMUtil.toMap(node.getAttributes()));
     children = loadSubPlugins(node);
@@ -115,9 +120,9 @@ public class PluginInfo implements MapSerializable {
     }
     this.type = type;
     this.name = (String) m.get(NAME);
-    Pair<String, String> parsed = parseClassName((String) m.get(CLASS_NAME));
-    this.className = parsed.second();
-    this.pkgName = parsed.first();
+    ClassName parsed = new ClassName((String) m.get(CLASS_NAME));
+    this.className = parsed.klas;
+    this.pkgName = parsed.pkg;
     attributes = unmodifiableMap(m);
     this.children =  Collections.<PluginInfo>emptyList();
     isFromSolrConfig = true;
diff --git a/solr/core/src/java/org/apache/solr/core/PluginLoader.java b/solr/core/src/java/org/apache/solr/core/PluginLoader.java
new file mode 100644
index 0000000..ef0bd94
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/core/PluginLoader.java
@@ -0,0 +1,30 @@
+/*
+ * 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.solr.core;
+
+/**A generic interface to load classes
+ *
+ */
+public interface PluginLoader {
+
+  <T> T newInstance(String cname, Class<T> expectedType, String... subpackages);
+
+  <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args);
+
+  <T> Class<? extends T> findClass(String cname, Class<T> expectedType);
+}
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 2c6b175..e7c1be5 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -56,6 +56,7 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
 
 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Timer;
@@ -173,6 +174,7 @@ import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.lucene.util.IOUtils.closeWhileHandlingException;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.common.params.CommonParams.PATH;
 
@@ -238,6 +240,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   public volatile boolean searchEnabled = true;
   public volatile boolean indexEnabled = true;
   public volatile boolean readOnly = false;
+  private final Supplier<IndexSchema> schemaSupplier;
 
   private PackageListeners packageListeners = new PackageListeners(this);
 
@@ -688,7 +691,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
         CoreDescriptor cd = new CoreDescriptor(name, getCoreDescriptor());
         cd.loadExtraProperties(); //Reload the extra properties
         core = new SolrCore(coreContainer, getName(), getDataDir(), coreConfig.getSolrConfig(),
-            coreConfig.getIndexSchema(), coreConfig.getProperties(),
+            () -> coreConfig.getIndexSchema(), coreConfig.getProperties(),
             cd, updateHandler, solrDelPolicy, currentCore, true);
 
         // we open a new IndexWriter to pick up the latest config
@@ -897,7 +900,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   }
 
   public SolrCore(CoreContainer coreContainer, CoreDescriptor cd, ConfigSet coreConfig) {
-    this(coreContainer, cd.getName(), null, coreConfig.getSolrConfig(), coreConfig.getIndexSchema(), coreConfig.getProperties(),
+    this(coreContainer, cd.getName(), null, coreConfig.getSolrConfig(), coreConfig.getIndexSchemaSupplier(), coreConfig.getProperties(),
         cd, null, null, null, false);
   }
 
@@ -905,6 +908,11 @@ public final class SolrCore implements SolrInfoBean, Closeable {
     return coreContainer;
   }
 
+  public void refreshSchema() {
+    IndexSchema old = schema;
+    schema = schemaSupplier.get();
+    closeWhileHandlingException(old);
+  }
 
   /**
    * Creates a new core and register it in the list of cores. If a core with the
@@ -912,11 +920,11 @@ public final class SolrCore implements SolrInfoBean, Closeable {
    *
    * @param dataDir the index directory
    * @param config  a solr config instance
-   * @param schema  a solr schema instance
+   * @param schemaSupplier  a solr schema {@link Supplier}
    * @since solr 1.3
    */
   public SolrCore(CoreContainer coreContainer, String name, String dataDir, SolrConfig config,
-                  IndexSchema schema, NamedList configSetProperties,
+                  Supplier<IndexSchema> schemaSupplier, NamedList configSetProperties,
                   CoreDescriptor coreDescriptor, UpdateHandler updateHandler,
                   IndexDeletionPolicyWrapper delPolicy, SolrCore prev, boolean reload) {
 
@@ -924,6 +932,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
     this.coreContainer = coreContainer;
 
+    this.schemaSupplier = schemaSupplier;
     final CountDownLatch latch = new CountDownLatch(1);
 
     try {
@@ -935,6 +944,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
       MDCLoggingContext.setCore(this);
 
       resourceLoader = config.getResourceLoader();
+      resourceLoader.core = this;
       this.solrConfig = config;
       this.configSetProperties = configSetProperties;
       // Initialize the metrics manager
@@ -959,6 +969,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
       log.info("[{}] Opening new SolrCore at [{}], dataDir=[{}]", logid, resourceLoader.getInstancePath(),
           this.dataDir);
 
+      IndexSchema schema = schemaSupplier.get();
       checkVersionFieldExistsInSchema(schema, coreDescriptor);
 
       // initialize core metrics
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index a57660e..46e2ecf 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -83,7 +83,7 @@ import org.slf4j.LoggerFactory;
 /**
  * @since solr 1.3
  */
-public class SolrResourceLoader implements ResourceLoader, Closeable {
+public class SolrResourceLoader implements ResourceLoader, PluginLoader, Closeable {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   static final String project = "solr";
@@ -118,6 +118,9 @@ public class SolrResourceLoader implements ResourceLoader, Closeable {
   // (such as the SolrZkClient) when XML docs are being parsed.    
   private RestManager.Registry managedResourceRegistry;
 
+  //package private , only to be used from SolrCore
+  SolrCore core;
+
   public synchronized RestManager.Registry getManagedResourceRegistry() {
     if (managedResourceRegistry == null) {
       managedResourceRegistry = new RestManager.Registry();
@@ -149,6 +152,15 @@ public class SolrResourceLoader implements ResourceLoader, Closeable {
 
   }
 
+  /**
+   * This could be null if it is not associated with a core yet
+   *
+   */
+  public SolrCore getCore() {
+    return core;
+
+  }
+
 
   public SolrResourceLoader(Path instanceDir) {
     this(instanceDir, null, null);
@@ -615,6 +627,7 @@ public class SolrResourceLoader implements ResourceLoader, Closeable {
   private static final Class[] NO_CLASSES = new Class[0];
   private static final Object[] NO_OBJECTS = new Object[0];
 
+  @Override
   public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
     return newInstance(cname, expectedType, subpackages, NO_CLASSES, NO_OBJECTS);
   }
diff --git a/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java b/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
index 4e59212..0511830 100644
--- a/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
+++ b/solr/core/src/java/org/apache/solr/schema/CurrencyFieldType.java
@@ -121,7 +121,7 @@ public class CurrencyFieldType extends FieldType implements SchemaAware, Resourc
     }
     try {
       Class<? extends ExchangeRateProvider> c
-          = schema.getResourceLoader().findClass(exchangeRateProviderClass, ExchangeRateProvider.class);
+          = schema.getPluginLoader().findClass(exchangeRateProviderClass, ExchangeRateProvider.class);
       provider = c.getConstructor().newInstance();
       provider.init(args);
     } catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
index 781e199..b72b835 100644
--- a/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/schema/FieldTypePluginLoader.java
@@ -34,6 +34,7 @@ import org.apache.lucene.analysis.util.TokenizerFactory;
 import org.apache.lucene.util.Version;
 import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.core.PluginLoader;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.DOMUtil;
@@ -78,7 +79,7 @@ public final class FieldTypePluginLoader
 
 
   @Override
-  protected FieldType create( SolrResourceLoader loader, 
+  protected FieldType create( PluginLoader loader,
                               String name, 
                               String className,
                               Node node ) throws Exception {
@@ -192,6 +193,7 @@ public final class FieldTypePluginLoader
   private Analyzer readAnalyzer(Node node) throws XPathExpressionException {
                                 
     final SolrResourceLoader loader = schema.getResourceLoader();
+    final PluginLoader pluginLoader = schema.getPluginLoader();
 
     // parent node used to be passed in as "fieldtype"
     // if (!fieldtype.hasChildNodes()) return null;
@@ -226,7 +228,7 @@ public final class FieldTypePluginLoader
 
       try {
         // No need to be core-aware as Analyzers are not in the core-aware list
-        final Class<? extends Analyzer> clazz = loader.findClass(analyzerName, Analyzer.class);
+        final Class<? extends Analyzer> clazz =  pluginLoader.findClass(analyzerName, Analyzer.class);
         Analyzer analyzer = clazz.getConstructor().newInstance();
 
         final String matchVersionStr = DOMUtil.getAttr(attrs, LUCENE_MATCH_VERSION_PARAM);
@@ -256,7 +258,7 @@ public final class FieldTypePluginLoader
       ("[schema.xml] analyzer/charFilter", CharFilterFactory.class, false, false) {
 
       @Override
-      protected CharFilterFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
+      protected CharFilterFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, CharFilterFactory.class.getSimpleName()).toString());
@@ -306,7 +308,7 @@ public final class FieldTypePluginLoader
       ("[schema.xml] analyzer/tokenizer", TokenizerFactory.class, false, false) {
       
       @Override
-      protected TokenizerFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
+      protected TokenizerFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenizerFactory.class.getSimpleName()).toString());
@@ -360,7 +362,7 @@ public final class FieldTypePluginLoader
       new AbstractPluginLoader<TokenFilterFactory>("[schema.xml] analyzer/filter", TokenFilterFactory.class, false, false)
     {
       @Override
-      protected TokenFilterFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
+      protected TokenFilterFactory create(PluginLoader loader, String name, String className, Node node) throws Exception {
         final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
         String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
         params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenFilterFactory.class.getSimpleName()).toString());
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 5f213d3..407c4d1 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -19,6 +19,7 @@ package org.apache.solr.schema;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.Writer;
 import java.lang.invoke.MethodHandles;
@@ -60,9 +61,13 @@ import org.apache.solr.common.util.Cache;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.core.PluginInfo;
+import org.apache.solr.core.PluginLoader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.core.XmlConfigFile;
+import org.apache.solr.pkg.PackageListeners;
+import org.apache.solr.pkg.PackageLoader;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.response.SchemaXmlWriter;
 import org.apache.solr.response.SolrQueryResponse;
@@ -91,7 +96,7 @@ import static java.util.Collections.singletonMap;
  *
  *
  */
-public class IndexSchema {
+public class IndexSchema implements Closeable {
   public static final String COPY_FIELD = "copyField";
   public static final String COPY_FIELDS = COPY_FIELD + "s";
   public static final String DEFAULT_SCHEMA_FILE = "schema.xml";
@@ -133,6 +138,7 @@ public class IndexSchema {
   protected final Version luceneVersion;
   protected float version;
   protected final SolrResourceLoader loader;
+  protected final PluginLoader pluginLoader;
 
   protected Map<String,SchemaField> fields = new HashMap<>();
   protected Map<String,FieldType> fieldTypes = new HashMap<>();
@@ -163,6 +169,7 @@ public class IndexSchema {
    */
   protected Map<SchemaField, Integer> copyFieldTargetCounts = new HashMap<>();
 
+
   /**
    * Constructs a schema using the specified resource name and stream.
    * @see SolrResourceLoader#openSchema
@@ -181,9 +188,95 @@ public class IndexSchema {
     }
   }
 
+  public PluginLoader getPluginLoader(){
+    return pluginLoader;
+  }
   protected IndexSchema(Version luceneVersion, SolrResourceLoader loader) {
     this.luceneVersion = Objects.requireNonNull(luceneVersion);
     this.loader = loader;
+    if(loader.getCore() == null) {
+      this.pluginLoader = loader;
+    } else {
+      PackageAwarePluginLoader papl = new PackageAwarePluginLoader(loader.getCore());
+      this.pluginLoader = papl;
+    }
+  }
+
+  class PackageAwarePluginLoader implements PluginLoader, Closeable {
+    final SolrCore core;
+    private final List<PackageListeners.Listener> listeners = new ArrayList<>();
+    Runnable reloadSchemaRunnable = () -> getCore().refreshSchema();
+
+
+    PackageAwarePluginLoader(SolrCore core) {
+      this.core = core;
+    }
+
+    SolrCore getCore() {
+      return core;
+    }
+
+    @Override
+    public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
+      return getIt(cname, expectedType, pkgloader -> pkgloader.newInstance(cname, expectedType, subpackages));
+    }
+
+    private <T> T getIt(String cname, Class expectedType, Function<SolrResourceLoader, T> fun) {
+      PluginInfo.ClassName className = new PluginInfo.ClassName(cname);
+      if (className.pkg == null) {
+        return  fun.apply(loader);
+      } else {
+        SolrResourceLoader pkgloader = core.getResourceLoader(className.pkg);
+        T inst = fun.apply(pkgloader);
+        PackageListeners.Listener listener = new PackageListeners.Listener() {
+          PluginInfo info = new PluginInfo(expectedType.getSimpleName(), singletonMap("class", cname));
+
+          @Override
+          public String packageName() {
+            return className.pkg;
+          }
+
+          @Override
+          public PluginInfo pluginInfo() {
+            return info;
+          }
+
+          @Override
+          public void changed(PackageLoader.Package pkg, PackageListeners.Ctx ctx) {
+            Runnable old = ctx.getPostProcessor(PackageAwarePluginLoader.class.getName());// just want to do one refresh for every package laod
+            if (old == null) ctx.addPostProcessor(PackageAwarePluginLoader.class.getName(), reloadSchemaRunnable);
+          }
+
+          @Override
+          public PackageLoader.Package.Version getPackageVersion() {
+            return null;
+          }
+        };
+        listeners.add(listener);
+        core.getPackageListeners().addListener(listener);
+        return inst;
+      }
+    }
+
+    @Override
+    public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
+      return getIt(cname, expectedType, (Function<SolrResourceLoader, Class<? extends T>>) loader -> loader.findClass(cname, expectedType));
+    }
+
+    @Override
+    public <T> T newInstance(String cName, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
+      return getIt(cName, expectedType, loader -> loader.newInstance(cName, expectedType, subPackages, params, args));
+    }
+
+
+
+    @Override
+    public void close() throws IOException {
+      for (PackageListeners.Listener l : listeners) {
+        core.getPackageListeners().removeListener(l);
+      }
+
+    }
   }
 
   /**
@@ -497,7 +590,7 @@ public class IndexSchema {
       if (similarityFactory == null) {
         final Class<?> simClass = SchemaSimilarityFactory.class;
         // use the loader to ensure proper SolrCoreAware handling
-        similarityFactory = loader.newInstance(simClass.getName(), SimilarityFactory.class);
+        similarityFactory = pluginLoader.newInstance(simClass.getName(), SimilarityFactory.class);
         similarityFactory.init(new ModifiableSolrParams());
       } else {
         isExplicitSimilarity = true;
@@ -971,7 +1064,7 @@ public class IndexSchema {
     dynamicCopyFields = temp;
   }
 
-  static SimilarityFactory readSimilarity(SolrResourceLoader loader, Node node) {
+  static SimilarityFactory readSimilarity(PluginLoader loader, Node node) {
     if (node==null) {
       return null;
     } else {
@@ -1981,4 +2074,10 @@ public class IndexSchema {
     return decoders.computeIfAbsent(ft, f -> PayloadUtils.getPayloadDecoder(ft));
   }
 
+  @Override
+  public void close() throws IOException {
+    if (pluginLoader instanceof PackageAwarePluginLoader) {
+      ((PackageAwarePluginLoader) pluginLoader).close();
+    }
+  }
 }
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 57b0c90..d65ece9 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
@@ -1272,7 +1272,7 @@ public final class ManagedIndexSchema extends IndexSchema {
     Map<String,FieldType> newFieldTypes = new HashMap<>();
     List<SchemaAware> schemaAwareList = new ArrayList<>();
     FieldTypePluginLoader typeLoader = new FieldTypePluginLoader(this, newFieldTypes, schemaAwareList);
-    typeLoader.loadSingle(loader, FieldTypeXmlAdapter.toNode(options));
+    typeLoader.loadSingle(pluginLoader, FieldTypeXmlAdapter.toNode(options));
     FieldType ft = newFieldTypes.get(typeName);
     if (!schemaAwareList.isEmpty())
       schemaAware.addAll(schemaAwareList);
diff --git a/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java b/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
index 00da7ed..9a5683f 100644
--- a/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
+++ b/solr/core/src/java/org/apache/solr/schema/PreAnalyzedField.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 package org.apache.solr.schema;
+
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
@@ -36,8 +37,8 @@ import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.SortedSetSelector;
 import org.apache.lucene.util.AttributeFactory;
-import org.apache.lucene.util.AttributeSource.State;
 import org.apache.lucene.util.AttributeSource;
+import org.apache.lucene.util.AttributeSource.State;
 import org.apache.solr.analysis.SolrAnalyzer;
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
@@ -79,7 +80,7 @@ public class PreAnalyzedField extends TextField implements HasImplicitIndexAnaly
         parser = new SimplePreAnalyzedParser();
       } else {
         try {
-          Class<? extends PreAnalyzedParser> implClazz = schema.getResourceLoader().findClass(implName, PreAnalyzedParser.class);
+          Class<? extends PreAnalyzedParser> implClazz = schema.getPluginLoader().findClass(implName, PreAnalyzedParser.class);
           Constructor<?> c = implClazz.getConstructor(new Class<?>[0]);
           parser = (PreAnalyzedParser) c.newInstance(new Object[0]);
         } catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java b/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
index 1243017..5be8ab4 100644
--- a/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
+++ b/solr/core/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
@@ -23,7 +23,7 @@ import java.util.Objects;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.core.PluginLoader;
 import org.apache.solr.util.DOMUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -86,11 +86,11 @@ public abstract class AbstractPluginLoader<T>
    * @param node - the XML node defining this plugin
    */
   @SuppressWarnings("unchecked")
-  protected T create( SolrResourceLoader loader, String name, String className, Node node ) throws Exception
+  protected T create(PluginLoader loader, String name, String className, Node node ) throws Exception
   {
     return loader.newInstance(className, pluginClassType, getDefaultPackages());
   }
-  
+
   /**
    * Register a plugin with a given name.
    * @return The plugin previously registered to this name, or null
@@ -135,7 +135,7 @@ public abstract class AbstractPluginLoader<T>
    * If a default element is defined, it will be returned from this function.
    * 
    */
-  public T load( SolrResourceLoader loader, NodeList nodes )
+  public T load(PluginLoader loader, NodeList nodes )
   {
     List<PluginInitInfo> info = new ArrayList<>();
     T defaultPlugin = null;
@@ -223,7 +223,7 @@ public abstract class AbstractPluginLoader<T>
    * The created class for the plugin will be returned from this function.
    * 
    */
-  public T loadSingle(SolrResourceLoader loader, Node node) {
+  public T loadSingle(PluginLoader loader, Node node) {
     List<PluginInitInfo> info = new ArrayList<>();
     T plugin = null;
 
@@ -280,4 +280,5 @@ public abstract class AbstractPluginLoader<T>
       this.node = node;
     }
   }
+
 }
diff --git a/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java b/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
index a3daeb8..ec9eef4 100644
--- a/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
+++ b/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
@@ -30,7 +30,6 @@ import org.apache.lucene.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.NamedList;
-import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.IndexSchemaFactory;
 import org.apache.solr.schema.SchemaField;
 import org.apache.solr.util.TestHarness;
@@ -203,7 +202,6 @@ public class TestCodecSupport extends SolrTestCaseJ4 {
     assertEquals("Unexpected codec factory for this test.", "solr.SchemaCodecFactory", config.get("codecFactory/@class"));
     assertNull("Unexpected configuration of codec factory for this test. Expecting empty element", 
         config.getNode("codecFactory", false).getFirstChild());
-    IndexSchema schema = IndexSchemaFactory.buildIndexSchema("schema_codec.xml", config);
 
     CoreContainer coreContainer = h.getCoreContainer();
     
@@ -211,7 +209,7 @@ public class TestCodecSupport extends SolrTestCaseJ4 {
       CoreDescriptor cd = new CoreDescriptor(newCoreName, testSolrHome.resolve(newCoreName),
           coreContainer.getContainerProperties(), coreContainer.isZooKeeperAware());
       c = new SolrCore(coreContainer, cd,
-          new ConfigSet("fakeConfigset", config, schema, null, true));
+          new ConfigSet("fakeConfigset", config, () -> IndexSchemaFactory.buildIndexSchema("schema_codec.xml", config), null, true));
       assertNull(coreContainer.registerCore(cd, c, false, false));
       h.coreName = newCoreName;
       assertEquals("We are not using the correct core", "solrconfig_codec2.xml", h.getCore().getConfigResource());