org.jahia.utils.ScriptEngineUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.utils.ScriptEngineUtils.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.utils;

import org.apache.commons.lang.StringUtils;
import org.jahia.services.render.scripting.bundle.BundleScriptEngineManager;
import org.jahia.services.render.scripting.bundle.BundleScriptingConfigurationConstants;

import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import java.util.Properties;

/**
 * ScriptEngine provider class.
 *
 * @author rincevent
 * @since JAHIA 6.5 Created : 27/01/11
 */
public class ScriptEngineUtils {
    private final BundleScriptEngineManager enginesManager;

    /**
     * Determines whether the {@link ScriptEngineFactory} associated with the specified extension supports at least one
     * of the script names declared by the given OSGi headers assuming they provide a value for the
     * {@link BundleScriptingConfigurationConstants#JAHIA_MODULE_SCRIPTING_VIEWS} header.
     *
     * @param extension the extension associated with the factory whose support for views defined in the specified
     *                  bundle is to be determined
     * @param headers   the OSGi headers to be checked if declared view technologies defined by the {@link
     *                  BundleScriptingConfigurationConstants#JAHIA_MODULE_SCRIPTING_VIEWS} OSGI header are supported by
     *                  the specified ScriptEngineFactory
     * @return {@code true} if the specified ScriptEngineFactory can handle at least one of the specified script names,
     * {@code false} otherwise. Note that if the headers contain the {@link BundleScriptingConfigurationConstants#JAHIA_MODULE_HAS_VIEWS}
     * header with a "{@code no}" value, we won't look at other headers since the module has indicated that it shouldn't
     * contain any views so the factory shouldn't attempt to process any it might find.
     */
    public static boolean canFactoryForExtensionProcessViews(String extension, Dictionary<String, String> headers) {
        ScriptEngineFactory engineFactory = getInstance().enginesManager.getFactoryForExtension(extension);
        return canFactoryProcessViews(engineFactory, headers);
    }

    /**
     * Determines whether the specified {@link ScriptEngineFactory} supports at least one of the script names
     * declared by the given OSGi headers assuming they provide a value for the
     * {@link BundleScriptingConfigurationConstants#JAHIA_MODULE_SCRIPTING_VIEWS} header.
     *
     * @param scriptFactory the ScriptEngineFactory whose support for views defined in the specified bundle is to be
     *                      determined
     * @param headers       the OSGi headers to be checked if declared view technologies defined by the {@link
     *                      BundleScriptingConfigurationConstants#JAHIA_MODULE_SCRIPTING_VIEWS} OSGI header are
     *                      supported by the specified ScriptEngineFactory
     * @return {@code true} if the specified ScriptEngineFactory can handle at least one of the specified script names,
     * {@code false} otherwise. Note that if the headers contain the {@link BundleScriptingConfigurationConstants#JAHIA_MODULE_HAS_VIEWS}
     * header with a "{@code no}" value, we won't look at other headers since the module has indicated that it shouldn't
     * contain any views so the factory shouldn't attempt to process any it might find.
     */
    public static boolean canFactoryProcessViews(ScriptEngineFactory scriptFactory,
            Dictionary<String, String> headers) {
        if (scriptFactory == null) {
            throw new IllegalArgumentException("ScriptEngineFactory is null");
        }

        if (headers != null) {

            final String hasViews = headers.get(BundleScriptingConfigurationConstants.JAHIA_MODULE_HAS_VIEWS);
            if ("no".equalsIgnoreCase(StringUtils.trim(hasViews))) {
                // if the bundle indicated that it doesn't provide views, the factory shouldn't process it regardless
                // of other configuration
                return false;
            } else {
                final String commaSeparatedScriptNames = headers
                        .get(BundleScriptingConfigurationConstants.JAHIA_MODULE_SCRIPTING_VIEWS);
                // check if the bundle provided a list of of comma-separated scripting language names for the views it provides
                // the bundle should only be scanned if it defined the header and the header contains the name or language of the factory associated with the extension
                final String[] split = StringUtils.split(commaSeparatedScriptNames, ',');
                if (split != null) {
                    // check extensions
                    final List<String> extensions = scriptFactory.getExtensions();
                    List<String> scriptNames = new ArrayList<>(split.length);
                    for (String scriptName : split) {
                        String script = scriptName.trim().toLowerCase();
                        scriptNames.add(script);
                        if (extensions.contains(script)) {
                            return true;
                        }
                    }

                    return scriptNames.contains(scriptFactory.getEngineName().trim().toLowerCase())
                            || scriptNames.contains(scriptFactory.getLanguageName().trim().toLowerCase());
                }
            }
        }
        return false;
    }

    // Initialization on demand holder idiom: thread-safe singleton initialization
    private static class Holder {
        static final ScriptEngineUtils INSTANCE = new ScriptEngineUtils();
    }

    public static ScriptEngineUtils getInstance() {
        return Holder.INSTANCE;
    }

    private ScriptEngineUtils() {
        super();
        enginesManager = BundleScriptEngineManager.getInstance();
        try {
            enginesManager.getEngineByExtension("groovy").eval("true");
        } catch (ScriptException e) {
            // Ignore
        }
    }

    /**
     * Returns an instance of a {@link ScriptEngine} by its name.
     *
     * @param name the name of the script engine to look for
     * @return an instance of a {@link ScriptEngine} by its name
     * @throws ScriptException in case of a script engine initialization error
     */
    public ScriptEngine getEngineByName(String name) throws ScriptException {
        return getScriptEngineFrom(name, false);
    }

    /**
     * Returns an instance of a {@link ScriptEngine} by its file extension.
     *
     * @param extension the extension of the script engine to look for
     * @return an instance of a {@link ScriptEngine} by its name
     * @throws ScriptException in case of a script engine initialization error
     */
    public ScriptEngine scriptEngine(String extension) throws ScriptException {
        return getScriptEngineFrom(extension, true);
    }

    private ScriptEngine getScriptEngineFrom(String nameOrExtension, boolean fromExtension) throws ScriptException {
        ScriptEngine scriptEngine = fromExtension ? enginesManager.getEngineByExtension(nameOrExtension)
                : enginesManager.getEngineByName(nameOrExtension);

        if (scriptEngine == null) {
            throw new ScriptException(
                    "Script engine not found for " + (fromExtension ? "extension: " : "name: ") + nameOrExtension);
        }
        initEngine(scriptEngine);
        return scriptEngine;
    }

    private void initEngine(ScriptEngine engine) {
        if (engine.getFactory().getNames().contains("velocity")) {
            final Properties velocityProperties = new Properties();
            final String key = "runtime.log.logsystem.log4j.logger";
            final String log4jLoggerProp = System.getProperty(key);
            if (log4jLoggerProp != null) {
                velocityProperties.setProperty(key, log4jLoggerProp);
            } else {
                velocityProperties.setProperty(key, "root");
            }
            engine.getContext().setAttribute("com.sun.script.velocity.properties", velocityProperties,
                    ScriptContext.GLOBAL_SCOPE);
        }
    }
}