View Javadoc
1   /**
2    * Copyright 2004-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.contract.model.util;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.Comparator;
21  import java.util.Enumeration;
22  import java.util.Iterator;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Set;
26  import java.util.Stack;
27  
28  import org.kuali.student.contract.model.MessageStructure;
29  import org.kuali.student.contract.model.Service;
30  import org.kuali.student.contract.model.ServiceContractModel;
31  import org.kuali.student.contract.model.XmlType;
32  import org.kuali.student.contract.writer.HtmlWriter;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   *
38   * @author nwright
39   */
40  public class HtmlContractWriter {
41  	
42  	private static final Logger log = LoggerFactory.getLogger(HtmlContractWriter.class);
43  
44      private HtmlWriter writer;
45      private ServiceContractModel model;
46      private ModelFinder finder;
47      private String directory;
48  
49      public HtmlContractWriter(String directory,
50              ServiceContractModel model) {
51          this.writer = new HtmlWriter(directory, "index.html",
52                  "Service Contracts Index");
53          this.directory = directory;
54          this.model = model;
55          this.finder = new ModelFinder(this.model);
56      }
57  
58      public void write(String projectVersion, String formattedDate) {
59          this.writeIndexPage(projectVersion, formattedDate);
60          for (Service service : model.getServices()) {
61              HtmlContractServiceWriter swriter = new HtmlContractServiceWriter(service,
62                      directory,
63                      model);
64              swriter.write(projectVersion, formattedDate);
65          }
66          for (XmlType xmlType : model.getXmlTypes()) {
67              HtmlContractMessageStructureWriter msWriter =
68                      new HtmlContractMessageStructureWriter(
69                      xmlType,
70                      directory,
71                      model);
72              msWriter.write(projectVersion, formattedDate);
73          }
74      }
75      private static final Comparator<XmlType> XML_TYPE_NAME_COMPARATOR =
76              new Comparator<XmlType>() {
77  
78                  @Override
79                  public int compare(XmlType e1, XmlType e2) {
80                      return e1.getName().toLowerCase().compareTo(e2.getName().toLowerCase());
81                  }
82              };
83      private static final Comparator<Service> SERVICE_NAME_COMPARATOR =
84              new Comparator<Service>() {
85  
86                  @Override
87                  public int compare(Service e1, Service e2) {
88                      return e1.getName().compareTo(e2.getName());
89                  }
90              };
91      private static final Comparator<Service> SERVICE_IMPL_NAME_COMPARATOR =
92              new Comparator<Service>() {
93  
94                  @Override
95                  public int compare(Service e1, Service e2) {
96                      String x1 = calcArea(e1) + "." + e1.getName();
97                      String x2 = calcArea(e2) + "." + e2.getName();
98                      return x1.compareTo(x2);
99                  }
100             };
101 
102     private String getOtherHomeTag () {
103         return "<a href=\"../dictionarydocs/index.html\">Dictionary Docs Home</a>";
104 //        return "";
105     }
106     private void writeIndexPage(String projectVersion, String formattedDate) {
107         
108         String otherHome = this.getOtherHomeTag();
109         VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">Home</a>", otherHome, projectVersion, formattedDate);
110         
111         writer.writeTag("h1", "Service Contracts");
112         
113         
114 
115         writer.indentPrintln(
116                 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
117         writer.indentPrintln(
118                 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
119         writer.indentPrintln("<b><a name=\"Services\"></a>Services</b>");
120         writer.indentPrintln(
121                 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
122         writer.indentPrintln("<ul>");
123         List<Service> services = new ArrayList<Service>(model.getServices());
124         Collections.sort(services, SERVICE_IMPL_NAME_COMPARATOR);
125         String oldArea = "";
126         for (Service service : services) {
127             String newArea = calcArea(service);
128             if (!newArea.equals(oldArea)) {
129                 if (!oldArea.isEmpty()) {
130                     writer.indentPrintln("</ul>");
131                     writer.decrementIndent();
132                 }
133                 writer.indentPrintln("<li>" + calcArea(service) + "</li>");
134                 writer.incrementIndent();
135                 writer.indentPrintln("<ul>");
136                 oldArea = newArea;
137             }
138             writer.indentPrint("<li>");
139             writer.print("<a href=\"" + service.getKey() + "Service" + ".html"
140                     + "\">" + service.getName() + "</a>");
141             writer.print("</li>");
142         }
143         writer.indentPrintln("</ul>");
144         writer.decrementIndent();
145         writer.indentPrintln("</ul>");        
146         writer.indentPrintln("</div>");
147         writer.indentPrintln("</div>");
148 
149         this.writeMainOrRootList();
150 
151         this.writeAlphabeticalList();
152 
153         writer.writeHeaderBodyAndFooterOutToFile();
154 
155     }
156 
157     private static String calcArea(Service service) {
158         return calcArea(service.getImplProject());
159     }
160 
161     private static String calcArea(String implProject) {
162         // group all student services together
163         if (implProject.startsWith("org.kuali.student.")) {
164             implProject = implProject.substring("org.kuali.student.".length());
165 //            return "Kuali Student Services";
166         }
167         if (implProject.startsWith("org.kuali.")) {
168             implProject = implProject.substring("org.kuali.".length());
169         }
170         if (implProject.contains(".api.")) {
171             implProject = implProject.substring(0, implProject.indexOf(".api."));
172         }
173         if (implProject.contains(".api.")) {
174             implProject = implProject.substring(0, implProject.indexOf(".api."));
175         }
176         if (implProject.startsWith("r2.")) {
177             implProject = implProject.substring("r2.".length());
178         }
179         if (implProject.contains(".class1.")) {
180             implProject = implProject.substring(0, implProject.indexOf(".class1.")) + 
181                     implProject.substring(implProject.indexOf(".class1.") + ".class1".length());
182         }
183         if (implProject.endsWith(".service")) {
184             implProject = implProject.substring(0, implProject.length() - ".service".length());
185         }
186         return implProject;
187     }
188 
189     private void writeMainOrRootList() {
190         Stack<String> stack = new Stack();
191         List<XmlType> types = this.getMainMessageStructures();
192         writer.indentPrintln(
193                 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
194         writer.indentPrintln(
195                 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
196         writer.indentPrintln(
197                 "<b><a name=\"MessageStructures\"></a> " + types.size() + " Main (root) Message Structures</b>");
198         writer.indentPrintln(
199                 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
200         writer.indentPrintln("<ul>");
201         for (XmlType type : types) {
202             this.writeLink(type);
203             if (!stack.contains(type.getName())) {
204                 stack.push(type.getName());
205                 this.writeSubStructures(type, stack);
206                 stack.pop();
207             }
208         }
209         writer.indentPrintln("</ul>");
210         writer.indentPrintln("</div>");
211         writer.indentPrintln("</div>");
212     }
213 
214     private String stripListOffEnd(String name) {
215         if (name.endsWith("List")) {
216             return name.substring(0, name.length() - "List".length());
217         }
218         return name;
219     }
220 
221     private boolean shouldWriteSubStructure(XmlType st) {
222         if (!st.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
223             return false;
224         }
225         return true;
226     }
227     
228     private void writeSubStructures(XmlType type, Stack<String> stack) {
229         boolean first = true;
230         for (MessageStructure ms : finder.findMessageStructures(type.getName())) {
231             XmlType st = finder.findXmlType(this.stripListOffEnd(ms.getType()));
232             if (st == null) {
233             	log.error (ms.getType() + " does not exist in the list of types with parents " + calcParents(stack));
234             	continue;
235             }
236             if (!shouldWriteSubStructure (st)) {
237                 continue;
238             }
239             if (first) {
240                 first = false;
241                 writer.indentPrintln("<ul>");
242             }
243             this.writeLink(st);
244             if (!stack.contains(st.getName())) {
245                 stack.push(st.getName());
246                 this.writeSubStructures(st, stack);
247                 stack.pop();
248             }
249         }
250         if (!first) {
251             writer.indentPrintln("</ul>");
252         }
253     }
254 
255     private String calcParents(Stack<String> stack) {
256         StringBuilder sb = new StringBuilder();
257         String dot = "";
258         Enumeration<String> en = stack.elements();
259         while (en.hasMoreElements()) {
260             sb.append(dot);
261             dot = ".";
262             sb.append(en.nextElement());
263         }
264         return sb.toString();
265     }
266 
267     private void writeLink(XmlType type) {
268         writer.indentPrint("<li>");
269         writer.print("<a href=\"" + type.getName() + ".html"
270                 + "\">" + type.getName() + "</a>");
271         writer.print("</li>");
272     }
273 
274     private List<XmlType> getMainMessageStructures() {
275         List<XmlType> types = new ArrayList(model.getXmlTypes().size());
276         for (XmlType type : this.getComplexMessageStructures()) {
277             if (isMainMessageStructure(type)) {
278                 types.add(type);
279             }
280         }
281         Collections.sort(types, XML_TYPE_NAME_COMPARATOR);
282         return types;
283     }
284 
285     private boolean isMainMessageStructure(XmlType xmlType) {
286         if (!HtmlContractMessageStructureWriter.calcOtherXmlTypeUsages(model,
287                 xmlType).isEmpty()) {
288             return false;
289         }
290         return true;
291     }
292 
293     private List<XmlType> getComplexMessageStructures() {
294         List<XmlType> types = new ArrayList(model.getXmlTypes().size());
295         for (XmlType type : model.getXmlTypes()) {
296             if (type.getPrimitive() == null) {
297                 throw new NullPointerException(type.getName()
298                         + " has no primitive flag set");
299             }
300             if (type.getPrimitive().equals(XmlType.COMPLEX)) {
301                 types.add(type);
302             }
303         }
304         Collections.sort(types, XML_TYPE_NAME_COMPARATOR);
305         return types;
306     }
307 
308     private void writeAlphabeticalList() {
309         List<XmlType> types = this.getComplexMessageStructures();
310         writer.indentPrintln(
311                 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
312         writer.indentPrintln(
313                 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
314         writer.indentPrintln(
315                 "<b><a name=\"MessageStructures\"></a>All " + types.size() + " Message Structures in Alphabetical Order</b>");
316         writer.indentPrintln(
317                 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
318         writer.indentPrintln("<ul>");
319         for (XmlType type : types) {
320             this.writeLink(type);
321         }
322         writer.indentPrintln("</ul>");
323         writer.indentPrintln("</div>");
324         writer.indentPrintln("</div>");
325     }
326 }