001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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 +=
180                                            PortletConstants.INSTANCE_SEPARATOR + instanceId;
181    
182                                    portlet = PortletLocalServiceUtil.getPortletById(
183                                            themeDisplay.getCompanyId(), portletId);*/
184                            }
185                            else {
186                                    if (_log.isDebugEnabled()) {
187                                            _log.debug(
188                                                    "Portlet " + portlet.getPortletId() +
189                                                            " is instanceable but does not have a " +
190                                                                    "valid instance id");
191                                    }
192    
193                                    portlet = null;
194                            }
195                    }
196    
197                    if (portlet == null) {
198                            return StringPool.BLANK;
199                    }
200    
201                    // Capture the current portlet's settings to reset them once the child
202                    // portlet is rendered
203    
204                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
205    
206                    PortletDisplay portletDisplayClone = PortletDisplayFactory.create();
207    
208                    portletDisplay.copyTo(portletDisplayClone);
209    
210                    PortletConfig portletConfig = (PortletConfig)request.getAttribute(
211                            JavaConstants.JAVAX_PORTLET_CONFIG);
212    
213                    try {
214                            return PortalUtil.renderPortlet(
215                                    servletContext, request, response, portlet, queryString,
216                                    columnId, columnPos, columnCount, path, writeOutput);
217                    }
218                    finally {
219                            portletDisplay.copyFrom(portletDisplayClone);
220    
221                            portletDisplayClone.recycle();
222    
223                            _defineObjects(
224                                    request, portletConfig, renderRequest, renderResponse);
225                    }
226            }
227    
228            public void processTemplate(
229                            ServletContext servletContext, HttpServletRequest request,
230                            HttpServletResponse response, PageContext pageContext,
231                            JspWriter jspWriter, String velocityTemplateId,
232                            String velocityTemplateContent)
233                    throws Exception {
234    
235                    processTemplate(
236                            servletContext, request, response, pageContext, jspWriter, null,
237                            velocityTemplateId, velocityTemplateContent);
238            }
239    
240            public void processTemplate(
241                            ServletContext servletContext, HttpServletRequest request,
242                            HttpServletResponse response, PageContext pageContext,
243                            JspWriter jspWriter, String portletId, String velocityTemplateId,
244                            String velocityTemplateContent)
245                    throws Exception {
246    
247                    if (Validator.isNull(velocityTemplateContent)) {
248                            return;
249                    }
250    
251                    TemplateProcessor processor = new TemplateProcessor(
252                            servletContext, request, response, portletId);
253    
254                    VelocityContext velocityContext =
255                            VelocityEngineUtil.getWrappedStandardToolsContext();
256    
257                    velocityContext.put("processor", processor);
258    
259                    // Velocity variables
260    
261                    VelocityVariablesUtil.insertVariables(velocityContext, request);
262    
263                    // liferay:include tag library
264    
265                    UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
266    
267                    MethodHandler methodHandler = new MethodHandler(
268                            _initMethodKey, servletContext, request,
269                            new PipingServletResponse(response, unsyncStringWriter),
270                            pageContext);
271    
272                    Object velocityTaglib = methodHandler.invoke(true);
273    
274                    velocityContext.put("taglibLiferay", velocityTaglib);
275                    velocityContext.put("theme", velocityTaglib);
276    
277                    try {
278                            VelocityEngineUtil.mergeTemplate(
279                                    velocityTemplateId, velocityTemplateContent, velocityContext,
280                                    unsyncStringWriter);
281                    }
282                    catch (Exception e) {
283                            _log.error(e, e);
284    
285                            throw e;
286                    }
287    
288                    String output = unsyncStringWriter.toString();
289    
290                    Map<Portlet, Object[]> portletsMap = processor.getPortletsMap();
291    
292                    Map<String, StringBundler> contentsMap =
293                            new HashMap<String, StringBundler>(portletsMap.size());
294    
295                    for (Map.Entry<Portlet, Object[]> entry : portletsMap.entrySet()) {
296                            Portlet portlet = entry.getKey();
297                            Object[] value = entry.getValue();
298    
299                            String queryString = (String)value[0];
300                            String columnId = (String)value[1];
301                            Integer columnPos = (Integer)value[2];
302                            Integer columnCount = (Integer)value[3];
303    
304                            UnsyncStringWriter portletUnsyncStringWriter =
305                                    new UnsyncStringWriter();
306    
307                            PipingServletResponse pipingServletResponse =
308                                    new PipingServletResponse(response, portletUnsyncStringWriter);
309    
310                            processPortlet(
311                                    servletContext, request, pipingServletResponse, portlet,
312                                    queryString, columnId, columnPos, columnCount, null, true);
313    
314                            contentsMap.put(
315                                    portlet.getPortletId(),
316                                    portletUnsyncStringWriter.getStringBundler());
317                    }
318    
319                    StringBundler sb = StringUtil.replaceWithStringBundler(
320                            output, "[$TEMPLATE_PORTLET_", "$]", contentsMap);
321    
322                    sb.writeTo(jspWriter);
323            }
324    
325            public String processXML(
326                            HttpServletRequest request, String content,
327                            RuntimeLogic runtimeLogic)
328                    throws Exception {
329    
330                    if (Validator.isNull(content)) {
331                            return StringPool.BLANK;
332                    }
333    
334                    Portlet renderPortlet = (Portlet)request.getAttribute(
335                            WebKeys.RENDER_PORTLET);
336    
337                    Boolean renderPortletResource = (Boolean)request.getAttribute(
338                            WebKeys.RENDER_PORTLET_RESOURCE);
339    
340                    String outerPortletId = (String)request.getAttribute(
341                            WebKeys.OUTER_PORTLET_ID);
342    
343                    if (outerPortletId == null) {
344                            request.setAttribute(
345                                    WebKeys.OUTER_PORTLET_ID, renderPortlet.getPortletId());
346                    }
347    
348                    try {
349                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
350    
351                            StringBuilder sb = new StringBuilder();
352    
353                            int x = 0;
354                            int y = content.indexOf(runtimeLogic.getOpenTag());
355    
356                            while (y != -1) {
357                                    sb.append(content.substring(x, y));
358    
359                                    int close1 = content.indexOf(runtimeLogic.getClose1Tag(), y);
360                                    int close2 = content.indexOf(runtimeLogic.getClose2Tag(), y);
361    
362                                    if ((close2 == -1) || ((close1 != -1) && (close1 < close2))) {
363                                            x = close1 + runtimeLogic.getClose1Tag().length();
364                                    }
365                                    else {
366                                            x = close2 + runtimeLogic.getClose2Tag().length();
367                                    }
368    
369                                    sb.append(runtimeLogic.processXML(content.substring(y, x)));
370    
371                                    y = content.indexOf(runtimeLogic.getOpenTag(), x);
372                            }
373    
374                            if (y == -1) {
375                                    sb.append(content.substring(x, content.length()));
376                            }
377    
378                            return sb.toString();
379                    }
380                    finally {
381                            if (outerPortletId == null) {
382                                    request.removeAttribute(WebKeys.OUTER_PORTLET_ID);
383                            }
384    
385                            request.setAttribute(WebKeys.RENDER_PORTLET, renderPortlet);
386    
387                            if (renderPortletResource == null) {
388                                    request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
389                            }
390                            else {
391                                    request.setAttribute(
392                                            WebKeys.RENDER_PORTLET_RESOURCE, renderPortletResource);
393                            }
394                    }
395            }
396    
397            private static void _defineObjects(
398                    HttpServletRequest request, PortletConfig portletConfig,
399                    RenderRequest renderRequest, RenderResponse renderResponse) {
400    
401                    if (portletConfig != null) {
402                            request.setAttribute(
403                                    JavaConstants.JAVAX_PORTLET_CONFIG, portletConfig);
404                    }
405    
406                    if (renderRequest != null) {
407                            request.setAttribute(
408                                    JavaConstants.JAVAX_PORTLET_REQUEST, renderRequest);
409                    }
410    
411                    if (renderResponse != null) {
412                            request.setAttribute(
413                                    JavaConstants.JAVAX_PORTLET_RESPONSE, renderResponse);
414                    }
415            }
416    
417            private static Log _log = LogFactoryUtil.getLog(RuntimePortletUtil.class);
418    
419            private static MethodKey _initMethodKey = new MethodKey(
420                    "com.liferay.taglib.util.VelocityTaglib", "init", ServletContext.class,
421                    HttpServletRequest.class, HttpServletResponse.class, PageContext.class);
422    
423    }