You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2020/06/28 05:12:18 UTC

[lucene-solr] branch branch_8x updated: SOLR-14404: support for openResource() in PackageResourceLoader & path-prefix for container plugins

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

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


The following commit(s) were added to refs/heads/branch_8x by this push:
     new 0065055  SOLR-14404: support for openResource() in PackageResourceLoader & path-prefix for container plugins
0065055 is described below

commit 00650552780225897e48cdf333a8c3f9f9ee963f
Author: Noble Paul <no...@users.noreply.github.com>
AuthorDate: Sun Jun 28 14:49:06 2020 +1000

    SOLR-14404: support for openResource() in PackageResourceLoader & path-prefix for container plugins
---
 .../apache/solr/api/CustomContainerPlugins.java    | 23 +++++++--
 .../java/org/apache/solr/pkg/PackageLoader.java    | 54 ++++++++++++++++++++++
 .../apache/solr/handler/TestContainerPlugin.java   | 50 ++++++++++++++++++--
 .../client/solrj/request/beans/PluginMeta.java     |  3 ++
 4 files changed, 123 insertions(+), 7 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java b/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
index 9246dac..6e2e0fb 100644
--- a/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
+++ b/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
@@ -23,15 +23,16 @@ import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.lucene.analysis.util.ResourceLoaderAware;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.request.beans.PluginMeta;
+import org.apache.solr.common.SolrException;
 import org.apache.solr.common.annotation.JsonProperty;
 import org.apache.solr.common.cloud.ClusterPropertiesListener;
 import org.apache.solr.common.util.Pair;
