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: package com.sun.portal.portletappengine;
014:
015: import com.sun.portal.log.common.PortalLogger;
016: import com.sun.portal.portlet.impl.PortletsResources;
017: import com.sun.portal.portletappengine.impl.LifecycleManagerImpl;
018: import com.sun.portal.portletappengine.impl.RequestResponseFactoryImpl;
019: import com.sun.portal.portletappengine.ipc.EventRequest;
020: import com.sun.portal.portletappengine.ipc.EventResponse;
021: import com.sun.portal.portletappengine.ipc.PortletEventListener;
022: import com.sun.portal.portletappengine.ubt.PortletEvents;
023: import com.sun.portal.portletappengine.ubt.PortletLogRecord;
024: import com.sun.portal.portletcontainercommon.PortletActions;
025: import com.sun.portal.portletcontainercommon.PortletContainerActionRequest;
026: import com.sun.portal.portletcontainercommon.PortletContainerActionResponse;
027: import com.sun.portal.portletcontainercommon.PortletContainerConstants;
028: import com.sun.portal.portletcontainercommon.PortletContainerErrorCode;
029: import com.sun.portal.portletcontainercommon.PortletContainerEventRequest;
030: import com.sun.portal.portletcontainercommon.PortletContainerEventResponse;
031: import com.sun.portal.portletcontainercommon.PortletContainerRenderRequest;
032: import com.sun.portal.portletcontainercommon.PortletContainerRenderResponse;
033: import com.sun.portal.portletcontainercommon.PortletContainerRequest;
034: import com.sun.portal.portletcontainercommon.PortletContainerResponse;
035: import com.sun.portal.portletcontainercommon.PreferencesValidatorSetter;
036: import com.sun.portal.portletcontainercommon.descriptor.PortletAppDescriptor;
037: import com.sun.portal.portletcontainercommon.descriptor.PortletDescriptor;
038: import com.sun.portal.portletcontainercommon.descriptor.SecurityConstraintDescriptor;
039: import com.sun.portal.ubt.UBTEvent;
040: import com.sun.portal.ubt.UBTLogManager;
041:
042: import javax.portlet.ActionRequest;
043: import javax.portlet.ActionResponse;
044: import javax.portlet.Portlet;
045: import javax.portlet.PortletException;
046: import javax.portlet.PortletMode;
047: import javax.portlet.PortletModeException;
048: import javax.portlet.PortletRequest;
049: import javax.portlet.PortletSecurityException;
050: import javax.portlet.PreferencesValidator;
051: import javax.portlet.ReadOnlyException;
052: import javax.portlet.RenderRequest;
053: import javax.portlet.RenderResponse;
054: import javax.portlet.UnavailableException;
055: import javax.portlet.WindowStateException;
056: import javax.servlet.ServletConfig;
057: import javax.servlet.ServletContext;
058: import javax.servlet.ServletException;
059: import javax.servlet.http.HttpServlet;
060: import javax.servlet.http.HttpServletRequest;
061: import javax.servlet.http.HttpServletResponse;
062: import java.io.ByteArrayOutputStream;
063: import java.io.IOException;
064: import java.io.StringWriter;
065: import java.util.Iterator;
066: import java.util.LinkedHashMap;
067: import java.util.List;
068: import java.util.Set;
069: import java.util.Locale;
070: import java.util.ResourceBundle;
071: import java.util.logging.Level;
072:
073: /**
074: * The portlet app engine servlet is the entry point of the portlet
075: * application engine.
076: * <p/>
077: * The portlet app engine receives requests from
078: * the portlet container through the Request Dispatcher, and then
079: * deligates the work to the following components:
080: * <UL>
081: * <LI> Lifecycycle manager: which allow create and retrieve
082: * portlet instances
083: * <LI> Request/response factory: generates portlet
084: * request/response objects
085: * <LI> Security manager: check for portlet access rights
086: * </UL>
087: * Once retrieves the target portlet, the portlet app engine servlet will
088: * executes the actions and sets the result in the response and return
089: * back to portlet container.
090: */
091: public class PortletAppEngineServlet extends HttpServlet {
092:
093: public static final String CONFIDENTIAL = "CONFIDENTIAL";
094: public static final String INTEGRAL = "INTEGRAL";
095:
096: public static final String JAVAX_PORTLET_ENTITY_ID = "javax.portlet.entityID";
097: public static final String JAVAX_PORTLET_TITLE = "javax.portlet.title";
098: public static final String JAVAX_PORTLET_LOCALE = "javax.portlet.locale";
099: private static final char DELIMETER = '|';
100:
101: // Global variables
102: private LifecycleManager lifecycleManager;
103: private RequestResponseFactory requestResponseFactory;
104: private static java.util.logging.Logger logger = PortalLogger
105: .getLogger(PortletAppEngineServlet.class);
106: private PortletAppDescriptor descriptor;
107: private ServletContext context;
108: private ServletConfig config = null;
109:
110: /*
111: * Initializes global variables.
112: * <P>
113: * @param config The <code>ServletConfig</code> object
114: */
115: public void init(ServletConfig config) throws ServletException {
116: super .init(config);
117: this .config = config;
118: context = config.getServletContext();
119: lifecycleManager = new LifecycleManagerImpl(context);
120: context.setAttribute(LifecycleManager.LIFECYCLE_MANAGER_PREFIX,
121: lifecycleManager);
122:
123: requestResponseFactory = new RequestResponseFactoryImpl(context);
124: context.setAttribute(
125: RequestResponseFactory.REQUEST_RESPONSE_FACTORY_PREFIX,
126: requestResponseFactory);
127:
128: descriptor = lifecycleManager.getDeploymentDescriptor();
129: PortletsResources pr = new PortletsResources(descriptor);
130: context.setAttribute(
131: PortletContainerConstants.PORTLET_RESOURCES, pr
132: .getPortletResourceMap());
133: //Following is added to fix CR 5048488
134: context.setAttribute(
135: PortletContainerConstants.PORTLET_METADATA_RESOURCES,
136: pr.getPortletMetadataResourceMap());
137: context.setAttribute(
138: PortletContainerConstants.GENERATE_EVENT_LIST,
139: ((LifecycleManagerImpl) lifecycleManager)
140: .getGeneratedEvents());
141: context.setAttribute(
142: PortletContainerConstants.CONSUME_EVENT_LIST,
143: ((LifecycleManagerImpl) lifecycleManager)
144: .getConsumeEvents());
145: }
146:
147: private String getTitle(HttpServletRequest req) {
148: String title = null;
149: String entityID = (String) req
150: .getAttribute(JAVAX_PORTLET_ENTITY_ID);
151: Locale locale = (Locale) req.getAttribute(JAVAX_PORTLET_LOCALE);
152: String portletName = entityID.substring(entityID
153: .indexOf(DELIMETER) + 1, entityID
154: .lastIndexOf(DELIMETER));
155: PortletDescriptor pd = getPortletDescriptor(portletName);
156: String rbName = pd.getResourceBundle();
157: title = getTitleFromRB(locale, rbName);
158: if (title != null && title.length() > 0)
159: req.setAttribute(JAVAX_PORTLET_TITLE, title);
160: else
161: req.removeAttribute(JAVAX_PORTLET_TITLE);
162: return title;
163: }
164:
165: private String getTitleFromPortletDescriptor(String portletName) {
166: PortletDescriptor pd = getPortletDescriptor(portletName);
167: String title = pd.getPortletInfoDescriptor().getTitle();
168: return title;
169: }
170:
171: private String getTitleFromRB(Locale locale, String rbName) {
172: String title = null;
173: if (rbName != null && rbName.length() > 0) {
174: ResourceBundle rb = null;
175: try {
176: rb = ResourceBundle.getBundle(rbName, locale, Thread
177: .currentThread().getContextClassLoader());
178: if (rb != null)
179: title = (String) rb.getString(JAVAX_PORTLET_TITLE);
180: } catch (Exception e) {
181: logger.log(Level.INFO, "PSPL_PAECSPPA0006", e);
182: }
183: }
184: return title;
185: }
186:
187: /**
188: * This mehtod is the meat of the servlet, which basically handles
189: * the request for executing a portlet.
190: * <p/>
191: * This method will do the following tasks:
192: * <UL>
193: * <LI>Obtains portlet request/response objects from
194: * request/response factory
195: * <LI>Checks for security violation, if any
196: * <LI>Obtains the target portlet object from the lifecycle
197: * manager
198: * <LI>Obtains the action list that is passed from the request
199: * <LI>Calls cooresponding portlet methods
200: * <LI>Sets cooresponding results in the response
201: * <LI>Handles exceptions
202: * <p/>
203: *
204: * @param req The <code>HttpServletRequest</code>
205: * @param res The <code>HttpServletResponse</code>
206: */
207: public void service(HttpServletRequest req, HttpServletResponse res)
208: throws IOException, ServletException {
209: if (JAVAX_PORTLET_TITLE.equals((String) req
210: .getAttribute(JAVAX_PORTLET_TITLE))) {
211: getTitle(req);
212: return;
213: }
214: StringWriter writer = new StringWriter(
215: PortletAppEngineConstants.INITIAL_BUFFER_SIZE);
216: ByteArrayOutputStream output = new ByteArrayOutputStream(
217: PortletAppEngineConstants.INITIAL_BUFFER_SIZE);
218: ActionRequest aReq = null;
219: RenderRequest rReq = null;
220: ActionResponse aRes = null;
221: RenderResponse rRes = null;
222: EventRequest eventRequest = null;
223: EventResponse eventResponse = null;
224: /*************************************************
225: * Setup local variables.
226: *************************************************/
227: PortletContainerRequest pContReq = (PortletContainerRequest) req
228: .getAttribute(PortletContainerRequest.PORTLET_CONTAINER_REQUEST);
229: PortletContainerResponse pContRes = (PortletContainerResponse) req
230: .getAttribute(PortletContainerResponse.PORTLET_CONTAINER_RESPONSE);
231: String portletName = pContReq.getPortletName();
232: PortletMode portletMode = PortletAppEngineUtils
233: .getPortletMode(pContReq.getChannelMode());
234: List actionList = pContReq.getActions();
235: String entityID = pContReq.getEntityID();
236: if (logger.isLoggable(Level.FINEST)) {
237: StringBuffer buf = new StringBuffer();
238: buf.append("context path=").append(req.getContextPath())
239: .append("///");
240: buf.append("entityID=").append(entityID).append("///");
241: buf.append("portletName=").append(portletName)
242: .append("///");
243: buf.append("portletMode=").append(portletMode)
244: .append("///");
245: buf.append("windowState=")
246: .append(pContReq.getWindowState()).append("///");
247: buf.append("actionList=");
248: for (int j = 0; j < actionList.size(); j++) {
249: buf.append((String) actionList.get(j)).append(" | ");
250: }
251: buf.append("///");
252: logger.log(Level.FINEST, "PSPL_PAECSPPA0001", buf
253: .toString());
254: }
255: /*************************************************
256: * Check security constraint
257: *************************************************/
258: if (checkSecurityConstraint(req, portletName)) {
259: /*************************************************
260: * Start processing actions.
261: *************************************************/
262: PortletDescriptor portletDescriptor = getPortletDescriptor(portletName);
263: PreferencesValidator validator = lifecycleManager
264: .getPreferencesValidator(portletName);
265: Portlet p = null;
266: try {
267: // gets the portlet
268: p = lifecycleManager.getPortlet(portletName);
269: // sets portlet config in request attribute
270: req.setAttribute(
271: PortletAppEngineConstants.PORTLET_CONFIG,
272: lifecycleManager.getPortletConfig(portletName));
273: logger.log(Level.FINEST, "PSPL_PAECSPPA0002",
274: portletName);
275: boolean stop = false;
276: // calls portlet actions
277: for (int i = 0; i < actionList.size() && !stop; i++) {
278: String action = (String) actionList.get(i);
279: req.setAttribute(
280: PortletAppEngineConstants.CURRENT_ACTION,
281: action);
282: if (action.equals(PortletActions.ACTION)) {
283: PortletContainerActionRequest pContActionReq = (PortletContainerActionRequest) pContReq;
284: PortletContainerActionResponse pContActionRes = (PortletContainerActionResponse) pContRes;
285: aReq = requestResponseFactory.getActionRequest(
286: req, res, pContActionReq,
287: pContActionRes, lifecycleManager
288: .getPortletContext(),
289: lifecycleManager.getPortalContext(),
290: portletDescriptor, writer);
291: aRes = requestResponseFactory
292: .getActionResponse(req, res, aReq,
293: pContActionReq, pContActionRes);
294: setValidator(aReq, validator, false);
295: p.processAction(aReq, aRes);
296: if (pContActionRes.getRedirectURL() != null) {
297: stop = true;
298: }
299: // unset validator
300: setValidator(aReq, validator, true);
301: //UBT code start
302: try {
303: UBTLogManager manager = UBTLogManager
304: .getInstance();
305: if (manager.isUBTEnabled()) {
306: UBTEvent port_act = UBTEvent
307: .getInstance(PortletEvents.PORTLET_ACTION);
308: manager.logEvent(new PortletLogRecord(
309: port_act, req, res, pContReq,
310: pContRes));
311: }
312: } catch (Exception e) {
313: //UBT exception
314: }
315: //UBT code -- end
316: LinkedHashMap evts = (LinkedHashMap) aReq
317: .getAttribute(PortletContainerConstants.FIRED_EVENTS);
318: if (evts != null && evts.size() > 0) {
319: req
320: .setAttribute(
321: PortletContainerConstants.EVENT_MAP,
322: evts);
323: }
324: } else if (action.equals(PortletActions.EVENT)) {
325: PortletContainerEventRequest pceRequest = (PortletContainerEventRequest) pContReq;
326: PortletContainerEventResponse pceResponse = (PortletContainerEventResponse) pContRes;
327: eventRequest = requestResponseFactory
328: .getEventRequest(req, res, pceRequest,
329: pceResponse, lifecycleManager
330: .getPortletContext(),
331: lifecycleManager
332: .getPortalContext(),
333: portletDescriptor);
334: eventResponse = requestResponseFactory
335: .getEventResponse(pceResponse);
336: PortletEventListener pel = null;
337: if (p instanceof PortletEventListener) {
338: pel = (PortletEventListener) p;
339: pel
340: .handleEvent(eventRequest,
341: eventResponse);
342: //If new events are fired, then set them on the request
343: LinkedHashMap evts = (LinkedHashMap) eventRequest
344: .getAttribute(PortletContainerConstants.FIRED_EVENTS);
345: if (evts != null && evts.size() > 0) {
346: LinkedHashMap oldEvts = (LinkedHashMap) req
347: .getAttribute(PortletContainerConstants.EVENT_MAP);
348: if (oldEvts != null
349: && !oldEvts.isEmpty()) {
350: Set keys = evts.keySet();
351: Iterator it = keys.iterator();
352: while (it.hasNext()) {
353: String eventName = (String) it
354: .next();
355: ByteArrayOutputStream baos = (ByteArrayOutputStream) evts
356: .get(eventName);
357: oldEvts.put(eventName, baos);
358: }
359: req
360: .setAttribute(
361: PortletContainerConstants.EVENT_MAP,
362: oldEvts);
363: } else {
364: req
365: .setAttribute(
366: PortletContainerConstants.EVENT_MAP,
367: evts);
368: }
369: }
370: }
371: requestResponseFactory
372: .releaseEventRequest(eventRequest);
373: requestResponseFactory
374: .releaseEventResponse(eventResponse);
375: } else if (action.equals(PortletActions.RENDER)) {
376: PortletContainerRenderRequest pContRenderReq = (PortletContainerRenderRequest) pContReq;
377: PortletContainerRenderResponse pContRenderRes = (PortletContainerRenderResponse) pContRes;
378: setCacheParams(pContRenderRes,
379: portletDescriptor);
380: rReq = requestResponseFactory.getRenderRequest(
381: req, res, pContRenderReq,
382: pContRenderRes, lifecycleManager
383: .getPortletContext(),
384: lifecycleManager.getPortalContext(),
385: portletDescriptor);
386: rRes = requestResponseFactory
387: .getRenderResponse(req, res, rReq,
388: pContRenderReq, pContRenderRes,
389: writer, output,
390: portletDescriptor);
391: setValidator(rReq, validator, false);
392: //Obtain the title from request and set it on PortletRenderRequest
393: String title = (String) req
394: .getAttribute("com.sun.portal.portlet."
395: + entityID + ".DPTITLE_EXACT");
396: String dpDefaultTitle = null;
397: if (title == null || title.length() == 0) {
398: // The DPTITLE_DEFAULT can be either the title from portlet.xml or DP customized for default locale
399: // If it is customized for default locale, use it
400: dpDefaultTitle = (String) req
401: .getAttribute("com.sun.portal.portlet."
402: + entityID
403: + ".DPTITLE_DEFAULT");
404: String portletDescriptorTitle = getTitleFromPortletDescriptor(portletName);
405: if (dpDefaultTitle != null
406: && !dpDefaultTitle
407: .equals(portletDescriptorTitle)) {
408: title = dpDefaultTitle;
409: }
410: }
411: if (title == null || title.length() == 0) {
412: PortletDescriptor pd = getPortletDescriptor(portletName);
413: String rbName = pd.getResourceBundle();
414: Locale locale = pContRenderReq.getLocale();
415: title = getTitleFromRB(locale, rbName);
416: }
417: if (title == null || title.length() == 0) {
418: title = dpDefaultTitle;
419: }
420: rReq
421: .setAttribute(
422: "com.sun.portal.portlet.DPTITLE",
423: title);
424: p.render(rReq, rRes);
425: // sets values in portlet container response
426: // the output is either in the writer or in the
427: // output stream
428: StringBuffer buff = writer.getBuffer();
429: String outString = output.toString(res
430: .getCharacterEncoding());
431: if (buff.length() > 0) {
432: pContRenderRes
433: .setMarkup(writer.getBuffer());
434: } else if (outString.length() > 0) {
435: pContRenderRes.setMarkup(new StringBuffer(
436: outString));
437: } else {
438: pContRenderRes.setMarkup(new StringBuffer(
439: ""));
440: }
441: setValidator(rReq, validator, true);
442: //UBT code -- start
443: try {
444: UBTLogManager manager = UBTLogManager
445: .getInstance();
446: if (manager.isUBTEnabled()) {
447: UBTEvent port_ren = UBTEvent
448: .getInstance(PortletEvents.PORLET_RENDER);
449: manager.logEvent(new PortletLogRecord(
450: port_ren, req, res, pContReq,
451: pContRes));
452: }
453: } catch (Exception e) {
454: //UBT exception
455: }
456: //UBT code -- end
457: }
458: }
459: } catch (UnavailableException ue) {
460: if (p != null) {
461: p.destroy();
462: lifecycleManager.removePortlet(portletName);
463: lifecycleManager.removePortletConfig(portletName);
464: }
465: pContRes
466: .setErrorCode(PortletContainerErrorCode.PORTLET_UNAVAILABLE);
467: logger.log(Level.WARNING, "PSPL_PAECSPPA0004", ue);
468: } catch (PortletSecurityException se) {
469: pContRes
470: .setErrorCode(PortletContainerErrorCode.SECURITY_VIOLATION);
471: logger.log(Level.WARNING, "PSPL_PAECSPPA0004", se);
472: } catch (PortletException pe) {
473: Throwable cause = pe.getCause();
474: if (pe instanceof PortletModeException
475: || cause instanceof PortletModeException) {
476:
477: pContRes
478: .setErrorCode(PortletContainerErrorCode.UNSUPPORTED_MODE);
479: } else if (pe instanceof ReadOnlyException
480: || cause instanceof ReadOnlyException) {
481:
482: pContRes
483: .setErrorCode(PortletContainerErrorCode.READONLY_ERROR);
484: } else if (pe instanceof WindowStateException
485: || cause instanceof WindowStateException) {
486:
487: pContRes
488: .setErrorCode(PortletContainerErrorCode.UNSUPPORTED_STATE);
489: } else {
490: pContRes
491: .setErrorCode(PortletContainerErrorCode.MISC_ERROR);
492: }
493: logger.log(Level.WARNING, "PSPL_PAECSPPA0004", pe);
494: } catch (IOException ie) {
495: pContRes
496: .setErrorCode(PortletContainerErrorCode.MISC_ERROR);
497: logger.log(Level.WARNING, "PSPL_PAECSPPA0004", ie);
498: } catch (RuntimeException re) {
499: pContRes
500: .setErrorCode(PortletContainerErrorCode.MISC_ERROR);
501: logger.log(Level.WARNING, "PSPL_PAECSPPA0004", re);
502: }
503: /*************************************************
504: * Releases objects.
505: *************************************************/
506: if (aReq != null) {
507: requestResponseFactory.releaseActionRequest(aReq);
508: }
509: if (rReq != null) {
510: requestResponseFactory.releaseRenderRequest(rReq);
511: }
512: if (aRes != null) {
513: requestResponseFactory.releaseActionResponse(aRes);
514: }
515: if (rRes != null) {
516: requestResponseFactory.releaseRenderResponse(rRes);
517: }
518: // if check security returns false
519: } else {
520: pContRes
521: .setErrorCode(PortletContainerErrorCode.SECURITY_VIOLATION);
522: logger.log(Level.WARNING, "PSPL_PAECSPPA0005");
523: }
524: }
525:
526: /*
527: * Returns the <code>PortletDescriptor</code> for given portlet
528: * name. Returns null if not defined.
529: */
530: private PortletDescriptor getPortletDescriptor(String portletName) {
531: PortletDescriptor portletDescriptor = null;
532: if (descriptor != null
533: && descriptor.getPortletsDescriptor() != null) {
534: portletDescriptor = descriptor.getPortletsDescriptor()
535: .getPortletDescriptor(portletName);
536: //log if this portlet use session
537: logger.log(Level.FINEST, "PSPL_PAECSPPA0003", new Boolean(
538: portletDescriptor.sessionEnabled()));
539: }
540: return portletDescriptor;
541: }
542:
543: /*
544: * Sets the preferences validator in the portlet preferences
545: */
546: private void setValidator(PortletRequest pReq,
547: PreferencesValidator validator, boolean cleanup) {
548:
549: PreferencesValidatorSetter setter = (PreferencesValidatorSetter) pReq
550: .getPreferences();
551:
552: if (setter != null && cleanup) {
553: setter.setPreferencesValidator(null);
554: }
555:
556: if (setter != null && validator != null) {
557: setter.setPreferencesValidator(validator);
558: }
559:
560: }
561:
562: /*
563: * Sets the cache expiration and default cache expiration
564: * in the portlet container response.
565: */
566: private void setCacheParams(
567: PortletContainerRenderResponse pContRes,
568: PortletDescriptor portletDescriptor) {
569: int expiration = PortletDescriptor.EXPIRATION_CACHE_NOT_DEFINED;
570: if (portletDescriptor != null) {
571: expiration = portletDescriptor.getCacheExpiration();
572: }
573: pContRes.setExpiration(expiration);
574: }
575:
576: private boolean checkSecurityConstraint(HttpServletRequest req,
577: String portletName) {
578: boolean isValid = true;
579: SecurityConstraintDescriptor secConsDescriptor = descriptor
580: .getSecurityConstraintDescriptor();
581: if (secConsDescriptor != null) {
582: String consType = secConsDescriptor
583: .getTransportGuaranteeType();
584: if (consType.equals(CONFIDENTIAL)
585: || consType.equals(INTEGRAL)) {
586: List portlets = secConsDescriptor
587: .getConstrainedPortlets();
588: boolean stop = false;
589:
590: for (Iterator i = portlets.iterator(); i.hasNext()
591: && !stop;) {
592: String nextP = (String) i.next();
593: if (portletName.equals(nextP)) {
594: stop = true;
595: }
596: }
597: if (stop && req.isSecure()) {
598: isValid = false;
599: }
600: }
601: }
602: return isValid;
603: }
604:
605: /*
606: * Cleanup of LifeCycleManager and RequestResponseFactory objects
607: * <P>
608: */
609: public void destroy() {
610: ((LifecycleManagerImpl) lifecycleManager).destroy();
611: ((RequestResponseFactoryImpl) requestResponseFactory).destroy();
612: }
613: }
|