1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.util;
17
18 import java.beans.PropertyDescriptor;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Queue;
27 import java.util.Set;
28
29 import org.apache.commons.lang.StringUtils;
30 import org.kuali.rice.krad.uif.UifConstants;
31 import org.kuali.rice.krad.uif.component.Component;
32 import org.kuali.rice.krad.uif.component.DataBinding;
33 import org.kuali.rice.krad.uif.component.Ordered;
34 import org.kuali.rice.krad.uif.container.CollectionGroup;
35 import org.kuali.rice.krad.uif.container.Container;
36 import org.kuali.rice.krad.uif.field.Field;
37 import org.kuali.rice.krad.uif.field.FieldGroup;
38 import org.kuali.rice.krad.uif.field.InputField;
39 import org.kuali.rice.krad.uif.layout.LayoutManager;
40 import org.kuali.rice.krad.uif.layout.TableLayoutManager;
41 import org.springframework.beans.BeanUtils;
42 import org.springframework.core.OrderComparator;
43
44
45
46
47
48
49 public class ComponentUtils {
50
51 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ComponentUtils.class);
52
53 public static <T extends Component> T copy(T component) {
54 return copy(component, null);
55 }
56
57 public static <T extends Component> T copy(T component, String idSuffix) {
58 T copy = component.copy();
59
60 if (StringUtils.isNotBlank(idSuffix)) {
61 updateIdsWithSuffixNested(copy, idSuffix);
62 }
63
64 return copy;
65 }
66
67 @SuppressWarnings("unchecked")
68 protected static <T extends Object> T getNewInstance(T object) {
69 T copy = null;
70 try {
71 copy = (T) object.getClass().newInstance();
72 } catch (Exception e) {
73 throw new RuntimeException("Unable to create new instance of class: " + object.getClass());
74 }
75
76 return copy;
77 }
78
79
80
81
82
83 public static <T extends Field> void bindAndIdFieldList(List<T> fields, String addBindingPrefix, String idSuffix) {
84 updateIdsWithSuffixNested(fields, idSuffix);
85 prefixBindingPath(fields, addBindingPrefix);
86 }
87
88 public static <T extends Field> List<T> copyFieldList(List<T> fields, String addBindingPrefix, String idSuffix) {
89 List<T> copiedFieldList = copyFieldList(fields, idSuffix);
90
91 prefixBindingPath(copiedFieldList, addBindingPrefix);
92
93 return copiedFieldList;
94 }
95
96 public static <T extends Field> List<T> copyFieldList(List<T> fields, String idSuffix) {
97 if (fields == null || fields.isEmpty()) {
98 return Collections.emptyList();
99 }
100
101 List<T> copiedFieldList = new ArrayList<T>(fields.size());
102
103 for (T field : fields) {
104 T copiedField = copy(field, idSuffix);
105 copiedFieldList.add(copiedField);
106 }
107
108 return copiedFieldList;
109 }
110
111 public static <T extends Component> T copyComponent(T component, String addBindingPrefix, String idSuffix) {
112 T copy = copy(component, idSuffix);
113
114 prefixBindingPathNested(copy, addBindingPrefix);
115
116 return copy;
117 }
118
119 public static <T extends Component> List<T> copyComponentList(List<T> components, String idSuffix) {
120 if (components == null || components.isEmpty()) {
121 return Collections.emptyList();
122 }
123
124 List<T> copiedComponentList = new ArrayList<T>(components.size());
125
126 for (T field : components) {
127 T copiedComponent = copy(field, idSuffix);
128 copiedComponentList.add(copiedComponent);
129 }
130
131 return copiedComponentList;
132 }
133
134 public static <T extends Component> List<T> getComponentsOfType(List<? extends Component> items,
135 Class<T> componentType) {
136 if (items == null || items.isEmpty()) {
137 return Collections.emptyList();
138 }
139
140 List<T> typeComponents = Collections.emptyList();
141
142 for (Component component : items) {
143
144 if (!componentType.isInstance(component)) {
145 continue;
146 }
147
148 if (typeComponents.isEmpty()) {
149 typeComponents = new ArrayList<T>(items.size());
150 }
151
152 typeComponents.add(componentType.cast(component));
153 }
154
155 return typeComponents;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 public static <T extends Component> List<T> getComponentsOfTypeDeep(List<? extends Component> items,
173 Class<T> componentType) {
174 if (items == null) {
175 return Collections.emptyList();
176 }
177
178 List<T> components = Collections.emptyList();
179
180 Queue<Component> componentQueue = new LinkedList<Component>();
181 componentQueue.addAll(items);
182
183 while (!componentQueue.isEmpty()) {
184 Component currentComponent = componentQueue.poll();
185 if (currentComponent == null) {
186 continue;
187 }
188
189 if (componentType.isInstance(currentComponent)) {
190 if (components.isEmpty()) {
191 components = new ArrayList<T>();
192 }
193
194 components.add(componentType.cast(currentComponent));
195 }
196
197 componentQueue.addAll(currentComponent.getComponentsForLifecycle());
198 }
199
200 return components;
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public static <T extends Component> List<T> getComponentsOfTypeDeep(Component component, Class<T> componentType) {
218 return getComponentsOfTypeDeep(Collections.singletonList(component), componentType);
219 }
220
221
222
223
224
225
226
227
228
229
230 public static <T extends Component> List<T> getComponentsOfTypeShallow(Component component,
231 Class<T> componentType) {
232 if (component == null) {
233 return Collections.emptyList();
234 }
235
236 List<T> typeComponents = getNestedComponentsOfTypeShallow(component, componentType);
237
238 if (componentType.isInstance(component)) {
239 if (typeComponents.isEmpty()) {
240 typeComponents = Collections.singletonList(componentType.cast(component));
241 } else {
242 typeComponents.add(0, componentType.cast(component));
243 }
244 }
245
246 return typeComponents;
247 }
248
249
250
251
252
253
254
255
256
257
258 public static <T extends Component> List<T> getNestedComponentsOfTypeShallow(Component component,
259 Class<T> componentType) {
260 if (component == null) {
261 return Collections.emptyList();
262 }
263
264 List<T> typeComponents = Collections.emptyList();
265 List<Component> nestedComponents = component.getComponentsForLifecycle();
266
267 for (Component nested : nestedComponents) {
268
269 if (!componentType.isInstance(nested)) {
270 continue;
271 }
272
273 if (typeComponents.isEmpty()) {
274 typeComponents = new ArrayList<T>();
275 }
276
277 typeComponents.add(componentType.cast(nested));
278 }
279
280 return typeComponents;
281 }
282
283
284
285
286
287
288
289
290 public static List<Component> getAllNestedComponents(Component component) {
291 if (component == null) {
292 return Collections.emptyList();
293 }
294
295 List<Component> components = Collections.emptyList();
296 Queue<Component> componentQueue = new LinkedList<Component>();
297 componentQueue.offer(component);
298
299 while (!componentQueue.isEmpty()) {
300 Component currentComponent = componentQueue.poll();
301
302 if (currentComponent == null) {
303 continue;
304 }
305
306 if (currentComponent != component) {
307 if (components.isEmpty()) {
308 components = new ArrayList<Component>();
309 }
310
311 components.add(currentComponent);
312 }
313
314 componentQueue.addAll(currentComponent.getComponentsForLifecycle());
315 }
316
317 return components;
318 }
319
320
321
322
323
324
325
326
327 public static Component findComponentInList(List<Component> components, String componentId) {
328 for (Component component : components) {
329 if (component != null && StringUtils.equals(component.getId(), componentId)) {
330 return component;
331 }
332 }
333
334 return null;
335 }
336
337
338
339
340
341
342
343
344 public static Component findNestedComponentById(Component parent, String nestedId) {
345 if (parent == null) {
346 return null;
347 }
348
349 Queue<Component> componentQueue = new LinkedList<Component>();
350 componentQueue.offer(parent);
351
352 while (!componentQueue.isEmpty()) {
353 Component child = componentQueue.poll();
354
355 if (child == null) {
356 continue;
357 }
358
359 if (child != parent && StringUtils.equals(nestedId, child.getId())) {
360 return child;
361 }
362
363 componentQueue.addAll(child.getComponentsForLifecycle());
364 }
365
366 return null;
367 }
368
369 public static void prefixBindingPath(List<? extends Field> fields, String addBindingPrefix) {
370 for (Field field : fields) {
371 if (field instanceof DataBinding) {
372 prefixBindingPath((DataBinding) field, addBindingPrefix);
373 } else if ((field instanceof FieldGroup) && (((FieldGroup) field).getItems() != null)) {
374 List<Field> groupFields = getComponentsOfTypeDeep(((FieldGroup) field).getItems(), Field.class);
375 prefixBindingPath(groupFields, addBindingPrefix);
376 }
377 }
378 }
379
380 public static void prefixBindingPathNested(Component component, String addBindingPrefix) {
381 if (component instanceof DataBinding) {
382 if (LOG.isDebugEnabled()) {
383 LOG.info("setting nested binding prefix '" + addBindingPrefix + "' on " + component);
384 }
385 prefixBindingPath((DataBinding) component, addBindingPrefix);
386 }
387
388 for (Component nested : component.getComponentsForLifecycle()) {
389 if (nested != null) {
390 prefixBindingPathNested(nested, addBindingPrefix);
391 }
392 }
393 }
394
395 public static void prefixBindingPath(DataBinding field, String addBindingPrefix) {
396 String bindingPrefix = addBindingPrefix;
397 if (StringUtils.isNotBlank(field.getBindingInfo().getBindByNamePrefix())) {
398 bindingPrefix += "." + field.getBindingInfo().getBindByNamePrefix();
399 }
400 field.getBindingInfo().setBindByNamePrefix(bindingPrefix);
401 }
402
403 public static void updateIdsWithSuffixNested(List<? extends Component> components, String idSuffix) {
404 for (Component component : components) {
405 updateIdsWithSuffixNested(component, idSuffix);
406 }
407 }
408
409 public static void updateIdsWithSuffixNested(Component component, String idSuffix) {
410 updateIdWithSuffix(component, idSuffix);
411
412 updateChildIdsWithSuffixNested(component, idSuffix);
413 }
414
415 public static void updateChildIdsWithSuffixNested(Component component, String idSuffix) {
416 for (Component nested : component.getComponentsForLifecycle()) {
417 if (nested != null) {
418 updateIdsWithSuffixNested(nested, idSuffix);
419 }
420 }
421
422 List<Component> propertyReplacerComponents = component.getPropertyReplacerComponents();
423 if (propertyReplacerComponents != null) {
424 for (Component nested : propertyReplacerComponents) {
425 if (nested != null) {
426 updateIdsWithSuffixNested(nested, idSuffix);
427 }
428 }
429 }
430 }
431
432
433
434
435
436
437
438 public static void clearIds(Component component) {
439 component.setId(null);
440
441 if (Container.class.isAssignableFrom(component.getClass())) {
442 LayoutManager layoutManager = ((Container) component).getLayoutManager();
443 layoutManager.setId(null);
444 }
445
446 for (Component nested : component.getComponentsForLifecycle()) {
447 if (nested != null) {
448 clearIds(nested);
449 }
450 }
451
452 List<Component> propertyReplacerComponents = component.getPropertyReplacerComponents();
453 if (propertyReplacerComponents != null) {
454 for (Component nested : propertyReplacerComponents) {
455 if (nested != null) {
456 clearIds(nested);
457 }
458 }
459 }
460 }
461
462 public static void clearIds(List<? extends Component> components) {
463 for (Component component : components) {
464 if (component != null) {
465 clearIds(component);
466 }
467 }
468 }
469
470
471
472
473
474
475
476 public static void updateIdWithSuffix(Component component, String idSuffix) {
477 if (component != null && !StringUtils.isEmpty(idSuffix)) {
478 component.setId(component.getId() + idSuffix);
479 }
480
481 if (component instanceof Container) {
482 LayoutManager manager = ((Container) component).getLayoutManager();
483 if (manager != null) {
484 manager.setId(manager.getId() + idSuffix);
485 }
486 }
487 }
488
489 public static void setComponentsPropertyDeep(List<? extends Component> components, String propertyPath,
490 Object propertyValue) {
491 for (Component component : components) {
492 setComponentPropertyDeep(component, propertyPath, propertyValue);
493 }
494 }
495
496 public static void setComponentPropertyDeep(Component component, String propertyPath, Object propertyValue) {
497 ObjectPropertyUtils.setPropertyValue(component, propertyPath, propertyValue, true);
498
499 for (Component nested : component.getComponentsForLifecycle()) {
500 if (nested != null) {
501 setComponentPropertyDeep(nested, propertyPath, propertyValue);
502 }
503 }
504 }
505
506 public static List<String> getComponentPropertyNames(Class<? extends Component> componentClass) {
507 List<String> componentProperties = new ArrayList<String>();
508
509 PropertyDescriptor[] properties = BeanUtils.getPropertyDescriptors(componentClass);
510 for (int i = 0; i < properties.length; i++) {
511 PropertyDescriptor descriptor = properties[i];
512 if (descriptor.getReadMethod() != null) {
513 componentProperties.add(descriptor.getName());
514 }
515 }
516
517 return componentProperties;
518 }
519
520
521
522
523
524
525
526
527
528 public static void setComponentPropertyFinal(Component component, String propertyName, Object propertyValue) {
529 if (component == null) {
530 return;
531 }
532
533 ObjectPropertyUtils.setPropertyValue(component, propertyName, propertyValue);
534
535 if ((component.getPropertyExpressions() != null) && component.getPropertyExpressions().containsKey(
536 propertyName)) {
537 component.getPropertyExpressions().remove(propertyName);
538 }
539 }
540
541
542
543
544
545
546
547
548 public static void pushObjectToContext(List<? extends Component> components, String contextName,
549 Object contextValue) {
550 if (components == null || components.isEmpty()) {
551 return;
552 }
553
554 Queue<Component> componentQueue = new LinkedList<Component>();
555 componentQueue.addAll(components);
556
557 while (!componentQueue.isEmpty()) {
558 Component currentComponent = componentQueue.poll();
559
560 if (currentComponent == null) {
561 continue;
562 }
563
564 currentComponent.pushObjectToContext(contextName, contextValue);
565
566 if (currentComponent instanceof Container) {
567 LayoutManager layoutManager = ((Container) currentComponent).getLayoutManager();
568 if (layoutManager != null) {
569 layoutManager.pushObjectToContext(contextName, contextValue);
570 }
571 }
572
573 componentQueue.addAll(currentComponent.getComponentsForLifecycle());
574 }
575 }
576
577
578
579
580
581
582
583
584
585
586
587 public static void pushObjectToContext(Component component, String contextName, Object contextValue) {
588 if (component == null) {
589 return;
590 }
591
592 pushObjectToContext(Collections.singletonList(component), contextName, contextValue);
593 }
594
595
596
597
598
599
600
601 public static void pushAllToContext(List<? extends Component> components, Map<String, Object> sourceContext) {
602 if (components == null || components.isEmpty()) {
603 return;
604 }
605
606 Queue<Component> componentQueue = new LinkedList<Component>();
607 componentQueue.addAll(components);
608
609 while (!componentQueue.isEmpty()) {
610 Component currentComponent = componentQueue.poll();
611
612 if (currentComponent == null) {
613 continue;
614 }
615
616 currentComponent.pushAllToContext(sourceContext);
617
618 if (currentComponent instanceof Container) {
619 LayoutManager layoutManager = ((Container) currentComponent).getLayoutManager();
620 if (layoutManager != null) {
621 layoutManager.pushAllToContext(sourceContext);
622 }
623 }
624
625 componentQueue.addAll(currentComponent.getComponentsForLifecycle());
626 }
627 }
628
629
630
631
632
633
634
635
636
637
638 public static void pushAllToContext(Component component, Map<String, Object> sourceContext) {
639 if (component == null) {
640 return;
641 }
642
643 pushAllToContext(Collections.singletonList(component), sourceContext);
644 }
645
646
647
648
649
650
651
652
653
654
655
656
657 public static void updateContextsForLine(List<? extends Component> components, Object collectionLine, int lineIndex,
658 String lineSuffix) {
659 for (Component component : components) {
660 updateContextForLine(component, collectionLine, lineIndex, lineSuffix);
661 }
662 }
663
664
665
666
667
668
669
670
671
672
673
674
675 public static void updateContextForLine(Component component, Object collectionLine, int lineIndex,
676 String lineSuffix) {
677 Map<String, Object> toUpdate = new HashMap<String,Object>(4);
678 toUpdate.put(UifConstants.ContextVariableNames.LINE, collectionLine);
679 toUpdate.put(UifConstants.ContextVariableNames.INDEX, Integer.valueOf(lineIndex));
680 toUpdate.put(UifConstants.ContextVariableNames.LINE_SUFFIX, lineSuffix);
681
682 boolean isAddLine = (lineIndex == -1);
683 toUpdate.put(UifConstants.ContextVariableNames.IS_ADD_LINE, isAddLine);
684 pushAllToContext(component, toUpdate);
685 }
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 public static List<? extends Ordered> sort(List<? extends Ordered> items, int defaultOrderSequence) {
707 if (items == null) {
708 return null;
709 }
710
711 List<Ordered> orderedItems = new ArrayList<Ordered>(items.size());
712
713
714 Set<Integer> foundOrders = new HashSet<Integer>();
715
716
717 for (int i = items.size()-1; i >= 0; i--) {
718 Ordered component = items.get(i);
719 int order = component.getOrder();
720
721
722 if (order == 0) {
723 orderedItems.add(component);
724 }
725
726 else if (!foundOrders.contains(Integer.valueOf(order))) {
727 orderedItems.add(component);
728 foundOrders.add(Integer.valueOf(order));
729 }
730 }
731
732
733
734 for (int i = 0; i < items.size(); i++) {
735 Ordered component = items.get(i);
736 int order = component.getOrder();
737
738
739 if (order == 0) {
740 defaultOrderSequence++;
741 while (foundOrders.contains(Integer.valueOf(defaultOrderSequence))) {
742 defaultOrderSequence++;
743 }
744 component.setOrder(defaultOrderSequence);
745 }
746 }
747
748
749 Collections.sort(orderedItems, new OrderComparator());
750
751 return orderedItems;
752 }
753
754
755
756
757
758
759
760
761 public static List<InputField> getAllInputFieldsWithinContainer(Container container) {
762 List<InputField> inputFields = new ArrayList<InputField>();
763
764 for (Component c : container.getComponentsForLifecycle()) {
765 if (c instanceof InputField) {
766 inputFields.add((InputField) c);
767 } else if (c instanceof Container) {
768 inputFields.addAll(getAllInputFieldsWithinContainer((Container) c));
769 } else if (c instanceof FieldGroup) {
770 Container cb = ((FieldGroup) c).getGroup();
771
772 inputFields.addAll(getAllInputFieldsWithinContainer(cb));
773 }
774 }
775
776 return inputFields;
777 }
778
779
780
781
782
783
784
785
786
787
788 public static boolean containsPropertyExpression(Component component, String propertyName,
789 boolean collectionMatch) {
790 boolean hasExpression = false;
791
792 Map<String, String> propertyExpressions = component.getPropertyExpressions();
793
794 if (collectionMatch) {
795 for (String expressionPropertyName : propertyExpressions.keySet()) {
796 if (expressionPropertyName.startsWith(propertyName)) {
797 hasExpression = true;
798 }
799 }
800 } else if (propertyExpressions.containsKey(propertyName)) {
801 hasExpression = true;
802 }
803
804 return hasExpression;
805 }
806
807
808
809
810
811
812
813
814 public static void adjustNestedLevelsForTableCollections(Container container, int currentLevel) {
815 if (container != null
816 && container instanceof CollectionGroup
817 && container.getLayoutManager() != null
818 && container.getLayoutManager() instanceof TableLayoutManager
819 && ((TableLayoutManager) container.getLayoutManager()).getRichTable() != null
820 && ((TableLayoutManager) container.getLayoutManager()).getRichTable().isRender()
821 && ((TableLayoutManager) container.getLayoutManager()).getRichTable().isForceLocalJsonData()) {
822 ((TableLayoutManager) container.getLayoutManager()).getRichTable().setNestedLevel(currentLevel);
823 currentLevel++;
824 }
825
826 if (container != null) {
827 List<Container> subContainers = ComponentUtils.getNestedComponentsOfTypeShallow(container, Container.class);
828 for (Container subContainer : subContainers) {
829 adjustNestedLevelsForTableCollections(subContainer, currentLevel);
830 }
831
832 List<FieldGroup> subFieldGroups = ComponentUtils.getNestedComponentsOfTypeShallow(container,
833 FieldGroup.class);
834 for (FieldGroup fieldGroup : subFieldGroups) {
835 if (fieldGroup != null) {
836 adjustNestedLevelsForTableCollections(fieldGroup.getGroup(), currentLevel);
837 }
838 }
839 }
840 }
841
842 }