001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package com.sun.rave.web.ui.appbase.faces;
043:
044: import com.sun.rave.web.ui.appbase.AbstractFragmentBean;
045: import com.sun.rave.web.ui.appbase.AbstractPageBean;
046: import com.sun.rave.web.ui.appbase.AbstractRequestBean;
047: import com.sun.rave.web.ui.appbase.ApplicationException;
048: import com.sun.rave.web.ui.appbase.servlet.LifecycleListener;
049: import java.io.IOException;
050: import java.util.ArrayList;
051: import java.util.Iterator;
052: import java.util.LinkedList;
053: import java.util.List;
054: import java.util.Locale;
055: import java.util.Map;
056:
057: import javax.faces.FacesException;
058: import javax.faces.FactoryFinder;
059: import javax.faces.application.ViewHandler;
060: import javax.faces.component.UIViewRoot;
061: import javax.faces.context.FacesContext;
062: import javax.faces.el.ValueBinding;
063: import javax.faces.event.PhaseEvent;
064: import javax.faces.event.PhaseId;
065: import javax.faces.event.PhaseListener;
066: import javax.faces.lifecycle.Lifecycle;
067: import javax.faces.lifecycle.LifecycleFactory;
068: import javax.servlet.ServletContext;
069:
070: /**
071: * <p>ViewHandler implementation that allows events to be triggered upon the
072: * occurrence of specific ViewHandler method calls. This implementation also
073: * posts relevant lifecycle events to initialized page beans, so it also
074: * implements <code>PhaseListener</code>.</p>
075: */
076:
077: public class ViewHandlerImpl extends ViewHandler implements
078: PhaseListener {
079:
080: // ------------------------------------------------------------ Constructors
081:
082: /**
083: * <p>Construct a new {@link ViewHandlerImpl} that delegates to the
084: * specified <code>ViewHandler</code> instance.</p>
085: *
086: * @param handler The ViewHandler instance to which we will delegate
087: */
088: public ViewHandlerImpl(ViewHandler handler) {
089:
090: this .handler = handler;
091:
092: }
093:
094: // ------------------------------------------------------ Instance Variables
095:
096: /**
097: * <p>The ViewHandler instance to which we delegate operations.</p>
098: */
099: private ViewHandler handler = null;
100:
101: /**
102: * <p>The cached <code>Lifecycle</code> instance for this application.</p>
103: */
104: private Lifecycle lifecycle = null;
105:
106: /**
107: * <p>The {@link PageBeanMapper} used to identify the page bean that
108: * corresponds to a view identifier. This instance is lazily instantiated,
109: * so use <code>pageBeanMapper()</code> to acquire a reference.</p>
110: */
111: private PageBeanMapper mapper = null;
112:
113: /**
114: * <p>Flag indicating whether we have been registered as a phase
115: * listener with the application <code>Lifecycle</code> instance
116: * yet. This registration needs to be performed lazily, rather
117: * than in our constructor, in case the <code>Lifecycle</code>
118: * instance is replaced by a customized version (as will occur when
119: * using the JSF-Portlet Bridge).</p>
120: */
121: private boolean registered = false;
122:
123: // ------------------------------------------------------ Manifest Constants
124:
125: /**
126: * <p>Request attribute key under which a <code>List</code> of any
127: * <code>Exception</code>s thrown by a page bean event handler,
128: * and then logged and swallowed, will be cached. Application
129: * logic can check for such exceptions (perhaps during the
130: * <code>destroy()</code> method), to invoke application specific
131: * error processing.</p>
132: */
133: public static final String CACHED_EXCEPTIONS = "com.sun.rave.web.ui.appbase.CACHED_EXCEPTIONS";
134:
135: /**
136: * <p>The <code>UIViewRoot</code> attribute under which we store
137: * <code>Boolean.TRUE</code> when <code>createView()</code> is
138: * called. This can be used by the <code>isPostBack()</code>
139: * method to determine whether this view was restored (no such
140: * attribute present) and a postback is happening, or whether
141: * this view was created (no postback is happening).</p>
142: */
143: public static final String CREATED_VIEW = "com.sun.rave.web.ui.appbase.CREATED_VIEW"; //NOI18N
144:
145: /**
146: * <p>Request attribute key under which a <code>List</code> of the
147: * {@link AbstractPageBean}s that have been created for the current
148: * request are stored. Typically, there will be either one or two
149: * page beans on this list, depending on whether page navigation has
150: * taken place or not, but will be more if/when static or dynamic
151: * includes are used.</p>
152: */
153: public static final String PAGE_BEANS_CREATED = "com.sun.rave.web.ui.appbase.PAGE_BEANS_CREATED"; //NOI18N
154:
155: // ---------------------------------------------------------- Public Methods
156:
157: // ----------------------------------------------------- ViewHandler Methods
158:
159: /**
160: * <p>Return an appropriate <code>Locale</code> to use for this
161: * and subsequent requests for the current client.</p>
162: *
163: * @param context <code>FacesContext</code> for the current request
164: *
165: * @exception NullPointerException if <code>context</code>
166: * is <code>null</code>
167: */
168: public Locale calculateLocale(FacesContext context) {
169:
170: Locale locale = handler.calculateLocale(context);
171: return locale;
172:
173: }
174:
175: /**
176: * <p>Return an appropriate <code>RenderKit</code> identifier
177: * for this and subsequent requests from the current
178: * client.
179: *
180: * @param context <code>FacesContext</code> for the current request
181: *
182: * @exception NullPointerException if <code>context</code>
183: * is <code>null</code>
184: */
185: public String calculateRenderKitId(FacesContext context) {
186:
187: String renderKitId = handler.calculateRenderKitId(context);
188: return renderKitId;
189:
190: }
191:
192: /**
193: * <p>Create and return a new <code>UIViewRoot</code> instance
194: * initialized with information from this <code>FacesContext</code>
195: * for the specified <code>viewId</code>.</p>
196: *
197: * @param context <code>FacesContext</code> for the current request
198: * @param viewId View identifier of the view to be created
199: *
200: * @exception NullPointerException if <code>context</code>
201: * or <code>viewId</code> is <code>null</code>
202: */
203: public UIViewRoot createView(FacesContext context, String viewId) {
204:
205: register();
206: UIViewRoot viewRoot = handler.createView(context, viewId);
207: viewRoot.getAttributes().put(CREATED_VIEW, Boolean.TRUE);
208: return viewRoot;
209:
210: }
211:
212: /**
213: * <p>Return a URL suitable for rendering that selects the
214: * specified view identifier.</p>
215: *
216: * @param context <code>FacesContext</code> for the current request
217: * @param viewId View identifier of the desired view
218: *
219: * @exception NullPointerException if <code>context</code>
220: * or <code>viewId</code> is <code>null</code>
221: */
222: public String getActionURL(FacesContext context, String viewId) {
223:
224: String url = handler.getActionURL(context, viewId);
225: return url;
226:
227: }
228:
229: /**
230: * <p>Return a URL suitable for rendering that selects the
231: * specified resource.</p>
232: *
233: * @param context <code>FacesContext</code> for the current request
234: * @param path Context-relative resource path to reference
235: *
236: * @exception NullPointerException if <code>context</code>
237: * or <code>path</code> is <code>null</code>
238: */
239: public String getResourceURL(FacesContext context, String path) {
240:
241: String url = handler.getResourceURL(context, path);
242: return url;
243:
244: }
245:
246: /**
247: * <p>Perform the necessary actions to render the specified view
248: * as part of the current response.</p>
249: *
250: * @param context <code>FacesContext</code> for the current request
251: * @param viewRoot View to be rendered
252: *
253: * @exception NullPointerException if <code>context</code>
254: * or <code>viewRoot</code> is <code>null</code>
255: */
256: public void renderView(FacesContext context, UIViewRoot viewRoot)
257: throws IOException, FacesException {
258:
259: // Set up our page bean, if this has not yet been done
260: register();
261: int count = recordedCount(context);
262: AbstractPageBean pageBean = pageBean(context);
263: if (pageBean != null) {
264:
265: // If our page bean was just now created, that means we were
266: // called from Render Response phase. Therefore, we'll
267: // fake a "before Render Response" event for symmetry with the
268: // fact that an "after Render Response" event is going to get
269: // fired later on
270: if (recordedCount(context) > count) {
271: try {
272: pageBean.beforePhase(new PhaseEvent(context,
273: PhaseId.RENDER_RESPONSE, lifecycle()));
274: } catch (RuntimeException e) {
275: context.getExternalContext().log(e.getMessage(), e);
276: cache(context, e);
277: }
278: }
279:
280: // Fire the prerender() callback event
281: prerender(context, pageBean);
282:
283: }
284:
285: // If we have cached any exceptions already, call cleanup()
286: // (which will also cause an ApplicationException wrapping them
287: // to be thrown).
288: if (cached(context) != null) {
289: cleanup(context);
290: return;
291: }
292:
293: // Render the specified view, calling cleanup() if any exception
294: // is thrown (which will also cause an ApplicationException
295: // wrapping it to be thrown).
296: try {
297: if (!context.getResponseComplete()) {
298: handler.renderView(context, viewRoot);
299: }
300: } catch (RuntimeException e) {
301: context.getExternalContext().log(e.getMessage(), e);
302: cache(context, e);
303: cleanup(context);
304: }
305:
306: }
307:
308: /**
309: * <p>Perform necessary actions to restore the specified view
310: * and return a corresponding <code>UIViewRoot</code>. If there
311: * is no view information to be restored, return <code>null</code>.</p>
312: *
313: * @param context <code>FacesContext</code> for the current request
314: * @param viewId View identifier of the view to be restored
315: *
316: * @exception NullPointerException if <code>context</code>
317: * or <code>viewId</code> is <code>null</code>
318: */
319: public UIViewRoot restoreView(FacesContext context, String viewId) {
320:
321: register();
322: UIViewRoot viewRoot = handler.restoreView(context, viewId);
323:
324: /* mbohm (6451472): when the view root is
325: * restored in the RESTORE_VIEW phase, its attributes from the
326: * previous request are preserved. This will include the CREATED_VIEW
327: * view root attribute. That is causing isPostBack always to think
328: * that the view root was just created (so isPostBack always returns
329: * false). So be sure to clean out the CREATED_VIEW view root attribute
330: * here.
331: */
332: if (viewRoot != null) {
333: viewRoot.getAttributes().remove(CREATED_VIEW);
334: }
335: return viewRoot;
336:
337: }
338:
339: /**
340: * <p>Take appropriate action to save the current state information.</p>
341: *
342: * @param context <code>FacesContext</code> for the current request
343: *
344: * @exception IOException if an input/output error occurs
345: * @exception NullPointerException if <code>context</code>
346: * is <code>null</code>
347: */
348: public void writeState(FacesContext context) throws IOException {
349:
350: handler.writeState(context);
351:
352: }
353:
354: // -------------------------------------------------- PhaseListener Methods
355:
356: /**
357: * <p>Return <code>PhaseId.ANY_PHASE</code> because we are interested
358: * in all phase events.</p>
359: */
360: public PhaseId getPhaseId() {
361: return PhaseId.ANY_PHASE;
362: }
363:
364: /**
365: * <p>Process the specified <em>before phase</em> event.</p>
366: *
367: * @param event <code>PhaseEvent</code> to be processed
368: */
369: public void beforePhase(PhaseEvent event) {
370:
371: PhaseId phaseId = event.getPhaseId();
372: FacesContext context = event.getFacesContext();
373:
374: // Ripple this event through to all the page beans that have been
375: // initialized for this request and call beforePhase()
376: List list = (List) context.getExternalContext().getRequestMap()
377: .get(PAGE_BEANS_CREATED);
378: if (list != null) {
379: Iterator pageBeans = list.iterator();
380: while (pageBeans.hasNext()) {
381: AbstractPageBean pageBean = (AbstractPageBean) pageBeans
382: .next();
383: try {
384: pageBean.beforePhase(event);
385: } catch (RuntimeException e) {
386: context.getExternalContext().log(e.getMessage(), e);
387: cache(context, e);
388: }
389: }
390: }
391:
392: // Broadcast application level events as required
393: if (PhaseId.APPLY_REQUEST_VALUES.equals(phaseId)) {
394: // This is the page that will be processing the form submit,
395: // so tell the page bean by calling preprocess() on it
396: preprocess(context);
397: }
398:
399: }
400:
401: /**
402: * <p>Process the specified <em>after phase</em> event.</p>
403: *
404: * @param event <code>PhaseEvent</code> to be processed
405: */
406: public void afterPhase(PhaseEvent event) {
407:
408: PhaseId phaseId = event.getPhaseId();
409: FacesContext context = event.getFacesContext();
410:
411: // Ripple this event through to all the page beans that have been
412: // initialized for this request and call afterPhase()
413: List list = (List) context.getExternalContext().getRequestMap()
414: .get(PAGE_BEANS_CREATED);
415: if (list != null) {
416: Iterator pageBeans = list.iterator();
417: while (pageBeans.hasNext()) {
418: AbstractPageBean pageBean = (AbstractPageBean) pageBeans
419: .next();
420: try {
421: pageBean.afterPhase(event);
422: } catch (RuntimeException e) {
423: context.getExternalContext().log(e.getMessage(), e);
424: cache(context, e);
425: }
426: }
427: }
428:
429: // In a portlet environment, the "action" and "render"
430: // parts of the lifecycle appear as two different requests.
431: // Therefore, clean up the page that processed the current
432: // form submit (if any)
433: if (!(context.getExternalContext().getContext() instanceof ServletContext)) {
434: if (PhaseId.INVOKE_APPLICATION.equals(phaseId)
435: || context.getRenderResponse()
436: || context.getResponseComplete()) {
437: cleanup(context);
438: return;
439: }
440: }
441:
442: // Broadcast application level events as required
443: if (PhaseId.RENDER_RESPONSE.equals(phaseId)
444: || context.getResponseComplete()) {
445: // Unconditionally clean up after rendering is completed
446: cleanup(context);
447: }
448:
449: }
450:
451: // -------------------------------------------------------- Package Methods
452:
453: /**
454: * <p>Cache the specified exception in a request scope attribute
455: * that application logic can use to invoke error processing.
456: * All such cached exceptions will be available in the <code>List</code>
457: * used to maintain the cache.</p>
458: *
459: * @param context <code>FacesContext</code> for the current request
460: * @param exception Exception to be cached
461: */
462: public static void cache(FacesContext context, Exception exception) {
463:
464: // Is there an active FacesContext? There will not be if a lifecycle
465: // event was fired on a non-Faces request
466: if (context == null) {
467: return;
468: }
469:
470: // Add this exception to the list of exceptions for this request
471: Map map = context.getExternalContext().getRequestMap();
472: List list = (List) map.get(CACHED_EXCEPTIONS);
473: if (list == null) {
474: list = new LinkedList();
475: map.put(CACHED_EXCEPTIONS, list);
476: }
477: list.add(exception);
478:
479: }
480:
481: /**
482: * <p>Record the specified {@link AbstractPageBean} on the list of
483: * page beans that have been , and therefore need to have their
484: * beforePhase() and afterPhase() methods called at appropriate times.</p>
485: *
486: * @param context <code>FacesContext</code> for this request
487: * @param bean Page bean to be added to the list
488: */
489: public static void record(FacesContext context,
490: AbstractPageBean bean) {
491:
492: if (context == null) {
493: return;
494: }
495:
496: Map map = context.getExternalContext().getRequestMap();
497: List list = (List) map.get(PAGE_BEANS_CREATED);
498: if (list == null) {
499: list = new LinkedList();
500: map.put(PAGE_BEANS_CREATED, list);
501: }
502: list.add(bean);
503:
504: }
505:
506: // -------------------------------------------------------- Private Methods
507:
508: /**
509: * <p>Return a <code>List</code> of cached exceptions associated with
510: * this request, if any. If there were no such exceptions, return
511: * <code>null</code>.</p>
512: *
513: * @param context <code>FacesContext</code> for the current request
514: */
515: private List cached(FacesContext context) {
516:
517: Map map = context.getExternalContext().getRequestMap();
518: return (List) map.get(CACHED_EXCEPTIONS);
519:
520: }
521:
522: /**
523: * <p>Cause any application model request scope beans (instances of
524: * {@link AbstractFragmentBean}, {@link AbstractPageBean}, and
525: * {@link AbstractRequestBean}) to be removed from request scope.
526: * A side effect of this will be to cause {@link LifecycleListener}
527: * to fire <code>destroy()</code> methods on them.</p>
528: *
529: * <p>Then, if we have cached any exceptions associated with this request,
530: * throw an {@link ApplicationException} that wraps the list. If this occurs,
531: * the first cached exception will be considered the root cause.</p>
532: *
533: * @param context <code>FacesContext</code> for the current request
534: */
535: private void cleanup(FacesContext context) {
536:
537: // Acquire a list of request scope attribute keys to be processed
538: List list = new ArrayList();
539: Map map = context.getExternalContext().getRequestMap();
540: map.remove(PAGE_BEANS_CREATED);
541: Iterator entries = map.entrySet().iterator();
542: while (entries.hasNext()) {
543: Map.Entry entry = (Map.Entry) entries.next();
544: Object value = entry.getValue();
545: if (value != null) {
546: if ((value instanceof AbstractFragmentBean)
547: || (value instanceof AbstractPageBean)
548: || (value instanceof AbstractRequestBean)) {
549: list.add(entry.getKey());
550: }
551: }
552: }
553:
554: // Cause the selected attributes to be removed from request scope,
555: // which will trigger calls to their destroy() methods
556: Iterator keys = list.iterator();
557: while (keys.hasNext()) {
558: map.remove(keys.next());
559: }
560:
561: // If we cached any exceptions, wrap them in an ApplicationException
562: // and throw it
563: List exceptions = cached(context);
564: if ((exceptions != null) && (exceptions.size() > 0)) {
565: throw new ApplicationException((Exception) exceptions
566: .get(0), exceptions);
567: }
568:
569: }
570:
571: /**
572: * <p>Return the <code>Lifecycle</code> instance for this application,
573: * caching it the first time it is retrieved.</p>
574: */
575: private Lifecycle lifecycle() {
576:
577: if (lifecycle == null) {
578: String lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE; // FIXME - override?
579: LifecycleFactory factory = (LifecycleFactory) FactoryFinder
580: .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
581: lifecycle = factory.getLifecycle(lifecycleId);
582: }
583: return lifecycle;
584:
585: }
586:
587: /**
588: * <p>Log the specified message via <code>FacesContext</code> if it is
589: * not null, or directly to the container otherwise.</p>
590: *
591: * @param message Message to be logged
592: */
593: private void log(String message) {
594:
595: FacesContext context = FacesContext.getCurrentInstance();
596: if (context != null) {
597: context.getExternalContext().log(message);
598: } else {
599: System.out.println(message);
600: }
601:
602: }
603:
604: /**
605: * <p>Log the specified message and exception via <code>FacesContext</code>
606: * if it is not null, or directly to the container otherwise.</p>
607: *
608: * @param message Message to be logged
609: * @param throwable Exception to be logged
610: */
611: private void log(String message, Throwable throwable) {
612:
613: FacesContext context = FacesContext.getCurrentInstance();
614: if (context != null) {
615: context.getExternalContext().log(message);
616: } else {
617: System.out.println(message);
618: }
619:
620: }
621:
622: /**
623: * <p>Return the {@link AbstractPageBean} instance related to the
624: * current request (if any). Otherwise, return <code>null</code>.</p>
625: *
626: * @param context <code>FacesContext</code> for the current request
627: */
628: private AbstractPageBean pageBean(FacesContext context) {
629:
630: // Identify the current view (if any)
631: UIViewRoot view = context.getViewRoot();
632: if (view == null) {
633: return null;
634: }
635:
636: // Map the view identifier to the corresponding page bean name
637: String viewId = view.getViewId();
638: if (view == null) {
639: return null;
640: }
641:
642: // Return the relevant page bean (if any)
643: return pageBean(context, viewId);
644:
645: }
646:
647: /**
648: * <p>Return the {@link AbstractPageBean} instance related to the
649: * current request (if any). Otherwise, return <code>null</code>.</p>
650: *
651: * @param context <code>FacesContext</code> for the current request
652: * @param viewId View identifier used to select the page bean
653: */
654: private AbstractPageBean pageBean(FacesContext context,
655: String viewId) {
656:
657: // Identify the managed bean name of the corresponding page bean
658: String viewName = pageBeanMapper().mapViewId(viewId);
659: if (viewName == null) {
660: return null;
661: }
662:
663: // Retrieve or create a corresponding page bean instance
664: ValueBinding vb = context.getApplication().createValueBinding(
665: "#{" + viewName + "}"); //NOI18N
666: AbstractPageBean pageBean = null;
667: try {
668: pageBean = (AbstractPageBean) vb.getValue(context);
669: } catch (ClassCastException e) {
670: // System.out.println(" WARNING: Bean for " + viewId + " is not a page bean");
671: }
672: return pageBean;
673:
674: }
675:
676: /**
677: * <p>Return the {@link PageBeanMapper} we will use to map view identifiers
678: * to managed bean names of the corresponding page beans, instantiating a
679: * new instance if necessary. <strong>FIXME</strong> - make the actual
680: * implementation class to be used configurable.</p>
681: */
682: private PageBeanMapper pageBeanMapper() {
683:
684: if (mapper == null) {
685: mapper = new PageBeanMapperImpl();
686: }
687: return mapper;
688:
689: }
690:
691: /**
692: * <p>Call the <code>preprocess()</code> method on the page bean
693: * associated with this request (if any).</p>
694: *
695: * @param context <code>FacesContext</code> for the current request
696: */
697: private void preprocess(FacesContext context) {
698:
699: preprocess(context, pageBean(context));
700:
701: }
702:
703: /**
704: * <p>Call the <code>preprocess()</code> method on the page bean
705: * that is associated with the specified view identifier (if any).</p>
706: *
707: * @param context <code>FacesContext</code> for the current request
708: * @param viewId View identifier of the selected view
709: */
710: private void preprocess(FacesContext context, String viewId) {
711:
712: preprocess(context, pageBean(context, viewId));
713:
714: }
715:
716: /**
717: * <p>Call the <code>preprocess()</code> method on the specified
718: * page bean associated with this request.</p>
719: *
720: * @param context <code>FacesContext</code> for the current request
721: * @param pageBean {@link AbstractPageBean{ for the current view
722: */
723: private void preprocess(FacesContext context,
724: AbstractPageBean pageBean) {
725:
726: if (pageBean == null) {
727: return;
728: }
729:
730: // CR 6255669 - Log and swallow any thrown RuntimeException
731: try {
732: pageBean.preprocess();
733: } catch (RuntimeException e) {
734: context.getExternalContext().log(e.getMessage(), e);
735: cache(context, e);
736: }
737:
738: }
739:
740: /**
741: * <p>Call the <code>prerender()</code> method on the page bean
742: * associated with this request (if any).</p>
743: *
744: * @param context <code>FacesContext</code> for the current request
745: */
746: private void prerender(FacesContext context) {
747:
748: prerender(context, pageBean(context));
749:
750: }
751:
752: /**
753: * <p>Call the <code>prerender()</code> method on the specified
754: * page bean associated with this request.</p>
755: *
756: * @param context <code>FacesContext</code> for the current request
757: * @param pageBean {@link AbstractPageBean{ for the current view
758: */
759: private void prerender(FacesContext context,
760: AbstractPageBean pageBean) {
761:
762: if (pageBean == null) {
763: return;
764: }
765:
766: // CR 6255669 - Log and swallow any thrown RuntimeException
767: try {
768: if (!context.getResponseComplete()) {
769: pageBean.prerender();
770: }
771: } catch (RuntimeException e) {
772: context.getExternalContext().log(e.getMessage(), e);
773: cache(context, e);
774: }
775:
776: }
777:
778: /**
779: * <p>Return a <code>List</code> of cached page beans that have
780: * been created, and therefore need to have their beforePhase()
781: * and afterPhase() methods called at appropriate times. If there were
782: * no such beans, return <code>null</code>.</p>
783: *
784: * @param context <code>FacesContext</code> for the current request
785: */
786: private List recorded(FacesContext context) {
787:
788: if (context != null) {
789: Map map = context.getExternalContext().getRequestMap();
790: return (List) map.get(PAGE_BEANS_CREATED);
791: } else {
792: return null;
793: }
794:
795: }
796:
797: /**
798: * <p>Return the number of page beans that have been created for
799: * this request.</p>
800: *
801: * @param context <code>FacesContext</code> for the current request
802: */
803: private int recordedCount(FacesContext context) {
804:
805: if (context != null) {
806: Map map = context.getExternalContext().getRequestMap();
807: List list = (List) map.get(PAGE_BEANS_CREATED);
808: if (list != null) {
809: return list.size();
810: } else {
811: return 0;
812: }
813: } else {
814: return 0;
815: }
816:
817: }
818:
819: /**
820: * <p>Register this instance as a <code>PhaseListener</code> with the
821: * <code>Lifecycle</code> instance for this web application, if we
822: * have not already done so.</p>
823: */
824: private void register() {
825:
826: if (registered) {
827: return;
828: }
829: lifecycle().addPhaseListener(this );
830: registered = true;
831:
832: }
833:
834: }
|