1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.common.assembly.data;
17
18 import java.io.Serializable;
19 import java.sql.Time;
20 import java.sql.Timestamp;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.Map.Entry;
29
30 import javax.xml.bind.annotation.XmlRootElement;
31 import javax.xml.bind.annotation.XmlType;
32
33
34
35
36
37
38
39 @SuppressWarnings({"serial", "unchecked"})
40 public class Data implements Serializable, Iterable<Data.Property>, HasChangeCallbacks {
41 @XmlType(name = "lookUpDataType")
42 public enum DataType {
43 STRING, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN, DATE, TRUNCATED_DATE, DATA, LIST
44 }
45
46 @XmlRootElement
47 public static class BooleanValue implements Value {
48 private Boolean value;
49
50 protected BooleanValue() {
51
52 }
53
54 public BooleanValue(final Boolean value) {
55 this.value = value;
56 }
57
58 @Override
59 public <T> T get() {
60 return (T) value;
61 }
62
63 @Override
64 public Class getType() {
65 return Boolean.class;
66 }
67
68 @Override
69 public String toString() {
70 if (value == null) {
71 return "";
72 } else {
73 return String.valueOf(value);
74 }
75 }
76 }
77
78 @XmlRootElement
79 public static class DataValue implements Value {
80 private Data value;
81
82 protected DataValue() {
83
84 }
85
86 public DataValue(final Data value) {
87 this.value = value;
88 }
89
90 @Override
91 public <T> T get() {
92 return (T) value;
93 }
94
95 @Override
96 public Class getType() {
97 return Data.class;
98 }
99
100 @Override
101 public String toString() {
102 if (value == null) {
103 return null;
104 } else {
105 return value.toString();
106 }
107 }
108 }
109
110 @XmlRootElement
111 public static class DateValue implements Value {
112 private Date value;
113
114 protected DateValue() {
115
116 }
117
118 public DateValue(final Date value) {
119 this.value = value;
120 }
121
122 @Override
123 public <T> T get() {
124 return (T) value;
125 }
126
127 @Override
128 public Class getType() {
129 return Date.class;
130 }
131
132 @Override
133 public String toString() {
134 if (value == null) {
135 return null;
136 } else {
137 return String.valueOf(value);
138 }
139 }
140 }
141
142 @XmlRootElement
143 public static class DoubleValue implements Value {
144 private Double value;
145
146 protected DoubleValue() {
147
148 }
149
150 public DoubleValue(final Double value) {
151 this.value = value;
152 }
153
154 @Override
155 public <T> T get() {
156 return (T) value;
157 }
158
159 @Override
160 public Class getType() {
161 return Double.class;
162 }
163
164 @Override
165 public String toString() {
166 if (value == null) {
167 return null;
168 } else {
169 return String.valueOf(value);
170 }
171 }
172 }
173
174 @XmlRootElement
175 public static class FloatValue implements Value {
176 private Float value;
177
178 protected FloatValue() {
179
180 }
181
182 public FloatValue(final Float value) {
183 this.value = value;
184 }
185
186 @Override
187 public <T> T get() {
188 return (T) value;
189 }
190
191 @Override
192 public Class getType() {
193 return Float.class;
194 }
195
196 @Override
197 public String toString() {
198 if (value == null) {
199 return null;
200 } else {
201 return String.valueOf(value);
202 }
203 }
204 }
205
206 public static class IntegerKey implements Key {
207 private Integer key;
208
209 protected IntegerKey() {
210
211 }
212
213 public IntegerKey(final Integer key) {
214 this.key = key;
215 }
216
217
218
219
220
221
222
223 @Override
224 public boolean equals(final Object obj) {
225 return obj instanceof IntegerKey && key.equals(((IntegerKey) obj).key);
226 }
227
228 @Override
229 public <T> T get() {
230 return (T) key;
231 }
232
233 @Override
234 public Class getType() {
235 return Integer.class;
236 }
237
238
239
240
241
242
243
244 @Override
245 public int hashCode() {
246 return key.hashCode();
247 }
248
249
250
251
252
253
254
255 @Override
256 public String toString() {
257 return String.valueOf(key);
258 }
259
260 }
261
262 @XmlRootElement
263 public static class IntegerValue implements Value {
264 private Integer value;
265
266 protected IntegerValue() {
267
268 }
269
270 public IntegerValue(final Integer value) {
271 this.value = value;
272 }
273
274 @Override
275 public <T> T get() {
276 return (T) value;
277 }
278
279 @Override
280 public Class getType() {
281 return Integer.class;
282 }
283
284 @Override
285 public String toString() {
286 if (value == null) {
287 return null;
288 } else {
289 return String.valueOf(value);
290 }
291 }
292 }
293
294 public interface Key extends Serializable {
295
296 <T> T get();
297
298 Class getType();
299 }
300
301 @XmlRootElement
302 public static class LongValue implements Value {
303 private Long value;
304
305 protected LongValue() {
306
307 }
308
309 public LongValue(final Long value) {
310 this.value = value;
311 }
312
313 @Override
314 public <T> T get() {
315 return (T) value;
316 }
317
318 @Override
319 public Class getType() {
320 return Long.class;
321 }
322
323 @Override
324 public String toString() {
325 if (value == null) {
326 return null;
327 } else {
328 return String.valueOf(value);
329 }
330 }
331 }
332
333 public interface Property {
334 <T> T getKey();
335
336 Class getKeyType();
337
338 Key getWrappedKey();
339
340 <T> T getValue();
341
342 Class getValueType();
343
344 Value getWrappedValue();
345 }
346
347 @XmlRootElement
348 public static class ShortValue implements Value {
349 private Short value;
350
351 protected ShortValue() {
352
353 }
354
355 public ShortValue(final Short value) {
356 this.value = value;
357 }
358
359 @Override
360 public <T> T get() {
361 return (T) value;
362 }
363
364 @Override
365 public Class getType() {
366 return Short.class;
367 }
368
369 @Override
370 public String toString() {
371 if (value == null) {
372 return null;
373 } else {
374 return String.valueOf(value);
375 }
376 }
377 }
378
379 @XmlRootElement
380 public static class StringKey implements Key {
381 private String key;
382
383 protected StringKey() {
384
385 }
386
387 public StringKey(final String key) {
388 this.key = key;
389 }
390
391
392
393
394
395
396
397 @Override
398 public boolean equals(final Object obj) {
399 return obj instanceof StringKey && key.equals(((StringKey) obj).key);
400 }
401
402 @Override
403 public <T> T get() {
404 return (T) key;
405 }
406
407 @Override
408 public Class<?> getType() {
409 return String.class;
410 }
411
412
413
414
415
416
417
418 @Override
419 public int hashCode() {
420 return key.hashCode();
421 }
422
423
424
425
426
427
428
429 @Override
430 public String toString() {
431 return key;
432 }
433
434 }
435
436 @XmlRootElement
437 public static class StringValue implements Value {
438 private String value;
439
440 protected StringValue() {
441
442 }
443
444 public StringValue(final String value) {
445 this.value = value;
446 }
447
448 @Override
449 public <T> T get() {
450 return (T) value;
451 }
452
453 @Override
454 public Class getType() {
455 return String.class;
456 }
457
458 @Override
459 public String toString() {
460 return value;
461 }
462
463 public void setValue(String value) {
464 this.value = value;
465 }
466 }
467
468 @XmlRootElement
469 public static class TimestampValue implements Value {
470 private Timestamp value;
471
472 protected TimestampValue() {
473
474 }
475
476 public TimestampValue(final Timestamp value) {
477 this.value = value;
478 }
479
480 @Override
481 public <T> T get() {
482 return (T) value;
483 }
484
485 @Override
486 public Class getType() {
487 return Timestamp.class;
488 }
489
490 @Override
491 public String toString() {
492 if (value == null) {
493 return null;
494 } else {
495 return String.valueOf(value);
496 }
497 }
498 }
499
500 @XmlRootElement
501 public static class TimeValue implements Value {
502 private Time value;
503
504 protected TimeValue() {
505
506 }
507
508 public TimeValue(final Time value) {
509 this.value = value;
510 }
511
512 @Override
513 public <T> T get() {
514 return (T) value;
515 }
516
517 @Override
518 public Class getType() {
519 return Time.class;
520 }
521
522 @Override
523 public String toString() {
524 if (value == null) {
525 return null;
526 } else {
527 return String.valueOf(value);
528 }
529 }
530 }
531
532
533
534
535
536
537
538 public interface Value extends Serializable {
539 <T> T get();
540
541 Class getType();
542 }
543
544 public static final Key WILDCARD_KEY = new Data.StringKey(QueryPath.getWildCard());
545
546 private transient Set<ChangeCallback> changeCallbacks;
547
548 private String className;
549
550 private Map<Key, Value> map;
551
552 private Data parent = null;
553
554 private Key parentKey = null;
555
556 public Data() {
557 this(Data.class.getName());
558 }
559
560 public Data(final String className) {
561 this.className = className;
562 map = new LinkedHashMap<Key, Value>();
563 }
564
565 protected void _getQueryPath(final QueryPath path) {
566 if (parent != null) {
567 parent._getQueryPath(path);
568 path.add(parentKey);
569 }
570 }
571
572 protected void execChangeCallbacks(ChangeType type, QueryPath path) {
573 if (changeCallbacks != null) {
574 for (ChangeCallback c : changeCallbacks) {
575 c.onChange(type, path);
576 }
577 }
578 if (parent != null) {
579 parent.execChangeCallbacks(type, path);
580 }
581 }
582
583 public ChangeCallbackRegistration addChangeCallback(final ChangeCallback callback) {
584 if (changeCallbacks == null) {
585 changeCallbacks = new HashSet<ChangeCallback>();
586 }
587 changeCallbacks.add(callback);
588 return new ChangeCallbackRegistration() {
589 @Override
590 public void remove() {
591 if (changeCallbacks != null) {
592 changeCallbacks.remove(callback);
593 }
594 }
595 };
596 }
597
598 private void put(Key key, Value value) {
599 Value existing = map.put(key, value);
600 ChangeType type = existing == null ? ChangeType.ADD : ChangeType.UPDATE;
601 QueryPath path = getQueryPath();
602 path.add(key);
603 execChangeCallbacks(type, path);
604 }
605
606 public void remove(Key key) {
607
608 map.remove(key);
609 QueryPath path = getQueryPath();
610 path.add(key);
611 execChangeCallbacks(ChangeType.REMOVE, path);
612 }
613
614 public void add(final Boolean value) {
615 put(new IntegerKey(map.size()), new BooleanValue(value));
616 }
617
618 public void add(final Data value) {
619 final Key k = new IntegerKey(map.size());
620 put(k, new DataValue(value));
621 if (value != null) {
622 value.parent = this;
623 value.parentKey = k;
624 }
625 }
626
627 public void add(final Date value) {
628 put(new IntegerKey(map.size()), new DateValue(value));
629 }
630
631 public void add(final Double value) {
632 put(new IntegerKey(map.size()), new DoubleValue(value));
633 }
634
635 public void add(final Float value) {
636 put(new IntegerKey(map.size()), new FloatValue(value));
637 }
638
639 public void add(final Integer value) {
640 put(new IntegerKey(map.size()), new IntegerValue(value));
641 }
642
643 public void add(final Long value) {
644 put(new IntegerKey(map.size()), new LongValue(value));
645 }
646
647 public void add(final Short value) {
648 put(new IntegerKey(map.size()), new ShortValue(value));
649 }
650
651 public void add(final String value) {
652 put(new IntegerKey(map.size()), new StringValue(value));
653 }
654
655 public void add(final Time value) {
656 put(new IntegerKey(map.size()), new TimeValue(value));
657 }
658
659 public void add(final Timestamp value) {
660 put(new IntegerKey(map.size()), new TimestampValue(value));
661 }
662
663 public Data copy() {
664 return copy(new Data(this.className), true);
665 }
666
667 public Data copy(Data target, boolean recurse) {
668
669
670 for (final Entry<Key, Value> e : map.entrySet()) {
671 if (recurse && e.getValue().getType().equals(Data.class)) {
672 Data value = e.getValue().get();
673 if (value != null) {
674 value = value.copy();
675 }
676 target.map.put(e.getKey(), new DataValue(value));
677 } else {
678 target.map.put(e.getKey(), e.getValue());
679 }
680 }
681 return target;
682 }
683
684 public <T> T get(final Integer key) {
685 final Value v = map.get(new IntegerKey(key));
686 T result = null;
687 if (v != null) {
688 result = (T) v.get();
689 }
690 return result;
691 }
692
693 public <T> T get(final Key key) {
694 final Value v = map.get(key);
695 T result = null;
696 if (v != null) {
697 result = (T) v.get();
698 }
699 return result;
700 }
701
702 public <T> T get(final String key) {
703 final Value v = map.get(new StringKey(key));
704 T result = null;
705 if (v != null) {
706 result = (T) v.get();
707 }
708 return result;
709 }
710
711 public String getClassName() {
712 return this.className;
713 }
714
715 public Data getParent() {
716 return parent;
717 }
718
719 public QueryPath getQueryPath() {
720 final QueryPath result = new QueryPath();
721 _getQueryPath(result);
722 return result;
723 }
724
725
726
727
728
729 public Iterator<Property> realPropertyIterator() {
730 HashMap<Key, Value> propertyMap = new HashMap<Key, Value>(map);
731
732 propertyMap.remove(new StringKey("_runtimeData"));
733
734 final Iterator<Map.Entry<Key, Value>> impl = propertyMap.entrySet().iterator();
735
736 return new Iterator<Property>() {
737 Map.Entry<Key, Value> current;
738
739 @Override
740 public boolean hasNext() {
741 return impl.hasNext();
742 }
743
744 @Override
745 public Property next() {
746 final Map.Entry<Key, Value> entry = impl.next();
747 current = entry;
748 return new Property() {
749 @Override
750 public <T> T getKey() {
751 return (T) entry.getKey().get();
752 }
753
754 @Override
755 public Class<?> getKeyType() {
756 return entry.getKey().getType();
757 }
758
759 @Override
760 public <T> T getValue() {
761 return (T) entry.getValue().get();
762 }
763
764 @Override
765 public Class<?> getValueType() {
766 return entry.getValue().getType();
767 }
768
769 @Override
770 public Key getWrappedKey() {
771 return entry.getKey();
772 }
773
774 @Override
775 public Value getWrappedValue() {
776 return entry.getValue();
777 }
778 };
779 }
780
781 @Override
782 public void remove() {
783 impl.remove();
784 QueryPath path = getQueryPath();
785 path.add(current.getKey());
786 execChangeCallbacks(ChangeType.REMOVE, path);
787 }
788 };
789 }
790
791
792
793
794
795
796
797 @Override
798 public Iterator<Property> iterator() {
799 final Iterator<Map.Entry<Key, Value>> impl = map.entrySet().iterator();
800
801 return new Iterator<Property>() {
802 Map.Entry<Key, Value> current;
803
804 @Override
805 public boolean hasNext() {
806 return impl.hasNext();
807 }
808
809 @Override
810 public Property next() {
811 final Map.Entry<Key, Value> entry = impl.next();
812 current = entry;
813 return new Property() {
814 @Override
815 public <T> T getKey() {
816 return (T) entry.getKey().get();
817 }
818
819 @Override
820 public Class<?> getKeyType() {
821 return entry.getKey().getType();
822 }
823
824 @Override
825 public <T> T getValue() {
826 return (T) entry.getValue().get();
827 }
828
829 @Override
830 public Class<?> getValueType() {
831 return entry.getValue().getType();
832 }
833
834 @Override
835 public Key getWrappedKey() {
836 return entry.getKey();
837 }
838
839 @Override
840 public Value getWrappedValue() {
841 return entry.getValue();
842 }
843 };
844 }
845
846 @Override
847 public void remove() {
848 impl.remove();
849 QueryPath path = getQueryPath();
850 path.add(current.getKey());
851 execChangeCallbacks(ChangeType.REMOVE, path);
852 }
853 };
854 }
855
856 public <T> T query(final QueryPath path) {
857 T result = null;
858 Data d = this;
859 for (final Iterator itr = path.iterator(); itr.hasNext() && d != null;) {
860 final Key k = (Key) itr.next();
861 if (itr.hasNext()) {
862 Object obj = d.get(k);
863 if (obj != null && !(obj instanceof Data)) {
864
865
866
867 throw new java.lang.IllegalArgumentException();
868 } else {
869 d = d.get(k);
870 }
871 } else {
872 result = (T) d.get(k);
873 }
874 }
875 return result;
876 }
877
878 public <T> T query(final String path) {
879 return (T) query(QueryPath.parse(path));
880 }
881
882 public Class<?> getType(final QueryPath path) {
883 Value result = null;
884 Data d = this;
885 for (final Iterator itr = path.iterator(); itr.hasNext();) {
886 final Key k = (Key) itr.next();
887 if (itr.hasNext()) {
888 d = d.get(k);
889 } else {
890 result = map.get(k);
891 }
892 }
893 return result.getType();
894
895 }
896
897 public void set(final Integer key, final Boolean value) {
898 put(new IntegerKey(key), new BooleanValue(value));
899 }
900
901 public void set(final Integer key, final Data value) {
902 final Key k = new IntegerKey(key);
903 put(k, new DataValue(value));
904 if (value != null) {
905 value.parent = this;
906 value.parentKey = k;
907 }
908 }
909
910 public void set(final Integer key, final Date value) {
911 put(new IntegerKey(key), new DateValue(value));
912 }
913
914 public void set(final Integer key, final Double value) {
915 put(new IntegerKey(key), new DoubleValue(value));
916 }
917
918 public void set(final Integer key, final Float value) {
919 put(new IntegerKey(key), new FloatValue(value));
920 }
921
922 public void set(final Integer key, final Integer value) {
923 put(new IntegerKey(key), new IntegerValue(value));
924 }
925
926 public void set(final Integer key, final Long value) {
927 put(new IntegerKey(key), new LongValue(value));
928 }
929
930 public void set(final Integer key, final Short value) {
931 put(new IntegerKey(key), new ShortValue(value));
932 }
933
934 public void set(final Integer key, final String value) {
935 put(new IntegerKey(key), new StringValue(value));
936 }
937
938 public void set(final Integer key, final Time value) {
939 put(new IntegerKey(key), new TimeValue(value));
940 }
941
942 public void set(final Integer key, final Timestamp value) {
943 put(new IntegerKey(key), new TimestampValue(value));
944 }
945
946 public void set(final Key key, final Boolean value) {
947 put(key, new BooleanValue(value));
948 }
949
950 public void set(final Key key, final Data value) {
951 put(key, new DataValue(value));
952 if (value != null) {
953 value.parent = this;
954 value.parentKey = key;
955 }
956 }
957
958 public void set(final Key key, final Date value) {
959 put(key, new DateValue(value));
960 }
961
962 public void set(final Key key, final Double value) {
963 put(key, new DoubleValue(value));
964 }
965
966 public void set(final Key key, final Float value) {
967 put(key, new FloatValue(value));
968 }
969
970 public void set(final Key key, final Integer value) {
971 put(key, new IntegerValue(value));
972 }
973
974 public void set(final Key key, final Long value) {
975 put(key, new LongValue(value));
976 }
977
978 public void set(final Key key, final Short value) {
979 put(key, new ShortValue(value));
980 }
981
982 public void set(final Key key, final String value) {
983 put(key, new StringValue(value));
984 }
985
986 public void set(final Key key, final Time value) {
987 put(key, new TimeValue(value));
988 }
989
990 public void set(final Key key, final Timestamp value) {
991 put(key, new TimestampValue(value));
992 }
993
994 public void set(final Key key, final Value value) {
995 put(key, value);
996 if (value instanceof DataValue) {
997 final Data d = value.get();
998 if (d != null) {
999 d.parent = this;
1000 d.parentKey = key;
1001 }
1002 }
1003 }
1004
1005 public void set(final String key, final Boolean value) {
1006 put(new StringKey(key), new BooleanValue(value));
1007 }
1008
1009 public void set(final String key, final Data value) {
1010 final Key k = new StringKey(key);
1011 put(k, new DataValue(value));
1012 if (value != null) {
1013 value.parent = this;
1014 value.parentKey = k;
1015 }
1016 }
1017
1018 public void set(final String key, final Date value) {
1019 put(new StringKey(key), new DateValue(value));
1020 }
1021
1022 public void set(final String key, final Double value) {
1023 put(new StringKey(key), new DoubleValue(value));
1024 }
1025
1026 public void set(final String key, final Float value) {
1027 put(new StringKey(key), new FloatValue(value));
1028 }
1029
1030 public void set(final String key, final Integer value) {
1031 put(new StringKey(key), new IntegerValue(value));
1032 }
1033
1034 public void set(final String key, final Long value) {
1035 put(new StringKey(key), new LongValue(value));
1036 }
1037
1038 public void set(final String key, final Short value) {
1039 put(new StringKey(key), new ShortValue(value));
1040 }
1041
1042 public void set(final String key, final String value) {
1043 put(new StringKey(key), new StringValue(value));
1044 }
1045
1046 public void set(final String key, final Time value) {
1047 put(new StringKey(key), new TimeValue(value));
1048 }
1049
1050 public void set(final String key, final Timestamp value) {
1051 put(new StringKey(key), new TimestampValue(value));
1052 }
1053
1054 public Integer size() {
1055 return map.size();
1056 }
1057
1058 public String toString() {
1059 return _toXmlString("");
1060 }
1061
1062
1063
1064
1065
1066 private String _toString(){
1067 StringBuffer dataString = new StringBuffer();
1068
1069 dataString.append("{");
1070 for (Iterator itr = this.iterator(); itr.hasNext();) {
1071 Property p = (Property) itr.next();
1072 dataString.append(p.getKey() + "=" + p.getValue());
1073 if (itr.hasNext()) {
1074 dataString.append(", ");
1075 }
1076 }
1077 dataString.append("}");
1078
1079 return dataString.toString();
1080 }
1081
1082
1083
1084
1085
1086 private String _toXmlString(String indent){
1087 StringBuffer dataString = new StringBuffer();
1088
1089 for (Iterator itr = this.iterator(); itr.hasNext();) {
1090 Property p = (Property) itr.next();
1091 Object value = p.getValue();
1092 if (value instanceof Data){
1093 if (p.getKey() instanceof Integer){
1094 dataString.append(indent + "<listitem index=\"" + p.getKey() + "\">\n");
1095 dataString.append(((Data)value)._toXmlString(indent + " "));
1096 dataString.append(indent + "</listitem>\n");
1097 } else {
1098 dataString.append(indent + "<" + p.getKey() + ">\n");
1099 dataString.append(((Data)value)._toXmlString(indent + " "));
1100 dataString.append(indent + "</" + p.getKey() + ">\n");
1101 }
1102 } else if (p.getKey() instanceof Integer){
1103 dataString.append(indent + "<listitem index=\"" + p.getKey() + "\" value=\""+ value + "\"/>\n");
1104 } else {
1105 dataString.append(indent + "<" + p.getKey() + " value=\""+ value + "\"/>\n");
1106 }
1107 }
1108
1109 return dataString.toString();
1110 }
1111
1112 public boolean containsKey(Key key) {
1113 return map.containsKey(key);
1114 }
1115
1116 public boolean containsValue(Value value) {
1117 return map.containsValue(value);
1118 }
1119
1120
1121
1122
1123 public Set keySet() {
1124 return map.keySet();
1125 }
1126
1127 public boolean isEmpty() {
1128 return map.isEmpty();
1129 }
1130 }