001    /**
002     * Copyright (c) 2000-2011 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, RenderRequest renderRequest,
118                            RenderResponse renderResponse, String portletId, String queryString,
119                            boolean writeOutput)
120                    throws Exception {
121    
122                    return processPortlet(
123                            servletContext, request, response, renderRequest, renderResponse,
124                            portletId, queryString, null, null, null, writeOutput);
125            }
126    
127            public String processPortlet(
128                            ServletContext servletContext, HttpServletRequest request,
129                            HttpServletResponse response, RenderRequest renderRequest,
130                            RenderResponse renderResponse, String portletId, String queryString,
131                            String columnId, Integer columnPos, Integer columnCount,
132                            boolean writeOutput)
133                    throws Exception {
134    
135                    return processPortlet(
136                            servletContext, request, response, renderRequest, renderResponse,
137                            null, portletId, queryString, columnId, columnPos, columnCount,
138                            null, writeOutput);
139            }
140    
141            public String processPortlet(
142                            ServletContext servletContext, HttpServletRequest request,
143                            HttpServletResponse response, Portlet portlet, String queryString,
144                            String columnId, Integer columnPos, Integer columnCount,
145                            String path, boolean writeOutput)
146                    throws Exception {
147    
148                    return processPortlet(
149                            servletContext, request, response, null, null, portlet,
150                            portlet.getPortletId(), queryString, columnId, columnPos,
151                            columnCount, path, writeOutput);
152            }
153    
154            public String processPortlet(
155                            ServletContext servletContext, HttpServletRequest request,
156                            HttpServletResponse response, RenderRequest renderRequest,
157                            RenderResponse renderResponse, Portlet portlet, String portletId,
158                            String queryString, String columnId, Integer columnPos,
159                            Integer columnCount, String path, boolean writeOutput)
160                    throws Exception {
161    
162                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
163                            WebKeys.THEME_DISPLAY);
164    
165                    if (portlet == null) {
166                            portlet = PortletLocalServiceUtil.getPortletById(
167                                    themeDisplay.getCompanyId(), portletId);
168                    }
169    
170                    if ((portlet != null) && (portlet.isInstanceable()) &&
171                            (!portlet.isAddDefaultResource())) {
172    
173                            String instanceId = portlet.getInstanceId();
174    
175                            if (Validator.isNotNull(instanceId) &&
176                                    Validator.isPassword(instanceId) &&
177                                    (instanceId.length() >= 4)) {
178    
179                                    /*portletId += PortletConstants.INSTANCE_SEPARATOR + instanceId;
180    
181                                    portlet = PortletLocalServiceUtil.getPortletById(
182                                            themeDisplay.getCompanyId(), portletId);*/
183                            }
184                            else {
185                                    if (_log.isDebugEnabled()) {
186                                            _log.debug(
187                                                    "Portlet " + portlet.getPortletId() +
188                                                            " is instanceable but does not have a " +
189                                                                    "valid instance id");
190                                    }
191    
192                                    portlet = null;
193                            }
194                    }
195    
196                    if (portlet == null) {
197                            return StringPool.BLANK;
198                    }
199    
200                    // Capture the current portlet's settings to reset them once the child
201                    // portlet is rendered
202    
203                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
204    
205                    PortletDisplay portletDisplayClone = PortletDisplayFactory.create();
206    
207                    portletDisplay.copyTo(portletDisplayClone);
208    
209                    PortletConfig portletConfig = (PortletConfig)request.getAttribute(
210                            JavaConstants.JAVAX_PORTLET_CONFIG);
211    
212                    try {
213                            return PortalUtil.renderPortlet(
214                                    servletContext, request, response, portlet, queryString,
215                                    columnId, columnPos, columnCount, path, writeOutput);
216                    }
217                    finally {
218                            portletDisplay.copyFrom(portletDisplayClone);
219    
220                            portletDisplayClone.recycle();
221    
222                            _defineObjects(
223                                    request, portletConfig, renderRequest, renderResponse);
224                    }
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                    Portlet renderPortlet = (Portlet)request.getAttribute(
334                            WebKeys.RENDER_PORTLET);
335    
336                    Boolean renderPortletResource = (Boolean)request.getAttribute(
337                            WebKeys.RENDER_PORTLET_RESOURCE);
338    
339                    String outerPortletId = (String)request.getAttribute(
340                            WebKeys.OUTER_PORTLET_ID);
341    
342                    if (outerPortletId == null) {
343                            request.setAttribute(
344                                    WebKeys.OUTER_PORTLET_ID, renderPortlet.getPortletId());
345                    }
346    
347                    try {
348                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
349    
350                            StringBuilder sb = new StringBuilder();
351    
352                            int x = 0;
353                            int y = content.indexOf(runtimeLogic.getOpenTag());
354    
355                            while (y != -1) {
356                                    sb.append(content.substring(x, y));
357    
358                                    int close1 = content.indexOf(runtimeLogic.getClose1Tag(), y);
359                                    int close2 = content.indexOf(runtimeLogic.getClose2Tag(), y);
360    
361                                    if ((close2 == -1) || ((close1 != -1) && (close1 < close2))) {
362                                            x = close1 + runtimeLogic.getClose1Tag().length();
363                                    }
364                                    else {
365                                            x = close2 + runtimeLogic.getClose2Tag().length();
366                                    }
367    
368                                    sb.append(runtimeLogic.processXML(content.substring(y, x)));
369    
370                                    y = content.indexOf(runtimeLogic.getOpenTag(), x);
371                            }
372    
373                            if (y == -1) {
374                                    sb.append(content.substring(x, content.length()));
375                            }
376    
377                            return sb.toString();
378                    }
379                    finally {
380                            if (outerPortletId == null) {
381                                    request.removeAttribute(WebKeys.OUTER_PORTLET_ID);
382                            }
383    
384                            request.setAttribute(WebKeys.RENDER_PORTLET, renderPortlet);
385    
386                            if (renderPortletResource == null) {
387                                    request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
388                            }
389                            else {
390                                    request.setAttribute(
391                                            WebKeys.RENDER_PORTLET_RESOURCE, renderPortletResource);
392                            }
393                    }
394            }
395    
396            private static void _defineObjects(
397                    HttpServletRequest request, PortletConfig portletConfig,
398                    RenderRequest renderRequest, RenderResponse renderResponse) {
399    
400                    if (portletConfig != null) {
401                            request.setAttribute(
402                                    JavaConstants.JAVAX_PORTLET_CONFIG, portletConfig);
403                    }
404    
405                    if (renderRequest != null) {
406                            request.setAttribute(
407                                    JavaConstants.JAVAX_PORTLET_REQUEST, renderRequest);
408                    }
409    
410                    if (renderResponse != null) {
411                            request.setAttribute(
412                                    JavaConstants.JAVAX_PORTLET_RESPONSE, renderResponse);
413                    }
414            }
415    
416            private static Log _log = LogFactoryUtil.getLog(RuntimePortletUtil.class);
417    
418            private static MethodKey _initMethodKey = new MethodKey(
419                    "com.liferay.taglib.util.VelocityTaglib", "init", ServletContext.class,
420                    HttpServletRequest.class, HttpServletResponse.class, PageContext.class);
421    
422    }