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