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.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import javax.servlet.http.HttpServletRequest;
28
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.log4j.Logger;
33 import org.kuali.rice.core.api.CoreApiServiceLocator;
34 import org.kuali.rice.core.api.config.property.Config;
35 import org.kuali.rice.core.api.config.property.ConfigContext;
36 import org.kuali.rice.krad.datadictionary.validator.ValidationController;
37 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
38 import org.kuali.rice.krad.uif.UifConstants;
39 import org.kuali.rice.krad.uif.UifPropertyPaths;
40 import org.kuali.rice.krad.uif.component.Component;
41 import org.kuali.rice.krad.uif.container.Group;
42 import org.kuali.rice.krad.uif.freemarker.LifecycleRenderingContext;
43 import org.kuali.rice.krad.uif.service.ViewHelperService;
44 import org.kuali.rice.krad.uif.util.LifecycleElement;
45 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
46 import org.kuali.rice.krad.uif.view.DefaultExpressionEvaluator;
47 import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
48 import org.kuali.rice.krad.uif.view.ExpressionEvaluatorFactory;
49 import org.kuali.rice.krad.uif.view.View;
50 import org.kuali.rice.krad.util.KRADConstants;
51
52
53
54
55
56
57
58 public class ViewLifecycle implements Serializable {
59 private static Logger LOG = Logger.getLogger(ViewLifecycle.class);
60 private static final long serialVersionUID = -4767600614111642241L;
61
62 private static final ThreadLocal<ViewLifecycleProcessor> PROCESSOR = new ThreadLocal<ViewLifecycleProcessor>();
63
64 private static Boolean strict;
65 private static Boolean renderInLifecycle;
66 private static Boolean trace;
67
68 private final List<EventRegistration> eventRegistrations;
69 private final View view;
70
71 private final ComponentPostMetadata refreshComponentPostMetadata;
72
73 final ViewHelperService helper;
74
75 final Object model;
76
77 final HttpServletRequest request;
78 private ViewPostMetadata viewPostMetadata;
79
80 private Set<String> visitedIds;
81
82
83
84
85
86
87
88
89
90
91
92 private ViewLifecycle(View view, Object model, ComponentPostMetadata refreshComponentPostMetadata,
93 HttpServletRequest request) {
94 this.view = view;
95 this.model = model;
96 this.request = request;
97 this.refreshComponentPostMetadata = refreshComponentPostMetadata;
98 this.helper = view.getViewHelperService();
99 this.eventRegistrations = new ArrayList<EventRegistration>();
100 }
101
102
103
104
105
106
107
108
109
110 public static void encapsulateLifecycle(View view, Object model, HttpServletRequest request,
111 Runnable lifecycleProcess) {
112 encapsulateLifecycle(view, model, null, null, request, lifecycleProcess);
113 }
114
115
116
117
118
119
120 public static void encapsulateLifecycle(View view, Object model, ViewPostMetadata viewPostMetadata,
121 ComponentPostMetadata refreshComponentPostMetadata, HttpServletRequest request, Runnable lifecycleProcess) {
122 ViewLifecycleProcessor processor = PROCESSOR.get();
123 if (processor != null) {
124 throw new IllegalStateException("Another lifecycle is already active on this thread");
125 }
126
127 try {
128 ViewLifecycle viewLifecycle = new ViewLifecycle(view, model, refreshComponentPostMetadata, request);
129 processor = isAsynchronousLifecycle() ? new AsynchronousViewLifecycleProcessor(viewLifecycle) :
130 new SynchronousViewLifecycleProcessor(viewLifecycle);
131 PROCESSOR.set(processor);
132
133 if (viewPostMetadata != null) {
134 viewLifecycle.viewPostMetadata = viewPostMetadata;
135 }
136
137 lifecycleProcess.run();
138
139 } finally {
140 PROCESSOR.remove();
141 }
142 }
143
144
145
146
147
148
149
150
151
152
153 public static void preProcess(View view) {
154 encapsulateLifecycle(view, null, null, new ViewLifecyclePreProcessBuild());
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public static ViewPostMetadata buildView(View view, Object model, HttpServletRequest request,
181 final Map<String, String> parameters) {
182 ViewPostMetadata postMetadata = new ViewPostMetadata(view.getId());
183
184 ViewLifecycle.encapsulateLifecycle(view, model, postMetadata, null, request, new ViewLifecycleBuild(parameters,
185 null));
186
187
188 if (CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsBoolean(
189 UifConstants.VALIDATE_VIEWS_ONBUILD)) {
190 ValidationController validator = new ValidationController(true, true, true, true, false);
191 Log tempLogger = LogFactory.getLog(ViewLifecycle.class);
192 validator.validate(view, tempLogger, false);
193 }
194
195 return postMetadata;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 public static Component performComponentLifecycle(View view, Object model, HttpServletRequest request,
209 ViewPostMetadata viewPostMetadata, String componentId) {
210 ComponentPostMetadata componentPostMetadata = viewPostMetadata.getComponentPostMetadata(componentId);
211 if ((componentPostMetadata == null) || componentPostMetadata.isDetachedComponent()) {
212 if (componentPostMetadata == null) {
213 componentPostMetadata = viewPostMetadata.initializeComponentPostMetadata(componentId);
214 }
215
216 setupStandaloneComponentForRefresh(view, componentId, componentPostMetadata);
217 }
218
219 Map<String, List<String>> refreshPathMappings = componentPostMetadata.getRefreshPathMappings();
220
221 encapsulateLifecycle(view, model, viewPostMetadata, componentPostMetadata, request, new ViewLifecycleBuild(null,
222 refreshPathMappings));
223
224 return ObjectPropertyUtils.getPropertyValue(view, componentPostMetadata.getPath());
225 }
226
227
228
229
230
231
232
233
234
235
236 protected static void setupStandaloneComponentForRefresh(View view, String componentId,
237 ComponentPostMetadata componentPostMetadata) {
238 Component refreshComponent = (Component) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBean(
239 componentId);
240
241 if ((refreshComponent == null) || !(refreshComponent instanceof Group)) {
242 throw new RuntimeException("Refresh component was null or not a group instance");
243 }
244
245 List<Group> dialogs = new ArrayList<Group>();
246 if ((view.getDialogs() != null) && !view.getDialogs().isEmpty()) {
247 dialogs.addAll(view.getDialogs());
248 }
249
250 dialogs.add((Group) refreshComponent);
251 view.setDialogs(dialogs);
252
253 String refreshPath = UifPropertyPaths.DIALOGS + "[" + (view.getDialogs().size() - 1) + "]";
254 componentPostMetadata.setPath(refreshPath);
255
256 List<String> refreshPaths = new ArrayList<String>();
257 refreshPaths.add(refreshPath);
258
259 Map<String, List<String>> refreshPathMappings = new HashMap<String, List<String>>();
260
261 refreshPathMappings.put(UifConstants.ViewPhases.INITIALIZE, refreshPaths);
262 refreshPathMappings.put(UifConstants.ViewPhases.APPLY_MODEL, refreshPaths);
263 refreshPathMappings.put(UifConstants.ViewPhases.FINALIZE, refreshPaths);
264
265 componentPostMetadata.setRefreshPathMappings(refreshPathMappings);
266
267 componentPostMetadata.setDetachedComponent(true);
268 }
269
270
271
272
273
274
275
276 public static boolean isRefreshComponent(String viewPhase, String viewPath) {
277 if (!ViewLifecycle.isRefreshLifecycle()) {
278 return false;
279 }
280
281 return StringUtils.equals(getRefreshComponentPhasePath(viewPhase), viewPath);
282 }
283
284
285
286
287
288
289
290 public static String getRefreshComponentPhasePath(String viewPhase) {
291 if (!ViewLifecycle.isRefreshLifecycle()) {
292 return null;
293 }
294
295 ComponentPostMetadata refreshComponentPostMetadata = ViewLifecycle.getRefreshComponentPostMetadata();
296 if (refreshComponentPostMetadata == null) {
297 return null;
298 }
299
300 String refreshPath = refreshComponentPostMetadata.getPath();
301 if (refreshComponentPostMetadata.getPhasePathMapping() != null) {
302 Map<String, String> phasePathMapping = refreshComponentPostMetadata.getPhasePathMapping();
303
304
305
306 if (phasePathMapping.containsKey(viewPhase)) {
307 refreshPath = phasePathMapping.get(viewPhase);
308 }
309 }
310
311 return refreshPath;
312 }
313
314
315
316
317
318
319
320
321
322
323 public void invokeEventListeners(LifecycleEvent event, View view, Object model, LifecycleElement eventElement) {
324 synchronized (eventRegistrations) {
325 for (EventRegistration registration : eventRegistrations) {
326 if (registration.getEvent().equals(event) && (registration.getEventComponent() == eventElement)) {
327 registration.getEventListener().processEvent(event, view, model, eventElement);
328 }
329 }
330 }
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349 public void registerLifecycleCompleteListener(Component eventComponent, LifecycleEventListener listenerComponent) {
350 EventRegistration eventRegistration = new EventRegistration(LifecycleEvent.LIFECYCLE_COMPLETE, eventComponent,
351 listenerComponent);
352
353 synchronized (eventRegistrations) {
354 eventRegistrations.add(eventRegistration);
355 }
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376 public static boolean isStrict() {
377 if (strict == null) {
378 strict = ConfigContext.getCurrentContextConfig().getBooleanProperty(
379 KRADConstants.ConfigParameters.KRAD_STRICT_LIFECYCLE, false);
380 }
381
382 return strict;
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396 public static boolean isRenderInLifecycle() {
397 if (renderInLifecycle == null) {
398 renderInLifecycle = ConfigContext.getCurrentContextConfig().getBooleanProperty(
399 KRADConstants.ConfigParameters.KRAD_RENDER_IN_LIFECYCLE, false);
400 }
401
402 return renderInLifecycle;
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416 public static boolean isAsynchronousLifecycle() {
417 Config config = ConfigContext.getCurrentContextConfig();
418 return config != null && config.getBooleanProperty(
419 KRADConstants.ConfigParameters.KRAD_VIEW_LIFECYCLE_ASYNCHRONOUS, false);
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436 public static boolean isTrace() {
437 if (trace == null) {
438 Config config = ConfigContext.getCurrentContextConfig();
439 if (config == null) {
440 return false;
441 }
442
443 trace = config.getBooleanProperty(KRADConstants.ConfigParameters.KRAD_VIEW_LIFECYCLE_TRACE, false);
444 }
445
446 return trace;
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460 public static void reportIllegalState(String message) {
461 reportIllegalState(message, null);
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475
476 public static void reportIllegalState(String message, Throwable cause) {
477 IllegalStateException illegalState = new IllegalStateException(message + "\nPhase: " + ViewLifecycle.getPhase(),
478 cause);
479
480 if (ViewLifecycle.isStrict()) {
481 throw illegalState;
482 } else {
483 LOG.warn(illegalState.getMessage(), illegalState);
484 }
485 }
486
487
488
489
490
491
492 public static ViewHelperService getHelper() {
493 ViewLifecycle active = getActiveLifecycle();
494
495 if (active.helper == null) {
496 throw new IllegalStateException("Context view helper is not available");
497 }
498
499 return active.helper;
500 }
501
502
503
504
505
506
507 public static View getView() {
508 ViewLifecycle active = getActiveLifecycle();
509
510 if (active.view == null) {
511 throw new IllegalStateException("Context view is not available");
512 }
513
514 return active.view;
515 }
516
517
518
519
520
521
522
523
524
525
526
527
528 public static ExpressionEvaluator getExpressionEvaluator() {
529 ViewLifecycleProcessor processor = PROCESSOR.get();
530
531 if (processor == null) {
532 ExpressionEvaluatorFactory expressionEvaluatorFactory =
533 KRADServiceLocatorWeb.getExpressionEvaluatorFactory();
534
535 if (expressionEvaluatorFactory == null) {
536 return new DefaultExpressionEvaluator();
537 } else {
538 return expressionEvaluatorFactory.createExpressionEvaluator();
539 }
540 }
541
542 return processor.getExpressionEvaluator();
543 }
544
545
546
547
548
549
550 public static Object getModel() {
551 ViewLifecycle active = getActiveLifecycle();
552
553 if (active.model == null) {
554 throw new IllegalStateException("Model is not available");
555 }
556
557 return active.model;
558 }
559
560
561
562
563
564
565 public static Set<String> getVisitedIds() {
566 ViewLifecycle active = getActiveLifecycle();
567
568 if (active.visitedIds == null) {
569 synchronized (active) {
570 if (active.visitedIds == null) {
571 active.visitedIds = Collections.synchronizedSet(new HashSet<String>());
572 }
573 }
574 }
575
576 return active.visitedIds;
577 }
578
579
580
581
582
583
584 public static ViewPostMetadata getViewPostMetadata() {
585 ViewLifecycle active = getActiveLifecycle();
586
587 if (active.model == null) {
588 throw new IllegalStateException("Post Metadata is not available");
589 }
590
591 return active.viewPostMetadata;
592 }
593
594
595
596
597
598
599
600
601 public static ComponentPostMetadata getRefreshComponentPostMetadata() {
602 ViewLifecycle active = getActiveLifecycle();
603
604 if (active == null) {
605 throw new IllegalStateException("No lifecycle is active");
606 }
607
608 return active.refreshComponentPostMetadata;
609 }
610
611
612
613
614
615
616 public static boolean isRefreshLifecycle() {
617 ViewLifecycle active = getActiveLifecycle();
618
619 if (active == null) {
620 throw new IllegalStateException("No lifecycle is active");
621 }
622
623 return (active.refreshComponentPostMetadata != null);
624 }
625
626
627
628
629
630
631 public static HttpServletRequest getRequest() {
632 ViewLifecycle active = getActiveLifecycle();
633
634 if (active.model == null) {
635 throw new IllegalStateException("Request is not available");
636 }
637
638 return active.request;
639 }
640
641
642
643
644
645
646 public static ViewLifecyclePhase getPhase() {
647 ViewLifecycleProcessor processor = PROCESSOR.get();
648 try {
649 return processor == null ? null : processor.getActivePhase();
650 } catch (IllegalStateException e) {
651 LOG.debug("No lifecycle phase is active on the current processor", e);
652 return null;
653 }
654 }
655
656
657
658
659
660
661 public static LifecycleRenderingContext getRenderingContext() {
662 ViewLifecycleProcessor processor = PROCESSOR.get();
663 return processor == null ? null : processor.getRenderingContext();
664 }
665
666
667
668
669
670
671 public static ViewLifecycleProcessor getProcessor() {
672 ViewLifecycleProcessor processor = PROCESSOR.get();
673
674 if (processor == null) {
675 throw new IllegalStateException("No view lifecycle is active on this thread");
676 }
677
678 return processor;
679 }
680
681
682
683
684
685
686
687
688
689
690
691
692
693 static void setProcessor(ViewLifecycleProcessor processor) {
694 ViewLifecycleProcessor active = PROCESSOR.get();
695
696 if (active != null && processor != null) {
697 throw new IllegalStateException("Another lifecycle processor is already active on this thread");
698 }
699
700 if (processor == null) {
701 PROCESSOR.remove();
702 } else {
703 PROCESSOR.set(processor);
704 }
705 }
706
707
708
709
710
711
712 public static ViewLifecycle getActiveLifecycle() {
713 return getProcessor().getLifecycle();
714 }
715
716
717
718
719
720
721 public static boolean isActive() {
722 return PROCESSOR.get() != null;
723 }
724
725
726
727
728 public static enum LifecycleEvent {
729
730
731 LIFECYCLE_COMPLETE
732 }
733
734
735
736
737 protected class EventRegistration implements Serializable {
738 private static final long serialVersionUID = -5077429381388641016L;
739
740
741 private LifecycleEvent event;
742
743
744 private Component eventComponent;
745
746
747 private LifecycleEventListener eventListener;
748
749
750
751
752
753
754
755
756 private EventRegistration(LifecycleEvent event, Component eventComponent,
757 LifecycleEventListener eventListener) {
758 this.event = event;
759 this.eventComponent = eventComponent;
760 this.eventListener = eventListener;
761 }
762
763
764
765
766
767
768
769 public LifecycleEvent getEvent() {
770 return event;
771 }
772
773
774
775
776
777
778 public Component getEventComponent() {
779 return eventComponent;
780 }
781
782
783
784
785
786
787 public LifecycleEventListener getEventListener() {
788 return eventListener;
789 }
790
791
792
793
794
795
796
797 public void setEvent(LifecycleEvent event) {
798 this.event = event;
799 }
800
801
802
803
804
805
806
807 public void setEventComponent(Component eventComponent) {
808 this.eventComponent = eventComponent;
809 }
810
811
812
813
814
815
816
817 public void setEventListener(LifecycleEventListener eventListener) {
818 this.eventListener = eventListener;
819 }
820 }
821
822 }