1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.lifecycle;
17
18 import java.util.Deque;
19 import java.util.HashMap;
20 import java.util.LinkedHashSet;
21 import java.util.LinkedList;
22 import java.util.Map;
23 import java.util.Set;
24
25 import org.apache.log4j.Logger;
26 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
27 import org.kuali.rice.krad.uif.component.Component;
28 import org.kuali.rice.krad.uif.freemarker.LifecycleRenderingContext;
29 import org.kuali.rice.krad.uif.util.LifecycleElement;
30 import org.kuali.rice.krad.uif.util.ProcessLogger;
31 import org.kuali.rice.krad.uif.view.DefaultExpressionEvaluator;
32 import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
33 import org.kuali.rice.krad.uif.view.ExpressionEvaluatorFactory;
34 import org.springframework.util.StringUtils;
35
36
37
38
39
40
41 public class SynchronousViewLifecycleProcessor extends ViewLifecycleProcessorBase {
42 private static final Logger LOG = Logger.getLogger(SynchronousViewLifecycleProcessor.class);
43
44
45 private final Deque<ViewLifecyclePhase> pendingPhases = new LinkedList<ViewLifecyclePhase>();
46
47
48 private ViewLifecyclePhase activePhase;
49
50
51 private LifecycleRenderingContext renderingContext;
52
53
54 private final ExpressionEvaluator expressionEvaluator;
55
56 private static String getTracePath(ViewLifecyclePhase phase) {
57 Component parent = phase.getParent();
58 if (parent == null) {
59 return "";
60 } else {
61 return phase.getParent().getViewPath();
62 }
63 }
64
65 private static final class TraceNode {
66 private final String path;
67 private StringBuilder buffer = new StringBuilder();
68 private Set<String> childPaths = new LinkedHashSet<String>();
69
70 private TraceNode(ViewLifecyclePhase phase) {
71 path = getTracePath(phase);
72 }
73
74 private void startTrace(ViewLifecyclePhase phase) {
75 try {
76 LifecycleElement element = phase.getElement();
77
78 String parentPath = phase.getParentPath();
79 if (StringUtils.hasLength(parentPath)) {
80 childPaths.add(phase.getParentPath());
81 }
82
83 buffer.append('\n');
84 for (int i = 0; i < phase.getDepth(); i++) {
85 buffer.append(" ");
86 }
87 buffer.append(phase.getViewPath());
88 buffer.append(' ');
89 buffer.append(phase.getEndViewStatus());
90 buffer.append(' ');
91 buffer.append(element.getViewStatus());
92 buffer.append(' ');
93 buffer.append(element.isRender());
94 buffer.append(' ');
95 buffer.append(element.getClass().getSimpleName());
96 buffer.append(' ');
97 buffer.append(element.getId());
98 buffer.append(' ');
99 } catch (Throwable e) {
100 LOG.warn("Error tracing lifecycle", e);
101 }
102 }
103
104 private void finishTrace(long phaseStartTime, Throwable error) {
105 if (error == null) {
106 buffer.append(" done ");
107 } else {
108 buffer.append(" ERROR ");
109 }
110 buffer.append(ProcessLogger.intervalToString(System.currentTimeMillis() - phaseStartTime));
111 }
112 }
113
114 private final Map<String, TraceNode> trace = ViewLifecycle.isTrace() ? new HashMap<String, TraceNode>() : null;
115
116 private TraceNode getTraceNode(ViewLifecyclePhase phase) {
117 if (trace == null) {
118 return null;
119 }
120
121 String tracePath = getTracePath(phase);
122 TraceNode traceNode = trace.get(tracePath);
123
124 if (traceNode == null) {
125 traceNode = new TraceNode(phase);
126 trace.put(tracePath, traceNode);
127 }
128
129 return traceNode;
130 }
131
132
133
134
135
136
137 public SynchronousViewLifecycleProcessor(ViewLifecycle lifecycle) {
138 super(lifecycle);
139
140
141
142 ExpressionEvaluatorFactory expressionEvaluatorFactory;
143 if (lifecycle.helper == null) {
144 LOG.warn("No helper is defined for the view lifecycle, using global expression evaluation factory");
145 expressionEvaluatorFactory = KRADServiceLocatorWeb.getExpressionEvaluatorFactory();
146 } else {
147 expressionEvaluatorFactory = lifecycle.helper.getExpressionEvaluatorFactory();
148 }
149
150 if (expressionEvaluatorFactory == null) {
151 LOG.warn("No global expression evaluation factory is defined, using DefaultExpressionEvaluator");
152 expressionEvaluator = new DefaultExpressionEvaluator();
153 } else {
154 expressionEvaluator = expressionEvaluatorFactory.createExpressionEvaluator();
155 }
156 }
157
158
159
160
161 @Override
162 public void offerPendingPhase(ViewLifecyclePhase pendingPhase) {
163 pendingPhases.offer(pendingPhase);
164 }
165
166
167
168
169 @Override
170 public void pushPendingPhase(ViewLifecyclePhase phase) {
171 pendingPhases.push(phase);
172 }
173
174
175
176
177 @Override
178 public void performPhase(ViewLifecyclePhase initialPhase) {
179 long startTime = System.currentTimeMillis();
180 TraceNode initialNode = getTraceNode(initialPhase);
181
182 offerPendingPhase(initialPhase);
183 while (!pendingPhases.isEmpty()) {
184 ViewLifecyclePhase pendingPhase = pendingPhases.poll();
185 long phaseStartTime = System.currentTimeMillis();
186
187 try {
188 if (trace != null) {
189 getTraceNode(pendingPhase).startTrace(pendingPhase);
190 }
191
192 pendingPhase.run();
193
194 if (trace != null) {
195 getTraceNode(pendingPhase).finishTrace(phaseStartTime, null);
196 }
197
198 } catch (Throwable e) {
199 if (trace != null) {
200 getTraceNode(pendingPhase).finishTrace(phaseStartTime, e);
201 }
202
203 if (e instanceof RuntimeException) {
204 throw (RuntimeException) e;
205 } else if (e instanceof Error) {
206 throw (Error) e;
207 } else {
208 throw new IllegalStateException(e);
209 }
210 }
211 }
212
213 if (trace != null) {
214 assert initialNode != null : initialPhase;
215 Deque<TraceNode> msgQueue = new LinkedList<TraceNode>();
216 StringBuilder msg = new StringBuilder();
217
218 msgQueue.push(initialNode);
219 while (!msgQueue.isEmpty()) {
220 TraceNode traceNode = msgQueue.pop();
221 assert traceNode != null : msg + " " + trace.keySet();
222 assert traceNode.buffer != null : traceNode.path;
223
224 msg.append(traceNode.buffer);
225
226 for (String childPath : traceNode.childPaths) {
227 TraceNode child = trace.get(traceNode.path + (traceNode.path.equals("") ? "" : ".") + childPath);
228 if (child != null) {
229 msgQueue.push(child);
230 }
231 }
232 }
233
234 LOG.info("Lifecycle phase processing completed in "
235 + ProcessLogger.intervalToString(System.currentTimeMillis() - startTime) + msg);
236 trace.clear();
237 }
238 }
239
240
241
242
243 @Override
244 public ViewLifecyclePhase getActivePhase() {
245 return activePhase;
246 }
247
248
249
250
251 public LifecycleRenderingContext getRenderingContext() {
252 if (renderingContext == null && ViewLifecycle.isRenderInLifecycle()) {
253 ViewLifecycle lifecycle = getLifecycle();
254 this.renderingContext = new LifecycleRenderingContext(lifecycle.model, lifecycle.request);
255 }
256
257 return this.renderingContext;
258 }
259
260
261
262
263 @Override
264 public ExpressionEvaluator getExpressionEvaluator() {
265 return this.expressionEvaluator;
266 }
267
268
269
270
271 @Override
272 void setActivePhase(ViewLifecyclePhase phase) {
273 if (activePhase != null && phase != null) {
274 throw new IllegalStateException("Another phase is already active on this lifecycle thread " + activePhase);
275 }
276
277 activePhase = phase;
278 }
279
280 }