| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001-2002 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.tools.ant.taskdefs.optional.metamata; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.Vector; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; |
| import org.apache.tools.ant.taskdefs.LogStreamHandler; |
| import org.apache.tools.ant.types.EnumeratedAttribute; |
| import org.apache.tools.ant.types.Path; |
| |
| /** |
| * Calculates global complexity and quality metrics on Java source code. |
| * |
| * You will not be able to use this task with the evaluation version since |
| * as of Metamata 2.0, Metrics does not support command line :-( |
| * |
| * For more information, visit the website at |
| * <a href="http://www.metamata.com">www.metamata.com</a> |
| * |
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> |
| */ |
| public class MMetrics extends AbstractMetamataTask { |
| /* |
| The command line options as of Metamata 2.0 are as follows: |
| |
| Usage |
| mmetrics <option>... <path>... |
| |
| Parameters |
| path File or directory to measure. |
| |
| Options |
| -arguments -A <file> Includes command line arguments from file. |
| -classpath -cp <path> Sets class path (also source path unless one |
| explicitly set). Overrides METAPATH/CLASSPATH. |
| -compilation-units Measure compilation units. |
| -files Measure compilation units. |
| -format -f <format> Sets output format, default output file type. |
| -help -h Prints help and exits. |
| -indent -i <string> Sets string used to indent labels one level. |
| -methods Measure methods, types, and compilation units. |
| -output -o <file> Sets output file name. |
| -quiet -q Suppresses copyright message. |
| -sourcepath <path> Sets source path. Overrides SOURCEPATH. |
| -types Measure types and compilation units. |
| -verbose -v Prints all messages. |
| -version -V Prints version and exits. |
| |
| Format Options |
| comma csv Format output as comma-separated text. |
| html htm Format output as an HTML table. |
| tab tab-separated tsv Format output as tab-separated text. |
| text txt Format output as space-aligned text. |
| */ |
| |
| /** the granularity mode. Should be one of 'files', 'methods' and 'types'. */ |
| private String granularity = null; |
| |
| /** the XML output file */ |
| private File outFile = null; |
| |
| /** the location of the temporary txt report */ |
| private File tmpFile; |
| |
| private Path path = null; |
| |
| //--------------------------- PUBLIC METHODS ------------------------------- |
| |
| /** default constructor */ |
| public MMetrics() { |
| super("com.metamata.sc.MMetrics"); |
| } |
| |
| /** |
| * Attributes for granularity. |
| */ |
| public static class GranularityAttribute extends EnumeratedAttribute { |
| public String[] getValues() { |
| return new String[]{"compilation-units", "files", "methods", "types", "packages"}; |
| } |
| } |
| |
| /** |
| * set the granularity of the audit. Should be one of 'files', 'methods' |
| * or 'types'. |
| * @param granularity the audit reporting mode. |
| */ |
| public void setGranularity(GranularityAttribute granularity) { |
| this.granularity = granularity.getValue(); |
| } |
| |
| /** |
| * Set the output XML file |
| * @param file the xml file to write the XML report to. |
| */ |
| public void setTofile(File file) { |
| this.outFile = file; |
| } |
| |
| /** |
| * Set a new path (directory) to measure metrics from. |
| * @return the path instance to use. |
| */ |
| public Path createPath() { |
| if (path == null) { |
| path = new Path(project); |
| } |
| return path; |
| |
| } |
| |
| //------------------- PROTECTED / PRIVATE METHODS -------------------------- |
| |
| |
| // check for existing options and outfile, all other are optional |
| protected void checkOptions() throws BuildException { |
| super.checkOptions(); |
| |
| if (outFile == null) { |
| throw new BuildException("Output XML file must be set via 'tofile' attribute."); |
| } |
| if (path == null && fileSets.size() == 0) { |
| throw new BuildException("Must set either paths (path element) or files (fileset element)"); |
| } |
| // I don't accept dirs and files at the same time, I cannot recognize the semantic in the result |
| if (path != null && fileSets.size() > 0) { |
| throw new BuildException("Cannot set paths (path element) and files (fileset element) at the same time"); |
| } |
| tmpFile = createTmpFile(); |
| } |
| |
| protected void execute0(ExecuteStreamHandler handler) throws BuildException { |
| super.execute0(handler); |
| transformFile(); |
| } |
| |
| /** |
| * transform the generated file via the handler |
| * This function can either be called if the result is written to the output |
| * file via -output or we could use the handler directly on stdout if not. |
| * @see #createStreamHandler() |
| */ |
| protected void transformFile() throws BuildException { |
| FileInputStream tmpStream = null; |
| try { |
| tmpStream = new FileInputStream(tmpFile); |
| } catch (IOException e) { |
| throw new BuildException("Error reading temporary file: " + tmpFile, e); |
| } |
| FileOutputStream xmlStream = null; |
| try { |
| xmlStream = new FileOutputStream(outFile); |
| ExecuteStreamHandler xmlHandler = new MMetricsStreamHandler(this, xmlStream); |
| xmlHandler.setProcessOutputStream(tmpStream); |
| xmlHandler.start(); |
| xmlHandler.stop(); |
| } catch (IOException e) { |
| throw new BuildException("Error creating output file: " + outFile, e); |
| } finally { |
| if (xmlStream != null) { |
| try { |
| xmlStream.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| if (tmpStream != null) { |
| try { |
| tmpStream.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| } |
| |
| |
| /** cleanup the temporary txt report */ |
| protected void cleanUp() throws BuildException { |
| try { |
| super.cleanUp(); |
| } finally { |
| if (tmpFile != null) { |
| tmpFile.delete(); |
| tmpFile = null; |
| } |
| } |
| } |
| |
| /** |
| * if the report is transform via a temporary txt file we should use a |
| * a normal logger here, otherwise we could use the metrics handler |
| * directly to capture and transform the output on stdout to XML. |
| */ |
| protected ExecuteStreamHandler createStreamHandler() { |
| // write the report directtly to an XML stream |
| // return new MMetricsStreamHandler(this, xmlStream); |
| return new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_INFO); |
| } |
| |
| |
| protected Vector getOptions() { |
| Vector options = new Vector(512); |
| // there is a bug in Metamata 2.0 build 37. The sourcepath argument does |
| // not work. So we will use the sourcepath prepended to classpath. (order |
| // is important since Metamata looks at .class and .java) |
| if (sourcePath != null) { |
| sourcePath.append(classPath); // srcpath is prepended |
| classPath = sourcePath; |
| sourcePath = null; // prevent from using -sourcepath |
| } |
| |
| // don't forget to modify the pattern if you change the options reporting |
| if (classPath != null) { |
| options.addElement("-classpath"); |
| options.addElement(classPath.toString()); |
| } |
| options.addElement("-output"); |
| options.addElement(tmpFile.toString()); |
| |
| options.addElement("-" + granularity); |
| |
| // display the metamata copyright |
| // options.addElement( "-quiet"); |
| options.addElement("-format"); |
| |
| // need this because that's what the handler is using, it's |
| // way easier to process than any other separator |
| options.addElement("tab"); |
| |
| // specify a / as the indent character, used by the handler. |
| options.addElement("-i"); |
| options.addElement("/"); |
| |
| // directories |
| String[] dirs = path.list(); |
| for (int i = 0; i < dirs.length; i++) { |
| options.addElement(dirs[i]); |
| } |
| // files next. |
| addAllVector(options, includedFiles.keys()); |
| return options; |
| } |
| |
| } |