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