KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > test > xml > XMLTestReportProcessor


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.test.xml;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.BufferedInputStream JavaDoc;
26 import java.io.BufferedOutputStream JavaDoc;
27 import java.io.FileWriter JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.PrintWriter JavaDoc;
30 import java.io.StringWriter JavaDoc;
31 import java.io.Writer JavaDoc;
32
33 import java.net.URL JavaDoc;
34
35 import java.util.Calendar JavaDoc;
36
37 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
38 import javax.xml.parsers.DocumentBuilder JavaDoc;
39
40 import org.apache.batik.test.TestReport;
41 import org.apache.batik.test.TestReportProcessor;
42 import org.apache.batik.test.TestSuite;
43 import org.apache.batik.test.TestException;
44
45 import org.apache.batik.util.XMLConstants;
46
47 import org.w3c.dom.Attr JavaDoc;
48 import org.w3c.dom.Document JavaDoc;
49 import org.w3c.dom.Element JavaDoc;
50 import org.w3c.dom.NamedNodeMap JavaDoc;
51 import org.w3c.dom.Node JavaDoc;
52 import org.w3c.dom.NodeList JavaDoc;
53 import org.w3c.dom.DOMImplementation JavaDoc;
54
55 /**
56  * This implementation of the <tt>TestReportProcessor</tt> interface
57  * converts the <tt>TestReports</tt> it processes into an
58  * XML document that it outputs in a directory. The directory
59  * used by the object can be configured at creation time.
60  * <br />
61  * The <tt>XMLTestReportProcessor</tt> can optionally notify a
62  * report consumer of the XML file it created.
63  *
64  * @author <a HREF="mailto:vhardy@apache.org">Vincent Hardy</a>
65  * @version $Id: XMLTestReportProcessor.java,v 1.19 2004/08/18 07:17:06 vhardy Exp $
66  */

