001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.myfaces.lifecycle;
020:
021: import java.util.ArrayList;
022: import java.util.List;
023:
024: import javax.faces.FacesException;
025: import javax.faces.context.FacesContext;
026: import javax.faces.event.PhaseId;
027: import javax.faces.event.PhaseListener;
028: import javax.faces.lifecycle.Lifecycle;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.apache.myfaces.util.DebugUtils;
033:
034: /**
035: * Implements the lifecycle as described in Spec. 1.0 PFD Chapter 2
036: * @author Manfred Geiler
037: * @author Nikolay Petrov
038: */
039: public class LifecycleImpl extends Lifecycle {
040: private static final Log log = LogFactory
041: .getLog(LifecycleImpl.class);
042:
043: private PhaseExecutor[] lifecycleExecutors;
044: private PhaseExecutor renderExecutor;
045:
046: private final List<PhaseListener> _phaseListenerList = new ArrayList<PhaseListener>();
047:
048: /**
049: * Lazy cache for returning _phaseListenerList as an Array.
050: */
051: private PhaseListener[] _phaseListenerArray = null;
052:
053: public LifecycleImpl() {
054: // hide from public access
055: lifecycleExecutors = new PhaseExecutor[] {
056: new RestoreViewExecutor(),
057: new ApplyRequestValuesExecutor(),
058: new ProcessValidationsExecutor(),
059: new UpdateModelValuesExecutor(),
060: new InvokeApplicationExecutor() };
061:
062: renderExecutor = new RenderResponseExecutor();
063: }
064:
065: public void execute(FacesContext facesContext)
066: throws FacesException {
067: PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(
068: this , facesContext, getPhaseListeners());
069: for (int executorIndex = 0; executorIndex < lifecycleExecutors.length; executorIndex++) {
070: if (executePhase(facesContext,
071: lifecycleExecutors[executorIndex], phaseListenerMgr)) {
072: return;
073: }
074: }
075: }
076:
077: private boolean executePhase(FacesContext facesContext,
078: PhaseExecutor executor,
079: PhaseListenerManager phaseListenerMgr)
080: throws FacesException {
081: boolean skipFurtherProcessing = false;
082: if (log.isTraceEnabled()) {
083: log.trace("entering " + executor.getPhase() + " in "
084: + LifecycleImpl.class.getName());
085: }
086:
087: try {
088: phaseListenerMgr.informPhaseListenersBefore(executor
089: .getPhase());
090:
091: if (isResponseComplete(facesContext, executor.getPhase(),
092: true)) {
093: // have to return right away
094: return true;
095: }
096: if (shouldRenderResponse(facesContext, executor.getPhase(),
097: true)) {
098: skipFurtherProcessing = true;
099: }
100:
101: if (executor.execute(facesContext)) {
102: return true;
103: }
104: } finally {
105: phaseListenerMgr.informPhaseListenersAfter(executor
106: .getPhase());
107: }
108:
109: if (isResponseComplete(facesContext, executor.getPhase(), false)
110: || shouldRenderResponse(facesContext, executor
111: .getPhase(), false)) {
112: // since this phase is completed we don't need to return right away even if the response is completed
113: skipFurtherProcessing = true;
114: }
115:
116: if (!skipFurtherProcessing && log.isTraceEnabled()) {
117: log.trace("exiting " + executor.getPhase() + " in "
118: + LifecycleImpl.class.getName());
119: }
120:
121: return skipFurtherProcessing;
122: }
123:
124: public void render(FacesContext facesContext) throws FacesException {
125: // if the response is complete we should not be invoking the phase listeners
126: if (isResponseComplete(facesContext, renderExecutor.getPhase(),
127: true)) {
128: return;
129: }
130: if (log.isTraceEnabled())
131: log.trace("entering " + renderExecutor.getPhase() + " in "
132: + LifecycleImpl.class.getName());
133:
134: PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(
135: this , facesContext, getPhaseListeners());
136:
137: try {
138: phaseListenerMgr.informPhaseListenersBefore(renderExecutor
139: .getPhase());
140: // also possible that one of the listeners completed the response
141: if (isResponseComplete(facesContext, renderExecutor
142: .getPhase(), true)) {
143: return;
144: }
145:
146: renderExecutor.execute(facesContext);
147: } finally {
148: phaseListenerMgr.informPhaseListenersAfter(renderExecutor
149: .getPhase());
150: }
151:
152: if (log.isTraceEnabled()) {
153: //Note: DebugUtils Logger must also be in trace level
154: DebugUtils.traceView("View after rendering");
155: }
156:
157: if (log.isTraceEnabled()) {
158: log.trace("exiting " + renderExecutor.getPhase() + " in "
159: + LifecycleImpl.class.getName());
160: }
161: }
162:
163: private boolean isResponseComplete(FacesContext facesContext,
164: PhaseId phase, boolean before) {
165: boolean flag = false;
166: if (facesContext.getResponseComplete()) {
167: if (log.isDebugEnabled()) {
168: log
169: .debug("exiting from lifecycle.execute in "
170: + phase
171: + " because getResponseComplete is true from one of the "
172: + (before ? "before" : "after")
173: + " listeners");
174: }
175: flag = true;
176: }
177: return flag;
178: }
179:
180: private boolean shouldRenderResponse(FacesContext facesContext,
181: PhaseId phase, boolean before) {
182: boolean flag = false;
183: if (facesContext.getRenderResponse()) {
184: if (log.isDebugEnabled()) {
185: log
186: .debug("exiting from lifecycle.execute in "
187: + phase
188: + " because getRenderResponse is true from one of the "
189: + (before ? "before" : "after")
190: + " listeners");
191: }
192: flag = true;
193: }
194: return flag;
195: }
196:
197: public void addPhaseListener(PhaseListener phaseListener) {
198: if (phaseListener == null) {
199: throw new NullPointerException(
200: "PhaseListener must not be null.");
201: }
202: synchronized (_phaseListenerList) {
203: _phaseListenerList.add(phaseListener);
204: _phaseListenerArray = null; // reset lazy cache array
205: }
206: }
207:
208: public void removePhaseListener(PhaseListener phaseListener) {
209: if (phaseListener == null) {
210: throw new NullPointerException(
211: "PhaseListener must not be null.");
212: }
213: synchronized (_phaseListenerList) {
214: _phaseListenerList.remove(phaseListener);
215: _phaseListenerArray = null; // reset lazy cache array
216: }
217: }
218:
219: public PhaseListener[] getPhaseListeners() {
220: synchronized (_phaseListenerList) {
221: // (re)build lazy cache array if necessary
222: if (_phaseListenerArray == null) {
223: _phaseListenerArray = _phaseListenerList
224: .toArray(new PhaseListener[_phaseListenerList
225: .size()]);
226: }
227: return _phaseListenerArray;
228: }
229: }
230: }
|