1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.datadictionary.mojo;
17
18 import java.io.File;
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.OutputStream;
22 import java.io.PrintStream;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.net.URLClassLoader;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.LinkedHashMap;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33
34 import org.apache.maven.artifact.DependencyResolutionRequiredException;
35 import org.apache.maven.plugin.AbstractMojo;
36 import org.apache.maven.plugin.MojoExecutionException;
37 import org.apache.maven.project.MavenProject;
38 import org.joda.time.DateTime;
39 import org.kuali.student.contract.model.MessageStructure;
40 import org.kuali.student.contract.model.ServiceContractModel;
41 import org.kuali.student.contract.model.impl.ServiceContractModelCache;
42 import org.kuali.student.contract.model.impl.ServiceContractModelQDoxLoader;
43 import org.kuali.student.contract.model.util.DateUtility;
44 import org.kuali.student.contract.model.util.VersionLinesUtility;
45 import org.kuali.student.contract.model.validation.ServiceContractModelValidator;
46 import org.kuali.student.datadictionary.util.DictionaryFormatter;
47 import org.kuali.student.datadictionary.util.DictionaryTesterHelper;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public class KSDictionaryDocMojo extends AbstractMojo {
85
86 private static final Logger log = LoggerFactory.getLogger(KSDictionaryDocMojo.class);
87
88
89
90
91
92
93 private MavenProject project;
94
95
96
97
98 private List<String> sourceDirs;
99
100
101
102
103
104 private List<String> supportFiles = new ArrayList<String>();
105
106
107
108 private File htmlDirectory;
109
110 private String testDictionaryFile;
111
112 private LinkedHashMap<String, String> dictionaryFileToMessageStructureMap = new LinkedHashMap<String, String>();
113
114
115 public List<String> getSourceDirs() {
116 return sourceDirs;
117 }
118
119 public void setSourceDirs(List<String> sourceDirs) {
120 this.sourceDirs = sourceDirs;
121 }
122
123 public void setHtmlDirectory(File htmlDirectory) {
124 this.htmlDirectory = htmlDirectory;
125 }
126
127 public File getHtmlDirectory() {
128 return htmlDirectory;
129 }
130
131 public MavenProject getProject() {
132 return project;
133 }
134
135 public List<String> getSupportFiles() {
136 return supportFiles;
137 }
138
139 public void setSupportFiles(List<String> supportFiles) {
140 this.supportFiles.clear();
141
142 if (supportFiles != null)
143 this.supportFiles.addAll(supportFiles);
144 }
145
146 private ServiceContractModel getModel() {
147 ServiceContractModel instance = new ServiceContractModelQDoxLoader(
148 sourceDirs);
149 return new ServiceContractModelCache(instance);
150 }
151
152 private boolean validate(ServiceContractModel model) {
153 Collection<String> errors = new ServiceContractModelValidator(model).validate();
154 if (errors.size() > 0) {
155 StringBuilder buf = new StringBuilder();
156 buf.append(errors.size()).append(" errors found while validating the data.");
157 return false;
158 }
159 return true;
160 }
161
162 @Override
163 public void execute()
164 throws MojoExecutionException {
165 this.getLog().info("generating dictionary documentation");
166
167 if (getPluginContext() != null) {
168 project = (MavenProject) getPluginContext().get("project");
169 }
170
171
172
173
174 if (project != null) {
175 this.getLog().info("adding current project's classpath to plugin class loader");
176 List<String> runtimeClasspathElements;
177 try {
178 runtimeClasspathElements = project.getRuntimeClasspathElements();
179 } catch (DependencyResolutionRequiredException ex) {
180 throw new MojoExecutionException("Failed to get runtime classpath elements.", ex);
181 }
182 URL[] runtimeUrls = new URL[runtimeClasspathElements.size()];
183 for (int i = 0; i < runtimeClasspathElements.size(); i++) {
184 String element = (String) runtimeClasspathElements.get(i);
185 try {
186 runtimeUrls[i] = new File(element).toURI().toURL();
187 } catch (MalformedURLException ex) {
188 throw new MojoExecutionException(element, ex);
189 }
190 }
191 URLClassLoader newLoader = new URLClassLoader(runtimeUrls,
192 Thread.currentThread().getContextClassLoader());
193 Thread.currentThread().setContextClassLoader(newLoader);
194 }
195
196
197 if (!htmlDirectory.exists()) {
198 if (!htmlDirectory.mkdirs()) {
199 throw new IllegalArgumentException("Could not create directory "
200 + this.htmlDirectory.getPath());
201 }
202 }
203
204 Set<String> inpFiles = new LinkedHashSet<String>();
205 if (project != null) {
206 ServiceContractModel model = this.getModel();
207 this.validate(model);
208 inpFiles.addAll(extractDictionaryFiles(model));
209
210 }
211 else {
212 inpFiles.add(this.testDictionaryFile);
213 }
214
215
216 String outputDir = this.htmlDirectory.getAbsolutePath();
217 DictionaryTesterHelper tester = new DictionaryTesterHelper(outputDir, inpFiles, this.supportFiles);
218 tester.doTest(project.getVersion(), DateUtility.asYMDHMInEasternTimeZone(new DateTime()));
219
220
221 String indexFileName = this.htmlDirectory.getPath() + "/" + "index.html";
222 File indexFile = new File(indexFileName);
223 OutputStream outputStream;
224 try {
225 outputStream = new FileOutputStream(indexFile, false);
226 } catch (FileNotFoundException ex) {
227
228 throw new IllegalArgumentException(indexFileName, ex);
229 }
230
231 String formattedDate = DateUtility.asYMDHMInEasternTimeZone(new DateTime());
232
233 PrintStream out = new PrintStream(outputStream);
234
235 DictionaryFormatter.writeHeader(out, "Data Dictionary Index");
236
237 VersionLinesUtility.writeVersionTag(out, "<a href=\"index.html\">Home</a>", "<a href=\"../contractdocs/index.html\">Contract Docs Home</a>", project.getVersion(), formattedDate);
238
239 out.println("<h1>Data Dictionary Index</h1>");
240 out.println("<blockquote>A Red background indicates that there is a problem with the data dictionary for that type.</blockquote>");
241 out.println("<ul>");
242
243 Map<String, List<String>> fileToBeanNameMap = tester.getInputFileToBeanNameMap();
244
245 for (String inputFile : fileToBeanNameMap.keySet()) {
246
247 boolean containsError = false;
248
249 if (tester.getInvalidDictionaryFiles().contains(inputFile)) {
250 containsError = true;
251 }
252
253 List<String> beanIds = fileToBeanNameMap.get(inputFile);
254
255 for (String beanId : beanIds) {
256
257 String outputFileName = beanId + ".html";
258
259 if (containsError)
260 out.println ("<li class=\"invalid\">");
261 else
262 out.println ("<li>");
263
264 out.println("<a href=\"" + outputFileName + "\">" + beanId
265 + "</a>");
266 }
267 }
268 out.println("</ul>");
269
270
271
272 if (tester.getMissingDictionaryFiles().size() > 0) {
273 out.println("<h1>Missing Dictionary Files</h1>");
274 out.println("<blockquote>The Message structure exists but there is no dictionary file present.</blockquote>");
275 out.println("<ul>");
276 for (String missingFile : tester.getMissingDictionaryFiles()) {
277 out.println("<li><b>" + missingFile + "</b></li>");
278 }
279 out.println("</ul>");
280
281 }
282
283 DictionaryFormatter.writeFooter(out);
284 out.close();
285
286 log.info("finished generating dictionary documentation");
287 }
288
289 private Collection<String> extractDictionaryFiles(
290 ServiceContractModel model) {
291
292 Set<String> dictionaryFiles = new LinkedHashSet<String>();
293
294 List<MessageStructure> ms = model.getMessageStructures();
295
296 for (MessageStructure messageStructure : ms) {
297
298 String inputFileName = "ks-" + messageStructure.getXmlObject() + "-dictionary.xml";
299
300 dictionaryFiles.add(inputFileName);
301
302
303 dictionaryFileToMessageStructureMap.put(inputFileName, messageStructure.getXmlObject());
304
305 }
306
307
308 return dictionaryFiles;
309 }
310
311
312
313
314
315 public void setTestDictionaryFile(String dictionaryFile) {
316 this.testDictionaryFile = dictionaryFile;
317
318 }
319 }