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