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.lang.StringUtils;
19 import org.kuali.rice.kim.api.identity.Person;
20 import org.kuali.rice.krad.uif.CssConstants;
21 import org.kuali.rice.krad.uif.UifConstants;
22 import org.kuali.rice.krad.uif.UifPropertyPaths;
23 import org.kuali.rice.krad.uif.component.BindingInfo;
24 import org.kuali.rice.krad.uif.component.Component;
25 import org.kuali.rice.krad.uif.component.ComponentSecurity;
26 import org.kuali.rice.krad.uif.component.DataBinding;
27 import org.kuali.rice.krad.uif.container.collections.LineBuilderContext;
28 import org.kuali.rice.krad.uif.control.Control;
29 import org.kuali.rice.krad.uif.control.ControlBase;
30 import org.kuali.rice.krad.uif.element.Action;
31 import org.kuali.rice.krad.uif.field.Field;
32 import org.kuali.rice.krad.uif.field.FieldGroup;
33 import org.kuali.rice.krad.uif.field.InputField;
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.lifecycle.ViewLifecycle;
37 import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
38 import org.kuali.rice.krad.uif.util.ComponentUtils;
39 import org.kuali.rice.krad.uif.util.ScriptUtils;
40 import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
41 import org.kuali.rice.krad.uif.view.View;
42 import org.kuali.rice.krad.uif.view.ViewAuthorizer;
43 import org.kuali.rice.krad.uif.view.ViewModel;
44 import org.kuali.rice.krad.uif.view.ViewPresentationController;
45 import org.kuali.rice.krad.util.GlobalVariables;
46 import org.kuali.rice.krad.web.form.UifFormBase;
47
48 import java.io.Serializable;
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53
54
55
56
57
58
59
60 public class CollectionGroupLineBuilder implements Serializable {
61 private static final long serialVersionUID = 981187437246864378L;
62
63 private LineBuilderContext lineBuilderContext;
64
65 public CollectionGroupLineBuilder(LineBuilderContext lineBuilderContext) {
66 this.lineBuilderContext = lineBuilderContext;
67 }
68
69
70
71
72
73
74
75 public void buildLine() {
76 preprocessLine();
77
78 boolean hasLineFields =
79 (lineBuilderContext.getLineFields() != null) && (!lineBuilderContext.getLineFields().isEmpty());
80 boolean hasSubCollections = (lineBuilderContext.getSubCollectionFields() != null) &&
81 (!lineBuilderContext.getSubCollectionFields().isEmpty());
82
83
84 if (hasLineFields || hasSubCollections) {
85 lineBuilderContext.getLayoutManager().buildLine(lineBuilderContext);
86 }
87
88
89
90 applyOnChangeForSave(lineBuilderContext.getLineFields());
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public void preprocessLine() {
107 List<? extends Component> lineItems = initializeLineItems();
108
109 List<Field> lineFields = processAnyRemoteFieldsHolder(lineBuilderContext.getCollectionGroup(), lineItems);
110
111 adjustFieldBindingAndId(lineFields);
112
113
114 ComponentUtils.updateContextsForLine(lineFields, lineBuilderContext.getCollectionGroup(),
115 lineBuilderContext.getCurrentLine(), lineBuilderContext.getLineIndex(),
116 lineBuilderContext.getIdSuffix());
117
118 boolean canViewLine = checkViewLineAuthorization();
119 if (!canViewLine) {
120 return;
121 }
122
123 List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(lineBuilderContext.getLineActions(),
124 Action.class);
125 setFocusOnIdForActions(actions, lineFields);
126
127 boolean canEditLine = checkEditLineAuthorization(lineFields);
128 ComponentUtils.pushObjectToContext(lineFields, UifConstants.ContextVariableNames.READONLY_LINE, !canEditLine);
129 ComponentUtils.pushObjectToContext(actions, UifConstants.ContextVariableNames.READONLY_LINE, !canEditLine);
130
131
132 applyLineFieldAuthorizationAndPresentationLogic(!canEditLine, lineFields, actions);
133
134
135 lineFields = removeNonRenderLineFields(lineFields);
136
137 buildSubCollectionFieldGroups();
138
139
140 List<Action> lineFieldActions = ViewLifecycleUtils.getElementsOfTypeDeep(lineFields, Action.class);
141 if (lineFieldActions != null) {
142 lineBuilderContext.getCollectionGroup().getCollectionGroupBuilder().initializeActions(lineFieldActions,
143 lineBuilderContext.getCollectionGroup(), lineBuilderContext.getLineIndex());
144 }
145
146 setupAddLineControlValidation(lineFields);
147
148 lineBuilderContext.setLineFields(lineFields);
149 }
150
151
152
153
154
155
156
157 protected List<? extends Component> initializeLineItems() {
158 List<? extends Component> lineItems;
159
160 if (lineBuilderContext.isAddLine()) {
161 lineItems = ComponentUtils.copyComponentList(lineBuilderContext.getCollectionGroup().getAddLineItems(),
162 null);
163 } else {
164 lineItems = ComponentUtils.copyComponentList(lineBuilderContext.getCollectionGroup().getItems(), null);
165 }
166
167 return lineItems;
168 }
169
170
171
172
173
174
175
176
177
178
179 public List<Field> processAnyRemoteFieldsHolder(CollectionGroup group, List<? extends Component> items) {
180 List<Field> processedItems = new ArrayList<Field>();
181
182
183
184 for (Component item : items) {
185 if (item instanceof RemoteFieldsHolder) {
186 List<InputField> translatedFields = ((RemoteFieldsHolder) item).fetchAndTranslateRemoteFields(group);
187 processedItems.addAll(translatedFields);
188 } else {
189 processedItems.add((Field) item);
190 }
191 }
192
193 return processedItems;
194 }
195
196
197
198
199
200
201
202 protected void adjustFieldBindingAndId(List<Field> lineFields) {
203
204 ComponentUtils.bindAndIdFieldList(lineFields, lineBuilderContext.getBindingPath(),
205 lineBuilderContext.getIdSuffix());
206
207 for (Field field : lineFields) {
208 List<CollectionGroup> components = ViewLifecycleUtils.getElementsOfTypeDeep(field, CollectionGroup.class);
209 for (CollectionGroup fieldCollectionGroup : components) {
210 fieldCollectionGroup.setSubCollectionSuffix(lineBuilderContext.getIdSuffix());
211 }
212 }
213
214 if (lineBuilderContext.isBindToForm()) {
215 ComponentUtils.setComponentsPropertyDeep(lineFields, UifPropertyPaths.BIND_TO_FORM, Boolean.valueOf(true));
216 }
217 }
218
219
220
221
222
223
224
225
226
227 protected void setFocusOnIdForActions(List<Action> actions, List<Field> lineFields) {
228 for (Action action : actions) {
229 if (action == null) {
230 continue;
231 }
232
233 boolean focusLineFirst = StringUtils.isNotBlank(action.getFocusOnIdAfterSubmit()) &&
234 action.getFocusOnIdAfterSubmit().equalsIgnoreCase(UifConstants.Order.LINE_FIRST.toString());
235 boolean lineHasFields = !lineFields.isEmpty();
236 if (focusLineFirst && lineHasFields) {
237 action.setFocusOnIdAfterSubmit(lineFields.get(0).getId() + UifConstants.IdSuffixes.CONTROL);
238 }
239 }
240 }
241
242
243
244
245
246
247
248 protected void applyOnChangeForSave(List<Field> lineFields) {
249 boolean isLineNewlyAdded = ((UifFormBase) lineBuilderContext.getModel()).isAddedCollectionItem(
250 lineBuilderContext.getCurrentLine());
251 boolean saveLineEnabled = lineBuilderContext.getCollectionGroup().isRenderSaveLineActions();
252
253 if (!isLineNewlyAdded && !saveLineEnabled) {
254 return;
255 }
256
257 for (Field field : lineFields) {
258 boolean isInputField = (field instanceof InputField);
259 if (field.isHidden() || field.isReadOnly() || !isInputField) {
260 continue;
261 }
262
263 ControlBase control = (ControlBase) ((InputField) field).getControl();
264
265 String onBlurScript = UifConstants.JsFunctions.COLLECTION_LINE_CHANGED + "(this, '" +
266 CssConstants.Classes.NEW_COLLECTION_ITEM + "');";
267 onBlurScript = ScriptUtils.appendScript(control.getOnBlurScript(), onBlurScript);
268
269 control.setOnBlurScript(onBlurScript);
270 }
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284 protected List<Field> removeNonRenderLineFields(List<Field> lineFields) {
285 List<Field> fields = new ArrayList<Field>();
286
287 ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
288
289 for (Field lineField : lineFields) {
290 String conditionalRender = lineField.getPropertyExpression(UifPropertyPaths.RENDER);
291
292
293 if (StringUtils.isNotBlank(conditionalRender)) {
294 Map<String, Object> context = getContextForField(ViewLifecycle.getView(),
295 lineBuilderContext.getCollectionGroup(), lineField);
296
297
298
299 conditionalRender = expressionEvaluator.replaceBindingPrefixes(ViewLifecycle.getView(), lineField,
300 conditionalRender);
301
302 Boolean render = (Boolean) expressionEvaluator.evaluateExpression(context, conditionalRender);
303 lineField.setRender(render);
304 }
305
306
307 if (lineField.isRender() || StringUtils.isNotBlank(lineField.getProgressiveRender())) {
308 fields.add(lineField);
309 }
310 }
311
312 return fields;
313 }
314
315
316
317
318
319
320 protected boolean checkViewLineAuthorization() {
321 boolean canViewLine = !lineBuilderContext.getCollectionGroup().isHidden();
322
323
324 if (canViewLine && !lineBuilderContext.isAddLine()) {
325 canViewLine = checkViewLineAuthorizationAndPresentationLogic();
326 }
327
328 if (!canViewLine) {
329 addUnauthorizedBindingInfo();
330 }
331
332 return canViewLine;
333 }
334
335
336
337
338
339
340
341 protected boolean checkViewLineAuthorizationAndPresentationLogic() {
342 ViewPresentationController presentationController = ViewLifecycle.getView().getPresentationController();
343 ViewAuthorizer authorizer = ViewLifecycle.getView().getAuthorizer();
344
345 Person user = GlobalVariables.getUserSession().getPerson();
346
347 CollectionGroup collectionGroup = lineBuilderContext.getCollectionGroup();
348
349 boolean canViewLine = authorizer.canViewLine(ViewLifecycle.getView(), lineBuilderContext.getModel(),
350 collectionGroup, collectionGroup.getPropertyName(), lineBuilderContext.getCurrentLine(), user);
351 if (canViewLine) {
352 canViewLine = presentationController.canViewLine(ViewLifecycle.getView(), lineBuilderContext.getModel(),
353 collectionGroup, collectionGroup.getPropertyName(), lineBuilderContext.getCurrentLine());
354 }
355
356 return canViewLine;
357 }
358
359
360
361
362
363
364
365 protected boolean checkEditLineAuthorization(List<Field> lineFields) {
366 boolean canEditLine = !lineBuilderContext.getCollectionGroup().isReadOnly();
367
368 if (!canEditLine) {
369 ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
370 View view = ViewLifecycle.getView();
371
372 for (Field field : lineFields) {
373 field.pushObjectToContext(UifConstants.ContextVariableNames.PARENT,
374 lineBuilderContext.getCollectionGroup());
375 field.pushAllToContext(view.getContext());
376 field.pushObjectToContext(UifConstants.ContextVariableNames.COMPONENT, field);
377
378 expressionEvaluator.evaluatePropertyExpression(view, field.getContext(), field,
379 UifPropertyPaths.READ_ONLY, true);
380
381 if (!field.isReadOnly()) {
382 canEditLine = true;
383 break;
384 }
385 }
386 }
387
388 if (canEditLine && !lineBuilderContext.isAddLine()) {
389 canEditLine = checkEditLineAuthorizationAndPresentationLogic();
390 }
391
392 if (!canEditLine) {
393 addUnauthorizedBindingInfo();
394 }
395
396 return canEditLine;
397 }
398
399
400
401
402
403
404
405 protected boolean checkEditLineAuthorizationAndPresentationLogic() {
406 ViewPresentationController presentationController = ViewLifecycle.getView().getPresentationController();
407 ViewAuthorizer authorizer = ViewLifecycle.getView().getAuthorizer();
408
409 Person user = GlobalVariables.getUserSession().getPerson();
410
411 CollectionGroup collectionGroup = lineBuilderContext.getCollectionGroup();
412
413 boolean canEditLine = authorizer.canEditLine(ViewLifecycle.getView(), lineBuilderContext.getModel(),
414 collectionGroup, collectionGroup.getPropertyName(), lineBuilderContext.getCurrentLine(), user);
415 if (canEditLine) {
416 canEditLine = presentationController.canEditLine(ViewLifecycle.getView(), lineBuilderContext.getModel(),
417 collectionGroup, collectionGroup.getPropertyName(), lineBuilderContext.getCurrentLine());
418 }
419
420 return canEditLine;
421 }
422
423
424
425
426
427 protected void addUnauthorizedBindingInfo() {
428 if (lineBuilderContext.getCollectionGroup().getUnauthorizedLineBindingInfos() == null) {
429 lineBuilderContext.getCollectionGroup().setUnauthorizedLineBindingInfos(new ArrayList<BindingInfo>());
430 }
431
432 BindingInfo bindingInfo = new BindingInfo();
433 bindingInfo.setDefaults(ViewLifecycle.getView(), lineBuilderContext.getBindingPath());
434 lineBuilderContext.getCollectionGroup().getUnauthorizedLineBindingInfos().add(bindingInfo);
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449 protected void applyLineFieldAuthorizationAndPresentationLogic(boolean readOnlyLine, List<Field> lineFields,
450 List<? extends Component> actionList) {
451 ViewPresentationController presentationController = ViewLifecycle.getView().getPresentationController();
452 ViewAuthorizer authorizer = ViewLifecycle.getView().getAuthorizer();
453
454 Person user = GlobalVariables.getUserSession().getPerson();
455 ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
456
457 CollectionGroup collectionGroup = lineBuilderContext.getCollectionGroup();
458 View view = ViewLifecycle.getView();
459 ViewModel model = lineBuilderContext.getModel();
460 Object currentLine = lineBuilderContext.getCurrentLine();
461
462 for (Field lineField : lineFields) {
463 String propertyName = null;
464 if (lineField instanceof DataBinding) {
465 propertyName = ((DataBinding) lineField).getPropertyName();
466 }
467
468
469
470 ComponentSecurity componentSecurity = lineField.getComponentSecurity();
471
472 Map<String, Object> context = getContextForField(ViewLifecycle.getView(), collectionGroup, lineField);
473 expressionEvaluator.evaluateExpressionsOnConfigurable(ViewLifecycle.getView(), componentSecurity, context);
474
475
476 if (!lineField.isRender() || lineField.isHidden()) {
477 continue;
478 }
479
480 boolean canViewField = authorizer.canViewLineField(view, model, collectionGroup,
481 collectionGroup.getPropertyName(), currentLine, lineField, propertyName, user);
482 if (canViewField) {
483 canViewField = presentationController.canViewLineField(view, model, collectionGroup,
484 collectionGroup.getPropertyName(), currentLine, lineField, propertyName);
485 }
486
487 if (!canViewField) {
488
489
490 lineField.setHidden(true);
491
492 if (lineField.getPropertyExpressions().containsKey(UifPropertyPaths.HIDDEN)) {
493 lineField.getPropertyExpressions().remove(UifPropertyPaths.HIDDEN);
494 }
495
496 continue;
497 }
498
499
500 boolean canEditField = !readOnlyLine;
501 if (!readOnlyLine) {
502 canEditField = authorizer.canEditLineField(view, model, collectionGroup,
503 collectionGroup.getPropertyName(), currentLine, lineField, propertyName, user);
504 if (canEditField) {
505 canEditField = presentationController.canEditLineField(view, model, collectionGroup,
506 collectionGroup.getPropertyName(), currentLine, lineField, propertyName);
507 }
508 }
509
510 if (readOnlyLine || !canEditField) {
511 lineField.setReadOnly(true);
512
513 if (lineField.getPropertyExpressions().containsKey(UifPropertyPaths.READ_ONLY)) {
514 lineField.getPropertyExpressions().remove(UifPropertyPaths.READ_ONLY);
515 }
516 }
517 }
518
519
520 List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(actionList, Action.class);
521 for (Action action : actions) {
522 if (!action.isRender()) {
523 continue;
524 }
525
526 boolean canPerformAction = authorizer.canPerformLineAction(view, model, collectionGroup,
527 collectionGroup.getPropertyName(), currentLine, action, action.getActionEvent(), action.getId(),
528 user);
529 if (canPerformAction) {
530 canPerformAction = presentationController.canPerformLineAction(view, model, collectionGroup,
531 collectionGroup.getPropertyName(), currentLine, action, action.getActionEvent(),
532 action.getId());
533 }
534
535 if (!canPerformAction) {
536 action.setRender(false);
537
538 if (action.getPropertyExpressions().containsKey(UifPropertyPaths.RENDER)) {
539 action.getPropertyExpressions().remove(UifPropertyPaths.RENDER);
540 }
541 }
542 }
543 }
544
545
546
547
548
549
550 protected void buildSubCollectionFieldGroups() {
551 CollectionGroup collectionGroup = lineBuilderContext.getCollectionGroup();
552 String idSuffix = lineBuilderContext.getIdSuffix();
553
554
555 if (lineBuilderContext.isAddLine() || (collectionGroup.getSubCollections() == null)) {
556 return;
557 }
558
559 List<FieldGroup> subCollectionFields = new ArrayList<FieldGroup>();
560 for (int subLineIndex = 0; subLineIndex < collectionGroup.getSubCollections().size(); subLineIndex++) {
561 CollectionGroup subCollectionPrototype = collectionGroup.getSubCollections().get(subLineIndex);
562 CollectionGroup subCollectionGroup = ComponentUtils.copy(subCollectionPrototype, idSuffix);
563
564
565 boolean renderSubCollection = checkSubCollectionRender(subCollectionGroup);
566 if (!renderSubCollection) {
567 continue;
568 }
569
570 subCollectionGroup.getBindingInfo().setBindByNamePrefix(lineBuilderContext.getBindingPath());
571 if (subCollectionGroup.isRenderAddLine()) {
572 subCollectionGroup.getAddLineBindingInfo().setBindByNamePrefix(lineBuilderContext.getBindingPath());
573 }
574
575
576 String subCollectionSuffix = idSuffix;
577 if (StringUtils.isNotBlank(subCollectionGroup.getSubCollectionSuffix())) {
578 subCollectionSuffix = subCollectionGroup.getSubCollectionSuffix() + idSuffix;
579 }
580 subCollectionGroup.setSubCollectionSuffix(subCollectionSuffix);
581
582 FieldGroup fieldGroupPrototype =
583 lineBuilderContext.getLayoutManager().getSubCollectionFieldGroupPrototype();
584
585 FieldGroup subCollectionFieldGroup = ComponentUtils.copy(fieldGroupPrototype,
586 idSuffix + UifConstants.IdSuffixes.SUB + subLineIndex);
587 subCollectionFieldGroup.setGroup(subCollectionGroup);
588
589 ComponentUtils.updateContextForLine(subCollectionFieldGroup, collectionGroup,
590 lineBuilderContext.getCurrentLine(), lineBuilderContext.getLineIndex(),
591 idSuffix + UifConstants.IdSuffixes.SUB + subLineIndex);
592 ComponentUtils.pushObjectToContext(subCollectionGroup, UifConstants.ContextVariableNames.PARENT_LINE,
593 lineBuilderContext.getCurrentLine());
594
595 subCollectionFields.add(subCollectionFieldGroup);
596 }
597
598 ComponentUtils.pushObjectToContext(subCollectionFields, UifConstants.ContextVariableNames.PARENT_LINE,
599 lineBuilderContext.getCurrentLine());
600
601 lineBuilderContext.setSubCollectionFields(subCollectionFields);
602 }
603
604
605
606
607
608
609
610
611 protected boolean checkSubCollectionRender(CollectionGroup subCollectionGroup) {
612 String conditionalRender = subCollectionGroup.getPropertyExpression(UifPropertyPaths.RENDER);
613
614
615
616
617 if (StringUtils.isNotBlank(conditionalRender)) {
618 Map<String, Object> context = new HashMap<String, Object>();
619 Map<String, Object> viewContext = ViewLifecycle.getView().getContext();
620
621 if (viewContext != null) {
622 context.putAll(viewContext);
623 }
624
625 context.put(UifConstants.ContextVariableNames.PARENT, lineBuilderContext.getCollectionGroup());
626 context.put(UifConstants.ContextVariableNames.COMPONENT, subCollectionGroup);
627
628 Boolean render = (Boolean) ViewLifecycle.getExpressionEvaluator().evaluateExpression(context,
629 conditionalRender);
630 subCollectionGroup.setRender(render);
631 }
632
633 return subCollectionGroup.isRender();
634 }
635
636
637
638
639
640 protected void setupAddLineControlValidation(List<Field> lineFields) {
641 if (!lineBuilderContext.isAddLine()) {
642 return;
643 }
644
645 String selector = "";
646 for (Field field : lineFields) {
647 if (field instanceof InputField) {
648
649
650 Control control = ((InputField) field).getControl();
651
652 if (control != null) {
653 control.addStyleClass(CssConstants.Classes.IGNORE_VALID);
654 selector = selector + ",#" + field.getId() + UifConstants.IdSuffixes.CONTROL;
655 }
656 } else if (field instanceof FieldGroup) {
657 List<InputField> fields = ViewLifecycleUtils.getElementsOfTypeDeep(((FieldGroup) field).getGroup(),
658 InputField.class);
659
660 for (InputField nestedField : fields) {
661 Control control = nestedField.getControl();
662
663 if (control != null) {
664 control.addStyleClass(CssConstants.Classes.IGNORE_VALID);
665 selector = selector + ",#" + nestedField.getId() + UifConstants.IdSuffixes.CONTROL;
666 }
667 }
668 }
669 }
670
671 lineBuilderContext.getCollectionGroup().addDataAttribute(UifConstants.DataAttributes.ADD_CONTROLS,
672 selector.replaceFirst(",", ""));
673 }
674
675
676
677
678
679
680
681
682
683
684 protected Map<String, Object> getContextForField(View view, CollectionGroup collectionGroup, Field field) {
685 Map<String, Object> context = new HashMap<String, Object>();
686
687 Map<String, Object> viewContext = view.getContext();
688 if (viewContext != null) {
689 context.putAll(viewContext);
690 }
691
692 Map<String, Object> fieldContext = field.getContext();
693 if (fieldContext != null) {
694 context.putAll(fieldContext);
695 }
696
697 context.put(UifConstants.ContextVariableNames.PARENT, collectionGroup);
698 context.put(UifConstants.ContextVariableNames.COMPONENT, field);
699
700 return context;
701 }
702 }