/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.scripting.support;

import java.io.IOException;
import java.util.Map;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptEvaluator;
import org.springframework.scripting.ScriptSource;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

javax.script (JSR-223) based implementation of Spring's ScriptEvaluator strategy interface.
Author:Juergen Hoeller, Costin Leau
See Also:
Since:4.0
/** * {@code javax.script} (JSR-223) based implementation of Spring's {@link ScriptEvaluator} * strategy interface. * * @author Juergen Hoeller * @author Costin Leau * @since 4.0 * @see ScriptEngine#eval(String) */
public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { @Nullable private String engineName; @Nullable private volatile Bindings globalBindings; @Nullable private volatile ScriptEngineManager scriptEngineManager;
Construct a new StandardScriptEvaluator.
/** * Construct a new {@code StandardScriptEvaluator}. */
public StandardScriptEvaluator() { }
Construct a new StandardScriptEvaluator for the given class loader.
Params:
  • classLoader – the class loader to use for script engine detection
/** * Construct a new {@code StandardScriptEvaluator} for the given class loader. * @param classLoader the class loader to use for script engine detection */
public StandardScriptEvaluator(ClassLoader classLoader) { this.scriptEngineManager = new ScriptEngineManager(classLoader); }
Construct a new StandardScriptEvaluator for the given JSR-223 ScriptEngineManager to obtain script engines from.
Params:
  • scriptEngineManager – the ScriptEngineManager (or subclass thereof) to use
Since:4.2.2
/** * Construct a new {@code StandardScriptEvaluator} for the given JSR-223 * {@link ScriptEngineManager} to obtain script engines from. * @param scriptEngineManager the ScriptEngineManager (or subclass thereof) to use * @since 4.2.2 */
public StandardScriptEvaluator(ScriptEngineManager scriptEngineManager) { this.scriptEngineManager = scriptEngineManager; }
Set the name of the language meant for evaluating the scripts (e.g. "Groovy").

This is effectively an alias for "engineName", potentially (but not yet) providing common abbreviations for certain languages beyond what the JSR-223 script engine factory exposes.

See Also:
/** * Set the name of the language meant for evaluating the scripts (e.g. "Groovy"). * <p>This is effectively an alias for {@link #setEngineName "engineName"}, * potentially (but not yet) providing common abbreviations for certain languages * beyond what the JSR-223 script engine factory exposes. * @see #setEngineName */
public void setLanguage(String language) { this.engineName = language; }
Set the name of the script engine for evaluating the scripts (e.g. "Groovy"), as exposed by the JSR-223 script engine factory.
See Also:
Since:4.2.2
/** * Set the name of the script engine for evaluating the scripts (e.g. "Groovy"), * as exposed by the JSR-223 script engine factory. * @since 4.2.2 * @see #setLanguage */
public void setEngineName(String engineName) { this.engineName = engineName; }
Set the globally scoped bindings on the underlying script engine manager, shared by all scripts, as an alternative to script argument bindings.
See Also:
Since:4.2.2
/** * Set the globally scoped bindings on the underlying script engine manager, * shared by all scripts, as an alternative to script argument bindings. * @since 4.2.2 * @see #evaluate(ScriptSource, Map) * @see javax.script.ScriptEngineManager#setBindings(Bindings) * @see javax.script.SimpleBindings */
public void setGlobalBindings(Map<String, Object> globalBindings) { Bindings bindings = StandardScriptUtils.getBindings(globalBindings); this.globalBindings = bindings; ScriptEngineManager scriptEngineManager = this.scriptEngineManager; if (scriptEngineManager != null) { scriptEngineManager.setBindings(bindings); } } @Override public void setBeanClassLoader(ClassLoader classLoader) { ScriptEngineManager scriptEngineManager = this.scriptEngineManager; if (scriptEngineManager == null) { scriptEngineManager = new ScriptEngineManager(classLoader); this.scriptEngineManager = scriptEngineManager; Bindings bindings = this.globalBindings; if (bindings != null) { scriptEngineManager.setBindings(bindings); } } } @Override @Nullable public Object evaluate(ScriptSource script) { return evaluate(script, null); } @Override @Nullable public Object evaluate(ScriptSource script, @Nullable Map<String, Object> argumentBindings) { ScriptEngine engine = getScriptEngine(script); try { if (CollectionUtils.isEmpty(argumentBindings)) { return engine.eval(script.getScriptAsString()); } else { Bindings bindings = StandardScriptUtils.getBindings(argumentBindings); return engine.eval(script.getScriptAsString(), bindings); } } catch (IOException ex) { throw new ScriptCompilationException(script, "Cannot access script for ScriptEngine", ex); } catch (ScriptException ex) { throw new ScriptCompilationException(script, new StandardScriptEvalException(ex)); } }
Obtain the JSR-223 ScriptEngine to use for the given script.
Params:
  • script – the script to evaluate
Returns:the ScriptEngine (never null)
/** * Obtain the JSR-223 ScriptEngine to use for the given script. * @param script the script to evaluate * @return the ScriptEngine (never {@code null}) */
protected ScriptEngine getScriptEngine(ScriptSource script) { ScriptEngineManager scriptEngineManager = this.scriptEngineManager; if (scriptEngineManager == null) { scriptEngineManager = new ScriptEngineManager(); this.scriptEngineManager = scriptEngineManager; } if (StringUtils.hasText(this.engineName)) { return StandardScriptUtils.retrieveEngineByName(scriptEngineManager, this.engineName); } else if (script instanceof ResourceScriptSource) { Resource resource = ((ResourceScriptSource) script).getResource(); String extension = StringUtils.getFilenameExtension(resource.getFilename()); if (extension == null) { throw new IllegalStateException( "No script language defined, and no file extension defined for resource: " + resource); } ScriptEngine engine = scriptEngineManager.getEngineByExtension(extension); if (engine == null) { throw new IllegalStateException("No matching engine found for file extension '" + extension + "'"); } return engine; } else { throw new IllegalStateException( "No script language defined, and no resource associated with script: " + script); } } }