001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
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.PySystemState;
031    import org.python.util.InteractiveInterpreter;
032    
033    /**
034     * @author Alberto Montero
035     */
036    public class PythonExecutor extends BaseScriptingExecutor {
037    
038            @Override
039            public void clearCache() {
040                    _portalCache.removeAll();
041            }
042    
043            @Override
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 Python");
052                    }
053    
054                    PyCode compiledScript = getCompiledScript(script);
055    
056                    InteractiveInterpreter interactiveInterpreter =
057                            new InteractiveInterpreter();
058    
059                    for (Map.Entry<String, Object> entry : inputObjects.entrySet()) {
060                            String key = entry.getKey();
061                            Object value = entry.getValue();
062    
063                            interactiveInterpreter.set(key, value);
064                    }
065    
066                    interactiveInterpreter.exec(compiledScript);
067    
068                    if (outputNames == null) {
069                            return null;
070                    }
071    
072                    Map<String, Object> outputObjects = new HashMap<String, Object>();
073    
074                    for (String outputName : outputNames) {
075                            outputObjects.put(
076                                    outputName, interactiveInterpreter.get(outputName));
077                    }
078    
079                    return outputObjects;
080            }
081    
082            @Override
083            public String getLanguage() {
084                    return _LANGUAGE;
085            }
086    
087            protected PyCode getCompiledScript(String script) {
088                    if (!_initialized) {
089                            synchronized (this) {
090                                    if (!_initialized) {
091                                            PySystemState.initialize();
092    
093                                            _initialized = true;
094                                    }
095                            }
096                    }
097    
098                    String key = String.valueOf(script.hashCode());
099    
100                    PyCode compiledScript = _portalCache.get(key);
101    
102                    if (compiledScript == null) {
103                            compiledScript = Py.compile_flags(
104                                    script, "<string>", CompileMode.exec, Py.getCompilerFlags());
105    
106                            _portalCache.put(key, compiledScript);
107                    }
108    
109                    return compiledScript;
110            }
111    
112            private static final String _CACHE_NAME = PythonExecutor.class.getName();
113    
114            private static final String _LANGUAGE = "python";
115    
116            private volatile boolean _initialized;
117            private PortalCache<String, PyCode> _portalCache =
118                    SingleVMPoolUtil.getCache(_CACHE_NAME);
119    
120    }