001    /**
002     * Copyright (c) 2000-2010 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.portlet.layoutconfiguration.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.servlet.PipingServletResponse;
021    import com.liferay.portal.kernel.util.JavaConstants;
022    import com.liferay.portal.kernel.util.MethodHandler;
023    import com.liferay.portal.kernel.util.MethodKey;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.velocity.VelocityContext;
029    import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
030    import com.liferay.portal.model.Portlet;
031    import com.liferay.portal.service.PortletLocalServiceUtil;
032    import com.liferay.portal.theme.PortletDisplay;
033    import com.liferay.portal.theme.PortletDisplayFactory;
034    import com.liferay.portal.theme.ThemeDisplay;
035    import com.liferay.portal.util.PortalUtil;
036    import com.liferay.portal.util.WebKeys;
037    import com.liferay.portal.velocity.VelocityVariables;
038    import com.liferay.portlet.layoutconfiguration.util.velocity.TemplateProcessor;
039    import com.liferay.portlet.layoutconfiguration.util.xml.RuntimeLogic;
040    
041    import java.util.HashMap;
042    import java.util.Map;
043    
044    import javax.portlet.PortletConfig;
045    import javax.portlet.RenderRequest;
046    import javax.portlet.RenderResponse;
047    
048    import javax.servlet.ServletContext;
049    import javax.servlet.http.HttpServletRequest;
050    import javax.servlet.http.HttpServletResponse;
051    import javax.servlet.jsp.JspWriter;
052    import javax.servlet.jsp.PageContext;
053    
054    /**
055     * @author Brian Wing Shun Chan
056     * @author Raymond Augé
057     * @author Shuyang Zhou
058     */
059    public class RuntimePortletUtil {
060    
061            public static String processPortlet(
062                            ServletContext servletContext, HttpServletRequest request,
063                            HttpServletResponse response, RenderRequest renderRequest,
064                            RenderResponse renderResponse, String portletId, String queryString,
065                            boolean writeOutput)
066                    throws Exception {
067    
068                    return processPortlet(
069                            servletContext, request, response, renderRequest, renderResponse,
070                            portletId, queryString, null, null, null, writeOutput);
071            }
072    
073            public static String processPortlet(
074                            ServletContext servletContext, HttpServletRequest request,
075                            HttpServletResponse response, RenderRequest renderRequest,
076                            RenderResponse renderResponse, String portletId, String queryString,
077                            String columnId, Integer columnPos, Integer columnCount,
078                            boolean writeOutput)
079                    throws Exception {
080    
081                    return processPortlet(
082                            servletContext, request, response, renderRequest, renderResponse,
083                            null, portletId, queryString, columnId, columnPos, columnCount,
084                            null, writeOutput);
085            }
086    
087            public static String processPortlet(
088                            ServletContext servletContext, HttpServletRequest request,
089                            HttpServletResponse response, Portlet portlet, String queryString,
090                            String columnId, Integer columnPos, Integer columnCount,
091                            String path, boolean writeOutput)
092                    throws Exception {
093    
094                    return processPortlet(
095                            servletContext, request, response, null, null, portlet,
096                            portlet.getPortletId(), queryString, columnId, columnPos,
097                            columnCount, path, writeOutput);
098            }
099    
100            public static String processPortlet(
101                            ServletContext servletContext, HttpServletRequest request,
102                            HttpServletResponse response, RenderRequest renderRequest,
103                            RenderResponse renderResponse, Portlet portlet, String portletId,
104                            String queryString, String columnId, Integer columnPos,
105                            Integer columnCount, String path, boolean writeOutput)
106                    throws Exception {
107    
108                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
109                            WebKeys.THEME_DISPLAY);
110    
111                    if (portlet == null) {
112                            portlet = PortletLocalServiceUtil.getPortletById(
113                                    themeDisplay.getCompanyId(), portletId);
114                    }
115    
116                    if ((portlet != null) && (portlet.isInstanceable()) &&
117                            (!portlet.isAddDefaultResource())) {
118    
119                            String instanceId = portlet.getInstanceId();
120    
121                            if (Validator.isNotNull(instanceId) &&
122                                    Validator.isPassword(instanceId) &&
123                                    (instanceId.length() == 4)) {
124    
125                                    /*portletId +=
126                                            PortletConstants.INSTANCE_SEPARATOR + instanceId;
127    
128                                    portlet = PortletLocalServiceUtil.getPortletById(
129                                            themeDisplay.getCompanyId(), portletId);*/
130                            }
131                            else {
132                                    if (_log.isDebugEnabled()) {
133                                            _log.debug(
134                                                    "Portlet " + portlet.getPortletId() +
135                                                            " is instanceable but does not have a " +
136                                                                    "valid instance id");
137                                    }
138    
139                                    portlet = null;
140                            }
141                    }
142    
143                    if (portlet == null) {
144                            return StringPool.BLANK;
145                    }
146    
147                    // Capture the current portlet's settings to reset them once the child
148                    // portlet is rendered
149    
150                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
151    
152                    PortletDisplay portletDisplayClone = PortletDisplayFactory.create();
153    
154                    portletDisplay.copyTo(portletDisplayClone);
155    
156                    PortletConfig portletConfig = (PortletConfig)request.getAttribute(
157                            JavaConstants.JAVAX_PORTLET_CONFIG);
158    
159                    try {
160                            return PortalUtil.renderPortlet(
161                                    servletContext, request, response, portlet, queryString,
162                                    columnId, columnPos, columnCount, path, writeOutput);
163                    }
164                    finally {
165                            portletDisplay.copyFrom(portletDisplayClone);
166    
167                            portletDisplayClone.recycle();
168    
169                            _defineObjects(
170                                    request, portletConfig, renderRequest, renderResponse);
171                    }
172            }
173    
174            public static void processTemplate(
175                            ServletContext servletContext, HttpServletRequest request,
176                            HttpServletResponse response, PageContext pageContext,
177                            JspWriter jspWriter, String velocityTemplateId,
178                            String velocityTemplateContent)
179                    throws Exception {
180    
181                    processTemplate(
182                            servletContext, request, response, pageContext, jspWriter, null,
183                            velocityTemplateId, velocityTemplateContent);
184            }
185    
186            public static void processTemplate(
187                            ServletContext servletContext, HttpServletRequest request,
188                            HttpServletResponse response, PageContext pageContext,
189                            JspWriter jspWriter, String portletId, String velocityTemplateId,
190                            String velocityTemplateContent)
191                    throws Exception {
192    
193                    if (Validator.isNull(velocityTemplateContent)) {
194                            return;
195                    }
196    
197                    TemplateProcessor processor = new TemplateProcessor(
198                            servletContext, request, response, portletId);
199    
200                    VelocityContext velocityContext =
201                            VelocityEngineUtil.getWrappedStandardToolsContext();
202    
203                    velocityContext.put("processor", processor);
204    
205                    // Velocity variables
206    
207                    VelocityVariables.insertVariables(velocityContext, request);
208    
209                    // liferay:include tag library
210    
211                    UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
212    
213                    MethodHandler methodHandler = new MethodHandler(
214                            _initMethodKey, servletContext, request,
215                            new PipingServletResponse(response, unsyncStringWriter),
216                            pageContext);
217    
218                    Object velocityTaglib = methodHandler.invoke(true);
219    
220                    velocityContext.put("taglibLiferay", velocityTaglib);
221                    velocityContext.put("theme", velocityTaglib);
222    
223                    try {
224                            VelocityEngineUtil.mergeTemplate(
225                                    velocityTemplateId, velocityTemplateContent, velocityContext,
226                                    unsyncStringWriter);
227                    }
228                    catch (Exception e) {
229                            _log.error(e, e);
230    
231                            throw e;
232                    }
233    
234                    String output = unsyncStringWriter.toString();
235    
236                    Map<Portlet, Object[]> portletsMap = processor.getPortletsMap();
237    
238                    Map<String, StringBundler> contentsMap =
239                            new HashMap<String, StringBundler>(portletsMap.size());
240    
241                    for (Map.Entry<Portlet, Object[]> entry : portletsMap.entrySet()) {
242                            Portlet portlet = entry.getKey();
243                            Object[] value = entry.getValue();
244    
245                            String queryString = (String)value[0];
246                            String columnId = (String)value[1];
247                            Integer columnPos = (Integer)value[2];
248                            Integer columnCount = (Integer)value[3];
249    
250                            UnsyncStringWriter portletUnsyncStringWriter =
251                                    new UnsyncStringWriter();
252    
253                            PipingServletResponse pipingServletResponse =
254                                    new PipingServletResponse(response, portletUnsyncStringWriter);
255    
256                            processPortlet(
257                                    servletContext, request, pipingServletResponse, portlet,
258                                    queryString, columnId, columnPos, columnCount, null, true);
259    
260                            contentsMap.put(
261                                    portlet.getPortletId(),
262                                    portletUnsyncStringWriter.getStringBundler());
263                    }
264    
265                    StringBundler sb = StringUtil.replaceWithStringBundler(
266                            output, "[$TEMPLATE_PORTLET_", "$]", contentsMap);
267    
268                    sb.writeTo(jspWriter);
269            }
270    
271            public static String processXML(
272                            HttpServletRequest request, String content,
273                            RuntimeLogic runtimeLogic)
274                    throws Exception {
275    
276                    if (Validator.isNull(content)) {
277                            return StringPool.BLANK;
278                    }
279    
280                    try {
281                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
282    
283                            StringBuilder sb = new StringBuilder();
284    
285                            int x = 0;
286                            int y = content.indexOf(runtimeLogic.getOpenTag());
287    
288                            while (y != -1) {
289                                    sb.append(content.substring(x, y));
290    
291                                    int close1 = content.indexOf(runtimeLogic.getClose1Tag(), y);
292                                    int close2 = content.indexOf(runtimeLogic.getClose2Tag(), y);
293    
294                                    if ((close2 == -1) || ((close1 != -1) && (close1 < close2))) {
295                                            x = close1 + runtimeLogic.getClose1Tag().length();
296                                    }
297                                    else {
298                                            x = close2 + runtimeLogic.getClose2Tag().length();
299                                    }
300    
301                                    sb.append(runtimeLogic.processXML(content.substring(y, x)));
302    
303                                    y = content.indexOf(runtimeLogic.getOpenTag(), x);
304                            }
305    
306                            if (y == -1) {
307                                    sb.append(content.substring(x, content.length()));
308                            }
309    
310                            return sb.toString();
311                    }
312                    finally {
313                            request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
314                    }
315            }
316    
317            private static void _defineObjects(
318                    HttpServletRequest request, PortletConfig portletConfig,
319                    RenderRequest renderRequest, RenderResponse renderResponse) {
320    
321                    if (portletConfig != null) {
322                            request.setAttribute(
323                                    JavaConstants.JAVAX_PORTLET_CONFIG, portletConfig);
324                    }
325    
326                    if (renderRequest != null) {
327                            request.setAttribute(
328                                    JavaConstants.JAVAX_PORTLET_REQUEST, renderRequest);
329                    }
330    
331                    if (renderResponse != null) {
332                            request.setAttribute(
333                                    JavaConstants.JAVAX_PORTLET_RESPONSE, renderResponse);
334                    }
335            }
336    
337            private static Log _log = LogFactoryUtil.getLog(RuntimePortletUtil.class);
338    
339            private static MethodKey _initMethodKey = new MethodKey(
340                    "com.liferay.taglib.util.VelocityTaglib", "init", ServletContext.class,
341                    HttpServletRequest.class, HttpServletResponse.class, PageContext.class);
342    
343    }