67 public class XMLTestReportProcessor
68     implements TestReportProcessor,
69                XTRConstants, XMLConstants {
70     /**
71      * An <tt>XMLReportConsumer</tt> is notified every time a
72      * new report is generated by an <tt>XMLTestReportProcessor</tt>
73      */

74     public static interface XMLReportConsumer {
75         /**
76          * Invoked when new report has been generated.
77          * @param xmlReport file containing the xml report
78          * @param reportDirectory base directory where any resource relative
79          * to the report processing should be stored.
80          */

81         public void onNewReport(File JavaDoc xmlReport,
82                                 File JavaDoc reportDirectory) throws Exception JavaDoc ;
83     }
84
85     /**
86      * Error message if report directory does not exist.
87      */

88     public static final String JavaDoc ERROR_REPORT_DIRECTORY_UNUSABLE
89         = "xml.XMLTestReportProcessor.error.report.directory.unusable";
90                                  
91     /**
92      * Error message if report resources directory does not exist.
93      */

94     public static final String JavaDoc ERROR_REPORT_RESOURCES_DIRECTORY_UNUSABLE
95         = "xml.XMLTestReportProcessor.error.report.resources.directory.unusable";
96
97     /**
98      * Default report directory
99      */

100     public static final String JavaDoc XML_TEST_REPORT_DEFAULT_DIRECTORY
101         = Messages.formatMessage("XMLTestReportProcessor.config.xml.test.report.default.directory", null);
102
103     /**
104      * Directory where the XML report is created
105      */

106     public static final String JavaDoc XML_REPORT_DIRECTORY
107         = Messages.formatMessage("XMLTestReportProcessor.xml.report.directory", null);
108
109     /**
110      * Directory where resources (e.g., images) referenced by the
111      * XML report are copied.
112      */

113     public static final String JavaDoc XML_RESOURCES_DIRECTORY
114         = Messages.formatMessage("XMLTestReportProcessor.xml.resources.directory", null);
115
116     /**
117      * Test report name
118      */

119     public static final String JavaDoc XML_TEST_REPORT_NAME
120         = Messages.formatMessage("XMLTestReportProcessor.config.xml.test.report.name", null);
121
122     /**
123      * The XMLReportConsumer instance is notified whenever
124      * this object generates a new report.
125      */

126     protected XMLReportConsumer consumer;
127
128     /**
129      * String encoding the date the report was generated.
130      */

131     protected String JavaDoc reportDate;
132
133     /**
134      * Directory into which this processor puts all files and resources.
135      */

136     protected File JavaDoc reportDirectory;
137
138     /**
139      * Directory into which XML files are created
140      */

141     protected File JavaDoc xmlDirectory;
142
143     /**
144      * Directory into whichr resources refered to by XML files are created
145      */

146     protected File JavaDoc xmlResourcesDirectory;
147
148     /**
149      * Default constructor
150      */

151     public XMLTestReportProcessor(){
152     }
153
154     /**
155      * @param reportConsumer consumer for the XML report generated
156      * by this object. May be null.
157      */

158     public XMLTestReportProcessor(XMLTestReportProcessor.XMLReportConsumer consumer){
159         this.consumer = consumer;
160     }
161
162     /**
163      * Recursively processes the input <tt>TestReport</tt> and
164      * any of its children.
165      */

166     public void processReport(TestReport report)
167         throws TestException {
168
169         /**
170          * First, create the directories for the
171          * report and report resources
172          */

173         initializeReportDirectories();
174         
175         try {
176             
177             /**
178              * Create a new document and build the root
179              * <testReport> element. Then, process the
180              * TestReports recursively.
181              */

182             DocumentBuilder JavaDoc docBuilder
183                 = DocumentBuilderFactory.newInstance().newDocumentBuilder();
184             DOMImplementation JavaDoc impl
185                 = docBuilder.getDOMImplementation();
186             
187             Document JavaDoc document = null;
188
189             if(report.getTest() instanceof TestSuite){
190                 document = impl.createDocument(XTR_NAMESPACE_URI,
191                                                XTR_TEST_SUITE_REPORT_TAG, null);
192             }
193             else {
194                 document = impl.createDocument(XTR_NAMESPACE_URI,
195                                                XTR_TEST_REPORT_TAG, null);
196             }
197
198             Element JavaDoc root = document.getDocumentElement();
199             
200             root.setAttribute(XTR_DATE_ATTRIBUTE,
201                                 reportDate);
202
203             processReport(report, root, document);
204             
205             File JavaDoc xmlReport = serializeReport(root);
206
207             if(consumer != null){
208                 consumer.onNewReport(xmlReport, getReportDirectory());
209             }
210
211         } catch(Exception JavaDoc e) {
212             StringWriter JavaDoc sw = new StringWriter JavaDoc();
213             PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
214             e.printStackTrace(pw);
215             throw new TestException(INTERNAL_ERROR,
216                                     new Object JavaDoc[] { e.getClass().getName(),
217                                                    e.getMessage(),
218                                                    sw.toString() },
219                                     e);
220         }
221     }
222
223     /**
224      * Checks that the input File represents a directory that
225      * can be used. If the directory does not exist, this method
226      * will attempt to create it.
227      */

228     public void checkDirectory(File JavaDoc dir,
229                                String JavaDoc errorCode)
230         throws TestException {
231         boolean dirOK = false;
232         try{
233             if(!dir.exists()){
234                 dirOK = dir.mkdir();
235             }
236             else if(dir.isDirectory()){
237                 dirOK = true;
238             }
239         }finally{
240             if(!dirOK){
241                 throw new TestException(errorCode,
242                                         new Object JavaDoc[] {dir.getAbsolutePath()},
243                                         null);
244                 
245             }
246         }
247     }
248
249     /**
250      * By default, the report directory is given by a configuration
251      * variable. Each test run will create a sub directory with
252      * the current date and time as the same. All the resources
253      * created by the report processor are then put into that
254      * "dated" directory.
255      */

256     public void initializeReportDirectories() throws TestException {
257         //
258
// Base report directory
259
//
260
File JavaDoc baseReportDir = new File JavaDoc(XML_TEST_REPORT_DEFAULT_DIRECTORY);
261         checkDirectory(baseReportDir, ERROR_REPORT_DIRECTORY_UNUSABLE);
262         
263         //
264
// Create sub-directory name based on date and time
265
//
266
Calendar JavaDoc c = Calendar.getInstance();
267         String JavaDoc dirName = "" + c.get(Calendar.YEAR) + "."
268             + makeTwoDigits (c.get(Calendar.MONTH)+1) + "."
269             + makeTwoDigits (c.get(Calendar.DAY_OF_MONTH)) + "-"
270             + makeTwoDigits (c.get(Calendar.HOUR_OF_DAY)) + "h"
271             + makeTwoDigits (c.get(Calendar.MINUTE)) + "m"
272             + makeTwoDigits (c.get(Calendar.SECOND)) + "s";
273         
274         reportDate = dirName;
275         reportDirectory = new File JavaDoc(baseReportDir, dirName);
276         checkDirectory(reportDirectory, ERROR_REPORT_DIRECTORY_UNUSABLE);
277
278         //
279
// Now, create a sub-directory for XML files and
280
// anotherone for resources
281
//
282
xmlDirectory = new File JavaDoc(reportDirectory, XML_REPORT_DIRECTORY);
283         checkDirectory(xmlDirectory, ERROR_REPORT_DIRECTORY_UNUSABLE);
284
285         xmlResourcesDirectory = new File JavaDoc(xmlDirectory, XML_RESOURCES_DIRECTORY);
286         checkDirectory(xmlResourcesDirectory, ERROR_REPORT_DIRECTORY_UNUSABLE);
287     }
288
289     /**
290      * Forces a two digit string
291      */

292     protected String JavaDoc makeTwoDigits(int i){
293         if(i > 9){
294             return "" + i;
295         }
296         else{
297             return "0" + i;
298         }
299     }
300
301     /**
302      * Returns the report directory
303      */

304     public File JavaDoc getReportDirectory(){
305         return reportDirectory;
306     }
307
308     /**
309      * By default, the report resources directory is
310      * given by a configuration variable.
311      */

312     public File JavaDoc getReportResourcesDirectory() {
313         return xmlResourcesDirectory;
314     }
315
316     /**
317      * Recursively processes the input <tt>TestReport</tt> adding
318      * the report information to the input element.
319      */

320     protected void processReport(TestReport report,
321                                  Element JavaDoc reportElement,
322                                  Document JavaDoc reportDocument) throws IOException JavaDoc {
323         if(report == null){
324             throw new IllegalArgumentException JavaDoc();
325         }
326
327         reportElement.setAttribute(XTR_TEST_NAME_ATTRIBUTE,
328                                    report.getTest().getName());
329
330         String JavaDoc id = report.getTest().getQualifiedId();
331         if( !"".equals(id) ){
332             reportElement.setAttribute(XTR_ID_ATTRIBUTE,
333                                        id
334                                        );
335         }
336
337         String JavaDoc status = report.hasPassed()
338             ? XTR_PASSED_VALUE
339             : XTR_FAILED_VALUE;
340         
341         reportElement.setAttribute(XTR_STATUS_ATTRIBUTE,
342                                    status);
343
344         String JavaDoc className = report.getTest().getClass().getName();
345
346         reportElement.setAttribute(XTR_CLASS_ATTRIBUTE,
347                                    className);
348
349         if(!report.hasPassed()){
350             reportElement.setAttribute(XTR_ERROR_CODE_ATTRIBUTE,
351                                        report.getErrorCode());
352         }
353         
354         TestReport.Entry[] entries = report.getDescription();
355         int n = entries != null ? entries.length : 0;
356
357         if (n>0) {
358             Element JavaDoc descriptionElement
359                 = reportDocument.createElementNS(null,
360                                                  XTR_DESCRIPTION_TAG);
361             
362             reportElement.appendChild(descriptionElement);
363
364             for(int i=0; i<n; i++){
365                 processEntry(entries[i],
366                              descriptionElement,
367                              reportDocument);
368
369             }
370         }
371     }
372
373     protected void processEntry(TestReport.Entry entry,
374                                 Element JavaDoc descriptionElement,
375                                 Document JavaDoc reportDocument) throws IOException JavaDoc {
376
377         Object JavaDoc value = entry.getValue();
378         String JavaDoc key = entry.getKey();
379
380         if(value instanceof TestReport){
381             TestReport report = (TestReport)value;
382             
383             Element JavaDoc reportElement = null;
384
385             if(report.getTest() instanceof TestSuite){
386                 reportElement
387                     = reportDocument.createElementNS(XTR_NAMESPACE_URI,
388                                                      XTR_TEST_SUITE_REPORT_TAG);
389             }
390             else{
391                 reportElement
392                     = reportDocument.createElementNS(XTR_NAMESPACE_URI,
393                                                      XTR_TEST_REPORT_TAG);
394             }
395
396             descriptionElement.appendChild(reportElement);
397             processReport((TestReport)entry.getValue(),
398                           reportElement,
399                           reportDocument);
400         }
401         else if(value instanceof URL JavaDoc){
402             Element JavaDoc entryElement
403                 = reportDocument.createElementNS(XTR_NAMESPACE_URI,
404                                                  XTR_URI_ENTRY_TAG);
405
406             descriptionElement.appendChild(entryElement);
407             
408             entryElement.setAttribute(XTR_KEY_ATTRIBUTE,
409                                       key.toString());
410             
411             entryElement.setAttribute(XTR_VALUE_ATTRIBUTE,
412                                       value.toString());
413
414         }
415         else if(value instanceof File JavaDoc){
416             //
417
// The entry is a potentially temporary File. Copy
418
// the file to the repository and create a file entry
419
// referencing that file copy.
420
//
421
File JavaDoc tmpFile = (File JavaDoc)value;
422
423             File JavaDoc tmpFileCopy = createResourceFileForName(tmpFile.getName());
424
425             copy(tmpFile, tmpFileCopy);
426
427             Element JavaDoc entryElement
428                 = reportDocument.createElementNS(XTR_NAMESPACE_URI,
429                                                  XTR_FILE_ENTRY_TAG);
430
431             descriptionElement.appendChild(entryElement);
432             
433             entryElement.setAttribute(XTR_KEY_ATTRIBUTE,
434                                       key.toString());
435             
436             entryElement.setAttribute(XTR_VALUE_ATTRIBUTE,
437                                       tmpFileCopy.toURL().toString());
438
439         }
440         else {
441            
442             Element JavaDoc entryElement
443                 = reportDocument.createElementNS(XTR_NAMESPACE_URI,
444                                                  XTR_GENERIC_ENTRY_TAG);
445
446             descriptionElement.appendChild(entryElement);
447             
448             entryElement.setAttribute(XTR_KEY_ATTRIBUTE,
449                                       key.toString());
450             
451             Attr JavaDoc a = reportDocument.createAttribute(XTR_VALUE_ATTRIBUTE);
452             a.setValue(value!=null?value.toString():"null");
453             entryElement.setAttributeNode(a);
454         }
455     }
456
457     /**
458      * Untility method. Creates a file in the resources directory
459      * for the given name. If a file in that directory does not
460      * exist yet, then it is used. Otherwise, a file with the same
461      * name with a digit suffix is created. For example, if "myFile.png"
462      * is requested, then "myFile.png" is created or "myFile<n>.png"
463      * where <n> will be one or several digits.
464      */

465     protected File JavaDoc createResourceFileForName(String JavaDoc fileName){
466         File JavaDoc r = new File JavaDoc(xmlResourcesDirectory, fileName);
467         if(!r.exists()){
468             return r;
469         }
470         else{
471             return createResourceFileForName(fileName, 1);
472         }
473     }
474
475     protected File JavaDoc createResourceFileForName(String JavaDoc fileName,
476                                              int instance){
477         // First, create a 'versioned' file name
478
int n = fileName.lastIndexOf('.');
479         String JavaDoc iFileName = fileName + instance;
480         if(n != -1){
481             iFileName = fileName.substring(0, n) + instance
482                 + fileName.substring(n, fileName.length());
483         }
484
485         File JavaDoc r = new File JavaDoc(xmlResourcesDirectory, iFileName);
486         if(!r.exists()){
487             return r;
488         }
489         else{
490             return createResourceFileForName(fileName,
491                                              instance + 1);
492         }
493     }
494
495     /**
496      * Utility method. Copies in to out
497      */

498     protected void copy(File JavaDoc in, File JavaDoc out) throws IOException JavaDoc {
499         InputStream JavaDoc is = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(in));
500         OutputStream JavaDoc os = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(out));
501         
502         final byte[] b = new byte[1024];
503         int n = -1;
504         while( (n = is.read(b)) != -1 ){
505             os.write(b, 0, n);
506         }
507         
508         is.close();
509         os.close();
510     }
511
512     /**
513      * Saves the XML document into a file
514      */

