diff --git a/gradle/maven/defaults-maven.gradle b/gradle/maven/defaults-maven.gradle
index 2662a69a25d..443d6904f0a 100644
--- a/gradle/maven/defaults-maven.gradle
+++ b/gradle/maven/defaults-maven.gradle
@@ -66,6 +66,7 @@ configure(rootProject) {
":solr:contrib:langid",
":solr:contrib:jaegertracer-configurator",
":solr:contrib:prometheus-exporter",
+ ":solr:contrib:scripting",
":solr:test-framework",
]
diff --git a/settings.gradle b/settings.gradle
index be2c09cc235..494c7102de2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -65,6 +65,7 @@ include "solr:contrib:extraction"
include "solr:contrib:langid"
include "solr:contrib:jaegertracer-configurator"
include "solr:contrib:prometheus-exporter"
+include "solr:contrib:scripting"
include "solr:contrib:ltr"
include "solr:webapp"
include "solr:test-framework"
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 4ce0332d68e..7a17a75f75f 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -188,6 +188,9 @@ Other Changes
* SOLR-14297: Replace commons-codec Base64 with JDK8 Base64 (Andras Salamon via Houston Putman)
+* SOLR-14067: StatelessScriptUpdateProcessorFactory moved to it's own /contrib/scripting/ package instead
+ of shipping as part of Solr due to security concerns. Renamed to ScriptUpdateProcessorFactory for simpler name. (Eric Pugh)
+
Bug Fixes
---------------------
* SOLR-14546: Fix for a relatively hard to hit issue in OverseerTaskProcessor that could lead to out of order execution
diff --git a/solr/contrib/scripting/README.md b/solr/contrib/scripting/README.md
new file mode 100644
index 00000000000..3436a65ca6d
--- /dev/null
+++ b/solr/contrib/scripting/README.md
@@ -0,0 +1,14 @@
+Welcome to Apache Solr Scripting!
+===============================
+
+# Introduction
+
+The Scripting contrib module pulls together various scripting related functions.
+
+Today, the ScriptUpdateProcessorFactory allows Java scripting engines to support scripts written in languages such as JavaScript, Ruby, Python, and Groovy to be used during Solr document update processing, allowing dramatic flexibility in expressing custom document processing before being indexed. It exposes hooks for commit, delete, etc, but add is the most common usage. It is implemented as an UpdateProcessor to be placed in an UpdateChain.
+
+## Getting Started
+
+For information on how to get started please see:
+ * [Solr Reference Guide's section on Update Request Processors](https://lucene.apache.org/solr/guide/update-request-processors.html)
+ * [Solr Reference Guide's section on ScriptUpdateProcessorFactory](https://lucene.apache.org/solr/guide/script-update-processor.html)
diff --git a/solr/contrib/scripting/build.gradle b/solr/contrib/scripting/build.gradle
new file mode 100644
index 00000000000..32f4e1ec419
--- /dev/null
+++ b/solr/contrib/scripting/build.gradle
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+apply plugin: 'java-library'
+
+description = 'Scripting Package'
+
+dependencies {
+ implementation project(':solr:core')
+ testImplementation project(':solr:test-framework')
+}
diff --git a/solr/core/src/java/org/apache/solr/update/processor/ScriptEngineCustomizer.java b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptEngineCustomizer.java
similarity index 96%
rename from solr/core/src/java/org/apache/solr/update/processor/ScriptEngineCustomizer.java
rename to solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptEngineCustomizer.java
index f230526b624..05dd604ba80 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/ScriptEngineCustomizer.java
+++ b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptEngineCustomizer.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.solr.update.processor;
+package org.apache.solr.scripting.update;
import javax.script.ScriptEngine;
diff --git a/solr/core/src/java/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactory.java b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
similarity index 89%
rename from solr/core/src/java/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactory.java
rename to solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
index d2f5a07173f..e0de01bec1e 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactory.java
+++ b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.solr.update.processor;
+package org.apache.solr.scripting.update;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
@@ -26,6 +26,8 @@ import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.update.*;
+import org.apache.solr.update.processor.UpdateRequestProcessor;
+import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.FilenameUtils;
@@ -58,34 +60,33 @@ import org.slf4j.LoggerFactory;
/**
*
- * An update request processor factory that enables the use of update
- * processors implemented as scripts which can be loaded by the
- * {@link SolrResourceLoader} (usually via the conf
dir for
- * the SolrCore).
+ * An update request processor factory that enables the use of update
+ * processors implemented as scripts which can be loaded from the
+ * configSet. Previously known as the StatelessScriptUpdateProcessorFactory.
*
*
* This factory requires at least one configuration parameter named
- * script
which may be the name of a script file as a string,
- * or an array of multiple script files. If multiple script files are
- * specified, they are executed sequentially in the order specified in the
+ * script
which may be the name of a script file as a string,
+ * or an array of multiple script files. If multiple script files are
+ * specified, they are executed sequentially in the order specified in the
* configuration -- as if multiple factories were configured sequentially
*
*
- * Each script file is expected to declare functions with the same name
- * as each method in {@link UpdateRequestProcessor}, using the same
- * arguments. One slight deviation is in the optional return value from
- * these functions: If a script function has a boolean
return
- * value, and that value is false
then the processor will
- * cleanly terminate processing of the command and return, without forwarding
+ * Each script file is expected to declare functions with the same name
+ * as each method in {@link UpdateRequestProcessor}, using the same
+ * arguments. One slight deviation is in the optional return value from
+ * these functions: If a script function has a boolean
return
+ * value, and that value is false
then the processor will
+ * cleanly terminate processing of the command and return, without forwarding
* the command on to the next script or processor in the chain.
- * Due to limitations in the {@link ScriptEngine} API used by
+ * Due to limitations in the {@link ScriptEngine} API used by
* this factory, it can not enforce that all functions exist on initialization,
* so errors from missing functions will only be generated at runtime when
* the chain attempts to use them.
*
*
- * The factory may also be configured with an optional "params" argument,
- * which can be an {@link NamedList} (or array, or any other simple Java
+ * The factory may also be configured with an optional "params" argument,
+ * which can be an {@link NamedList} (or array, or any other simple Java
* object) which will be put into the global scope for each script.
*
*
@@ -97,40 +98,40 @@ import org.slf4j.LoggerFactory;
*
params - The "params" init argument in the factory configuration (if any)
*
*
- * Internally this update processor uses JDK 6 scripting engine support,
- * and any {@link Invocable} implementations of ScriptEngine
- * that can be loaded using the Solr Plugin ClassLoader may be used.
- * By default, the engine used for each script is determined by the filed
- * extension (ie: a *.js file will be treated as a JavaScript script) but
- * this can be overridden by specifying an explicit "engine" name init
- * param for the factory, which identifies a registered name of a
- * {@link ScriptEngineFactory}.
- * (This may be particularly useful if multiple engines are available for
- * the same scripting language, and you wish to force the usage of a
+ * Internally this update processor uses JDK 6 scripting engine support,
+ * and any {@link Invocable} implementations of ScriptEngine
+ * that can be loaded using the Solr Plugin ClassLoader may be used.
+ * By default, the engine used for each script is determined by the file
+ * extension (ie: a *.js file will be treated as a JavaScript script) but
+ * this can be overridden by specifying an explicit "engine" name init
+ * param for the factory, which identifies a registered name of a
+ * {@link ScriptEngineFactory}.
+ * (This may be particularly useful if multiple engines are available for
+ * the same scripting language, and you wish to force the usage of a
* particular engine because of known quirks)
*
*
- * A new {@link ScriptEngineManager} is created for each
- * SolrQueryRequest
defining a "global" scope for the script(s)
- * which is request specific. Separate ScriptEngine
instances
- * are then used to evaluate the script files, resulting in an "engine" scope
+ * A new {@link ScriptEngineManager} is created for each
+ * SolrQueryRequest
defining a "global" scope for the script(s)
+ * which is request specific. Separate ScriptEngine
instances
+ * are then used to evaluate the script files, resulting in an "engine" scope
* that is specific to each script.
*
*
* A simple example...
*
*
- * <processor class="solr.StatelessScriptUpdateProcessorFactory">
+ * <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
* <str name="script">updateProcessor.js</str>
* </processor>
*
*
- * A more complex example involving multiple scripts in different languages,
- * and a "params" NamedList
that will be put into the global
+ * A more complex example involving multiple scripts in different languages,
+ * and a "params" NamedList
that will be put into the global
* scope of each script...
*
*
- * <processor class="solr.StatelessScriptUpdateProcessorFactory">
+ * <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
* <arr name="script">
* <str name="script">first-processor.js</str>
* <str name="script">second-processor.py</str>
@@ -142,11 +143,11 @@ import org.slf4j.LoggerFactory;
* </processor>
*
*
- * An example where the script file extensions are ignored, and an
+ * An example where the script file extensions are ignored, and an
* explicit script engine is used....
*
*
- * <processor class="solr.StatelessScriptUpdateProcessorFactory">
+ * <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
* <arr name="script">
* <str name="script">first-processor.txt</str>
* <str name="script">second-processor.txt</str>
@@ -154,10 +155,10 @@ import org.slf4j.LoggerFactory;
* <str name="engine">rhino</str>
* </processor>
*
- *
+ *
* @since 4.0.0
*/
-public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
+public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -182,8 +183,8 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
Collection scripts =
args.removeConfigArgs(SCRIPT_ARG);
if (scripts.isEmpty()) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
- "StatelessScriptUpdateProcessorFactory must be " +
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "ScriptUpdateProcessorFactory must be " +
"initialized with at least one " + SCRIPT_ARG);
}
scriptFiles = new ArrayList<>();
@@ -199,8 +200,8 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
engineName = (String)engine;
} else {
throw new SolrException
- (SolrException.ErrorCode.SERVER_ERROR,
- "'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
+ (SolrException.ErrorCode.SERVER_ERROR,
+ "'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
engine.getClass() + ")");
}
}
@@ -246,7 +247,7 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
req.close();
}
-
+
}
@@ -259,13 +260,13 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
* @param rsp The solr response
* @return The list of initialized script engines.
*/
- private List initEngines(SolrQueryRequest req,
- SolrQueryResponse rsp)
+ private List initEngines(SolrQueryRequest req,
+ SolrQueryResponse rsp)
throws SolrException {
-
+
List scriptEngines = new ArrayList<>();
- ScriptEngineManager scriptEngineManager
+ ScriptEngineManager scriptEngineManager
= new ScriptEngineManager(resourceLoader.getClassLoader());
scriptEngineManager.put("logger", log);
@@ -281,10 +282,10 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
engine = scriptEngineManager.getEngineByName(engineName);
if (engine == null) {
String details = getSupportedEngines(scriptEngineManager, false);
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"No ScriptEngine found by name: "
- + engineName +
- (null != details ?
+ + engineName +
+ (null != details ?
" -- supported names: " + details : ""));
}
} else {
@@ -292,18 +293,18 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
(scriptFile.getExtension());
if (engine == null) {
String details = getSupportedEngines(scriptEngineManager, true);
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"No ScriptEngine found by file extension: "
- + scriptFile.getFileName() +
- (null != details ?
+ + scriptFile.getFileName() +
+ (null != details ?
" -- supported extensions: " + details : ""));
-
+
}
}
if (! (engine instanceof Invocable)) {
- String msg =
- "Engine " + ((null != engineName) ? engineName :
+ String msg =
+ "Engine " + ((null != engineName) ? engineName :
("for script " + scriptFile.getFileName())) +
" does not support function invocation (via Invocable): " +
engine.getClass().toString() + " (" +
@@ -319,7 +320,7 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
scriptEngines.add(new EngineInfo((Invocable)engine, scriptFile));
try {
Reader scriptSrc = scriptFile.openReader(resourceLoader);
-
+
try {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
@@ -333,23 +334,23 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
throw (ScriptException) e.getException();
}
} catch (ScriptException e) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
- "Unable to evaluate script: " +
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "Unable to evaluate script: " +
scriptFile.getFileName(), e);
} finally {
IOUtils.closeQuietly(scriptSrc);
}
} catch (IOException ioe) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
- "Unable to evaluate script: " +
- scriptFile.getFileName(), ioe);
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "Unable to evaluate script: " +
+ scriptFile.getFileName(), ioe);
}
}
return scriptEngines;
}
/**
- * For error messages - returns null if there are any exceptions of any
+ * For error messages - returns null if there are any exceptions of any
* kind building the string (or of the list is empty for some unknown reason).
* @param ext - if true, list of extensions, otherwise a list of engine names
*/
@@ -403,7 +404,7 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
if (invokeFunction("processDelete", cmd)) {
super.processDelete(cmd);
}
-
+
}
@Override
@@ -435,9 +436,9 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
}
/**
- * returns true if processing should continue, or false if the
- * request should be ended now. Result value is computed from the return
- * value of the script function if: it exists, is non-null, and can be
+ * returns true if processing should continue, or false if the
+ * request should be ended now. Result value is computed from the return
+ * value of the script function if: it exists, is non-null, and can be
* cast to a java Boolean.
*/
private boolean invokeFunction(String name, Object... cmd) {
@@ -461,10 +462,10 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
}
} catch (ScriptException | NoSuchMethodException e) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
- "Unable to invoke function " + name +
- " in script: " +
- engine.getScriptFile().getFileName() +
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "Unable to invoke function " + name +
+ " in script: " +
+ engine.getScriptFile().getFileName() +
": " + e.getMessage(), e);
}
}
diff --git a/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/package-info.java b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/package-info.java
new file mode 100644
index 00000000000..5bf10665b9d
--- /dev/null
+++ b/solr/contrib/scripting/src/java/org/apache/solr/scripting/update/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Support for scripting during document updates.
+ */
+package org.apache.solr.scripting.update;
diff --git a/solr/contrib/scripting/src/java/overview.html b/solr/contrib/scripting/src/java/overview.html
new file mode 100644
index 00000000000..82eb0f8bebf
--- /dev/null
+++ b/solr/contrib/scripting/src/java/overview.html
@@ -0,0 +1,26 @@
+
+
+
+Apache Solr Search Server: Scripting contrib
+
+
+This package provides an Update Processor that allows for Java scripting engines
+to be used during the Solr document update processing.
+
+
+
diff --git a/solr/core/src/test-files/solr/collection1/conf/addfields.updateprocessor.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/addfields.updateprocessor.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/addfields.updateprocessor.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/addfields.updateprocessor.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml
similarity index 93%
rename from solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml
index ded7416f1ad..9bc55069154 100644
--- a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-bogus-scriptengine-name.xml
@@ -22,7 +22,7 @@
${tests.luceneMatchVersion:LATEST}
-
+
giberish
missleading.extension.updateprocessor.js.txt
diff --git a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml
similarity index 89%
rename from solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml
index 709774d6a22..354277910b3 100644
--- a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-invalid-scriptfile.xml
@@ -22,10 +22,10 @@
${tests.luceneMatchVersion:LATEST}
-
+
javascript
- currency.xml
+ invalid.script.xml
diff --git a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml
similarity index 93%
rename from solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml
index d13ba0b0ad6..ed43d9f8910 100644
--- a/solr/core/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/bad-solrconfig-missing-scriptfile.xml
@@ -22,7 +22,7 @@
${tests.luceneMatchVersion:LATEST}
-
+
a-file-name-that-does-not-exist.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/conditional.updateprocessor.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/conditional.updateprocessor.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/conditional.updateprocessor.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/conditional.updateprocessor.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/cross-compatible.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/cross-compatible.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/cross-compatible.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/cross-compatible.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/evil.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/evil.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/evil.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/evil.js
diff --git a/solr/contrib/scripting/src/test-files/solr/collection1/conf/invalid.script.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/invalid.script.xml
new file mode 100644
index 00000000000..c8455af0ed9
--- /dev/null
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/invalid.script.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/solr/core/src/test-files/solr/collection1/conf/missing.functions.updateprocessor.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/missing.functions.updateprocessor.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/missing.functions.updateprocessor.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/missing.functions.updateprocessor.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/missleading.extension.updateprocessor.js.txt b/solr/contrib/scripting/src/test-files/solr/collection1/conf/missleading.extension.updateprocessor.js.txt
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/missleading.extension.updateprocessor.js.txt
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/missleading.extension.updateprocessor.js.txt
diff --git a/solr/contrib/scripting/src/test-files/solr/collection1/conf/schema.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/schema.xml
new file mode 100644
index 00000000000..140f12bd41a
--- /dev/null
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/schema.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+
+
+
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml
similarity index 78%
rename from solr/core/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml
index 74f00fd4ef6..afa5a7c56d7 100644
--- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig-script-updateprocessor.xml
@@ -18,7 +18,7 @@
-->
@@ -29,7 +29,7 @@
-
+
javascript
missleading.extension.updateprocessor.js.txt
@@ -42,7 +42,7 @@
-
+
trivial.updateprocessor0.js
true
@@ -53,7 +53,7 @@
-
+
trivial.updateprocessor0.js
trivial.updateprocessor1.js
@@ -67,7 +67,7 @@
-
+
trivial.updateprocessor0.js
trivial.updateprocessor1.js
@@ -79,46 +79,46 @@
-
-
+
conditional.updateprocessor.js
addfields.updateprocessor.js
-
-
+
conditional.updateprocessor.js
-
+
addfields.updateprocessor.js
-
+
throw.error.on.add.updateprocessor.js
-
+
missing.functions.updateprocessor.js
-
+
cross-compatible.js
-
+
evil.js
diff --git a/solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml
new file mode 100644
index 00000000000..de5c714aa23
--- /dev/null
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+ ${useCompoundFile:false}
+
+ ${solr.tests.maxBufferedDocs}
+ ${solr.tests.ramBufferSizeMB}
+ ${solr.tests.maxCommitMergeWaitTime:-1}
+ ${solr.tests.ramPerThreadHardLimitMB}
+
+
+
+ 1000
+ 10000
+
+
+ ${solr.tests.lockType:single}
+
+ ${solr.tests.infostream:false}
+
+
diff --git a/solr/contrib/scripting/src/test-files/solr/collection1/conf/stateless-solrconfig-script-updateprocessor.xml b/solr/contrib/scripting/src/test-files/solr/collection1/conf/stateless-solrconfig-script-updateprocessor.xml
new file mode 100644
index 00000000000..58fbb862860
--- /dev/null
+++ b/solr/contrib/scripting/src/test-files/solr/collection1/conf/stateless-solrconfig-script-updateprocessor.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ ${tests.luceneMatchVersion:LATEST}
+
+
+
+
+
+
+
+ javascript
+ missleading.extension.updateprocessor.js.txt
+
+
+
+
+
+
+
+
+
+
+
+ trivial.updateprocessor0.js
+
+ true
+ 1
+
+
+
+
+
+
+
+
+ trivial.updateprocessor0.js
+ trivial.updateprocessor1.js
+
+
+ true
+ 1
+
+
+
+
+
+
+
+ trivial.updateprocessor0.js
+ trivial.updateprocessor1.js
+
+ true
+ 1
+
+
+
+
+
+
+
+
+ conditional.updateprocessor.js
+ addfields.updateprocessor.js
+
+
+
+
+
+
+ conditional.updateprocessor.js
+
+
+ addfields.updateprocessor.js
+
+
+
+
+
+ throw.error.on.add.updateprocessor.js
+
+
+
+
+
+ missing.functions.updateprocessor.js
+
+
+
+
+
+ cross-compatible.js
+
+
+
+
+
+ evil.js
+
+
+
+
diff --git a/solr/core/src/test-files/solr/collection1/conf/throw.error.on.add.updateprocessor.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/throw.error.on.add.updateprocessor.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/throw.error.on.add.updateprocessor.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/throw.error.on.add.updateprocessor.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/trivial.updateprocessor0.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/trivial.updateprocessor0.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/trivial.updateprocessor0.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/trivial.updateprocessor0.js
diff --git a/solr/core/src/test-files/solr/collection1/conf/trivial.updateprocessor1.js b/solr/contrib/scripting/src/test-files/solr/collection1/conf/trivial.updateprocessor1.js
similarity index 100%
rename from solr/core/src/test-files/solr/collection1/conf/trivial.updateprocessor1.js
rename to solr/contrib/scripting/src/test-files/solr/collection1/conf/trivial.updateprocessor1.js
diff --git a/solr/core/src/test/org/apache/solr/update/processor/ScriptEngineTest.java b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptEngineTest.java
similarity index 98%
rename from solr/core/src/test/org/apache/solr/update/processor/ScriptEngineTest.java
rename to solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptEngineTest.java
index 8a913e16426..e0bd83ba736 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/ScriptEngineTest.java
+++ b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptEngineTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.solr.update.processor;
+package org.apache.solr.scripting.update;
import org.apache.lucene.util.Constants;
diff --git a/solr/core/src/test/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactoryTest.java b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptUpdateProcessorFactoryTest.java
similarity index 87%
rename from solr/core/src/test/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactoryTest.java
rename to solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptUpdateProcessorFactoryTest.java
index 09dd7839995..0a53db04393 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactoryTest.java
+++ b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/ScriptUpdateProcessorFactoryTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.solr.update.processor;
+package org.apache.solr.scripting.update;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@@ -25,24 +25,26 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.core.SolrCore;
+import org.apache.solr.update.processor.UpdateProcessorTestBase;
+import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.junit.Assume;
import org.junit.BeforeClass;
/**
- * Tests {@link StatelessScriptUpdateProcessorFactory}.
+ * Tests {@link ScriptUpdateProcessorFactory}.
*
- * TODO: This test, to run from an IDE, requires a working directory of <path-to>/solr/core/src/test-files. Fix!
+ * TODO: This test, to run from an IDE, requires a working directory of <path-to>/solr/contrib/scripting/src/test-files. Fix!
*/
-public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
+public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
@BeforeClass
public static void beforeClass() throws Exception {
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
- initCore("solrconfig-script-updateprocessor.xml", "schema12.xml");
+ initCore("solrconfig-script-updateprocessor.xml", "schema.xml");
}
/**
- * simple test of a basic script processor chain using the full
+ * simple test of a basic script processor chain using the full
* RequestHandler + UpdateProcessorChain flow
*/
public void testFullRequestHandlerFlow() throws Exception {
@@ -62,13 +64,13 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
// clean up
processDeleteById("run-no-scripts","4055");
processCommit("run-no-scripts");
-
+
}
public void testSingleScript() throws Exception {
SolrCore core = h.getCore();
UpdateRequestProcessorChain chained = core.getUpdateProcessingChain("single-script");
- final StatelessScriptUpdateProcessorFactory factory = ((StatelessScriptUpdateProcessorFactory) chained.getProcessors().get(0));
+ final ScriptUpdateProcessorFactory factory = ((ScriptUpdateProcessorFactory) chained.getProcessors().get(0));
final List functionMessages = new ArrayList<>();
factory.setScriptEngineCustomizer(new ScriptEngineCustomizer() {
@Override
@@ -91,7 +93,7 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
processDeleteById("single-script","1");
processCommit("single-script");
-
+
assertQ("found deleted doc",
req("q","id:1")
, "//result[@numFound=0]");
@@ -108,12 +110,12 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
public void testMultipleScripts() throws Exception {
SolrCore core = h.getCore();
- for (final String chain : new String[] {"dual-scripts-arr",
+ for (final String chain : new String[] {"dual-scripts-arr",
"dual-scripts-strs"}) {
-
+
UpdateRequestProcessorChain chained = core.getUpdateProcessingChain(chain);
- final StatelessScriptUpdateProcessorFactory factory =
- ((StatelessScriptUpdateProcessorFactory) chained.getProcessors().get(0));
+ final ScriptUpdateProcessorFactory factory =
+ ((ScriptUpdateProcessorFactory) chained.getProcessors().get(0));
final List functionMessages = new ArrayList<>();
ScriptEngineCustomizer customizer = new ScriptEngineCustomizer() {
@Override
@@ -128,12 +130,12 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
doc(f("id", "2"),
f("name", " foo "),
f("subject", "bar")));
-
- assertEquals(chain + " didn't add Double field",
+
+ assertEquals(chain + " didn't add Double field",
42.3d, d.getFieldValue("script_added_d"));
assertEquals(chain + " didn't add integer field",
42, d.getFieldValue("script_added_i"));
-
+
processCommit("run-no-scripts");
assertQ(chain + ": couldn't find doc by id",
@@ -142,72 +144,72 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
processDeleteById(chain, "2");
processCommit(chain);
-
+
assertEquals(chain, 6, functionMessages.size());
assertTrue(chain, functionMessages.contains("processAdd0"));
assertTrue(chain, functionMessages.contains("processAdd1"));
assertTrue(chain + ": script order doesn't match conf order",
- functionMessages.indexOf("processAdd0")
+ functionMessages.indexOf("processAdd0")
< functionMessages.indexOf("processAdd1"));
assertTrue(chain, functionMessages.contains("processDelete0"));
assertTrue(chain, functionMessages.contains("processDelete1"));
assertTrue(chain + ": script order doesn't match conf order",
- functionMessages.indexOf("processDelete0")
+ functionMessages.indexOf("processDelete0")
< functionMessages.indexOf("processDelete1"));
assertTrue(chain, functionMessages.contains("processCommit0"));
assertTrue(chain, functionMessages.contains("processCommit1"));
assertTrue(chain + ": script order doesn't match conf order",
- functionMessages.indexOf("processCommit0")
+ functionMessages.indexOf("processCommit0")
< functionMessages.indexOf("processCommit1"));
finish(chain);
-
+
assertEquals(chain, 8, functionMessages.size());
assertTrue(chain, functionMessages.contains("finish0"));
assertTrue(chain, functionMessages.contains("finish1"));
assertTrue(chain + ": script order doesn't match conf order",
- functionMessages.indexOf("finish0")
+ functionMessages.indexOf("finish0")
< functionMessages.indexOf("finish1"));
assertQ(chain + ": found deleted doc",
req("q","id:2")
, "//result[@numFound=0]");
-
+
}
}
public void testConditionalExecution() throws Exception {
- for (String chain : new String[] {"conditional-script",
+ for (String chain : new String[] {"conditional-script",
"conditional-scripts"}) {
ModifiableSolrParams reqParams = new ModifiableSolrParams();
-
+
SolrInputDocument d = processAdd(chain,
reqParams,
doc(f("id", "3"),
f("name", " foo "),
f("subject", "bar")));
-
- assertFalse(chain + " added String field despite condition",
+
+ assertFalse(chain + " added String field despite condition",
d.containsKey("script_added_s"));
- assertFalse(chain + " added Double field despite condition",
+ assertFalse(chain + " added Double field despite condition",
d.containsKey("script_added_d"));
-
+
reqParams.add("go-for-it", "true");
-
+
d = processAdd(chain,
reqParams,
doc(f("id", "4"),
f("name", " foo "),
f("subject", "bar")));
-
- assertEquals(chain + " didn't add String field",
+
+ assertEquals(chain + " didn't add String field",
"i went for it", d.getFieldValue("script_added_s"));
- assertEquals(chain +" didn't add Double field",
+ assertEquals(chain +" didn't add Double field",
42.3d, d.getFieldValue("script_added_d"));
assertEquals(chain + " didn't add integer field",
42, d.getFieldValue("script_added_i"));
@@ -222,8 +224,8 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
doc(f("id", "5"),
f("name", " foo "),
f("subject", "bar")));
-
- assertEquals(chain +" didn't add Double field",
+
+ assertEquals(chain +" didn't add Double field",
42.3d, d.getFieldValue("script_added_d"));
assertEquals(chain + " didn't add integer field",
42, d.getFieldValue("script_added_i"));
diff --git a/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/TestBadScriptingUpdateProcessorConfig.java b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/TestBadScriptingUpdateProcessorConfig.java
new file mode 100644
index 00000000000..9d64e8d1422
--- /dev/null
+++ b/solr/contrib/scripting/src/test/org/apache/solr/scripting/update/TestBadScriptingUpdateProcessorConfig.java
@@ -0,0 +1,49 @@
+/*
+ * 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.scripting.update;
+
+import javax.script.ScriptEngineManager;
+
+import org.apache.solr.core.AbstractBadConfigTestBase;
+import org.junit.Assume;
+
+public class TestBadScriptingUpdateProcessorConfig extends AbstractBadConfigTestBase {
+
+
+ public void testBogusScriptEngine() throws Exception {
+ // sanity check
+ Assume.assumeTrue(null == (new ScriptEngineManager()).getEngineByName("giberish"));
+
+ assertConfigs("bad-solrconfig-bogus-scriptengine-name.xml",
+ "schema.xml","giberish");
+ }
+
+ public void testMissingScriptFile() throws Exception {
+ // sanity check
+ Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
+ assertConfigs("bad-solrconfig-missing-scriptfile.xml",
+ "schema.xml","a-file-name-that-does-not-exist.js");
+ }
+
+ public void testInvalidScriptFile() throws Exception {
+ // sanity check
+ Assume.assumeNotNull((new ScriptEngineManager()).getEngineByName("javascript"));
+ assertConfigs("bad-solrconfig-invalid-scriptfile.xml",
+ "schema.xml","invalid.script.xml");
+ }
+
+}
diff --git a/solr/core/src/test-files/solr/configsets/upload/with-script-processor/missleading.extension.updateprocessor.js.txt b/solr/core/src/test-files/solr/configsets/upload/with-script-processor/missleading.extension.updateprocessor.js.txt
deleted file mode 100644
index 984e1d82f10..00000000000
--- a/solr/core/src/test-files/solr/configsets/upload/with-script-processor/missleading.extension.updateprocessor.js.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-function processAdd(cmd) {
- // Integer.valueOf is needed here to get a tru java object, because
- // all javascript numbers are floating point (ie: java.lang.Double)
- cmd.getSolrInputDocument().addField("script_added_i",
- java.lang.Integer.valueOf(42));
- cmd.getSolrInputDocument().addField("script_added_d", 42.3);
-
-}
-function processDelete() {
- // NOOP
-}
-function processCommit() {
- // NOOP
-}
-function processRollback() {
- // NOOP
-}
-function processMergeIndexes() {
- // NOOP
-}
-function finish() {
- // NOOP
-}
diff --git a/solr/core/src/test-files/solr/configsets/upload/with-script-processor/solrconfig.xml b/solr/core/src/test-files/solr/configsets/upload/with-script-processor/solrconfig.xml
index 1c62889d19e..affccbfa6f8 100644
--- a/solr/core/src/test-files/solr/configsets/upload/with-script-processor/solrconfig.xml
+++ b/solr/core/src/test-files/solr/configsets/upload/with-script-processor/solrconfig.xml
@@ -37,12 +37,9 @@
${tests.luceneMatchVersion:LATEST}
-
-
- ${solr.commitwithin.softcommit:true}
-
+
+
-
explicit
@@ -55,11 +52,10 @@
javascript
- missleading.extension.updateprocessor.js.txt
+ trivial.updateprocessor.js
-
diff --git a/solr/core/src/test-files/solr/configsets/upload/with-script-processor/trivial.updateprocessor.js b/solr/core/src/test-files/solr/configsets/upload/with-script-processor/trivial.updateprocessor.js
new file mode 100644
index 00000000000..698b78c758e
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/upload/with-script-processor/trivial.updateprocessor.js
@@ -0,0 +1,22 @@
+function processAdd(cmd) {
+ // Integer.valueOf is needed here to get a tru java object, because
+ // all javascript numbers are floating point (ie: java.lang.Double)
+ cmd.getSolrInputDocument().addField("script_added_i",
+ java.lang.Integer.valueOf(42));
+}
+
+function processDelete() {
+ // NOOP
+}
+function processCommit() {
+ // NOOP
+}
+function processRollback() {
+ // NOOP
+}
+function processMergeIndexes() {
+ // NOOP
+}
+function finish() {
+ // NOOP
+}
diff --git a/solr/core/src/test/org/apache/solr/core/TestBadConfig.java b/solr/core/src/test/org/apache/solr/core/TestBadConfig.java
index 1dfad85f327..91fd9ae3fde 100644
--- a/solr/core/src/test/org/apache/solr/core/TestBadConfig.java
+++ b/solr/core/src/test/org/apache/solr/core/TestBadConfig.java
@@ -16,10 +16,6 @@
*/
package org.apache.solr.core;
-import javax.script.ScriptEngineManager;
-
-import org.junit.Assume;
-
public class TestBadConfig extends AbstractBadConfigTestBase {
public void testUnsetSysProperty() throws Exception {
@@ -44,7 +40,7 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
}
public void testUpdateLogButNoVersionField() throws Exception {
-
+
System.setProperty("enable.update.log", "true");
try {
assertConfigs("solrconfig.xml", "schema12.xml", "_version_");
@@ -53,28 +49,6 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
}
}
- public void testBogusScriptEngine() throws Exception {
- // sanity check
- Assume.assumeTrue(null == (new ScriptEngineManager()).getEngineByName("giberish"));
-
- assertConfigs("bad-solrconfig-bogus-scriptengine-name.xml",
- "schema.xml","giberish");
- }
-
- public void testMissingScriptFile() throws Exception {
- // sanity check
- Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
- assertConfigs("bad-solrconfig-missing-scriptfile.xml",
- "schema.xml","a-file-name-that-does-not-exist.js");
- }
-
- public void testInvalidScriptFile() throws Exception {
- // sanity check
- Assume.assumeNotNull((new ScriptEngineManager()).getEngineByName("javascript"));
- assertConfigs("bad-solrconfig-invalid-scriptfile.xml",
- "schema.xml","currency.xml");
- }
-
public void testBogusMergePolicy() throws Exception {
assertConfigs("bad-mpf-solrconfig.xml", "schema-minimal.xml",
"DummyMergePolicyFactory");
@@ -89,7 +63,7 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
assertConfigs("bad-solrconfig-managed-schema-named-schema.xml.xml",
"schema-minimal.xml", "managedSchemaResourceName can't be 'schema.xml'");
}
-
+
public void testUnknownSchemaAttribute() throws Exception {
assertConfigs("bad-solrconfig-unexpected-schema-attribute.xml", "schema-minimal.xml",
"Unexpected arg(s): {bogusParam=bogusValue}");
diff --git a/solr/packaging/build.gradle b/solr/packaging/build.gradle
index 27e8e3ad7f6..3b242ad7199 100644
--- a/solr/packaging/build.gradle
+++ b/solr/packaging/build.gradle
@@ -52,6 +52,7 @@ dependencies {
":solr:contrib:langid",
":solr:contrib:ltr",
":solr:contrib:prometheus-exporter",
+ ":solr:contrib:scripting"
].each { contribName ->
distSolr project(contribName)
contrib project(path: contribName, configuration: "packaging")
diff --git a/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml b/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
index 8fea9ca8d49..14f094dc24c 100644
--- a/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
+++ b/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
@@ -83,6 +83,8 @@
+
+
+
- -->
-
+
+
+ update-script.js
+
+ example config parameter
+
+
+
+
+
+
+
+----
+
+NOTE: The processor supports the defaults/appends/invariants concept for its config.
+However, it is also possible to skip this level and configure the parameters directly underneath the `` tag.
+
+Below follows a list of each configuration parameters and their meaning:
+
+`script`::
+The script file name. The script file must be placed in the `conf/ directory.
+There can be one or more "script" parameters specified; multiple scripts are executed in the order specified.
+
+`engine`::
+Optionally specifies the scripting engine to use. This is only needed if the extension
+of the script file is not a standard mapping to the scripting engine. For example, if your
+script file was coded in JavaScript but the file name was called `update-script.foo`,
+use "javascript" as the engine name.
+
+`params`::
+Optional parameters that are passed into the script execution context. This is
+specified as a named list (``) structure with nested typed parameters. If
+specified, the script context will get a "params" object, otherwise there will be no "params" object available.
+
+
+== Script execution context
+
+Every script has some variables provided to it.
+
+`logger`::
+Logger (org.slf4j.Logger) instance. This is useful for logging information from the script.
+
+`req`::
+{solr-javadocs}/core/org/apache/solr/request/SolrQueryRequest.html[SolrQueryRequest] instance.
+
+`rsp`::
+{solr-javadocs}/core/org/apache/solr/response/SolrQueryResponse.html[SolrQueryResponse] instance.
+
+`params`::
+The "params" object, if any specified, from the configuration.
+
+== Examples
+
+The `processAdd()` and the other script methods can return false to skip further
+processing of the document. All methods must be defined, though generally the
+`processAdd()` method is where the action is.
+
+Here's a URL that works with the techproducts example setup demonstrating specifying
+the "script" update chain: `http://localhost:8983/solr/techproducts/update?commit=true&stream.contentType=text/csv&fieldnames=id,description&stream.body=1,foo&update.chain=script`
+which logs the following:
+
+[source,text]
+----
+INFO: update-script#processAdd: id=1
+----
+
+You can see the message recorded in the Solr logging UI.
+
+=== Javascript
+
+Note: There is a JavaScript example `update-script.js` as part of the `techproducts` configset.
+Check `solrconfig.xml` and uncomment the update request processor definition to enable this feature.
+
+[source,javascript]
+----
+function processAdd(cmd) {
+
+ doc = cmd.solrDoc; // org.apache.solr.common.SolrInputDocument
+ id = doc.getFieldValue("id");
+ logger.info("update-script#processAdd: id=" + id);
+
+// Set a field value:
+// doc.setField("foo_s", "whatever");
+
+// Get a configuration parameter:
+// config_param = params.get('config_param'); // "params" only exists if processor configured with
+
+// Get a request parameter:
+// some_param = req.getParams().get("some_param")
+
+// Add a field of field names that match a pattern:
+// - Potentially useful to determine the fields/attributes represented in a result set, via faceting on field_name_ss
+// field_names = doc.getFieldNames().toArray();
+// for(i=0; i < field_names.length; i++) {
+// field_name = field_names[i];
+// if (/attr_.*/.test(field_name)) { doc.addField("attribute_ss", field_names[i]); }
+// }
+
+}
+
+function processDelete(cmd) {
+ // no-op
+}
+
+function processMergeIndexes(cmd) {
+ // no-op
+}
+
+function processCommit(cmd) {
+ // no-op
+}
+
+function processRollback(cmd) {
+ // no-op
+}
+
+function finish() {
+ // no-op
+}
+----
+
+=== Ruby
+Ruby support is implemented via the https://www.jruby.org/[JRuby] project.
+To use JRuby as the scripting engine, add `jruby.jar` to Solr.
+
+Here's an example of a JRuby update processing script (note that all variables passed in require prefixing with `$`, such as `$logger`):
+
+[source,ruby]
+----
+def processAdd(cmd)
+ doc = cmd.solrDoc # org.apache.solr.common.SolrInputDocument
+ id = doc.getFieldValue('id')
+
+ $logger.info "update-script#processAdd: id=#{id}"
+
+ doc.setField('source_s', 'ruby')
+
+ $logger.info "update-script#processAdd: config_param=#{$params.get('config_param')}"
+end
+
+def processDelete(cmd)
+ # no-op
+end
+
+def processMergeIndexes(cmd)
+ # no-op
+end
+
+def processCommit(cmd)
+ # no-op
+end
+
+def processRollback(cmd)
+ # no-op
+end
+
+def finish()
+ # no-op
+end
+----
+
+==== Known issues
+
+The following in JRuby does not work as expected for some reason, though it does work properly in JavaScript:
+
+[source,ruby]
+----
+# $logger.info "update-script#processAdd: request_param=#{$req.params.get('request_param')}"
+# $rsp.add('script_processed',id)
+----
+
+=== Groovy
+
+Add JARs from a Groovy distro's `lib/` directory to Solr. All JARs from
+Groovy's distro probably aren't required, but more than just the main `groovy.jar`
+file is needed (at least when this was tested using Groovy 2.0.6)
+
+[source,groovy]
+----
+def processAdd(cmd) {
+ doc = cmd.solrDoc // org.apache.solr.common.SolrInputDocument
+ id = doc.getFieldValue('id')
+
+ logger.info "update-script#processAdd: id=" + id
+
+ doc.setField('source_s', 'groovy')
+
+ logger.info "update-script#processAdd: config_param=" + params.get('config_param')
+
+ logger.info "update-script#processAdd: request_param=" + req.params.get('request_param')
+ rsp.add('script_processed',id)
+}
+
+def processDelete(cmd) {
+ // no-op
+}
+
+def processMergeIndexes(cmd) {
+ // no-op
+}
+
+def processCommit(cmd) {
+ // no-op
+}
+
+def processRollback(cmd) {
+ // no-op
+}
+
+def finish() {
+ // no-op
+}
+----
+
+=== Python
+Python support is implemented via the https://www.jython.org/[Jython] project.
+Add the *standalone* `jython.jar` (the JAR that contains all the dependencies) into Solr.
+
+[source,python]
+----
+def processAdd(cmd):
+ doc = cmd.solrDoc
+ id = doc.getFieldValue("id")
+ logger.info("update-script#processAdd: id=" + id)
+
+def processDelete(cmd):
+ logger.info("update-script#processDelete")
+
+def processMergeIndexes(cmd):
+ logger.info("update-script#processMergeIndexes")
+
+def processCommit(cmd):
+ logger.info("update-script#processCommit")
+
+def processRollback(cmd):
+ logger.info("update-script#processRollback")
+
+def finish():
+ logger.info("update-script#finish")
+----
diff --git a/solr/solr-ref-guide/src/update-request-processors.adoc b/solr/solr-ref-guide/src/update-request-processors.adoc
index 7e9dce834e9..aeee353a197 100644
--- a/solr/solr-ref-guide/src/update-request-processors.adoc
+++ b/solr/solr-ref-guide/src/update-request-processors.adoc
@@ -283,7 +283,7 @@ What follows are brief descriptions of the currently available update request pr
{solr-javadocs}/core/org/apache/solr/update/processor/SignatureUpdateProcessorFactory.html[SignatureUpdateProcessorFactory]:: Uses a defined set of fields to generate a hash "signature" for the document. Useful for only indexing one copy of "similar" documents.
-{solr-javadocs}/core/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactory.html[StatelessScriptUpdateProcessorFactory]:: An update request processor factory that enables the use of update processors implemented as scripts.
+{solr-javadocs}/contrib/scripting/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.html[ScriptUpdateProcessorFactory]:: An processor that enables the use of update processors implemented as scripts. Learn more at the <> page.
{solr-javadocs}/core/org/apache/solr/update/processor/TemplateUpdateProcessorFactory.html[TemplateUpdateProcessorFactory]:: Allows adding new fields to documents based on a template pattern. This update processor can also be used at runtime (without defining it in `solrconfig.xml`), see the section <> below.
diff --git a/solr/test-framework/src/java/org/apache/solr/update/processor/UpdateProcessorTestBase.java b/solr/test-framework/src/java/org/apache/solr/update/processor/UpdateProcessorTestBase.java
index d3aa9797601..21c4972efea 100644
--- a/solr/test-framework/src/java/org/apache/solr/update/processor/UpdateProcessorTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/update/processor/UpdateProcessorTestBase.java
@@ -140,7 +140,7 @@ public class UpdateProcessorTestBase extends SolrTestCaseJ4 {
/**
* Convenience method for building up SolrInputDocuments
*/
- final SolrInputDocument doc(SolrInputField... fields) {
+ protected final SolrInputDocument doc(SolrInputField... fields) {
SolrInputDocument d = new SolrInputDocument();
for (SolrInputField f : fields) {
d.put(f.getName(), f);
@@ -162,7 +162,7 @@ public class UpdateProcessorTestBase extends SolrTestCaseJ4 {
/**
* Convenience method for building up SolrInputFields with default boost
*/
- final SolrInputField f(String name, Object... values) {
+ protected final SolrInputField f(String name, Object... values) {
return field(name, values);
}
}