001: /*
002: * Copyright 2004-2005 Sun Microsystems, Inc. All
003: * rights reserved. Use of this product is subject
004: * to license terms. Federal Acquisitions:
005: * Commercial Software -- Government Users
006: * Subject to Standard License Terms and
007: * Conditions.
008: *
009: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
010: * are trademarks or registered trademarks of Sun Microsystems,
011: * Inc. in the United States and other countries.
012: */
013:
014: package com.sun.portal.container.portlet.impl;
015:
016: import com.iplanet.sso.SSOToken;
017: import com.sun.portal.container.ChannelMode;
018: import com.sun.portal.container.Container;
019: import com.sun.portal.container.ContainerException;
020: import com.sun.portal.container.ContainerRequest;
021: import com.sun.portal.container.ContainerResponse;
022: import com.sun.portal.container.ContentException;
023: import com.sun.portal.container.ExecuteActionRequest;
024: import com.sun.portal.container.ExecuteActionResponse;
025: import com.sun.portal.container.ExecuteEventRequest;
026: import com.sun.portal.container.ExecuteEventResponse;
027: import com.sun.portal.container.GetMarkupRequest;
028: import com.sun.portal.container.GetMarkupResponse;
029: import com.sun.portal.container.GetResourceRequest;
030: import com.sun.portal.container.GetResourceResponse;
031: import com.sun.portal.container.impl.ExecuteEventRequestImpl;
032: import com.sun.portal.container.impl.ExecuteEventResponseImpl;
033: import com.sun.portal.container.impl.ExecuteActionResponseImpl;
034: import com.sun.portal.container.portlet.CacheManager;
035: import com.sun.portal.container.portlet.PortletCacheEntry;
036: import com.sun.portal.container.portlet.PreferenceManager;
037: import com.sun.portal.desktop.context.DesktopAppContext;
038: import com.sun.portal.desktop.context.DesktopAppContextThreadLocalizer;
039: import com.sun.portal.log.common.PortalLogger;
040: import com.sun.portal.portletcontainercommon.PortletActions;
041: import com.sun.portal.portletcontainercommon.PortletCacheType;
042: import com.sun.portal.portletcontainercommon.PortletContainerActionRequest;
043: import com.sun.portal.portletcontainercommon.PortletContainerActionResponse;
044: import com.sun.portal.portletcontainercommon.PortletContainerConstants;
045: import com.sun.portal.portletcontainercommon.PortletContainerErrorCode;
046: import com.sun.portal.portletcontainercommon.PortletContainerEventRequest;
047: import com.sun.portal.portletcontainercommon.PortletContainerEventResponse;
048: import com.sun.portal.portletcontainercommon.PortletContainerRenderRequest;
049: import com.sun.portal.portletcontainercommon.PortletContainerRenderResponse;
050: import com.sun.portal.portletcontainercommon.PortletContainerRequest;
051: import com.sun.portal.portletcontainercommon.PortletContainerResponse;
052: import com.sun.portal.providers.context.LocalePropertiesFilter;
053: import com.sun.portal.providers.context.ProviderContext;
054: import com.sun.portal.providers.context.ProviderContextException;
055: import com.sun.portal.providers.window.WindowProvider;
056:
057: import javax.portlet.PortletPreferences;
058: import javax.servlet.RequestDispatcher;
059: import javax.servlet.ServletContext;
060: import javax.servlet.ServletException;
061: import javax.servlet.http.HttpServletRequest;
062: import javax.servlet.http.HttpServletResponse;
063: import javax.servlet.http.HttpSession;
064: import java.io.IOException;
065: import java.util.*;
066: import java.util.logging.Level;
067: import java.util.logging.Logger;
068:
069: /**
070: * The <code>PortletContainer</code> class provides an implementation for the
071: * <code>Container</code> interface according to JSR168 specification. In
072: * this implementation, <code>PortletContainer</code> assemble the requests
073: * into <code>PortletContainerActionRequest</code> or
074: * <code>PortletContainerRenderRequest</code> and dispatch them to <code>
075: * PortletAppEngineServlet</code> for processing. The responses from <code>
076: * PortletAppEngineServlet</code> come back as
077: * <code>PortletContainerActionResponse</code> or
078: * <code>PortletContainerRenderResponse</code>.
079: * <code>PortletContainer</code> also works with the <code>
080: * CacheManager</code> to cache and retrieve contents when appropiate.
081: */
082: public class PortletContainer implements Container {
083:
084: private PreferenceManager preferenceManager;
085: private CacheManager cacheManager;
086: private ServletContext sctx;
087:
088: private boolean serializeAll;
089: // used only for non SunONE web containers to determine the validity of session
090: private String sessionInvalid;
091: private static final String SESSION_INVALID = "javax.portlet.session_invalid";
092:
093: private static ArrayList actionList;
094: private static ArrayList renderList;
095: private static ArrayList eventList;
096:
097: private static final String PAE_NAME = "/servlet/PortletAppEngineServlet";
098: private static final String DISPATCHER_STATE = "__dispatcherState__";
099: private static String HTTP_SESSION_ID = "javax.portlet.http_session_id";
100: private static final String FIRST_THREAD = "javax.portlet.pc.first_thread";
101: private static final String APPSERVER = "Sun-Java-System/Application-Server";
102: private static final String SUN = "Sun";
103: private static final String SESSION_ENABLED = "sessionEnabled";
104: private static final String TRUE = "true";
105: private static final String FALSE = "false";
106:
107: // Create a logger for this class
108: private static Logger debugLogger = PortalLogger
109: .getLogger(PortletContainer.class);
110:
111: // boolean for detecting presence of appserver ...
112: private boolean isAS = false;
113: // Appserver exec mode : serial/parallel
114: private String portletRenderModeParallel;
115:
116: static {
117: actionList = new ArrayList();
118: renderList = new ArrayList();
119: eventList = new ArrayList();
120:
121: actionList.add(PortletActions.ACTION);
122: renderList.add(PortletActions.RENDER);
123: eventList.add(PortletActions.EVENT);
124: }
125:
126: void init(ServletContext sc) {
127: preferenceManager = (PreferenceManager) sc
128: .getAttribute(PreferenceManager.PREFERENCE_MANAGER);
129: cacheManager = (CacheManager) sc
130: .getAttribute(CacheManager.CACHE_MANAGER);
131: sctx = sc;
132: // This is a work around for BEA Weblogic problem (see bug 4917439).
133: // For non-Sun ONE web container, we serialize all the portlet
134: // operations.
135: String serverInfo = sc.getServerInfo();
136:
137: if (serverInfo != null && serverInfo.indexOf(SUN) >= 0) {
138: serializeAll = false;
139: if (serverInfo.equalsIgnoreCase(APPSERVER))
140: isAS = true;
141: // not used for SunONE AS/WS to evaluate the validity of session,
142: // the value is set to true by default so that in PortletRequestImpl
143: // where it's determining session validity with ((sessionIdComparison)
144: // && sessionInValid), the first part of the expression will be the only
145: // thing used to evaluate validity.
146: sessionInvalid = TRUE;
147: } else {
148: serializeAll = true;
149: // used by non SunONE container to determine if session is still valid
150: // this value will be set to true when the portlet container's session
151: // is invalidated due to user's logout. In PortletRequestImpl when getSession
152: // is called, this value will be used to determine if the session is still
153: // valid.
154: sessionInvalid = FALSE;
155: }
156: }
157:
158: public void getMarkup(GetMarkupRequest request,
159: GetMarkupResponse response) throws ContainerException,
160: ContentException {
161: String entityID = request.getEntityID();
162: PortletContainerRenderResponse pcr = null;
163: ContentException contentException = null;
164:
165: boolean authlessUser = (request.getUserID() == null) ? true
166: : false;
167: boolean isInViewMode = (request.getChannelMode())
168: .equals(ChannelMode.VIEW);
169:
170: // Determine whether we can use the cached content.
171: // Content will be left as null if the cached content cannot be
172: // used or not available.
173: PortletCacheEntry pce = null;
174:
175: if (!authlessUser && isInViewMode) {
176: if (request.getIsTarget()) {
177: cacheManager.removeCachedPortlet(request);
178: } else {
179: pce = cacheManager.getCachedPortlet(request);
180: }
181: }
182:
183: try {
184: if (pce == null) {
185: HttpServletRequest req = request
186: .getHttpServletRequest();
187: PortletContainerErrorCode errorCode = null;
188: ProviderContext pc = getProviderContext(request);
189: String channel = PortletContainerUtility
190: .getChannelNameFromEntityID(entityID);
191: String title = null;
192: Locale locale = pc.getLocale();
193: if (locale == null)
194: locale = req.getLocale();
195: try {
196: List pflist = LocalePropertiesFilter
197: .getLocalePropertiesFilters(locale, true);
198: title = pc.getStringProperty(channel, "title",
199: pflist, true);
200: if (title != null && title.length() > 0) {
201: req.setAttribute("com.sun.portal.portlet."
202: + entityID + ".DPTITLE_EXACT", title);
203: } else {
204: title = pc.getStringProperty(channel, "title",
205: pflist, false);
206: if (title != null && title.length() > 0) {
207: req.setAttribute("com.sun.portal.portlet."
208: + entityID + ".DPTITLE_DEFAULT",
209: title);
210: }
211: }
212: } catch (ProviderContextException e) {
213: e.printStackTrace();
214: }
215: pcr = (PortletContainerRenderResponse) invokePAE(
216: PortletActions.RENDER, request, response);
217: errorCode = pcr.getErrorCode();
218:
219: if (errorCode
220: .equals(PortletContainerErrorCode.NO_ERROR)) {
221: // cache content
222: if (!authlessUser && isInViewMode) {
223: int expiration_cache = pcr.getExpiration();
224: // check if the entry needs to be cached
225: if ((expiration_cache > 0)
226: || (expiration_cache == -1)) {
227: pce = new PortletCacheEntry(
228: PortletCacheType.TYPE_EXPIRATION,
229: pcr.getMarkup(), pcr.getTitle(),
230: expiration_cache);
231: cacheManager.putCachedPortlet(request, pce);
232: }
233: }
234:
235: } else {
236: debugLogger.log(Level.SEVERE, "PSPL_PCCSPCPCI0001",
237: new Object[] { entityID, errorCode });
238:
239: // throw different subclass of ContentException.
240:
241: contentException = new ContentException(
242: "PortletContainer.getMarkup(): Exception thrown from render() of "
243: + entityID, errorCode);
244:
245: // cannot throw the exception here since it will be caught
246: // by the catch all exception block down below
247: }
248: } else {
249: response.setMarkup(pce.getCachedContent());
250: response.setTitle(pce.getTitleResource());
251: }
252: } catch (Exception e) {
253: throw new ContainerException(
254: "PortletContainer.getMarkup():getting content ", e);
255: }
256: if (contentException != null) {
257: throw contentException;
258: }
259: }
260:
261: /**
262: * Helper method to send the failure events to all the participating portlets. Failure event does not
263: * contain any data.
264: *
265: * @param request - ContainerRequest object
266: * @param response - ContainerResponse object
267: * @throws ContainerException - if an exception is caught during invokePAE
268: */
269: private void sendFailureEvent(ContainerRequest request,
270: ContainerResponse response) throws ContainerException {
271: HttpServletRequest hreq = request.getHttpServletRequest();
272: PortletContainerResponse pcres = null;
273: //Get the list of participating portlets
274: LinkedHashMap eventMap = (LinkedHashMap) hreq
275: .getAttribute(PortletContainerConstants.EVENT_MAP);
276: //Get the event-portlet mapping from IPCHelper ...
277: IPCHelper ipch = new IPCHelper();
278: LinkedHashMap regEvtMap = ipch
279: .getEventPortletMap(getProviderContext(request));
280:
281: //if the eventMap is empty or null; no need to continue ...
282: if (eventMap == null || eventMap.isEmpty())
283: return;
284:
285: //Create a new LinkedHashMap and copy all the events in it
286: LinkedHashMap events = new LinkedHashMap();
287: events.putAll(eventMap);
288: //Since request/response paradigm is used for data transfer, remove the event map from request ...
289: hreq.removeAttribute(PortletContainerConstants.EVENT_MAP);
290:
291: Set keys = events.keySet();
292: Iterator iter = keys.iterator();
293: while (iter.hasNext()) {
294: String eventName = (String) iter.next();
295: hreq.setAttribute(PortletContainerConstants.EVENT_NAME,
296: PortletContainerConstants.EVENT_HANDLING_FAILED);
297: hreq.setAttribute(PortletContainerConstants.EVENT_DATA,
298: null);
299: if (regEvtMap.containsKey(eventName)) {
300: Set portletSet = (Set) regEvtMap.get(eventName);
301: if (portletSet != null && portletSet.size() > 0) {
302: Iterator iterPortlets = portletSet.iterator();
303: while (iterPortlets.hasNext()) {
304: String portletEntityId = (String) iterPortlets
305: .next();
306: request.setEntityID(portletEntityId);
307: try {
308: pcres = (PortletContainerResponse) invokePAE(
309: PortletActions.EVENT, request,
310: response);
311: PortletContainerErrorCode errorCode = pcres
312: .getErrorCode();
313: if (!errorCode
314: .equals(PortletContainerErrorCode.NO_ERROR)) {
315: debugLogger.log(Level.SEVERE,
316: "PSPL_PCCSPCPCI0001",
317: new Object[] { portletEntityId,
318: errorCode });
319: } else {
320: //Get response and set render parameters ...
321: setRenderParameters(
322: (ExecuteEventRequestImpl) request,
323: (ExecuteEventResponseImpl) response);
324: }
325: } catch (Exception e) {
326: throw new ContainerException(
327: "PortletContainer.executeAction(): ",
328: e);
329: }//end try
330: }
331: }
332: }
333: iter.remove();
334: }//end while
335: }
336:
337: /**
338: * Main method in inter portlet communication. Used to send events to the selected set of portlets.
339: * Uses the parameters to send the information across the web app via invokePAE.
340: *
341: * @param request - ContainerRequest object
342: * @param response - ContainerResponse object
343: * @throws ContainerException - throws this exception if an exception occurs during invokePAE.
344: */
345: public void sendEvent(ContainerRequest request,
346: ContainerResponse response) throws ContainerException {
347: int gen = 0;
348: HttpServletRequest hreq = request.getHttpServletRequest();
349: cacheManager.removeCachedPortlet(request);
350: PortletContainerResponse pcres = null;
351: Object maxEventGenerationsValue = hreq
352: .getAttribute("MAX_EVENT_GENERATIONS");
353: int maxEventGenerations = -1;
354: // If there is no value in the session, do not fire any event
355: if (maxEventGenerationsValue != null)
356: maxEventGenerations = ((Integer) maxEventGenerationsValue)
357: .intValue();
358:
359: //Keep sending the events till the event queue is empty or MAX_EVENT_GENERATION is reached.
360: while (gen < maxEventGenerations) {
361: //Get the event map from HttpservletRequest ...
362: LinkedHashMap eventMap = (LinkedHashMap) hreq
363: .getAttribute(PortletContainerConstants.EVENT_MAP);
364:
365: //Get the event-portlet mapping from IPCHelper ...
366: IPCHelper ipch = new IPCHelper();
367: LinkedHashMap regEvtMap = ipch
368: .getEventPortletMap(getProviderContext(request));
369:
370: //if the eventMap is empty or null; no need to continue ...
371: if (eventMap == null || eventMap.isEmpty())
372: return;
373:
374: //Create a new LinkedHashMap and copy all the events in it
375: LinkedHashMap events = new LinkedHashMap();
376: events.putAll(eventMap);
377:
378: //Since request/response paradigm is used for data transfer, remove the event map from request ...
379: hreq.removeAttribute(PortletContainerConstants.EVENT_MAP);
380:
381: Set keys = events.keySet();
382: Iterator iter = keys.iterator();
383: while (iter.hasNext()) {
384: String eventName = (String) iter.next();
385: byte[] serializedData = (byte[]) events.get(eventName);
386: hreq.setAttribute(PortletContainerConstants.EVENT_NAME,
387: eventName);
388: hreq.setAttribute(PortletContainerConstants.EVENT_DATA,
389: serializedData);
390: if (regEvtMap.containsKey(eventName)) {
391: Set portletSet = (Set) regEvtMap.get(eventName);
392: if (portletSet != null && portletSet.size() > 0) {
393: Iterator iterPortlets = portletSet.iterator();
394: while (iterPortlets.hasNext()) {
395: String portletEntityId = (String) iterPortlets
396: .next();
397: request.setEntityID(portletEntityId);
398: try {
399: pcres = (PortletContainerResponse) invokePAE(
400: PortletActions.EVENT, request,
401: response);
402: PortletContainerErrorCode errorCode = pcres
403: .getErrorCode();
404: if (!errorCode
405: .equals(PortletContainerErrorCode.NO_ERROR)) {
406: debugLogger.log(Level.SEVERE,
407: "PSPL_PCCSPCPCI0001",
408: new Object[] {
409: portletEntityId,
410: errorCode });
411: } else {
412: //Get response and set render parameters ...
413: setRenderParameters(
414: (ExecuteEventRequestImpl) request,
415: (ExecuteEventResponseImpl) response);
416: }
417: } catch (Exception e) {
418: throw new ContainerException(
419: "PortletContainer.executeAction(): ",
420: e);
421: }//end try
422: }
423: }
424: }
425: iter.remove();
426: }//end while
427: // Increment gen only if there is events in the queue
428: if (null != hreq
429: .getAttribute(PortletContainerConstants.EVENT_MAP)) {
430: gen++;
431: }
432: }//end while for gen
433:
434: //Send failure events to all the portlets if the MAX_EVENT_GENERATION is exceeded ...
435: // Do not send any failure events if there is no MAX_EVENT_GENERATION
436: if (maxEventGenerationsValue != null
437: && gen >= maxEventGenerations) {
438: sendFailureEvent(request, response);
439: }
440: }//end method
441:
442: private void setRenderParameters(ExecuteEventRequest request,
443: ExecuteEventResponse cres) {
444: Map renderParms = (Map) ((ExecuteEventResponseImpl) cres)
445: .getRenderParameters();
446: boolean authless = getProviderContext(request).isAuthless(
447: request.getHttpServletRequest());
448: if (authless) {
449: if (renderParms != null) {
450: String parm = (String) getProviderContext(request)
451: .getClientProperty(
452: WindowProvider.RENDER_PARAM_PREFIX
453: + request.getEntityID());
454: if (parm != null && parm.length() > 0) {
455: Map parmMap = IPCHelper.getMapFromString(parm);
456: if (parmMap != null && !parmMap.isEmpty()) {
457: parmMap.putAll(renderParms);
458: getProviderContext(request).setClientProperty(
459: WindowProvider.RENDER_PARAM_PREFIX
460: + request.getEntityID(),
461: IPCHelper.getStringFromMap(parmMap));
462: }
463: } else {
464: getProviderContext(request).setClientProperty(
465: WindowProvider.RENDER_PARAM_PREFIX
466: + request.getEntityID(),
467: IPCHelper.getStringFromMap(renderParms));
468: }
469: }
470: } else {
471: if (renderParms != null) {
472: Map parmMap = (Map) getProviderContext(request)
473: .getSessionProperty(
474: WindowProvider.RENDER_PARAM_PREFIX
475: + request.getEntityID());
476: if (parmMap != null && !parmMap.isEmpty()) {
477: parmMap.putAll(renderParms);
478: getProviderContext(request).setSessionProperty(
479: WindowProvider.RENDER_PARAM_PREFIX
480: + request.getEntityID(), parmMap);
481: } else {
482: getProviderContext(request).setSessionProperty(
483: WindowProvider.RENDER_PARAM_PREFIX
484: + request.getEntityID(),
485: renderParms);
486: }
487: }
488: }
489: }
490:
491: private Map getRenderParameters(ContainerRequest request) {
492: Map renderParms = null;
493: boolean authless = getProviderContext(request).isAuthless(
494: request.getHttpServletRequest());
495: if (authless) {
496: String parm = (String) getProviderContext(request)
497: .getClientProperty(
498: WindowProvider.RENDER_PARAM_PREFIX
499: + request.getEntityID());
500: if (parm != null)
501: renderParms = IPCHelper.getMapFromString(parm);
502: } else {
503: Object parm = getProviderContext(request)
504: .getSessionProperty(
505: WindowProvider.RENDER_PARAM_PREFIX
506: + request.getEntityID());
507: if (parm != null) {
508: if (parm instanceof Map) {
509: return (Map) parm;
510: }
511: if (parm instanceof String) {
512: renderParms = IPCHelper
513: .getMapFromString((String) parm);
514: }
515: }
516: }
517: return renderParms;
518: }
519:
520: public void executeAction(ExecuteActionRequest request,
521: ExecuteActionResponse response) throws ContainerException,
522: ContentException {
523:
524: String entityID = request.getEntityID();
525: PortletContainerActionResponse pcres = null;
526: ContentException contentException = null;
527:
528: // clear out the cache
529: cacheManager.removeCachedPortlet(request);
530:
531: try {
532: pcres = (PortletContainerActionResponse) invokePAE(
533: PortletActions.ACTION, request, response);
534: PortletContainerErrorCode errorCode = pcres.getErrorCode();
535: if (!errorCode.equals(PortletContainerErrorCode.NO_ERROR)) {
536: debugLogger.log(Level.SEVERE, "PSPL_PCCSPCPCI0001",
537: new Object[] { entityID, errorCode });
538:
539: // throw different subclass of ContentException
540: contentException = new ContentException(
541: "PortletContainer.executeAction(): Exception thrown from processAction() of "
542: + entityID, errorCode);
543:
544: // cannot throw the exception here since it will be caught
545: // by the catch all exception block down below
546:
547: }
548: //Now check if an event is fired ...
549: LinkedHashMap eventMap = (LinkedHashMap) (request
550: .getHttpServletRequest())
551: .getAttribute(PortletContainerConstants.EVENT_MAP);
552:
553: if (eventMap != null && eventMap.isEmpty() == false) {
554: ExecuteEventRequest eereq = (ExecuteEventRequest) getEventRequest(request);
555: ExecuteEventResponse eeres = (ExecuteEventResponse) getEventResponse(response);
556: sendEvent(eereq, eeres);
557: Map renderParams = getRenderParameters(request); // This map might also contain the Render Parameters set by EventResponse
558: if (renderParams != null) {
559: Map existingRenderParams = ((ExecuteActionResponseImpl) response)
560: .getRenderParameters();
561: // Merge the Render Parameters set by Event Response and those set by RenderResponse into
562: // a modifiable Map. This is because the next time during eventing the map gets modified.
563: // Merging might throw exception if the Render Parameter Map is unmodifiable. If exception
564: // is thrown, convert it into a modifiable map and merge the parameters.
565: try {
566: renderParams.putAll(existingRenderParams);
567: response.setRenderParameters(renderParams);
568: } catch (UnsupportedOperationException uoe) {
569: Map modifiableRenderParams = new HashMap(
570: renderParams);
571: modifiableRenderParams
572: .putAll(existingRenderParams);
573: response
574: .setRenderParameters(modifiableRenderParams);
575: }
576: }
577: }
578: } catch (Exception e) {
579: throw new ContainerException(
580: "PortletContainer.executeAction(): ", e);
581: }
582: if (contentException != null) {
583: throw contentException;
584: }
585: }
586:
587: public void getResources(GetResourceRequest request,
588: GetResourceResponse response) throws ContainerException {
589:
590: String entityID = request.getEntityID();
591: String appName = PortletContainerUtility
592: .getAppNameFromEntityID(entityID);
593: String portletName = PortletContainerUtility
594: .getPortletNameFromEntityID(entityID);
595: //Get the ServletContext for the Portlet Web Application.
596: ServletContext context = sctx.getContext(appName);
597: try {
598: //Get the Resources map for the portlet web application.
599: //This is constructed and set as an attribute of servlet context, during the
600: //init of the PAEServlet, of the portlet web application.
601: //if called before the init, resource not be available and will return 'null'.
602: HttpServletRequest req = request.getHttpServletRequest();
603: Locale locale = getProviderContext(request).getLocale();
604: if (locale == null)
605: locale = request.getLocale();
606: Map resources = (Map) context
607: .getAttribute(PortletContainerConstants.PORTLET_RESOURCES);
608: ResourceBundle bundle = getResourceBundle(resources,
609: portletName, locale);
610: response.setResource(bundle);
611: } catch (Exception e) {
612: throw new ContainerException(
613: "PortletContainer.getResources(): ", e);
614: }
615: }
616:
617: protected PortletContainerResponse invokePAE(String action,
618: ContainerRequest request, ContainerResponse response)
619: throws IOException, ServletException {
620:
621: HttpServletRequest req = request.getHttpServletRequest();
622: HttpServletResponse res = response.getHttpServletResponse();
623: String entityID = request.getEntityID();
624:
625: String appName = PortletContainerUtility
626: .getAppNameFromEntityID(entityID);
627: String portletName = PortletContainerUtility
628: .getPortletNameFromEntityID(entityID);
629:
630: if (debugLogger.isLoggable(Level.INFO)) {
631: StringBuffer sb = new StringBuffer(
632: "PortletContainer.invokePAE(): invoking:\n");
633: sb.append("app name ");
634: sb.append(appName);
635: sb.append("\nportlet name ");
636: sb.append(portletName);
637: sb.append("\naction ");
638: sb.append(action);
639: debugLogger.log(Level.INFO, "PSPL_PCCSPCPCI0002", sb
640: .toString());
641: }
642:
643: PortletPreferences pp = preferenceManager
644: .getPortletPreferences(request);
645:
646: PortletContainerRequest pcreq = null;
647: PortletContainerResponse pcres = null;
648:
649: if (action.equals(PortletActions.RENDER)) {
650: pcreq = new PortletContainerRenderRequest(
651: (GetMarkupRequest) request);
652: pcres = new PortletContainerRenderResponse(
653: (GetMarkupResponse) response);
654: pcreq.setActions(renderList);
655: } else if (action.equals(PortletActions.ACTION)) {
656: pcreq = new PortletContainerActionRequest(
657: (ExecuteActionRequest) request);
658: pcres = new PortletContainerActionResponse(
659: (ExecuteActionResponse) response);
660: pcreq.setActions(actionList);
661: } else if (action.equals(PortletActions.EVENT)) {
662: pcreq = new PortletContainerEventRequest(
663: (ExecuteEventRequest) request);
664: pcres = new PortletContainerEventResponse(
665: (ExecuteEventResponse) response);
666: pcreq.setActions(eventList);
667: }
668:
669: ProviderContext pc = getProviderContext(request);
670:
671: SSOToken token = (SSOToken) req
672: .getAttribute(PortletContainerConstants.SSO_TOKEN);
673: pcreq.setSSOToken(token);
674: pcreq.setResponseContentType(pc.getContentType());
675:
676: // put pp, ui, actions and attributes to pcreq
677: pcreq.setPortletPreferences(pp);
678: pcreq.setPortletName(portletName);
679: pcreq.setLocale(pc.getLocale());
680:
681: PAERequestWrapper reqWrapper = new PAERequestWrapper(req);
682: reqWrapper.setAttribute(
683: PortletContainerRequest.PORTLET_CONTAINER_REQUEST,
684: pcreq);
685: reqWrapper.setAttribute(
686: PortletContainerResponse.PORTLET_CONTAINER_RESPONSE,
687: pcres);
688:
689: DispatcherState ds = null;
690: boolean sessionEnabled = true;
691: String channel = PortletContainerUtility
692: .getChannelNameFromEntityID(entityID);
693: if (isAS) {
694: if (portletRenderModeParallel == null) {
695: DesktopAppContext desktopAppContext = DesktopAppContextThreadLocalizer
696: .get();
697: portletRenderModeParallel = desktopAppContext
698: .getPortletRenderModeParallel().trim();
699: if (FALSE.equalsIgnoreCase(portletRenderModeParallel)) {
700: serializeAll = true;
701: } else if (TRUE
702: .equalsIgnoreCase(portletRenderModeParallel)) {
703: serializeAll = false;
704: }
705: }
706: }
707:
708: try {
709: sessionEnabled = pc.getBooleanProperty(channel,
710: SESSION_ENABLED);
711: //Even if the session is enabled we still want to do parallel processing for Appserver
712: if ((isAS == true) && (serializeAll == false))
713: sessionEnabled = false;
714: } catch (ProviderContextException pce) {
715: // assume sessionEnabled is true and continue.
716: }
717:
718: boolean authlessUser = (request.getUserID() == null) ? true
719: : false;
720:
721: // It has been verified that executing the portlets of portal
722: // page in a parallel fashion (sharing the same request
723: // object) would result in a session messup problem if those
724: // portlets are in different portlet applications and use
725: // session. This is true even though we sync all the
726: // sessionEnabled portlet requests and only allow parallel
727: // processing on those sessless portlets.
728: //
729: // Although the servlet sepc still does not allow concurrent
730: // threads sharing the same request object, with the
731: // implementation below, it is ok to have portlet requests
732: // of mixed sessionEnabled portlets and sessionless portlets
733: // to be processed in a semi-parallel manner (logic in
734: // DispatcherState class) if THOSE POSTLETS ARE PACKAGED
735: // IN THE SAME PORTLET APPLICATION.
736:
737: while (true) {
738: synchronized (req) {
739: ds = (DispatcherState) req
740: .getAttribute(DISPATCHER_STATE);
741: if (ds == null) {
742: ds = new DispatcherState();
743: req.setAttribute(DISPATCHER_STATE, ds);
744: }
745:
746: if (!ds.canEnter(appName, sessionEnabled, serializeAll)) {
747: try {
748: req.wait();
749: } catch (InterruptedException e) {
750: // counter already incremented by caller
751: }
752: } else {
753: handleSession(request, authlessUser);
754: reqWrapper.setAttribute(HTTP_SESSION_ID,
755: getSessionId(pc, authlessUser));
756: break;
757: }
758: }
759: }
760:
761: ServletContext context = sctx.getContext(appName);
762: RequestDispatcher rd = context.getRequestDispatcher(PAE_NAME);
763: PAEResponseWrapper resWrapper = new PAEResponseWrapper(res);
764: rd.include(reqWrapper, resWrapper);
765:
766: synchronized (req) {
767: if (ds.exit()) {
768: req.notifyAll();
769: }
770: }
771: return pcres;
772: }
773:
774: private void handleSession(ContainerRequest request,
775: boolean authlessUser) {
776:
777: HttpServletRequest req = request.getHttpServletRequest();
778: req.setAttribute(SESSION_INVALID, sessionInvalid);
779:
780: ProviderContext pc = getProviderContext(request);
781:
782: HttpSession hs = null;
783:
784: if (!isSessionIdExist(pc, authlessUser)) {
785: hs = req.getSession(false);
786: if (hs != null) {
787: // session INVALID,
788: //probably due to new user login
789: hs.invalidate();
790: req.setAttribute(SESSION_INVALID, TRUE);
791: }
792: }
793:
794: // In the situation that:
795: // a)the sessionID has been set in ProviderContext
796: // during the processing of the previous "client
797: // request" (browser driven action), and
798: // b)the current thread is the first one of those
799: // threads with this "client request",
800: // the code needs to make sure the HttpSession object
801: // is being created appropriately in the Portal Server
802: // web application (A typical example of this scenario
803: // is the desktop reload).
804: //
805: // This is basically a workaround which deals with the
806: // situation that the session cookie was not
807: // appropriately set due to the unpredictable context
808: // switching in processing the previous client request.
809:
810: if (req.getAttribute(FIRST_THREAD) == null) {
811: hs = req.getSession(true);
812: setSessionId(pc, authlessUser, hs.getId());
813: req.setAttribute(FIRST_THREAD, Boolean.TRUE);
814: } else {
815: hs = req.getSession(false);
816: }
817: }
818:
819: private boolean isSessionIdExist(ProviderContext pc,
820: boolean authlessUser) {
821: boolean retValue;
822: retValue = (pc.getClientProperty(HTTP_SESSION_ID) == null) ? false
823: : true;
824: return retValue;
825: }
826:
827: private void setSessionId(ProviderContext pc, boolean authlessUser,
828: String sessionID) {
829: pc.setClientProperty(HTTP_SESSION_ID, sessionID);
830: }
831:
832: private String getSessionId(ProviderContext pc, boolean authlessUser) {
833: return pc.getClientProperty(HTTP_SESSION_ID);
834: }
835:
836: protected ProviderContext getProviderContext(
837: ContainerRequest request) {
838: HttpServletRequest req = request.getHttpServletRequest();
839:
840: return (ProviderContext) req
841: .getAttribute(PortletContainerConstants.PROVIDER_CONTEXT);
842: }
843:
844: private ResourceBundle getResourceBundle(Map resourceMap,
845: String portlet, Locale locale) {
846: ResourceBundle retval = null;
847: if (resourceMap != null && portlet != null) {
848: if (locale == null) {
849: locale = Locale.getDefault();
850: }
851: Map resBundleMap = (Map) resourceMap.get(portlet);
852: if (resBundleMap != null) {
853: retval = (ResourceBundle) resBundleMap.get(locale
854: .toString());
855: }
856: }
857: return retval;
858: }
859:
860: private ContainerRequest getEventRequest(ContainerRequest creq) {
861: HttpServletRequest req = creq.getHttpServletRequest();
862: ExecuteEventRequestImpl eer = new ExecuteEventRequestImpl();
863: eer.setHttpServletRequest(req);
864:
865: //Set allowable content types ...
866: ProviderContext pc = (ProviderContext) req
867: .getAttribute(PortletContainerConstants.PROVIDER_CONTEXT);
868: String contentType = pc.getContentType();
869: List allowableContentTypes = new ArrayList();
870: allowableContentTypes.add(contentType);
871: eer.setAllowableContentType(allowableContentTypes);
872:
873: //Set user id ...
874: String userID = null;
875: if (!pc.isAuthless(req)) {
876: userID = pc.getUserID();
877: }
878: eer.setUserID(userID);
879: eer.setChannelMode(creq.getChannelMode());
880: eer.setWindowState(creq.getWindowState());
881:
882: eer.setChannelURLFactory(creq.getChannelURLFactory());
883: eer.setAllowableWindowState(creq.getAllowableWindowState());
884: eer.setAllowableChannelMode(creq.getAllowableChannelMode());
885:
886: eer.setChannelURLFactory(creq.getChannelURLFactory());
887: eer.setRoles(creq.getRoles());
888: eer.setUserInfo(creq.getUserInfo());
889:
890: return eer;
891: }
892:
893: private ContainerResponse getEventResponse(ContainerResponse cres) {
894: ExecuteEventResponseImpl eeri = new ExecuteEventResponseImpl();
895: eeri.setHttpServletResponse(cres.getHttpServletResponse());
896: return eeri;
897: }
898: }
|