515     protected File JavaDoc serializeReport(Element JavaDoc reportElement) throws IOException JavaDoc {
516         //
517
// First, create a new File
518
//
519
File JavaDoc reportFile = new File JavaDoc(xmlDirectory,
520                                    XML_TEST_REPORT_NAME);
521
522         FileWriter JavaDoc fw = new FileWriter JavaDoc(reportFile);
523
524         serializeElement(reportElement,
525                          "",
526                          fw);
527
528         fw.close();
529
530         return reportFile;
531     }
532
533     
534     static private String JavaDoc EOL;
535
536     static private String JavaDoc PROPERTY_LINE_SEPARATOR = "line.separator";
537     static private String JavaDoc PROPERTY_LINE_SEPARATOR_DEFAULT = "\n";
538     static {
539         String JavaDoc temp;
540         try {
541             temp = System.getProperty (PROPERTY_LINE_SEPARATOR,
542                                        PROPERTY_LINE_SEPARATOR_DEFAULT);
543         } catch (SecurityException JavaDoc e) {
544             temp = PROPERTY_LINE_SEPARATOR_DEFAULT;
545         }
546         EOL = temp;
547     }
548
549     protected void serializeElement(Element JavaDoc element,
550                                     String JavaDoc prefix,
551                                     Writer JavaDoc writer) throws IOException JavaDoc {
552         writer.write(prefix);
553         writer.write(XML_OPEN_TAG_START);
554         writer.write(element.getTagName());
555         
556         serializeAttributes(element,
557                             writer);
558         
559         NodeList JavaDoc children = element.getChildNodes();
560         if(children != null && children.getLength() > 0){
561             writer.write(XML_OPEN_TAG_END_CHILDREN);
562             writer.write(EOL);
563             int n = children.getLength();
564             for(int i=0; i<n; i++){
565                 Node JavaDoc child = children.item(i);
566                 if(child.getNodeType() == Node.ELEMENT_NODE){
567                     serializeElement((Element JavaDoc)child,
568                                      prefix + XML_TAB,
569                                      writer);
570                 }
571             }
572             writer.write(prefix);
573             writer.write(XML_CLOSE_TAG_START);
574             writer.write(element.getTagName());
575             writer.write(XML_CLOSE_TAG_END);
576         }
577         else{
578             writer.write(XML_OPEN_TAG_END_NO_CHILDREN);
579         }
580
581         writer.write(EOL);
582
583     }
584
585     protected void serializeAttributes(Element JavaDoc element,
586                                        Writer JavaDoc writer) throws IOException JavaDoc{
587         NamedNodeMap JavaDoc attributes = element.getAttributes();
588         if (attributes != null){
589             int nAttr = attributes.getLength();
590             for(int i=0; i<nAttr; i++){
591                 Attr JavaDoc attr = (Attr JavaDoc)attributes.item(i);
592                 writer.write(XML_SPACE);
593                 writer.write(attr.getName());
594                 writer.write(XML_EQUAL_SIGN);
595                 writer.write(XML_DOUBLE_QUOTE);
596                 writer.write(encode(attr.getValue()));
597                 writer.write(XML_DOUBLE_QUOTE);
598             }
599         }
600     }
601
602     /**
603      * Poor way of replacing '<', '>', '"', '&' and '''
604      * in attribute values.
605      */

606     protected String JavaDoc encode(String JavaDoc attrValue){
607         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(attrValue);
608         replace(sb, XML_CHAR_AMP, XML_ENTITY_AMP);
609         replace(sb, XML_CHAR_LT, XML_ENTITY_LT);
610         replace(sb, XML_CHAR_GT, XML_ENTITY_GT);
611         replace(sb, XML_CHAR_QUOT, XML_ENTITY_QUOT);
612         replace(sb, XML_CHAR_APOS, XML_ENTITY_APOS);
613         return sb.toString();
614     }
615
616     protected void replace(StringBuffer JavaDoc s,
617                              char c,
618                              String JavaDoc r){
619         String JavaDoc v = s.toString() + 1;
620         int i = v.length();
621
622         while( (i=v.lastIndexOf(c, --i)) != -1 ){
623             s.deleteCharAt(i);
624             s.insert(i, r);
625         }
626     }
627 }
628
Popular Tags