001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.scripting.groovy;
016    
017    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
018    import com.liferay.portal.kernel.scripting.BaseScriptingExecutor;
019    import com.liferay.portal.kernel.scripting.ExecutionException;
020    import com.liferay.portal.kernel.scripting.ScriptingException;
021    import com.liferay.portal.kernel.util.AggregateClassLoader;
022    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
023    
024    import groovy.lang.Binding;
025    import groovy.lang.GroovyShell;
026    import groovy.lang.Script;
027    
028    import java.util.HashMap;
029    import java.util.Map;
030    import java.util.Set;
031    import java.util.WeakHashMap;
032    
033    /**
034     * @author Alberto Montero
035     * @author Brian Wing Shun Chan
036     */
037    public class GroovyExecutor extends BaseScriptingExecutor {
038    
039            @Override
040            public void clearCache() {
041                    SingleVMPoolUtil.clear(_CACHE_NAME);
042            }
043    
044            public Map<String, Object> eval(
045                            Set<String> allowedClasses, Map<String, Object> inputObjects,
046                            Set<String> outputNames, String script, ClassLoader... classLoaders)
047                    throws ScriptingException {
048    
049                    if (allowedClasses != null) {
050                            throw new ExecutionException(
051                                    "Constrained execution not supported for Groovy");
052                    }
053    
054                    Script compiledScript = getCompiledScript(script, classLoaders);
055    
056                    Binding binding = new Binding(inputObjects);
057    
058                    compiledScript.setBinding(binding);
059    
060                    compiledScript.run();
061    
062                    if (outputNames == null) {
063                            return null;
064                    }
065    
066                    Map<String, Object> outputObjects = new HashMap<String, Object>();
067    
068                    for (String outputName : outputNames) {
069                            outputObjects.put(outputName, binding.getVariable(outputName));
070                    }
071    
072                    return outputObjects;
073            }
074    
075            public String getLanguage() {
076                    return _LANGUAGE;
077            }
078    
079            protected Script getCompiledScript(
080                    String script, ClassLoader[] classLoaders) {
081    
082                    GroovyShell groovyShell = getGroovyShell(classLoaders);
083    
084                    String key = String.valueOf(script.hashCode());
085    
086                    Script compiledScript = (Script)SingleVMPoolUtil.get(_CACHE_NAME, key);
087    
088                    if (compiledScript == null) {
089                            compiledScript = groovyShell.parse(script);
090    
091                            SingleVMPoolUtil.put(_CACHE_NAME, key, compiledScript);
092                    }
093    
094                    return compiledScript;
095            }
096    
097            protected GroovyShell getGroovyShell(ClassLoader[] classLoaders) {
098                    if ((classLoaders == null) || (classLoaders.length == 0)) {
099                            if (_groovyShell == null) {
100                                    synchronized (this) {
101                                            if (_groovyShell == null) {
102                                                    _groovyShell = new GroovyShell();
103                                            }
104                                    }
105                            }
106    
107                            return _groovyShell;
108                    }
109    
110                    ClassLoader aggregateClassLoader =
111                            AggregateClassLoader.getAggregateClassLoader(
112                                    PACLClassLoaderUtil.getPortalClassLoader(), classLoaders);
113    
114                    GroovyShell groovyShell = null;
115    
116                    if (!_groovyShells.containsKey(aggregateClassLoader)) {
117                            synchronized (this) {
118                                    if (!_groovyShells.containsKey(aggregateClassLoader)) {
119                                            groovyShell = new GroovyShell(aggregateClassLoader);
120    
121                                            _groovyShells.put(aggregateClassLoader, groovyShell);
122                                    }
123                            }
124                    }
125    
126                    return groovyShell;
127            }
128    
129            private static final String _CACHE_NAME = GroovyExecutor.class.getName();
130    
131            private static final String _LANGUAGE = "groovy";
132    
133            private volatile GroovyShell _groovyShell = new GroovyShell();
134            private volatile Map<ClassLoader, GroovyShell> _groovyShells =
135                    new WeakHashMap<ClassLoader, GroovyShell>();
136    
137    }