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.MethodInvoker;
023    import com.liferay.portal.kernel.util.MethodWrapper;
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                    MethodWrapper methodWrapper = new MethodWrapper(
214                            "com.liferay.taglib.util.VelocityTaglib", "init",
215                            new Object[] {
216                                    servletContext, request,
217                                    new PipingServletResponse(response, unsyncStringWriter),
218                                    pageContext
219                            });
220    
221                    Object velocityTaglib = MethodInvoker.invoke(methodWrapper);
222    
223                    velocityContext.put("taglibLiferay", velocityTaglib);
224                    velocityContext.put("theme", velocityTaglib);
225    
226                    try {
227                            VelocityEngineUtil.mergeTemplate(
228                                    velocityTemplateId, velocityTemplateContent, velocityContext,
229                                    unsyncStringWriter);
230                    }
231                    catch (Exception e) {
232                            _log.error(e, e);
233    
234                            throw e;
235                    }
236    
237                    String output = unsyncStringWriter.toString();
238    
239                    Map<Portlet, Object[]> portletsMap = processor.getPortletsMap();
240    
241                    Map<String, StringBundler> contentsMap =
242                            new HashMap<String, StringBundler>(portletsMap.size());
243    
244                    for (Map.Entry<Portlet, Object[]> entry : portletsMap.entrySet()) {
245                            Portlet portlet = entry.getKey();
246                            Object[] value = entry.getValue();
247    
248                            String queryString = (String)value[0];
249                            String columnId = (String)value[1];
250                            Integer columnPos = (Integer)value[2];
251                            Integer columnCount = (Integer)value[3];
252    
253                            UnsyncStringWriter portletUnsyncStringWriter =
254                                    new UnsyncStringWriter();
255    
256                            PipingServletResponse pipingServletResponse =
257                                    new PipingServletResponse(response, portletUnsyncStringWriter);
258    
259                            processPortlet(
260                                    servletContext, request, pipingServletResponse, portlet,
261                                    queryString, columnId, columnPos, columnCount, null, true);
262    
263                            contentsMap.put(
264                                    portlet.getPortletId(),
265                                    portletUnsyncStringWriter.getStringBundler());
266                    }
267    
268                    StringBundler sb = StringUtil.replaceWithStringBundler(
269                            output, "[$TEMPLATE_PORTLET_", "$]", contentsMap);
270    
271                    sb.writeTo(jspWriter);
272            }
273    
274            public static String processXML(
275                            HttpServletRequest request, String content,
276                            RuntimeLogic runtimeLogic)
277                    throws Exception {
278    
279                    if (Validator.isNull(content)) {
280                            return StringPool.BLANK;
281                    }
282    
283                    try {
284                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
285    
286                            StringBuilder sb = new StringBuilder();
287    
288                            int x = 0;
289                            int y = content.indexOf(runtimeLogic.getOpenTag());
290    
291                            while (y != -1) {
292                                    sb.append(content.substring(x, y));
293    
294                                    int close1 = content.indexOf(runtimeLogic.getClose1Tag(), y);
295                                    int close2 = content.indexOf(runtimeLogic.getClose2Tag(), y);
296    
297                                    if ((close2 == -1) || ((close1 != -1) && (close1 < close2))) {
298                                            x = close1 + runtimeLogic.getClose1Tag().length();
299                                    }
300                                    else {
301                                            x = close2 + runtimeLogic.getClose2Tag().length();
302                                    }
303    
304                                    sb.append(runtimeLogic.processXML(content.substring(y, x)));
305    
306                                    y = content.indexOf(runtimeLogic.getOpenTag(), x);
307                            }
308    
309                            if (y == -1) {
310                                    sb.append(content.substring(x, content.length()));
311                            }
312    
313                            return sb.toString();
314                    }
315                    finally {
316                            request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
317                    }
318            }
319    
320            private static void _defineObjects(
321                    HttpServletRequest request, PortletConfig portletConfig,
322                    RenderRequest renderRequest, RenderResponse renderResponse) {
323    
324                    if (portletConfig != null) {
325                            request.setAttribute(
326                                    JavaConstants.JAVAX_PORTLET_CONFIG, portletConfig);
327                    }
328    
329                    if (renderRequest != null) {
330                            request.setAttribute(
331                                    JavaConstants.JAVAX_PORTLET_REQUEST, renderRequest);
332                    }
333    
334                    if (renderResponse != null) {
335                            request.setAttribute(
336                                    JavaConstants.JAVAX_PORTLET_RESPONSE, renderResponse);
337                    }
338            }
339    
340            private static Log _log = LogFactoryUtil.getLog(RuntimePortletUtil.class);
341    
342    }