1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.exception.RiceRuntimeException;
20 import org.kuali.rice.kim.api.identity.Person;
21 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
22 import org.kuali.rice.krad.datadictionary.AttributeDefinition;
23 import org.kuali.rice.krad.inquiry.Inquirable;
24 import org.kuali.rice.krad.service.DataDictionaryService;
25 import org.kuali.rice.krad.service.KRADServiceLocator;
26 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
27 import org.kuali.rice.krad.service.ModuleService;
28 import org.kuali.rice.krad.uif.UifConstants;
29 import org.kuali.rice.krad.uif.component.ComponentSecurity;
30 import org.kuali.rice.krad.uif.container.Group;
31 import org.kuali.rice.krad.uif.field.ActionField;
32 import org.kuali.rice.krad.uif.field.FieldGroup;
33 import org.kuali.rice.krad.uif.view.ViewAuthorizer;
34 import org.kuali.rice.krad.uif.view.ViewPresentationController;
35 import org.kuali.rice.krad.uif.component.BindingInfo;
36 import org.kuali.rice.krad.uif.component.ClientSideState;
37 import org.kuali.rice.krad.uif.component.Component;
38 import org.kuali.rice.krad.uif.component.DataBinding;
39 import org.kuali.rice.krad.uif.component.PropertyReplacer;
40 import org.kuali.rice.krad.uif.component.RequestParameter;
41 import org.kuali.rice.krad.uif.container.CollectionGroup;
42 import org.kuali.rice.krad.uif.container.Container;
43 import org.kuali.rice.krad.uif.control.Control;
44 import org.kuali.rice.krad.uif.field.DataField;
45 import org.kuali.rice.krad.uif.field.InputField;
46 import org.kuali.rice.krad.uif.field.Field;
47 import org.kuali.rice.krad.uif.field.RemoteFieldsHolder;
48 import org.kuali.rice.krad.uif.layout.LayoutManager;
49 import org.kuali.rice.krad.uif.modifier.ComponentModifier;
50 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
51 import org.kuali.rice.krad.uif.service.ViewDictionaryService;
52 import org.kuali.rice.krad.uif.service.ViewHelperService;
53 import org.kuali.rice.krad.uif.util.BooleanMap;
54 import org.kuali.rice.krad.uif.util.CloneUtils;
55 import org.kuali.rice.krad.uif.util.ComponentFactory;
56 import org.kuali.rice.krad.uif.util.ComponentUtils;
57 import org.kuali.rice.krad.uif.util.ExpressionUtils;
58 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
59 import org.kuali.rice.krad.uif.util.ScriptUtils;
60 import org.kuali.rice.krad.uif.util.ViewModelUtils;
61 import org.kuali.rice.krad.uif.view.View;
62 import org.kuali.rice.krad.uif.view.ViewModel;
63 import org.kuali.rice.krad.uif.widget.Inquiry;
64 import org.kuali.rice.krad.uif.widget.Widget;
65 import org.kuali.rice.krad.util.GlobalVariables;
66 import org.kuali.rice.krad.util.KRADConstants;
67 import org.kuali.rice.krad.util.ObjectUtils;
68 import org.kuali.rice.krad.valuefinder.ValueFinder;
69 import org.kuali.rice.krad.web.form.UifFormBase;
70 import org.springframework.util.MethodInvoker;
71
72 import java.io.Serializable;
73 import java.lang.annotation.Annotation;
74 import java.util.ArrayList;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.HashMap;
78 import java.util.HashSet;
79 import java.util.List;
80 import java.util.Map;
81 import java.util.Map.Entry;
82 import java.util.Set;
83
84
85
86
87
88
89 public class ViewHelperServiceImpl implements ViewHelperService, Serializable {
90 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ViewHelperServiceImpl.class);
91
92 private transient DataDictionaryService dataDictionaryService;
93 private transient ExpressionEvaluatorService expressionEvaluatorService;
94 private transient ViewDictionaryService viewDictionaryService;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 @Override
111 public void populateViewFromRequestParameters(View view, Map<String, String> parameters) {
112
113
114 Map<String, Set<PropertyReplacer>> viewPropertyReplacers = new HashMap<String, Set<PropertyReplacer>>();
115 for (PropertyReplacer replacer : view.getPropertyReplacers()) {
116 Set<PropertyReplacer> propertyReplacers = new HashSet<PropertyReplacer>();
117 if (viewPropertyReplacers.containsKey(replacer.getPropertyName())) {
118 propertyReplacers = viewPropertyReplacers.get(replacer.getPropertyName());
119 }
120 propertyReplacers.add(replacer);
121
122 viewPropertyReplacers.put(replacer.getPropertyName(), propertyReplacers);
123 }
124
125 Map<String, Annotation> annotatedFields = CloneUtils.getFieldsWithAnnotation(view.getClass(),
126 RequestParameter.class);
127
128
129
130 Map<String, String> viewRequestParameters = new HashMap<String, String>();
131 for (String fieldToPopulate : annotatedFields.keySet()) {
132 RequestParameter requestParameter = (RequestParameter) annotatedFields.get(fieldToPopulate);
133
134
135 String requestParameterName = requestParameter.parameterName();
136 if (StringUtils.isBlank(requestParameterName)) {
137 requestParameterName = fieldToPopulate;
138 }
139
140 if (!parameters.containsKey(requestParameterName)) {
141 continue;
142 }
143
144 String fieldValue = parameters.get(requestParameterName);
145 if (StringUtils.isNotBlank(fieldValue)) {
146 viewRequestParameters.put(requestParameterName, fieldValue);
147 ObjectPropertyUtils.setPropertyValue(view, fieldToPopulate, fieldValue);
148
149
150
151 if (view.getPropertyExpressions().containsKey(fieldToPopulate)) {
152 view.getPropertyExpressions().remove(fieldToPopulate);
153 }
154
155 if (viewPropertyReplacers.containsKey(fieldToPopulate)) {
156 Set<PropertyReplacer> propertyReplacers = viewPropertyReplacers.get(fieldToPopulate);
157 for (PropertyReplacer replacer : propertyReplacers) {
158 view.getPropertyReplacers().remove(replacer);
159 }
160 }
161 }
162 }
163
164 view.setViewRequestParameters(viewRequestParameters);
165 }
166
167
168
169
170
171 @Override
172 public void performInitialization(View view, Object model) {
173 view.assignComponentIds(view);
174 performComponentInitialization(view, model, view);
175 }
176
177
178
179
180
181
182
183
184
185
186
187
188
189 public void performComponentLifecycle(View view, Object model, Component component, String origId) {
190 Component origComponent = view.getViewIndex().getComponentById(origId);
191
192 Component parent = (Component) origComponent.getContext().get(UifConstants.ContextVariableNames.PARENT);
193 component.pushAllToContext(origComponent.getContext());
194
195
196 String suffix = StringUtils.replaceOnce(origComponent.getId(), origComponent.getFactoryId(), "");
197
198 if (suffix.endsWith(UifConstants.IdSuffixes.ATTRIBUTE)) {
199 suffix = StringUtils.removeEnd(suffix, UifConstants.IdSuffixes.ATTRIBUTE);
200 }
201 ComponentUtils.updateIdWithSuffix(component, suffix);
202
203
204 if (component instanceof DataBinding) {
205 ((DataBinding) component).setBindingInfo(((DataBinding) origComponent).getBindingInfo());
206 ((DataBinding) component).getBindingInfo().setBindingPath(
207 ((DataBinding) origComponent).getBindingInfo().getBindingPath());
208 }
209
210
211 if (component instanceof Field) {
212 ((Field) component).setLabelFieldRendered(((Field) origComponent).isLabelFieldRendered());
213 } else if (component instanceof CollectionGroup) {
214 ((CollectionGroup) component).setSubCollectionSuffix(
215 ((CollectionGroup) origComponent).getSubCollectionSuffix());
216 }
217
218
219 if (component.isResetDataOnRefresh()) {
220
221 if (component instanceof DataField) {
222
223
224
225 ObjectPropertyUtils.initializeProperty(model,
226 ((DataField) component).getBindingInfo().getBindingPath());
227 }
228 }
229
230 performComponentInitialization(view, model, component);
231 performComponentApplyModel(view, component, model);
232
233
234 if (component instanceof Group || component instanceof FieldGroup) {
235 List<Component> nestedComponents = ComponentUtils.getAllNestedComponents(component);
236 for (Component nestedComponent : nestedComponents) {
237 Component origNestedComponent = null;
238 if (nestedComponent instanceof DataField) {
239 origNestedComponent = view.getViewIndex().getComponentById(
240 nestedComponent.getId() + suffix + UifConstants.IdSuffixes.ATTRIBUTE);
241 } else {
242 origNestedComponent = view.getViewIndex().getComponentById(nestedComponent.getId() + suffix);
243 }
244
245 if (origNestedComponent != null) {
246
247 if (nestedComponent instanceof DataBinding) {
248 ((DataBinding) nestedComponent).setBindingInfo(
249 ((DataBinding) origNestedComponent).getBindingInfo());
250 ((DataBinding) nestedComponent).getBindingInfo().setBindingPath(
251 ((DataBinding) origNestedComponent).getBindingInfo().getBindingPath());
252 }
253
254
255 if (nestedComponent instanceof Field) {
256 ((Field) nestedComponent).setLabelFieldRendered(
257 ((Field) origNestedComponent).isLabelFieldRendered());
258 }
259
260
261 ComponentUtils.updateIdWithSuffix(nestedComponent, suffix);
262 }
263 }
264 }
265
266
267 Map<String, Object> clientState = new HashMap<String, Object>();
268 performComponentFinalize(view, component, model, parent, clientState);
269
270
271 String clientStateScript = buildClientSideStateScript(view, clientState, true);
272 String onLoadScript = component.getOnLoadScript();
273 if (StringUtils.isNotBlank(onLoadScript)) {
274 clientStateScript = onLoadScript + clientStateScript;
275 }
276 component.setOnLoadScript(clientStateScript);
277
278
279 view.getViewIndex().indexComponent(component);
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 public void performComponentInitialization(View view, Object model, Component component) {
308 if (component == null) {
309 return;
310 }
311
312 if (StringUtils.isBlank(component.getId()) || StringUtils.isBlank(component.getFactoryId())) {
313 throw new RiceRuntimeException("Ids are not set, this should happen unless a component is misconfigured");
314 }
315
316
317
318 LOG.debug("Initializing component: " + component.getId() + " with type: " + component.getClass());
319
320
321 component.performInitialization(view, model);
322
323
324 if (component instanceof DataField) {
325 initializeDataFieldFromDataDictionary(view, (DataField) component);
326 }
327
328
329 view.getViewIndex().addInitialComponentState(component);
330
331 if (component instanceof Container) {
332 LayoutManager layoutManager = ((Container) component).getLayoutManager();
333
334
335 addCustomContainerComponents(view, model, (Container) component);
336
337
338
339 if (!(component instanceof CollectionGroup)) {
340 processAnyRemoteFieldsHolder(view, model, (Container) component);
341 }
342 }
343
344
345 if (component instanceof CollectionGroup) {
346
347 }
348
349
350 runComponentModifiers(view, component, null, UifConstants.ViewPhases.INITIALIZE);
351
352
353 for (Component nestedComponent : component.getComponentsForLifecycle()) {
354 performComponentInitialization(view, model, nestedComponent);
355 }
356
357
358 for (PropertyReplacer replacer : component.getPropertyReplacers()) {
359 for (Component replacerComponent : replacer.getNestedComponents()) {
360 performComponentInitialization(view, model, replacerComponent);
361 }
362 }
363
364
365 performCustomInitialization(view, component);
366 }
367
368
369
370
371
372
373
374
375
376
377 protected void processAnyRemoteFieldsHolder(View view, Object model, Container container) {
378 List<Component> processedItems = new ArrayList<Component>();
379
380
381
382 for (Component item : container.getItems()) {
383 if (item instanceof RemoteFieldsHolder) {
384 List<InputField> translatedFields = ((RemoteFieldsHolder) item).fetchAndTranslateRemoteFields(view,
385 model, container);
386 processedItems.addAll(translatedFields);
387 } else {
388 processedItems.add(item);
389 }
390 }
391
392
393 container.setItems(processedItems);
394 }
395
396
397
398
399
400
401
402
403 protected void initializeDataFieldFromDataDictionary(View view, DataField field) {
404 AttributeDefinition attributeDefinition = null;
405
406 String dictionaryAttributeName = field.getDictionaryAttributeName();
407 String dictionaryObjectEntry = field.getDictionaryObjectEntry();
408
409
410
411 if (StringUtils.isNotBlank(dictionaryObjectEntry) && StringUtils.isBlank(dictionaryAttributeName)) {
412 dictionaryAttributeName = field.getPropertyName();
413 }
414
415
416 if (StringUtils.isNotBlank(dictionaryAttributeName) && StringUtils.isNotBlank(dictionaryObjectEntry)) {
417 attributeDefinition = getDataDictionaryService().getAttributeDefinition(dictionaryObjectEntry,
418 dictionaryAttributeName);
419 }
420
421
422 if (attributeDefinition == null) {
423 String propertyPath = field.getBindingInfo().getBindingPath();
424 if (StringUtils.isNotBlank(field.getBindingInfo().getCollectionPath())) {
425 propertyPath = field.getBindingInfo().getCollectionPath();
426 if (StringUtils.isNotBlank(field.getBindingInfo().getBindByNamePrefix())) {
427 propertyPath += "." + field.getBindingInfo().getBindByNamePrefix();
428 }
429 propertyPath += "." + field.getBindingInfo().getBindingName();
430 }
431
432 attributeDefinition = findNestedDictionaryAttribute(view, field, null, propertyPath);
433 }
434
435
436 if (attributeDefinition != null) {
437 field.copyFromAttributeDefinition(view, attributeDefinition);
438 }
439
440
441 if (field instanceof InputField) {
442 InputField inputField = (InputField) field;
443 if (inputField.getControl() == null) {
444 Control control = ComponentFactory.getTextControl();
445 control.setId(view.getNextId());
446 control.setFactoryId(control.getId());
447
448 inputField.setControl(control);
449 }
450 }
451 }
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478 protected AttributeDefinition findNestedDictionaryAttribute(View view, DataField field, String parentPath,
479 String propertyPath) {
480 AttributeDefinition attributeDefinition = null;
481
482
483 String dictionaryAttributeName = propertyPath;
484 String dictionaryObjectEntry = null;
485
486 if (field.getBindingInfo().isBindToMap()) {
487 parentPath = "";
488 if (!field.getBindingInfo().isBindToForm() && StringUtils.isNotBlank(
489 field.getBindingInfo().getBindingObjectPath())) {
490 parentPath = field.getBindingInfo().getBindingObjectPath();
491 }
492 if (StringUtils.isNotBlank(field.getBindingInfo().getBindByNamePrefix())) {
493 if (StringUtils.isNotBlank(parentPath)) {
494 parentPath += "." + field.getBindingInfo().getBindByNamePrefix();
495 } else {
496 parentPath = field.getBindingInfo().getBindByNamePrefix();
497 }
498 }
499
500 dictionaryAttributeName = field.getBindingInfo().getBindingName();
501 }
502
503 if (StringUtils.isNotBlank(parentPath)) {
504 Class<?> dictionaryModelClass = ViewModelUtils.getPropertyTypeByClassAndView(view, parentPath);
505 if (dictionaryModelClass != null) {
506 dictionaryObjectEntry = dictionaryModelClass.getName();
507
508 attributeDefinition = getDataDictionaryService().getAttributeDefinition(dictionaryObjectEntry,
509 dictionaryAttributeName);
510 }
511 }
512
513
514
515 if ((attributeDefinition == null) && StringUtils.contains(propertyPath, ".")) {
516 String nextParentPath = StringUtils.substringBefore(propertyPath, ".");
517 if (StringUtils.isNotBlank(parentPath)) {
518 nextParentPath = parentPath + "." + nextParentPath;
519 }
520 String nextPropertyPath = StringUtils.substringAfter(propertyPath, ".");
521
522 return findNestedDictionaryAttribute(view, field, nextParentPath, nextPropertyPath);
523 }
524
525
526 if (attributeDefinition != null) {
527 field.setDictionaryAttributeName(dictionaryAttributeName);
528 field.setDictionaryObjectEntry(dictionaryObjectEntry);
529 }
530
531 return attributeDefinition;
532 }
533
534
535
536
537
538 @Override
539 public void performApplyModel(View view, Object model) {
540
541 retrieveEditModesAndActionFlags(view, (UifFormBase) model);
542
543
544 setViewContext(view, model);
545
546 performComponentApplyModel(view, view, model);
547 }
548
549
550
551
552
553
554
555
556
557 protected void retrieveEditModesAndActionFlags(View view, UifFormBase model) {
558 ViewPresentationController presentationController = view.getPresentationController();
559 ViewAuthorizer authorizer = view.getAuthorizer();
560
561 Person user = GlobalVariables.getUserSession().getPerson();
562
563 Set<String> actionFlags = presentationController.getActionFlags(view, model);
564 actionFlags = authorizer.getActionFlags(view, model, user, actionFlags);
565
566 view.setActionFlags(new BooleanMap(actionFlags));
567
568 Set<String> editModes = presentationController.getEditModes(view, model);
569 editModes = authorizer.getEditModes(view, model, user, editModes);
570
571 view.setEditModes(new BooleanMap(editModes));
572 }
573
574
575
576
577
578
579
580
581 protected void setViewContext(View view, Object model) {
582 view.pushAllToContext(getPreModelContext(view));
583
584
585 for (Entry<String, String> variableExpression : view.getExpressionVariables().entrySet()) {
586 String variableName = variableExpression.getKey();
587 Object value = getExpressionEvaluatorService().evaluateExpression(model, view.getContext(),
588 variableExpression.getValue());
589 view.pushObjectToContext(variableName, value);
590 }
591 }
592
593
594
595
596
597
598
599
600 protected Map<String, Object> getPreModelContext(View view) {
601 Map<String, Object> context = new HashMap<String, Object>();
602
603 context.put(UifConstants.ContextVariableNames.VIEW, view);
604 context.put(UifConstants.ContextVariableNames.VIEW_HELPER, this);
605
606 Map<String, String> properties = KRADServiceLocator.getKualiConfigurationService().getAllProperties();
607 context.put(UifConstants.ContextVariableNames.CONFIG_PROPERTIES, properties);
608 context.put(UifConstants.ContextVariableNames.CONSTANTS, KRADConstants.class);
609
610 return context;
611 }
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628 protected void performComponentApplyModel(View view, Component component, Object model) {
629 if (component == null) {
630 return;
631 }
632
633
634 component.pushAllToContext(getCommonContext(view, component));
635 ExpressionUtils.adjustPropertyExpressions(view, component);
636 getExpressionEvaluatorService().evaluateObjectExpressions(component, model, component.getContext());
637
638
639 ComponentSecurity componentSecurity = component.getComponentSecurity();
640 ExpressionUtils.adjustPropertyExpressions(view, componentSecurity);
641 getExpressionEvaluatorService().evaluateObjectExpressions(componentSecurity, model, component.getContext());
642
643
644 if (component instanceof DataBinding) {
645 BindingInfo bindingInfo = ((DataBinding) component).getBindingInfo();
646 ExpressionUtils.adjustPropertyExpressions(view, bindingInfo);
647 getExpressionEvaluatorService().evaluateObjectExpressions(bindingInfo, model, component.getContext());
648 }
649
650
651 if (component instanceof Container) {
652 LayoutManager layoutManager = ((Container) component).getLayoutManager();
653
654 if (layoutManager != null) {
655 layoutManager.getContext().putAll(getCommonContext(view, component));
656 layoutManager.pushObjectToContext(UifConstants.ContextVariableNames.PARENT, component);
657 layoutManager.pushObjectToContext(UifConstants.ContextVariableNames.MANAGER, layoutManager);
658
659 ExpressionUtils.adjustPropertyExpressions(view, layoutManager);
660 getExpressionEvaluatorService().evaluateObjectExpressions(layoutManager, model,
661 layoutManager.getContext());
662 }
663 }
664
665
666 syncClientSideStateForComponent(component, ((ViewModel) model).getClientStateForSyncing());
667
668
669 applyAuthorizationAndPresentationLogic(view, component, (ViewModel) model);
670
671
672 Component parent = (Component) component.getContext().get(UifConstants.ContextVariableNames.PARENT);
673 component.performApplyModel(view, model, parent);
674
675
676 performCustomApplyModel(view, component, model);
677
678
679 runComponentModifiers(view, component, model, UifConstants.ViewPhases.APPLY_MODEL);
680
681
682 for (Component nestedComponent : component.getComponentsForLifecycle()) {
683 if (nestedComponent != null) {
684 nestedComponent.pushObjectToContext(UifConstants.ContextVariableNames.PARENT, component);
685 }
686
687 performComponentApplyModel(view, nestedComponent, model);
688 }
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 protected void applyAuthorizationAndPresentationLogic(View view, Component component, ViewModel model) {
713 ViewPresentationController presentationController = view.getPresentationController();
714 ViewAuthorizer authorizer = view.getAuthorizer();
715
716 Person user = GlobalVariables.getUserSession().getPerson();
717
718
719 if (!component.isRender()) {
720 return;
721 }
722
723
724 if (component instanceof View) {
725 if (!view.isReadOnly()) {
726 boolean canEditView = authorizer.canEditView(view, model, user);
727 if (canEditView) {
728 canEditView = presentationController.canEditView(view, model);
729 }
730 view.setReadOnly(!canEditView);
731 }
732 }
733
734
735 else if (component instanceof Group) {
736 Group group = (Group) component;
737
738
739 if (!group.isHidden()) {
740 boolean canViewGroup = authorizer.canViewGroup(view, model, group, group.getId(), user);
741 if (canViewGroup) {
742 canViewGroup = presentationController.canViewGroup(view, model, group, group.getId());
743 }
744 group.setHidden(!canViewGroup);
745 group.setRender(canViewGroup);
746 }
747
748
749 if (!group.isReadOnly()) {
750 boolean canEditGroup = authorizer.canEditGroup(view, model, group, group.getId(), user);
751 if (canEditGroup) {
752 canEditGroup = presentationController.canEditGroup(view, model, group, group.getId());
753 }
754 group.setReadOnly(!canEditGroup);
755 }
756 }
757
758
759 else if (component instanceof Field) {
760 Field field = (Field) component;
761
762 String propertyName = null;
763 if (field instanceof DataBinding) {
764 propertyName = ((DataBinding) field).getPropertyName();
765 }
766
767
768 if (!field.isHidden()) {
769 boolean canViewField = authorizer.canViewField(view, model, field, propertyName, user);
770 if (canViewField) {
771 canViewField = presentationController.canViewField(view, model, field, propertyName);
772 }
773 field.setHidden(!canViewField);
774 field.setRender(canViewField);
775 }
776
777
778 if (!field.isReadOnly()) {
779
780 boolean canEditField = authorizer.canEditField(view, model, field, propertyName, user);
781 if (canEditField) {
782 canEditField = presentationController.canEditField(view, model, field, propertyName);
783 }
784 field.setReadOnly(!canEditField);
785 }
786
787
788 if ((field.getRequired() == null) || !field.getRequired().booleanValue()) {
789 boolean fieldIsRequired = presentationController.fieldIsRequired(view, model, field, propertyName);
790 }
791
792 if (field instanceof DataField) {
793 DataField dataField = (DataField) field;
794
795
796 boolean canUnmaskValue = authorizer.canUnmaskField(view, model, dataField, dataField.getPropertyName(),
797 user);
798 if (!canUnmaskValue) {
799 dataField.setApplyValueMask(true);
800 dataField.setMaskFormatter(dataField.getComponentSecurity().getAttributeSecurity().
801 getMaskFormatter());
802 } else {
803
804 boolean canPartiallyUnmaskValue = authorizer.canPartialUnmaskField(view, model, dataField,
805 dataField.getPropertyName(), user);
806 if (!canPartiallyUnmaskValue) {
807 dataField.setApplyValueMask(true);
808 dataField.setMaskFormatter(
809 dataField.getComponentSecurity().getAttributeSecurity().getPartialMaskFormatter());
810 }
811 }
812 }
813
814
815 if (field instanceof ActionField) {
816 ActionField actionField = (ActionField) field;
817
818 boolean canTakeAction = authorizer.canPerformAction(view, model, actionField,
819 actionField.getActionEvent(), actionField.getId(), user);
820 if (canTakeAction) {
821 canTakeAction = presentationController.canPerformAction(view, model, actionField,
822 actionField.getActionEvent(), actionField.getId());
823 }
824 actionField.setRender(canTakeAction);
825 }
826 }
827
828
829 else if (component instanceof Widget) {
830 Widget widget = (Widget) component;
831
832
833 if (!widget.isHidden()) {
834 boolean canViewWidget = authorizer.canViewWidget(view, model, widget, widget.getId(), user);
835 if (canViewWidget) {
836 canViewWidget = presentationController.canViewWidget(view, model, widget, widget.getId());
837 }
838 widget.setHidden(!canViewWidget);
839 widget.setRender(canViewWidget);
840 }
841
842
843 if (!widget.isReadOnly()) {
844 boolean canEditWidget = authorizer.canEditWidget(view, model, widget, widget.getId(), user);
845 if (canEditWidget) {
846 canEditWidget = presentationController.canEditWidget(view, model, widget, widget.getId());
847 }
848 widget.setReadOnly(!canEditWidget);
849 }
850 }
851 }
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868 protected void runComponentModifiers(View view, Component component, Object model, String runPhase) {
869 for (ComponentModifier modifier : component.getComponentModifiers()) {
870
871 if (StringUtils.equals(runPhase, UifConstants.ViewPhases.INITIALIZE)) {
872 modifier.performInitialization(view, model, component);
873 }
874
875
876 if (StringUtils.equals(modifier.getRunPhase(), runPhase)) {
877
878 boolean runModifier = true;
879 if (StringUtils.isNotBlank(modifier.getRunCondition())) {
880 Map<String, Object> context = new HashMap<String, Object>();
881 context.put(UifConstants.ContextVariableNames.COMPONENT, component);
882 context.put(UifConstants.ContextVariableNames.VIEW, view);
883
884 String conditionEvaluation = getExpressionEvaluatorService().evaluateExpressionTemplate(model,
885 context, modifier.getRunCondition());
886 runModifier = Boolean.parseBoolean(conditionEvaluation);
887 }
888
889 if (runModifier) {
890 modifier.performModification(view, model, component);
891 }
892 }
893 }
894 }
895
896
897
898
899
900
901
902
903 protected Map<String, Object> getCommonContext(View view, Component component) {
904 Map<String, Object> context = new HashMap<String, Object>();
905
906 context.putAll(view.getContext());
907 context.put(UifConstants.ContextVariableNames.COMPONENT, component);
908
909 return context;
910 }
911
912
913
914
915
916 @Override
917 public void performFinalize(View view, Object model) {
918 Map<String, Object> clientState = new HashMap<String, Object>();
919 performComponentFinalize(view, view, model, null, clientState);
920
921 String clientStateScript = buildClientSideStateScript(view, clientState, false);
922 String viewPreLoadScript = view.getPreLoadScript();
923 if (StringUtils.isNotBlank(viewPreLoadScript)) {
924 clientStateScript = viewPreLoadScript + clientStateScript;
925 }
926 view.setPreLoadScript(clientStateScript);
927
928
929 if (!((ViewModel) model).isDefaultsApplied()) {
930 applyDefaultValues(view, view, model);
931 ((ViewModel) model).setDefaultsApplied(true);
932 }
933 }
934
935
936
937
938
939
940
941
942
943
944
945
946 protected String buildClientSideStateScript(View view, Map<String, Object> clientSideState, boolean updateOnly) {
947
948
949
950 for (Entry<String, Object> additionalState : view.getClientSideState().entrySet()) {
951 if (!clientSideState.containsKey(additionalState.getKey())) {
952 clientSideState.put(additionalState.getKey(), additionalState.getValue());
953 } else {
954 Object state = clientSideState.get(additionalState.getKey());
955 Object mergeState = additionalState.getValue();
956 if ((state instanceof Map) && (mergeState instanceof Map)) {
957 ((Map) state).putAll((Map) mergeState);
958 } else {
959 clientSideState.put(additionalState.getKey(), additionalState.getValue());
960 }
961 }
962 }
963
964
965 String clientStateScript = "";
966 if (!clientSideState.isEmpty()) {
967 if (updateOnly) {
968 clientStateScript = "updateViewState({";
969 } else {
970 clientStateScript = "initializeViewState({";
971 }
972
973 for (Entry<String, Object> stateEntry : clientSideState.entrySet()) {
974 clientStateScript += "'" + stateEntry.getKey() + "':";
975 clientStateScript += ScriptUtils.translateValue(stateEntry.getValue());
976 clientStateScript += ",";
977 }
978 clientStateScript = StringUtils.removeEnd(clientStateScript, ",");
979 clientStateScript += "});";
980 }
981
982
983 if (!updateOnly) {
984 String kradImageLocation = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
985 "krad.externalizable.images.url");
986 clientStateScript += "setConfigParam('"
987 + UifConstants.ClientSideVariables.KRAD_IMAGE_LOCATION
988 + "','"
989 + kradImageLocation
990 + "');";
991 }
992
993 return clientStateScript;
994 }
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 protected void performComponentFinalize(View view, Component component, Object model, Component parent,
1007 Map<String, Object> clientSideState) {
1008 if (component == null) {
1009 return;
1010 }
1011
1012
1013 ViewModel viewModel = (ViewModel) model;
1014 if ((component instanceof DataBinding) && view.isSupportsReadOnlyFieldsOverride() && !viewModel
1015 .getReadOnlyFieldsList().isEmpty()) {
1016 String propertyName = ((DataBinding) component).getPropertyName();
1017 if (viewModel.getReadOnlyFieldsList().contains(propertyName)) {
1018 component.setReadOnly(true);
1019 }
1020 }
1021
1022
1023 invokeMethodFinalizer(view, component, model);
1024
1025
1026 component.performFinalize(view, model, parent);
1027
1028
1029 addClientSideStateForComponent(component, clientSideState);
1030
1031
1032 performCustomFinalize(view, component, model, parent);
1033
1034
1035 runComponentModifiers(view, component, model, UifConstants.ViewPhases.FINALIZE);
1036
1037
1038 for (Component nestedComponent : component.getComponentsForLifecycle()) {
1039 performComponentFinalize(view, nestedComponent, model, component, clientSideState);
1040 }
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057 protected void addClientSideStateForComponent(Component component, Map<String, Object> clientSideState) {
1058 Map<String, Annotation> annotatedFields = CloneUtils.getFieldsWithAnnotation(component.getClass(),
1059 ClientSideState.class);
1060
1061 if (!annotatedFields.isEmpty()) {
1062 Map<String, Object> componentClientState = null;
1063 if (component instanceof View) {
1064 componentClientState = clientSideState;
1065 } else {
1066 if (clientSideState.containsKey(component.getId())) {
1067 componentClientState = (Map<String, Object>) clientSideState.get(component.getId());
1068 } else {
1069 componentClientState = new HashMap<String, Object>();
1070 clientSideState.put(component.getId(), componentClientState);
1071 }
1072 }
1073
1074 for (Entry<String, Annotation> annotatedField : annotatedFields.entrySet()) {
1075 ClientSideState clientSideStateAnnot = (ClientSideState) annotatedField.getValue();
1076
1077 String variableName = clientSideStateAnnot.variableName();
1078 if (StringUtils.isBlank(variableName)) {
1079 variableName = annotatedField.getKey();
1080 }
1081
1082 Object value = ObjectPropertyUtils.getPropertyValue(component, annotatedField.getKey());
1083 componentClientState.put(variableName, value);
1084 }
1085 }
1086 }
1087
1088
1089
1090
1091
1092
1093
1094
1095 protected void syncClientSideStateForComponent(Component component, Map<String, Object> clientSideState) {
1096
1097 Map<String, Object> componentState = null;
1098 if (component instanceof View) {
1099 componentState = clientSideState;
1100 } else {
1101 if (clientSideState.containsKey(component.getId())) {
1102 componentState = (Map<String, Object>) clientSideState.get(component.getId());
1103 }
1104 }
1105
1106
1107 if ((componentState != null) && (!componentState.isEmpty())) {
1108 Map<String, Annotation> annotatedFields = CloneUtils.getFieldsWithAnnotation(component.getClass(),
1109 ClientSideState.class);
1110
1111 for (Entry<String, Annotation> annotatedField : annotatedFields.entrySet()) {
1112 ClientSideState clientSideStateAnnot = (ClientSideState) annotatedField.getValue();
1113
1114 String variableName = clientSideStateAnnot.variableName();
1115 if (StringUtils.isBlank(variableName)) {
1116 variableName = annotatedField.getKey();
1117 }
1118
1119 if (componentState.containsKey(variableName)) {
1120 Object value = componentState.get(variableName);
1121 ObjectPropertyUtils.setPropertyValue(component, annotatedField.getKey(), value);
1122 }
1123 }
1124 }
1125 }
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 protected void invokeMethodFinalizer(View view, Component component, Object model) {
1137 String finalizeMethodToCall = component.getFinalizeMethodToCall();
1138 MethodInvoker finalizeMethodInvoker = component.getFinalizeMethodInvoker();
1139
1140 if (StringUtils.isBlank(finalizeMethodToCall) && (finalizeMethodInvoker == null)) {
1141 return;
1142 }
1143
1144 if (finalizeMethodInvoker == null) {
1145 finalizeMethodInvoker = new MethodInvoker();
1146 }
1147
1148
1149
1150 if (StringUtils.isBlank(finalizeMethodInvoker.getTargetMethod())) {
1151 finalizeMethodInvoker.setTargetMethod(finalizeMethodToCall);
1152 }
1153
1154
1155 if ((finalizeMethodInvoker.getTargetClass() == null) && (finalizeMethodInvoker.getTargetObject() == null)) {
1156 finalizeMethodInvoker.setTargetObject(view.getViewHelperService());
1157 }
1158
1159
1160 List<Object> additionalArguments = component.getFinalizeMethodAdditionalArguments();
1161 if (additionalArguments == null) {
1162 additionalArguments = new ArrayList<Object>();
1163 }
1164
1165 Object[] arguments = new Object[2 + additionalArguments.size()];
1166 arguments[0] = component;
1167 arguments[1] = model;
1168
1169 int argumentIndex = 1;
1170 for (Object argument : additionalArguments) {
1171 argumentIndex++;
1172 arguments[argumentIndex] = argument;
1173 }
1174 finalizeMethodInvoker.setArguments(arguments);
1175
1176
1177 try {
1178 LOG.debug("Invoking render method: "
1179 + finalizeMethodInvoker.getTargetMethod()
1180 + " for component: "
1181 + component.getId());
1182 finalizeMethodInvoker.prepare();
1183
1184 Class<?> methodReturnType = finalizeMethodInvoker.getPreparedMethod().getReturnType();
1185 if (StringUtils.equals("void", methodReturnType.getName())) {
1186 finalizeMethodInvoker.invoke();
1187 } else {
1188 String renderOutput = (String) finalizeMethodInvoker.invoke();
1189
1190 component.setSelfRendered(true);
1191 component.setRenderOutput(renderOutput);
1192 }
1193 } catch (Exception e) {
1194 LOG.error("Error invoking rendering method for component: " + component.getId(), e);
1195 throw new RuntimeException("Error invoking rendering method for component: " + component.getId(), e);
1196 }
1197 }
1198
1199
1200
1201
1202
1203 @Override
1204 public void processCollectionAddLine(View view, Object model, String collectionPath) {
1205
1206 CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath);
1207 if (collectionGroup == null) {
1208 logAndThrowRuntime("Unable to get collection group component for path: " + collectionPath);
1209 }
1210
1211
1212 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath);
1213 if (collection == null) {
1214 logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath);
1215 }
1216
1217
1218 String addLinePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
1219 Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLinePath);
1220 if (addLine == null) {
1221 logAndThrowRuntime("Add line instance not found for path: " + addLinePath);
1222 }
1223
1224 processBeforeAddLine(view, collectionGroup, model, addLine);
1225
1226
1227 boolean isValidLine = performAddLineValidation(view, collectionGroup, model, addLine);
1228 if (isValidLine) {
1229
1230
1231
1232 if (collection instanceof List) {
1233 ((List) collection).add(0, addLine);
1234 } else {
1235 collection.add(addLine);
1236 }
1237
1238
1239 collectionGroup.initializeNewCollectionLine(view, model, collectionGroup, true);
1240 }
1241
1242 processAfterAddLine(view, collectionGroup, model, addLine);
1243 }
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257 protected boolean performAddLineValidation(View view, CollectionGroup collectionGroup, Object model,
1258 Object addLine) {
1259 boolean isValid = true;
1260
1261
1262
1263
1264 return isValid;
1265 }
1266
1267
1268
1269
1270
1271 public void processCollectionDeleteLine(View view, Object model, String collectionPath, int lineIndex) {
1272
1273 CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath);
1274 if (collectionGroup == null) {
1275 logAndThrowRuntime("Unable to get collection group component for path: " + collectionPath);
1276 }
1277
1278
1279 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath);
1280 if (collection == null) {
1281 logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath);
1282 }
1283
1284
1285
1286 if (collection instanceof List) {
1287 Object deleteLine = ((List<Object>) collection).get(lineIndex);
1288
1289
1290 boolean isValid = performDeleteLineValidation(view, collectionGroup, deleteLine);
1291 if (isValid) {
1292 ((List<Object>) collection).remove(lineIndex);
1293 processAfterDeleteLine(view, collectionGroup, model, lineIndex);
1294 }
1295 } else {
1296 logAndThrowRuntime("Only List collection implementations are supported for the delete by index method");
1297 }
1298 }
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310 protected boolean performDeleteLineValidation(View view, CollectionGroup collectionGroup, Object deleteLine) {
1311 boolean isValid = true;
1312
1313
1314
1315
1316 return isValid;
1317 }
1318
1319
1320
1321
1322 public void processMultipleValueLookupResults(View view, Object model, String collectionPath,
1323 String lookupResultValues) {
1324
1325 if (StringUtils.isBlank(lookupResultValues)) {
1326 return;
1327 }
1328
1329
1330 CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath);
1331 if (collectionGroup == null) {
1332 throw new RuntimeException("Unable to find collection group for path: " + collectionPath);
1333 }
1334
1335 Class<?> collectionObjectClass = collectionGroup.getCollectionObjectClass();
1336 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model,
1337 collectionGroup.getBindingInfo().getBindingPath());
1338 if (collection == null) {
1339 Class<?> collectionClass = ObjectPropertyUtils.getPropertyType(model,
1340 collectionGroup.getBindingInfo().getBindingPath());
1341 collection = (Collection<Object>) ObjectUtils.newInstance(collectionClass);
1342 ObjectPropertyUtils.setPropertyValue(model, collectionGroup.getBindingInfo().getBindingPath(), collection);
1343 }
1344
1345 Map<String, String> fieldConversions = collectionGroup.getCollectionLookup().getFieldConversions();
1346 List<String> toFieldNamesColl = new ArrayList(fieldConversions.values());
1347 Collections.sort(toFieldNamesColl);
1348 String[] toFieldNames = new String[toFieldNamesColl.size()];
1349 toFieldNamesColl.toArray(toFieldNames);
1350
1351
1352 String[] lineValues = StringUtils.split(lookupResultValues, ",");
1353
1354
1355 for (String lineValue : lineValues) {
1356 Object lineDataObject = null;
1357
1358
1359 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(
1360 collectionObjectClass);
1361 if (moduleService != null && moduleService.isExternalizable(collectionObjectClass)) {
1362 lineDataObject = moduleService.createNewObjectFromExternalizableClass(collectionObjectClass.asSubclass(
1363 ExternalizableBusinessObject.class));
1364 } else {
1365 lineDataObject = ObjectUtils.newInstance(collectionObjectClass);
1366 }
1367
1368
1369 applyDefaultValuesForCollectionLine(view, model, collectionGroup, lineDataObject);
1370
1371 String[] fieldValues = StringUtils.split(lineValue, ":");
1372 if (fieldValues.length != toFieldNames.length) {
1373 throw new RuntimeException(
1374 "Value count passed back from multi-value lookup does not match field conversion count");
1375 }
1376
1377
1378 for (int i = 0; i < fieldValues.length; i++) {
1379 String fieldName = toFieldNames[i];
1380 ObjectPropertyUtils.setPropertyValue(lineDataObject, fieldName, fieldValues[i]);
1381 }
1382
1383
1384
1385 collection.add(lineDataObject);
1386 }
1387 }
1388
1389
1390
1391
1392
1393
1394
1395
1396 public void buildInquiryLink(Object dataObject, String propertyName, Inquiry inquiry) {
1397 Inquirable inquirable = getViewDictionaryService().getInquirable(dataObject.getClass(), inquiry.getViewName());
1398 if (inquirable != null) {
1399 inquirable.buildInquirableLink(dataObject, propertyName, inquiry);
1400 } else {
1401
1402 inquiry.setRender(false);
1403 }
1404 }
1405
1406
1407
1408
1409
1410
1411 public void applyDefaultValuesForCollectionLine(View view, Object model, CollectionGroup collectionGroup,
1412 Object line) {
1413
1414 List<DataField> dataFields = ComponentUtils.getComponentsOfTypeDeep(collectionGroup.getAddLineFields(),
1415 DataField.class);
1416 for (DataField dataField : dataFields) {
1417 String bindingPath = "";
1418 if (StringUtils.isNotBlank(dataField.getBindingInfo().getBindByNamePrefix())) {
1419 bindingPath = dataField.getBindingInfo().getBindByNamePrefix() + ".";
1420 }
1421 bindingPath += dataField.getBindingInfo().getBindingName();
1422
1423 populateDefaultValueForField(view, line, dataField, bindingPath);
1424 }
1425 }
1426
1427
1428
1429
1430
1431
1432
1433
1434 protected void applyDefaultValues(View view, Component component, Object model) {
1435 if (component == null) {
1436 return;
1437 }
1438
1439
1440 if (component instanceof DataField) {
1441 DataField dataField = ((DataField) component);
1442
1443
1444 dataField.getBindingInfo().setDefaults(view, dataField.getPropertyName());
1445
1446 populateDefaultValueForField(view, model, dataField, dataField.getBindingInfo().getBindingPath());
1447 }
1448
1449 List<Component> nestedComponents = component.getComponentsForLifecycle();
1450
1451
1452 if (component instanceof View) {
1453 nestedComponents.addAll(((View) component).getItems());
1454 }
1455
1456 for (Component nested : nestedComponents) {
1457 applyDefaultValues(view, nested, model);
1458 }
1459 }
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477 protected void populateDefaultValueForField(View view, Object object, DataField dataField, String bindingPath) {
1478
1479 String defaultValue = dataField.getDefaultValue();
1480 if (StringUtils.isBlank(defaultValue) && (dataField.getDefaultValueFinderClass() != null)) {
1481 ValueFinder defaultValueFinder = ObjectUtils.newInstance(dataField.getDefaultValueFinderClass());
1482 defaultValue = defaultValueFinder.getValue();
1483 }
1484
1485
1486 if (StringUtils.isNotBlank(defaultValue) && ObjectPropertyUtils.isWritableProperty(object, bindingPath)) {
1487 if (getExpressionEvaluatorService().containsElPlaceholder(defaultValue)) {
1488 Map<String, Object> context = getPreModelContext(view);
1489 defaultValue = getExpressionEvaluatorService().evaluateExpressionTemplate(null, context, defaultValue);
1490 }
1491
1492
1493 ObjectPropertyUtils.setPropertyValue(object, bindingPath, defaultValue);
1494 }
1495 }
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514 protected void addCustomContainerComponents(View view, Object model, Container container) {
1515
1516 }
1517
1518
1519
1520
1521
1522
1523
1524
1525 protected void performCustomInitialization(View view, Component component) {
1526
1527 }
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538 protected void performCustomApplyModel(View view, Component component, Object model) {
1539
1540 }
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550 protected void performCustomFinalize(View view, Component component, Object model, Component parent) {
1551
1552 }
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565 protected void processBeforeAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
1566
1567 }
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580 protected void processAfterAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
1581
1582 }
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593 protected void processAfterDeleteLine(View view, CollectionGroup collectionGroup, Object model, int lineIndex) {
1594
1595 }
1596
1597 protected void logAndThrowRuntime(String message) {
1598 LOG.error(message);
1599 throw new RuntimeException(message);
1600 }
1601
1602 protected DataDictionaryService getDataDictionaryService() {
1603 if (this.dataDictionaryService == null) {
1604 this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
1605 }
1606
1607 return this.dataDictionaryService;
1608 }
1609
1610 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1611 this.dataDictionaryService = dataDictionaryService;
1612 }
1613
1614 protected ExpressionEvaluatorService getExpressionEvaluatorService() {
1615 if (this.expressionEvaluatorService == null) {
1616 this.expressionEvaluatorService = KRADServiceLocatorWeb.getExpressionEvaluatorService();
1617 }
1618
1619 return this.expressionEvaluatorService;
1620 }
1621
1622 public void setExpressionEvaluatorService(ExpressionEvaluatorService expressionEvaluatorService) {
1623 this.expressionEvaluatorService = expressionEvaluatorService;
1624 }
1625
1626 public ViewDictionaryService getViewDictionaryService() {
1627 if (this.viewDictionaryService == null) {
1628 this.viewDictionaryService = KRADServiceLocatorWeb.getViewDictionaryService();
1629 }
1630 return this.viewDictionaryService;
1631 }
1632
1633 public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
1634 this.viewDictionaryService = viewDictionaryService;
1635 }
1636 }