1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.internal.lifecycle;
21
22 import org.apache.myfaces.tobago.util.DebugUtils;
23 import org.apache.myfaces.tobago.util.RequestUtils;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import javax.faces.FacesException;
28 import javax.faces.context.FacesContext;
29 import javax.faces.event.PhaseId;
30 import javax.faces.event.PhaseListener;
31 import javax.faces.lifecycle.Lifecycle;
32 import java.util.ArrayList;
33 import java.util.List;
34
35
36
37
38 public class TobagoLifecycle extends Lifecycle {
39
40 private static final Logger LOG = LoggerFactory.getLogger(TobagoLifecycle.class);
41
42 public static final String VIEW_ROOT_KEY = TobagoLifecycle.class.getName() + ".VIEW_ROOT_KEY";
43 public static final String FACES_MESSAGES_KEY = TobagoLifecycle.class.getName() + ".FACES_MESSAGES_KEY";
44
45 private PhaseExecutor[] lifecycleExecutors;
46 private PhaseExecutor renderExecutor;
47
48 private final List<PhaseListener> phaseListenerList = new ArrayList<PhaseListener>();
49
50
51
52
53 private PhaseListener[] phaseListenerArray = null;
54
55 public TobagoLifecycle() {
56
57 lifecycleExecutors = new PhaseExecutor[]{
58 new RestoreViewExecutor(),
59 new ApplyRequestValuesExecutor(),
60 new ProcessValidationsExecutor(),
61 new UpdateModelValuesExecutor(),
62 new InvokeApplicationExecutor()
63 };
64
65 renderExecutor = new RenderResponseExecutor();
66 }
67
68 public void execute(FacesContext context) throws FacesException {
69
70 PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, context, getPhaseListeners());
71
72
73
74 RequestUtils.ensureEncoding(context);
75
76 for (PhaseExecutor executor : lifecycleExecutors) {
77 if (executePhase(context, executor, phaseListenerMgr)) {
78 return;
79 }
80 }
81 }
82
83 private boolean executePhase(FacesContext facesContext, PhaseExecutor executor, PhaseListenerManager phaseListenerMgr)
84 throws FacesException {
85
86 boolean skipFurtherProcessing = false;
87 if (LOG.isTraceEnabled()) {
88 LOG.trace("entering " + executor.getPhase() + " in " + TobagoLifecycle.class.getName());
89 }
90
91 try {
92 phaseListenerMgr.informPhaseListenersBefore(executor.getPhase());
93
94 if (isResponseComplete(facesContext, executor.getPhase(), true)) {
95
96 return true;
97 }
98 if (shouldRenderResponse(facesContext, executor.getPhase(), true)) {
99 skipFurtherProcessing = true;
100 }
101
102 if (executor.execute(facesContext)) {
103 return true;
104 }
105 } finally {
106 phaseListenerMgr.informPhaseListenersAfter(executor.getPhase());
107 }
108
109
110 if (isResponseComplete(facesContext, executor.getPhase(), false)
111 || shouldRenderResponse(facesContext, executor.getPhase(), false)) {
112
113 skipFurtherProcessing = true;
114 }
115
116 if (!skipFurtherProcessing && LOG.isTraceEnabled()) {
117 LOG.trace("exiting " + executor.getPhase() + " in " + TobagoLifecycle.class.getName());
118 }
119
120 return skipFurtherProcessing;
121 }
122
123 public void render(FacesContext facesContext) throws FacesException {
124
125 if (isResponseComplete(facesContext, renderExecutor.getPhase(), true)) {
126 return;
127 }
128 if (LOG.isTraceEnabled()) {
129 LOG.trace("entering " + renderExecutor.getPhase() + " in " + TobagoLifecycle.class.getName());
130 }
131
132 PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
133
134 try {
135 phaseListenerMgr.informPhaseListenersBefore(renderExecutor.getPhase());
136
137 if (isResponseComplete(facesContext, renderExecutor.getPhase(), true)) {
138 return;
139 }
140 renderExecutor.execute(facesContext);
141 } finally {
142 phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
143 }
144
145 if (LOG.isTraceEnabled()) {
146 LOG.trace(DebugUtils.toString(facesContext.getViewRoot(), 0));
147 LOG.trace("exiting " + renderExecutor.getPhase() + " in " + TobagoLifecycle.class.getName());
148 }
149
150 }
151
152 private boolean isResponseComplete(FacesContext facesContext, PhaseId phase, boolean before) {
153 boolean flag = false;
154 if (facesContext.getResponseComplete()) {
155 if (LOG.isDebugEnabled()) {
156 LOG.debug("exiting from lifecycle.execute in " + phase
157 + " because getResponseComplete is true from one of the "
158 + (before ? "before" : "after") + " listeners");
159 }
160 flag = true;
161 }
162 return flag;
163 }
164
165 private boolean shouldRenderResponse(FacesContext facesContext, PhaseId phase, boolean before) {
166 boolean flag = false;
167 if (facesContext.getRenderResponse()) {
168 if (LOG.isDebugEnabled()) {
169 LOG.debug("exiting from lifecycle.execute in " + phase
170 + " because getRenderResponse is true from one of the "
171 + (before ? "before" : "after") + " listeners");
172 }
173 flag = true;
174 }
175 return flag;
176 }
177
178 public void addPhaseListener(PhaseListener phaseListener) {
179 if (phaseListener == null) {
180 throw new NullPointerException("PhaseListener must not be null.");
181 }
182 synchronized (phaseListenerList) {
183 phaseListenerList.add(phaseListener);
184 phaseListenerArray = null;
185 }
186 }
187
188 public void removePhaseListener(PhaseListener phaseListener) {
189 if (phaseListener == null) {
190 throw new NullPointerException("PhaseListener must not be null.");
191 }
192 synchronized (phaseListenerList) {
193 phaseListenerList.remove(phaseListener);
194 phaseListenerArray = null;
195 }
196 }
197
198 public PhaseListener[] getPhaseListeners() {
199 synchronized (phaseListenerList) {
200
201 if (phaseListenerArray == null) {
202 phaseListenerArray = phaseListenerList.toArray(new PhaseListener[phaseListenerList.size()]);
203 }
204 return phaseListenerArray;
205 }
206 }
207 }