View Javadoc

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  //  builder.append ("======= start dump of object structure definition ========");
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 //  builder.append ("======= end dump of object structure definition ========");
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 //    System.out.println ("formatting substructure " + subName);
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 //   throw new IllegalArgumentException ("Could not find class for " + className);
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    // process if explicity asking for substructures OR the field is a freestanding field
253    // so it won't be processed by just processing all of the DTO's and their sub-objects
254    if (this.processSubstructures || subClazz == null)
255    {
256     if ( ! this.subStructuresAlreadyProcessed.contains (
257       fd.getDataObjectStructure ()))
258     {
259 //     System.out.println ("Adding " + subStrucName + " to set to be processed");
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 //  return "optional";
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 //  this is the search description not the lookup description
410 //  builder.append (" - ");
411 //  builder.append (lc.getDesc ());
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 //   return "single";
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   //TODO: other more complex constraints
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  }