14
14
* See the License for the specific language governing permissions and
15
15
* limitations under the License.
16
16
*/
17
- package org .apache .solr .update . processor ;
17
+ package org .apache .solr .scripting . update ;
18
18
19
19
import org .apache .solr .common .SolrException ;
20
20
import org .apache .solr .common .SolrException .ErrorCode ;
26
26
import org .apache .solr .request .LocalSolrQueryRequest ;
27
27
import org .apache .solr .response .SolrQueryResponse ;
28
28
import org .apache .solr .update .*;
29
+ import org .apache .solr .update .processor .UpdateRequestProcessor ;
30
+ import org .apache .solr .update .processor .UpdateRequestProcessorFactory ;
29
31
import org .apache .solr .util .plugin .SolrCoreAware ;
30
32
import org .apache .commons .io .IOUtils ;
31
33
import org .apache .commons .io .FilenameUtils ;
58
60
59
61
/**
60
62
* <p>
61
- * An update request processor factory that enables the use of update
62
- * processors implemented as scripts which can be loaded by the
63
- * {@link SolrResourceLoader} (usually via the <code>conf</code> dir for
64
- * the SolrCore).
63
+ * An update request processor factory that enables the use of update
64
+ * processors implemented as scripts which can be loaded from the
65
+ * configSet. Previously known as the StatelessScriptUpdateProcessorFactory.
65
66
* </p>
66
67
* <p>
67
68
* This factory requires at least one configuration parameter named
68
- * <code>script</code> which may be the name of a script file as a string,
69
- * or an array of multiple script files. If multiple script files are
70
- * specified, they are executed sequentially in the order specified in the
69
+ * <code>script</code> which may be the name of a script file as a string,
70
+ * or an array of multiple script files. If multiple script files are
71
+ * specified, they are executed sequentially in the order specified in the
71
72
* configuration -- as if multiple factories were configured sequentially
72
73
* </p>
73
74
* <p>
74
- * Each script file is expected to declare functions with the same name
75
- * as each method in {@link UpdateRequestProcessor}, using the same
76
- * arguments. One slight deviation is in the optional return value from
77
- * these functions: If a script function has a <code>boolean</code> return
78
- * value, and that value is <code>false</code> then the processor will
79
- * cleanly terminate processing of the command and return, without forwarding
75
+ * Each script file is expected to declare functions with the same name
76
+ * as each method in {@link UpdateRequestProcessor}, using the same
77
+ * arguments. One slight deviation is in the optional return value from
78
+ * these functions: If a script function has a <code>boolean</code> return
79
+ * value, and that value is <code>false</code> then the processor will
80
+ * cleanly terminate processing of the command and return, without forwarding
80
81
* the command on to the next script or processor in the chain.
81
- * Due to limitations in the {@link ScriptEngine} API used by
82
+ * Due to limitations in the {@link ScriptEngine} API used by
82
83
* this factory, it can not enforce that all functions exist on initialization,
83
84
* so errors from missing functions will only be generated at runtime when
84
85
* the chain attempts to use them.
85
86
* </p>
86
87
* <p>
87
- * The factory may also be configured with an optional "params" argument,
88
- * which can be an {@link NamedList} (or array, or any other simple Java
88
+ * The factory may also be configured with an optional "params" argument,
89
+ * which can be an {@link NamedList} (or array, or any other simple Java
89
90
* object) which will be put into the global scope for each script.
90
91
* </p>
91
92
* <p>
97
98
* <li>params - The "params" init argument in the factory configuration (if any)</li>
98
99
* </ul>
99
100
* <p>
100
- * Internally this update processor uses JDK 6 scripting engine support,
101
- * and any {@link Invocable} implementations of <code>ScriptEngine</code>
102
- * that can be loaded using the Solr Plugin ClassLoader may be used.
103
- * By default, the engine used for each script is determined by the filed
104
- * extension (ie: a *.js file will be treated as a JavaScript script) but
105
- * this can be overridden by specifying an explicit "engine" name init
106
- * param for the factory, which identifies a registered name of a
107
- * {@link ScriptEngineFactory}.
108
- * (This may be particularly useful if multiple engines are available for
109
- * the same scripting language, and you wish to force the usage of a
101
+ * Internally this update processor uses JDK 6 scripting engine support,
102
+ * and any {@link Invocable} implementations of <code>ScriptEngine</code>
103
+ * that can be loaded using the Solr Plugin ClassLoader may be used.
104
+ * By default, the engine used for each script is determined by the file
105
+ * extension (ie: a *.js file will be treated as a JavaScript script) but
106
+ * this can be overridden by specifying an explicit "engine" name init
107
+ * param for the factory, which identifies a registered name of a
108
+ * {@link ScriptEngineFactory}.
109
+ * (This may be particularly useful if multiple engines are available for
110
+ * the same scripting language, and you wish to force the usage of a
110
111
* particular engine because of known quirks)
111
112
* </p>
112
113
* <p>
113
- * A new {@link ScriptEngineManager} is created for each
114
- * <code>SolrQueryRequest</code> defining a "global" scope for the script(s)
115
- * which is request specific. Separate <code>ScriptEngine</code> instances
116
- * are then used to evaluate the script files, resulting in an "engine" scope
114
+ * A new {@link ScriptEngineManager} is created for each
115
+ * <code>SolrQueryRequest</code> defining a "global" scope for the script(s)
116
+ * which is request specific. Separate <code>ScriptEngine</code> instances
117
+ * are then used to evaluate the script files, resulting in an "engine" scope
117
118
* that is specific to each script.
118
119
* </p>
119
120
* <p>
120
121
* A simple example...
121
122
* </p>
122
123
* <pre class="prettyprint">
123
- * <processor class="solr.StatelessScriptUpdateProcessorFactory ">
124
+ * <processor class="org.apache. solr.scripting.update.ScriptUpdateProcessorFactory ">
124
125
* <str name="script">updateProcessor.js</str>
125
126
* </processor>
126
127
* </pre>
127
128
* <p>
128
- * A more complex example involving multiple scripts in different languages,
129
- * and a "params" <code>NamedList</code> that will be put into the global
129
+ * A more complex example involving multiple scripts in different languages,
130
+ * and a "params" <code>NamedList</code> that will be put into the global
130
131
* scope of each script...
131
132
* </p>
132
133
* <pre class="prettyprint">
133
- * <processor class="solr.StatelessScriptUpdateProcessorFactory ">
134
+ * <processor class="org.apache. solr.scripting.update.ScriptUpdateProcessorFactory ">
134
135
* <arr name="script">
135
136
* <str name="script">first-processor.js</str>
136
137
* <str name="script">second-processor.py</str>
142
143
* </processor>
143
144
* </pre>
144
145
* <p>
145
- * An example where the script file extensions are ignored, and an
146
+ * An example where the script file extensions are ignored, and an
146
147
* explicit script engine is used....
147
148
* </p>
148
149
* <pre class="prettyprint">
149
- * <processor class="solr.StatelessScriptUpdateProcessorFactory ">
150
+ * <processor class="org.apache. solr.scripting.update.ScriptUpdateProcessorFactory ">
150
151
* <arr name="script">
151
152
* <str name="script">first-processor.txt</str>
152
153
* <str name="script">second-processor.txt</str>
153
154
* </arr>
154
155
* <str name="engine">rhino</str>
155
156
* </processor>
156
157
* </pre>
157
- *
158
+ *
158
159
* @since 4.0.0
159
160
*/
160
- public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
161
+ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
161
162
162
163
private static final Logger log = LoggerFactory .getLogger (MethodHandles .lookup ().lookupClass ());
163
164
@@ -182,8 +183,8 @@ public void init(@SuppressWarnings({"rawtypes"})NamedList args) {
182
183
Collection <String > scripts =
183
184
args .removeConfigArgs (SCRIPT_ARG );
184
185
if (scripts .isEmpty ()) {
185
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
186
- "StatelessScriptUpdateProcessorFactory must be " +
186
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
187
+ "ScriptUpdateProcessorFactory must be " +
187
188
"initialized with at least one " + SCRIPT_ARG );
188
189
}
189
190
scriptFiles = new ArrayList <>();
@@ -199,8 +200,8 @@ public void init(@SuppressWarnings({"rawtypes"})NamedList args) {
199
200
engineName = (String )engine ;
200
201
} else {
201
202
throw new SolrException
202
- (SolrException .ErrorCode .SERVER_ERROR ,
203
- "'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
203
+ (SolrException .ErrorCode .SERVER_ERROR ,
204
+ "'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
204
205
engine .getClass () + ")" );
205
206
}
206
207
}
@@ -246,7 +247,7 @@ public void inform(SolrCore core) {
246
247
req .close ();
247
248
}
248
249
249
-
250
+
250
251
}
251
252
252
253
@@ -259,13 +260,13 @@ public void inform(SolrCore core) {
259
260
* @param rsp The solr response
260
261
* @return The list of initialized script engines.
261
262
*/
262
- private List <EngineInfo > initEngines (SolrQueryRequest req ,
263
- SolrQueryResponse rsp )
263
+ private List <EngineInfo > initEngines (SolrQueryRequest req ,
264
+ SolrQueryResponse rsp )
264
265
throws SolrException {
265
-
266
+
266
267
List <EngineInfo > scriptEngines = new ArrayList <>();
267
268
268
- ScriptEngineManager scriptEngineManager
269
+ ScriptEngineManager scriptEngineManager
269
270
= new ScriptEngineManager (resourceLoader .getClassLoader ());
270
271
271
272
scriptEngineManager .put ("logger" , log );
@@ -281,29 +282,29 @@ private List<EngineInfo> initEngines(SolrQueryRequest req,
281
282
engine = scriptEngineManager .getEngineByName (engineName );
282
283
if (engine == null ) {
283
284
String details = getSupportedEngines (scriptEngineManager , false );
284
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
285
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
285
286
"No ScriptEngine found by name: "
286
- + engineName +
287
- (null != details ?
287
+ + engineName +
288
+ (null != details ?
288
289
" -- supported names: " + details : "" ));
289
290
}
290
291
} else {
291
292
engine = scriptEngineManager .getEngineByExtension
292
293
(scriptFile .getExtension ());
293
294
if (engine == null ) {
294
295
String details = getSupportedEngines (scriptEngineManager , true );
295
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
296
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
296
297
"No ScriptEngine found by file extension: "
297
- + scriptFile .getFileName () +
298
- (null != details ?
298
+ + scriptFile .getFileName () +
299
+ (null != details ?
299
300
" -- supported extensions: " + details : "" ));
300
-
301
+
301
302
}
302
303
}
303
304
304
305
if (! (engine instanceof Invocable )) {
305
- String msg =
306
- "Engine " + ((null != engineName ) ? engineName :
306
+ String msg =
307
+ "Engine " + ((null != engineName ) ? engineName :
307
308
("for script " + scriptFile .getFileName ())) +
308
309
" does not support function invocation (via Invocable): " +
309
310
engine .getClass ().toString () + " (" +
@@ -319,7 +320,7 @@ private List<EngineInfo> initEngines(SolrQueryRequest req,
319
320
scriptEngines .add (new EngineInfo ((Invocable )engine , scriptFile ));
320
321
try {
321
322
Reader scriptSrc = scriptFile .openReader (resourceLoader );
322
-
323
+
323
324
try {
324
325
try {
325
326
AccessController .doPrivileged (new PrivilegedExceptionAction <Void >() {
@@ -333,23 +334,23 @@ public Void run() throws ScriptException {
333
334
throw (ScriptException ) e .getException ();
334
335
}
335
336
} catch (ScriptException e ) {
336
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
337
- "Unable to evaluate script: " +
337
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
338
+ "Unable to evaluate script: " +
338
339
scriptFile .getFileName (), e );
339
340
} finally {
340
341
IOUtils .closeQuietly (scriptSrc );
341
342
}
342
343
} catch (IOException ioe ) {
343
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
344
- "Unable to evaluate script: " +
345
- scriptFile .getFileName (), ioe );
344
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
345
+ "Unable to evaluate script: " +
346
+ scriptFile .getFileName (), ioe );
346
347
}
347
348
}
348
349
return scriptEngines ;
349
350
}
350
351
351
352
/**
352
- * For error messages - returns null if there are any exceptions of any
353
+ * For error messages - returns null if there are any exceptions of any
353
354
* kind building the string (or of the list is empty for some unknown reason).
354
355
* @param ext - if true, list of extensions, otherwise a list of engine names
355
356
*/
@@ -403,7 +404,7 @@ public void processDelete(DeleteUpdateCommand cmd) throws IOException {
403
404
if (invokeFunction ("processDelete" , cmd )) {
404
405
super .processDelete (cmd );
405
406
}
406
-
407
+
407
408
}
408
409
409
410
@ Override
@@ -435,9 +436,9 @@ public void finish() throws IOException {
435
436
}
436
437
437
438
/**
438
- * returns true if processing should continue, or false if the
439
- * request should be ended now. Result value is computed from the return
440
- * value of the script function if: it exists, is non-null, and can be
439
+ * returns true if processing should continue, or false if the
440
+ * request should be ended now. Result value is computed from the return
441
+ * value of the script function if: it exists, is non-null, and can be
441
442
* cast to a java Boolean.
442
443
*/
443
444
private boolean invokeFunction (String name , Object ... cmd ) {
@@ -461,10 +462,10 @@ private boolean invokeFunctionUnsafe(String name, Object... cmd) {
461
462
}
462
463
463
464
} catch (ScriptException | NoSuchMethodException e ) {
464
- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
465
- "Unable to invoke function " + name +
466
- " in script: " +
467
- engine .getScriptFile ().getFileName () +
465
+ throw new SolrException (SolrException .ErrorCode .SERVER_ERROR ,
466
+ "Unable to invoke function " + name +
467
+ " in script: " +
468
+ engine .getScriptFile ().getFileName () +
468
469
": " + e .getMessage (), e );
469
470
}
470
471
}
0 commit comments