1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.action;
24  
25  import com.liferay.portal.kernel.language.LanguageUtil;
26  import com.liferay.portal.kernel.servlet.BrowserSniffer;
27  import com.liferay.portal.kernel.servlet.HttpHeaders;
28  import com.liferay.portal.kernel.servlet.StringServletResponse;
29  import com.liferay.portal.kernel.util.ContentTypes;
30  import com.liferay.portal.kernel.util.JavaConstants;
31  import com.liferay.portal.kernel.util.ParamUtil;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.model.Layout;
34  import com.liferay.portal.model.Portlet;
35  import com.liferay.portal.model.PortletPreferencesIds;
36  import com.liferay.portal.model.User;
37  import com.liferay.portal.model.impl.LayoutImpl;
38  import com.liferay.portal.service.PortletLocalServiceUtil;
39  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
40  import com.liferay.portal.struts.ActionConstants;
41  import com.liferay.portal.struts.StrutsUtil;
42  import com.liferay.portal.theme.ThemeDisplay;
43  import com.liferay.portal.util.PortalUtil;
44  import com.liferay.portal.util.PropsValues;
45  import com.liferay.portal.util.WebKeys;
46  import com.liferay.portlet.ActionRequestFactory;
47  import com.liferay.portlet.ActionRequestImpl;
48  import com.liferay.portlet.ActionResponseFactory;
49  import com.liferay.portlet.ActionResponseImpl;
50  import com.liferay.portlet.CachePortlet;
51  import com.liferay.portlet.PortletConfigFactory;
52  import com.liferay.portlet.PortletInstanceFactory;
53  import com.liferay.portlet.PortletPreferencesFactoryUtil;
54  import com.liferay.portlet.PortletURLImpl;
55  import com.liferay.portlet.RenderParametersPool;
56  import com.liferay.portlet.RenderRequestFactory;
57  import com.liferay.portlet.RenderRequestImpl;
58  import com.liferay.portlet.RenderResponseFactory;
59  import com.liferay.portlet.RenderResponseImpl;
60  import com.liferay.util.Http;
61  import com.liferay.util.servlet.ServletResponseUtil;
62  import com.liferay.util.servlet.UploadServletRequest;
63  
64  import java.io.ByteArrayInputStream;
65  import java.io.InputStream;
66  
67  import java.util.Iterator;
68  import java.util.Map;
69  
70  import javax.portlet.PortletConfig;
71  import javax.portlet.PortletContext;
72  import javax.portlet.PortletMode;
73  import javax.portlet.PortletPreferences;
74  import javax.portlet.PortletURL;
75  import javax.portlet.WindowState;
76  
77  import javax.servlet.RequestDispatcher;
78  import javax.servlet.ServletContext;
79  import javax.servlet.http.HttpServletRequest;
80  import javax.servlet.http.HttpServletResponse;
81  import javax.servlet.http.HttpSession;
82  import javax.servlet.jsp.PageContext;
83  
84  import org.apache.commons.logging.Log;
85  import org.apache.commons.logging.LogFactory;
86  import org.apache.struts.action.Action;
87  import org.apache.struts.action.ActionForm;
88  import org.apache.struts.action.ActionForward;
89  import org.apache.struts.action.ActionMapping;
90  
91  /**
92   * <a href="LayoutAction.java.html"><b><i>View Source</i></b></a>
93   *
94   * @author Brian Wing Shun Chan
95   *
96   */
97  public class LayoutAction extends Action {
98  
99      public ActionForward execute(
100             ActionMapping mapping, ActionForm form, HttpServletRequest req,
101             HttpServletResponse res)
102         throws Exception {
103 
104         ThemeDisplay themeDisplay =
105             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
106 
107         Layout layout = themeDisplay.getLayout();
108 
109         Boolean layoutDefault  = (Boolean)req.getAttribute(
110             WebKeys.LAYOUT_DEFAULT);
111 
112         if ((layoutDefault != null) && (layoutDefault.booleanValue())) {
113             Layout requestedLayout =
114                 (Layout)req.getAttribute(WebKeys.REQUESTED_LAYOUT);
115 
116             if (requestedLayout != null) {
117                 String redirect =
118                     themeDisplay.getURLSignIn() + "?redirect=" +
119                         PortalUtil.getLayoutURL(requestedLayout, themeDisplay);
120 
121                 if (_log.isDebugEnabled()) {
122                     _log.debug("Redirect requested layout to " + redirect);
123                 }
124 
125                 res.sendRedirect(redirect);
126             }
127             else {
128                 String redirect = PortalUtil.getLayoutURL(layout, themeDisplay);
129 
130                 if (_log.isDebugEnabled()) {
131                     _log.debug("Redirect default layout to " + redirect);
132                 }
133 
134                 res.sendRedirect(redirect);
135             }
136 
137             return null;
138         }
139 
140         long plid = ParamUtil.getLong(req, "p_l_id");
141         boolean resetLayout = ParamUtil.getBoolean(
142             req, "p_l_reset", PropsValues.LAYOUT_DEFAULT_P_L_RESET);
143         String action = ParamUtil.getString(req, "p_p_action");
144 
145         if (plid > 0) {
146             try {
147                 if (resetLayout) {
148                     RenderParametersPool.clear(req, plid);
149                 }
150 
151                 if (action.equals("1")) {
152                     Portlet portlet = processActionRequest(req, res);
153 
154                     if (portlet != null) {
155                         ActionResponseImpl actionResponseImpl =
156                             (ActionResponseImpl)req.getAttribute(
157                                 JavaConstants.JAVAX_PORTLET_RESPONSE);
158 
159                         String redirectLocation =
160                             actionResponseImpl.getRedirectLocation();
161 
162                         if (Validator.isNotNull(redirectLocation)) {
163                             res.sendRedirect(redirectLocation);
164 
165                             return null;
166                         }
167 
168                         if (portlet.isActionURLRedirect()) {
169                             redirectActionURL(
170                                 req, res, actionResponseImpl, portlet);
171                         }
172                     }
173                 }
174                 else if (action.equals("0")) {
175                     processRenderRequest(req, res);
176                 }
177 
178                 if (layout != null) {
179 
180                     // Include layout content before the page loads because
181                     // portlets on the page can set the page title and page
182                     // subtitle
183 
184                     includeLayoutContent(req, res, themeDisplay, layout);
185 
186                     if (themeDisplay.isStateExclusive()) {
187                         serverExclusiveResource(req, res, themeDisplay);
188 
189                         return null;
190                     }
191                 }
192 
193                 return mapping.findForward("portal.layout");
194             }
195             catch (Exception e) {
196                 req.setAttribute(PageContext.EXCEPTION, e);
197 
198                 return mapping.findForward(ActionConstants.COMMON_ERROR);
199             }
200             finally {
201                 try {
202                     if (action.equals("1")) {
203                         ActionRequestImpl actionRequestImpl =
204                             (ActionRequestImpl)req.getAttribute(
205                                 JavaConstants.JAVAX_PORTLET_REQUEST);
206 
207                         ActionRequestFactory.recycle(actionRequestImpl);
208                     }
209                 }
210                 catch (Exception e) {
211                     _log.error(e);
212                 }
213 
214                 req.removeAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
215 
216                 try {
217                     if (action.equals("1")) {
218                         ActionResponseImpl actionResponseImpl =
219                             (ActionResponseImpl)req.getAttribute(
220                                 JavaConstants.JAVAX_PORTLET_RESPONSE);
221 
222                         ActionResponseFactory.recycle(actionResponseImpl);
223                     }
224                 }
225                 catch (Exception e) {
226                     _log.error(e);
227                 }
228 
229                 req.removeAttribute(JavaConstants.JAVAX_PORTLET_RESPONSE);
230             }
231         }
232         else {
233             try {
234                 forwardLayout(req);
235 
236                 return mapping.findForward(ActionConstants.COMMON_FORWARD);
237             }
238             catch (Exception e) {
239                 req.setAttribute(PageContext.EXCEPTION, e);
240 
241                 return mapping.findForward(ActionConstants.COMMON_ERROR);
242             }
243         }
244     }
245 
246     protected void forwardLayout(HttpServletRequest req) throws Exception {
247         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
248         long plid = LayoutImpl.DEFAULT_PLID;
249         String layoutFriendlyURL = null;
250 
251         ThemeDisplay themeDisplay =
252             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
253 
254         if (layout != null) {
255             plid = layout.getPlid();
256             layoutFriendlyURL =
257                 PortalUtil.getLayoutFriendlyURL(layout, themeDisplay);
258         }
259 
260         String forwardURL = layoutFriendlyURL;
261 
262         if (Validator.isNull(forwardURL)) {
263             forwardURL =
264                 themeDisplay.getPathMain() + "/portal/layout?p_l_id=" + plid;
265 
266             if (Validator.isNotNull(themeDisplay.getDoAsUserId())) {
267                 forwardURL = Http.addParameter(
268                     forwardURL, "doAsUserId", themeDisplay.getDoAsUserId());
269             }
270         }
271 
272         if (_log.isDebugEnabled()) {
273             _log.debug("Forward layout to " + forwardURL);
274         }
275 
276         req.setAttribute(WebKeys.FORWARD_URL, forwardURL);
277     }
278 
279     protected void includeLayoutContent(
280             HttpServletRequest req, HttpServletResponse res,
281             ThemeDisplay themeDisplay, Layout layout)
282         throws Exception {
283 
284         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
285 
286         String path = StrutsUtil.TEXT_HTML_DIR;
287 
288         if (BrowserSniffer.is_wap_xhtml(req)) {
289             path = StrutsUtil.TEXT_WAP_DIR;
290         }
291 
292         // Manually check the p_p_id. See LEP-1724.
293 
294         if (themeDisplay.isStateExclusive() ||
295             Validator.isNotNull(ParamUtil.getString(req, "p_p_id"))) {
296 
297             path += "/portal/layout/view/portlet.jsp";
298         }
299         else {
300             path += PortalUtil.getLayoutViewPage(layout);
301         }
302 
303         RequestDispatcher rd = ctx.getRequestDispatcher(path);
304 
305         StringServletResponse stringServletRes = new StringServletResponse(res);
306 
307         rd.include(req, stringServletRes);
308 
309         req.setAttribute(WebKeys.LAYOUT_CONTENT, stringServletRes.getString());
310     }
311 
312     protected Portlet processActionRequest(
313             HttpServletRequest req, HttpServletResponse res)
314         throws Exception {
315 
316         return processPortletRequest(req, res, true);
317     }
318 
319     protected Portlet processPortletRequest(
320             HttpServletRequest req, HttpServletResponse res, boolean action)
321         throws Exception {
322 
323         HttpSession ses = req.getSession();
324 
325         long companyId = PortalUtil.getCompanyId(req);
326         User user = PortalUtil.getUser(req);
327         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
328         String portletId = ParamUtil.getString(req, "p_p_id");
329 
330         Portlet portlet = PortletLocalServiceUtil.getPortletById(
331             companyId, portletId);
332 
333         if (portlet == null) {
334             return null;
335         }
336 
337         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
338 
339         CachePortlet cachePortlet = PortletInstanceFactory.create(portlet, ctx);
340 
341         if (user != null) {
342             CachePortlet.clearResponse(
343                 ses, layout.getPrimaryKey(), portletId,
344                 LanguageUtil.getLanguageId(req));
345         }
346 
347         PortletPreferencesIds portletPreferencesIds =
348             PortletPreferencesFactoryUtil.getPortletPreferencesIds(
349                 req, portletId);
350 
351         PortletPreferences portletPreferences =
352             PortletPreferencesLocalServiceUtil.getPreferences(
353                 portletPreferencesIds);
354 
355         PortletConfig portletConfig = PortletConfigFactory.create(portlet, ctx);
356         PortletContext portletCtx = portletConfig.getPortletContext();
357 
358         WindowState windowState = new WindowState(
359             ParamUtil.getString(req, "p_p_state"));
360 
361         PortletMode portletMode = new PortletMode(
362             ParamUtil.getString(req, "p_p_mode"));
363 
364         if (action) {
365             String contentType = req.getHeader(HttpHeaders.CONTENT_TYPE);
366 
367             if (_log.isDebugEnabled()) {
368                 _log.debug("Content type " + contentType);
369             }
370 
371             UploadServletRequest uploadReq = null;
372 
373             try {
374                 if ((contentType != null) &&
375                     (contentType.startsWith(
376                         ContentTypes.MULTIPART_FORM_DATA))) {
377 
378                     if (!cachePortlet.getPortletConfig().isWARFile() ||
379                         cachePortlet.isStrutsPortlet()) {
380 
381                         uploadReq = new UploadServletRequest(req);
382 
383                         req = uploadReq;
384                     }
385                 }
386 
387                 ActionRequestImpl actionRequestImpl =
388                     ActionRequestFactory.create(
389                         req, portlet, cachePortlet, portletCtx, windowState,
390                         portletMode, portletPreferences, layout.getPlid());
391 
392                 ActionResponseImpl actionResponseImpl =
393                     ActionResponseFactory.create(
394                         actionRequestImpl, res, portletId, user, layout,
395                         windowState, portletMode);
396 
397                 actionRequestImpl.defineObjects(
398                     portletConfig, actionResponseImpl);
399 
400                 cachePortlet.processAction(
401                     actionRequestImpl, actionResponseImpl);
402 
403                 RenderParametersPool.put(
404                     req, layout.getPlid(), portletId,
405                     actionResponseImpl.getRenderParameters());
406             }
407             finally {
408                 if (uploadReq != null) {
409                     uploadReq.cleanUp();
410                 }
411             }
412         }
413         else {
414             PortalUtil.updateWindowState(
415                 portletId, user, layout, windowState, req);
416 
417             PortalUtil.updatePortletMode(
418                 portletId, user, layout, portletMode, req);
419         }
420 
421         return portlet;
422     }
423 
424     protected Portlet processRenderRequest(
425             HttpServletRequest req, HttpServletResponse res)
426         throws Exception {
427 
428         return processPortletRequest(req, res, false);
429     }
430 
431     protected void redirectActionURL(
432             HttpServletRequest req, HttpServletResponse res,
433             ActionResponseImpl actionResponseImpl, Portlet portlet)
434         throws Exception {
435 
436         ActionRequestImpl actionRequestImpl =
437             (ActionRequestImpl)req.getAttribute(
438                 JavaConstants.JAVAX_PORTLET_REQUEST);
439 
440         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
441 
442         PortletURL portletURL = new PortletURLImpl(
443             actionRequestImpl, actionRequestImpl.getPortletName(),
444             layout.getLayoutId(), false);
445 
446         Map renderParameters = actionResponseImpl.getRenderParameters();
447 
448         Iterator itr = renderParameters.entrySet().iterator();
449 
450         while (itr.hasNext()) {
451             Map.Entry entry = (Map.Entry)itr.next();
452 
453             String key = (String)entry.getKey();
454             Object value = entry.getValue();
455 
456             if (value instanceof String) {
457                 portletURL.setParameter(key, (String)value);
458             }
459             else if (value instanceof String[]) {
460                 portletURL.setParameter(key, (String[])value);
461             }
462         }
463 
464         res.sendRedirect(portletURL.toString());
465     }
466 
467     protected void serverExclusiveResource(
468             HttpServletRequest req, HttpServletResponse res,
469             ThemeDisplay themeDisplay)
470         throws Exception {
471 
472         RenderRequestImpl renderRequestImpl = (RenderRequestImpl)
473             req.getAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
474 
475         RenderResponseImpl renderResponseImpl = (RenderResponseImpl)
476             req.getAttribute(JavaConstants.JAVAX_PORTLET_RESPONSE);
477 
478         StringServletResponse stringServletResponse = (StringServletResponse)
479             renderRequestImpl.getAttribute(WebKeys.STRING_SERVLET_RESPONSE);
480 
481         renderResponseImpl.transferHeaders(res);
482 
483         if (stringServletResponse.isCalledGetOutputStream()) {
484             InputStream is = new ByteArrayInputStream(
485                 stringServletResponse.getByteArrayMaker().toByteArray());
486 
487             ServletResponseUtil.sendFile(
488                 res, renderResponseImpl.getResourceName(), is,
489                 renderResponseImpl.getContentType());
490         }
491         else {
492             byte[] content = stringServletResponse.getString().getBytes();
493 
494             ServletResponseUtil.sendFile(
495                 res, renderResponseImpl.getResourceName(), content,
496                 renderResponseImpl.getContentType());
497         }
498 
499         RenderRequestFactory.recycle(renderRequestImpl);
500         RenderResponseFactory.recycle(renderResponseImpl);
501     }
502 
503     private static Log _log = LogFactory.getLog(LayoutAction.class);
504 
505 }