001    /**
002     * Copyright (c) 2000-2013 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.python;
016    
017    import com.liferay.portal.kernel.cache.PortalCache;
018    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
019    import com.liferay.portal.kernel.scripting.BaseScriptingExecutor;
020    import com.liferay.portal.kernel.scripting.ExecutionException;
021    import com.liferay.portal.kernel.scripting.ScriptingException;
022    
023    import java.util.HashMap;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import org.python.core.CompileMode;
028    import org.python.core.Py;
029    import org.python.core.PyCode;
030    import org.python.core.PyObject;
031    import org.python.core.PySystemState;
032    import org.python.util.InteractiveInterpreter;
033    
034    /**
035     * @author Alberto Montero
036     */
037    public class PythonExecutor extends BaseScriptingExecutor {
038    
039            @Override
040            public void clearCache() {
041                    _portalCache.removeAll();
042            }
043    
044            @Override
045            public Map<String, Object> eval(
046                            Set<String> allowedClasses, Map<String, Object> inputObjects,
047                            Set<String> outputNames, String script, ClassLoader... classLoaders)
048                    throws ScriptingException {
049    
050                    if (allowedClasses != null) {
051                            throw new ExecutionException(
052                                    "Constrained execution not supported for Python");
053                    }
054    
055                    PyCode compiledScript = getCompiledScript(script);
056    
057                    InteractiveInterpreter interactiveInterpreter =
058                            new InteractiveInterpreter();
059    
060                    for (Map.Entry<String, Object> entry : inputObjects.entrySet()) {
061                            String key = entry.getKey();
062                            Object value = entry.getValue();
063    
064                            interactiveInterpreter.set(key, value);
065                    }
066    
067                    interactiveInterpreter.exec(compiledScript);
068    
069                    if (outputNames == null) {
070                            return null;
071                    }
072    
073                    Map<String, Object> outputObjects = new HashMap<String, Object>();
074    
075                    for (String outputName : outputNames) {
076                            PyObject pyObject = interactiveInterpreter.get(outputName);
077    
078                            outputObjects.put(outputName, pyObject.__tojava__(Object.class));
079                    }
080    
081                    return outputObjects;
082            }
083    
084            @Override
085            public String getLanguage() {
086                    return _LANGUAGE;
087            }
088    
089            protected PyCode getCompiledScript(String script) {
090                    if (!_initialized) {
091                            synchronized (this) {
092                                    if (!_initialized) {
093                                            PySystemState.initialize();
094    
095                                            _initialized = true;
096                                    }
097                            }
098                    }
099    
100                    String key = String.valueOf(script.hashCode());
101    
102                    PyCode compiledScript = _portalCache.get(key);
103    
104                    if (compiledScript == null) {
105                            compiledScript = Py.compile_flags(
106                                    script, "<string>", CompileMode.exec, Py.getCompilerFlags());
107    
108                            _portalCache.put(key, compiledScript);
109                    }
110    
111                    return compiledScript;
112            }
113    
114            private static final String _CACHE_NAME = PythonExecutor.class.getName();
115    
116            private static final String _LANGUAGE = "python";
117    
118            private volatile boolean _initialized;
119            private PortalCache<String, PyCode> _portalCache =
120                    SingleVMPoolUtil.getCache(_CACHE_NAME);
121    
122    }