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;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
018    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.scripting.Scripting;
022    import com.liferay.portal.kernel.scripting.ScriptingException;
023    import com.liferay.portal.kernel.scripting.ScriptingExecutor;
024    import com.liferay.portal.kernel.scripting.UnsupportedLanguageException;
025    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    
029    import java.io.IOException;
030    import java.io.LineNumberReader;
031    
032    import java.util.HashMap;
033    import java.util.Map;
034    import java.util.Set;
035    import java.util.concurrent.ConcurrentHashMap;
036    
037    import javax.portlet.ActionRequest;
038    import javax.portlet.ActionResponse;
039    import javax.portlet.PortletConfig;
040    import javax.portlet.PortletContext;
041    import javax.portlet.PortletRequest;
042    import javax.portlet.PortletResponse;
043    import javax.portlet.RenderRequest;
044    import javax.portlet.RenderResponse;
045    import javax.portlet.ResourceRequest;
046    import javax.portlet.ResourceResponse;
047    
048    import org.apache.commons.lang.time.StopWatch;
049    
050    import org.python.core.Py;
051    import org.python.core.PyFile;
052    import org.python.core.PySyntaxError;
053    
054    /**
055     * @author Alberto Montero
056     * @author Brian Wing Shun Chan
057     */
058    @DoPrivileged
059    public class ScriptingImpl implements Scripting {
060    
061            @Override
062            public void addScriptingExecutor(
063                    String language, ScriptingExecutor scriptingExecutor) {
064    
065                    _scriptingExecutors.put(language, scriptingExecutor);
066            }
067    
068            @Override
069            public void clearCache(String language) throws ScriptingException {
070                    ScriptingExecutor scriptingExecutor = _scriptingExecutors.get(language);
071    
072                    if (scriptingExecutor == null) {
073                            throw new UnsupportedLanguageException(language);
074                    }
075    
076                    scriptingExecutor.clearCache();
077            }
078    
079            @Override
080            public Map<String, Object> eval(
081                            Set<String> allowedClasses, Map<String, Object> inputObjects,
082                            Set<String> outputNames, String language, String script,
083                            ClassLoader... classLoaders)
084                    throws ScriptingException {
085    
086                    ScriptingExecutor scriptingExecutor = _scriptingExecutors.get(language);
087    
088                    if (scriptingExecutor == null) {
089                            throw new UnsupportedLanguageException(language);
090                    }
091    
092                    StopWatch stopWatch = null;
093    
094                    if (_log.isDebugEnabled()) {
095                            stopWatch = new StopWatch();
096    
097                            stopWatch.start();
098                    }
099    
100                    try {
101                            return scriptingExecutor.eval(
102                                    allowedClasses, inputObjects, outputNames, script,
103                                    classLoaders);
104                    }
105                    catch (Exception e) {
106                            throw new ScriptingException(getErrorMessage(script, e), e);
107                    }
108                    finally {
109                            if (_log.isDebugEnabled()) {
110                                    _log.debug(
111                                            "Evaluated script in " + stopWatch.getTime() + " ms");
112                            }
113                    }
114            }
115    
116            @Override
117            public void exec(
118                            Set<String> allowedClasses, Map<String, Object> inputObjects,
119                            String language, String script, ClassLoader... classLoaders)
120                    throws ScriptingException {
121    
122                    eval(
123                            allowedClasses, inputObjects, null, language, script, classLoaders);
124            }
125    
126            @Override
127            public Map<String, Object> getPortletObjects(
128                    PortletConfig portletConfig, PortletContext portletContext,
129                    PortletRequest portletRequest, PortletResponse portletResponse) {
130    
131                    Map<String, Object> objects = new HashMap<String, Object>();
132    
133                    objects.put("portletConfig", portletConfig);
134                    objects.put("portletContext", portletContext);
135                    objects.put("preferences", portletRequest.getPreferences());
136    
137                    if (portletRequest instanceof ActionRequest) {
138                            objects.put("actionRequest", portletRequest);
139                    }
140                    else if (portletRequest instanceof RenderRequest) {
141                            objects.put("renderRequest", portletRequest);
142                    }
143                    else if (portletRequest instanceof ResourceRequest) {
144                            objects.put("resourceRequest", portletRequest);
145                    }
146                    else {
147                            objects.put("portletRequest", portletRequest);
148                    }
149    
150                    if (portletResponse instanceof ActionResponse) {
151                            objects.put("actionResponse", portletResponse);
152                    }
153                    else if (portletResponse instanceof RenderResponse) {
154                            objects.put("renderResponse", portletResponse);
155                    }
156                    else if (portletResponse instanceof ResourceResponse) {
157                            objects.put("resourceResponse", portletResponse);
158                    }
159                    else {
160                            objects.put("portletResponse", portletResponse);
161                    }
162    
163                    objects.put(
164                            "userInfo", portletRequest.getAttribute(PortletRequest.USER_INFO));
165    
166                    return objects;
167            }
168    
169            @Override
170            public Set<String> getSupportedLanguages() {
171                    return _scriptingExecutors.keySet();
172            }
173    
174            @Override
175            public void setScriptingExecutors(
176                    Map<String, ScriptingExecutor> scriptingExecutors) {
177    
178                    for (Map.Entry<String, ScriptingExecutor> entry :
179                                    scriptingExecutors.entrySet()) {
180    
181                            _scriptingExecutors.put(entry.getKey(), entry.getValue());
182                    }
183            }
184    
185            protected String getErrorMessage(Exception e) {
186                    String message = e.getMessage();
187    
188                    if (e instanceof PySyntaxError) {
189                            PySyntaxError pySyntaxError = (PySyntaxError)e;
190    
191                            UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
192                                    new UnsyncByteArrayOutputStream();
193    
194                            Py.displayException(
195                                    pySyntaxError.type, pySyntaxError.value,
196                                    pySyntaxError.traceback,
197                                    new PyFile(unsyncByteArrayOutputStream));
198    
199                            message = unsyncByteArrayOutputStream.toString();
200                    }
201    
202                    return message;
203            }
204    
205            protected String getErrorMessage(String script, Exception e) {
206                    StringBundler sb = new StringBundler();
207    
208                    sb.append(getErrorMessage(e));
209                    sb.append(StringPool.NEW_LINE);
210    
211                    try {
212                            LineNumberReader lineNumberReader = new LineNumberReader(
213                                    new UnsyncStringReader(script));
214    
215                            while (true) {
216                                    String line = lineNumberReader.readLine();
217    
218                                    if (line == null) {
219                                            break;
220                                    }
221    
222                                    sb.append("Line ");
223                                    sb.append(lineNumberReader.getLineNumber());
224                                    sb.append(": ");
225                                    sb.append(line);
226                                    sb.append(StringPool.NEW_LINE);
227                            }
228                    }
229                    catch (IOException ioe) {
230                            sb.setIndex(0);
231    
232                            sb.append(getErrorMessage(e));
233                            sb.append(StringPool.NEW_LINE);
234                            sb.append(script);
235                    }
236    
237                    return sb.toString();
238            }
239    
240            private static Log _log = LogFactoryUtil.getLog(ScriptingImpl.class);
241    
242            private Map<String, ScriptingExecutor> _scriptingExecutors =
243                    new ConcurrentHashMap<String, ScriptingExecutor>();
244    
245    }