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