@@ -49,6 +50,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static org.apache.lucene.util.IOUtils.closeWhileHandlingException;
+import static org.apache.solr.common.util.Utils.makeMap;
 
 public class CustomContainerPlugins implements ClusterPropertiesListener {
   private final ObjectMapper mapper = SolrJacksonAnnotationInspector.createObjectMapper();
@@ -122,7 +124,7 @@ public class CustomContainerPlugins implements ClusterPropertiesListener {
         }
         if (e.getValue() == Diff.ADDED) {
           for (ApiHolder holder : apiInfo.holders) {
-            containerApiBag.register(holder, Collections.singletonMap("plugin-name", e.getKey()));
+            containerApiBag.register(holder, getTemplateVars(apiInfo.info));
           }
           currentPlugins.put(e.getKey(), apiInfo);
         } else {
@@ -134,7 +136,7 @@ public class CustomContainerPlugins implements ClusterPropertiesListener {
             if (oldApi instanceof ApiHolder) {
               replaced.add((ApiHolder) oldApi);
             }
-            containerApiBag.register(holder, Collections.singletonMap("plugin-name", e.getKey()));
+            containerApiBag.register(holder, getTemplateVars(apiInfo.info));
           }
           if (old != null) {
             for (ApiHolder holder : old.holders) {
@@ -151,6 +153,12 @@ public class CustomContainerPlugins implements ClusterPropertiesListener {
     }
   }
 
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  private static  Map<String, String> getTemplateVars(PluginMeta pluginMeta) {
+    Map result = makeMap("plugin-name", pluginMeta.name, "path-prefix", pluginMeta.pathPrefix);
+    return result;
+  }
+
   private static class ApiHolder extends Api {
     final AnnotatedApi api;
 
@@ -236,7 +244,7 @@ public class CustomContainerPlugins implements ClusterPropertiesListener {
             errs.add("The @EndPint must have exactly one method and path attributes");
           }
           List<String> pathSegments = StrUtils.splitSmart(endPoint.path()[0], '/', true);
-          PathTrie.replaceTemplates(pathSegments, Collections.singletonMap("plugin-name", info.name));
+          PathTrie.replaceTemplates(pathSegments, getTemplateVars(info));
           if (V2HttpCall.knownPrefixes.contains(pathSegments.get(0))) {
             errs.add("path must not have a prefix: "+pathSegments.get(0));
           }
@@ -270,6 +278,13 @@ public class CustomContainerPlugins implements ClusterPropertiesListener {
       } else {
         throw new RuntimeException("Must have a no-arg constructor or CoreContainer constructor ");
       }
+      if (instance instanceof ResourceLoaderAware) {
+        try {
+          ((ResourceLoaderAware) instance).inform(pkgVersion.getLoader());
+        } catch (IOException e) {
+          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+        }
+      }
       this.holders = new ArrayList<>();
       for (Api api : AnnotatedApi.getApis(instance)) {
         holders.add(new ApiHolder((AnnotatedApi) api));
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 1089288..63e801e 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageLoader.java
@@ -18,18 +18,27 @@
 package org.apache.solr.pkg;
 
 import java.io.Closeable;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.util.SimplePostTool;
+import org.apache.zookeeper.server.ByteBufferInputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -303,9 +312,12 @@ public class PackageLoader implements Closeable {
     }
   }
   static class PackageResourceLoader extends SolrResourceLoader {
+    List<Path> paths;
+
 
     PackageResourceLoader(String name, List<Path> classpath, Path instanceDir, ClassLoader parent) {
       super(name, classpath, instanceDir, parent);
+      this.paths = classpath;
     }
 
     @Override
@@ -329,6 +341,48 @@ public class PackageLoader implements Closeable {
     public  <T> void addToInfoBeans(T obj) {
       //do not do anything. It should be handled externally
     }
+
+    @Override
+    public InputStream openResource(String resource) throws IOException {
+      for (Path path : paths) {
+        try(FileInputStream in = new FileInputStream(path.toFile())) {
+          ZipInputStream zis = new ZipInputStream(in);
+          try {
+            ZipEntry entry;
+            while ((entry = zis.getNextEntry()) != null) {
+              if (resource == null || resource.equals(entry.getName())) {
+                SimplePostTool.BAOS out = new SimplePostTool.BAOS();
+                byte[] buffer = new byte[2048];
+                int size;
+                while ((size = zis.read(buffer, 0, buffer.length)) != -1) {
+                  out.write(buffer, 0, size);
+                }
+                out.close();
+                return new ByteBufferStream(out.getByteBuffer());
+              }
+            }
+          } finally {
+            zis.closeEntry();
+          }
+        }
+      }
+
+      return null;
+    }
+  }
+
+  private static class ByteBufferStream extends ByteBufferInputStream implements Supplier<ByteBuffer> {
+    private final ByteBuffer buf ;
+
+    public ByteBufferStream(ByteBuffer buf) {
+      super(buf);
+      this.buf = buf;
+    }
+
+    @Override
+    public ByteBuffer get() {
+      return buf;
+    }
   }
 
   private static String findBiggest(String lessThan, List<String> sortedList) {
diff --git a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
index da9696c..f4115d4 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
@@ -18,11 +18,16 @@
 package org.apache.solr.handler;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
 import java.util.Map;
 import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
 import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
+import org.apache.lucene.analysis.util.ResourceLoader;
+import org.apache.lucene.analysis.util.ResourceLoaderAware;
 
 import com.google.common.collect.ImmutableMap;
 import org.apache.solr.api.Command;
@@ -39,6 +44,7 @@ import org.apache.solr.cloud.MiniSolrCloudCluster;
 import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.NavigableObject;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.filestore.PackageStoreAPI;
 import org.apache.solr.filestore.TestDistribPackageStore;
 import org.apache.solr.filestore.TestDistribPackageStore.Fetcher;
@@ -125,9 +131,12 @@ public class TestContainerPlugin extends SolrCloudTestCase {
       //test with a class  @EndPoint methods. This also uses a template in the path name
       plugin.klass = C4.class.getName();
       plugin.name = "collections";
+      plugin.pathPrefix = "collections";
       expectError(req, cluster.getSolrClient(), errPath, "path must not have a prefix: collections");
 
       plugin.name = "my-random-name";
+      plugin.pathPrefix = "my-random-prefix";
+
       req.process(cluster.getSolrClient());
 
       //let's test the plugin
@@ -139,7 +148,7 @@ public class TestContainerPlugin extends SolrCloudTestCase {
           ImmutableMap.of("/method.name", "m1"));
 
   TestDistribPackageStore.assertResponseValues(10,
-          () -> new V2Request.Builder("/my-random-name/their/plugin")
+          () -> new V2Request.Builder("/my-random-prefix/their/plugin")
               .forceV2(true)
               .withMethod(GET)
               .build().process(cluster.getSolrClient()),
@@ -189,7 +198,7 @@ public class TestContainerPlugin extends SolrCloudTestCase {
       plugin.name = "myplugin";
       plugin.klass = "mypkg:org.apache.solr.handler.MyPlugin";
       plugin.version = add.version;
-      V2Request req1 = new V2Request.Builder("/cluster/plugin")
+      final V2Request req1 = new V2Request.Builder("/cluster/plugin")
           .forceV2(true)
           .withMethod(POST)
           .withPayload(singletonMap("add", plugin))
@@ -240,11 +249,46 @@ public class TestContainerPlugin extends SolrCloudTestCase {
       TestDistribPackageStore.assertResponseValues(10,
           invokePlugin,
           ImmutableMap.of("/myplugin.version", "2.0"));
+
+      plugin.name = "plugin2";
+      plugin.klass = "mypkg:"+ C5.class.getName();
+      plugin.version = "2.0";
+      req1.process(cluster.getSolrClient());
+      assertNotNull(C5.classData);
+      assertEquals( 1452, C5.classData.limit());
     } finally {
       cluster.shutdown();
     }
   }
 
+  public static class C5 implements ResourceLoaderAware {
+    static ByteBuffer classData;
+    private  SolrResourceLoader resourceLoader;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void inform(ResourceLoader loader) throws IOException {
+      this.resourceLoader = (SolrResourceLoader) loader;
+      try {
+        InputStream is = resourceLoader.openResource("org/apache/solr/handler/MyPlugin.class");
+        if (is instanceof Supplier) {
+          classData = ((Supplier<ByteBuffer>) is).get();
+        }
+      } catch (IOException e) {
+        //do not do anything
+      }
+    }
+
+    @EndPoint(method = GET,
+        path = "/$plugin-name/m2",
+        permission = PermissionNameProvider.Name.COLL_READ_PERM)
+    public void m2() {
+
+
+    }
+
+  }
+
   public static class C1 {
 
   }
@@ -280,7 +324,7 @@ public class TestContainerPlugin extends SolrCloudTestCase {
     }
 
     @EndPoint(method = GET,
-        path = "$plugin-name/their/plugin",
+        path = "$path-prefix/their/plugin",
         permission = PermissionNameProvider.Name.READ_PERM)
     public void m2(SolrQueryRequest req, SolrQueryResponse rsp) {
       rsp.add("method.name", "m2");
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/PluginMeta.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/PluginMeta.java
index f06c849..80098ca 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/PluginMeta.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/PluginMeta.java
@@ -35,6 +35,9 @@ public class PluginMeta implements ReflectMapWriter {
   @JsonProperty
   public String version;
 
+  @JsonProperty("path-prefix")
+  public String pathPrefix;
+
 
   public PluginMeta copy() {
     PluginMeta result = new PluginMeta();