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.taglib.util;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.log.LogUtil;
020    import com.liferay.portal.kernel.portlet.PortletBag;
021    import com.liferay.portal.kernel.portlet.PortletBagPool;
022    import com.liferay.portal.kernel.servlet.DirectRequestDispatcherFactoryUtil;
023    import com.liferay.portal.kernel.servlet.TrackedServletRequest;
024    import com.liferay.portal.kernel.servlet.taglib.TagDynamicIdFactory;
025    import com.liferay.portal.kernel.servlet.taglib.TagDynamicIdFactoryRegistry;
026    import com.liferay.portal.kernel.servlet.taglib.TagDynamicIncludeUtil;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.PropsKeys;
029    import com.liferay.portal.kernel.util.PropsUtil;
030    import com.liferay.portal.kernel.util.ServerDetector;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.UnicodeProperties;
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.model.PortletConstants;
038    import com.liferay.portal.model.Theme;
039    import com.liferay.portal.theme.ThemeDisplay;
040    import com.liferay.portal.util.CustomJspRegistryUtil;
041    import com.liferay.portlet.exportimport.staging.StagingUtil;
042    import com.liferay.taglib.FileAvailabilityUtil;
043    import com.liferay.taglib.servlet.JspWriterHttpServletResponse;
044    import com.liferay.taglib.servlet.PipingServletResponse;
045    
046    import javax.servlet.RequestDispatcher;
047    import javax.servlet.ServletContext;
048    import javax.servlet.http.HttpServletRequest;
049    import javax.servlet.http.HttpServletResponse;
050    import javax.servlet.jsp.JspException;
051    import javax.servlet.jsp.tagext.BodyContent;
052    
053    /**
054     * @author Brian Wing Shun Chan
055     * @author Shuyang Zhou
056     * @author Eduardo Lundgren
057     * @author Raymond Aug??
058     */
059    public class IncludeTag extends AttributesTagSupport {
060    
061            @Override
062            public int doEndTag() throws JspException {
063                    try {
064                            String page = getPage();
065    
066                            if (Validator.isNull(page)) {
067                                    page = getEndPage();
068                            }
069    
070                            callSetAttributes();
071    
072                            if (themeResourceExists(page)) {
073                                    doIncludeTheme(page);
074    
075                                    return EVAL_PAGE;
076                            }
077    
078                            if (!FileAvailabilityUtil.isAvailable(servletContext, page)) {
079                                    logUnavailablePage(page);
080    
081                                    return processEndTag();
082                            }
083    
084                            doInclude(page, false);
085    
086                            return EVAL_PAGE;
087                    }
088                    catch (Exception e) {
089                            throw new JspException(e);
090                    }
091                    finally {
092                            clearDynamicAttributes();
093                            clearParams();
094                            clearProperties();
095    
096                            cleanUpSetAttributes();
097    
098                            if (!ServerDetector.isResin()) {
099                                    setPage(null);
100                                    setUseCustomPage(true);
101    
102                                    cleanUp();
103                            }
104                    }
105            }
106    
107            @Override
108            public int doStartTag() throws JspException {
109                    try {
110                            String page = getStartPage();
111    
112                            callSetAttributes();
113    
114                            if (themeResourceExists(page)) {
115                                    doIncludeTheme(page);
116    
117                                    return EVAL_BODY_INCLUDE;
118                            }
119    
120                            if (!FileAvailabilityUtil.isAvailable(servletContext, page)) {
121                                    logUnavailablePage(page);
122    
123                                    return processStartTag();
124                            }
125    
126                            doInclude(page, true);
127    
128                            return EVAL_BODY_INCLUDE;
129                    }
130                    catch (Exception e) {
131                            throw new JspException(e);
132                    }
133            }
134    
135            public void runTag() throws JspException {
136                    doStartTag();
137                    doEndTag();
138            }
139    
140            public void setPage(String page) {
141                    _page = page;
142            }
143    
144            public void setPortletId(String portletId) {
145                    if (Validator.isNotNull(portletId)) {
146                            String rootPortletId = PortletConstants.getRootPortletId(portletId);
147    
148                            PortletBag portletBag = PortletBagPool.get(rootPortletId);
149    
150                            servletContext = portletBag.getServletContext();
151                    }
152            }
153    
154            public void setStrict(boolean strict) {
155                    _strict = strict;
156            }
157    
158            public void setUseCustomPage(boolean useCustomPage) {
159                    _useCustomPage = useCustomPage;
160            }
161    
162            protected void callSetAttributes() {
163                    HttpServletRequest request = getOriginalServletRequest();
164    
165                    if (isCleanUpSetAttributes()) {
166                            _trackedRequest = new TrackedServletRequest(request);
167    
168                            request = _trackedRequest;
169                    }
170    
171                    setNamespacedAttribute(request, "bodyContent", getBodyContentWrapper());
172                    setNamespacedAttribute(
173                            request, "dynamicAttributes", getDynamicAttributes());
174                    setNamespacedAttribute(
175                            request, "scopedAttributes", getScopedAttributes());
176    
177                    setAttributes(request);
178            }
179    
180            protected void cleanUp() {
181            }
182    
183            protected void cleanUpSetAttributes() {
184                    if (isCleanUpSetAttributes() && (_trackedRequest != null)) {
185                            for (String name : _trackedRequest.getSetAttributes()) {
186                                    _trackedRequest.removeAttribute(name);
187                            }
188    
189                            _trackedRequest = null;
190                    }
191            }
192    
193            protected void doInclude(
194                            String page, boolean dynamicIncludeAscendingPriority)
195                    throws JspException {
196    
197                    try {
198                            include(page, dynamicIncludeAscendingPriority);
199                    }
200                    catch (Exception e) {
201                            String currentURL = (String)request.getAttribute(
202                                    WebKeys.CURRENT_URL);
203    
204                            String message =
205                                    "Current URL " + currentURL + " generates exception: " +
206                                            e.getMessage();
207    
208                            LogUtil.log(_log, e, message);
209    
210                            if (e instanceof JspException) {
211                                    throw (JspException)e;
212                            }
213                    }
214            }
215    
216            protected void doIncludeTheme(String page) throws Exception {
217                    HttpServletResponse response =
218                            (HttpServletResponse)pageContext.getResponse();
219    
220                    Theme theme = (Theme)request.getAttribute(WebKeys.THEME);
221    
222                    ThemeUtil.include(servletContext, request, response, page, theme);
223            }
224    
225            protected Object getBodyContentWrapper() {
226                    final BodyContent bodyContent = getBodyContent();
227    
228                    if (bodyContent == null) {
229                            return null;
230                    }
231    
232                    return new Object() {
233    
234                            @Override
235                            public String toString() {
236                                    return bodyContent.getString();
237                            }
238    
239                    };
240            }
241    
242            protected String getCustomPage(
243                    ServletContext servletContext, HttpServletRequest request,
244                    String page) {
245    
246                    if (Validator.isNull(page)) {
247                            return null;
248                    }
249    
250                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
251                            WebKeys.THEME_DISPLAY);
252    
253                    if (themeDisplay == null) {
254                            return null;
255                    }
256    
257                    Group group = null;
258    
259                    try {
260                            group = StagingUtil.getLiveGroup(themeDisplay.getScopeGroupId());
261                    }
262                    catch (Exception e) {
263                            return null;
264                    }
265    
266                    UnicodeProperties typeSettingsProperties =
267                            group.getTypeSettingsProperties();
268    
269                    String customJspServletContextName = typeSettingsProperties.getProperty(
270                            "customJspServletContextName");
271    
272                    if (Validator.isNull(customJspServletContextName)) {
273                            return null;
274                    }
275    
276                    String customPage = CustomJspRegistryUtil.getCustomJspFileName(
277                            customJspServletContextName, page);
278    
279                    if (FileAvailabilityUtil.isAvailable(servletContext, customPage)) {
280                            return customPage;
281                    }
282    
283                    return null;
284            }
285    
286            protected String getEndPage() {
287                    return null;
288            }
289    
290            protected HttpServletRequest getOriginalServletRequest() {
291                    return (HttpServletRequest)pageContext.getRequest();
292            }
293    
294            protected String getPage() {
295                    return _page;
296            }
297    
298            protected RequestDispatcher getRequestDispatcher(String page) {
299                    return DirectRequestDispatcherFactoryUtil.getRequestDispatcher(
300                            servletContext, page);
301            }
302    
303            protected String getStartPage() {
304                    return null;
305            }
306    
307            protected void include(String page, boolean doStartTag) throws Exception {
308                    JspWriterHttpServletResponse jspWriterHttpServletResponse = null;
309    
310                    Class<?> clazz = getClass();
311    
312                    String tagClassName = clazz.getName();
313    
314                    String tagDynamicId = null;
315    
316                    String tagPointPrefix = null;
317    
318                    if (doStartTag) {
319                            tagPointPrefix = "doStartTag#";
320                    }
321                    else {
322                            tagPointPrefix = "doEndTag#";
323                    }
324    
325                    TagDynamicIdFactory tagDynamicIdFactory =
326                            TagDynamicIdFactoryRegistry.getTagDynamicIdFactory(tagClassName);
327    
328                    if (tagDynamicIdFactory != null) {
329                            jspWriterHttpServletResponse = new JspWriterHttpServletResponse(
330                                    pageContext);
331    
332                            tagDynamicId = tagDynamicIdFactory.getTagDynamicId(
333                                    request, jspWriterHttpServletResponse, this);
334    
335                            TagDynamicIncludeUtil.include(
336                                    request, jspWriterHttpServletResponse, tagClassName,
337                                    tagDynamicId, tagPointPrefix + "before", doStartTag);
338                    }
339    
340                    if (_useCustomPage) {
341                            String customPage = getCustomPage(servletContext, request, page);
342    
343                            if (Validator.isNotNull(customPage)) {
344                                    page = customPage;
345                            }
346                    }
347    
348                    RequestDispatcher requestDispatcher = getRequestDispatcher(page);
349    
350                    request.setAttribute(
351                            WebKeys.SERVLET_CONTEXT_INCLUDE_FILTER_STRICT, _strict);
352    
353                    HttpServletResponse response = new PipingServletResponse(pageContext);
354    
355                    requestDispatcher.include(request, response);
356    
357                    request.removeAttribute(WebKeys.SERVLET_CONTEXT_INCLUDE_FILTER_STRICT);
358    
359                    if (tagDynamicIdFactory != null) {
360                            TagDynamicIncludeUtil.include(
361                                    request, jspWriterHttpServletResponse, tagClassName,
362                                    tagDynamicId, tagPointPrefix + "after", doStartTag);
363                    }
364            }
365    
366            protected boolean isCleanUpSetAttributes() {
367                    return _CLEAN_UP_SET_ATTRIBUTES;
368            }
369    
370            protected boolean isPortalPage(String page) {
371                    if (page.startsWith("/html/taglib/") &&
372                            (page.endsWith("/end.jsp") || page.endsWith("/page.jsp") ||
373                             page.endsWith("/start.jsp"))) {
374    
375                            return true;
376                    }
377    
378                    return false;
379            }
380    
381            protected boolean isUseCustomPage() {
382                    return _useCustomPage;
383            }
384    
385            protected void logUnavailablePage(String page) {
386                    if ((page == null) || !_log.isWarnEnabled()) {
387                            return;
388                    }
389    
390                    String contextPath = servletContext.getContextPath();
391    
392                    if (contextPath.equals(StringPool.BLANK)) {
393                            contextPath = StringPool.SLASH;
394                    }
395    
396                    StringBundler sb = new StringBundler(13);
397    
398                    sb.append("Unable to find ");
399                    sb.append(page);
400                    sb.append(" in the context ");
401                    sb.append(contextPath);
402                    sb.append(".");
403    
404                    if (isPortalPage(page)) {
405                            if (contextPath.equals(StringPool.SLASH)) {
406                                    sb = null;
407                            }
408                            else {
409                                    sb.append(" You must not use a taglib from a module and ");
410                                    sb.append("set the attribute \"servletContext\". Inline the ");
411                                    sb.append("content directly where the taglib is invoked.");
412                            }
413                    }
414                    else if (contextPath.equals(StringPool.SLASH)) {
415                            Class<?> clazz = getClass();
416    
417                            if (clazz.equals(IncludeTag.class)) {
418                                    sb.append(" You must set the attribute \"servletContext\" ");
419                                    sb.append("with the value \"<%= application %>\" when ");
420                                    sb.append("invoking a taglib from a module.");
421                            }
422                            else {
423                                    sb.append(" You must not use a taglib from a module and ");
424                                    sb.append("set the attribute \"file\". Inline the content ");
425                                    sb.append("directly where the taglib is invoked.");
426                            }
427                    }
428    
429                    if (sb != null) {
430                            _log.warn(sb.toString());
431                    }
432            }
433    
434            protected int processEndTag() throws Exception {
435                    return EVAL_PAGE;
436            }
437    
438            protected int processStartTag() throws Exception {
439                    return EVAL_BODY_INCLUDE;
440            }
441    
442            protected void setAttributes(HttpServletRequest request) {
443            }
444    
445            protected boolean themeResourceExists(String page) throws Exception {
446                    if ((page == null) || !_THEME_JSP_OVERRIDE_ENABLED || _strict) {
447                            return false;
448                    }
449    
450                    Theme theme = (Theme)request.getAttribute(WebKeys.THEME);
451    
452                    if (theme == null) {
453                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
454                                    WebKeys.THEME_DISPLAY);
455    
456                            if (themeDisplay != null) {
457                                    theme = themeDisplay.getTheme();
458                            }
459                    }
460    
461                    if (theme == null) {
462                            return false;
463                    }
464    
465                    String portletId = ThemeUtil.getPortletId(request);
466    
467                    boolean exists = theme.resourceExists(servletContext, portletId, page);
468    
469                    if (_log.isDebugEnabled() && exists) {
470                            String resourcePath = theme.getResourcePath(
471                                    servletContext, null, page);
472    
473                            _log.debug(resourcePath);
474                    }
475    
476                    return exists;
477            }
478    
479            private static final boolean _CLEAN_UP_SET_ATTRIBUTES = false;
480    
481            private static final boolean _THEME_JSP_OVERRIDE_ENABLED =
482                    GetterUtil.getBoolean(
483                            PropsUtil.get(PropsKeys.THEME_JSP_OVERRIDE_ENABLED));
484    
485            private static final Log _log = LogFactoryUtil.getLog(IncludeTag.class);
486    
487            private String _page;
488            private boolean _strict;
489            private TrackedServletRequest _trackedRequest;
490            private boolean _useCustomPage = true;
491    
492    }