1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.container;
17
18 import org.apache.commons.collections.ListUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.mo.common.active.Inactivatable;
21 import org.kuali.rice.kim.api.identity.Person;
22 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
23 import org.kuali.rice.krad.uif.UifConstants;
24 import org.kuali.rice.krad.uif.UifParameters;
25 import org.kuali.rice.krad.uif.UifPropertyPaths;
26 import org.kuali.rice.krad.uif.component.Component;
27 import org.kuali.rice.krad.uif.component.ComponentSecurity;
28 import org.kuali.rice.krad.uif.control.Control;
29 import org.kuali.rice.krad.uif.component.DataBinding;
30 import org.kuali.rice.krad.uif.field.ActionField;
31 import org.kuali.rice.krad.uif.field.InputField;
32 import org.kuali.rice.krad.uif.field.Field;
33 import org.kuali.rice.krad.uif.field.FieldGroup;
34 import org.kuali.rice.krad.uif.field.RemoteFieldsHolder;
35 import org.kuali.rice.krad.uif.layout.CollectionLayoutManager;
36 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
37 import org.kuali.rice.krad.uif.util.ComponentUtils;
38 import org.kuali.rice.krad.uif.util.ExpressionUtils;
39 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
40 import org.kuali.rice.krad.uif.view.View;
41 import org.kuali.rice.krad.uif.view.ViewAuthorizer;
42 import org.kuali.rice.krad.uif.view.ViewModel;
43 import org.kuali.rice.krad.uif.view.ViewPresentationController;
44 import org.kuali.rice.krad.util.GlobalVariables;
45 import org.kuali.rice.krad.util.KRADUtils;
46 import org.kuali.rice.krad.util.ObjectUtils;
47 import org.kuali.rice.krad.web.form.UifFormBase;
48
49 import java.io.Serializable;
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55
56
57
58
59
60
61
62
63
64 public class CollectionGroupBuilder implements Serializable {
65 private static final long serialVersionUID = -4762031957079895244L;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public void build(View view, Object model, CollectionGroup collectionGroup) {
88
89 if (collectionGroup.isRenderAddLine() && !collectionGroup.isReadOnly()) {
90 buildAddLine(view, model, collectionGroup);
91 }
92
93
94 List<Object> modelCollection = ObjectPropertyUtils.getPropertyValue(model, ((DataBinding) collectionGroup)
95 .getBindingInfo().getBindingPath());
96
97 if (modelCollection != null) {
98
99 List<Integer> showIndexes = performCollectionFiltering(view, model, collectionGroup, modelCollection);
100
101
102 for (int index = 0; index < modelCollection.size(); index++) {
103
104 if (showIndexes.contains(index)) {
105 String bindingPathPrefix = collectionGroup.getBindingInfo().getBindingName() + "[" + index + "]";
106 if (StringUtils.isNotBlank(collectionGroup.getBindingInfo().getBindByNamePrefix())) {
107 bindingPathPrefix =
108 collectionGroup.getBindingInfo().getBindByNamePrefix() + "." + bindingPathPrefix;
109 }
110
111 Object currentLine = modelCollection.get(index);
112
113 List<ActionField> actions = getLineActions(view, model, collectionGroup, currentLine, index);
114 buildLine(view, model, collectionGroup, bindingPathPrefix, actions, false, currentLine, index);
115 }
116 }
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 protected List<Integer> performCollectionFiltering(View view, Object model, CollectionGroup collectionGroup,
136 Collection<?> collection) {
137 List<Integer> filteredIndexes = new ArrayList<Integer>();
138 for (int i = 0; i < collection.size(); i++) {
139 filteredIndexes.add(new Integer(i));
140 }
141
142 if (Inactivatable.class.isAssignableFrom(collectionGroup.getCollectionObjectClass()) && !collectionGroup
143 .isShowInactive()) {
144 List<Integer> activeIndexes = collectionGroup.getActiveCollectionFilter().filter(view, model,
145 collectionGroup);
146 filteredIndexes = ListUtils.intersection(filteredIndexes, activeIndexes);
147 }
148
149 for (CollectionFilter collectionFilter : collectionGroup.getFilters()) {
150 List<Integer> indexes = collectionFilter.filter(view, model, collectionGroup);
151 filteredIndexes = ListUtils.intersection(filteredIndexes, indexes);
152 if (filteredIndexes.isEmpty()) {
153 break;
154 }
155 }
156
157 return filteredIndexes;
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172 protected void buildAddLine(View view, Object model, CollectionGroup collectionGroup) {
173 boolean addLineBindsToForm = false;
174
175
176 initializeNewCollectionLine(view, model, collectionGroup, false);
177
178
179
180 if (StringUtils.isBlank(collectionGroup.getAddLinePropertyName())) {
181 addLineBindsToForm = true;
182 }
183
184 String addLineBindingPath = collectionGroup.getAddLineBindingInfo().getBindingPath();
185 List<ActionField> actions = getAddLineActions(view, model, collectionGroup);
186
187 Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLineBindingPath);
188 buildLine(view, model, collectionGroup, addLineBindingPath, actions, addLineBindsToForm, addLine, -1);
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 @SuppressWarnings("unchecked")
218 protected void buildLine(View view, Object model, CollectionGroup collectionGroup, String bindingPath,
219 List<ActionField> actions, boolean bindToForm, Object currentLine, int lineIndex) {
220 CollectionLayoutManager layoutManager = (CollectionLayoutManager) collectionGroup.getLayoutManager();
221
222
223 List<? extends Component> lineItems = null;
224 String lineSuffix = null;
225 if (lineIndex == -1) {
226 lineItems = ComponentUtils.copyComponentList(collectionGroup.getAddLineFields(), null);
227 lineSuffix = UifConstants.IdSuffixes.ADD_LINE;
228 } else {
229 lineItems = ComponentUtils.copyComponentList(collectionGroup.getItems(), null);
230 lineSuffix = UifConstants.IdSuffixes.LINE + Integer.toString(lineIndex);
231 }
232
233 if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
234 lineSuffix = collectionGroup.getSubCollectionSuffix() + lineSuffix;
235 }
236
237
238 List<Field> lineFields = processAnyRemoteFieldsHolder(view, model, collectionGroup, lineItems);
239
240
241 lineFields = (List<Field>) ComponentUtils.copyFieldList(lineFields, bindingPath, lineSuffix);
242
243 boolean readOnlyLine = collectionGroup.isReadOnly();
244
245
246 if (lineIndex == -1) {
247 for (Field f : lineFields) {
248 if (f instanceof InputField) {
249
250
251 Control control = ((InputField) f).getControl();
252 if (control != null) {
253 control.addStyleClass(collectionGroup.getFactoryId() + "-addField");
254 control.addStyleClass("ignoreValid");
255 }
256 }
257 }
258
259
260 for (ActionField action : actions) {
261 if (action.getActionParameter(UifParameters.ACTION_TYPE).equals(UifParameters.ADD_LINE)) {
262 action.setFocusOnAfterSubmit(lineFields.get(0).getId());
263 }
264 }
265 } else {
266
267 boolean canViewLine = checkViewLineAuthorizationAndPresentationLogic(view, (ViewModel) model,
268 collectionGroup, currentLine);
269
270
271 if (!canViewLine) {
272 return;
273 }
274
275
276 if (!collectionGroup.isReadOnly()) {
277 readOnlyLine = !checkEditLineAuthorizationAndPresentationLogic(view, (ViewModel) model, collectionGroup,
278 currentLine);
279 }
280
281 ComponentUtils.pushObjectToContext(lineFields, UifConstants.ContextVariableNames.READONLY_LINE,
282 readOnlyLine);
283 ComponentUtils.pushObjectToContext(actions, UifConstants.ContextVariableNames.READONLY_LINE, readOnlyLine);
284 }
285
286 ComponentUtils.updateContextsForLine(lineFields, currentLine, lineIndex);
287
288
289 applyLineFieldAuthorizationAndPresentationLogic(view, (ViewModel) model, collectionGroup, currentLine,
290 readOnlyLine, lineFields, actions);
291
292 if (bindToForm) {
293 ComponentUtils.setComponentsPropertyDeep(lineFields, UifPropertyPaths.BIND_TO_FORM, new Boolean(true));
294 }
295
296
297 lineFields = removeNonRenderLineFields(view, model, collectionGroup, lineFields, currentLine, lineIndex);
298
299
300 List<FieldGroup> subCollectionFields = new ArrayList<FieldGroup>();
301 if ((lineIndex != -1) && (collectionGroup.getSubCollections() != null)) {
302 for (int subLineIndex = 0; subLineIndex < collectionGroup.getSubCollections().size(); subLineIndex++) {
303 CollectionGroup subCollectionPrototype = collectionGroup.getSubCollections().get(subLineIndex);
304 CollectionGroup subCollectionGroup = ComponentUtils.copy(subCollectionPrototype, lineSuffix);
305
306
307 boolean renderSubCollection = checkSubCollectionRender(view, model, collectionGroup,
308 subCollectionGroup);
309 if (!renderSubCollection) {
310 continue;
311 }
312
313 subCollectionGroup.getBindingInfo().setBindByNamePrefix(bindingPath);
314 if (subCollectionGroup.isRenderAddLine()) {
315 subCollectionGroup.getAddLineBindingInfo().setBindByNamePrefix(bindingPath);
316 }
317
318
319 String subCollectionSuffix = lineSuffix;
320 if (StringUtils.isNotBlank(subCollectionGroup.getSubCollectionSuffix())) {
321 subCollectionSuffix = subCollectionGroup.getSubCollectionSuffix() + lineSuffix;
322 }
323 subCollectionGroup.setSubCollectionSuffix(subCollectionSuffix);
324
325 FieldGroup fieldGroupPrototype = layoutManager.getSubCollectionFieldGroupPrototype();
326
327 FieldGroup subCollectionFieldGroup = ComponentUtils.copy(fieldGroupPrototype,
328 lineSuffix + UifConstants.IdSuffixes.SUB + subLineIndex);
329 subCollectionFieldGroup.setGroup(subCollectionGroup);
330
331
332
333 ComponentUtils.updateContextForLine(subCollectionFieldGroup, currentLine, lineIndex);
334
335 subCollectionFields.add(subCollectionFieldGroup);
336 }
337 }
338
339
340 layoutManager.buildLine(view, model, collectionGroup, lineFields, subCollectionFields, bindingPath, actions,
341 lineSuffix, currentLine, lineIndex);
342 }
343
344
345
346
347
348
349
350
351
352
353
354 protected List<Field> processAnyRemoteFieldsHolder(View view, Object model, CollectionGroup group,
355 List<? extends Component> items) {
356 List<Field> processedItems = new ArrayList<Field>();
357
358
359
360 for (Component item : items) {
361 if (item instanceof RemoteFieldsHolder) {
362 List<InputField> translatedFields = ((RemoteFieldsHolder) item).fetchAndTranslateRemoteFields(view,
363 model, group);
364 processedItems.addAll(translatedFields);
365 } else {
366 processedItems.add((Field) item);
367 }
368 }
369
370 return processedItems;
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 protected List<Field> removeNonRenderLineFields(View view, Object model, CollectionGroup collectionGroup,
396 List<Field> lineFields, Object currentLine, int lineIndex) {
397 List<Field> fields = new ArrayList<Field>();
398
399 for (Field lineField : lineFields) {
400 String conditionalRender = lineField.getPropertyExpression("render");
401
402
403 if (StringUtils.isNotBlank(conditionalRender)) {
404 Map<String, Object> context = getContextForField(view, collectionGroup, lineField);
405
406
407
408 conditionalRender = ExpressionUtils.replaceBindingPrefixes(view, lineField, conditionalRender);
409
410 Boolean render = (Boolean) getExpressionEvaluatorService().evaluateExpression(model, context,
411 conditionalRender);
412 lineField.setRender(render);
413 }
414
415
416 if (lineField.isRender() || StringUtils.isNotBlank(lineField.getProgressiveRender())) {
417 fields.add(lineField);
418 }
419 }
420
421 return fields;
422 }
423
424
425
426
427
428
429
430
431
432
433
434
435 protected boolean checkViewLineAuthorizationAndPresentationLogic(View view, ViewModel model,
436 CollectionGroup collectionGroup, Object line) {
437 ViewPresentationController presentationController = view.getPresentationController();
438 ViewAuthorizer authorizer = view.getAuthorizer();
439
440 Person user = GlobalVariables.getUserSession().getPerson();
441
442
443 boolean canViewLine = authorizer.canViewLine(view, model, collectionGroup, collectionGroup.getPropertyName(),
444 line, user);
445 if (canViewLine) {
446 canViewLine = presentationController.canViewLine(view, model, collectionGroup,
447 collectionGroup.getPropertyName(), line);
448 }
449
450 return canViewLine;
451 }
452
453
454
455
456
457
458
459
460
461
462
463
464 protected boolean checkEditLineAuthorizationAndPresentationLogic(View view, ViewModel model,
465 CollectionGroup collectionGroup, Object line) {
466 ViewPresentationController presentationController = view.getPresentationController();
467 ViewAuthorizer authorizer = view.getAuthorizer();
468
469 Person user = GlobalVariables.getUserSession().getPerson();
470
471
472 boolean canEditLine = authorizer.canEditLine(view, model, collectionGroup, collectionGroup.getPropertyName(),
473 line, user);
474 if (canEditLine) {
475 canEditLine = presentationController.canEditLine(view, model, collectionGroup,
476 collectionGroup.getPropertyName(), line);
477 }
478
479 return canEditLine;
480 }
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497 protected void applyLineFieldAuthorizationAndPresentationLogic(View view, ViewModel model,
498 CollectionGroup collectionGroup, Object line, boolean readOnlyLine, List<Field> lineFields,
499 List<ActionField> actions) {
500 ViewPresentationController presentationController = view.getPresentationController();
501 ViewAuthorizer authorizer = view.getAuthorizer();
502
503 Person user = GlobalVariables.getUserSession().getPerson();
504
505 for (Field lineField : lineFields) {
506 String propertyName = null;
507 if (lineField instanceof DataBinding) {
508 propertyName = ((DataBinding) lineField).getPropertyName();
509 }
510
511
512
513 ComponentSecurity componentSecurity = lineField.getComponentSecurity();
514 ExpressionUtils.adjustPropertyExpressions(view, componentSecurity);
515
516 Map<String, Object> context = getContextForField(view, collectionGroup, lineField);
517 getExpressionEvaluatorService().evaluateObjectExpressions(componentSecurity, model, context);
518
519
520 if (lineField.isRender() && !lineField.isHidden()) {
521 boolean canViewField = authorizer.canViewLineField(view, model, collectionGroup,
522 collectionGroup.getPropertyName(), line, lineField, propertyName, user);
523 if (canViewField) {
524 canViewField = presentationController.canViewLineField(view, model, collectionGroup,
525 collectionGroup.getPropertyName(), line, lineField, propertyName);
526 }
527
528 if (!canViewField) {
529
530
531 lineField.setHidden(true);
532
533 if (lineField.getPropertyExpressions().containsKey("hidden")) {
534 lineField.getPropertyExpressions().remove("hidden");
535 }
536
537 continue;
538 }
539
540
541 boolean canEditField = !readOnlyLine;
542 if (!readOnlyLine) {
543 canEditField = authorizer.canEditLineField(view, model, collectionGroup,
544 collectionGroup.getPropertyName(), line, lineField, propertyName, user);
545 if (canEditField) {
546 canEditField = presentationController.canEditLineField(view, model, collectionGroup,
547 collectionGroup.getPropertyName(), line, lineField, propertyName);
548 }
549 }
550
551 if (readOnlyLine || !canEditField) {
552 lineField.setReadOnly(true);
553
554 if (lineField.getPropertyExpressions().containsKey("readOnly")) {
555 lineField.getPropertyExpressions().remove("readOnly");
556 }
557 }
558 }
559 }
560
561
562 for (ActionField actionField : actions) {
563 if (actionField.isRender()) {
564 boolean canPerformAction = authorizer.canPerformLineAction(view, model, collectionGroup,
565 collectionGroup.getPropertyName(), line, actionField, actionField.getActionEvent(),
566 actionField.getId(), user);
567 if (canPerformAction) {
568 canPerformAction = presentationController.canPerformLineAction(view, model, collectionGroup,
569 collectionGroup.getPropertyName(), line, actionField, actionField.getActionEvent(),
570 actionField.getId());
571 }
572
573 if (!canPerformAction) {
574 actionField.setRender(false);
575
576 if (actionField.getPropertyExpressions().containsKey("render")) {
577 actionField.getPropertyExpressions().remove("render");
578 }
579 }
580 }
581 }
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599 protected boolean checkSubCollectionRender(View view, Object model, CollectionGroup collectionGroup,
600 CollectionGroup subCollectionGroup) {
601 String conditionalRender = subCollectionGroup.getPropertyExpression("render");
602
603
604
605
606 if (StringUtils.isNotBlank(conditionalRender)) {
607 Map<String, Object> context = new HashMap<String, Object>();
608 context.putAll(view.getContext());
609 context.put(UifConstants.ContextVariableNames.PARENT, collectionGroup);
610 context.put(UifConstants.ContextVariableNames.COMPONENT, subCollectionGroup);
611
612 Boolean render = (Boolean) getExpressionEvaluatorService().evaluateExpression(model, context,
613 conditionalRender);
614 subCollectionGroup.setRender(render);
615 }
616
617 return subCollectionGroup.isRender();
618 }
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639 protected List<ActionField> getLineActions(View view, Object model, CollectionGroup collectionGroup,
640 Object collectionLine, int lineIndex) {
641 String lineSuffix = UifConstants.IdSuffixes.LINE + Integer.toString(lineIndex);
642 if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
643 lineSuffix = collectionGroup.getSubCollectionSuffix() + lineSuffix;
644 }
645 List<ActionField> lineActions = ComponentUtils.copyFieldList(collectionGroup.getActionFields(), lineSuffix);
646
647 for (ActionField actionField : lineActions) {
648 actionField.addActionParameter(UifParameters.SELLECTED_COLLECTION_PATH, collectionGroup.getBindingInfo()
649 .getBindingPath());
650 actionField.addActionParameter(UifParameters.SELECTED_LINE_INDEX, Integer.toString(lineIndex));
651 actionField.setJumpToIdAfterSubmit(collectionGroup.getId() + "_div");
652
653 actionField.setClientSideJs("performCollectionAction('"+collectionGroup.getId()+"');");
654 }
655
656 ComponentUtils.updateContextsForLine(lineActions, collectionLine, lineIndex);
657
658 return lineActions;
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676 protected List<ActionField> getAddLineActions(View view, Object model, CollectionGroup collectionGroup) {
677 String lineSuffix = UifConstants.IdSuffixes.ADD_LINE;
678 if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
679 lineSuffix = collectionGroup.getSubCollectionSuffix() + lineSuffix;
680 }
681 List<ActionField> lineActions = ComponentUtils.copyFieldList(collectionGroup.getAddLineActionFields(),
682 lineSuffix);
683
684 for (ActionField actionField : lineActions) {
685 actionField.addActionParameter(UifParameters.SELLECTED_COLLECTION_PATH, collectionGroup.getBindingInfo()
686 .getBindingPath());
687 actionField.setJumpToIdAfterSubmit(collectionGroup.getId() + "_div");
688 actionField.addActionParameter(UifParameters.ACTION_TYPE, UifParameters.ADD_LINE);
689
690 String baseId = collectionGroup.getFactoryId();
691 if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
692 baseId += collectionGroup.getSubCollectionSuffix();
693 }
694
695 actionField.setClientSideJs("addLineToCollection('"+collectionGroup.getId()+"', '"+ baseId +"');");
696 }
697
698
699 String addLinePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
700 Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLinePath);
701
702 ComponentUtils.updateContextsForLine(lineActions, addLine, -1);
703
704 return lineActions;
705 }
706
707
708
709
710
711
712
713
714
715
716 protected Map<String, Object> getContextForField(View view, CollectionGroup collectionGroup, Field field) {
717 Map<String, Object> context = new HashMap<String, Object>();
718
719 context.putAll(view.getContext());
720 context.putAll(field.getContext());
721 context.put(UifConstants.ContextVariableNames.PARENT, collectionGroup);
722 context.put(UifConstants.ContextVariableNames.COMPONENT, field);
723
724 return context;
725 }
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746 public void initializeNewCollectionLine(View view, Object model, CollectionGroup collectionGroup,
747 boolean clearExistingLine) {
748 Object newLine = null;
749
750
751 if (StringUtils.isBlank(collectionGroup.getAddLinePropertyName())) {
752
753 if (!(model instanceof UifFormBase)) {
754 throw new RuntimeException("Cannot create new collection line for group: "
755 + collectionGroup.getPropertyName() + ". Model does not extend " + UifFormBase.class.getName());
756 }
757
758
759 Map<String, Object> newCollectionLines = ObjectPropertyUtils.getPropertyValue(model,
760 UifPropertyPaths.NEW_COLLECTION_LINES);
761 if (newCollectionLines == null) {
762 newCollectionLines = new HashMap<String, Object>();
763 ObjectPropertyUtils.setPropertyValue(model, UifPropertyPaths.NEW_COLLECTION_LINES, newCollectionLines);
764 }
765
766
767 String newCollectionLineKey = KRADUtils
768 .translateToMapSafeKey(collectionGroup.getBindingInfo().getBindingPath());
769 String addLineBindingPath = UifPropertyPaths.NEW_COLLECTION_LINES + "['" + newCollectionLineKey + "']";
770 collectionGroup.getAddLineBindingInfo().setBindingPath(addLineBindingPath);
771
772
773 if (!newCollectionLines.containsKey(newCollectionLineKey)
774 || (newCollectionLines.get(newCollectionLineKey) == null) || clearExistingLine) {
775
776 newLine = ObjectUtils.newInstance(collectionGroup.getCollectionObjectClass());
777 newCollectionLines.put(newCollectionLineKey, newLine);
778 }
779 } else {
780
781 Object addLine = ObjectPropertyUtils.getPropertyValue(model, collectionGroup.getAddLineBindingInfo()
782 .getBindingPath());
783 if ((addLine == null) || clearExistingLine) {
784 newLine = ObjectUtils.newInstance(collectionGroup.getCollectionObjectClass());
785 ObjectPropertyUtils.setPropertyValue(model, collectionGroup.getAddLineBindingInfo().getBindingPath(),
786 newLine);
787 }
788 }
789
790
791 if (newLine != null) {
792 view.getViewHelperService().applyDefaultValuesForCollectionLine(view, model, collectionGroup, newLine);
793 }
794 }
795
796 protected ExpressionEvaluatorService getExpressionEvaluatorService() {
797 return KRADServiceLocatorWeb.getExpressionEvaluatorService();
798 }
799
800 }