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.contract.model.util; 017 018 import java.util.HashSet; 019 import java.util.LinkedHashSet; 020 import java.util.Set; 021 import org.kuali.student.contract.model.Lookup; 022 023 import org.kuali.student.contract.model.MessageStructure; 024 import org.kuali.student.contract.model.ServiceContractModel; 025 import org.kuali.student.contract.model.ServiceMethod; 026 import org.kuali.student.contract.model.ServiceMethodParameter; 027 import org.kuali.student.contract.model.XmlType; 028 import org.kuali.student.contract.writer.HtmlWriter; 029 import org.slf4j.Logger; 030 import org.slf4j.LoggerFactory; 031 032 /** 033 * 034 * @author nwright 035 */ 036 public class HtmlContractMessageStructureWriter { 037 038 private static final Logger log = LoggerFactory.getLogger(HtmlContractMessageStructureWriter.class); 039 040 private XmlType xmlType; 041 private HtmlWriter writer; 042 private ServiceContractModel model; 043 private ModelFinder finder; 044 045 public HtmlContractMessageStructureWriter(XmlType xmlType, String directory, 046 ServiceContractModel model) { 047 this.xmlType = xmlType; 048 this.writer = new HtmlWriter(directory, xmlType.getName() + ".html", 049 xmlType.getName()); 050 this.model = model; 051 this.finder = new ModelFinder(this.model); 052 } 053 054 private String initUpper(String str) { 055 if (str == null) { 056 return null; 057 } 058 if (str.length() == 0) { 059 return str; 060 } 061 if (str.length() == 1) { 062 return str.toUpperCase(); 063 } 064 return str.substring(0, 1).toUpperCase() + str.substring(1); 065 } 066 067 private boolean isMainMessageStructure(XmlType xmlType) { 068 if (!HtmlContractMessageStructureWriter.calcOtherXmlTypeUsages(model, 069 xmlType).isEmpty()) { 070 return false; 071 } 072 return true; 073 } 074 075 private boolean shouldAddDictionaryLink (XmlType xmlType) { 076 return this.isMainMessageStructure(xmlType); 077 } 078 079 public void write(String projectVersion, String formattedDate) { 080 081 this.writeStyleSheet(); 082 083 084 if (this.shouldAddDictionaryLink(xmlType)) { 085 VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">home</a>", "<a href=\"../dictionarydocs/" + initUpper(xmlType.getName()) + ".html\">dictionary doc</a>", projectVersion, formattedDate); 086 } 087 else 088 VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">home</a>", "" ,projectVersion, formattedDate); 089 090 091 writer.writeTag("h1", xmlType.getName()); 092 093 writer.indentPrintln("<table id=\"structureMetaTable\">"); 094 writer.indentPrintln("<tr>"); 095 writer.writeTag("th", "class=h", "Name"); 096 writer.writeTag("td", "id=structureName colspan=2", xmlType.getName()); 097 writer.indentPrintln("</tr>"); 098 // writer.indentPrintln ("<tr>"); 099 // writer.writeTag ("th", "class=h", "Version"); 100 // writer.writeTag ("td", "id=structureVersion colspan=2", xmlType.getVersion ()); 101 // writer.indentPrintln ("</tr>"); 102 writer.indentPrintln("<tr>"); 103 writer.writeTag("th", "rowspan=3 class=h", "Usage"); 104 writer.indentPrint("<td id=\"structureVersion\" colspan=2>"); 105 for (String servKey : xmlType.getService().split(",")) { 106 writer.indentPrintln("<a href=\"" + servKey + "Service" + ".html" + "\">" 107 + servKey + "Service" + "</a>"); 108 } 109 writer.indentPrint("</td>"); 110 111 writer.indentPrintln("</tr>"); 112 writer.indentPrintln("<tr>"); 113 writer.writeTag("th", "class=h", ""); 114 writer.indentPrint("<td id=\"structureVersion\" colspan=2>"); 115 for (ServiceMethod method : this.calcUsageByMethods(xmlType)) { 116 writer.indentPrintln("<a href=\"" + method.getService() + "Service" 117 + ".html" + "#" + method.getService() + "-" 118 + method.getName() + "\">" 119 + method.getName() + "</a>"); 120 } 121 writer.indentPrint("</td>"); 122 writer.indentPrintln("</tr>"); 123 writer.indentPrintln("<tr>"); 124 writer.writeTag("th", "class=h", ""); 125 writer.indentPrint("<td id=\"structureVersion\" colspan=2>"); 126 for (String xmlTypeName : this.calcOtherXmlTypeUsages(xmlType)) { 127 XmlType usageType = finder.findXmlType(xmlTypeName); 128 if (usageType == null) { 129 throw new NullPointerException("Coud not find XmlType with name=" 130 + xmlTypeName); 131 } 132 writer.indentPrintln("<a href=\"" + usageType.getName() + ".html" + "\">" 133 + usageType.getName() + "</a>"); 134 } 135 writer.indentPrint("</td>"); 136 writer.indentPrintln("</tr>"); 137 138 writer.writeTag("th", "class=h", "Type"); 139 writer.writeTag("td", "id=structureVersion colspan=2", 140 xmlType.getPrimitive()); 141 writer.indentPrintln("</tr>"); 142 writer.indentPrintln("</table>"); 143 144 writer.writeTag("h2", "Description"); 145 writer.indentPrintln(this.addHTMLBreaks(calcDescription (xmlType))); 146 147 if (!xmlType.getPrimitive().equals(XmlType.COMPLEX)) { 148 return; 149 } 150 writer.indentPrintln( 151 "<h2><a name=\"StructureDefinition\"></a>Structure Definition</h2>"); 152 153 154 writer.indentPrintln("<table class=\"structTable\">"); 155 writer.indentPrintln("<tr>"); 156 writer.indentPrintln("<th class=\"h\">ShortName</th>"); 157 writer.indentPrintln("<th class=\"h\">Name</th>"); 158 writer.indentPrintln("<th class=\"h\">Type</th>"); 159 writer.indentPrintln("<th class=\"h\">Description</th>"); 160 writer.indentPrintln("<th class=\"h\">Required?</th>"); 161 writer.indentPrintln("<th class=\"h\">Read only?</th>"); 162 writer.indentPrintln("<th class=\"h\">Lookup (WIP)</th>"); 163 writer.indentPrintln("<th class=\"h\">Implementation Notes</th>"); 164 writer.indentPrintln("</tr>"); 165 166 for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) { 167 this.writeMessageStructure(ms); 168 } 169 writer.indentPrintln("</table>"); 170 writer.writeHeaderBodyAndFooterOutToFile(); 171 } 172 173 174 private String calcDescription(XmlType xmlType) { 175 StringBuilder sb = new StringBuilder(); 176 String newLine = ""; 177 if (xmlType.getDesc() != null && !xmlType.getDesc().trim().isEmpty()) { 178 sb.append(newLine); 179 newLine = "\n"; 180 sb.append(xmlType.getDesc ()); 181 } 182 if (xmlType.isDeprecated()) { 183 sb.append(newLine); 184 newLine = "\n"; 185 sb.append("============== Deprecated ==============="); 186 } 187 return sb.toString(); 188 } 189 190 private String checkForNbsp(String str) { 191 if (str == null) { 192 return " "; 193 } 194 if (str.trim().isEmpty()) { 195 return " "; 196 } 197 return str; 198 } 199 200 private String addHTMLBreaks(String str) { 201 if (str == null) { 202 return " "; 203 } 204 return str.replaceAll("(\r\n|\r|\n|\n\r)", "<br>"); 205 } 206 207 public static Set<String> calcUsageByService(ServiceContractModel mdl, XmlType xmlType) { 208 Set<String> services = new HashSet(); 209 for (ServiceMethod method : calcUsageByMethods(mdl, xmlType)) { 210 services.add(method.getService()); 211 } 212 return services; 213 } 214 215 private Set<ServiceMethod> calcUsageByMethods(XmlType xmlType) { 216 return calcUsageByMethods(model, xmlType); 217 } 218 219 public static Set<ServiceMethod> calcUsageByMethods(ServiceContractModel mdl, XmlType xmlType) { 220 Set<ServiceMethod> methods = new LinkedHashSet(); 221 for (ServiceMethod method : mdl.getServiceMethods()) { 222 if (stripListFromType(method.getReturnValue().getType()).equalsIgnoreCase(xmlType.getName())) { 223 methods.add(method); 224 continue; 225 } 226 for (ServiceMethodParameter param : method.getParameters()) { 227 if (stripListFromType(param.getType()).equalsIgnoreCase(xmlType.getName())) { 228 methods.add(method); 229 break; 230 } 231 } 232 } 233 return methods; 234 } 235 236 private Set<String> calcOtherXmlTypeUsages(XmlType xmlType) { 237 return calcOtherXmlTypeUsages(model, xmlType); 238 } 239 240 public static Set<String> calcOtherXmlTypeUsages(ServiceContractModel mdl, 241 XmlType xmlType) { 242 Set<String> xmlTypeNames = new LinkedHashSet(); 243 for (MessageStructure ms : mdl.getMessageStructures()) { 244 if (ms.getType() == null) { 245 throw new NullPointerException(ms.getId() + " has no type set"); 246 } 247 if (stripListFromType(ms.getType()).equalsIgnoreCase(xmlType.getName())) { 248 xmlTypeNames.add(ms.getXmlObject()); 249 } 250 } 251 return xmlTypeNames; 252 } 253 254 private void writeMessageStructure(MessageStructure ms) { 255 writer.indentPrintln("<tr>"); 256 writer.writeTag("td", "class=\"structSName\"", ms.getShortName()); 257 writer.writeTag("td", "class=\"structLName\"", ms.getName()); 258 XmlType subType = finder.findXmlType(this.stripListFromType(ms.getType())); 259 if (subType == null) { 260 // for (XmlType xmlt : model.getXmlTypes()) { 261 // System.out.println(this.getClass().getSimpleName() + ": " 262 // + xmlt.getName()); 263 // } 264 // throw new NullPointerException(ms.getXmlObject() + "." + ms.getShortName() 265 // + " has type " + ms.getType() 266 // + " was not found in list of known types"); 267 268 log.error (ms.getXmlObject() + "." + ms.getShortName() 269 + " has type " + ms.getType() 270 + " was not found in list of known types"); 271 return; 272 } 273 if (subType.getPrimitive().equals(XmlType.COMPLEX)) { 274 writer.indentPrint("<td class=\"structType\">"); 275 writer.indentPrintln("<a href=\"" + subType.getName() + ".html" + "\">" 276 + ms.getType() + "</a>"); 277 writer.indentPrint("</td>"); 278 } else { 279 writer.writeTag("td", "class=\"structType\"", ms.getType()); 280 } 281 writer.writeTag("td", "class=\"structDesc\"", addHTMLBreaks(missingData( 282 calcDescription(ms)))); 283 writer.writeTag("td", "class=\"structOpt\"", checkForNbsp(ms.getRequired())); 284 writer.writeTag("td", "class=\"structOpt\"", checkForNbsp(ms.getReadOnly())); 285 286 writer.writeTag("td", "class=\"structCard\"", addHTMLBreaks (checkForNbsp (calcLookup (ms.getLookup ())))); 287 // writer.writeTag ("td", "class=\"structStatus\"", ms.getStatus ()); 288 writer.writeTag("td", "class=\"commentsDesc\"", addHTMLBreaks(this.checkForNbsp(ms.getImplNotes()))); 289 writer.indentPrintln("</tr>"); 290 291 // writer.indentPrintln ("</table>"); 292 // writer.indentPrintln ("<p>"); 293 294 // writer.indentPrintln ("<p>"); 295 } 296 297 private String calcLookup(Lookup lookup) { 298 if (lookup == null) { 299 return null; 300 } 301 StringBuilder sb = new StringBuilder(); 302 String newLine = "\n"; 303 sb.append(lookup.getServiceKey()); 304 sb.append(":"); 305 sb.append(lookup.getXmlTypeName()); 306 if (lookup.getGetMethod() != null) { 307 sb.append(newLine); 308 sb.append(lookup.getGetMethod()); 309 } 310 if (lookup.getSearchMethod() != null) { 311 sb.append(newLine); 312 sb.append(lookup.getSearchMethod()); 313 if (lookup.getAdditionalCriteria() != null) { 314 sb.append(newLine); 315 sb.append(lookup.getAdditionalCriteria().toString()); 316 } 317 } 318 return sb.toString(); 319 } 320 321 private String calcDescription(MessageStructure ms) { 322 StringBuilder sb = new StringBuilder(); 323 String newLine = ""; 324 if (ms.getDescription() != null && !ms.getDescription().trim().isEmpty()) { 325 sb.append(newLine); 326 newLine = "\n"; 327 sb.append(ms.getDescription()); 328 } 329 if (ms.isDeprecated()) { 330 sb.append(newLine); 331 newLine = "\n"; 332 sb.append("============== Deprecated ==============="); 333 } 334 return sb.toString(); 335 } 336 337 private String missingData(String str) { 338 if (str == null) { 339 return "???"; 340 } 341 if (str.trim().isEmpty()) { 342 return "???"; 343 } 344 return str; 345 } 346 347 private static String stripListFromType(String type) { 348 if (type.endsWith("List")) { 349 return type.substring(0, type.length() - "List".length()); 350 } 351 return type; 352 } 353 354 public void writeStyleSheet() { 355 writer.indentPrintln("<style type=\"text/css\">"); 356 writer.indentPrintln(""); 357 writer.indentPrintln("table#structureMetaTable {"); 358 writer.indentPrintln("border-collapse:collapse;"); 359 writer.indentPrintln("border:1px solid #000000;"); 360 writer.indentPrintln("width:95%;"); 361 writer.indentPrintln("}"); 362 writer.indentPrintln("table#structureMetaTable th.h {"); 363 writer.indentPrintln("border:1px solid #000000;"); 364 writer.indentPrintln("background-color:#eeeeee;"); 365 writer.indentPrintln("width:15%;"); 366 writer.indentPrintln("}"); 367 writer.indentPrintln("table#structureMetaTable td#structureName {"); 368 writer.indentPrintln("border:1px solid #000000;"); 369 writer.indentPrintln("width:85%;"); 370 writer.indentPrintln("}"); 371 writer.indentPrintln("table#structureMetaTable td#structureVersion {"); 372 writer.indentPrintln("border:1px solid #000000;"); 373 writer.indentPrintln("width:70%;"); 374 writer.indentPrintln("}"); 375 writer.indentPrintln("table#structureMetaTable td#structureVersionHistory {"); 376 writer.indentPrintln("border:1px solid #000000;"); 377 writer.indentPrintln("width:15%;"); 378 writer.indentPrintln("}"); 379 writer.indentPrintln(""); 380 writer.indentPrintln("</style>"); 381 382 writer.indentPrintln("<style type=\"text/css\">"); 383 writer.indentPrintln(""); 384 writer.indentPrintln("table.structTable {"); 385 writer.indentPrintln("border-collapse:collapse;"); 386 writer.indentPrintln("border:1px solid #000000;"); 387 writer.indentPrintln("width:95%;"); 388 writer.indentPrintln("}"); 389 writer.indentPrintln(""); 390 writer.indentPrintln("table.structTable td.d {"); 391 writer.indentPrintln("border:1px solid #000000;"); 392 writer.indentPrintln("}"); 393 writer.indentPrintln(""); 394 writer.indentPrintln("table.structTable th.h {"); 395 writer.indentPrintln("border:1px solid #000000;"); 396 writer.indentPrintln("background-color:#eeeeee;"); 397 writer.indentPrintln("}"); 398 writer.indentPrintln(""); 399 writer.indentPrintln("table.structTable td.structSName {"); 400 writer.indentPrintln("border:1px solid #000000;"); 401 writer.indentPrintln("background-color:#f2f2f2;"); 402 writer.indentPrintln("color:#222222;"); 403 writer.indentPrintln("text-align:left;"); 404 writer.indentPrintln("vertical-align:top;"); 405 writer.indentPrintln("font-weight:bold;"); 406 writer.indentPrintln("font-style:italic;"); 407 writer.indentPrintln(""); 408 writer.indentPrintln("}"); 409 writer.indentPrintln(""); 410 writer.indentPrintln("table.structTable td.structLName {"); 411 writer.indentPrintln("border:1px solid #000000;"); 412 writer.indentPrintln("background:#ffffff;"); 413 writer.indentPrintln("vertical-align:top;"); 414 writer.indentPrintln(""); 415 writer.indentPrintln("}"); 416 writer.indentPrintln(""); 417 writer.indentPrintln("table.structTable td.structType {"); 418 writer.indentPrintln("border:1px solid #000000;"); 419 writer.indentPrintln("background:#ffffff;"); 420 writer.indentPrintln("vertical-align:top;"); 421 writer.indentPrintln("font-style:italic;"); 422 writer.indentPrintln(""); 423 writer.indentPrintln("}"); 424 writer.indentPrintln(""); 425 writer.indentPrintln("table.structTable td.structDesc {"); 426 writer.indentPrintln("border:1px solid #000000;"); 427 writer.indentPrintln("background:#ffffff;"); 428 writer.indentPrintln("vertical-align:top;"); 429 writer.indentPrintln(""); 430 writer.indentPrintln("}"); 431 writer.indentPrintln(""); 432 writer.indentPrintln("table.structTable td.structOpt {"); 433 writer.indentPrintln("border:1px solid #000000;"); 434 writer.indentPrintln("background:#ffffff;"); 435 writer.indentPrintln("vertical-align:top;"); 436 writer.indentPrintln("text-align: center;"); 437 writer.indentPrintln("}"); 438 writer.indentPrintln(""); 439 writer.indentPrintln("table.structTable td.structReq {"); 440 writer.indentPrintln("border:1px solid #000000;"); 441 writer.indentPrintln("background:#ccccff;"); 442 writer.indentPrintln("vertical-align:top;"); 443 writer.indentPrintln("text-align: center;"); 444 writer.indentPrintln("}"); 445 writer.indentPrintln(""); 446 writer.indentPrintln(""); 447 writer.indentPrintln("table.structTable td.structCard {"); 448 writer.indentPrintln("border:1px solid #000000;"); 449 writer.indentPrintln("background:#ffffff;"); 450 writer.indentPrintln("vertical-align:top;"); 451 writer.indentPrintln("text-align: center;"); 452 writer.indentPrintln("}"); 453 writer.indentPrintln(""); 454 writer.indentPrintln("table.structTable td.structAttr {"); 455 writer.indentPrintln("border:1px solid #000000;"); 456 writer.indentPrintln("background:#ffffff;"); 457 writer.indentPrintln("vertical-align:top;"); 458 writer.indentPrintln("text-align: center;"); 459 writer.indentPrintln("}"); 460 writer.indentPrintln(""); 461 writer.indentPrintln("table.structTable td.structElem {"); 462 writer.indentPrintln("border:1px solid #000000;"); 463 writer.indentPrintln("background:#ccccff;"); 464 writer.indentPrintln("vertical-align:top;"); 465 writer.indentPrintln("text-align: center;"); 466 writer.indentPrintln("}"); 467 writer.indentPrintln(""); 468 writer.indentPrintln("table.structTable td.structStatus {"); 469 writer.indentPrintln("border:1px solid #000000;"); 470 writer.indentPrintln("background:#ffffff;"); 471 writer.indentPrintln("vertical-align:top;"); 472 writer.indentPrintln("text-align: center;"); 473 writer.indentPrintln(""); 474 writer.indentPrintln("}"); 475 writer.indentPrintln(""); 476 writer.indentPrintln("table.structTable td.commentsDesc {"); 477 writer.indentPrintln("border:1px solid #000000;"); 478 writer.indentPrintln("background:#ffffff;"); 479 writer.indentPrintln("vertical-align:top;"); 480 writer.indentPrintln(""); 481 writer.indentPrintln("}"); 482 writer.indentPrintln(""); 483 writer.indentPrintln(""); 484 writer.indentPrintln("</style>"); 485 486 487 } 488 }