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