001    /**
002     * Copyright (c) 2000-2010 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.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                    Portlet renderPortlet = (Portlet)request.getAttribute(
281                            WebKeys.RENDER_PORTLET);
282    
283                    Boolean renderPortletResource = (Boolean)request.getAttribute(
284                            WebKeys.RENDER_PORTLET_RESOURCE);
285    
286                    String outerPortletId = (String)request.getAttribute(
287                            WebKeys.OUTER_PORTLET_ID);
288    
289                    if (outerPortletId == null) {
290                            request.setAttribute(
291                                    WebKeys.OUTER_PORTLET_ID, renderPortlet.getPortletId());
292                    }
293    
294                    try {
295                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
296    
297                            StringBuilder sb = new StringBuilder();
298    
299                            int x = 0;
300                            int y = content.indexOf(runtimeLogic.getOpenTag());
301    
302                            while (y != -1) {
303                                    sb.append(content.substring(x, y));
304    
305                                    int close1 = content.indexOf(runtimeLogic.getClose1Tag(), y);
306                                    int close2 = content.indexOf(runtimeLogic.getClose2Tag(), y);
307    
308                                    if ((close2 == -1) || ((close1 != -1) && (close1 < close2))) {
309                                            x = close1 + runtimeLogic.getClose1Tag().length();
310                                    }
311                                    else {
312                                            x = close2 + runtimeLogic.getClose2Tag().length();
313                                    }
314    
315                                    sb.append(runtimeLogic.processXML(content.substring(y, x)));
316    
317                                    y = content.indexOf(runtimeLogic.getOpenTag(), x);
318                            }
319    
320                            if (y == -1) {
321                                    sb.append(content.substring(x, content.length()));
322                            }
323    
324                            return sb.toString();
325                    }
326                    finally {
327                            if (outerPortletId == null) {
328                                    request.removeAttribute(WebKeys.OUTER_PORTLET_ID);
329                            }
330    
331                            request.setAttribute(WebKeys.RENDER_PORTLET, renderPortlet);
332    
333                            if (renderPortletResource == null) {
334                                    request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
335                            }
336                            else {
337                                    request.setAttribute(
338                                            WebKeys.RENDER_PORTLET_RESOURCE, renderPortletResource);
339                            }
340                    }
341            }
342    
343            private static void _defineObjects(
344                    HttpServletRequest request, PortletConfig portletConfig,
345                    RenderRequest renderRequest, RenderResponse renderResponse) {
346    
347                    if (portletConfig != null) {
348                            request.setAttribute(
349                                    JavaConstants.JAVAX_PORTLET_CONFIG, portletConfig);
350                    }
351    
352                    if (renderRequest != null) {
353                            request.setAttribute(
354                                    JavaConstants.JAVAX_PORTLET_REQUEST, renderRequest);
355                    }
356    
357                    if (renderResponse != null) {
358                            request.setAttribute(
359                                    JavaConstants.JAVAX_PORTLET_RESPONSE, renderResponse);
360                    }
361            }
362    
363            private static Log _log = LogFactoryUtil.getLog(RuntimePortletUtil.class);
364    
365            private static MethodKey _initMethodKey = new MethodKey(
366                    "com.liferay.taglib.util.VelocityTaglib", "init", ServletContext.class,
367                    HttpServletRequest.class, HttpServletResponse.class, PageContext.class);
368    
369    }