001/** 002 * Copyright 2010 The Kuali Foundation Licensed under the 003 * Educational Community License, Version 2.0 (the "License"); you may 004 * not use this file except in compliance with the License. You may 005 * obtain a copy of the License at 006 * 007 * http://www.osedu.org/licenses/ECL-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, 010 * software distributed under the License is distributed on an "AS IS" 011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 012 * or implied. See the License for the specific language governing 013 * permissions and limitations under the License. 014 */ 015package org.kuali.student.r1.common.assembly.dictionary; 016 017import java.util.ArrayList; 018import java.util.Collections; 019import java.util.List; 020import java.util.Set; 021 022import org.kuali.student.r1.common.assembly.data.ConstraintMetadata; 023import org.kuali.student.r1.common.assembly.data.Data; 024import org.kuali.student.r1.common.assembly.data.LookupMetadata; 025import org.kuali.student.r1.common.assembly.data.LookupParamMetadata; 026import org.kuali.student.r1.common.assembly.data.Metadata; 027import org.kuali.student.r1.common.assembly.data.MetadataInterrogator; 028 029@Deprecated 030public class MetadataFormatter { 031 032 private StringBuilder builder = new StringBuilder(5000); 033 private Metadata structureMetadata; 034 private String type; 035 private String rowSeperator = "\n"; 036 private String colSeperator = "|"; 037 private String structureName; 038 private int level; 039// private Map<String, Metadata> subStructuresToProcess = new LinkedHashMap<String, Metadata>(); 040 private Set<Metadata> structuresAlreadyProcessed; 041 private MetadataFormatter parent; 042 043 public MetadataFormatter(String structureName, Metadata structureMetadata, 044 String type, MetadataFormatter parent, 045 Set<Metadata> structuresAlreadyProcessed, int level) { 046 this.structureName = structureName; 047 this.structureMetadata = structureMetadata; 048 this.type = type; 049 this.parent = parent; 050 this.structuresAlreadyProcessed = structuresAlreadyProcessed; 051 this.level = level; 052 } 053 054 public String getStructureName() { 055 return structureName; 056 } 057 058 public MetadataFormatter getParent() { 059 return parent; 060 } 061 062 public String getRowSeperator() { 063 return rowSeperator; 064 } 065 066 public void setRowSeperator(String rowSeperator) { 067 this.rowSeperator = rowSeperator; 068 } 069 070 public String getColSeparator() { 071 return colSeperator; 072 } 073 074 public void setColSeparator(String separator) { 075 this.colSeperator = separator; 076 } 077 078 private String pad(String str, int size) { 079 StringBuilder padStr = new StringBuilder(size); 080 padStr.append(str); 081 while (padStr.length() < size) { 082 padStr.append(' '); 083 } 084 return padStr.toString(); 085 } 086 087 public String formatForWiki() { 088 if (!this.structuresAlreadyProcessed.add(structureMetadata)) { 089 return ""; 090 } 091 if (level == 1) { 092 builder.append(rowSeperator); 093 // builder.append 094 // ("======= start dump of object structure definition ========"); 095 builder.append(rowSeperator); 096 String header = "h1. " + this.calcSimpleName(structureName); 097 if (type != null) { 098 header = "h2. " + type; 099 } 100 builder.append(header); 101 builder.append("{anchor:" + structureName + "}"); 102 builder.append(rowSeperator); 103 builder.append("The object key is " + structureName); 104 builder.append(rowSeperator); 105 builder.append("The type is " + type); 106 builder.append(rowSeperator); 107 builder.append(colSeperator); 108 builder.append(colSeperator); 109 builder.append("Field"); 110 builder.append(colSeperator); 111 builder.append(colSeperator); 112 builder.append("Required?"); 113 builder.append(colSeperator); 114 builder.append(colSeperator); 115 builder.append("DataType"); 116 builder.append(colSeperator); 117 builder.append(colSeperator); 118 builder.append("Length"); 119 builder.append(colSeperator); 120 builder.append(colSeperator); 121 builder.append("Dynamic"); 122 builder.append(colSeperator); 123 builder.append(colSeperator); 124 builder.append("Default"); 125 builder.append(colSeperator); 126 builder.append(colSeperator); 127 builder.append("Repeats?"); 128 builder.append(colSeperator); 129 builder.append(colSeperator); 130 builder.append("Valid Characters"); 131 builder.append(colSeperator); 132 builder.append(colSeperator); 133 builder.append("Lookup Widget"); 134 builder.append(colSeperator); 135 builder.append(colSeperator); 136 builder.append("Lookup"); 137 builder.append(colSeperator); 138 builder.append(colSeperator); 139 builder.append(rowSeperator); 140 } 141 142 List<String> keys = new ArrayList<String>(); 143 keys.addAll(structureMetadata.getProperties().keySet()); 144 Collections.sort(keys); 145 for (String key : keys) { 146 if (key.equalsIgnoreCase ("_runtimeData")) 147 { 148 continue; 149 } 150 Metadata fieldMeta = structureMetadata.getProperties().get(key); 151 builder.append(colSeperator); 152 builder.append(calcFieldInfo (key, fieldMeta)); 153 builder.append(colSeperator); 154 builder.append(pad(calcRequired(fieldMeta), 10)); 155 builder.append(colSeperator); 156 builder.append(pad(calcDataType(fieldMeta), 25)); 157 builder.append(colSeperator); 158 builder.append(pad(calcLength(fieldMeta), 15)); 159 builder.append(colSeperator); 160 builder.append(pad(calcDynamic(fieldMeta), 7)); 161 builder.append(colSeperator); 162 builder.append(pad(calcDefaultValue(fieldMeta), 15)); 163 builder.append(colSeperator); 164 builder.append(calcRepeating(fieldMeta)); 165 builder.append(colSeperator); 166 builder.append(calcValidChars(fieldMeta)); 167 builder.append(colSeperator); 168 builder.append(calcWidget(fieldMeta)); 169 builder.append(colSeperator); 170 builder.append(calcLookup(fieldMeta)); 171 builder.append(colSeperator); 172 builder.append(rowSeperator); 173 if (fieldMeta.getDataType().equals(Data.DataType.DATA) 174 || fieldMeta.getDataType().equals(Data.DataType.LIST)) { 175 if (fieldMeta.getProperties() == null) { 176 throw new IllegalArgumentException( 177 fieldMeta.getName() 178 + " is DATA but does not have a sub-structure defined"); 179 } 180 MetadataFormatter formatter = new MetadataFormatter(key, 181 fieldMeta, null, this, structuresAlreadyProcessed, 182 level + 1); 183 builder.append(formatter.formatForWiki()); 184 } 185 } 186 187 return builder.toString(); 188 } 189 190 private String calcDataType(Metadata fieldMeta) { 191 if (fieldMeta.getDataType().equals(Data.DataType.LIST)) { 192 StringBuilder type = new StringBuilder(); 193 type.append("LIST of "); 194 String comma = ""; 195 for (String key : fieldMeta.getProperties().keySet()) { 196 type.append(comma); 197 type.append(fieldMeta.getProperties().get(key).getDataType() 198 .toString()); 199 comma = ", "; 200 } 201 return type.toString(); 202 } 203 return fieldMeta.getDataType().toString(); 204 } 205 206 private String calcDefaultValue(Metadata fieldMeta) { 207 if (fieldMeta.getDefaultValue() != null) { 208 return fieldMeta.getDefaultValue().toString(); 209 } 210 return " "; 211 } 212 213 private String calcDynamic(Metadata meta) { 214 if (meta.isDynamic()) { 215 return "dynamic"; 216 } 217 return " "; 218 } 219 220 private String calcFieldInfo (String key, Metadata fieldMeta) 221 { 222 StringBuilder bldr = new StringBuilder (40); 223 bldr.append (pad(calcFullyQualifiedFieldName(key), 30)); 224 if (fieldMeta.getLabelKey () != null) 225 { 226 bldr.append ("\\\\\n"); 227 bldr.append ("Label: "); 228 bldr.append (fieldMeta.getLabelKey ()); 229 } 230 return bldr.toString (); 231 } 232 233 public String calcFullyQualifiedFieldName(String fieldName) { 234 if (parent == null) { 235 return escapeWiki(fieldName); 236 } 237 return parent.calcFullyQualifiedFieldName(structureName) + "." 238 + escapeWiki(fieldName); 239 } 240 241 private String calcSimpleName(String name) { 242 if (name.lastIndexOf(".") != -1) { 243 name = name.substring(name.lastIndexOf(".") + 1); 244 } 245 return name; 246 } 247 248 private String calcNotSoSimpleName(String name) { 249 if (name.lastIndexOf(".") == -1) { 250 return name; 251 } 252 String simpleName = calcSimpleName(name); 253 String fieldName = calcSimpleName(name.substring(0, name.length() 254 - simpleName.length() - 1)); 255 return fieldName + "." + simpleName; 256 } 257 258 private String calcRequired(Metadata fieldMeta) { 259 for (ConstraintMetadata cons : fieldMeta.getConstraints()) { 260 if (cons.getMaxOccurs() != null) { 261 if (cons.getMaxOccurs() == 0) { 262 return "NOT USED"; 263 } 264 } 265 266 if (cons.getMinOccurs() != null) { 267 if (cons.getMinOccurs() >= 1) { 268 return "required"; 269 } 270 } 271 } 272 return " "; 273 // return "optional"; 274 } 275 276 private static final String LINK_TO_DEFINITIONS = "KULSTG:Formatted View of Base Dictionary#Valid Character Definitions"; 277 278 private String calcValidChars(Metadata fieldMeta) { 279 for (ConstraintMetadata cons : fieldMeta.getConstraints()) { 280 if (cons.getValidChars() == null) { 281 continue; 282 } 283 String validChars = escapeWiki(cons.getValidChars()); 284 String descr = "[" + "See" + "|" + LINK_TO_DEFINITIONS + "]" 285 + "\\\\\n" + validChars; 286 return descr; 287 } 288 return " "; 289 } 290 291 private String escapeWiki(String str) { 292 StringBuilder bldr = new StringBuilder(str.length()); 293 boolean precededByBackSlash = false; 294 for (int i = 0; i < str.length(); i++) { 295 char c = str.charAt(i); 296 switch (c) { 297 case '\\': 298 case '[': 299 case '*': 300 case ']': 301 case '|': 302 if (!precededByBackSlash) { 303 bldr.append('\\'); 304 } 305 break; 306 default: 307 break; 308 } 309 bldr.append(c); 310 if (c == '\\') { 311 precededByBackSlash = true; 312 } else { 313 precededByBackSlash = false; 314 } 315 } 316 return bldr.toString(); 317 } 318 319 private String calcWidget(Metadata fieldMeta) { 320 StringBuilder bldr = new StringBuilder(); 321 String comma = ""; 322 if (!fieldMeta.isCanEdit()) { 323 bldr.append(comma); 324 bldr.append("not editable"); 325 comma = ", "; 326 } 327 if (!fieldMeta.isCanView()) { 328 bldr.append(comma); 329 bldr.append("not viewable"); 330 comma = ", "; 331 } 332 if (!fieldMeta.isCanUnmask()) { 333 bldr.append(comma); 334 bldr.append("Not unmaskable"); 335 comma = ", "; 336 } 337 if (fieldMeta.getInitialLookup() != null) { 338 bldr.append(comma); 339 bldr.append(fieldMeta.getInitialLookup().getWidget()); 340 comma = ", "; 341 } 342 if (bldr.length() == 0) { 343 bldr.append(" "); 344 } 345 return bldr.toString(); 346 } 347 348 private String calcLookup(Metadata fieldMeta) { 349 StringBuilder bldr = new StringBuilder (); 350 if (fieldMeta.getInitialLookup() != null) { 351 bldr.append (calcLookup (fieldMeta.getInitialLookup ())); 352 } 353 354 if (fieldMeta.getAdditionalLookups () != null) { 355 if (fieldMeta.getAdditionalLookups ().size () > 0) { 356 if (fieldMeta.getInitialLookup() == null) { 357 bldr.append ("No initial lookup but..."); 358 } 359 bldr.append("\\\\"); 360 bldr.append("\n"); 361 bldr.append("\\\\"); 362 bldr.append("\n"); 363 bldr.append ("Additional Lookups:"); 364 bldr.append("\\\\"); 365 bldr.append("\n"); 366 } 367 for (LookupMetadata lm : fieldMeta.getAdditionalLookups ()) { 368 bldr.append("\\\\"); 369 bldr.append("\n"); 370 bldr.append (calcLookup (lm)); 371 bldr.append("\\\\"); 372 bldr.append("\n"); 373 } 374 } 375 if (bldr.length () == 0) 376 { 377 bldr.append (" "); 378 } 379 return bldr.toString (); 380 } 381 382 private String calcLookup(LookupMetadata lm) { 383 StringBuilder bldr = new StringBuilder(); 384 bldr.append(lm.getId()); 385// if (lm.getUsage () != null) { 386// bldr.append (" usage " + lm.getUsage ()); 387// } 388 // this is the search description not the lookup description 389 bldr.append (" - "); 390 bldr.append (lm.getName()); 391 bldr.append (" " + lm.getWidget ()); 392 String and = " with option "; 393 if (lm.getWidgetOptions () != null) { 394 for (LookupMetadata.WidgetOption wo: lm.getWidgetOptions ().keySet ()) 395 { 396 bldr.append (" and "); 397 bldr.append (wo); 398 bldr.append ("="); 399 bldr.append (lm.getWidgetOptions ().get (wo)); 400 } 401 } 402 and = ""; 403 bldr.append("\\\\\n"); 404 bldr.append("Implemented using search: "); 405 String searchPage = calcWikiSearchPage(lm.getSearchTypeId()); 406 bldr.append("[" + lm.getSearchTypeId() + "|" + searchPage + "#" 407 + lm.getSearchTypeId() + "]"); 408 List<LookupParamMetadata> configuredParameters = filterConfiguredParams(lm 409 .getParams()); 410 if (configuredParameters.size() > 0) { 411 bldr.append("\\\\"); 412 bldr.append("\n"); 413 bldr.append(" where "); 414 and = ""; 415 for (LookupParamMetadata param : configuredParameters) { 416 bldr.append(and); 417 and = " and "; 418 bldr.append(param.getName()); 419 bldr.append (" (" + param.getDataType () + ") "); 420 bldr.append("="); 421 if (param.getDefaultValueString() != null) { 422 bldr.append(param.getDefaultValueString()); 423 } 424 if (param.getDefaultValueList() != null) { 425 String comma = ""; 426 for (String defValue : param.getDefaultValueList()) { 427 bldr.append(comma); 428 comma = ", "; 429 bldr.append(defValue); 430 } 431 } 432 } 433 } 434 List<LookupParamMetadata> userEnterableParameters = this.filterUserEnterableParams (lm 435 .getParams()); 436 if (userEnterableParameters.size() > 0) { 437 bldr.append("\\\\"); 438 bldr.append("\n"); 439 bldr.append(" and the user can enter: "); 440 for (LookupParamMetadata param : userEnterableParameters) { 441 bldr.append ("\\\\\n"); 442 bldr.append(param.getName()); 443 bldr.append (" (" + param.getDataType () + ")"); 444 if (param.getWidget () != null) { 445 bldr.append(" using widget "); 446 bldr.append (param.getWidget ()); 447 } 448 if (param.getDefaultValueString() != null) { 449 bldr.append("defaulted to " + param.getDefaultValueString()); 450 } 451 if (param.getDefaultValueList() != null) { 452 String comma = "defaulted to "; 453 for (String defValue : param.getDefaultValueList()) { 454 bldr.append(comma); 455 comma = ", "; 456 bldr.append(defValue); 457 } 458 } 459 if (param.getChildLookup () != null) 460 { 461 bldr.append("\\\\"); 462 bldr.append("\n"); 463 bldr.append ("using a child lookup: "); 464 bldr.append("\\\\"); 465 bldr.append("\n"); 466 bldr.append (calcLookup (param.getChildLookup ())); 467 } 468 } 469 } 470 return bldr.toString(); 471 } 472 473 private static final String PAGE_PREFIX = "Formatted View of "; 474 private static final String PAGE_SUFFIX = " Searches"; 475 476 private String calcWikiSearchPage(String searchType) { 477 return PAGE_PREFIX + calcWikigPageAbbrev(searchType) + PAGE_SUFFIX; 478 } 479 480 private String calcWikigPageAbbrev(String searchType) { 481 if (searchType == null) { 482 return null; 483 } 484 if (searchType.equals("enumeration.management.search")) { 485 return "EM"; 486 } 487 if (searchType.startsWith("lu.")) { 488 return "LU"; 489 } 490 if (searchType.startsWith("cluset.")) { 491 return "LU"; 492 } 493 if (searchType.startsWith("lo.")) { 494 return "LO"; 495 } 496 if (searchType.startsWith("lrc.")) { 497 return "LRC"; 498 } 499 if (searchType.startsWith("comment.")) { 500 return "Comment"; 501 } 502 if (searchType.startsWith("org.")) { 503 return "Organization"; 504 } 505 if (searchType.startsWith("atp.")) { 506 return "ATP"; 507 } 508 if (searchType.startsWith("person.")) { 509 return "Person"; 510 } 511 if (searchType.startsWith("proposal.")) { 512 return "Proposal"; 513 } 514 if (searchType.startsWith("subjectCode.")) { 515 return "SC"; 516 } 517 throw new IllegalArgumentException("Unknown type of search: " 518 + searchType); 519 } 520 521 private List<LookupParamMetadata> filterConfiguredParams( 522 List<LookupParamMetadata> params) { 523 List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>(); 524 if (params == null) { 525 return list; 526 } 527 if (params.size() == 0) { 528 return list; 529 } 530 for (LookupParamMetadata param : params) { 531 if (param.getDefaultValueString() != null) { 532 list.add(param); 533 continue; 534 } 535 if (param.getDefaultValueList() != null) { 536 list.add(param); 537 continue; 538 } 539 } 540 return list; 541 } 542 543 private List<LookupParamMetadata> filterUserEnterableParams ( 544 List<LookupParamMetadata> params) { 545 List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>(); 546 if (params == null) { 547 return list; 548 } 549 if (params.size() == 0) { 550 return list; 551 } 552 for (LookupParamMetadata param : params) { 553 if (param.getWriteAccess () != null) { 554 if ( ! param.getWriteAccess ().equals (Metadata.WriteAccess.NEVER)) { 555 list.add(param); 556 continue; 557 } 558 } 559 } 560 return list; 561 } 562 563 private String calcRepeating(Metadata fieldMeta) { 564 if (!fieldMeta.getDataType().equals(Data.DataType.LIST)) { 565 return " "; 566 } 567 // return "repeating"; 568 MetadataInterrogator mi = new MetadataInterrogator(fieldMeta); 569 if (mi.getSmallestMaxOccurs() == null) { 570 if (mi.getLargestMinOccurs() != null 571 && mi.getLargestMinOccurs() > 1) { 572 return "repeating: minimum " + mi.getLargestMinOccurs() 573 + " times"; 574 } 575 return "repeating: unlimited"; 576 } 577 if (mi.getSmallestMaxOccurs() == 0) { 578 return "NOT USED"; 579 } 580 if (mi.getSmallestMaxOccurs() == 1) { 581 return " "; 582 // return "single"; 583 } 584 585 if (mi.getLargestMinOccurs() != null) { 586 if (mi.getLargestMinOccurs() > 1) { 587 return "repeating: " + mi.getLargestMinOccurs() + " to " 588 + mi.getSmallestMaxOccurs() + " times"; 589 } 590 } 591 return "repeating: maximum " + mi.getSmallestMaxOccurs() + " times"; 592 } 593 594 private String calcLength(Metadata fieldMeta) { 595 MetadataInterrogator mi = new MetadataInterrogator(fieldMeta); 596 if (mi.getSmallestMaxLength() != null) { 597 if (mi.getLargestMinLength() != null 598 && mi.getLargestMinLength() != 0) { 599 if (mi.getSmallestMaxLength() == mi.getLargestMinLength()) { 600 return ("(must be " + mi.getSmallestMaxLength() + ")"); 601 } 602 return "(" + mi.getLargestMinLength() + " to " 603 + mi.getSmallestMaxLength() + ")"; 604 } 605 return "(up to " + mi.getSmallestMaxLength() + ")"; 606 } 607 if (mi.getLargestMinLength() != null) { 608 return "(over " + mi.getLargestMinLength() + ")"; 609 } 610 return " "; 611 } 612}