1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 package net.sourceforge.xuse.build;
111
112 import java.io.File;
113 import java.io.FileInputStream;
114 import java.io.FileNotFoundException;
115 import java.io.FileWriter;
116 import java.io.IOException;
117 import java.io.InputStream;
118 import java.io.Reader;
119 import java.io.StringReader;
120 import java.util.Arrays;
121 import java.util.HashMap;
122 import java.util.Iterator;
123 import java.util.List;
124 import java.util.Map;
125 import java.util.Map.Entry;
126
127 import javax.xml.parsers.SAXParserFactory;
128 import javax.xml.transform.Transformer;
129 import javax.xml.transform.TransformerException;
130 import javax.xml.transform.TransformerFactory;
131 import javax.xml.transform.URIResolver;
132 import javax.xml.transform.stream.StreamResult;
133 import javax.xml.transform.stream.StreamSource;
134
135 import net.sf.saxon.Controller;
136 import net.sf.saxon.FeatureKeys;
137 import net.sourceforge.xuse.log.Logger;
138 import net.sourceforge.xuse.utils.CommandLineWrapper;
139 import net.sourceforge.xuse.utils.Utils;
140 import net.sourceforge.xuse.utils.XuseUtils;
141
142 import com.xmlsolutions.annotation.Requirement;
143
144
145 public class StylesheetInvoker {
146
147 private static final TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl();
148 private static final SAXParserFactory saxFactory = SAXParserFactory.newInstance();
149 private static final URIResolver uriResolver = transformerFactory.getURIResolver();
150 private static final boolean DO_GRAPHS = CommandLineWrapper.graphVizAvailable();
151 private static final String PERF_XML_OUT_BASE = "target/performance/";
152
153 private static final StylesheetInvoker INSTANCE = new StylesheetInvoker();
154
155 protected StylesheetInvoker() {
156 Logger.debug(StylesheetInvoker.class, "Using TransformerFactory: " + transformerFactory.getClass().getCanonicalName());
157 Logger.debug(StylesheetInvoker.class, "Using SAXParserFactory: " + saxFactory.getClass().getCanonicalName());
158 Logger.debug(StylesheetInvoker.class, "Using URI Resolver: " + uriResolver.getClass().getCanonicalName());
159 try {
160 saxFactory.setFeature("http://xml.org/sax/features/validation", false);
161 transformerFactory.setAttribute(FeatureKeys.DTD_VALIDATION, false);
162
163 if (XusePropertiesReader.doPerformanceAnalysis()) {
164 transformerFactory.setAttribute(FeatureKeys.LINE_NUMBERING,Boolean.TRUE);
165 }
166
167 try {
168 transformerFactory.setAttribute(FeatureKeys.XINCLUDE, true);
169
170 transformerFactory.newTransformer(new StreamSource(ClassLoader.getSystemResourceAsStream("xslts/utils/core-utils.xsl")));
171 } catch (Throwable t) {
172 Logger.warn(StylesheetInvoker.class, "It seems that your parser (" + saxFactory.getClass().getCanonicalName() + ") does not support XInclude directives so these will not be processed");
173
174 transformerFactory.setAttribute(FeatureKeys.XINCLUDE, false);
175 }
176 File perfDir = new File(PERF_XML_OUT_BASE);
177 if (!perfDir.exists()) {
178 perfDir.mkdirs();
179 }
180 } catch (Throwable t) {
181 Logger.error(this, "Could not initialise XML parser", t);
182 }
183 }
184
185 public static final StylesheetInvoker getInstance() {
186 return INSTANCE;
187 }
188
189 public void invokeXslForString(String xmlString, String output, String xslFile, String templateName, Map args) throws BuildException {
190 try {
191 Reader source = new StringReader(xmlString);
192 StreamSource xmlSource = new StreamSource(source);
193 this.invokeXslForStreamSource(xmlSource, output, xslFile, templateName, args);
194 } catch (Throwable t) {
195 throw new BuildException("Error transforming xml with " + xslFile + "\nto output : " + output + "\nerror was: "+ t.getLocalizedMessage(), t);
196 }
197 }
198
199 private void invokeXslForStreamSource(StreamSource xmlSource, String output, String xslFile, String templateName, Map args) throws TransformerException {
200
201 StreamSource xsl = getXsl(xslFile);
202 Transformer transformer = this.initTransformer(xsl, args);
203 if(templateName != null && templateName.trim().length() > 0) {
204
205 ((Controller)transformer).setInitialTemplate(templateName);
206 }
207 File outFile = new File(output);
208 StreamResult tempResult = new StreamResult(outFile.toURI().toString());
209 tempResult.setSystemId(outFile.toURI().toString());
210 transformer.transform(xmlSource, tempResult);
211
212 }
213
214 public void invokeXsl(String input, String output, String xslFile, String templateName, Map args) throws BuildException {
215 Logger.debug(this, "Applying transform: " + xslFile + " to " + input + " writing " + output + " usings args (" + args + ")");
216 try {
217 StreamSource xmlSource = null;
218 if (input != null) {
219
220 File srcXML = new File(input);
221 if (!srcXML.exists()) {
222
223 srcXML = new File(new File("."), input);
224 if (!srcXML.exists()) {
225 Logger.warn(this, "Cannot find: " + srcXML.getAbsolutePath());
226 }
227 }
228 InputStream source = new FileInputStream(srcXML);
229 xmlSource = new StreamSource(source);
230 xmlSource.setSystemId(srcXML.getAbsolutePath());
231 }
232 this.invokeXslForStreamSource(xmlSource, output, xslFile, templateName, args);
233 } catch (Throwable t) {
234 throw new BuildException("Error transforming " + input + "\nwith " + xslFile + "\nto output : " + output + "\nerror was: "+ t.getLocalizedMessage(), t);
235 }
236 }
237
238 public void invokeXsl(StreamSource source, StreamResult result, String xslFile, String templateName, Map args) throws BuildException {
239 try {
240
241 StreamSource xsl = getXsl(xslFile);
242 Transformer transformer = this.initTransformer(xsl, args);
243 if(templateName != null && templateName.trim().length() > 0) {
244
245 ((Controller)transformer).setInitialTemplate(templateName);
246 }
247 transformer.transform(source, result);
248 } catch (Throwable t) {
249 throw new BuildException("Error transforming " + source.getSystemId() + "\nwith " + xslFile + "\nto output : " + result.getSystemId() + "\nerror was: "+ t.getLocalizedMessage(), t);
250 }
251 }
252
253 public void invokeXsl(String input, String output, String xslFile) throws BuildException {
254 this.invokeXsl(input, output, xslFile, null, null);
255 }
256
257 @Requirement(traceTo={"RQ58"})
258 public void invokePDFUseCases() throws BuildException {
259 if (XusePropertiesReader.doPerformanceAnalysis()) {
260
261 transformerFactory.setAttribute(FeatureKeys.TRACE_LISTENER,TraceListenerFactory.getInstance().getTraceListener(PERF_XML_OUT_BASE + "pdf-use-cases.xml"));
262 }
263 String xslID = XusePropertiesReader.getSitePdfXslController();
264 String sourceID = XusePropertiesReader.getRequirementsRepositoryFile();
265 this.invokeXsl(sourceID, "deleteme.xml", xslID, "do-use-cases", null);
266 }
267
268 @Requirement(traceTo={"RQ58"})
269 public void invokePDFSingleUseCase(String useCaseId) throws BuildException {
270 if (XusePropertiesReader.doPerformanceAnalysis()) {
271
272 transformerFactory.setAttribute(FeatureKeys.TRACE_LISTENER,TraceListenerFactory.getInstance().getTraceListener(PERF_XML_OUT_BASE + "pdf-use-case.xml"));
273 }
274 String xslID = XusePropertiesReader.getSitePdfXslController();
275 String sourceID = XusePropertiesReader.getRequirementsRepositoryFile();
276 Map<String, String> args = new HashMap<String, String>();
277 args.put("uc-id", useCaseId);
278 this.invokeXsl(sourceID, "deleteme.xml", xslID, "single-use-case", args);
279 }
280
281 public void invokeImportTraceReport() throws BuildException {
282 String xslID = "xslts/data-imports/import-trace-report.xsl";
283 String sourceID = XusePropertiesReader.getTraceReportInput();
284 String upgradedRepositoryFileName = XusePropertiesReader.getTraceReportOutput();
285 Logger.info(INSTANCE, "Importing traces from " + sourceID + ", wrting result " + upgradedRepositoryFileName);
286 this.invokeXsl(sourceID, upgradedRepositoryFileName, xslID, null, null);
287 }
288
289 public void invokeBuildHTMLSite() throws BuildException {
290 if (XusePropertiesReader.doPerformanceAnalysis()) {
291
292 transformerFactory.setAttribute(FeatureKeys.TRACE_LISTENER,TraceListenerFactory.getInstance().getTraceListener(PERF_XML_OUT_BASE + "html.xml"));
293 }
294 String xslID = XusePropertiesReader.getSiteXslController();
295 String sourceID = XusePropertiesReader.getRequirementsRepositoryFile();
296 this.invokeXsl(sourceID, "deleteme.xml", xslID, "main", null);
297 }
298
299 public void processPerformanceResults() throws BuildException {
300 if (XusePropertiesReader.doPerformanceAnalysis()) {
301 Logger.info(this, "Plotting performance results...");
302 try {
303
304
305
306
307
308 TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl();
309 Transformer transformer = factory.newTransformer(getXsl("timing-profile.xsl"));
310 List<File> performanceXMLFiles = Arrays.asList(new File(PERF_XML_OUT_BASE).listFiles());
311 File outDir = new File(XusePropertiesReader.getOutputDirectory() + "/performance");
312 if (!outDir.exists()) {
313 outDir.mkdirs();
314 }
315 for (File performanceXMLFile : performanceXMLFiles) {
316 Logger.debug(this, "Creating performance results for: " + performanceXMLFile.getAbsolutePath());
317 InputStream source = new FileInputStream(performanceXMLFile);
318 StreamSource xmlSource = new StreamSource(source);
319 xmlSource.setSystemId(performanceXMLFile.getAbsolutePath());
320 File outFile = new File(outDir, "performance-results-" + performanceXMLFile.getName().substring(0, performanceXMLFile.getName().lastIndexOf(".")) + ".html");
321 StreamResult result = new StreamResult(outFile.toURI().toString());
322 result.setSystemId(outFile.toURI().toString());
323 transformer.transform(xmlSource, result);
324 }
325 } catch (Throwable t) {
326 throw new BuildException("Error generating performance results", t);
327 }
328 }
329 }
330
331 @Requirement(traceTo={"RQ19", "RQ60"})
332 public void invokeBuildHTMLDocuments() throws BuildException {
333
334 List<String> allDocs = XuseUtils.getDocuments();
335 if (allDocs != null) {
336 for (String currentDoc : allDocs) {
337 File currentFile = new File(currentDoc);
338 if (currentFile.exists() && currentFile.isFile()) {
339 if (XusePropertiesReader.doPerformanceAnalysis()) {
340
341 String docSuffix = currentFile.getName().substring(0, currentFile.getName().lastIndexOf("."));
342 transformerFactory.setAttribute(FeatureKeys.TRACE_LISTENER, TraceListenerFactory.getInstance().getTraceListener(PERF_XML_OUT_BASE + "html-documents-" + docSuffix + ".xml"));
343 }
344 String xslID = XusePropertiesReader.getGenericDocumentXsl();
345 this.invokeXsl(currentDoc, XusePropertiesReader.getOutputDirectory() + "/deleteme.html", xslID, null, null);
346 File deleteMeHTML = new File(XusePropertiesReader.getOutputDirectory() + "/deleteme.html");
347 if (!deleteMeHTML.delete()) {
348 Logger.debug(this, "Could not delete temporary file " + deleteMeHTML.getAbsolutePath());
349 }
350 } else {
351 Logger.warn(this, "Location " + currentFile + " does not appear to be a valid file");
352 }
353 }
354 }
355 }
356
357 public void invokeGraphRequirement(String requirementId) throws BuildException {
358 String requirementsDoc = XusePropertiesReader.getRequirementsRepositoryFile();
359
360 String xsl = "xslts/graph/requirement-graph.xsl";
361 Map<String, String> args = new HashMap<String, String>();
362 args.put("req-id", requirementId);
363 String dotDir = XusePropertiesReader.getOutputDirectory();
364 String dotFile = "req-" + requirementId + ".dot";
365 String svgTempFile = XusePropertiesReader.getOutputDirectory() + "/req-" + requirementId + "-temp.svg";
366 String svgFile = XusePropertiesReader.getOutputDirectory() + "/req-" + requirementId + ".svg";
367 this.invokeXsl(requirementsDoc, dotFile, xsl, null, args);
368 FileWriter svgResultFile = null;
369 try {
370 String resultSvgRaw = CommandLineWrapper.executeGraphVizForSvg(dotDir, dotFile);
371 svgResultFile = new FileWriter(svgTempFile);
372 svgResultFile.append(resultSvgRaw);
373 this.invokeXslForString(resultSvgRaw, svgFile, "xslts/graph/prettying-graphviz.xsl", null, null);
374 } catch (IOException ioe) {
375 throw new BuildException("Could not create requirement graph", ioe);
376 } finally {
377 if (svgResultFile != null) {
378 try {
379 svgResultFile.close();
380 } catch (IOException e) {
381 throw new BuildException("Could not close SVG result file", e);
382 }
383 }
384 }
385 }
386
387 @Requirement(traceTo={"RQ48"})
388 public void invokeValidateProject() throws BuildException {
389 if (XusePropertiesReader.doPerformanceAnalysis()) {
390
391 transformerFactory.setAttribute(FeatureKeys.TRACE_LISTENER,TraceListenerFactory.getInstance().getTraceListener("validate.xml"));
392 }
393 String xslID = XusePropertiesReader.getSiteXslController();
394 String sourceID = XusePropertiesReader.getRequirementsRepositoryFile();
395 this.invokeXsl(sourceID, "deleteme.xml", xslID, "validate", null);
396 }
397
398 public void invokeUpgrade() throws BuildException {
399 String xslID = XusePropertiesReader.getUpgradeXslController();
400 String sourceID = XusePropertiesReader.getRequirementsRepositoryFile();
401 this.invokeXsl(sourceID, "deleteme.xml", xslID, "main", null);
402 }
403
404 public Transformer initTransformer(StreamSource xsl, Map<String, String> addtionalArgs) throws BuildException {
405
406 try {
407
408
409 Transformer transformer = transformerFactory.newTransformer(xsl);
410 File baseDir = new File(".");
411 transformer.setParameter("baseDir", baseDir.getAbsolutePath());
412 transformer.setParameter("theme", XusePropertiesReader.getHTMLTheme());
413 transformer.setParameter("useCaseFolder", XusePropertiesReader.getUseCaseDirectory());
414 transformer.setParameter("html-output-location", XusePropertiesReader.getOutputDirectory());
415 transformer.setParameter("dictionary", XusePropertiesReader.getDictionary());
416 transformer.setParameter("userDictionary", XusePropertiesReader.getUserDictionary());
417 transformer.setParameter("requirement-xml-file", XusePropertiesReader.getRequirementsRepositoryFile());
418 transformer.setParameter("actors-xml-file", XusePropertiesReader.getActors());
419 transformer.setParameter("stakeholders-xml-file", XusePropertiesReader.getStakeholders());
420 transformer.setParameter("glossary-xml-file", XusePropertiesReader.getGlossary());
421 transformer.setParameter("company", XusePropertiesReader.getCompanyName());
422 transformer.setParameter("project", XusePropertiesReader.getProjectName());
423 transformer.setParameter("customer", XusePropertiesReader.getCustomerName());
424 transformer.setParameter("company-logo", XusePropertiesReader.getCompanyLogo());
425 transformer.setParameter("project-logo", XusePropertiesReader.getProjectLogo());
426 transformer.setParameter("customer-logo", XusePropertiesReader.getCustomerLogo());
427 transformer.setParameter("req-nav-style", XusePropertiesReader.getRequirementNavigationViewStyle());
428 transformer.setParameter("req-list-style", XusePropertiesReader.getRequirementListStyle());
429
430 transformer.setParameter("graphviz-available", new Boolean(DO_GRAPHS));
431 transformer.setParameter("usecase-pkg-diag-html", new Boolean(XusePropertiesReader.graphUseCasePackageHTML()));
432 transformer.setParameter("usecase-pkg-diag-pdf", new Boolean(XusePropertiesReader.graphUseCasePackagePDF()));
433 transformer.setParameter("usecase-pkg-diag-splines", XusePropertiesReader.graphUseCasePackageSplines());
434 transformer.setParameter("usecase-pkg-diag-degrees", XusePropertiesReader.graphUseCasePackageDegrees());
435 transformer.setParameter("use-case-activity-html", new Boolean(XusePropertiesReader.graphUseCaseActivityDiagramsHTML()));
436 transformer.setParameter("use-case-activity-pdf", new Boolean(XusePropertiesReader.graphUseCaseActivityDiagramsPDF()));
437 transformer.setParameter("use-case-activity-splines", XusePropertiesReader.graphUseCaseActivityDiagramsSplines());
438
439 transformer.setParameter("min-log-level", XusePropertiesReader.getLogLevelAsStr());
440 transformer.setParameter("skip-model-validation", new Boolean(XusePropertiesReader.skipModelValidation()));
441 transformer.setParameter("store-model-memento", new Boolean(XusePropertiesReader.storeModelMemento()));
442 transformer.setParameter("skip-glossary-linking", new Boolean(XusePropertiesReader.skipGlossaryLinking()));
443
444
445 if (addtionalArgs != null && !addtionalArgs.isEmpty()) {
446 Iterator<Entry<String, String>> iter = addtionalArgs.entrySet().iterator();
447 Map.Entry<String,String> entry = null;
448 while (iter.hasNext()) {
449 entry = iter.next();
450 Logger.debug(this, "Adding parameter: " + entry.getKey() + "; " + entry.getValue());
451 transformer.setParameter((String)entry.getKey(), entry.getValue());
452 }
453 }
454 this.overrideTransforInitialisation(transformer);
455 return transformer;
456 } catch (Throwable t) {
457 t.printStackTrace();
458 throw new BuildException("Error initialising XSLT: " + t.getLocalizedMessage(), t);
459 }
460 }
461
462 protected void overrideTransforInitialisation(Transformer transformer) throws BuildException {
463
464 }
465
466 private StreamSource getXsl(String name) throws BuildException {
467
468
469 File xuseDir = new File(XusePropertiesReader.getXuseWorkingDir());
470 File file = new File(xuseDir, name);
471 StreamSource streamSource = null;
472 try {
473 if (!file.exists()) {
474 InputStream is = ClassLoader.getSystemResourceAsStream(name);
475 if (is != null) {
476 streamSource = new StreamSource(is);
477 } else {
478 throw new BuildException("Could not locate " + name + " in " + xuseDir.getAbsolutePath() + ", or in the classpath");
479 }
480 } else {
481 streamSource = new StreamSource(new FileInputStream(file));
482 streamSource.setSystemId(file.toURI().toString());
483 }
484 } catch (FileNotFoundException fnfe) {
485 throw new BuildException("Error finding the file - " + name + " - in the classpath.", fnfe);
486 }
487 return streamSource;
488 }
489
490
491
492 }