001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.taglib.portletext;
016    
017    import com.liferay.portal.kernel.json.JSONFactoryUtil;
018    import com.liferay.portal.kernel.json.JSONObject;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.portlet.PortletContainerUtil;
023    import com.liferay.portal.kernel.portlet.PortletJSONUtil;
024    import com.liferay.portal.kernel.portlet.PortletLayoutListener;
025    import com.liferay.portal.kernel.portlet.PortletParameterUtil;
026    import com.liferay.portal.kernel.portlet.RestrictPortletServletRequest;
027    import com.liferay.portal.kernel.servlet.DynamicServletRequest;
028    import com.liferay.portal.kernel.servlet.PipingServletResponse;
029    import com.liferay.portal.kernel.servlet.PortalIncludeUtil;
030    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
031    import com.liferay.portal.kernel.util.MapUtil;
032    import com.liferay.portal.kernel.util.PrefixPredicateFilter;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.WebKeys;
035    import com.liferay.portal.model.Layout;
036    import com.liferay.portal.model.LayoutTypePortlet;
037    import com.liferay.portal.model.Portlet;
038    import com.liferay.portal.service.PortletLocalServiceUtil;
039    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
040    import com.liferay.portal.theme.ThemeDisplay;
041    import com.liferay.portal.util.PortletKeys;
042    import com.liferay.portlet.PortletPreferencesFactoryUtil;
043    
044    import java.util.HashMap;
045    import java.util.Map;
046    import java.util.Stack;
047    
048    import javax.servlet.http.HttpServletRequest;
049    import javax.servlet.http.HttpServletResponse;
050    import javax.servlet.jsp.JspException;
051    import javax.servlet.jsp.PageContext;
052    import javax.servlet.jsp.tagext.TagSupport;
053    
054    /**
055     * @author Brian Wing Shun Chan
056     */
057    public class RuntimeTag extends TagSupport {
058    
059            public static void doTag(
060                            String portletName, PageContext pageContext,
061                            HttpServletRequest request, HttpServletResponse response)
062                    throws Exception {
063    
064                    doTag(portletName, null, pageContext, request, response);
065            }
066    
067            public static void doTag(
068                            String portletName, String queryString, PageContext pageContext,
069                            HttpServletRequest request, HttpServletResponse response)
070                    throws Exception {
071    
072                    doTag(portletName, queryString, null, pageContext, request, response);
073            }
074    
075            public static void doTag(
076                            String portletName, String queryString, String defaultPreferences,
077                            PageContext pageContext, HttpServletRequest request,
078                            HttpServletResponse response)
079                    throws Exception {
080    
081                    if (pageContext != null) {
082                            response = new PipingServletResponse(
083                                    response, pageContext.getOut());
084                    }
085    
086                    String portletId = portletName;
087    
088                    RestrictPortletServletRequest restrictPortletServletRequest =
089                            new RestrictPortletServletRequest(request);
090    
091                    queryString = PortletParameterUtil.addNamespace(portletId, queryString);
092    
093                    Map<String, String[]> parameterMap = request.getParameterMap();
094    
095                    if (!portletId.equals(request.getParameter("p_p_id"))) {
096                            parameterMap = MapUtil.filter(
097                                    parameterMap, new HashMap<String, String[]>(),
098                                    new PrefixPredicateFilter("p_p_"));
099                    }
100    
101                    request = DynamicServletRequest.addQueryString(
102                            restrictPortletServletRequest, parameterMap, queryString, false);
103    
104                    try {
105                            request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
106    
107                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
108                                    WebKeys.THEME_DISPLAY);
109    
110                            Stack<String> embeddedPortletIds = _embeddedPortletIds.get();
111    
112                            if (embeddedPortletIds == null) {
113                                    embeddedPortletIds = new Stack<String>();
114    
115                                    _embeddedPortletIds.set(embeddedPortletIds);
116                            }
117    
118                            if (embeddedPortletIds.search(portletId) > -1) {
119                                    String errorMessage = LanguageUtil.get(
120                                            pageContext, "the-application-cannot-include-itself");
121    
122                                    request.setAttribute(
123                                            "liferay-portlet:runtime:errorMessage", errorMessage);
124    
125                                    PortalIncludeUtil.include(pageContext, _ERROR_PAGE);
126    
127                                    return;
128                            }
129    
130                            if (themeDisplay.isStateMaximized()) {
131                                    LayoutTypePortlet layoutTypePortlet =
132                                            themeDisplay.getLayoutTypePortlet();
133    
134                                    if (layoutTypePortlet.hasStateMaxPortletId(portletId)) {
135    
136                                            // A portlet in the maximized state has already been
137                                            // processed
138    
139                                            return;
140                                    }
141                            }
142    
143                            Layout layout = themeDisplay.getLayout();
144    
145                            Portlet portlet = getPortlet(
146                                    themeDisplay.getCompanyId(), portletId);
147    
148                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
149    
150                            if ((PortletPreferencesLocalServiceUtil.getPortletPreferencesCount(
151                                            PortletKeys.PREFS_OWNER_TYPE_LAYOUT, themeDisplay.getPlid(),
152                                            portletId) < 1) ||
153                                    layout.isTypeControlPanel() ||
154                                    layout.isTypePanel()) {
155    
156                                    PortletPreferencesFactoryUtil.getLayoutPortletSetup(
157                                            layout, portletId, defaultPreferences);
158                                    PortletPreferencesFactoryUtil.getPortletSetup(
159                                            request, portletId, defaultPreferences);
160    
161                                    PortletLayoutListener portletLayoutListener =
162                                            portlet.getPortletLayoutListenerInstance();
163    
164                                    if (portletLayoutListener != null) {
165                                            portletLayoutListener.onAddToLayout(
166                                                    portletId, themeDisplay.getPlid());
167                                    }
168    
169                                    PortletJSONUtil.populatePortletJSONObject(
170                                            request, StringPool.BLANK, portlet, jsonObject);
171                            }
172    
173                            PortletJSONUtil.writeHeaderPaths(response, jsonObject);
174    
175                            embeddedPortletIds.push(portletId);
176    
177                            PortletContainerUtil.render(request, response, portlet);
178    
179                            embeddedPortletIds.pop();
180    
181                            PortletJSONUtil.writeFooterPaths(response, jsonObject);
182                    }
183                    finally {
184                            restrictPortletServletRequest.mergeSharedAttributes();
185                    }
186            }
187    
188            @Override
189            public int doEndTag() throws JspException {
190                    try {
191                            HttpServletRequest request =
192                                    (HttpServletRequest)pageContext.getRequest();
193    
194                            Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
195    
196                            if (layout == null) {
197                                    return EVAL_PAGE;
198                            }
199    
200                            HttpServletResponse response =
201                                    (HttpServletResponse)pageContext.getResponse();
202    
203                            doTag(
204                                    _portletName, _queryString, _defaultPreferences, pageContext,
205                                    request, response);
206    
207                            return EVAL_PAGE;
208                    }
209                    catch (Exception e) {
210                            _log.error(e, e);
211    
212                            throw new JspException(e);
213                    }
214            }
215    
216            public void setDefaultPreferences(String defaultPreferences) {
217                    _defaultPreferences = defaultPreferences;
218            }
219    
220            public void setPortletName(String portletName) {
221                    _portletName = portletName;
222            }
223    
224            public void setQueryString(String queryString) {
225                    _queryString = queryString;
226            }
227    
228            /**
229             * @see com.liferay.portal.model.impl.LayoutTypePortletImpl#getStaticPortlets(
230             *      String)
231             */
232            protected static Portlet getPortlet(long companyId, String portletId)
233                    throws Exception {
234    
235                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
236                            companyId, portletId);
237    
238                    // See LayoutTypePortletImpl#getStaticPortlets for why we only clone
239                    // non-instanceable portlets
240    
241                    if (!portlet.isInstanceable()) {
242                            portlet = (Portlet)portlet.clone();
243                    }
244    
245                    portlet.setStatic(true);
246    
247                    return portlet;
248            }
249    
250            private static final String _ERROR_PAGE =
251                    "/html/taglib/portlet/runtime/error.jsp";
252    
253            private static Log _log = LogFactoryUtil.getLog(RuntimeTag.class);
254    
255            private static final ThreadLocal<Stack<String>> _embeddedPortletIds =
256                    new AutoResetThreadLocal<Stack<String>>(
257                            RuntimeTag.class + "._embeddedPortletIds");
258    
259            private String _defaultPreferences;
260            private String _portletName;
261            private String _queryString;
262    
263    }