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.portlet.PortletModeFactory;
27  import com.liferay.portal.kernel.portlet.WindowStateFactory;
28  import com.liferay.portal.kernel.servlet.BrowserSniffer;
29  import com.liferay.portal.kernel.servlet.HttpHeaders;
30  import com.liferay.portal.kernel.servlet.StringServletResponse;
31  import com.liferay.portal.kernel.util.ContentTypes;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.JavaConstants;
34  import com.liferay.portal.kernel.util.ParamUtil;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.Validator;
37  import com.liferay.portal.model.Layout;
38  import com.liferay.portal.model.LayoutTypePortlet;
39  import com.liferay.portal.model.Portlet;
40  import com.liferay.portal.model.PortletPreferencesIds;
41  import com.liferay.portal.model.User;
42  import com.liferay.portal.model.impl.LayoutImpl;
43  import com.liferay.portal.service.PortletLocalServiceUtil;
44  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
45  import com.liferay.portal.struts.ActionConstants;
46  import com.liferay.portal.struts.StrutsUtil;
47  import com.liferay.portal.theme.ThemeDisplay;
48  import com.liferay.portal.util.PortalUtil;
49  import com.liferay.portal.util.PropsValues;
50  import com.liferay.portal.util.WebKeys;
51  import com.liferay.portlet.ActionRequestFactory;
52  import com.liferay.portlet.ActionRequestImpl;
53  import com.liferay.portlet.ActionResponseFactory;
54  import com.liferay.portlet.ActionResponseImpl;
55  import com.liferay.portlet.EventRequestFactory;
56  import com.liferay.portlet.EventRequestImpl;
57  import com.liferay.portlet.EventResponseFactory;
58  import com.liferay.portlet.EventResponseImpl;
59  import com.liferay.portlet.InvokerPortlet;
60  import com.liferay.portlet.PortletConfigFactory;
61  import com.liferay.portlet.PortletInstanceFactory;
62  import com.liferay.portlet.PortletPreferencesFactoryUtil;
63  import com.liferay.portlet.PortletRequestImpl;
64  import com.liferay.portlet.PortletURLImpl;
65  import com.liferay.portlet.RenderParametersPool;
66  import com.liferay.portlet.RenderRequestFactory;
67  import com.liferay.portlet.RenderRequestImpl;
68  import com.liferay.portlet.RenderResponseFactory;
69  import com.liferay.portlet.RenderResponseImpl;
70  import com.liferay.portlet.ResourceRequestFactory;
71  import com.liferay.portlet.ResourceRequestImpl;
72  import com.liferay.portlet.ResourceResponseFactory;
73  import com.liferay.portlet.ResourceResponseImpl;
74  import com.liferay.portlet.StateAwareResponseImpl;
75  import com.liferay.util.MapUtil;
76  import com.liferay.util.servlet.ServletResponseUtil;
77  import com.liferay.util.servlet.UploadServletRequest;
78  
79  import java.io.ByteArrayInputStream;
80  import java.io.InputStream;
81  
82  import java.util.HashMap;
83  import java.util.List;
84  import java.util.Map;
85  
86  import javax.portlet.Event;
87  import javax.portlet.PortletConfig;
88  import javax.portlet.PortletContext;
89  import javax.portlet.PortletException;
90  import javax.portlet.PortletMode;
91  import javax.portlet.PortletPreferences;
92  import javax.portlet.PortletRequest;
93  import javax.portlet.PortletResponse;
94  import javax.portlet.PortletURL;
95  import javax.portlet.UnavailableException;
96  import javax.portlet.WindowState;
97  
98  import javax.servlet.RequestDispatcher;
99  import javax.servlet.ServletContext;
100 import javax.servlet.http.HttpServletRequest;
101 import javax.servlet.http.HttpServletResponse;
102 import javax.servlet.http.HttpSession;
103 import javax.servlet.jsp.PageContext;
104 
105 import javax.xml.namespace.QName;
106 
107 import org.apache.commons.logging.Log;
108 import org.apache.commons.logging.LogFactory;
109 import org.apache.struts.action.Action;
110 import org.apache.struts.action.ActionForm;
111 import org.apache.struts.action.ActionForward;
112 import org.apache.struts.action.ActionMapping;
113 
114 /**
115  * <a href="LayoutAction.java.html"><b><i>View Source</i></b></a>
116  *
117  * @author Brian Wing Shun Chan
118  *
119  */
120 public class LayoutAction extends Action {
121 
122     public ActionForward execute(
123             ActionMapping mapping, ActionForm form, HttpServletRequest req,
124             HttpServletResponse res)
125         throws Exception {
126 
127         ThemeDisplay themeDisplay = (ThemeDisplay)req.getAttribute(
128             WebKeys.THEME_DISPLAY);
129 
130         Layout layout = themeDisplay.getLayout();
131 
132         Boolean layoutDefault = (Boolean)req.getAttribute(
133             WebKeys.LAYOUT_DEFAULT);
134 
135         if ((layoutDefault != null) && (layoutDefault.booleanValue())) {
136             Layout requestedLayout =
137                 (Layout)req.getAttribute(WebKeys.REQUESTED_LAYOUT);
138 
139             if (requestedLayout != null) {
140                 String redirectParam = "redirect";
141 
142                 if (Validator.isNotNull(PropsValues.AUTH_LOGIN_PORTLET_NAME) &&
143                     Validator.isNotNull(PropsValues.AUTH_LOGIN_URL)) {
144 
145                     redirectParam =
146                         PortalUtil.getPortletNamespace(
147                             PropsValues.AUTH_LOGIN_PORTLET_NAME) +
148                         redirectParam;
149                 }
150 
151                 String url = PortalUtil.getLayoutURL(
152                     requestedLayout, themeDisplay);
153 
154                 String redirect = HttpUtil.addParameter(
155                     themeDisplay.getURLSignIn(), redirectParam, url);
156 
157                 if (_log.isDebugEnabled()) {
158                     _log.debug("Redirect requested layout to " + redirect);
159                 }
160 
161                 res.sendRedirect(redirect);
162             }
163             else {
164                 String redirect = PortalUtil.getLayoutURL(layout, themeDisplay);
165 
166                 if (_log.isDebugEnabled()) {
167                     _log.debug("Redirect default layout to " + redirect);
168                 }
169 
170                 res.sendRedirect(redirect);
171             }
172 
173             return null;
174         }
175 
176         long plid = ParamUtil.getLong(req, "p_l_id");
177 
178         if (plid > 0) {
179             return processLayout(mapping, req, res, plid);
180         }
181         else {
182             try {
183                 forwardLayout(req);
184 
185                 return mapping.findForward(ActionConstants.COMMON_FORWARD);
186             }
187             catch (Exception e) {
188                 req.setAttribute(PageContext.EXCEPTION, e);
189 
190                 return mapping.findForward(ActionConstants.COMMON_ERROR);
191             }
192         }
193     }
194 
195     protected void forwardLayout(HttpServletRequest req) throws Exception {
196         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
197         long plid = LayoutImpl.DEFAULT_PLID;
198         String layoutFriendlyURL = null;
199 
200         ThemeDisplay themeDisplay =
201             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
202 
203         if (layout != null) {
204             plid = layout.getPlid();
205             layoutFriendlyURL =
206                 PortalUtil.getLayoutFriendlyURL(layout, themeDisplay);
207         }
208 
209         String forwardURL = layoutFriendlyURL;
210 
211         if (Validator.isNull(forwardURL)) {
212             forwardURL =
213                 themeDisplay.getPathMain() + "/portal/layout?p_l_id=" + plid;
214 
215             if (Validator.isNotNull(themeDisplay.getDoAsUserId())) {
216                 forwardURL = HttpUtil.addParameter(
217                     forwardURL, "doAsUserId", themeDisplay.getDoAsUserId());
218             }
219         }
220 
221         if (_log.isDebugEnabled()) {
222             _log.debug("Forward layout to " + forwardURL);
223         }
224 
225         req.setAttribute(WebKeys.FORWARD_URL, forwardURL);
226     }
227 
228     protected void includeLayoutContent(
229             HttpServletRequest req, HttpServletResponse res,
230             ThemeDisplay themeDisplay, Layout layout)
231         throws Exception {
232 
233         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
234 
235         String path = StrutsUtil.TEXT_HTML_DIR;
236 
237         if (BrowserSniffer.is_wap_xhtml(req)) {
238             path = StrutsUtil.TEXT_WAP_DIR;
239         }
240 
241         // Manually check the p_p_id. See LEP-1724.
242 
243         if (themeDisplay.isStateExclusive() ||
244             Validator.isNotNull(ParamUtil.getString(req, "p_p_id"))) {
245 
246             path += "/portal/layout/view/portlet.jsp";
247         }
248         else {
249             path += PortalUtil.getLayoutViewPage(layout);
250         }
251 
252         RequestDispatcher rd = ctx.getRequestDispatcher(path);
253 
254         StringServletResponse stringServletRes = new StringServletResponse(res);
255 
256         rd.include(req, stringServletRes);
257 
258         req.setAttribute(WebKeys.LAYOUT_CONTENT, stringServletRes.getString());
259     }
260 
261     protected void processEvent(
262             PortletRequestImpl portletReqImpl,
263             StateAwareResponseImpl stateAwareResImpl, Portlet portlet,
264             List<Portlet> portlets, Event event)
265         throws Exception {
266 
267         HttpServletRequest req = portletReqImpl.getHttpServletRequest();
268         HttpServletResponse res = stateAwareResImpl.getHttpServletResponse();
269 
270         String portletId = portlet.getPortletId();
271 
272         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
273 
274         InvokerPortlet invokerPortlet = PortletInstanceFactory.create(
275             portlet, ctx);
276 
277         PortletConfig portletConfig = PortletConfigFactory.create(portlet, ctx);
278         PortletContext portletCtx = portletConfig.getPortletContext();
279 
280         WindowState windowState = portletReqImpl.getWindowState();
281         PortletMode portletMode = portletReqImpl.getPortletMode();
282 
283         User user = stateAwareResImpl.getUser();
284         Layout layout = stateAwareResImpl.getLayout();
285 
286         PortletPreferences portletPreferences =
287             portletReqImpl.getPreferencesImpl();
288 
289         EventRequestImpl eventReqImpl = EventRequestFactory.create(
290             req, portlet, invokerPortlet, portletCtx, windowState,
291             portletMode, portletPreferences, layout.getPlid());
292 
293         eventReqImpl.setEvent(event);
294 
295         EventResponseImpl eventResImpl = EventResponseFactory.create(
296             eventReqImpl, res, portletId, user, layout, windowState,
297             portletMode);
298 
299         eventReqImpl.defineObjects(portletConfig, eventResImpl);
300 
301         try {
302             try {
303                 invokerPortlet.processEvent(eventReqImpl, eventResImpl);
304 
305                 if (eventResImpl.isCalledSetRenderParameter()) {
306                     Map<String, String[]> renderParameterMap =
307                         new HashMap<String, String[]>();
308 
309                     MapUtil.copy(
310                         eventResImpl.getRenderParameterMap(),
311                         renderParameterMap);
312 
313                     RenderParametersPool.put(
314                         req, layout.getPlid(), portletId, renderParameterMap);
315                 }
316             }
317             catch (UnavailableException ue) {
318                 throw ue;
319             }
320             catch (PortletException pe) {
321                 eventResImpl.setWindowState(windowState);
322                 eventResImpl.setPortletMode(portletMode);
323             }
324 
325             processEvents(eventReqImpl, eventResImpl, portlets);
326         }
327         finally {
328             EventRequestFactory.recycle(eventReqImpl);
329             EventResponseFactory.recycle(eventResImpl);
330         }
331     }
332 
333     protected void processEvents(
334             PortletRequestImpl portletReqImpl,
335             StateAwareResponseImpl stateAwareResImpl, List<Portlet> portlets)
336         throws Exception {
337 
338         List<Event> events = stateAwareResImpl.getEvents();
339 
340         if (events.size() == 0) {
341             return;
342         }
343 
344         for (Event event : events) {
345             QName qName = event.getQName();
346 
347             for (Portlet portlet : portlets) {
348                 QName processingQName = portlet.getProcessingEvent(
349                     qName.getNamespaceURI(), qName.getLocalPart());
350 
351                 if (processingQName != null) {
352                     processEvent(
353                         portletReqImpl, stateAwareResImpl, portlet, portlets,
354                         event);
355                 }
356             }
357         }
358     }
359 
360     protected ActionForward processLayout(
361             ActionMapping mapping, HttpServletRequest req,
362             HttpServletResponse res, long plid)
363         throws Exception {
364 
365         ThemeDisplay themeDisplay = (ThemeDisplay)req.getAttribute(
366             WebKeys.THEME_DISPLAY);
367 
368         try {
369             Layout layout = themeDisplay.getLayout();
370 
371             boolean resetLayout = ParamUtil.getBoolean(
372                 req, "p_l_reset", PropsValues.LAYOUT_DEFAULT_P_L_RESET);
373 
374             if (!PropsValues.TCK_URL && resetLayout) {
375                 RenderParametersPool.clear(req, plid);
376             }
377 
378             if (themeDisplay.isLifecycleAction()) {
379                 Portlet portlet = processPortletRequest(
380                     req, res, PortletRequest.ACTION_PHASE);
381 
382                 if (portlet != null) {
383                     ActionResponseImpl actionResImpl =
384                         (ActionResponseImpl)req.getAttribute(
385                             JavaConstants.JAVAX_PORTLET_RESPONSE);
386 
387                     String redirectLocation =
388                         actionResImpl.getRedirectLocation();
389 
390                     if (Validator.isNotNull(redirectLocation)) {
391                         res.sendRedirect(redirectLocation);
392 
393                         return null;
394                     }
395 
396                     if (portlet.isActionURLRedirect()) {
397                         redirectActionURL(
398                             req, res, actionResImpl, portlet);
399 
400                         return null;
401                     }
402                 }
403             }
404             else if (themeDisplay.isLifecycleRender()) {
405                 processPortletRequest(req, res, PortletRequest.RENDER_PHASE);
406             }
407 
408             if (themeDisplay.isLifecycleResource()) {
409                 processPortletRequest(req, res, PortletRequest.RESOURCE_PHASE);
410 
411                 return null;
412             }
413             else {
414                 if (layout != null) {
415 
416                     // Include layout content before the page loads because
417                     // portlets on the page can set the page title and page
418                     // subtitle
419 
420                     includeLayoutContent(req, res, themeDisplay, layout);
421 
422                     if (themeDisplay.isStateExclusive()) {
423                         renderExclusive(req, res, themeDisplay);
424 
425                         return null;
426                     }
427                 }
428 
429                 return mapping.findForward("portal.layout");
430             }
431         }
432         catch (Exception e) {
433             req.setAttribute(PageContext.EXCEPTION, e);
434 
435             return mapping.findForward(ActionConstants.COMMON_ERROR);
436         }
437         finally {
438             PortletRequest portletReq = (PortletRequest)req.getAttribute(
439                 JavaConstants.JAVAX_PORTLET_REQUEST);
440 
441             try {
442                 if (portletReq != null) {
443                     if (themeDisplay.isLifecycleAction()) {
444                         ActionRequestImpl actionReqImpl =
445                             (ActionRequestImpl)portletReq;
446 
447                         ActionRequestFactory.recycle(actionReqImpl);
448                     }
449                     else if (themeDisplay.isLifecycleRender()) {
450                         RenderRequestImpl renderReqImpl =
451                             (RenderRequestImpl)portletReq;
452 
453                         RenderRequestFactory.recycle(renderReqImpl);
454                     }
455                     else if (themeDisplay.isLifecycleResource()) {
456                         ResourceRequestImpl resourceReqImpl =
457                             (ResourceRequestImpl)portletReq;
458 
459                         ResourceRequestFactory.recycle(resourceReqImpl);
460                     }
461                 }
462             }
463             catch (Exception e) {
464                 _log.error(e);
465             }
466 
467             req.removeAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
468 
469             PortletResponse portletRes = (PortletResponse)req.getAttribute(
470                 JavaConstants.JAVAX_PORTLET_RESPONSE);
471 
472             try {
473                 if (portletRes != null) {
474                     if (themeDisplay.isLifecycleAction()) {
475                         ActionResponseImpl actionResImpl =
476                             (ActionResponseImpl)portletRes;
477 
478                         ActionResponseFactory.recycle(actionResImpl);
479                     }
480                     else if (themeDisplay.isLifecycleRender()) {
481                         RenderResponseImpl renderResImpl =
482                             (RenderResponseImpl)portletRes;
483 
484                         RenderResponseFactory.recycle(renderResImpl);
485                     }
486                     else if (themeDisplay.isLifecycleResource()) {
487                         ResourceResponseImpl resourceResImpl =
488                             (ResourceResponseImpl)portletRes;
489 
490                         ResourceResponseFactory.recycle(resourceResImpl);
491                     }
492                 }
493             }
494             catch (Exception e) {
495                 _log.error(e);
496             }
497 
498             req.removeAttribute(JavaConstants.JAVAX_PORTLET_RESPONSE);
499         }
500     }
501 
502     protected Portlet processPortletRequest(
503             HttpServletRequest req, HttpServletResponse res, String lifecycle)
504         throws Exception {
505 
506         HttpSession ses = req.getSession();
507 
508         long companyId = PortalUtil.getCompanyId(req);
509         User user = PortalUtil.getUser(req);
510         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
511 
512         String portletId = ParamUtil.getString(req, "p_p_id");
513 
514         Portlet portlet = PortletLocalServiceUtil.getPortletById(
515             companyId, portletId);
516 
517         if (portlet == null) {
518             return null;
519         }
520 
521         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
522 
523         InvokerPortlet invokerPortlet = PortletInstanceFactory.create(
524             portlet, ctx);
525 
526         if (user != null) {
527             InvokerPortlet.clearResponse(
528                 ses, layout.getPrimaryKey(), portletId,
529                 LanguageUtil.getLanguageId(req));
530         }
531 
532         PortletConfig portletConfig = PortletConfigFactory.create(portlet, ctx);
533         PortletContext portletCtx = portletConfig.getPortletContext();
534 
535         WindowState windowState = WindowStateFactory.getWindowState(
536             ParamUtil.getString(req, "p_p_state"));
537 
538         PortletMode portletMode = PortletModeFactory.getPortletMode(
539             ParamUtil.getString(req, "p_p_mode"));
540 
541         PortletPreferencesIds portletPreferencesIds =
542             PortletPreferencesFactoryUtil.getPortletPreferencesIds(
543                 req, portletId);
544 
545         PortletPreferences portletPreferences =
546             PortletPreferencesLocalServiceUtil.getPreferences(
547                 portletPreferencesIds);
548 
549         if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
550             String contentType = req.getHeader(HttpHeaders.CONTENT_TYPE);
551 
552             if (_log.isDebugEnabled()) {
553                 _log.debug("Content type " + contentType);
554             }
555 
556             UploadServletRequest uploadReq = null;
557 
558             try {
559                 if ((contentType != null) &&
560                     (contentType.startsWith(
561                         ContentTypes.MULTIPART_FORM_DATA))) {
562 
563                     if (!invokerPortlet.getPortletConfig().isWARFile() ||
564                         invokerPortlet.isStrutsPortlet()) {
565 
566                         uploadReq = new UploadServletRequest(req);
567 
568                         req = uploadReq;
569                     }
570                 }
571 
572                 ActionRequestImpl actionReqImpl = ActionRequestFactory.create(
573                     req, portlet, invokerPortlet, portletCtx, windowState,
574                     portletMode, portletPreferences, layout.getPlid());
575 
576                 ActionResponseImpl actionResImpl = ActionResponseFactory.create(
577                     actionReqImpl, res, portletId, user, layout, windowState,
578                     portletMode);
579 
580                 actionReqImpl.defineObjects(portletConfig, actionResImpl);
581 
582                 invokerPortlet.processAction(actionReqImpl, actionResImpl);
583 
584                 RenderParametersPool.put(
585                     req, layout.getPlid(), portletId,
586                     actionResImpl.getRenderParameterMap());
587 
588                 if (actionResImpl.getEvents().size() > 0) {
589                     if (layout.getType().equals(LayoutImpl.TYPE_PORTLET)) {
590                         LayoutTypePortlet layoutTypePortlet =
591                             (LayoutTypePortlet)layout.getLayoutType();
592 
593                         List<Portlet> portlets =
594                             layoutTypePortlet.getPortlets();
595 
596                         processEvents(actionReqImpl, actionResImpl, portlets);
597 
598                         actionReqImpl.defineObjects(
599                             portletConfig, actionResImpl);
600                     }
601                 }
602             }
603             finally {
604                 if (uploadReq != null) {
605                     uploadReq.cleanUp();
606                 }
607             }
608         }
609         else if (lifecycle.equals(PortletRequest.RENDER_PHASE) ||
610                  lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
611 
612             PortalUtil.updateWindowState(
613                 portletId, user, layout, windowState, req);
614 
615             PortalUtil.updatePortletMode(
616                 portletId, user, layout, portletMode, req);
617         }
618 
619         if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
620             ResourceRequestImpl resourceReqImpl =
621                 ResourceRequestFactory.create(
622                     req, portlet, invokerPortlet, portletCtx, windowState,
623                     portletMode, portletPreferences, layout.getPlid());
624 
625             StringServletResponse stringServletRes = new StringServletResponse(
626                 res);
627 
628             ResourceResponseImpl resourceResImpl =
629                 ResourceResponseFactory.create(
630                     resourceReqImpl, stringServletRes, portletId, companyId);
631 
632             resourceReqImpl.defineObjects(portletConfig, resourceResImpl);
633 
634             invokerPortlet.serveResource(resourceReqImpl, resourceResImpl);
635 
636             if (stringServletRes.isCalledGetOutputStream()) {
637                 InputStream is = new ByteArrayInputStream(
638                     stringServletRes.getByteArrayMaker().toByteArray());
639 
640                 ServletResponseUtil.sendFile(
641                     res, resourceReqImpl.getResourceID(), is,
642                     resourceResImpl.getContentType());
643             }
644             else {
645                 byte[] content = stringServletRes.getString().getBytes(
646                     StringPool.UTF8);
647 
648                 ServletResponseUtil.sendFile(
649                     res, resourceReqImpl.getResourceID(), content,
650                     resourceResImpl.getContentType());
651             }
652         }
653 
654         return portlet;
655     }
656 
657     protected void redirectActionURL(
658             HttpServletRequest req, HttpServletResponse res,
659             ActionResponseImpl actionResImpl, Portlet portlet)
660         throws Exception {
661 
662         ActionRequestImpl actionReqImpl = (ActionRequestImpl)req.getAttribute(
663             JavaConstants.JAVAX_PORTLET_REQUEST);
664 
665         Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
666 
667         PortletURL portletURL = new PortletURLImpl(
668             actionReqImpl, actionReqImpl.getPortletName(), layout.getLayoutId(),
669             PortletRequest.RENDER_PHASE);
670 
671         Map<String, String[]> renderParameters =
672             actionResImpl.getRenderParameterMap();
673 
674         for (Map.Entry<String, String[]> entry : renderParameters.entrySet()) {
675             String key = entry.getKey();
676             String[] value = entry.getValue();
677 
678             portletURL.setParameter(key, value);
679         }
680 
681         res.sendRedirect(portletURL.toString());
682     }
683 
684     protected void renderExclusive(
685             HttpServletRequest req, HttpServletResponse res,
686             ThemeDisplay themeDisplay)
687         throws Exception {
688 
689         RenderRequestImpl renderReqImpl = (RenderRequestImpl)req.getAttribute(
690             JavaConstants.JAVAX_PORTLET_REQUEST);
691 
692         RenderResponseImpl renderResImpl = (RenderResponseImpl)req.getAttribute(
693             JavaConstants.JAVAX_PORTLET_RESPONSE);
694 
695         StringServletResponse stringServletRes =
696             (StringServletResponse)renderReqImpl.getAttribute(
697                 WebKeys.STRING_SERVLET_RESPONSE);
698 
699         renderResImpl.transferHeaders(res);
700 
701         if (stringServletRes.isCalledGetOutputStream()) {
702             InputStream is = new ByteArrayInputStream(
703                 stringServletRes.getByteArrayMaker().toByteArray());
704 
705             ServletResponseUtil.sendFile(
706                 res, renderResImpl.getResourceName(), is,
707                 renderResImpl.getContentType());
708         }
709         else {
710             byte[] content = stringServletRes.getString().getBytes(
711                 StringPool.UTF8);
712 
713             ServletResponseUtil.sendFile(
714                 res, renderResImpl.getResourceName(), content,
715                 renderResImpl.getContentType());
716         }
717 
718         RenderRequestFactory.recycle(renderReqImpl);
719         RenderResponseFactory.recycle(renderResImpl);
720     }
721 
722     private static Log _log = LogFactory.getLog(LayoutAction.class);
723 
724 }