/* * $Id: LifecycleImpl.java,v 1.46 2004/10/29 19:48:38 edburns Exp $ */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.faces.lifecycle; import com.sun.faces.util.Util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.faces.FacesException; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** *
LifecycleImpl is the stock implementation of the standard * Lifecycle in the JavaServer Faces RI.
*/ public class LifecycleImpl extends Lifecycle { // -------------------------------------------------------- Static Variables // Log instance for this class private static final Log log = LogFactory.getLog(LifecycleImpl.class); // ------------------------------------------------------ Instance Variables // The set of PhaseListeners registered with this Lifecycle instance private ArrayList listeners = new ArrayList(); // The set of Phase instances that are executed by the execute() method // in order by the ordinal property of each phase private Phase phases[] = { null, // ANY_PHASE placeholder, not a real Phase new RestoreViewPhase(), new ApplyRequestValuesPhase(), new ProcessValidationsPhase(), new UpdateModelValuesPhase(), new InvokeApplicationPhase() }; // The Phase instance for the render() method private Phase response = new RenderResponsePhase(); // ------------------------------------------------------- Lifecycle Methods // Execute the phases up to but not including Render Response public void execute(FacesContext context) throws FacesException { if (context == null) { throw new NullPointerException (Util.getExceptionMessageString (Util.NULL_PARAMETERS_ERROR_MESSAGE_ID)); } if (log.isDebugEnabled()) { log.debug("execute(" + context + ")"); } for (int i = 1; i < phases.length; i++) { // Skip ANY_PHASE placeholder if (context.getRenderResponse() || context.getResponseComplete()) { break; } phase((PhaseId) PhaseId.VALUES.get(i), phases[i], context); if (reload((PhaseId) PhaseId.VALUES.get(i), context)) { if (log.isDebugEnabled()) { log.debug("Skipping rest of execute() because of a reload"); } context.renderResponse(); } } } // Execute the Render Response phase public void render(FacesContext context) throws FacesException { if (context == null) { throw new NullPointerException (Util.getExceptionMessageString (Util.NULL_PARAMETERS_ERROR_MESSAGE_ID)); } if (log.isDebugEnabled()) { log.debug("render(" + context + ")"); } if (!context.getResponseComplete()) { phase(PhaseId.RENDER_RESPONSE, response, context); } } // Add a new PhaseListener to the set of registered listeners public void addPhaseListener(PhaseListener listener) { if (listener == null) { throw new NullPointerException (Util.getExceptionMessageString (Util.NULL_PARAMETERS_ERROR_MESSAGE_ID)); } if (log.isDebugEnabled()) { log.debug("addPhaseListener(" + listener.getPhaseId().toString() + "," + listener); } synchronized (this.listeners) { ArrayList temp = (ArrayList) this.listeners.clone(); temp.add(listener); this.listeners = temp; } } // Return the set of PhaseListeners that have been registered public PhaseListener[] getPhaseListeners() { synchronized (this.listeners) { return (PhaseListener[]) this.listeners.toArray( new PhaseListener[this.listeners.size()]); } } // Remove a registered PhaseListener from the set of registered listeners public void removePhaseListener(PhaseListener listener) { if (listener == null) { throw new NullPointerException (Util.getExceptionMessageString (Util.NULL_PARAMETERS_ERROR_MESSAGE_ID)); } if (log.isDebugEnabled()) { log.debug("removePhaseListener(" + listener.getPhaseId().toString() + "," + listener); } synchronized (this.listeners) { ArrayList temp = (ArrayList) this.listeners.clone(); temp.remove(listener); this.listeners = temp; } } // --------------------------------------------------------- Private Methods private void executePhase(PhaseId phaseId, Phase phase, FacesContext context) throws FacesException { if (!skipping(phaseId, context)) { phase.execute(context); } } // Execute the specified phase, calling all listeners as well private void phase(PhaseId phaseId, Phase phase, FacesContext context) throws FacesException { if (log.isTraceEnabled()) { log.trace("phase(" + phaseId.toString() + "," + context + ")"); } // grab a pointer to our listeners List ourListeners = this.listeners; int numListeners = ourListeners.size(); // if we have PhaseListeners to fire if (numListeners > 0) { // instantiate all of our variables PhaseEvent event = new PhaseEvent(context, phaseId, this); PhaseListener listener = null; PhaseId listenerPhaseId = null; int i; // call all relevant PhaseListeners before for (i = 0; i < numListeners; i++) { listener = (PhaseListener) ourListeners.get(i); listenerPhaseId = listener.getPhaseId(); if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId)) { try { listener.beforePhase(event); } catch (Throwable e) { if (log.isTraceEnabled()) { log.trace("beforePhase(" + phaseId.toString() + "," + context + ") threw exception: " + e + " " + e.getMessage() + "\n" + Util.getStackTraceString(e)); } } } } try { // if response is not already handled, execute phase if (!skipping(phaseId, context)) { phase.execute(context); } } finally { // call all relevant PhaseListeners after for (i = numListeners - 1; i >= 0; i--) { listener = (PhaseListener) ourListeners.get(i); listenerPhaseId = listener.getPhaseId(); if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId)) { try { listener.afterPhase(event); } catch (Throwable e) { if (log.isTraceEnabled()) { log.trace("afterPhase(" + phaseId.toString() + "," + context + ") threw exception: " + e + " " + e.getMessage() + "\n" + Util.getStackTraceString(e)); } } } } } } else { // else no PhaseListeners and simply execute the Phase // if response is not already handled, execute phase if (!skipping(phaseId, context)) { phase.execute(context); } } } // Return "true" if this request is a browser reload and we just // completed the Restore View phase private boolean reload(PhaseId phaseId, FacesContext context) { if (!phaseId.equals(PhaseId.RESTORE_VIEW)) { return (false); } if (!(context.getExternalContext().getRequest() instanceof HttpServletRequest)) { return (false); } HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); String method = request.getMethod(); // Is this a GET request with query parameters? if ("GET".equals(method)) { Iterator names = context.getExternalContext(). getRequestParameterNames(); if (names.hasNext()) { return (false); } } // Is this a POST or PUT request? if ("POST".equals(method) || "PUT".equals(method)) { return (false); } // Assume this is a reload return (true); } // Return "true" if we should be skipping the actual phase execution private boolean skipping(PhaseId phaseId, FacesContext context) { if (context.getResponseComplete()) { return (true); } else if (context.getRenderResponse() && !phaseId.equals(PhaseId.RENDER_RESPONSE)) { return (true); } else { return (false); } } }