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.ArrayList;
019 import java.util.Collections;
020 import java.util.Comparator;
021 import java.util.Enumeration;
022 import java.util.Iterator;
023 import java.util.LinkedHashSet;
024 import java.util.List;
025 import java.util.Set;
026 import java.util.Stack;
027
028 import org.kuali.student.contract.model.MessageStructure;
029 import org.kuali.student.contract.model.Service;
030 import org.kuali.student.contract.model.ServiceContractModel;
031 import org.kuali.student.contract.model.XmlType;
032 import org.kuali.student.contract.writer.HtmlWriter;
033 import org.slf4j.Logger;
034 import org.slf4j.LoggerFactory;
035
036 /**
037 *
038 * @author nwright
039 */
040 public class HtmlContractWriter {
041
042 private static final Logger log = LoggerFactory.getLogger(HtmlContractWriter.class);
043
044 private HtmlWriter writer;
045 private ServiceContractModel model;
046 private ModelFinder finder;
047 private String directory;
048
049 public HtmlContractWriter(String directory,
050 ServiceContractModel model) {
051 this.writer = new HtmlWriter(directory, "index.html",
052 "Service Contracts Index");
053 this.directory = directory;
054 this.model = model;
055 this.finder = new ModelFinder(this.model);
056 }
057
058 public void write(String projectVersion, String formattedDate) {
059 this.writeIndexPage(projectVersion, formattedDate);
060 for (Service service : model.getServices()) {
061 HtmlContractServiceWriter swriter = new HtmlContractServiceWriter(service,
062 directory,
063 model);
064 swriter.write(projectVersion, formattedDate);
065 }
066 for (XmlType xmlType : model.getXmlTypes()) {
067 HtmlContractMessageStructureWriter msWriter =
068 new HtmlContractMessageStructureWriter(
069 xmlType,
070 directory,
071 model);
072 msWriter.write(projectVersion, formattedDate);
073 }
074 }
075 private static final Comparator<XmlType> XML_TYPE_NAME_COMPARATOR =
076 new Comparator<XmlType>() {
077
078 @Override
079 public int compare(XmlType e1, XmlType e2) {
080 return e1.getName().toLowerCase().compareTo(e2.getName().toLowerCase());
081 }
082 };
083 private static final Comparator<Service> SERVICE_NAME_COMPARATOR =
084 new Comparator<Service>() {
085
086 @Override
087 public int compare(Service e1, Service e2) {
088 return e1.getName().compareTo(e2.getName());
089 }
090 };
091 private static final Comparator<Service> SERVICE_IMPL_NAME_COMPARATOR =
092 new Comparator<Service>() {
093
094 @Override
095 public int compare(Service e1, Service e2) {
096 String x1 = calcArea(e1) + "." + e1.getName();
097 String x2 = calcArea(e2) + "." + e2.getName();
098 return x1.compareTo(x2);
099 }
100 };
101
102 private void writeIndexPage(String projectVersion, String formattedDate) {
103
104 VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">Home</a>", "<a href=\"../dictionarydocs/index.html\">Dictionary Docs Home</a>", projectVersion, formattedDate);
105
106 writer.writeTag("h1", "Service Contracts");
107
108
109
110 writer.indentPrintln(
111 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
112 writer.indentPrintln(
113 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
114 writer.indentPrintln("<b><a name=\"Services\"></a>Services</b>");
115 writer.indentPrintln(
116 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
117 writer.indentPrintln("<ul>");
118 List<Service> services = new ArrayList<Service>(model.getServices());
119 Collections.sort(services, SERVICE_IMPL_NAME_COMPARATOR);
120
121 Set<String>mergedServiceNames = new LinkedHashSet<String>();
122
123 Iterator<Service> it = services.iterator();
124
125 while (it.hasNext()) {
126 Service svc = it.next();
127
128 if (mergedServiceNames.contains(svc.getName())) {
129
130 it.remove();
131
132 }
133 else
134 mergedServiceNames.add(svc.getName());
135 }
136
137 String oldArea = "";
138 for (Service service : services) {
139 String newArea = calcArea(service);
140 if (!newArea.equals(oldArea)) {
141 if (!oldArea.isEmpty()) {
142 writer.indentPrintln("</ul>");
143 writer.decrementIndent();
144 }
145 writer.indentPrintln("<li>" + calcArea(service) + "</li>");
146 writer.incrementIndent();
147 writer.indentPrintln("<ul>");
148 oldArea = newArea;
149 }
150 writer.indentPrint("<li>");
151 writer.print("<a href=\"" + service.getName() + ".html"
152 + "\">" + service.getName() + "</a>");
153 writer.print("</li>");
154 }
155 writer.indentPrintln("</ul>");
156 writer.decrementIndent();
157 writer.indentPrintln("</ul>");
158 writer.indentPrintln("</div>");
159 writer.indentPrintln("</div>");
160
161 this.writeMainOrRootList();
162
163 this.writeAlphabeticalList();
164
165 writer.writeHeaderBodyAndFooterOutToFile();
166
167 }
168
169 private static String calcArea(Service service) {
170 return calcArea(service.getImplProject());
171 }
172
173 private static String calcArea(String implProject) {
174 // group all student services together
175 if (implProject.startsWith("org.kuali.student")) {
176 return "Kuali Student Services";
177 }
178 if (implProject.startsWith("org.kuali.")) {
179 implProject = implProject.substring("org.kuali.".length());
180 }
181 if (implProject.contains(".api.")) {
182 implProject = implProject.substring(0, implProject.indexOf(".api."));
183 }
184 return implProject;
185 }
186
187 private void writeMainOrRootList() {
188 Stack<String> stack = new Stack();
189 List<XmlType> types = this.getMainMessageStructures();
190 writer.indentPrintln(
191 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
192 writer.indentPrintln(
193 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
194 writer.indentPrintln(
195 "<b><a name=\"MessageStructures\"></a> " + types.size() + " Main (root) Message Structures</b>");
196 writer.indentPrintln(
197 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
198 writer.indentPrintln("<ul>");
199 for (XmlType type : types) {
200 this.writeLink(type);
201 if (!stack.contains(type.getName())) {
202 stack.push(type.getName());
203 this.writeSubStructures(type, stack);
204 stack.pop();
205 }
206 }
207 writer.indentPrintln("</ul>");
208 writer.indentPrintln("</div>");
209 writer.indentPrintln("</div>");
210 }
211
212 private String stripListOffEnd(String name) {
213 if (name.endsWith("List")) {
214 return name.substring(0, name.length() - "List".length());
215 }
216 return name;
217 }
218
219 private void writeSubStructures(XmlType type, Stack<String> stack) {
220 boolean first = true;
221 for (MessageStructure ms : finder.findMessageStructures(type.getName())) {
222 XmlType st = finder.findXmlType(this.stripListOffEnd(ms.getType()));
223 if (st == null) {
224 log.error (ms.getType() + " does not exist in the list of types with parents " + calcParents(stack));
225 continue;
226 }
227 if (!st.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
228 continue;
229 }
230 if (first) {
231 first = false;
232 writer.indentPrintln("<ul>");
233 }
234 this.writeLink(st);
235 if (!stack.contains(st.getName())) {
236 stack.push(st.getName());
237 this.writeSubStructures(st, stack);
238 stack.pop();
239 }
240 }
241 if (!first) {
242 writer.indentPrintln("</ul>");
243 }
244 }
245
246 private String calcParents(Stack<String> stack) {
247 StringBuilder sb = new StringBuilder();
248 String dot = "";
249 Enumeration<String> en = stack.elements();
250 while (en.hasMoreElements()) {
251 sb.append(dot);
252 dot = ".";
253 sb.append(en.nextElement());
254 }
255 return sb.toString();
256 }
257
258 private void writeLink(XmlType type) {
259 writer.indentPrint("<li>");
260 writer.print("<a href=\"" + type.getName() + ".html"
261 + "\">" + type.getName() + "</a>");
262 writer.print("</li>");
263 }
264
265 private List<XmlType> getMainMessageStructures() {
266 List<XmlType> types = new ArrayList(model.getXmlTypes().size());
267 for (XmlType type : this.getComplexMessageStructures()) {
268 if (isMainMessageStructure(type)) {
269 types.add(type);
270 }
271 }
272 Collections.sort(types, XML_TYPE_NAME_COMPARATOR);
273 return types;
274 }
275
276 private boolean isMainMessageStructure(XmlType xmlType) {
277 if (!HtmlContractMessageStructureWriter.calcOtherXmlTypeUsages(model,
278 xmlType).isEmpty()) {
279 return false;
280 }
281 return true;
282 }
283
284 private List<XmlType> getComplexMessageStructures() {
285 List<XmlType> types = new ArrayList(model.getXmlTypes().size());
286 for (XmlType type : model.getXmlTypes()) {
287 if (type.getPrimitive() == null) {
288 throw new NullPointerException(type.getName()
289 + " has no primitive flag set");
290 }
291 if (type.getPrimitive().equals(XmlType.COMPLEX)) {
292 types.add(type);
293 }
294 }
295 Collections.sort(types, XML_TYPE_NAME_COMPARATOR);
296 return types;
297 }
298
299 private void writeAlphabeticalList() {
300 List<XmlType> types = this.getComplexMessageStructures();
301 writer.indentPrintln(
302 "<div class=\"panel\" style=\"background-color: rgb(255, 255, 255); border: 1px solid rgb(204, 204, 204);\">");
303 writer.indentPrintln(
304 "<div class=\"panelHeader\" style=\"border-bottom: 1px solid rgb(204, 204, 204); background-color: rgb(238, 238, 238);\">");
305 writer.indentPrintln(
306 "<b><a name=\"MessageStructures\"></a>All " + types.size() + " Message Structures in Alphabetical Order</b>");
307 writer.indentPrintln(
308 "</div><div class=\"panelContent\" style=\"background-color: rgb(255, 255, 255);\">");
309 writer.indentPrintln("<ul>");
310 for (XmlType type : types) {
311 this.writeLink(type);
312 }
313 writer.indentPrintln("</ul>");
314 writer.indentPrintln("</div>");
315 writer.indentPrintln("</div>");
316 }
317 }