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