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