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