/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.util.bridges.scripting; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.portlet.PortletResponseUtil; import com.liferay.portal.kernel.scripting.ScriptingException; import com.liferay.portal.kernel.scripting.ScriptingHelperUtil; import com.liferay.portal.kernel.scripting.ScriptingUtil; import com.liferay.portal.kernel.security.permission.ActionKeys; import com.liferay.portal.kernel.security.permission.PermissionChecker; import com.liferay.portal.kernel.service.permission.PortalPermissionUtil; import com.liferay.portal.kernel.servlet.SessionErrors; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.ContentTypes; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.HtmlUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import java.io.IOException; import java.io.InputStream; import java.util.Map; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.GenericPortlet; import javax.portlet.PortletConfig; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; /** * @author Jorge Ferrer * @author Brian Wing Shun Chan * @author Alberto Montero */ public class ScriptingPortlet extends GenericPortlet { @Override public void doDispatch( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { String fileName = getFileName(renderRequest); if (fileName != null) { include(fileName, renderRequest, renderResponse); } else { super.doDispatch(renderRequest, renderResponse); } } @Override public void doEdit( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { if (renderRequest.getPreferences() == null) { super.doEdit(renderRequest, renderResponse); } else { include(editFile, renderRequest, renderResponse); } } @Override public void doHelp( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(helpFile, renderRequest, renderResponse); } @Override public void doView( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(viewFile, renderRequest, renderResponse); } @Override public void init() throws PortletException { super.init(); filePath = getInitParameter("file-path"); if (Validator.isNull(filePath)) { throw new PortletException("file-path parameter is not set"); } else if (filePath.contains(StringPool.BACK_SLASH) || filePath.contains(StringPool.DOUBLE_SLASH) || filePath.contains(StringPool.PERIOD) || filePath.contains(StringPool.SPACE)) { throw new PortletException( "template-path " + filePath + " has invalid characters"); } else if (!filePath.startsWith(StringPool.SLASH) || !filePath.endsWith(StringPool.SLASH)) { throw new PortletException( "template-path " + filePath + " must start and end with a /"); } actionFile = getInitParameter("action-file"); editFile = getInitParameter("edit-file"); helpFile = getInitParameter("help-file"); resourceFile = getInitParameter("resource-file"); viewFile = getInitParameter("view-file"); language = getInitParameter("scripting-language"); globalFiles = StringUtil.split(getInitParameter("global-files")); } @Override public void processAction( ActionRequest actionRequest, ActionResponse actionResponse) throws IOException, PortletException { include(actionFile, actionRequest, actionResponse); } @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { try { doRender(renderRequest, renderResponse); } catch (IOException ioe) { throw ioe; } catch (PortletException pe) { throw pe; } catch (Exception e) { throw new PortletException(e); } } @Override public void serveResource( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { include(resourceFile, resourceRequest, resourceResponse); } protected void checkPath(String path) throws PortletException { if (Validator.isNotNull(path) && (!path.startsWith(filePath) || !Validator.isFilePath(path, false))) { throw new PortletException( "Path " + path + " is not accessible by this portlet"); } } protected void declareBeans( InputStream is, PortletRequest portletRequest, PortletResponse portletResponse) throws IOException, ScriptingException { String script = new String(FileUtil.getBytes(is)); declareBeans(script, portletRequest, portletResponse); } protected void declareBeans( String script, PortletRequest portletRequest, PortletResponse portletResponse) throws IOException, ScriptingException { script = getGlobalScript() + script; PortletConfig portletConfig = getPortletConfig(); PortletContext portletContext = getPortletContext(); Map<String, Object> portletObjects = ScriptingHelperUtil.getPortletObjects( portletConfig, portletContext, portletRequest, portletResponse); ScriptingUtil.exec(null, portletObjects, language, script); } protected void doRender( RenderRequest renderRequest, RenderResponse renderResponse) throws Exception { Object error = SessionErrors.get(renderRequest, _ERROR); if (error != null) { Exception e = (Exception)error; writeErrorMessage(renderRequest, renderResponse, e.getMessage()); return; } super.render(renderRequest, renderResponse); error = SessionErrors.get(renderRequest, _ERROR); if (error != null) { Exception e = (Exception)error; writeErrorMessage(renderRequest, renderResponse, e.getMessage()); } } protected String getFileName(RenderRequest renderRequest) { return renderRequest.getParameter("file"); } protected String getGlobalScript() throws IOException { if (globalScript != null) { return globalScript; } if (globalFiles.length == 0) { globalScript = StringPool.BLANK; return globalScript; } StringBundler sb = new StringBundler(); for (String globalFile : globalFiles) { PortletContext portletContext = getPortletContext(); InputStream inputStream = portletContext.getResourceAsStream( globalFile); if (inputStream == null) { if (_log.isWarnEnabled()) { _log.warn("Global file " + globalFile + " does not exist"); } } if (inputStream != null) { String script = new String(FileUtil.getBytes(inputStream)); sb.append(script); sb.append(StringPool.NEW_LINE); } } globalScript = sb.toString(); return globalScript; } protected void include( String path, PortletRequest portletRequest, PortletResponse portletResponse) throws IOException, PortletException { checkPath(path); PortletContext portletContext = getPortletContext(); InputStream inputStream = portletContext.getResourceAsStream(path); if (inputStream == null) { _log.error(path + " is not a valid " + language + " file"); return; } try { declareBeans(inputStream, portletRequest, portletResponse); } catch (ScriptingException se) { SessionErrors.add(portletRequest, _ERROR, se); } finally { inputStream.close(); } } protected void writeErrorMessage( RenderRequest renderRequest, RenderResponse renderResponse, String errorMessage) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute( WebKeys.THEME_DISPLAY); PermissionChecker permissionChecker = themeDisplay.getPermissionChecker(); StringBundler sb = new StringBundler(6); sb.append("<div class=\"alert alert-error\">"); sb.append(themeDisplay.translate("an-unexpected-error-occurred")); sb.append("</div>"); if (PortalPermissionUtil.contains( permissionChecker, ActionKeys.CONFIGURATION)) { sb.append("<pre>"); sb.append(HtmlUtil.escape(errorMessage)); sb.append("</pre>"); } renderResponse.setContentType(ContentTypes.TEXT_HTML); PortletResponseUtil.write(renderResponse, sb.toString()); } protected String actionFile; protected String editFile; protected String filePath; protected String[] globalFiles; protected String globalScript; protected String helpFile; protected String language; protected String resourceFile; protected String viewFile; private static final String _ERROR = ScriptingPortlet.class + ".ERROR"; private static final Log _log = LogFactoryUtil.getLog( ScriptingPortlet.class); }