001    /**
002     * Copyright (c) 2000-2013 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.portletdisplaytemplate.util;
016    
017    import com.liferay.portal.kernel.bean.ClassLoaderBeanHandler;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.portletdisplaytemplate.BasePortletDisplayTemplateHandler;
021    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022    import com.liferay.portal.kernel.servlet.GenericServletWrapper;
023    import com.liferay.portal.kernel.servlet.PipingServletResponse;
024    import com.liferay.portal.kernel.template.TemplateConstants;
025    import com.liferay.portal.kernel.template.TemplateHandler;
026    import com.liferay.portal.kernel.template.TemplateHandlerRegistryUtil;
027    import com.liferay.portal.kernel.template.TemplateVariableGroup;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.JavaConstants;
030    import com.liferay.portal.kernel.util.PropsKeys;
031    import com.liferay.portal.kernel.util.ProxyUtil;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.kernel.util.WebKeys;
034    import com.liferay.portal.model.Group;
035    import com.liferay.portal.service.GroupLocalServiceUtil;
036    import com.liferay.portal.templateparser.Transformer;
037    import com.liferay.portal.theme.ThemeDisplay;
038    import com.liferay.portal.util.PortletKeys;
039    import com.liferay.portlet.PortletURLUtil;
040    import com.liferay.portlet.dynamicdatamapping.NoSuchTemplateException;
041    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
042    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
043    import com.liferay.taglib.util.VelocityTaglib;
044    import com.liferay.taglib.util.VelocityTaglibImpl;
045    import com.liferay.util.freemarker.FreeMarkerTaglibFactoryUtil;
046    
047    import freemarker.ext.servlet.HttpRequestHashModel;
048    import freemarker.ext.servlet.ServletContextHashModel;
049    
050    import freemarker.template.ObjectWrapper;
051    import freemarker.template.TemplateHashModel;
052    
053    import java.lang.reflect.InvocationHandler;
054    
055    import java.util.ArrayList;
056    import java.util.HashMap;
057    import java.util.LinkedHashMap;
058    import java.util.List;
059    import java.util.Locale;
060    import java.util.Map;
061    
062    import javax.portlet.PortletPreferences;
063    import javax.portlet.PortletURL;
064    import javax.portlet.RenderRequest;
065    import javax.portlet.RenderResponse;
066    
067    import javax.servlet.GenericServlet;
068    import javax.servlet.Servlet;
069    import javax.servlet.ServletContext;
070    import javax.servlet.http.HttpServletRequest;
071    import javax.servlet.http.HttpServletResponse;
072    import javax.servlet.http.HttpSession;
073    import javax.servlet.jsp.PageContext;
074    
075    /**
076     * @author Eduardo Garcia
077     * @author Juan Fern??ndez
078     * @author Brian Wing Shun Chan
079     */
080    @DoPrivileged
081    public class PortletDisplayTemplateImpl implements PortletDisplayTemplate {
082    
083            @Override
084            public DDMTemplate fetchDDMTemplate(long groupId, String displayStyle) {
085                    try {
086                            Group group = GroupLocalServiceUtil.getGroup(groupId);
087    
088                            Group companyGroup = GroupLocalServiceUtil.getCompanyGroup(
089                                    group.getCompanyId());
090    
091                            String uuid = getDDMTemplateUuid(displayStyle);
092    
093                            if (Validator.isNull(uuid)) {
094                                    return null;
095                            }
096    
097                            try {
098                                    return
099                                            DDMTemplateLocalServiceUtil.getDDMTemplateByUuidAndGroupId(
100                                                    uuid, groupId);
101                            }
102                            catch (NoSuchTemplateException nste) {
103                            }
104    
105                            try {
106                                    return
107                                            DDMTemplateLocalServiceUtil.getDDMTemplateByUuidAndGroupId(
108                                                    uuid, companyGroup.getGroupId());
109                            }
110                            catch (NoSuchTemplateException nste) {
111                            }
112                    }
113                    catch (Exception e) {
114                            if (_log.isWarnEnabled()) {
115                                    _log.warn(e, e);
116                            }
117                    }
118    
119                    return null;
120            }
121    
122            @Override
123            public long getDDMTemplateGroupId(long groupId) {
124                    try {
125                            Group group = GroupLocalServiceUtil.getGroup(groupId);
126    
127                            if (group.isLayout()) {
128                                    group = group.getParentGroup();
129                            }
130    
131                            if (group.isStagingGroup()) {
132                                    Group liveGroup = group.getLiveGroup();
133    
134                                    if (!liveGroup.isStagedPortlet(
135                                                    PortletKeys.PORTLET_DISPLAY_TEMPLATES)) {
136    
137                                            return liveGroup.getGroupId();
138                                    }
139                            }
140    
141                            return group.getGroupId();
142                    }
143                    catch (Exception e) {
144                            if (_log.isWarnEnabled()) {
145                                    _log.warn(e, e);
146                            }
147                    }
148    
149                    return groupId;
150            }
151    
152            @Override
153            public String getDDMTemplateUuid(String displayStyle) {
154                    if (!displayStyle.startsWith(DISPLAY_STYLE_PREFIX)) {
155                            return null;
156                    }
157    
158                    return displayStyle.substring(DISPLAY_STYLE_PREFIX.length());
159            }
160    
161            @Override
162            public long getPortletDisplayTemplateDDMTemplateId(
163                    long groupId, String displayStyle) {
164    
165                    long portletDisplayDDMTemplateId = 0;
166    
167                    long portletDisplayDDMTemplateGroupId = getDDMTemplateGroupId(groupId);
168    
169                    if (displayStyle.startsWith(DISPLAY_STYLE_PREFIX)) {
170                            DDMTemplate portletDisplayDDMTemplate = fetchDDMTemplate(
171                                    portletDisplayDDMTemplateGroupId, displayStyle);
172    
173                            if (portletDisplayDDMTemplate != null) {
174                                    portletDisplayDDMTemplateId =
175                                            portletDisplayDDMTemplate.getTemplateId();
176                            }
177                    }
178    
179                    return portletDisplayDDMTemplateId;
180            }
181    
182            @Override
183            public List<TemplateHandler> getPortletDisplayTemplateHandlers() {
184                    List<TemplateHandler> templateHandlers =
185                            TemplateHandlerRegistryUtil.getTemplateHandlers();
186    
187                    List<TemplateHandler> portletDisplayTemplateHandlers =
188                            new ArrayList<TemplateHandler>();
189    
190                    for (TemplateHandler templateHandler : templateHandlers) {
191                            if (templateHandler instanceof BasePortletDisplayTemplateHandler) {
192                                    portletDisplayTemplateHandlers.add(templateHandler);
193                            }
194                            else if (ProxyUtil.isProxyClass(templateHandler.getClass())) {
195                                    InvocationHandler invocationHandler =
196                                            ProxyUtil.getInvocationHandler(templateHandler);
197    
198                                    if (invocationHandler instanceof ClassLoaderBeanHandler) {
199                                            ClassLoaderBeanHandler classLoaderBeanHandler =
200                                                    (ClassLoaderBeanHandler)invocationHandler;
201    
202                                            Object bean = classLoaderBeanHandler.getBean();
203    
204                                            if (bean instanceof BasePortletDisplayTemplateHandler) {
205                                                    portletDisplayTemplateHandlers.add(templateHandler);
206                                            }
207                                    }
208                            }
209                    }
210    
211                    return portletDisplayTemplateHandlers;
212            }
213    
214            @Override
215            public Map<String, TemplateVariableGroup> getTemplateVariableGroups(
216                    String language) {
217    
218                    Map<String, TemplateVariableGroup> templateVariableGroups =
219                            new LinkedHashMap<String, TemplateVariableGroup>();
220    
221                    TemplateVariableGroup fieldsTemplateVariableGroup =
222                            new TemplateVariableGroup("fields");
223    
224                    fieldsTemplateVariableGroup.addCollectionVariable(
225                            "entries", List.class, PortletDisplayTemplateConstants.ENTRIES,
226                            "entries-item", null, "curEntry", null);
227                    fieldsTemplateVariableGroup.addVariable(
228                            "entry", null, PortletDisplayTemplateConstants.ENTRY);
229    
230                    templateVariableGroups.put("fields", fieldsTemplateVariableGroup);
231    
232                    TemplateVariableGroup generalVariablesTemplateVariableGroup =
233                            new TemplateVariableGroup("general-variables");
234    
235                    generalVariablesTemplateVariableGroup.addVariable(
236                            "current-url", String.class,
237                            PortletDisplayTemplateConstants.CURRENT_URL);
238                    generalVariablesTemplateVariableGroup.addVariable(
239                            "locale", Locale.class, PortletDisplayTemplateConstants.LOCALE);
240                    generalVariablesTemplateVariableGroup.addVariable(
241                            "portlet-preferences", Map.class,
242                            PortletDisplayTemplateConstants.PORTLET_PREFERENCES);
243                    generalVariablesTemplateVariableGroup.addVariable(
244                            "template-id", null, PortletDisplayTemplateConstants.TEMPLATE_ID);
245                    generalVariablesTemplateVariableGroup.addVariable(
246                            "theme-display", ThemeDisplay.class,
247                            PortletDisplayTemplateConstants.THEME_DISPLAY);
248    
249                    templateVariableGroups.put(
250                            "general-variables", generalVariablesTemplateVariableGroup);
251    
252                    TemplateVariableGroup utilTemplateVariableGroup =
253                            new TemplateVariableGroup("util");
254    
255                    utilTemplateVariableGroup.addVariable(
256                            "http-request", HttpServletRequest.class,
257                            PortletDisplayTemplateConstants.REQUEST);
258    
259                    if (language.equals(TemplateConstants.LANG_TYPE_VM)) {
260                            utilTemplateVariableGroup.addVariable(
261                                    "liferay-taglib", VelocityTaglib.class,
262                                    PortletDisplayTemplateConstants.TAGLIB_LIFERAY);
263                    }
264    
265                    utilTemplateVariableGroup.addVariable(
266                            "render-request", RenderRequest.class,
267                            PortletDisplayTemplateConstants.RENDER_REQUEST);
268                    utilTemplateVariableGroup.addVariable(
269                            "render-response", RenderResponse.class,
270                            PortletDisplayTemplateConstants.RENDER_RESPONSE);
271    
272                    templateVariableGroups.put("util", utilTemplateVariableGroup);
273    
274                    return templateVariableGroups;
275            }
276    
277            @Override
278            public String renderDDMTemplate(
279                            PageContext pageContext, long ddmTemplateId, List<?> entries)
280                    throws Exception {
281    
282                    Map<String, Object> contextObjects = new HashMap<String, Object>();
283    
284                    return renderDDMTemplate(
285                            pageContext, ddmTemplateId, entries, contextObjects);
286            }
287    
288            @Override
289            public String renderDDMTemplate(
290                            PageContext pageContext, long ddmTemplateId, List<?> entries,
291                            Map<String, Object> contextObjects)
292                    throws Exception {
293    
294                    contextObjects.put(
295                            PortletDisplayTemplateConstants.TEMPLATE_ID, ddmTemplateId);
296                    contextObjects.put(PortletDisplayTemplateConstants.ENTRIES, entries);
297    
298                    if (!entries.isEmpty()) {
299                            contextObjects.put(
300                                    PortletDisplayTemplateConstants.ENTRY, entries.get(0));
301                    }
302    
303                    HttpServletRequest request =
304                            (HttpServletRequest)pageContext.getRequest();
305    
306                    contextObjects.put(
307                            PortletDisplayTemplateConstants.LOCALE, request.getLocale());
308    
309                    contextObjects.put(PortletDisplayTemplateConstants.REQUEST, request);
310    
311                    RenderRequest renderRequest = (RenderRequest)request.getAttribute(
312                            JavaConstants.JAVAX_PORTLET_REQUEST);
313    
314                    contextObjects.put(
315                            PortletDisplayTemplateConstants.RENDER_REQUEST, renderRequest);
316    
317                    RenderResponse renderResponse = (RenderResponse)request.getAttribute(
318                            JavaConstants.JAVAX_PORTLET_RESPONSE);
319    
320                    contextObjects.put(
321                            PortletDisplayTemplateConstants.RENDER_RESPONSE, renderResponse);
322    
323                    PortletURL currentURL = PortletURLUtil.getCurrent(
324                            renderRequest, renderResponse);
325    
326                    contextObjects.put(
327                            PortletDisplayTemplateConstants.CURRENT_URL, currentURL.toString());
328    
329                    ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
330                            WebKeys.THEME_DISPLAY);
331    
332                    contextObjects.put(
333                            PortletDisplayTemplateConstants.THEME_DISPLAY, themeDisplay);
334    
335                    // Taglibs
336    
337                    DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
338                            ddmTemplateId);
339    
340                    contextObjects.put("class_name_id", ddmTemplate.getClassNameId());
341    
342                    String language = ddmTemplate.getLanguage();
343    
344                    if (language.equals(TemplateConstants.LANG_TYPE_FTL)) {
345                            _addTaglibSupportFTL(contextObjects, pageContext);
346                    }
347                    else if (language.equals(TemplateConstants.LANG_TYPE_VM)) {
348                            _addTaglibSupportVM(contextObjects, pageContext);
349                    }
350    
351                    contextObjects.putAll(_getPortletPreferences(renderRequest));
352    
353                    return _transformer.transform(
354                            themeDisplay, contextObjects, ddmTemplate.getScript(), language);
355            }
356    
357            private void _addTaglibSupportFTL(
358                            Map<String, Object> contextObjects, PageContext pageContext)
359                    throws Exception {
360    
361                    // FreeMarker servlet application
362    
363                    final Servlet servlet = (Servlet)pageContext.getPage();
364    
365                    GenericServlet genericServlet = null;
366    
367                    if (servlet instanceof GenericServlet) {
368                            genericServlet = (GenericServlet)servlet;
369                    }
370                    else {
371                            genericServlet = new GenericServletWrapper(servlet);
372    
373                            genericServlet.init(pageContext.getServletConfig());
374                    }
375    
376                    ServletContextHashModel servletContextHashModel =
377                            new ServletContextHashModel(
378                                    genericServlet, ObjectWrapper.DEFAULT_WRAPPER);
379    
380                    contextObjects.put(
381                            PortletDisplayTemplateConstants.FREEMARKER_SERVLET_APPLICATION,
382                            servletContextHashModel);
383    
384                    // FreeMarker servlet request
385    
386                    HttpServletRequest request =
387                            (HttpServletRequest)pageContext.getRequest();
388                    HttpServletResponse response =
389                            (HttpServletResponse)pageContext.getResponse();
390    
391                    HttpRequestHashModel requestHashModel = new HttpRequestHashModel(
392                            request, response, ObjectWrapper.DEFAULT_WRAPPER);
393    
394                    contextObjects.put(
395                            PortletDisplayTemplateConstants.FREEMARKER_SERVLET_REQUEST,
396                            requestHashModel);
397    
398                    // Taglib Liferay hash
399    
400                    TemplateHashModel taglibLiferayHash =
401                            FreeMarkerTaglibFactoryUtil.createTaglibFactory(
402                                    pageContext.getServletContext());
403    
404                    contextObjects.put(
405                            PortletDisplayTemplateConstants.TAGLIB_LIFERAY_HASH,
406                            taglibLiferayHash);
407            }
408    
409            private void _addTaglibSupportVM(
410                    Map<String, Object> contextObjects, PageContext pageContext) {
411    
412                    contextObjects.put(
413                            PortletDisplayTemplateConstants.TAGLIB_LIFERAY,
414                            _getVelocityTaglib(pageContext));
415            }
416    
417            private Map<String, Object> _getPortletPreferences(
418                    RenderRequest renderRequest) {
419    
420                    Map<String, Object> contextObjects = new HashMap<String, Object>();
421    
422                    PortletPreferences portletPreferences = renderRequest.getPreferences();
423    
424                    Map<String, String[]> map = portletPreferences.getMap();
425    
426                    contextObjects.put(
427                            PortletDisplayTemplateConstants.PORTLET_PREFERENCES, map);
428    
429                    for (Map.Entry<String, String[]> entry : map.entrySet()) {
430                            String[] values = entry.getValue();
431    
432                            if (ArrayUtil.isEmpty(values)) {
433                                    continue;
434                            }
435    
436                            String value = values[0];
437    
438                            if (value == null) {
439                                    continue;
440                            }
441    
442                            contextObjects.put(entry.getKey(), value);
443                    }
444    
445                    return contextObjects;
446            }
447    
448            private VelocityTaglib _getVelocityTaglib(PageContext pageContext) {
449                    HttpServletRequest request =
450                            (HttpServletRequest)pageContext.getRequest();
451    
452                    HttpSession session = request.getSession();
453    
454                    ServletContext servletContext = session.getServletContext();
455    
456                    HttpServletResponse response =
457                            (HttpServletResponse)pageContext.getResponse();
458    
459                    VelocityTaglib velocityTaglib = new VelocityTaglibImpl(
460                            servletContext, request,
461                            new PipingServletResponse(response, pageContext.getOut()),
462                            pageContext, null);
463    
464                    return velocityTaglib;
465            }
466    
467            private static Log _log = LogFactoryUtil.getLog(
468                    PortletDisplayTemplateImpl.class);
469    
470            private Transformer _transformer = new Transformer(
471                    PropsKeys.DYNAMIC_DATA_LISTS_ERROR_TEMPLATE, true);
472    
473    }