1 package org.kuali.student.r1.common.dictionary.service.impl;
2
3 import org.kuali.student.r1.common.dictionary.dto.CaseConstraint;
4 import org.kuali.student.r1.common.dictionary.dto.CommonLookupParam;
5 import org.kuali.student.r1.common.dictionary.dto.Constraint;
6 import org.kuali.student.r1.common.dictionary.dto.DataType;
7 import org.kuali.student.r1.common.dictionary.dto.FieldDefinition;
8 import org.kuali.student.r1.common.dictionary.dto.LookupConstraint;
9 import org.kuali.student.r1.common.dictionary.dto.ObjectStructureDefinition;
10 import org.kuali.student.r1.common.dictionary.dto.RequiredConstraint;
11 import org.kuali.student.r1.common.dictionary.dto.ValidCharsConstraint;
12 import org.kuali.student.r1.common.dictionary.dto.WhenConstraint;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.HashSet;
18 import java.util.LinkedHashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 @Deprecated
24 public class DictionaryFormatter
25 {
26
27 private StringBuilder builder = new StringBuilder (5000);
28 private ObjectStructureDefinition os;
29 private String rowSeperator = "\n";
30 private String colSeperator = "|";
31 private String name;
32 private String className;
33 private boolean processSubstructures = false;
34 private int level;
35 private Map<String, ObjectStructureDefinition> subStructuresToProcess =
36 new LinkedHashMap ();
37 private Set<ObjectStructureDefinition> subStructuresAlreadyProcessed;
38
39 public DictionaryFormatter (String name,
40 String className,
41 ObjectStructureDefinition os,
42 Set<ObjectStructureDefinition> subStructuresAlreadyProcessed,
43 int level,
44 boolean processSubstructures)
45 {
46 this.name = name;
47 this.className = className;
48 this.os = os;
49 this.subStructuresAlreadyProcessed = subStructuresAlreadyProcessed;
50 this.level = level;
51 this.processSubstructures = processSubstructures;
52 }
53 public static final String UNBOUNDED = "unbounded";
54
55 public String getRowSeperator ()
56 {
57 return rowSeperator;
58 }
59
60 public void setRowSeperator (String rowSeperator)
61 {
62 this.rowSeperator = rowSeperator;
63 }
64
65 public String getColSeparator ()
66 {
67 return colSeperator;
68 }
69
70 public void setColSeparator (String separator)
71 {
72 this.colSeperator = separator;
73 }
74
75 private String pad (String str, int size)
76 {
77 StringBuilder padStr = new StringBuilder (size);
78 padStr.append (str);
79 while (padStr.length () < size)
80 {
81 padStr.append (' ');
82 }
83 return padStr.toString ();
84 }
85
86 public String formatForWiki ()
87 {
88 builder.append (rowSeperator);
89
90 builder.append (rowSeperator);
91 builder.append ("h" + level + ". " + calcNotSoSimpleName (name));
92 builder.append ("{anchor:" + name + "}");
93 builder.append (rowSeperator);
94 if (className != null)
95 {
96 builder.append ("The corresponding java class for this dictionary object is "
97 + os.getName ());
98 }
99 if (os.isHasMetaData ())
100 {
101 builder.append (rowSeperator);
102 builder.append ("The dictionary says this object holds metadata");
103 }
104 builder.append (rowSeperator);
105 builder.append (colSeperator);
106 builder.append (colSeperator);
107 builder.append ("Field");
108 builder.append (colSeperator);
109 builder.append (colSeperator);
110 builder.append ("Required?");
111 builder.append (colSeperator);
112 builder.append (colSeperator);
113 builder.append ("DataType");
114 builder.append (colSeperator);
115 builder.append (colSeperator);
116 builder.append ("Length");
117 builder.append (colSeperator);
118 builder.append (colSeperator);
119 builder.append ("Dynamic or Hidden");
120 builder.append (colSeperator);
121 builder.append (colSeperator);
122 builder.append ("Default");
123 builder.append (colSeperator);
124 builder.append (colSeperator);
125 builder.append ("Repeats?");
126 builder.append (colSeperator);
127 builder.append (colSeperator);
128 builder.append ("Valid Characters");
129 builder.append (colSeperator);
130 builder.append (colSeperator);
131 builder.append ("Lookup");
132 builder.append (colSeperator);
133 builder.append (colSeperator);
134 builder.append ("Cross Field");
135 builder.append (colSeperator);
136 builder.append (colSeperator);
137 builder.append (rowSeperator);
138 for (FieldDefinition fd : getSortedFields ())
139 {
140 builder.append (colSeperator);
141 builder.append (pad (fd.getName (), 30));
142 builder.append (colSeperator);
143 builder.append (pad (calcRequired (fd), 10));
144 builder.append (colSeperator);
145 builder.append (pad (calcDataType (fd), 25));
146 builder.append (colSeperator);
147 builder.append (pad (calcLength (fd), 15));
148 builder.append (colSeperator);
149 builder.append (pad (calcDynamicOrHidden (fd), 7));
150 builder.append (colSeperator);
151 builder.append (pad (calcDefaultValue (fd), 15));
152 builder.append (colSeperator);
153 builder.append (calcRepeating (fd));
154 builder.append (colSeperator);
155 builder.append (calcValidCharsMinMax (fd));
156 builder.append (colSeperator);
157 builder.append (calcLookup (fd));
158 builder.append (colSeperator);
159 builder.append (calcCrossField (fd));
160 builder.append (colSeperator);
161 builder.append (rowSeperator);
162 }
163 List<String> discrepancies = null;
164 if (className == null)
165 {
166 discrepancies = new ArrayList (1);
167 discrepancies.add (
168 "There is no corresponding java class for this dictionary object structure");
169 }
170 else
171 {
172 discrepancies = new Dictionary2BeanComparer (className, os).compare ();
173 }
174 if (discrepancies.size () > 0)
175 {
176 builder.append ("h" + (level + 1) + ". " + discrepancies.size ()
177 + " discrepancie(s) found in "
178 + calcSimpleName (name));
179 builder.append (rowSeperator);
180 builder.append (formatAsString (discrepancies));
181 builder.append (rowSeperator);
182 }
183
184
185 builder.append (rowSeperator);
186 Set<ObjectStructureDefinition> subStructuresAlreadyProcessedBeforeProcessingSubStructures =
187 new HashSet ();
188 subStructuresAlreadyProcessedBeforeProcessingSubStructures.addAll (
189 subStructuresAlreadyProcessed);
190 for (String subName : this.subStructuresToProcess.keySet ())
191 {
192 ObjectStructureDefinition subOs = this.subStructuresToProcess.get (subName);
193 if ( ! subStructuresAlreadyProcessedBeforeProcessingSubStructures.contains (
194 subOs))
195 {
196 this.subStructuresAlreadyProcessed.add (subOs);
197
198 Class<?> subClazz = getClass (subOs.getName ());
199 DictionaryFormatter formatter =
200 new DictionaryFormatter (subName, subOs.getName (),
201 subOs,
202 subStructuresAlreadyProcessed,
203 level + 1,
204 this.processSubstructures);
205 builder.append (formatter.formatForWiki ());
206 builder.append (rowSeperator);
207 }
208 }
209
210 return builder.toString ();
211 }
212
213
214
215 private List<FieldDefinition> getSortedFields ()
216 {
217 List<FieldDefinition> fields = os.getAttributes ();
218 Collections.sort (fields, new FieldDefinitionNameComparator ());
219 return fields;
220 }
221
222 private static class FieldDefinitionNameComparator implements Comparator <FieldDefinition>
223 {
224 @Override
225 public int compare (FieldDefinition o1, FieldDefinition o2)
226 {
227 return o1.getName ().toLowerCase ().compareTo (o2.getName ().toLowerCase ());
228 }
229
230 }
231
232 private Class getClass (String className)
233 {
234 try
235 {
236 return Class.forName (className);
237 }
238 catch (ClassNotFoundException ex)
239 {
240 return null;
241
242 }
243 }
244
245 private String formatAsString (List<String> discrepancies)
246 {
247 int i = 0;
248 StringBuilder builder = new StringBuilder ();
249 for (String discrep : discrepancies)
250 {
251 i ++;
252 builder.append (i + ". " + discrep + "\n");
253 }
254 return builder.toString ();
255 }
256
257 private String calcDataType (FieldDefinition fd)
258 {
259 if (fd.getDataType ().equals (DataType.COMPLEX))
260 {
261 if (fd.getDataObjectStructure () == null)
262 {
263 throw new IllegalArgumentException (
264 fd.getName () + " is complex but does not have a sub-structure defined");
265 }
266 Class subClazz = this.getClass (fd.getDataObjectStructure ().getName ());
267 String subStrucName = calcComplexSubStructureName (fd);
268
269
270 if (this.processSubstructures || subClazz == null)
271 {
272 if ( ! this.subStructuresAlreadyProcessed.contains (
273 fd.getDataObjectStructure ()))
274 {
275
276 this.subStructuresToProcess.put (subStrucName, fd.getDataObjectStructure ());
277 }
278 }
279 return "[" + calcNotSoSimpleName (subStrucName) + "|#" + subStrucName + "]";
280 }
281 return fd.getDataType ().toString ();
282 }
283
284 private String calcDefaultValue (FieldDefinition fd)
285 {
286 if (fd.getDefaultValue () != null)
287 {
288 return fd.getDefaultValue ().toString ();
289 }
290 return " ";
291 }
292
293
294 private String calcDynamicOrHidden (FieldDefinition fd)
295 {
296 if (fd.isHide ())
297 {
298 if (fd.isDynamic ())
299 {
300 return "dynamic and hidden";
301 }
302 return "hidden";
303 }
304 if (fd.isDynamic ())
305 {
306 return "dynamic";
307 }
308 return " ";
309 }
310
311 private String calcComplexSubStructureName (FieldDefinition fd)
312 {
313 if (this.processSubstructures)
314 {
315 return name + "." + fd.getName () + "." + calcSimpleName (
316 fd.getDataObjectStructure ().getName ());
317 }
318 return calcSimpleName (fd.getDataObjectStructure ().getName ());
319 }
320
321 private String calcSimpleName (String name)
322 {
323 if (name.lastIndexOf (".") != -1)
324 {
325 name = name.substring (name.lastIndexOf (".") + 1);
326 }
327 return name;
328 }
329
330 private String calcNotSoSimpleName (String name)
331 {
332 if (name.lastIndexOf (".") == -1)
333 {
334 return name;
335 }
336 String simpleName = calcSimpleName (name);
337 String fieldName = calcSimpleName (name.substring (0, name.length ()
338 - simpleName.length ()
339 - 1));
340 return fieldName + "." + simpleName;
341 }
342
343 private String calcRequired (FieldDefinition fd)
344 {
345 if (fd.getMaxOccurs () != null)
346 {
347 if ( ! fd.getMaxOccurs ().equals (UNBOUNDED))
348 {
349 if (Integer.parseInt (fd.getMaxOccurs ()) == 0)
350 {
351 return "Not allowed";
352 }
353 }
354 }
355
356 if (fd.getMinOccurs () != null)
357 {
358 if (fd.getMinOccurs () >= 1)
359 {
360 return "required";
361 }
362 }
363
364 return " ";
365
366 }
367 private static final String LINK_TO_DEFINITIONS =
368 "KULSTG:Formatted View of Base Dictionary#Valid Character Definitions";
369
370 private String calcValidChars (FieldDefinition fd)
371 {
372 if (fd.getValidChars () == null)
373 {
374 return " ";
375 }
376 return calcValidChars (fd.getValidChars ());
377 }
378
379 private String calcValidChars (ValidCharsConstraint cons)
380 {
381 String labelKey = cons.getLabelKey();
382 if (labelKey == null)
383 {
384 labelKey = "validation.validChars";
385 }
386 String validChars = escapeWiki (cons.getValue ());
387 String descr = "[" + labelKey + "|" + LINK_TO_DEFINITIONS + "]" + "\\\\\n"
388 + validChars;
389 return descr;
390 }
391
392 private String escapeWiki (String str)
393 {
394 StringBuilder bldr = new StringBuilder (str.length ());
395 for (int i = 0; i < str.length (); i ++)
396 {
397 char c = str.charAt (i);
398 switch (c)
399 {
400 case '{':
401 case '}':
402 case '[':
403 case ']':
404 case '|':
405 bldr.append ('\\');
406 }
407 bldr.append (c);
408 }
409 return bldr.toString ();
410 }
411
412 private String calcLookup (FieldDefinition fd)
413 {
414 if (fd.getLookupDefinition () == null)
415 {
416 return " ";
417 }
418 return calcLookup (fd.getLookupDefinition ());
419 }
420
421 private String calcLookup (LookupConstraint lc)
422 {
423 StringBuilder bldr = new StringBuilder ();
424 bldr.append (lc.getId ());
425
426
427
428 String and = "";
429 bldr.append ("\\\\");
430 bldr.append ("\n");
431 bldr.append ("Implemented using search: ");
432 String searchPage = calcWikiSearchPage (lc.getSearchTypeId ());
433 bldr.append ("[" + lc.getSearchTypeId () + "|" + searchPage + "#"
434 + lc.getSearchTypeId () + "]");
435 List<CommonLookupParam> configuredParameters = filterConfiguredParams (
436 lc.getParams ());
437 if (configuredParameters.size () > 0)
438 {
439 bldr.append ("\\\\");
440 bldr.append ("\n");
441 bldr.append (" where ");
442 and = "";
443 for (CommonLookupParam param : configuredParameters)
444 {
445 bldr.append (and);
446 and = " and ";
447 bldr.append (param.getName ());
448 bldr.append ("=");
449 if (param.getDefaultValueString () != null)
450 {
451 bldr.append (param.getDefaultValueString ());
452 continue;
453 }
454 if (param.getDefaultValueList () != null)
455 {
456 String comma = "";
457 for (String defValue : param.getDefaultValueList ())
458 {
459 bldr.append (comma);
460 comma = ", ";
461 bldr.append (defValue);
462 }
463 }
464 }
465 }
466 return bldr.toString ();
467 }
468
469 private String calcValidCharsMinMax (FieldDefinition fd)
470 {
471 String validChars = calcValidChars (fd);
472 String minMax = calcMinMax (fd);
473 String and = " and ";
474 if (validChars.trim ().equals (""))
475 {
476 return minMax;
477 }
478 if (minMax.trim ().equals (""))
479 {
480 return validChars;
481 }
482 return validChars + "\\\\\n" + minMax;
483 }
484
485 private String calcMinMax (FieldDefinition fd)
486 {
487 if (fd.getExclusiveMin () == null)
488 {
489 if (fd.getInclusiveMax () == null)
490 {
491 return " ";
492 }
493 return "Must be <= " + fd.getInclusiveMax ();
494 }
495 if (fd.getInclusiveMax () == null)
496 {
497 return "Must be > " + fd.getExclusiveMin ();
498 }
499 return "Must be > " + fd.getExclusiveMin () + " and < "
500 + fd.getInclusiveMax ();
501 }
502 private static final String PAGE_PREFIX = "Formatted View of ";
503 private static final String PAGE_SUFFIX = " Searches";
504
505 private String calcWikiSearchPage (String searchType)
506 {
507 return PAGE_PREFIX + calcWikigPageAbbrev (searchType) + PAGE_SUFFIX;
508 }
509
510 private String calcWikigPageAbbrev (String searchType)
511 {
512 if (searchType == null)
513 {
514 return null;
515 }
516 if (searchType.equals ("enumeration.management.search"))
517 {
518 return "EM";
519 }
520 if (searchType.startsWith ("lu."))
521 {
522 return "LU";
523 }
524 if (searchType.startsWith ("cluset."))
525 {
526 return "LU";
527 }
528 if (searchType.startsWith ("lo."))
529 {
530 return "LO";
531 }
532 if (searchType.startsWith ("lrc."))
533 {
534 return "LRC";
535 }
536 if (searchType.startsWith ("comment."))
537 {
538 return "Comment";
539 }
540 if (searchType.startsWith ("org."))
541 {
542 return "Organization";
543 }
544 if (searchType.startsWith ("atp."))
545 {
546 return "ATP";
547 }
548 if (searchType.startsWith ("subjectCode."))
549 {
550 return "SC";
551 }
552 throw new IllegalArgumentException ("Unknown type of search: " + searchType);
553 }
554
555 private List<CommonLookupParam> filterConfiguredParams (
556 List<CommonLookupParam> params)
557 {
558 List list = new ArrayList ();
559 if (params == null)
560 {
561 return list;
562 }
563 if (params.size () == 0)
564 {
565 return list;
566 }
567 for (CommonLookupParam param : params)
568 {
569 if (param.getDefaultValueString () != null)
570 {
571 list.add (param);
572 continue;
573 }
574 if (param.getDefaultValueList () != null)
575 {
576 list.add (param);
577 }
578 }
579 return list;
580 }
581
582 private String calcRepeating (FieldDefinition fd)
583 {
584 if (fd.getMaxOccurs () == null)
585 {
586 return "???";
587 }
588 if (fd.getMaxOccurs ().equals (UNBOUNDED))
589 {
590 if (fd.getMinOccurs () != null && fd.getMinOccurs () > 1)
591 {
592 return "repeating: minimum " + fd.getMinOccurs () + " times";
593 }
594 return "repeating: unlimited";
595 }
596 if (Integer.parseInt (fd.getMaxOccurs ()) == 0)
597 {
598 return "NOT USED";
599 }
600 if (Integer.parseInt (fd.getMaxOccurs ()) == 1)
601 {
602 return " ";
603
604 }
605
606 if (fd.getMinOccurs () != null)
607 {
608 if (fd.getMinOccurs () > 1)
609 {
610 return "repeating: " + fd.getMinOccurs () + " to " + fd.getMaxOccurs ()
611 + " times";
612 }
613 }
614 return "repeating: maximum " + fd.getMaxOccurs () + " times";
615 }
616
617 private String calcLength (FieldDefinition fd)
618 {
619 if (fd.getMaxLength () != null)
620 {
621 if (fd.getMinLength () != null && fd.getMinLength () != 0)
622 {
623 if (Integer.parseInt (fd.getMaxLength ()) == fd.getMinLength ())
624 {
625 return ("(must be " + fd.getMaxLength () + ")");
626 }
627 return "(" + fd.getMinLength () + " to " + fd.getMaxLength () + ")";
628 }
629 return "(up to " + fd.getMaxLength () + ")";
630 }
631 if (fd.getMinLength () != null)
632 {
633 return "(over " + fd.getMinLength () + ")";
634 }
635 return " ";
636 }
637
638 private String calcCrossField (FieldDefinition fd)
639 {
640 StringBuilder b = new StringBuilder ();
641 String semicolon = "";
642 String cfr = calcCrossFieldRequire (fd);
643 if (cfr != null)
644 {
645 b.append (semicolon);
646 semicolon = "; ";
647 b.append (cfr);
648 }
649 String cfw = calcCrossFieldWhen (fd);
650 if (cfw != null)
651 {
652 b.append (semicolon);
653 semicolon = "; ";
654 b.append (cfw);
655 }
656 if (b.length () == 0)
657 {
658 return " ";
659 }
660 return b.toString ();
661 }
662
663 private String calcCrossFieldRequire (FieldDefinition fd)
664 {
665 if (fd.getRequireConstraint () == null)
666 {
667 return null;
668 }
669 if (fd.getRequireConstraint ().size () == 0)
670 {
671 return null;
672 }
673 StringBuilder b = new StringBuilder ();
674 String comma = "";
675 b.append ("if not empty then ");
676 for (RequiredConstraint rc : fd.getRequireConstraint ())
677 {
678 b.append (comma);
679 comma = ", ";
680 b.append (rc.getFieldPath ());
681 }
682 if (fd.getRequireConstraint ().size () == 1)
683 {
684 b.append (" is");
685 }
686 else
687 {
688 b.append (" are");
689 }
690 b.append (" also required");
691 return b.toString ();
692 }
693
694 private String calcCrossFieldWhen (FieldDefinition fd)
695 {
696 if (fd.getCaseConstraint () == null)
697 {
698 return null;
699 }
700 StringBuilder b = new StringBuilder ();
701 CaseConstraint cc = fd.getCaseConstraint ();
702 for (WhenConstraint wc : cc.getWhenConstraint ())
703 {
704 b.append ("\\\\");
705 b.append ("\n");
706 b.append ("when ");
707 b.append (cc.getFieldPath ());
708 b.append (" ");
709 if ( ! cc.isCaseSensitive ())
710 {
711 b.append ("ignoring case ");
712 }
713 b.append (cc.getOperator ());
714 b.append (" ");
715
716 b.append ("\\\\");
717 b.append ("\n");
718 String comma = "";
719 for (Object value : wc.getValues ())
720 {
721 b.append (comma);
722 comma = " or ";
723 b.append (asString (value));
724 }
725 b.append ("\\\\");
726 b.append ("\n");
727 b.append ("then override constraint:"
728 + calcOverride (fd, wc.getConstraint ()));
729 }
730 return b.toString ();
731 }
732
733 private String calcOverride (FieldDefinition fd, Constraint cons)
734 {
735 StringBuilder b = new StringBuilder ();
736 b.append (calcOverride ("serviceSide", fd.isServerSide (),
737 cons.isServerSide ()));
738 b.append (calcOverride ("exclusiveMin", fd.getExclusiveMin (),
739 cons.getExclusiveMin ()));
740 b.append (calcOverride ("inclusiveMax", fd.getInclusiveMax (),
741 cons.getInclusiveMax ()));
742 String minOccursMessage = calcOverride ("minOccurs", fd.getMinOccurs (),
743 cons.getMinOccurs ());
744 if ( ! minOccursMessage.trim ().equals (""))
745 {
746 if (cons.getMinOccurs () != null && cons.getMinOccurs () == 1)
747 {
748 minOccursMessage = " REQUIRED";
749 }
750 }
751 b.append (minOccursMessage);
752 b.append (calcOverride ("validchars", fd.getValidChars (),
753 cons.getValidChars ()));
754 b.append (calcOverride ("lookup", fd.getLookupDefinition (),
755 cons.getLookupDefinition ()));
756
757 return b.toString ();
758 }
759
760 private String calcOverride (String attribute, LookupConstraint val1,
761 LookupConstraint val2)
762 {
763 if (val1 == val2)
764 {
765 return "";
766 }
767 if (val1 == null && val2 != null)
768 {
769 return " add lookup " + this.calcLookup (val2);
770 }
771 if (val1 != null && val2 == null)
772 {
773 return " remove lookup constraint";
774 }
775 return " change lookup to " + calcLookup (val2);
776 }
777
778 private String calcOverride (String attribute, ValidCharsConstraint val1,
779 ValidCharsConstraint val2)
780 {
781 if (val1 == val2)
782 {
783 return "";
784 }
785 if (val1 == null && val2 != null)
786 {
787 return " add validchars " + calcValidChars (val2);
788 }
789 if (val1 != null && val2 == null)
790 {
791 return " remove validchars constraint";
792 }
793 return " change validchars to " + calcValidChars (val2);
794 }
795
796 private String calcOverride (String attribute, boolean val1, boolean val2)
797 {
798 if (val1 == val2)
799 {
800 return "";
801 }
802 return " " + attribute + "=" + val2;
803 }
804
805 private String calcOverride (String attribute, String val1, String val2)
806 {
807 if (val1 == null && val2 == null)
808 {
809 return "";
810 }
811 if (val1 == val2)
812 {
813 return "";
814 }
815 if (val1 == null)
816 {
817 return " " + attribute + "=" + val2;
818 }
819 if (val1.equals (val2))
820 {
821 return "";
822 }
823 return " " + attribute + "=" + val2;
824 }
825
826 private String calcOverride (String attribute, Object val1, Object val2)
827 {
828 if (val1 == null && val2 == null)
829 {
830 return "";
831 }
832 if (val1 == val2)
833 {
834 return "";
835 }
836 if (val1 == null)
837 {
838 return " " + attribute + "=" + val2;
839 }
840 if (val1.equals (val2))
841 {
842 return "";
843 }
844 return " " + attribute + "=" + asString (val2);
845 }
846
847 private String asString (Object value)
848 {
849 if (value == null)
850 {
851 return "null";
852 }
853 if (value instanceof String)
854 {
855 return (String) value;
856 }
857 return value.toString ();
858 }
859 }