001: /*
002: * $Id: FacesPortlet.java,v 1.6.16.1 2007/03/16 11:05:43 dg154973 Exp $
003: */
004:
005: /*
006: * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
007: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
008: */
009:
010: package com.sun.faces.portlet;
011:
012: import java.io.IOException;
013: import java.util.Map;
014: import javax.faces.FacesException;
015: import javax.faces.FactoryFinder;
016: import javax.faces.application.Application;
017: import javax.faces.context.FacesContext;
018: import javax.faces.context.FacesContextFactory;
019: import javax.faces.lifecycle.Lifecycle;
020: import javax.faces.lifecycle.LifecycleFactory;
021: import javax.faces.webapp.FacesServlet;
022: import javax.portlet.ActionRequest;
023: import javax.portlet.ActionResponse;
024: import javax.portlet.GenericPortlet;
025: import javax.portlet.PortletMode;
026: import javax.portlet.PortletConfig;
027: import javax.portlet.PortletSession;
028: import javax.portlet.PortletException;
029: import javax.portlet.RenderRequest;
030: import javax.portlet.RenderResponse;
031: import javax.portlet.PortletRequest;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: /**
037: * <p><strong>FacesPortlet</strong> is a portlet that manages the request
038: * processing lifecycle for web applications that are utilizing JavaServer
039: * Faces to construct the user interface in a portlet-based environment.</p>
040: */
041:
042: public class FacesPortlet extends GenericPortlet {
043:
044: // The Log instance for this class
045: private static final Log log = LogFactory
046: .getLog(FacesPortlet.class);
047:
048: /**
049: * <p>The key used to store/retrive the PortletConfig object.</p>
050: */
051: public static final String PORTLET_CONFIG = "javax.portlet.PortletConfig";
052:
053: // ------------------------------------------------------ Manifest Constants
054:
055: /**
056: * <p>Context initialization parameter name for the lifecycle identifier
057: * of the {@link Lifecycle} instance to be utilized.</p>
058: */
059: private static final String LIFECYCLE_ID_ATTR = FacesServlet.LIFECYCLE_ID_ATTR;
060:
061: // ------------------------------------------------------ Instance Variables
062:
063: /**
064: * <p>The {@link Application} instance for this web application.</p>
065: */
066: private Application application = null;
067:
068: /**
069: * <p>Factory for {@link FacesContext} instances.</p>
070: */
071: private FacesContextFactory facesContextFactory = null;
072:
073: /**
074: * <p>The {@link Lifecycle} instance to use for request processing.</p>
075: */
076: private Lifecycle lifecycle = null;
077:
078: /**
079: * <p>The <code>PortletConfig</code> instance for this portlet.</p>
080: */
081: private PortletConfig portletConfig = null;
082:
083: // ---------------------------------------------------------- Public Methods
084:
085: /**
086: * <p>Release all resources acquired at startup time.</p>
087: */
088: public void destroy() {
089: if (log.isTraceEnabled()) {
090: log.trace("Begin FacesPortlet.destory() ");
091: }
092: application = null;
093: facesContextFactory = null;
094: lifecycle = null;
095: portletConfig = null;
096: if (log.isTraceEnabled()) {
097: log.trace("End FacesPortlet.destory() ");
098: }
099:
100: }
101:
102: /**
103: * <p>Acquire the factory instance we will require.</p>
104: *
105: * @exception PortletException if, for any reason, the startp of
106: * this Faces application failed. This includes errors in the
107: * config file that is parsed before or during the processing of
108: * this <code>init()</code> method.
109: */
110: public void init(PortletConfig portletConfig)
111: throws PortletException {
112:
113: if (log.isTraceEnabled()) {
114: log.trace("Begin FacesPortlet.init() ");
115: }
116:
117: // Save our PortletConfig instance
118: this .portletConfig = portletConfig;
119: // Invoke Generic Portlet's init method
120: super .init(portletConfig);
121: if (log.isTraceEnabled()) {
122: log.trace("End FacesPortlet.init() ");
123: }
124: }
125:
126: public FacesContextFactory getFacesContextFactory()
127: throws PortletException {
128: if (facesContextFactory != null) {
129: return facesContextFactory;
130: }
131: // Acquire our FacesContextFactory instance
132: try {
133: facesContextFactory = (FacesContextFactory) FactoryFinder
134: .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
135: if (log.isTraceEnabled()) {
136: log.trace("Retrieved facesContextFactory "
137: + facesContextFactory);
138: }
139: } catch (FacesException e) {
140: Throwable rootCause = e.getCause();
141: if (rootCause == null) {
142: throw e;
143: } else {
144: throw new PortletException(e.getMessage(), rootCause);
145: }
146: }
147: return facesContextFactory;
148: }
149:
150: public Lifecycle getLifecycle() throws PortletException {
151: if (lifecycle != null) {
152: return lifecycle;
153: }
154: try {
155: LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
156: .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
157: if (log.isTraceEnabled()) {
158: log.trace("Retrieved lifecycleFactory "
159: + lifecycleFactory);
160: }
161: String lifecycleId = portletConfig.getPortletContext()
162: .getInitParameter(LIFECYCLE_ID_ATTR);
163: if (log.isDebugEnabled()) {
164: log.debug("lifecycleId " + lifecycleId);
165: }
166: if (lifecycleId == null) {
167: lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
168: }
169: lifecycle = lifecycleFactory.getLifecycle(lifecycleId);
170: if (log.isTraceEnabled()) {
171: log.trace("Retrieved lifecycle from lifecycleFactory "
172: + lifecycle);
173: }
174: } catch (FacesException e) {
175: Throwable rootCause = e.getCause();
176: if (rootCause == null) {
177: throw e;
178: } else {
179: throw new PortletException(e.getMessage(), rootCause);
180: }
181: }
182: return lifecycle;
183: }
184:
185: /**
186: * <p>Perform the request processing lifecycle for the specified request,
187: * up to (but not including) the <em>Render Response</em> phase.</p>
188: *
189: * @param request The portlet request we are processing
190: * @param response The portlet response we are processing
191: *
192: * @exception IOException if an input/output error occurs
193: * @exception PortletException if a portlet processing error occurs
194: */
195: public void processAction(ActionRequest request,
196: ActionResponse response) throws IOException,
197: PortletException {
198: if (log.isTraceEnabled()) {
199: log.trace("Begin FacesPortlet.processAction()");
200: }
201:
202: storeInitParameter(request);
203:
204: // Acquire the FacesContext instance for this request
205: FacesContext context = getFacesContextFactory()
206: .getFacesContext(portletConfig.getPortletContext(),
207: request, response, lifecycle);
208:
209: // Store the PortletConfig in the Application Map
210: storePortletConfig(context);
211:
212: if (log.isTraceEnabled()) {
213: log.trace("Begin Executing phases");
214: }
215: // Execute the pre-render request processing lifecycle for this request
216: try {
217: getLifecycle().execute(context);
218: if (log.isTraceEnabled()) {
219: log.trace("End Executing phases");
220: }
221: } catch (FacesException e) {
222: Throwable t = ((FacesException) e).getCause();
223: if (t == null) {
224: throw new PortletException(e.getMessage(), e);
225: } else {
226: if (t instanceof PortletException) {
227: throw ((PortletException) t);
228: } else if (t instanceof IOException) {
229: throw ((IOException) t);
230: } else {
231: throw new PortletException(t.getMessage(), t);
232: }
233: }
234:
235: } finally {
236: PortletSession session = (PortletSession) context
237: .getExternalContext().getSession(true);
238: PortletMode mode = request.getPortletMode();
239: Boolean errorFlag = (Boolean) session
240: .getAttribute(LifecycleImpl.ERROR_FLAG);
241: // If any error occured use the same mode
242: if (errorFlag != null && errorFlag.equals(Boolean.TRUE)) {
243: response.setPortletMode(mode);
244: } else {
245: // Check if the page is same as the INIT_VIEW page, if yes set the mode to VIEW
246: // If the page is not the INIT_VIEW page, it means EDIT/HELP has navigation
247: // continue by setting the same mode as the current mode.
248: String currentViewId = context.getViewRoot()
249: .getViewId();
250: String viewId = (String) portletConfig
251: .getInitParameter(LifecycleImpl.INIT_VIEW_PARAMETER);
252: try {
253: if (viewId.equals(currentViewId))
254: response.setPortletMode(PortletMode.VIEW);
255: else
256: response.setPortletMode(mode);
257: } catch (IllegalStateException ise) {
258: // sendRedirect might have been called
259: if (log.isInfoEnabled()) {
260: log.info(ise.getMessage());
261: }
262: }
263: }
264: // Release the FacesContext instance for this request
265: context.release();
266: }
267: if (log.isTraceEnabled()) {
268: log.trace("End FacesPortlet.processAction()");
269: }
270:
271: }
272:
273: /**
274: * <p>Perform the <em>Render Response</em> phase of the request processing
275: * lifecycle for the specified request.</p>
276: *
277: * <p>This method is invoked to serve up the <code>view</code> portlet mode.</p>
278: *
279: * @param request The portlet request we are processing
280: * @param response The portlet response we are processing
281: *
282: * @exception IOException if an input/output error occurs
283: * @exception PortletException if a portlet processing error occurs
284: */
285: public void doView(RenderRequest request, RenderResponse response)
286: throws PortletException, java.io.IOException {
287: renderFaces(request, response);
288: }
289:
290: /**
291: * <p>Perform the <em>Render Response</em> phase of the request processing
292: * lifecycle for the specified request.</p>
293: *
294: * <p>This method is invoked to serve up the <code>edit</code> portlet mode.</p>
295: *
296: * @param request The portlet request we are processing
297: * @param response The portlet response we are processing
298: *
299: * @exception IOException if an input/output error occurs
300: * @exception PortletException if a portlet processing error occurs
301: */
302: public void doEdit(RenderRequest request, RenderResponse response)
303: throws PortletException, java.io.IOException {
304: renderFaces(request, response);
305: }
306:
307: /**
308: * <p>Perform the <em>Render Response</em> phase of the request processing
309: * lifecycle for the specified request.</p>
310: *
311: * <p>This method is invoked to serve up the <code>help</code> portlet mode.</p>
312: *
313: * @param request The portlet request we are processing
314: * @param response The portlet response we are processing
315: *
316: * @exception IOException if an input/output error occurs
317: * @exception PortletException if a portlet processing error occurs
318: */
319: public void doHelp(RenderRequest request, RenderResponse response)
320: throws PortletException, java.io.IOException {
321: renderFaces(request, response);
322: }
323:
324: /**
325: * <p>Perform the <em>Render Response</em> phase of the request processing
326: * lifecycle for the specified request.</p>
327: *
328: * @param request The portlet request we are processing
329: * @param response The portlet response we are processing
330: *
331: * @exception IOException if an input/output error occurs
332: * @exception PortletException if a portlet processing error occurs
333: */
334: private void renderFaces(RenderRequest request,
335: RenderResponse response) throws IOException,
336: PortletException {
337: if (log.isTraceEnabled()) {
338: log.trace("Begin FacesPortlet.render()");
339: }
340: // in a portlet environment, the context type of reponse must
341: // be set explicitly.
342: response.setContentType(request.getResponseContentType());
343:
344: // The title is set in the Generic Portlet
345:
346: //Store in the initialization parameter
347: storeInitParameter(request);
348:
349: // Acquire the FacesContext instance for this request
350: FacesContext context = getFacesContextFactory()
351: .getFacesContext(portletConfig.getPortletContext(),
352: request, response, getLifecycle());
353:
354: // Store the PortletConfig in the Application Map
355: storePortletConfig(context);
356:
357: if (log.isTraceEnabled()) {
358: log.trace("Begin executing RenderResponse phase ");
359: }
360: // Execute the render response phase for this request
361: try {
362: getLifecycle().render(context);
363: if (log.isTraceEnabled()) {
364: log.trace("End executing RenderResponse phase ");
365: }
366: } catch (FacesException e) {
367: Throwable t = ((FacesException) e).getCause();
368: if (t == null) {
369: throw new PortletException(e.getMessage(), e);
370: } else {
371: if (t instanceof PortletException) {
372: throw ((PortletException) t);
373: } else if (t instanceof IOException) {
374: throw ((IOException) t);
375: } else {
376: throw new PortletException(t.getMessage(), t);
377: }
378: }
379:
380: } finally {
381:
382: // Release the FacesContext instance for this request
383: context.release();
384:
385: }
386: if (log.isTraceEnabled()) {
387: log.trace("End FacesPortlet.render()");
388: }
389:
390: }
391:
392: // --------------------------------------------------------- Private Methods
393:
394: /**
395: * Stores the init parameter identifier and the value for that in the request map.
396: * The init parameter identifier can be either com.sun.faces.portlet.INIT_VIEW or
397: * com.sun.faces.portlet.INIT_EDIT or com.sun.faces.portlet.INIT_HELP. The appropriate
398: * identifier based on the Portlet mode is stored. This value is used in LifeCycleImpl
399: * to keep the state information for each mode separate.
400: * The value for the identifier is used during the RenderResponse Phase to
401: * display the initial view.
402: *
403: * @param request the portlet request, can be ActionRequest or RenderRequest
404: * @throws PortletException
405: */
406: private void storeInitParameter(PortletRequest request)
407: throws PortletException {
408: PortletMode mode = request.getPortletMode();
409:
410: // Get the init parameter identifier based on the mode.
411: String initParameterIdentifier = null;
412: if (mode.equals(PortletMode.VIEW)) {
413: initParameterIdentifier = LifecycleImpl.INIT_VIEW_PARAMETER;
414: } else if (mode.equals(PortletMode.EDIT)) {
415: initParameterIdentifier = LifecycleImpl.INIT_EDIT_PARAMETER;
416: } else if (mode.equals(PortletMode.HELP)) {
417: initParameterIdentifier = LifecycleImpl.INIT_HELP_PARAMETER;
418: }
419: // Check whether the requested mode is allowed
420: if (!request.isPortletModeAllowed(mode)
421: || initParameterIdentifier == null) {
422: throw new PortletException(mode + " is not allowed");
423: }
424:
425: String initId = (String) portletConfig
426: .getInitParameter(initParameterIdentifier);
427: if (initId != null) {
428: // store the identifier in the request map. This identifier can be either a
429: // INIT_VIEW or INIT_EDIT or INIT_HELP based on the portlet mode. This information
430: // is used in LifeCycleImpl to keep the state information for each mode separate.
431: request.setAttribute(LifecycleImpl.INIT_PARAMETER,
432: initParameterIdentifier);
433: // store the value for the identifier in the requestMap so that it could be used
434: // during the RenderResponse Phase to display the initial view.
435: request.setAttribute(initParameterIdentifier, initId);
436: } else {
437: throw new PortletException(initParameterIdentifier
438: + " must be specified");
439: }
440: }
441:
442: /**
443: * Store the PortletConfig in the Application Map
444: */
445: private void storePortletConfig(FacesContext context) {
446: Map applicationMap = context.getExternalContext()
447: .getApplicationMap();
448: if (!applicationMap.containsKey(PORTLET_CONFIG))
449: applicationMap.put(PORTLET_CONFIG, portletConfig);
450: }
451: }
|