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