001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.scripting.support;
018
019import java.util.LinkedHashSet;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023import javax.script.Bindings;
024import javax.script.ScriptContext;
025import javax.script.ScriptEngine;
026import javax.script.ScriptEngineFactory;
027import javax.script.ScriptEngineManager;
028import javax.script.SimpleBindings;
029
030/**
031 * Common operations for dealing with a JSR-223 {@link ScriptEngine}.
032 *
033 * @author Juergen Hoeller
034 * @since 4.2.2
035 */
036public abstract class StandardScriptUtils {
037
038        /**
039         * Retrieve a {@link ScriptEngine} from the given {@link ScriptEngineManager}
040         * by name, delegating to {@link ScriptEngineManager#getEngineByName} but
041         * throwing a descriptive exception if not found or if initialization failed.
042         * @param scriptEngineManager the ScriptEngineManager to use
043         * @param engineName the name of the engine
044         * @return a corresponding ScriptEngine (never {@code null})
045         * @throws IllegalArgumentException if no matching engine has been found
046         * @throws IllegalStateException if the desired engine failed to initialize
047         */
048        public static ScriptEngine retrieveEngineByName(ScriptEngineManager scriptEngineManager, String engineName) {
049                ScriptEngine engine = scriptEngineManager.getEngineByName(engineName);
050                if (engine == null) {
051                        Set<String> engineNames = new LinkedHashSet<String>();
052                        for (ScriptEngineFactory engineFactory : scriptEngineManager.getEngineFactories()) {
053                                List<String> factoryNames = engineFactory.getNames();
054                                if (factoryNames.contains(engineName)) {
055                                        // Special case: getEngineByName returned null but engine is present...
056                                        // Let's assume it failed to initialize (which ScriptEngineManager silently swallows).
057                                        // If it happens to initialize fine now, alright, but we really expect an exception.
058                                        try {
059                                                engine = engineFactory.getScriptEngine();
060                                                engine.setBindings(scriptEngineManager.getBindings(), ScriptContext.GLOBAL_SCOPE);
061                                        }
062                                        catch (Throwable ex) {
063                                                throw new IllegalStateException("Script engine with name '" + engineName +
064                                                                "' failed to initialize", ex);
065                                        }
066                                }
067                                engineNames.addAll(factoryNames);
068                        }
069                        throw new IllegalArgumentException("Script engine with name '" + engineName +
070                                        "' not found; registered engine names: " + engineNames);
071                }
072                return engine;
073        }
074
075        static Bindings getBindings(Map<String, Object> bindings) {
076                return (bindings instanceof Bindings ? (Bindings) bindings : new SimpleBindings(bindings));
077        }
078
079}