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