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