001    /*
002     * Created on Jul 19, 2007
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2007-2009 the original author or authors.
014     */
015    package org.fest.swing.junit.ant;
016    
017    import static org.fest.util.Strings.concat;
018    
019    import java.io.File;
020    import java.net.URL;
021    import java.util.List;
022    import java.util.concurrent.CopyOnWriteArrayList;
023    
024    import org.apache.tools.ant.*;
025    import org.apache.tools.ant.taskdefs.*;
026    import org.apache.tools.ant.taskdefs.XSLTProcess.Param;
027    import org.apache.tools.ant.taskdefs.optional.junit.AggregateTransformer;
028    import org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator;
029    import org.apache.tools.ant.types.*;
030    import org.apache.tools.ant.types.resources.FileResource;
031    import org.apache.tools.ant.types.resources.URLResource;
032    import org.apache.tools.ant.util.FileUtils;
033    
034    /**
035     * Transforms a JUnit XML report. The default transformation generates an HTML report in either framed or non-framed
036     * style.
037     *
038     * @author Alex Ruiz
039     */
040    public class ReportTransformer extends AggregateTransformer {
041    
042      private static final String XSL_FILE_PATH = "org/fest/swing/junit/ant/";
043    
044      private Path classpath;
045    
046      /** The parameters that will be sent to the XSL transformation. */
047      private final List<Param> params;
048    
049      /** Instance of a utility class to use for file operations. */
050      private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
051    
052      /** Used to ensure the uniqueness of a property. */
053      private static int counter;
054    
055      /**
056       * Creates a new <code>{@link ReportTransformer}</code>.
057       * @param task task delegating to this class.
058       */
059      public ReportTransformer(Task task) {
060        super(task);
061        params = new CopyOnWriteArrayList<Param>();
062      }
063    
064      /**
065       * Create an instance of an XSL parameter for configuration by Ant.
066       * @return an instance of the <code>Param</code> class to be configured.
067       */
068      @Override public Param createParam() {
069        Param p = new Param();
070        params.add(p);
071        return p;
072      }
073    
074      /**
075       * Performs the XSLT transformation to generate the HTML report.
076       * @throws BuildException thrown if something goes wrong with the transformation.
077       */
078      @Override public void transform() throws BuildException {
079        checkOptions();
080        TempFile tempFileTask = tempFileTask();
081        XSLTProcess xsltTask = xsltTask();
082        File outputFile = outputFile(tempFileTask);
083        xsltTask.setOut(outputFile);
084        createNewParams(xsltTask);
085        createOutputDirParam(xsltTask);
086        long startingTime = System.currentTimeMillis();
087        try {
088          xsltTask.execute();
089        } catch (Exception e) {
090          throw new BuildException(concat("Errors while applying transformations: ", e.getMessage()), e);
091        }
092        long transformTime = System.currentTimeMillis() - startingTime;
093        task.log(concat("Transform time: ", String.valueOf(transformTime), " ms"));
094        delete(outputFile);
095      }
096    
097      private XSLTProcess xsltTask() {
098        XSLTProcess xsltTask = new XSLTProcess();
099        xsltTask.bindToOwner(task);
100        xsltTask.setClasspath(classpath);
101        xsltTask.setXslResource(getStylesheet());
102        xsltTask.setIn(((XMLResultAggregator) task).getDestinationFile());
103        return xsltTask;
104      }
105    
106      /**
107       * Access the stylesheet to be used as a resource.
108       * @return stylesheet as a resource
109       */
110      @Override protected Resource getStylesheet() {
111        String xslname = "junit-frames.xsl";
112        if (NOFRAMES.equals(format)) xslname = "junit-noframes.xsl";
113        if (styleDir == null) {
114          URLResource stylesheet = new URLResource();
115          URL stylesheetURL = getClass().getClassLoader().getResource(concat(XSL_FILE_PATH, xslname));
116          stylesheet.setURL(stylesheetURL);
117          return stylesheet;
118        }
119        FileResource stylesheet = new FileResource();
120        File stylesheetFile = new File(styleDir, xslname);
121        stylesheet.setFile(stylesheetFile);
122        return stylesheet;
123      }
124    
125      private TempFile tempFileTask() {
126        TempFile tempFileTask = new TempFile();
127        tempFileTask.bindToOwner(task);
128        return tempFileTask;
129      }
130    
131      private File outputFile(TempFile tempFileTask) {
132        Project project = task.getProject();
133        if (format.equals(FRAMES)) {
134          String tempFileProperty = concat(getClass().getName(), String.valueOf(counter++));
135          setUpTempFileTask(tempFileTask, tempFileProperty);
136          return new File(project.getProperty(tempFileProperty));
137        }
138        return new File(toDir, "junit-noframes.html");
139      }
140    
141      private void setUpTempFileTask(TempFile tempFileTask, String tempFileProperty) {
142        Project project = task.getProject();
143        File tmp = FILE_UTILS.resolveFile(project.getBaseDir(), project.getProperty("java.io.tmpdir"));
144        tempFileTask.setDestDir(tmp);
145        tempFileTask.setProperty(tempFileProperty);
146        tempFileTask.execute();
147      }
148    
149      private void createNewParams(XSLTProcess xsltTask) {
150        for (Param param : params) {
151          Param p = xsltTask.createParam();
152          p.setProject(task.getProject());
153          p.setName(param.getName());
154          p.setExpression(param.getExpression());
155        }
156      }
157    
158      private void createOutputDirParam(XSLTProcess xsltTask) {
159        Param p = xsltTask.createParam();
160        p.setProject(task.getProject());
161        p.setName("output.dir");
162        p.setExpression(toDir.getAbsolutePath());
163      }
164    
165      private void delete(File outputFile) {
166        if (!format.equals(FRAMES)) return;
167        Delete deleteTask = new Delete();
168        deleteTask.bindToOwner(task);
169        deleteTask.setFile(outputFile);
170        deleteTask.execute();
171      }
172    
173      /**
174       * Sets an additional classpath.
175       * @param classpath the additional classpath to append to the current one.
176       */
177      public void setClasspath(Path classpath) {
178        createClasspath().append(classpath);
179      }
180    
181      /**
182       * Sets a reference to a classpath.
183       * @param r the reference to set.
184       */
185      public void setClasspathRef(Reference r) {
186        createClasspath().setRefid(r);
187      }
188    
189      /**
190       * Creates the current classpath.
191       * @return the created classpath.
192       */
193      public Path createClasspath() {
194        if (classpath == null) classpath = new Path(task.getProject());
195        return classpath.createPath();
196      }
197    }