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 }