ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sbaill...@apache.org
Subject cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit AggregateTransformer.java
Date Tue, 07 Aug 2001 22:08:45 GMT
sbailliez    01/08/07 15:08:45

  Modified:    src/main/org/apache/tools/ant/taskdefs/optional/junit
                        AggregateTransformer.java
  Log:
  Huge summer cleanup to the code...
  - takes advantage of Xalan redirect extension, therefore I don't need extra code to split
the document several pieces and process them with different stylesheets.
  - now using a strategy to determine a valid Xalan executor at runtime. It first check for
Xalan2 then for Xalan1.
  As a convenience the Xalan version is displayed in the output.
  
  Revision  Changes    Path
  1.5       +142 -328  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
  
  Index: AggregateTransformer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- AggregateTransformer.java	2001/08/02 22:47:16	1.4
  +++ AggregateTransformer.java	2001/08/07 22:08:45	1.5
  @@ -56,17 +56,14 @@
   import org.apache.tools.ant.Task;
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.types.EnumeratedAttribute;
   
  -import java.io.File;
  -import java.io.FileInputStream;
  -import java.io.FileOutputStream;
  -import java.io.InputStream;
  -import java.io.OutputStream;
  -import java.io.FileNotFoundException;
  -import java.io.IOException;
  +import java.io.*;
   
   import java.util.Enumeration;
   import java.util.Hashtable;
  +import java.lang.reflect.Field;
  +import java.net.URL;
   
   import org.apache.xalan.xslt.XSLTProcessorFactory;
   import org.apache.xalan.xslt.XSLTProcessor;
  @@ -76,6 +73,13 @@
   import javax.xml.parsers.DocumentBuilderFactory;
   import javax.xml.parsers.DocumentBuilder;
   import javax.xml.parsers.ParserConfigurationException;
  +import javax.xml.transform.Transformer;
  +import javax.xml.transform.TransformerFactory;
  +import javax.xml.transform.Source;
  +import javax.xml.transform.Result;
  +import javax.xml.transform.dom.DOMSource;
  +import javax.xml.transform.stream.StreamSource;
  +import javax.xml.transform.stream.StreamResult;
   
   import org.w3c.dom.Document;
   import org.w3c.dom.Element;
  @@ -84,6 +88,7 @@
   import org.w3c.dom.NamedNodeMap;
   
   import org.xml.sax.SAXException;
  +import org.xml.sax.InputSource;
   
   /**
    * Transform a JUnit xml report.
  @@ -91,60 +96,21 @@
    * style. The non-framed style is convenient to have a concise report via mail, the
    * framed report is much more convenient if you want to browse into different
    * packages or testcases since it is a Javadoc like report.
  - * In the framed report, there are 3 frames:
  - * <ul>
  - *  <li>packageListFrame - list of all packages.
  - *  <li>classListFrame - summary of all testsuites belonging to a package or tests
list.
  - *  <li>classFrame - details of all tests made for a package or for a testsuite.
  - * </ul>
  - * As a default, the transformer will use its default stylesheets, they may not be
  - * be appropriate for users who wants to customize their reports, so you can indicates
  - * your own stylesheets by using <tt>setStyleDir()</tt>.
  - * Stylesheets must be as follows:
  - * <ul>
  - *   <li><b>all-packages.xsl</b> create the package list. It creates
  - *   all-packages.html file in the html folder and it is load in the packageListFrame</li>
  - *   <li><b>all-classes.xsl</b> creates the class list. It creates the
all-classes.html
  - * file in the html folder is loaded by the 'classListFrame' frame</li>
  - *   <li><b>overview-packages.xsl</b> allows to get summary on all tests
made
  - *   for each packages and each class that not include in a package. The filename
  - *   is overview-packages.html</li>
  - *   <li><b>class-detail.xsl</b> is the style for the detail of the tests
made on a class.
  - *   the Html resulting page in write in the directory of the package and the name
  - *   of this page is the name of the class with "-detail" element. For instance,
  - *   the style is applied on the MyClass testsuite, the resulting filename is
  - *   <u>MyClass-detail.html</u>. This file is load in the "classFrame" frame.</li>
  - *   <li><b>package-summary.xsl</b> allows to create a summary on the
package.
  - *   The resulting html file is write in the package directory. The name of this
  - *   file is <u>package-summary.html</u> This file is load in the "classFrame"
frame.</li>
  - *   <li><b>classes-list.xsl</b> create the list of the class in this
package.
  - *   The resulting html file is write in the package directory and it is load in
  - *   the 'classListFrame' frame. The name of the resulting file is <u>class-list.html</u></li>
  - * <li>
    *
  - * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
  - * @author <a href="mailto:ndelahaye@imediation.com">Nicolas Delahaye</a>
  + * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
    */
  -public class AggregateTransformer {     
  -        
  -    public final static String ALLPACKAGES = "all-packages";
  -        
  -    public final static String ALLCLASSES = "all-classes";
  -        
  -    public final static String OVERVIEW_PACKAGES = "overview-packages";
  -        
  -    public final static String CLASS_DETAILS = "class-details";
  -        
  -    public final static String CLASSES_LIST = "classes-list";
  -        
  -    public final static String PACKAGE_SUMMARY = "package-summary";
  -        
  -    public final static String OVERVIEW_SUMMARY = "overview-summary";
  +public class AggregateTransformer {
   
       public final static String FRAMES = "frames";
   
       public final static String NOFRAMES = "noframes";
   
  +    public static class Format extends EnumeratedAttribute {
  +		public String[] getValues(){
  +			return new String[]{FRAMES, NOFRAMES};
  +		}
  +	}
  +
       /** Task */
       protected Task task;
   
  @@ -160,9 +126,6 @@
       /** the format to use for the report. Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt>
*/
       protected String format;
   
  -    /** the file extension of the generated files. As a default it will be <tt>.html</tt>
*/
  -    protected String extension;
  -
       /** XML Parser factory */
       protected static final DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
   
  @@ -170,8 +133,8 @@
           this.task = task;
       }
   
  -    public void setFormat(String format){
  -        this.format = format;
  +    public void setFormat(Format format){
  +        this.format = format.getValue();
       }
   
       public void setXmlDocument(Document doc){
  @@ -183,9 +146,16 @@
        * to set the file directly. Much more for testing purposes.
        * @param xmlfile xml file to be processed
        */
  -    void setXmlfile(File xmlfile) throws BuildException {
  +    protected void setXmlfile(File xmlfile) throws BuildException {
           try {
  -            setXmlDocument(readDocument(xmlfile));
  +            DocumentBuilder builder = dbfactory.newDocumentBuilder();
  +            InputStream in = new FileInputStream(xmlfile);
  +            try {
  +                Document doc = builder.parse(in);
  +                setXmlDocument(doc);
  +            } finally {
  +                in.close();
  +            }
           } catch (Exception e){
               throw new BuildException("Error while parsing document: " + xmlfile, e);
           }
  @@ -208,15 +178,7 @@
   
       /** set the extension of the output files */
       public void setExtension(String ext){
  -        this.extension = ext;
  -    }
  -
  -    /** get the extension, if it is null, it will use .html as the default */
  -    protected String getExtension(){
  -        if (extension == null) {
  -            extension = ".html";
  -        }
  -        return extension;
  +        task.log("extension is not used anymore", Project.MSG_WARN);
       }
   
       public void transform() throws BuildException {
  @@ -224,19 +186,8 @@
           final long t0 = System.currentTimeMillis();
           try {
               Element root = document.getDocumentElement();
  -                        
  -            if (NOFRAMES.equals(format)) {
  -                //createCascadingStyleSheet();
  -                createSinglePageSummary(root);
  -            } else {
  -                createFrameStructure();
  -                createCascadingStyleSheet();
  -                createPackageList(root);
  -                createClassList(root);
  -                createPackageOverview(root);
  -                createAllTestSuiteDetails(root);
  -                createAllPackageDetails(root);
  -            }
  +            XalanExecutor executor = XalanExecutor.newInstance(this);
  +            executor.execute();
           } catch (Exception e){
               throw new BuildException("Errors while applying transformations", e);
           }
  @@ -246,283 +197,146 @@
   
       /** check for invalid options */
       protected void checkOptions() throws BuildException {
  -        if ( !FRAMES.equals(format) && !NOFRAMES.equals(format)) {
  -            throw new BuildException("Invalid format. Must be 'frames' or 'noframes' but
was: '" + format + "'");
  -        }
           // set the destination directory relative from the project if needed.
           if (toDir == null) {
               toDir = task.getProject().resolveFile(".");
           } else if ( !toDir.isAbsolute() ) {
               toDir = task.getProject().resolveFile(toDir.getPath());
           }
  -        // create the directories if needed
  -        if (!toDir.exists()) {
  -            if (!toDir.mkdirs()){
  -                throw new BuildException("Could not create directory " + toDir);
  -            }
  -        }
  -    }
  -
  -    /** create a single page summary */
  -    protected void createSinglePageSummary(Element root) throws IOException, SAXException
{
  -        transform(root, OVERVIEW_SUMMARY + ".xsl", OVERVIEW_SUMMARY + getExtension());
       }
   
       /**
  -     * read the xml file that should be the resuiting file of the testcase.
  -     * @param filename name of the xml resulting file of the testcase.
  -     */
  -    protected Document readDocument(File file) throws IOException, SAXException, ParserConfigurationException
{
  -        DocumentBuilder builder = dbfactory.newDocumentBuilder();
  -        InputStream in = new FileInputStream(file);
  -        try {
  -            return builder.parse(in);
  -        } finally {
  -            in.close();
  +     * Get the systemid of the appropriate stylesheet based on its
  +     * name and styledir. If no styledir is defined it will load
  +     * it as a java resource in the current package, otherwise it
  +     * will get it from the given directory.
  +     * @throws IOException thrown if the requested stylesheet does
  +     * not exist.
  +     */
  +    protected String getStylesheetSystemId() throws IOException {
  +        String xslname = "junit-frames.xsl";
  +        if (NOFRAMES.equals(format)){
  +            xslname = "junit-noframes.xsl";
           }
  -    }
  -
  -    protected void createCascadingStyleSheet() throws IOException, SAXException {
  -        InputStream in = null;
  -        if (styleDir == null) {
  -            in = getResourceAsStream("html/stylesheet.css");
  -        } else {
  -            in = new FileInputStream(new File(styleDir, "stylesheet.css"));
  -        }
  -        OutputStream out = new FileOutputStream( new File(toDir, "stylesheet.css"));
  -        copy(in, out);
  -    }
  -
  -    protected void createFrameStructure() throws IOException, SAXException{
  -        InputStream in = null;
  -        if (styleDir == null) {
  -            in = getResourceAsStream("html/index.html");
  +        URL url = null;
  +        if (styleDir == null){
  +            url = getClass().getResource(xslname);
  +            if (url == null){
  +                throw new FileNotFoundException("Could not find jar resource " + xslname);
  +            }
           } else {
  -            in = new FileInputStream(new File(styleDir, "index.html"));
  -        }
  -        OutputStream out = new FileOutputStream( new File(toDir, "index.html") );
  -        copy(in, out);
  -    }
  -        
  -    /**
  -     * Create the list of all packages.
  -     * @param root root of the xml document.
  -     */
  -    protected void createPackageList(Node root) throws SAXException {
  -        transform(root, ALLPACKAGES + ".xsl", ALLPACKAGES + getExtension());
  -    }
  -
  -    /**
  -     * Create the list of all classes.
  -     * @param root root of the xml document.
  -     */
  -    protected void createClassList(Node root) throws SAXException {
  -        transform(root, ALLCLASSES + ".xsl", ALLCLASSES + getExtension());
  -    }
  -
  -    /**
  -     * Create the summary used in the overview.
  -     * @param root root of the xml document.
  -     */
  -    protected void createPackageOverview(Node root) throws SAXException {
  -        transform(root,  OVERVIEW_PACKAGES + ".xsl", OVERVIEW_PACKAGES + getExtension());
  -    }
  -
  -    /**
  -     *  @return the list of all packages that exists defined in testsuite nodes
  -     */
  -    protected Enumeration getPackages(Element root){
  -        Hashtable map = new Hashtable();
  -        NodeList testsuites = root.getElementsByTagName(XMLConstants.TESTSUITE);
  -        final int size = testsuites.getLength();
  -        for (int i = 0; i < size; i++){
  -            Element testsuite = (Element) testsuites.item(i);
  -            String packageName = testsuite.getAttribute(XMLConstants.ATTR_PACKAGE);
  -            if (packageName == null){
  -                //@todo replace the exception by something else
  -                throw new IllegalStateException("Invalid 'testsuite' node: should contains
'package' attribute");
  +            File file = new File(styleDir, xslname);
  +            if (!file.exists()){
  +                throw new FileNotFoundException("Could not find file '" + file + "'");
               }
  -            map.put(packageName, packageName);
  -        }
  -        return map.keys();
  -    }
  -
  -    /**
  -     * create all resulting html pages for all testsuites.
  -     * @param root should be 'testsuites' node.
  -     */
  -    protected void createAllTestSuiteDetails(Element root) throws SAXException {
  -        NodeList testsuites = root.getElementsByTagName(XMLConstants.TESTSUITE);
  -        final int size = testsuites.getLength();
  -        for (int i = 0; i < size; i++){
  -            Element testsuite = (Element) testsuites.item(i);
  -            createTestSuiteDetails(testsuite);
  +            url = new URL("file", "", file.getAbsolutePath());
           }
  +        return url.toExternalForm();
       }
   
  -    /**
  -     * create the html resulting page of one testsuite.
  -     * @param root should be 'testsuite' node.
  -     */
  -    protected void createTestSuiteDetails(Element testsuite) throws SAXException {
  -                
  -        String packageName = testsuite.getAttribute(XMLConstants.ATTR_PACKAGE);       
 
  -        String pkgPath = packageToPath(packageName);
  -        
  -        // get the class name
  -        String name = testsuite.getAttribute(XMLConstants.ATTR_NAME);
  -
  -        // get the name of the testsuite and create the filename of the ouput html page
  -        String filename = name + "-details" + getExtension();
  -        String fullpathname = pkgPath + filename; // there's already end path separator
to pkgPath
  -
  -        // apply the style on the document.
  -        transform(testsuite, CLASS_DETAILS + ".xsl", fullpathname);
  -    }
  +}
   
  -    /**
  -     * create the html resulting page of the summary of each package of the root element.
  -     * @param root should be 'testsuites' node.
  -     */
  -    protected void createAllPackageDetails(Element root) throws SAXException, ParserConfigurationException
{
  -        Enumeration packages = getPackages(root);
  -        while ( packages.hasMoreElements() ){
  -            String pkgname = (String)packages.nextElement();
  -            // for each package get the list of its testsuite.
  -            DOMUtil.NodeFilter pkgFilter = new PackageFilter(pkgname);
  -            NodeList testsuites = DOMUtil.listChildNodes(root, pkgFilter, false);
  -            Element doc = buildDocument(testsuites);
  -            // skip package details if the package does not exist (root package)
  -            if( !pkgname.equals("") ){
  -                createPackageDetails(doc, pkgname);
  -            }
  -        }
  +/**
  + * Command class that encapsulate specific behavior for each
  + * Xalan version. The right executor will be instantiated at
  + * runtime via class lookup. For instance, it will check first
  + * for Xalan2, then for Xalan1.
  + */
  +abstract class XalanExecutor {
  +    /** the transformer caller */
  +    protected AggregateTransformer caller;
  +
  +    /** set the caller for this object. */
  +    private final void setCaller(AggregateTransformer caller){
  +        this.caller = caller;
       }
   
  -    protected String packageToPath(String pkgname){
  -        if (!pkgname.equals("")) {
  -            return pkgname.replace('.', File.separatorChar) + File.separatorChar;
  +    /** get the appropriate stream based on the format (frames/noframes) */
  +    protected OutputStream getOutputStream() throws IOException {
  +        if (caller.FRAMES.equals(caller.format)){
  +            // dummy output for the framed report
  +            // it's all done by extension...
  +            return new ByteArrayOutputStream();
  +        } else {
  +            return new FileOutputStream(new File(caller.toDir, "junit-noframes.html"));
           }
  -        return "." + File.separatorChar;
       }
   
  -    /**
  -     * create the html resulting page of the summary of a package .
  -     * @param root should be 'testsuites' node.
  -     * @param pkgname Name of the package that we want a summary.
  -     */
  -    protected void createPackageDetails(Node root, String pkgname) throws SAXException
{
  -        String path = packageToPath(pkgname);
  -
  -        // apply style to get the list of the classes of this package and
  -        // display it in the classListFrame.
  -        transform(root, CLASSES_LIST + ".xsl", path + CLASSES_LIST + getExtension());
  +    /** override to perform transformation */
  +    abstract void execute() throws Exception;
   
  -        // apply style to get a summary on this package.
  -        transform(root, PACKAGE_SUMMARY + ".xsl", path + PACKAGE_SUMMARY + getExtension());
  -    }
  -
       /**
  -     * Create an element root ("testsuites")
  -     * and import all nodes as children of this element.
  -     *
  +     * Create a valid Xalan executor. It checks first if Xalan2 is
  +     * present, if not it checks for xalan1. If none is available, it
  +     * fails.
  +     * @param caller object containing the transformation information.
  +     * @throws BuildException thrown if it could not find a valid xalan
  +     * executor.
        */
  -    protected Element buildDocument(NodeList list) throws ParserConfigurationException
{
  -        DocumentBuilder builder = dbfactory.newDocumentBuilder();
  -        Document doc = builder.newDocument();
  -        Element elem = doc.createElement(XMLConstants.TESTSUITES);
  -        final int len = list.getLength();
  -        for(int i=0 ; i < len ; i++) {
  -            DOMUtil.importNode(elem, list.item(i));
  -        }
  -        return elem;
  -    }
  -
  -    /**
  -     * Apply a template on a part of the xml document.
  -     *
  -     * @param root root of the document fragment
  -     * @param xslfile style file
  -     * @param outfilename filename of the result of the style applied on the Node
  -     *
  -     * @throws SAXException SAX Parsing Error on the style Sheet.
  -     */
  -    protected void transform(Node root, String xslname, String htmlname) throws SAXException
{
  -        try{
  -            XSLTInputSource xsl_source = getXSLStreamSource(xslname);
  -            XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
  -            File htmlfile = new File(toDir, htmlname);
  -            // create the directory if it does not exist
  -            File dir = new File(htmlfile.getParent()); // getParentFile is in JDK1.2+
  -            if (!dir.exists()) {
  -                dir.mkdirs();
  +    static XalanExecutor newInstance(AggregateTransformer caller) throws BuildException
{
  +        Class procVersion = null;
  +        XalanExecutor executor = null;
  +        try {
  +            procVersion = Class.forName("org.apache.xalan.processor.XSLProcessorVersion");
  +            executor = new Xalan2Executor();
  +        } catch (Exception xalan2missing){
  +            try {
  +                procVersion = Class.forName("org.apache.xalan.xslt.XSLProcessorVersion");
  +                executor = new Xalan1Executor();
  +            } catch (Exception xalan1missing){
  +                throw new BuildException("Could not find xalan2 nor xalan1 in the classpath.
Check http://xml.apache.org/xalan-j");
               }
  -            task.log("Applying '" + xslname + "'. Generating '" + htmlfile + "'", Project.MSG_VERBOSE);
  -            processor.process( new XSLTInputSource(root), xsl_source, new XSLTResultTarget(htmlfile.getAbsolutePath())
);
  -        } catch (IOException e){
  -            task.log(e.getMessage(), Project.MSG_ERR);
  -            e.printStackTrace(); //@todo bad, change this
  -            throw new SAXException(e.getMessage());
           }
  +        String version = getXalanVersion(procVersion);
  +        caller.task.log("Using Xalan version: " + version);
  +        executor.setCaller(caller);
  +        return executor;
       }
   
  -
  -    /**
  -     * default xsls are embedded in the distribution jar. As a default we will use
  -     * them, otherwise we will get the one supplied by the client in a given
  -     * directory. It must have the same name.
  -     */
  -    protected XSLTInputSource getXSLStreamSource(String name) throws IOException {
  -        InputStream in;
  -        String systemId; //we need this because there are references in xsls
  -        if (styleDir == null){
  -            in = getResourceAsStream("xsl/" + name);
  -            systemId = getClass().getResource("xsl/" + name).toString();
  -        } else {
  -            File f = new File(styleDir, name);
  -            in= new FileInputStream(f);
  -            systemId = "file:///" + f.getAbsolutePath();
  -        }
  -        XSLTInputSource ss = new XSLTInputSource(in);
  -        ss.setSystemId(systemId);
  -        return ss;
  -    }
  -
  -    private InputStream getResourceAsStream(String name) throws FileNotFoundException {
  -        InputStream in = getClass().getResourceAsStream(name);
  -        if (in == null) {
  -            throw new FileNotFoundException("Could not find resource '" + name + "'");
  +    /** pretty useful data (Xalan version information) to display. */
  +    private static String getXalanVersion(Class procVersion) {
  +        try {
  +            Field f = procVersion.getField("S_VERSION");
  +            return f.get(null).toString();
  +        } catch (Exception e){
  +            return "?";
           }
  -        return in;
       }
  +}
   
  -    /** Do some raw stream copying */
  -    private static void copy(InputStream in, OutputStream out) throws IOException {
  -        int size = -1;
  -        byte[] buffer =  new byte[1024];
  -        // Make the copy
  -        while( (size = in.read(buffer)) != -1){
  -            out.write(buffer,0,size);
  -        }
  +/**
  + * Xalan executor via JAXP. Nothing special must exists in the classpath
  + * besides of course, a parser, jaxp and xalan.
  + */
  +class Xalan2Executor extends XalanExecutor {
  +    void execute() throws Exception {
  +        TransformerFactory tfactory = TransformerFactory.newInstance();
  +        String system_id = caller.getStylesheetSystemId();
  +        Source xsl_src = new StreamSource(system_id);
  +        Transformer tformer = tfactory.newTransformer(xsl_src);
  +        Source xml_src = new DOMSource(caller.document);
  +        OutputStream os = getOutputStream();
  +        tformer.setParameter("output.dir", caller.toDir.getAbsolutePath());
  +        Result result = new StreamResult(os);
  +        tformer.transform(xml_src, result);
       }
  -
  -
  -    /**
  -     * allow us to check if the node is a object of a specific package.
  -     */
  -    protected static class PackageFilter implements DOMUtil.NodeFilter {
  -        private final String pkgName;
  +}
   
  -        PackageFilter(String pkgname) {
  -            this.pkgName = pkgname;
  -        }
  -        /**
  -         * if the node receive is not a element then return false
  -         * check if the node is a class of this package.
  -         */
  -        public boolean accept(Node node) {
  -            String pkgname = DOMUtil.getNodeAttribute(node, XMLConstants.ATTR_PACKAGE);
  -            return pkgName.equals(pkgname);
  -        }
  +/**
  + * Xalan 1 executor. It will need a lot of things in the classpath:
  + * xerces for the serialization, xalan and bsf for the extension.
  + * @todo do everything via reflection to avoid compile problems ?
  + */
  +class Xalan1Executor extends XalanExecutor {
  +    void execute() throws Exception {
  +        XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
  +        // need to quote otherwise it breaks because of "extra illegal tokens"
  +        processor.setStylesheetParam("output.dir", "'" + caller.toDir.getAbsolutePath()
+ "'");
  +        XSLTInputSource xml_src = new XSLTInputSource(caller.document);
  +        String system_id = caller.getStylesheetSystemId();
  +        XSLTInputSource xsl_src = new XSLTInputSource(system_id);
  +        OutputStream os = getOutputStream();
  +        XSLTResultTarget target = new XSLTResultTarget(os);
  +        processor.process( xml_src, xsl_src, target);
       }
   }
  
  
  

Mime
View raw message