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 2019/07/21 18:21:17 UTC
[lucene-solr] branch jira/solr-13637_1 updated: SOLR-13637: commit
woth tests
This is an automated email from the ASF dual-hosted git repository.
noble pushed a commit to branch jira/solr-13637_1
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/jira/solr-13637_1 by this push:
new ff89417 SOLR-13637: commit woth tests
ff89417 is described below
commit ff8941728331b8ec35770bc62365cdeb2096c9de
Author: noble <no...@apache.org>
AuthorDate: Sun Jul 21 11:20:56 2019 -0700
SOLR-13637: commit woth tests
---
solr/core/src/java/org/apache/solr/api/ApiBag.java | 21 ++--
.../src/java/org/apache/solr/core/LibListener.java | 8 +-
.../java/org/apache/solr/core/MemClassLoader.java | 1 +
.../src/java/org/apache/solr/core/PluginBag.java | 117 ++++++++++++++----
.../src/java/org/apache/solr/core/PluginInfo.java | 25 +++-
.../src/java/org/apache/solr/core/SolrCore.java | 16 ++-
.../org/apache/solr/handler/SolrConfigHandler.java | 17 ++-
.../processor/UpdateRequestProcessorChain.java | 16 +--
.../src/java/org/apache/solr/util/CryptoKeys.java | 4 +-
.../solr/handler/TestContainerReqHandler.java | 135 ++++++++++++++++++++-
.../apache/solr/update/processor/RuntimeUrp.java | 2 +-
.../org/apache/solr/client/solrj/SolrResponse.java | 9 +-
.../apache/solr/common/util/CommandOperation.java | 9 +-
.../java/org/apache/solr/common/util/Utils.java | 7 ++
...nfig.Commands.addRequestHandler.properties.json | 2 +-
.../apispec/core.config.Commands.generic.json | 2 +-
16 files changed, 327 insertions(+), 64 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/api/ApiBag.java b/solr/core/src/java/org/apache/solr/api/ApiBag.java
index 8a3f972..5692f31 100644
--- a/solr/core/src/java/org/apache/solr/api/ApiBag.java
+++ b/solr/core/src/java/org/apache/solr/api/ApiBag.java
@@ -230,16 +230,21 @@ public class ApiBag {
}
public static class ReqHandlerToApi extends Api implements PermissionNameProvider {
- SolrRequestHandler rh;
+ PluginBag.PluginHolder<SolrRequestHandler> rh;
public ReqHandlerToApi(SolrRequestHandler rh, SpecProvider spec) {
super(spec);
+ this.rh = new PluginBag.PluginHolder(new PluginInfo(SolrRequestHandler.TYPE, Collections.emptyMap()),rh );
+ }
+
+ public ReqHandlerToApi(PluginBag.PluginHolder<SolrRequestHandler> rh, SpecProvider spec) {
+ super(spec);
this.rh = rh;
}
@Override
public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
- rh.handleRequest(req, rsp);
+ rh.get().handleRequest(req, rsp);
}
@Override
@@ -339,22 +344,22 @@ public class ApiBag {
}
public static class LazyLoadedApi extends Api {
-
- private final PluginBag.PluginHolder<SolrRequestHandler> holder;
private Api delegate;
protected LazyLoadedApi(SpecProvider specProvider, PluginBag.PluginHolder<SolrRequestHandler> lazyPluginHolder) {
super(specProvider);
- this.holder = lazyPluginHolder;
+ delegate = new ReqHandlerToApi(lazyPluginHolder, spec);
}
@Override
public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
- if (!holder.isLoaded()) {
- delegate = new ReqHandlerToApi(holder.get(), ApiBag.EMPTY_SPEC);
- }
delegate.call(req, rsp);
}
+
+ @Override
+ public ValidatingJsonMap getSpec() {
+ return super.getSpec();
+ }
}
}
diff --git a/solr/core/src/java/org/apache/solr/core/LibListener.java b/solr/core/src/java/org/apache/solr/core/LibListener.java
index cc3f4eb..463ad21 100644
--- a/solr/core/src/java/org/apache/solr/core/LibListener.java
+++ b/solr/core/src/java/org/apache/solr/core/LibListener.java
@@ -28,6 +28,7 @@ import java.util.Objects;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap;
+import org.apache.lucene.analysis.util.ResourceLoader;
import org.apache.solr.api.Api;
import org.apache.solr.api.V2HttpCall;
import org.apache.solr.common.IteratorWriter;
@@ -102,6 +103,9 @@ public class LibListener implements ClusterPropertiesListener {
log.info("clusterprops.json changed , version {}", coreContainer.getZkController().getZkStateReader().getClusterPropsVersion());
boolean forceReload = updateRuntimeLibs(properties);
extHandler.updateReqHandlers(properties, forceReload);
+ for (SolrCore core : coreContainer.solrCores.getCores()) {
+ core.globalClassLoaderChanged();
+ }
myversion = coreContainer.getZkController().getZkStateReader().getClusterPropsVersion();
return false;
}
@@ -130,7 +134,9 @@ public class LibListener implements ClusterPropertiesListener {
}
return needsReload[0];
}
-
+ public ResourceLoader getResourceLoader() {
+ return memClassLoader == null ? coreContainer.getResourceLoader() : memClassLoader;
+ }
void createNewClassLoader(Map m) {
boolean[] loadedAll = new boolean[1];
loadedAll[0] = true;
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 7bba195..5c1b3e1 100644
--- a/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
@@ -180,6 +180,7 @@ public class MemClassLoader extends ClassLoader implements AutoCloseable, Resour
try {
return findClass(cname).asSubclass(expectedType);
} catch (Exception e) {
+ log.error("Error loading class from runtime libs ", e);
if (e instanceof SolrException) {
throw (SolrException) e;
} else {
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 73ec51c..b5271b0 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginBag.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java
@@ -115,24 +115,36 @@ public class PluginBag<T> implements AutoCloseable {
return result;
}
- public PluginHolder<T> createPlugin(PluginInfo info) {
- if ("true".equals(String.valueOf(info.attributes.get(RuntimeLib.TYPE)))) {
- log.debug(" {} : '{}' created with runtimeLib=true ", meta.getCleanTag(), info.name);
- LazyPluginHolder<T> holder = new LazyPluginHolder<>(meta, info, core, RuntimeLib.isEnabled() ?
- core.getMemClassLoader() :
- core.getResourceLoader(), true);
+ private static <T> T createInitInstance(PluginInfo pluginInfo, SolrConfig.SolrPluginInfo pluginMeta,
+ SolrCore core, ResourceLoader resourceLoader,
+ boolean isRuntimeLib) {
+ T localInst = null;
+ try {
+ localInst = (T) core.createInstance(pluginInfo.className, pluginMeta.clazz, pluginMeta.getCleanTag(), core, resourceLoader);
+ } catch (SolrException e) {
+ if (isRuntimeLib && !(resourceLoader instanceof MemClassLoader)) {
+ throw new SolrException(SolrException.ErrorCode.getErrorCode(e.code()),
+ e.getMessage() + ". runtime library loading is not enabled, start Solr with -Denable.runtime.lib=true",
+ e.getCause());
+ }
+ throw e;
- return meta.clazz == UpdateRequestProcessorFactory.class ?
- (PluginHolder<T>) new UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder(holder) :
- holder;
- } else if ("lazy".equals(info.attributes.get("startup")) && meta.options.contains(SolrConfig.PluginOpts.LAZY)) {
- log.debug("{} : '{}' created with startup=lazy ", meta.getCleanTag(), info.name);
- return new LazyPluginHolder<T>(meta, info, core, core.getResourceLoader(), false);
- } else {
- T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.getCleanTag(), null, core.getResourceLoader());
- initInstance(inst, info);
- return new PluginHolder<>(info, inst);
+
+ }
+ initInstance(localInst, pluginInfo);
+ if (localInst instanceof SolrCoreAware) {
+ SolrResourceLoader.assertAwareCompatibility(SolrCoreAware.class, localInst);
+ ((SolrCoreAware) localInst).inform(core);
}
+ if (localInst instanceof ResourceLoaderAware) {
+ SolrResourceLoader.assertAwareCompatibility(ResourceLoaderAware.class, localInst);
+ try {
+ ((ResourceLoaderAware) localInst).inform(core.getResourceLoader());
+ } catch (IOException e) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "error initializing component", e);
+ }
+ }
+ return localInst;
}
/** make a plugin available in an alternate name. This is an internal API and not for public use
@@ -323,13 +335,52 @@ public class PluginBag<T> implements AutoCloseable {
}
}
+ public PluginHolder<T> createPlugin(PluginInfo info) {
+ String runtimeType = info.getRuntimeLibType();
+ if ("global".equals(runtimeType)) {
+ log.debug(" {} : '{}' created with runtimeLib=global ", meta.getCleanTag(), info.name);
+ PluginHolder<T> holder = new GlobalLoaderPluginHolder<T>(info, core, meta);
+ return meta.clazz == UpdateRequestProcessorFactory.class ?
+ (PluginHolder<T>) new UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder((PluginHolder<UpdateRequestProcessorFactory>) holder) :
+ holder;
+
+ } else if ("core".equals(String.valueOf(runtimeType))) {
+ log.debug(" {} : '{}' created with runtimeLib=true ", meta.getCleanTag(), info.name);
+ LazyPluginHolder<T> holder = new LazyPluginHolder<>(meta, info, core, RuntimeLib.isEnabled() ?
+ core.getMemClassLoader() :
+ core.getResourceLoader(), true);
+
+ return meta.clazz == UpdateRequestProcessorFactory.class ?
+ (PluginHolder<T>) new UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder((PluginHolder<UpdateRequestProcessorFactory>) holder) :
+ holder;
+ } else if ("lazy".equals(info.attributes.get("startup")) && meta.options.contains(SolrConfig.PluginOpts.LAZY)) {
+ log.debug("{} : '{}' created with startup=lazy ", meta.getCleanTag(), info.name);
+ return new LazyPluginHolder<T>(meta, info, core, core.getResourceLoader(), false);
+ } else {
+ T inst = core.createInstance(info.className, (Class<T>) meta.clazz, meta.getCleanTag(), null, core.getResourceLoader());
+ initInstance(inst, info);
+ return new PluginHolder<>(info, inst);
+ }
+ }
+
+ public Api v2lookup(String path, String method, Map<String, String> parts) {
+ if (apiBag == null) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "this should not happen, looking up for v2 API at the wrong place");
+ }
+ return apiBag.lookup(path, method, parts);
+ }
+
+ public ApiBag getApiBag() {
+ return apiBag;
+ }
+
/**
* An indirect reference to a plugin. It just wraps a plugin instance.
* subclasses may choose to lazily load the plugin
*/
public static class PluginHolder<T> implements AutoCloseable {
- private T inst;
protected final PluginInfo pluginInfo;
+ T inst;
boolean registerAPI = false;
public PluginHolder(PluginInfo info) {
@@ -425,7 +476,8 @@ public class PluginBag<T> implements AutoCloseable {
MemClassLoader loader = (MemClassLoader) resourceLoader;
loader.loadJars();
}
- Class<T> clazz = (Class<T>) pluginMeta.clazz;
+ lazyInst = createInitInstance(pluginInfo,pluginMeta,core,resourceLoader, isRuntimeLib);
+ /* Class<T> clazz = (Class<T>) pluginMeta.clazz;
T localInst = null;
try {
localInst = core.createInstance(pluginInfo.className, clazz, pluginMeta.getCleanTag(), null, resourceLoader);
@@ -452,22 +504,35 @@ public class PluginBag<T> implements AutoCloseable {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "error initializing component", e);
}
}
- lazyInst = localInst; // only assign the volatile until after the plugin is completely ready to use
+ lazyInst = localInst; // only assign the volatile until after the plugin is completely ready to use*/
return true;
}
}
- public Api v2lookup(String path, String method, Map<String, String> parts) {
- if (apiBag == null) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "this should not happen, looking up for v2 API at the wrong place");
+ public class GlobalLoaderPluginHolder<T> extends PluginHolder<T> {
+ private final SolrCore core;
+ private final SolrConfig.SolrPluginInfo pluginMeta;
+ private final LibListener libListener;
+
+ public GlobalLoaderPluginHolder(PluginInfo info, SolrCore core, SolrConfig.SolrPluginInfo pluginMeta) {
+ super(info);
+ this.core = core;
+ this.pluginMeta = pluginMeta;
+ this.core.addGlobalClassLoaderListener(() -> reload());
+ this.libListener = core.getCoreContainer().getClusterPropertiesListener();
+ reload();
}
- return apiBag.lookup(path, method, parts);
- }
- public ApiBag getApiBag() {
- return apiBag;
+
+ private void reload() {
+ if(inst == null) log.info("reloading plugin {} ", pluginInfo.name);
+ inst = createInitInstance(pluginInfo, pluginMeta, core, core.getCoreContainer().getClusterPropertiesListener().getResourceLoader(), true);
+ }
+
+
}
+
}
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 1bc85ae..b537105 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -16,14 +16,22 @@
*/
package org.apache.solr.core;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.util.DOMUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import java.util.*;
-
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
@@ -35,6 +43,8 @@ import static org.apache.solr.schema.FieldType.CLASS_NAME;
*
*/
public class PluginInfo implements MapSerializable {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
public final String name, className, type;
public final NamedList initArgs;
public final Map<String, String> attributes;
@@ -187,4 +197,15 @@ public class PluginInfo implements MapSerializable {
result.isFromSolrConfig = isFromSolrConfig;
return result;
}
+ public String getRuntimeLibType(){
+ Object runtimeType = attributes.get(RuntimeLib.TYPE);
+ if(runtimeType == null || "false".equals(runtimeType) || Boolean.FALSE.equals(runtimeType)) return null;
+ runtimeType = runtimeType.toString();
+ if ("true".equals(String.valueOf(runtimeType))) {
+ log.warn("runtimeLib = true is deprecated, use runtimeLib=core/global");
+ runtimeType = "core";
+ }
+ return runtimeType.toString();
+ }
+
}
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 be29e7a..19fcd14 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -238,6 +238,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
public volatile boolean searchEnabled = true;
public volatile boolean indexEnabled = true;
public volatile boolean readOnly = false;
+ private List<Runnable> globalClassLoaderListeners = new ArrayList<>();
public Set<String> getMetricNames() {
return metricNames;
@@ -352,6 +353,15 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
.getPath();
}
}
+ void globalClassLoaderChanged(){
+ for (Runnable r : globalClassLoaderListeners) {
+ r.run();
+
+ }
+ }
+ void addGlobalClassLoaderListener(Runnable r){
+ globalClassLoaderListeners.add(r);
+ }
/**
@@ -858,7 +868,11 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
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());
+ ResourceLoader resourceLoader = "global".equals(info.getRuntimeLibType())?
+ coreContainer.getClusterPropertiesListener().
+ getResourceLoader(): getResourceLoader();
+
+ T o = createInstance(info.className == null ? defClassName : info.className, cast, msg, this, resourceLoader);
if (o instanceof PluginInfoInitialized) {
((PluginInfoInitialized) o).init(info);
} else if (o instanceof NamedListInitializedPlugin) {
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 ce36017..6e917ea 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -600,6 +600,8 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
}
}
} catch (Exception e) {
+
+ log.error( "error executing commands "+ Utils.toJSONString(ops) ,e);
resp.setException(e);
resp.add(CommandOperation.ERR_MSGS, singletonList(SchemaManager.getErrorStr(e)));
}
@@ -788,7 +790,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
return overlay;
}
}
- if (!verifyClass(op, clz, info.clazz)) return overlay;
+ if (!verifyClass(op, clz, info)) return overlay;
if (pluginExists(info, overlay, name)) {
if (isCeate) {
op.addError(formatString(" ''{0}'' already exists . Do an ''{1}'' , if you want to change it ", name, "update-" + info.getTagCleanLower()));
@@ -812,12 +814,19 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
return overlay.getNamedPlugins(info.getCleanTag()).containsKey(name);
}
- private boolean verifyClass(CommandOperation op, String clz, Class expected) {
+ private boolean verifyClass(CommandOperation op, String clz, SolrConfig.SolrPluginInfo pluginMeta) {
if (clz == null) return true;
- if (!"true".equals(String.valueOf(op.getStr(RuntimeLib.TYPE, null)))) {
+ PluginInfo info = new PluginInfo(pluginMeta.getCleanTag(), op.getDataMap());
+ if(info.getRuntimeLibType() != null && !RuntimeLib.isEnabled()){
+ op.addError("node not started with enable.runtime.lib=true");
+ return false;
+ }
+
+
+ if ( !"true".equals(String.valueOf(op.getStr(RuntimeLib.TYPE, null)))) {
//this is not dynamically loaded so we can verify the class right away
try {
- req.getCore().createInitInstance(new PluginInfo(SolrRequestHandler.TYPE, op.getDataMap()), expected, clz, "");
+ req.getCore().createInitInstance(new PluginInfo(SolrRequestHandler.TYPE, op.getDataMap()), pluginMeta.clazz, clz, "");
} catch (Exception e) {
op.addError(e.getMessage());
return false;
diff --git a/solr/core/src/java/org/apache/solr/update/processor/UpdateRequestProcessorChain.java b/solr/core/src/java/org/apache/solr/update/processor/UpdateRequestProcessorChain.java
index eb3c08b..c45f0c6 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/UpdateRequestProcessorChain.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/UpdateRequestProcessorChain.java
@@ -328,7 +328,7 @@ public final class UpdateRequestProcessorChain implements PluginInfoInitialized
public static class LazyUpdateProcessorFactoryHolder extends PluginBag.PluginHolder<UpdateRequestProcessorFactory> {
private volatile UpdateRequestProcessorFactory lazyFactory;
- public LazyUpdateProcessorFactoryHolder(final PluginBag.LazyPluginHolder holder) {
+ public LazyUpdateProcessorFactoryHolder(final PluginBag.PluginHolder<UpdateRequestProcessorFactory> holder) {
super(holder.getPluginInfo());
lazyFactory = new LazyUpdateRequestProcessorFactory(holder);
}
@@ -340,26 +340,20 @@ public final class UpdateRequestProcessorChain implements PluginInfoInitialized
}
public class LazyUpdateRequestProcessorFactory extends UpdateRequestProcessorFactory {
- private final PluginBag.LazyPluginHolder holder;
- UpdateRequestProcessorFactory delegate;
+ private final PluginBag.PluginHolder<UpdateRequestProcessorFactory> holder;
- public LazyUpdateRequestProcessorFactory(PluginBag.LazyPluginHolder holder) {
+ public LazyUpdateRequestProcessorFactory(PluginBag.PluginHolder holder) {
this.holder = holder;
}
public UpdateRequestProcessorFactory getDelegate() {
- return delegate;
+ return holder.get();
}
@Override
public UpdateRequestProcessor getInstance(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next) {
- if (delegate != null) return delegate.getInstance(req, rsp, next);
+ return holder.get().getInstance(req, rsp, next);
- synchronized (this) {
- if (delegate == null)
- delegate = (UpdateRequestProcessorFactory) holder.get();
- }
- return delegate.getInstance(req, rsp, next);
}
}
}
diff --git a/solr/core/src/java/org/apache/solr/util/CryptoKeys.java b/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
index 7d9e32b..ede009a 100644
--- a/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
+++ b/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
@@ -72,11 +72,11 @@ public final class CryptoKeys implements CLIO {
boolean verified;
try {
verified = CryptoKeys.verify(entry.getValue(), Base64.base64ToByteArray(sig), data);
- log.info("verified {} ", verified);
+ log.debug("verified {} ", verified);
if (verified) return entry.getKey();
} catch (Exception e) {
exception = e;
- log.info("NOT verified ");
+ log.debug("NOT verified ");
}
}
diff --git a/solr/core/src/test/org/apache/solr/handler/TestContainerReqHandler.java b/solr/core/src/test/org/apache/solr/handler/TestContainerReqHandler.java
index fac0d0f..34656d8 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestContainerReqHandler.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestContainerReqHandler.java
@@ -18,6 +18,8 @@
package org.apache.solr.handler;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.List;
@@ -27,18 +29,24 @@ import java.util.function.Predicate;
import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableMap;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrClient;
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.impl.BaseHttpSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.response.V2Response;
+import org.apache.solr.cloud.ConfigRequest;
import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.cloud.ClusterProperties;
import org.apache.solr.common.cloud.SolrZkClient;
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.Pair;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.MemClassLoader;
@@ -54,6 +62,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.cloud.TestCryptoKeys.readFile;
+import static org.apache.solr.common.params.CommonParams.JAVABIN;
+import static org.apache.solr.common.params.CommonParams.WT;
import static org.apache.solr.common.util.Utils.getObjectByPath;
import static org.apache.solr.core.TestDynamicLoading.getFileContent;
import static org.apache.solr.core.TestDynamicLoadingUrl.runHttpServer;
@@ -98,7 +108,6 @@ public class TestContainerReqHandler extends SolrCloudTestCase {
} catch (Exception e) {
if (i >= repeats - 1) throw e;
- log.error("exception in request", e);
continue;
}
}
@@ -223,8 +232,8 @@ public class TestContainerReqHandler extends SolrCloudTestCase {
} finally {
- server.first().stop();
cluster.shutdown();
+ server.first().stop();
}
}
@@ -237,7 +246,7 @@ public class TestContainerReqHandler extends SolrCloudTestCase {
Pair<Server, Integer> server = runHttpServer(jars);
int port = server.second();
- MiniSolrCloudCluster cluster = configureCluster(4).configure();
+ MiniSolrCloudCluster cluster = configureCluster(4).configure();
try {
@@ -328,7 +337,7 @@ public class TestContainerReqHandler extends SolrCloudTestCase {
Pair<Server, Integer> server = runHttpServer(jars);
int port = server.second();
- MiniSolrCloudCluster cluster = configureCluster(4).configure();
+ MiniSolrCloudCluster cluster = configureCluster(4).configure();
try {
@@ -428,4 +437,122 @@ public class TestContainerReqHandler extends SolrCloudTestCase {
}
}
+
+ public void testPluginGlobalLoader() throws Exception {
+ String COLLECTION_NAME = "globalLoaderColl";
+ Map<String, Object> jars = Utils.makeMap(
+ "/jar1.jar", getFileContent("runtimecode/runtimelibs.jar.bin"),
+ "/jar2.jar", getFileContent("runtimecode/runtimelibs_v2.jar.bin"),
+ "/jar3.jar", getFileContent("runtimecode/runtimelibs_v3.jar.bin"));
+
+ Pair<Server, Integer> server = runHttpServer(jars);
+ int port = server.second();
+ System.setProperty("enable.runtime.lib", "true");
+ MiniSolrCloudCluster cluster = configureCluster(4)
+ .addConfig("conf", configset("cloud-minimal"))
+ .configure();
+ try {
+ CollectionAdminRequest
+ .createCollection(COLLECTION_NAME, "conf", 2, 1)
+ .setMaxShardsPerNode(100)
+ .process(cluster.getSolrClient());
+
+
+ cluster.waitForActiveCollection(COLLECTION_NAME, 2, 2);
+ String payload = "{add-runtimelib:{name : 'foo', url: 'http://localhost:" + port + "/jar1.jar', " +
+ "sha512 : 'd01b51de67ae1680a84a813983b1de3b592fc32f1a22b662fc9057da5953abd1b72476388ba342cad21671cd0b805503c78ab9075ff2f3951fdf75fa16981420'}}";
+ new V2Request.Builder("/cluster")
+ .withPayload(payload)
+ .withMethod(SolrRequest.METHOD.POST)
+ .build().process(cluster.getSolrClient());
+ assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "add-runtimelib/sha512"),
+ getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true, "runtimeLib/foo/sha512"));
+
+
+ payload = "{\n" +
+ "'create-requesthandler' : { 'name' : '/runtime', 'class': 'org.apache.solr.core.RuntimeLibReqHandler' , 'runtimeLib':global }," +
+ "'create-searchcomponent' : { 'name' : 'get', 'class': 'org.apache.solr.core.RuntimeLibSearchComponent' , 'runtimeLib':global }," +
+ "'create-queryResponseWriter' : { 'name' : 'json1', 'class': 'org.apache.solr.core.RuntimeLibResponseWriter' , 'runtimeLib':global }" +
+ "}";
+ cluster.getSolrClient().request(new ConfigRequest(payload) {
+ @Override
+ public String getCollection() {
+ return COLLECTION_NAME;
+ }
+ });
+
+
+ SolrParams params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME, WT, JAVABIN));
+ assertResponseValues(10,
+ cluster.getSolrClient(),
+ new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/overlay", params),
+ Utils.makeMap(
+ "overlay/queryResponseWriter/json1/class", "org.apache.solr.core.RuntimeLibResponseWriter",
+ "overlay/searchComponent/get/class", "org.apache.solr.core.RuntimeLibSearchComponent"
+ ));
+
+ assertResponseValues(10,
+ cluster.getSolrClient(),
+ new GenericSolrRequest(SolrRequest.METHOD.GET, "/runtime", params),
+ Utils.makeMap("class", "org.apache.solr.core.RuntimeLibReqHandler",
+ "loader", MemClassLoader.class.getName()));
+
+ assertResponseValues(10,
+ cluster.getSolrClient(),
+ new GenericSolrRequest(SolrRequest.METHOD.GET, "/get?abc=xyz", params),
+ Utils.makeMap("get", "org.apache.solr.core.RuntimeLibSearchComponent",
+ "loader", MemClassLoader.class.getName()));
+
+ GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/runtime",
+ new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME, WT, "json1")));
+ req.setResponseParser(new ResponseParser() {
+ @Override
+ public String getWriterType() {
+ return "json1";
+ }
+
+ @Override
+ public NamedList<Object> processResponse(InputStream body, String encoding) {
+ return new NamedList<>((Map) Utils.fromJSON(body));
+ }
+
+ @Override
+ public NamedList<Object> processResponse(Reader reader) {
+ return new NamedList<>((Map) Utils.fromJSON(reader));
+
+ }
+
+ });
+ assertResponseValues(10,
+ cluster.getSolrClient(),
+ req,
+ Utils.makeMap("wt", "org.apache.solr.core.RuntimeLibResponseWriter",
+ "loader", MemClassLoader.class.getName()));
+
+
+
+ payload = "{update-runtimelib:{name : 'foo', url: 'http://localhost:" + port + "/jar2.jar', " +
+ "sha512 : 'bc5ce45ad281b6a08fb7e529b1eb475040076834816570902acb6ebdd809410e31006efdeaa7f78a6c35574f3504963f5f7e4d92247d0eb4db3fc9abdda5d417'}}";
+ new V2Request.Builder("/cluster")
+ .withPayload(payload)
+ .withMethod(SolrRequest.METHOD.POST)
+ .build().process(cluster.getSolrClient());
+ assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "update-runtimelib/sha512"),
+ getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true, "runtimeLib/foo/sha512"));
+
+
+ assertResponseValues(10,
+ cluster.getSolrClient(),
+ new GenericSolrRequest(SolrRequest.METHOD.GET, "/get?abc=xyz", params),
+ Utils.makeMap("get", "org.apache.solr.core.RuntimeLibSearchComponent",
+ "loader", MemClassLoader.class.getName(),
+ "Version","2"));
+ } finally {
+ cluster.deleteAllCollections();
+ cluster.shutdown();
+ server.first().stop();
+ }
+
+ }
+
}
diff --git a/solr/core/src/test/org/apache/solr/update/processor/RuntimeUrp.java b/solr/core/src/test/org/apache/solr/update/processor/RuntimeUrp.java
index 889b0bf..6cee3d9 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/RuntimeUrp.java
+++ b/solr/core/src/test/org/apache/solr/update/processor/RuntimeUrp.java
@@ -31,7 +31,7 @@ public class RuntimeUrp extends SimpleUpdateProcessorFactory {
List<String> names = new ArrayList<>();
for (UpdateRequestProcessorFactory p : processorChain.getProcessors()) {
if (p instanceof UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder.LazyUpdateRequestProcessorFactory) {
- p = ((UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder.LazyUpdateRequestProcessorFactory) p).delegate;
+ p = ((UpdateRequestProcessorChain.LazyUpdateProcessorFactoryHolder.LazyUpdateRequestProcessorFactory) p).getDelegate();
}
names.add(p.getClass().getSimpleName());
}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrResponse.java b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrResponse.java
index ef52eb2..73eb863 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrResponse.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrResponse.java
@@ -18,10 +18,12 @@ package org.apache.solr.client.solrj;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import org.apache.solr.common.MapWriter;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.NamedList;
@@ -32,7 +34,7 @@ import org.apache.solr.common.util.NamedList;
*
* @since solr 1.3
*/
-public abstract class SolrResponse implements Serializable {
+public abstract class SolrResponse implements Serializable, MapWriter {
/** Elapsed time in milliseconds for the request as seen from the client. */
public abstract long getElapsedTime();
@@ -43,6 +45,11 @@ public abstract class SolrResponse implements Serializable {
public abstract NamedList<Object> getResponse();
+ @Override
+ public void writeMap(EntryWriter ew) throws IOException {
+ getResponse().writeMap(ew);
+ }
+
public Exception getException() {
NamedList exp = (NamedList) getResponse().get("exception");
if (exp == null) {
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/CommandOperation.java b/solr/solrj/src/java/org/apache/solr/common/util/CommandOperation.java
index 277324a..3804f78 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/CommandOperation.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/CommandOperation.java
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.apache.solr.common.MapWriter;
import org.apache.solr.common.SolrException;
import org.noggit.JSONParser;
import org.noggit.ObjectBuilder;
@@ -38,7 +39,7 @@ import static java.util.Collections.singletonMap;
import static org.apache.solr.common.util.StrUtils.formatString;
import static org.apache.solr.common.util.Utils.toJSON;
-public class CommandOperation {
+public class CommandOperation implements MapWriter {
public final String name;
private Object commandData;//this is most often a map
private List<String> errors = new ArrayList<>();
@@ -386,4 +387,10 @@ public class CommandOperation {
if (o == null) return null;
return getInt(name, null);
}
+
+ @Override
+ public void writeMap(EntryWriter ew) throws IOException {
+ ew.put(name, commandData);
+ ew.putIfNotNull("errors", errors);
+ }
}
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
index 4eb3a3c..847949f 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
@@ -722,4 +722,11 @@ public class Utils {
return def;
}
+ public static void main(String[] args) {
+ List<String> strings = StrUtils.splitSmart("overlay/requestHandler//runtime/class",
+ '/', true);
+ System.out.println(strings);
+
+ }
+
}
diff --git a/solr/solrj/src/resources/apispec/core.config.Commands.addRequestHandler.properties.json b/solr/solrj/src/resources/apispec/core.config.Commands.addRequestHandler.properties.json
index 731c3d8..6ee1498 100644
--- a/solr/solrj/src/resources/apispec/core.config.Commands.addRequestHandler.properties.json
+++ b/solr/solrj/src/resources/apispec/core.config.Commands.addRequestHandler.properties.json
@@ -10,7 +10,7 @@
"description": "The request handler class. Class names do not need to be fully qualified if they are included with Solr, so you can abbreviate the name as 'solr.SearchHandler'. Custom or third-party class names may need to be fully qualified, however."
},
"runtimeLib": {
- "type": "boolean",
+ "type": "string",
"description": "An optional parameter to use a custom .jar file that has been uploaded to Solr's blobstore. This additionally requires that the .jar has also been registered with the 'add-runtimelib' command, which is one of the available commands for the Config API."
},
"startup": {
diff --git a/solr/solrj/src/resources/apispec/core.config.Commands.generic.json b/solr/solrj/src/resources/apispec/core.config.Commands.generic.json
index 9d2b01d..2ebfdf8 100644
--- a/solr/solrj/src/resources/apispec/core.config.Commands.generic.json
+++ b/solr/solrj/src/resources/apispec/core.config.Commands.generic.json
@@ -10,7 +10,7 @@
"description": "The configuration item class. Class names do not need to be fully qualified if they are included with Solr, so you can abbreviate the name as 'solr.SearchHandler'. Custom or third-party class names may need to be fully qualified, however."
},
"runtimeLib": {
- "type": "boolean",
+ "type": "string",
"description": "An optional parameter to use a custom .jar file that has been uploaded to Solr's blobstore. This additionally requires that the .jar has also been registered with the 'add-runtimelib' command, which is one of the available commands for the Config API."
}
},