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 "&nbsp;";
193            }
194            if (str.trim().isEmpty()) {
195                return "&nbsp;";
196            }
197            return str;
198        }
199    
200        private String addHTMLBreaks(String str) {
201            if (str == null) {
202                return "&nbsp;";
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    }