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