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