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