001 /** 002 * Copyright 2004-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.student.datadictionary.util; 017 018 import java.io.File; 019 import java.io.FileNotFoundException; 020 import java.io.FileOutputStream; 021 import java.io.OutputStream; 022 import java.io.PrintStream; 023 import java.util.ArrayList; 024 import java.util.Collections; 025 import java.util.Comparator; 026 import java.util.Date; 027 import java.util.List; 028 import java.util.Map; 029 import java.util.Stack; 030 031 import org.kuali.rice.krad.datadictionary.AttributeDefinition; 032 import org.kuali.rice.krad.datadictionary.AttributeDefinitionBase; 033 import org.kuali.rice.krad.datadictionary.CollectionDefinition; 034 import org.kuali.rice.krad.datadictionary.ComplexAttributeDefinition; 035 import org.kuali.rice.krad.datadictionary.DataObjectEntry; 036 import org.kuali.rice.krad.datadictionary.validation.constraint.BaseConstraint; 037 import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint; 038 import org.kuali.rice.krad.datadictionary.validation.constraint.CommonLookupParam; 039 import org.kuali.rice.krad.datadictionary.validation.constraint.LookupConstraint; 040 import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint; 041 import org.kuali.rice.krad.datadictionary.validation.constraint.WhenConstraint; 042 import org.kuali.rice.krad.uif.control.Control; 043 import org.kuali.rice.krad.uif.control.TextControl; 044 import org.kuali.student.contract.model.impl.ServiceContractModelPescXsdLoader; 045 import org.kuali.student.contract.model.util.VersionLinesUtility; 046 import org.slf4j.Logger; 047 import org.slf4j.LoggerFactory; 048 049 public class DictionaryFormatter { 050 051 private static Logger log = LoggerFactory.getLogger(DictionaryFormatter.class); 052 053 private DataObjectEntry doe; 054 private Map<String, DataObjectEntry> beansOfType; 055 private String beanId; 056 private String outputFileName; 057 058 public DictionaryFormatter(DataObjectEntry doe, Map<String, DataObjectEntry> beansOfType, String beanId, String outputFileName) { 059 this.doe = doe; 060 this.beansOfType = beansOfType; 061 this.beanId = beanId; 062 this.outputFileName = outputFileName; 063 } 064 065 public void formatForHtml(String projectVersion, String formattedDate) { 066 File file = new File(this.outputFileName); 067 OutputStream outputStream; 068 try { 069 outputStream = new FileOutputStream(file, false); 070 } catch (FileNotFoundException ex) { 071 throw new IllegalArgumentException(this.outputFileName, ex); 072 } 073 PrintStream out = new PrintStream(outputStream); 074 writeHeader(out, beanId); 075 writeBody(out, projectVersion, formattedDate); 076 writeFooter(out); 077 out.close(); 078 } 079 080 public static void writeHeader(PrintStream out, String title) { 081 out.println("<html>"); 082 out.println("<head>"); 083 writeTag(out, "title", title); 084 out.println ("<style>li.invalid { background: red; }</style>"); 085 out.println("</head>"); 086 out.println("<body bgcolor=\"#ffffff\" topmargin=0 marginheight=0>"); 087 } 088 089 public static void writeFooter(PrintStream out) { 090 out.println("</body>"); 091 out.println("</html>"); 092 } 093 094 private String initUpper(String str) { 095 if (str == null) { 096 return null; 097 } 098 if (str.length() == 0) { 099 return str; 100 } 101 if (str.length() == 1) { 102 return str.toUpperCase(); 103 } 104 return str.substring(0, 1).toUpperCase() + str.substring(1); 105 } 106 107 private void writeBody(PrintStream out, String projectVersion, String formattedDate) { 108 109 VersionLinesUtility.writeVersionTag(out, "<a href=\"index.html\">home</a>", "<a href=\"../contractdocs/" + initUpper(doe.getName()) + ".html\">contract doc</a>", projectVersion, formattedDate); 110 // builder.append ("======= start dump of object structure definition ========"); 111 out.println("<h1>" + this.beanId + "</h1>"); 112 113 out.println("<br>"); 114 out.println("<table border=1>"); 115 116 out.println("<tr>"); 117 out.println("<th bgcolor=lightblue>"); 118 out.println("Name"); 119 out.println("</th>"); 120 out.println("<td>"); 121 out.println(doe.getName()); 122 out.println("</td>"); 123 out.println("</tr>"); 124 125 out.println("<tr>"); 126 out.println("<th bgcolor=lightblue>"); 127 out.println("Label"); 128 out.println("</th>"); 129 out.println("<td>"); 130 out.println(doe.getObjectLabel()); 131 out.println("</td>"); 132 out.println("</tr>"); 133 134 out.println("<tr>"); 135 out.println("<th bgcolor=lightblue>"); 136 out.println("JSTL Key"); 137 out.println("</th>"); 138 out.println("<td>"); 139 out.println(doe.getJstlKey()); 140 out.println("</td>"); 141 out.println("</tr>"); 142 143 out.println("<tr>"); 144 out.println("<th bgcolor=lightblue>"); 145 out.println("Java Class"); 146 out.println("</th>"); 147 out.println("<td>"); 148 out.println(doe.getFullClassName()); 149 out.println("</td>"); 150 out.println("</tr>"); 151 out.println("<tr>"); 152 153 if (!doe.getDataObjectClass().getName().equals(doe.getFullClassName())) { 154 out.println("<tr>"); 155 out.println("<th bgcolor=lightblue>"); 156 out.println("Object Class"); 157 out.println("</th>"); 158 out.println("<td>"); 159 out.println(doe.getDataObjectClass().getName()); 160 out.println("</td>"); 161 out.println("</tr>"); 162 out.println("<tr>"); 163 } 164 165 if (!doe.getEntryClass().getName().equals(doe.getFullClassName())) { 166 out.println("<tr>"); 167 out.println("<th bgcolor=lightblue>"); 168 out.println("Entry Class"); 169 out.println("</th>"); 170 out.println("<td>"); 171 out.println(doe.getEntryClass().getName()); 172 out.println("</td>"); 173 out.println("</tr>"); 174 out.println("<tr>"); 175 } 176 177 out.println("<tr>"); 178 out.println("<th bgcolor=lightblue>"); 179 out.println("Description"); 180 out.println("</th>"); 181 out.println("<td>"); 182 out.println(doe.getObjectDescription()); 183 out.println("</td>"); 184 out.println("</tr>"); 185 186 out.println("<tr>"); 187 out.println("<th bgcolor=lightblue>"); 188 out.println("Primary Key(s)"); 189 out.println("</th>"); 190 out.println("<td>"); 191 StringBuilder bldr = new StringBuilder(); 192 String comma = ""; 193 if (doe.getPrimaryKeys() != null) { 194 for (String pk : doe.getPrimaryKeys()) { 195 bldr.append(comma); 196 comma = ", "; 197 bldr.append(pk); 198 } 199 } 200 out.println(bldr.toString()); 201 out.println("</td>"); 202 out.println("</tr>"); 203 204 out.println("<tr>"); 205 out.println("<th bgcolor=lightblue>"); 206 out.println("Field to use as the title (or name)"); 207 out.println("</th>"); 208 out.println("<td>"); 209 out.println(doe.getTitleAttribute()); 210 out.println("</td>"); 211 out.println("</tr>"); 212 213 out.println("</table>"); 214 // out.println("<br>"); 215 216 // fields 217 out.println("<h1>Field Definitions</h1>"); 218 // check for discrepancies first 219 List<String> discrepancies = new Dictionary2BeanComparer(doe.getFullClassName(), doe).compare(); 220 if (discrepancies.isEmpty()) { 221 out.println("No discrepancies were found between the dictionary definition and the java object -- "); 222 out.println("WARNING: take this with a grain of salt - the comparison does not dig into complex sub-objects nor collections so..."); 223 } else { 224 out.println("<b>" + discrepancies.size() + " discrepancie(s) were found between the dictionary definition and the java object" + "</b>"); 225 out.println("<ol>"); 226 for (String discrepancy : discrepancies) { 227 out.println("<li>" + discrepancy); 228 } 229 out.println("</ol>"); 230 } 231 // field table 232 out.println("<table border=1>"); 233 out.println("<tr bgcolor=lightblue>"); 234 out.println("<th>"); 235 out.println("Field"); 236 out.println("</th>"); 237 out.println("<th>"); 238 out.println("Required?"); 239 out.println("</th>"); 240 out.println("<th>"); 241 out.println("DataType"); 242 out.println("</th>"); 243 out.println("<th>"); 244 out.println("Length"); 245 out.println("</th>"); 246 out.println("<th>"); 247 out.println("Short Label"); 248 out.println("</th>"); 249 out.println("<th>"); 250 out.println("Summary"); 251 out.println("</th>"); 252 out.println("<th>"); 253 out.println("Label"); 254 out.println("</th>"); 255 out.println("<th>"); 256 out.println("Description"); 257 out.println("</th>"); 258 out.println("<th>"); 259 out.println("Read Only, Dynamic, or Hidden"); 260 out.println("</th>"); 261 out.println("<th>"); 262 out.println("Default"); 263 out.println("</th>"); 264 out.println("<th>"); 265 out.println("Repeats?"); 266 out.println("</th>"); 267 out.println("<th>"); 268 out.println("Valid Characters"); 269 out.println("</th>"); 270 out.println("<th>"); 271 out.println("Lookup"); 272 out.println("</th>"); 273 out.println("<th>"); 274 out.println("Cross Field"); 275 out.println("</th>"); 276 out.println("<th>"); 277 out.println("Default Control"); 278 out.println("</th>"); 279 out.println("</tr>"); 280 this.writeAttributes(out, doe, new Stack<String>(), new Stack<DataObjectEntry>()); 281 out.println("</table>"); 282 return; 283 } 284 285 private void writeAttributes(PrintStream out, DataObjectEntry ode, Stack<String> parentNames, Stack<DataObjectEntry> parents) { 286 // stop recursion 287 if (parents.contains(ode)) { 288 return; 289 } 290 // for (AttributeDefinition ad : getSortedFields()) { 291 if (ode.getAttributes() != null) { 292 for (AttributeDefinition ad : ode.getAttributes()) { 293 out.println("<tr>"); 294 out.println("<td>"); 295 out.println(nbsp(calcName(ad.getName(), parentNames))); 296 out.println("</td>"); 297 out.println("<td>"); 298 out.println(nbsp(calcRequired(ad))); 299 out.println("</td>"); 300 out.println("<td>"); 301 out.println(nbsp(calcDataType(ad))); 302 out.println("</td>"); 303 out.println("<td>"); 304 out.println(nbsp(calcLength(ad))); 305 out.println("</td>"); 306 out.println("<td>"); 307 out.println(nbsp(calcShortLabel(ad))); 308 out.println("</td>"); 309 out.println("<td>"); 310 out.println(nbsp(calcSummary(ad))); 311 out.println("</td>"); 312 out.println("<td>"); 313 out.println(nbsp(calcLabel(ad))); 314 out.println("</td>"); 315 out.println("<td>"); 316 out.println(nbsp(calcDescription(ad))); 317 out.println("</td>"); 318 out.println("<td>"); 319 out.println(nbsp(calcDynamicHiddenReadOnly(ad))); 320 out.println("</td>"); 321 out.println("<td>"); 322 out.println(nbsp(calcDefaultValue(ad))); 323 out.println("</td>"); 324 out.println("<td>"); 325 out.println(nbsp(null)); 326 out.println("</td>"); 327 out.println("<td>"); 328 out.println(nbsp(calcForceUpperValidCharsMinMax(ad))); 329 out.println("</td>"); 330 out.println("<td>"); 331 out.println(nbsp(calcLookup(ad))); 332 out.println("</td>"); 333 out.println("<td>"); 334 out.println(nbsp(calcCrossField(ad))); 335 out.println("</td>"); 336 out.println("<td>"); 337 out.println(nbsp(calcControl(ad))); 338 out.println("</td>"); 339 out.println("</tr>"); 340 } 341 } 342 if (ode.getComplexAttributes() != null) { 343 for (ComplexAttributeDefinition cad : ode.getComplexAttributes()) { 344 out.println("<tr>"); 345 out.println("<td>"); 346 out.println(nbsp(calcName(cad.getName(), parentNames))); 347 out.println("</td>"); 348 out.println("<td>"); 349 out.println(nbsp(calcRequired(cad))); 350 out.println("</td>"); 351 out.println("<td>"); 352 out.println("Complex"); 353 out.println("</td>"); 354 out.println("<td>"); 355 out.println(nbsp(null)); 356 out.println("</td>"); 357 out.println("<td>"); 358 out.println(nbsp(calcShortLabel(cad))); 359 out.println("</td>"); 360 out.println("<td>"); 361 out.println(nbsp(calcSummary(cad))); 362 out.println("</td>"); 363 out.println("<td>"); 364 out.println(nbsp(calcLabel(cad))); 365 out.println("</td>"); 366 out.println("<td>"); 367 out.println(nbsp(calcDescription(cad))); 368 out.println("</td>"); 369 out.println("<td>"); 370 out.println(nbsp(null)); 371 out.println("</td>"); 372 out.println("<td>"); 373 out.println(nbsp(null)); 374 out.println("</td>"); 375 out.println("<td>"); 376 out.println(nbsp(null)); 377 out.println("</td>"); 378 out.println("<td>"); 379 out.println(nbsp(null)); 380 out.println("</td>"); 381 out.println("<td>"); 382 out.println(nbsp(null)); 383 out.println("</td>"); 384 out.println("<td>"); 385 out.println(nbsp(null)); 386 out.println("</td>"); 387 out.println("<td>"); 388 out.println(nbsp(null)); 389 out.println("</td>"); 390 out.println("</tr>"); 391 parentNames.push(cad.getName()); 392 parents.push(ode); 393 this.writeAttributes(out, (DataObjectEntry) cad.getDataObjectEntry(), parentNames, parents); 394 parentNames.pop(); 395 parents.pop(); 396 } 397 } 398 if (ode.getCollections() != null) { 399 for (CollectionDefinition cd : ode.getCollections()) { 400 out.println("<tr>"); 401 out.println("<td>"); 402 out.println(nbsp(calcName(cd.getName(), parentNames))); 403 out.println("</td>"); 404 out.println("<td>"); 405 out.println(nbsp(calcRequired(cd))); 406 out.println("</td>"); 407 out.println("<td>"); 408 out.println("Complex"); 409 out.println("</td>"); 410 out.println("<td>"); 411 out.println(nbsp(null)); 412 out.println("</td>"); 413 out.println("<td>"); 414 out.println(nbsp(calcShortLabel(cd))); 415 out.println("</td>"); 416 out.println("<td>"); 417 out.println(nbsp(calcSummary(cd))); 418 out.println("</td>"); 419 out.println("<td>"); 420 out.println(nbsp(calcLabel(cd))); 421 out.println("</td>"); 422 out.println("<td>"); 423 out.println(nbsp(calcDescription(cd))); 424 out.println("</td>"); 425 out.println("<td>"); 426 out.println(nbsp(null)); 427 out.println("</td>"); 428 out.println("<td>"); 429 out.println(nbsp(null)); 430 out.println("</td>"); 431 out.println("<td>"); 432 out.println(nbsp("Repeating")); 433 out.println("</td>"); 434 out.println("<td>"); 435 out.println(nbsp(null)); 436 out.println("</td>"); 437 out.println("<td>"); 438 out.println(nbsp(null)); 439 out.println("</td>"); 440 out.println("<td>"); 441 out.println(nbsp(null)); 442 out.println("</td>"); 443 out.println("<td>"); 444 out.println(nbsp(null)); 445 out.println("</td>"); 446 out.println("</tr>"); 447 DataObjectEntry childDoe = this.getDataOjbectEntry(cd.getDataObjectClass()); 448 if (childDoe == null) { 449 // TODO: uncomment this but right now there are xml files that don't have one defined and it seems to work so... 450 // throw new NullPointerException ("Could not find a data object entry, " + cd.getDataObjectClass() + " for field " + calcName(cd.getName(), parents)); 451 log.warn("Could not find a data object entry, " + cd.getDataObjectClass() + " for field " + calcName(cd.getName(), parentNames)); 452 } else { 453 parentNames.push(cd.getName()); 454 parents.push(ode); 455 this.writeAttributes(out, (DataObjectEntry) childDoe, parentNames, parents); 456 parentNames.pop(); 457 parents.pop(); 458 } 459 } 460 } 461 } 462 463 private DataObjectEntry getDataOjbectEntry(String className) { 464 for (DataObjectEntry doe : this.beansOfType.values()) { 465 if (doe.getDataObjectClass().getName().equals(className)) { 466 return doe; 467 } 468 } 469 return null; 470 } 471 472 private String calcName(String name, Stack<String> parents) { 473 StringBuilder sb = new StringBuilder(); 474 for (String parent : parents) { 475 sb.append(parent); 476 sb.append("."); 477 } 478 sb.append(name); 479 return sb.toString(); 480 } 481 482 private String calcShortLabel(CollectionDefinition cd) { 483 return cd.getShortLabel(); 484 } 485 486 private String calcShortLabel(AttributeDefinitionBase ad) { 487 return ad.getShortLabel(); 488 } 489 490 private String calcLabel(CollectionDefinition cd) { 491 return cd.getLabel(); 492 } 493 494 private String calcLabel(AttributeDefinitionBase ad) { 495 return ad.getLabel(); 496 } 497 498 private String calcSummary(CollectionDefinition ad) { 499 return ad.getSummary(); 500 } 501 502 private String calcSummary(AttributeDefinitionBase ad) { 503 return ad.getSummary(); 504 } 505 506 private String calcDescription(CollectionDefinition cd) { 507 return cd.getDescription(); 508 } 509 510 private String calcDescription(AttributeDefinitionBase ad) { 511 return ad.getDescription(); 512 } 513 514 private List<AttributeDefinition> getSortedFields() { 515 List<AttributeDefinition> fields = doe.getAttributes(); 516 Collections.sort(fields, new AttributeDefinitionNameComparator()); 517 return fields; 518 } 519 520 private static class AttributeDefinitionNameComparator implements Comparator<AttributeDefinition> { 521 522 @Override 523 public int compare(AttributeDefinition o1, AttributeDefinition o2) { 524 return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); 525 } 526 } 527 528 private String formatAsString(List<String> discrepancies) { 529 int i = 0; 530 StringBuilder builder = new StringBuilder(); 531 for (String discrep : discrepancies) { 532 i++; 533 builder.append(i + ". " + discrep + "\n"); 534 } 535 return builder.toString(); 536 } 537 538 private String calcDataType(AttributeDefinition ad) { 539 // if (ad.getDataType().equals(DataType.COMPLEX)) { 540 // if (ad.getDataObjectStructure() == null) { 541 // throw new IllegalArgumentException( 542 // ad.getName() + " is complex but does not have a sub-structure defined"); 543 // } 544 // Class subClazz = this.getClass(ad.getDataObjectStructure().getName()); 545 // String subStrucName = calcComplexSubStructureName(ad); 546 // // process if explicity asking for substructures OR the field is a freestanding field 547 // // so it won't be processed by just processing all of the DTO's and their sub-objects 548 // if (this.processSubstructures || subClazz == null) { 549 // if (!this.subStructuresAlreadyProcessed.contains( 550 // ad.getDataObjectStructure())) { 551 //// System.out.println ("Adding " + subStrucName + " to set to be processed"); 552 // this.subStructuresToProcess.put(subStrucName, ad.getDataObjectStructure()); 553 // } 554 // } 555 // return "[" + calcNotSoSimpleName(subStrucName) + "|#" + subStrucName + "]"; 556 // } 557 return ad.getDataType().toString(); 558 } 559 560 private String calcDefaultValue(AttributeDefinition ad) { 561 // if (ad.getDefaultValue() != null) { 562 // return ad.getDefaultValue().toString(); 563 // } 564 return " "; 565 } 566 567 private String calcDynamicHiddenReadOnly(AttributeDefinition ad) { 568 StringBuilder sb = new StringBuilder(); 569 String comma = ""; 570 comma = this.appendIfNotNull(sb, this.calcDynamic(ad), comma); 571 comma = this.appendIfNotNull(sb, this.calcHidden(ad), comma); 572 comma = this.appendIfNotNull(sb, this.calcReadOnly(ad), comma); 573 return sb.toString(); 574 } 575 576 private String appendIfNotNull(StringBuilder sb, String value, String comma) { 577 if (value == null) { 578 return comma; 579 } 580 sb.append(comma); 581 sb.append(value); 582 return ", "; 583 } 584 585 private String calcDynamic(AttributeDefinition ad) { 586 // TODO: implement once KRAD team implements 587 // if (ad.isDynamic()) { 588 // return "dynamic"; 589 // } 590 return null; 591 } 592 593 private String calcHidden(AttributeDefinition ad) { 594 if (ad.getAttributeSecurity() == null) { 595 return null; 596 } 597 if (ad.getAttributeSecurity().isHide()) { 598 return "Hidden"; 599 } 600 return null; 601 602 } 603 604 private String calcReadOnly(AttributeDefinition ad) { 605 if (ad.getAttributeSecurity() == null) { 606 return null; 607 } 608 if (ad.getAttributeSecurity().isReadOnly()) { 609 return "Read only"; 610 } 611 return null; 612 613 } 614 615 private String calcComplexSubStructureName(AttributeDefinition ad) { 616 // if (this.processSubstructures) { 617 // return name + "." + ad.getName() + "." + calcSimpleName( 618 // ad.getDataObjectStructure().getName()); 619 // } 620 // return calcSimpleName(ad.getDataObjectStructure().getName()); 621 return " "; 622 } 623 624 private String calcSimpleName(String simpleName) { 625 if (simpleName.lastIndexOf(".") != -1) { 626 simpleName = simpleName.substring(simpleName.lastIndexOf(".") + 1); 627 } 628 return simpleName; 629 } 630 631 private String calcNotSoSimpleName(String name) { 632 if (name.lastIndexOf(".") == -1) { 633 return name; 634 } 635 String simpleName = calcSimpleName(name); 636 String fieldName = calcSimpleName(name.substring(0, name.length() 637 - simpleName.length() 638 - 1)); 639 return fieldName + "." + simpleName; 640 } 641 642 private String calcRequired(CollectionDefinition cd) { 643 if (cd.getMinOccurs() != null) { 644 if (cd.getMinOccurs() >= 1) { 645 return "required"; 646 } 647 } 648 // TODO: Deal with collections 649 // if (ad.getMaximumNumberOfElements() != null) { 650 // if (ad.getMaximumNumberOfElements().intValue() == 0) { 651 // return "Not allowed"; 652 // } 653 // } 654 // 655 // if (ad.getMinimumNumberOfElements() != null) { 656 // if (ad.getMinimumNumberOfElements().intValue() >= 1) { 657 // return "required"; 658 // } 659 // } 660 return " "; 661 // return "optional"; 662 } 663 664 private String calcRequired(AttributeDefinitionBase ad) { 665 if (ad.isRequired() != null) { 666 if (ad.isRequired()) { 667 return "required"; 668 } 669 } 670 // TODO: Deal with collections 671 // if (ad.getMaximumNumberOfElements() != null) { 672 // if (ad.getMaximumNumberOfElements().intValue() == 0) { 673 // return "Not allowed"; 674 // } 675 // } 676 // 677 // if (ad.getMinimumNumberOfElements() != null) { 678 // if (ad.getMinimumNumberOfElements().intValue() >= 1) { 679 // return "required"; 680 // } 681 // } 682 return " "; 683 // return "optional"; 684 } 685 686 private String calcForceUpperCase(AttributeDefinition ad) { 687 if (ad.getForceUppercase() != null && ad.getForceUppercase()) { 688 return "FORCE UPPER CASE"; 689 } 690 return " "; 691 } 692 693 private String calcValidChars(AttributeDefinition ad) { 694 if (ad.getValidCharactersConstraint() == null) { 695 return " "; 696 } 697 return calcValidChars(ad.getValidCharactersConstraint()); 698 } 699 700 private String calcValidChars(ValidCharactersConstraint cons) { 701 String messageKey = cons.getMessageKey(); 702 if (messageKey == null) { 703 messageKey = "validation.validChars"; 704 } 705 String validChars = escapeXML(cons.getValue()); 706 String descr = messageKey + "<br>" + validChars; 707 return descr; 708 } 709 710 private String calcLookup(AttributeDefinition ad) { 711 if (ad.getLookupDefinition() == null) { 712 return " "; 713 } 714 return calcLookup(ad.getLookupDefinition()); 715 } 716 717 private String calcLookup(LookupConstraint lc) { 718 StringBuilder bldr = new StringBuilder(); 719 bldr.append(lc.getId()); 720 // this is the search description not the lookup description 721 // builder.append (" - "); 722 // builder.append (lc.getDesc ()); 723 String and = ""; 724 bldr.append("<br>"); 725 bldr.append("\n"); 726 bldr.append("Implemented using search: "); 727 String searchPage = calcWikiSearchPage(lc.getSearchTypeId()); 728 bldr.append("[" + lc.getSearchTypeId() + "|" + searchPage + "#" 729 + lc.getSearchTypeId() + "]"); 730 List<CommonLookupParam> configuredParameters = filterConfiguredParams( 731 lc.getParams()); 732 if (configuredParameters.size() > 0) { 733 bldr.append("<br>"); 734 bldr.append("\n"); 735 bldr.append(" where "); 736 and = ""; 737 for (CommonLookupParam param : configuredParameters) { 738 bldr.append(and); 739 and = " and "; 740 bldr.append(param.getName()); 741 bldr.append("="); 742 if (param.getDefaultValueString() != null) { 743 bldr.append(param.getDefaultValueString()); 744 continue; 745 } 746 if (param.getDefaultValueList() != null) { 747 String comma = ""; 748 for (String defValue : param.getDefaultValueList()) { 749 bldr.append(comma); 750 comma = ", "; 751 bldr.append(defValue); 752 } 753 } 754 } 755 } 756 return bldr.toString(); 757 } 758 759 private String calcForceUpperValidCharsMinMax(AttributeDefinition ad) { 760 StringBuilder bldr = new StringBuilder(); 761 String brk = ""; 762 String forceUpper = calcForceUpperCase(ad); 763 if (!forceUpper.trim().isEmpty()) { 764 bldr.append(forceUpper); 765 brk = "<BR>"; 766 } 767 768 String validChars = calcValidChars(ad); 769 if (!validChars.trim().isEmpty()) { 770 bldr.append(brk); 771 brk = "<BR>"; 772 bldr.append(validChars); 773 } 774 775 String minMax = calcMinMax(ad); 776 if (!minMax.trim().isEmpty()) { 777 bldr.append(brk); 778 brk = "<BR>"; 779 bldr.append(minMax); 780 } 781 782 return bldr.toString(); 783 } 784 785 private String calcMinMax(AttributeDefinition ad) { 786 if (ad.getExclusiveMin() == null) { 787 if (ad.getInclusiveMax() == null) { 788 return " "; 789 } 790 return "Must be <= " + ad.getInclusiveMax(); 791 } 792 if (ad.getInclusiveMax() == null) { 793 return "Must be > " + ad.getExclusiveMin(); 794 } 795 return "Must be > " + ad.getExclusiveMin() + " and < " 796 + ad.getInclusiveMax(); 797 } 798 private static final String PAGE_PREFIX = "Formatted View of "; 799 private static final String PAGE_SUFFIX = " Searches"; 800 801 private String calcWikiSearchPage(String searchType) { 802 return PAGE_PREFIX + calcWikigPageAbbrev(searchType) + PAGE_SUFFIX; 803 } 804 805 private String calcWikigPageAbbrev(String searchType) { 806 if (searchType == null) { 807 return null; 808 } 809 if (searchType.equals("enumeration.management.search")) { 810 return "EM"; 811 } 812 if (searchType.startsWith("lu.")) { 813 return "LU"; 814 } 815 if (searchType.startsWith("cluset.")) { 816 return "LU"; 817 } 818 if (searchType.startsWith("lo.")) { 819 return "LO"; 820 } 821 if (searchType.startsWith("lrc.")) { 822 return "LRC"; 823 } 824 if (searchType.startsWith("comment.")) { 825 return "Comment"; 826 } 827 if (searchType.startsWith("org.")) { 828 return "Organization"; 829 } 830 if (searchType.startsWith("atp.")) { 831 return "ATP"; 832 } 833 throw new IllegalArgumentException("Unknown type of search: " + searchType); 834 } 835 836 private List<CommonLookupParam> filterConfiguredParams( 837 List<CommonLookupParam> params) { 838 List list = new ArrayList(); 839 if (params == null) { 840 return list; 841 } 842 if (params.size() == 0) { 843 return list; 844 } 845 for (CommonLookupParam param : params) { 846 if (param.getDefaultValueString() != null) { 847 list.add(param); 848 continue; 849 } 850 if (param.getDefaultValueList() != null) { 851 list.add(param); 852 } 853 } 854 return list; 855 } 856 857 private String calcLength(AttributeDefinition ad) { 858 if (ad.getMaxLength() != null) { 859 if (ad.getMinLength() != null && ad.getMinLength() != 0) { 860 if (ad.getMaxLength() == ad.getMinLength()) { 861 return ("must be " + ad.getMaxLength()); 862 } 863 return ad.getMinLength() + " to " + ad.getMaxLength(); 864 } 865 return "up to " + ad.getMaxLength(); 866 } 867 if (ad.getMinLength() != null) { 868 return "at least " + ad.getMinLength(); 869 } 870 return " "; 871 } 872 873 private String calcControl(AttributeDefinition ad) { 874 Control control = ad.getControlField(); 875 if (control == null) { 876 return " "; 877 } 878 if (control instanceof TextControl) { 879 TextControl textControl = (TextControl) control; 880 if (textControl.getDatePicker() != null) { 881 return "DateControl"; 882 } 883 if (!textControl.getStyleClassesAsString().isEmpty()) { 884 if (textControl.getStyleClassesAsString().contains("amount")) { 885 return "CurrencyControl"; 886 } 887 } 888 } 889 return control.getClass().getSimpleName(); 890 } 891 892 private String calcCrossField(AttributeDefinition ad) { 893 StringBuilder b = new StringBuilder(); 894 String semicolon = ""; 895 String cfr = calcCrossFieldRequire(ad); 896 if (cfr != null) { 897 b.append(semicolon); 898 semicolon = "; "; 899 b.append(cfr); 900 } 901 String cfw = calcCrossFieldWhen(ad); 902 if (cfw != null) { 903 b.append(semicolon); 904 semicolon = "; "; 905 b.append(cfw); 906 } 907 if (b.length() == 0) { 908 return " "; 909 } 910 return b.toString(); 911 } 912 913 private String calcCrossFieldRequire(AttributeDefinitionBase ad) { 914 // if (ad.getRequireConstraint() == null) { 915 // return null; 916 // } 917 // if (ad.getRequireConstraint().size() == 0) { 918 // return null; 919 // } 920 StringBuilder b = new StringBuilder(); 921 // String comma = ""; 922 // b.append("if not empty then "); 923 // for (RequiredConstraint rc : ad.getRequireConstraint()) { 924 // b.append(comma); 925 // comma = ", "; 926 // b.append(rc.getPropertyName()); 927 // } 928 // if (ad.getRequireConstraint().size() == 1) { 929 // b.append(" is"); 930 // } else { 931 // b.append(" are"); 932 // } 933 // b.append(" also required"); 934 return b.toString(); 935 } 936 937 private String calcCrossFieldWhen(AttributeDefinition ad) { 938 if (ad.getCaseConstraint() == null) { 939 return null; 940 } 941 StringBuilder b = new StringBuilder(); 942 CaseConstraint cc = ad.getCaseConstraint(); 943 for (WhenConstraint wc : cc.getWhenConstraint()) { 944 b.append("\\\\"); 945 b.append("\n"); 946 b.append("when "); 947 b.append(cc.getPropertyName()); 948 b.append(" "); 949 if (!cc.isCaseSensitive()) { 950 b.append("ignoring case "); 951 } 952 b.append(cc.getOperator()); 953 b.append(" "); 954 955 b.append("\\\\"); 956 b.append("\n"); 957 String comma = ""; 958 for (Object value : wc.getValues()) { 959 b.append(comma); 960 comma = " or "; 961 b.append(asString(value)); 962 } 963 b.append("\\\\"); 964 b.append("\n"); 965 b.append("then override constraint:" 966 + calcOverride(ad, (BaseConstraint) wc.getConstraint())); 967 } 968 return b.toString(); 969 } 970 971 private String calcOverride(AttributeDefinition ad, BaseConstraint cons) { 972 StringBuilder b = new StringBuilder(); 973 // b.append(calcOverride("serviceSide", ad.(), 974 // cons.getApplyClientSide())); 975 // b.append(calcOverride("exclusiveMin", ad.getExclusiveMin(), 976 // cons.getExclusiveMin())); 977 // b.append(calcOverride("inclusiveMax", ad.getInclusiveMax(), 978 // cons.getInclusiveMax())); 979 // String minOccursMessage = calcOverride("minOccurs", ad.getMinimumNumberOfElements(), 980 // cons.getMinimumNumberOfElements()); 981 // if (!minOccursMessage.trim().equals("")) { 982 // if (cons.getMinimumNumberOfElements() != null && cons.getMinimumNumberOfElements() == 1) { 983 // minOccursMessage = " REQUIRED"; 984 // } 985 // } 986 // b.append(minOccursMessage); 987 // b.append(calcOverride("validchars", ad.getValidCharactersConstraint(), 988 // cons.getValidCharactersConstraint())); 989 // b.append(calcOverride("lookup", ad.getLookupDefinition(), 990 // cons.getLookupDefinition())); 991 //TODO: other more complex constraints 992 return b.toString(); 993 } 994 995 private String calcOverride(String attribute, LookupConstraint val1, 996 LookupConstraint val2) { 997 if (val1 == val2) { 998 return ""; 999 } 1000 if (val1 == null && val2 != null) { 1001 return " add lookup " + this.calcLookup(val2); 1002 } 1003 if (val1 != null && val2 == null) { 1004 return " remove lookup constraint"; 1005 } 1006 return " change lookup to " + calcLookup(val2); 1007 } 1008 1009 private String calcOverride(String attribute, ValidCharactersConstraint val1, 1010 ValidCharactersConstraint val2) { 1011 if (val1 == val2) { 1012 return ""; 1013 } 1014 if (val1 == null && val2 != null) { 1015 return " add validchars " + calcValidChars(val2); 1016 } 1017 if (val1 != null && val2 == null) { 1018 return " remove validchars constraint"; 1019 } 1020 return " change validchars to " + calcValidChars(val2); 1021 } 1022 1023 private String calcOverride(String attribute, boolean val1, boolean val2) { 1024 if (val1 == val2) { 1025 return ""; 1026 } 1027 return " " + attribute + "=" + val2; 1028 } 1029 1030 private String calcOverride(String attribute, String val1, String val2) { 1031 if (val1 == null && val2 == null) { 1032 return ""; 1033 } 1034 if (val1 == val2) { 1035 return ""; 1036 } 1037 if (val1 == null) { 1038 return " " + attribute + "=" + val2; 1039 } 1040 if (val1.equals(val2)) { 1041 return ""; 1042 } 1043 return " " + attribute + "=" + val2; 1044 } 1045 1046 private String calcOverride(String attribute, Object val1, Object val2) { 1047 if (val1 == null && val2 == null) { 1048 return ""; 1049 } 1050 if (val1 == val2) { 1051 return ""; 1052 } 1053 if (val1 == null) { 1054 return " " + attribute + "=" + val2; 1055 } 1056 if (val1.equals(val2)) { 1057 return ""; 1058 } 1059 return " " + attribute + "=" + asString(val2); 1060 } 1061 1062 private String asString(Object value) { 1063 if (value == null) { 1064 return "null"; 1065 } 1066 if (value instanceof String) { 1067 return (String) value; 1068 } 1069 return value.toString(); 1070 } 1071 1072 private String nbsp(String str) { 1073 if (str == null) { 1074 return " "; 1075 } 1076 if (str.trim().isEmpty()) { 1077 return " "; 1078 } 1079 return str; 1080 } 1081 1082 public static void writeTag(PrintStream out, String tag, String value) { 1083 writeTag(out, tag, null, value); 1084 } 1085 1086 public static void writeTag(PrintStream out, String tag, String modifiers, String value) { 1087 if (value == null) { 1088 return; 1089 } 1090 if (value.equals("")) { 1091 return; 1092 } 1093 out.print("<" + tag); 1094 if (modifiers != null && !modifiers.isEmpty()) { 1095 out.print(" " + modifiers); 1096 } 1097 out.print(">"); 1098 out.print(escapeXML(value)); 1099 out.print("</" + tag + ">"); 1100 out.println(""); 1101 } 1102 1103 public static String escapeXML(String s) { 1104 StringBuffer sb = new StringBuffer(); 1105 int n = s.length(); 1106 for (int i = 0; i < n; i++) { 1107 // http://www.hdfgroup.org/HDF5/XML/xml_escape_chars.htm 1108 char c = s.charAt(i); 1109 switch (c) { 1110 case '"': 1111 sb.append("""); 1112 break; 1113 case '\'': 1114 sb.append("'"); 1115 break; 1116 case '&': 1117 sb.append("&"); 1118 break; 1119 case '<': 1120 sb.append("<"); 1121 break; 1122 case '>': 1123 sb.append(">"); 1124 break; 1125 //case ' ': sb.append(" ");break;\ 1126 default: 1127 sb.append(c); 1128 break; 1129 } 1130 } 1131 return sb.toString(); 1132 } 1133 1134 private void writeLink(PrintStream out, String url, String value) { 1135 out.print("<a href=\"" + url + "\">" + value + "</a>"); 1136 } 1137 }