git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@405267 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -81,7 +81,11 @@ Changes that could break older environments: | |||||
| * Testlet (test) optional task removed. | * Testlet (test) optional task removed. | ||||
| * Icontract optional task removed. | |||||
| * Icontract optional task removed. | |||||
| * Metamata (maudit, mmetrics, and mparse tasks) removed. | |||||
| * Sitraka (jpcoverage, jpcovmerge, jpcovreport) tasks suppressed. | |||||
| Fixed bugs: | Fixed bugs: | ||||
| ----------- | ----------- | ||||
| @@ -195,8 +195,6 @@ | |||||
| <or> | <or> | ||||
| <filename name="${optional.package}/junit/Xalan2Executor*"/> | <filename name="${optional.package}/junit/Xalan2Executor*"/> | ||||
| <filename name="${optional.package}/TraXLiaison*"/> | <filename name="${optional.package}/TraXLiaison*"/> | ||||
| <filename name="${optional.package}/sitraka/**"/> | |||||
| <filename name="${optional.package}/metamata/MMetrics*"/> | |||||
| <filename name="${optional.package}/XsltTest*"/> | <filename name="${optional.package}/XsltTest*"/> | ||||
| <filename name="${type.package}/XMLCatalogBuildFileTest*"/> | <filename name="${type.package}/XMLCatalogBuildFileTest*"/> | ||||
| </or> | </or> | ||||
| @@ -225,7 +223,6 @@ | |||||
| <or> | <or> | ||||
| <filename name="${regexp.package}/JakartaOro*"/> | <filename name="${regexp.package}/JakartaOro*"/> | ||||
| <filename name="${optional.package}/perforce/*"/> | <filename name="${optional.package}/perforce/*"/> | ||||
| <filename name="${optional.package}/metamata/MAudit*"/> | |||||
| </or> | </or> | ||||
| </selector> | </selector> | ||||
| @@ -1654,8 +1651,6 @@ | |||||
| time dependencies --> | time dependencies --> | ||||
| <exclude name="${optional.package}/ReplaceRegExpTest.java" | <exclude name="${optional.package}/ReplaceRegExpTest.java" | ||||
| unless="some.regexp.support"/> | unless="some.regexp.support"/> | ||||
| <exclude name="${optional.package}/sitraka/*.java" | |||||
| unless="some.regexp.support"/> | |||||
| <exclude name="${ant.package}/types/selectors/ContainsRegexpTest.java" | <exclude name="${ant.package}/types/selectors/ContainsRegexpTest.java" | ||||
| unless="some.regexp.support"/> | unless="some.regexp.support"/> | ||||
| <exclude name="${ant.package}/types/mappers/RegexpPatternMapperTest.java" | <exclude name="${ant.package}/types/mappers/RegexpPatternMapperTest.java" | ||||
| @@ -1684,9 +1679,6 @@ | |||||
| if="tests.are.on.system.classpath"/> | if="tests.are.on.system.classpath"/> | ||||
| <exclude name="${optional.package}/junit/JUnitClassLoaderTest.java" | <exclude name="${optional.package}/junit/JUnitClassLoaderTest.java" | ||||
| if="tests.are.on.system.classpath"/> | if="tests.are.on.system.classpath"/> | ||||
| <exclude name="${optional.package}/sitraka/XMLReportTest.java" | |||||
| if="tests.are.on.system.classpath"/> | |||||
| <!-- these tests need to be localised before being ran???? --> | <!-- these tests need to be localised before being ran???? --> | ||||
| <exclude name="${optional.package}/PvcsTest.java"/> | <exclude name="${optional.package}/PvcsTest.java"/> | ||||
| @@ -1743,8 +1735,6 @@ | |||||
| unless="tests.and.ant.share.classloader"/> | unless="tests.and.ant.share.classloader"/> | ||||
| <exclude name="${optional.package}/TraXLiaisonTest.java" | <exclude name="${optional.package}/TraXLiaisonTest.java" | ||||
| unless="tests.and.ant.share.classloader"/> | unless="tests.and.ant.share.classloader"/> | ||||
| <exclude name="${optional.package}/metamata/MAuditParserTest.java" | |||||
| unless="tests.and.ant.share.classloader"/> | |||||
| <exclude name="${taskdefs.package}/ProcessDestroyerTest.java" | <exclude name="${taskdefs.package}/ProcessDestroyerTest.java" | ||||
| unless="tests.and.ant.share.classloader"/> | unless="tests.and.ant.share.classloader"/> | ||||
| <exclude name="${taskdefs.package}/ProtectedJarMethodsTest.java" | <exclude name="${taskdefs.package}/ProtectedJarMethodsTest.java" | ||||
| @@ -1,545 +0,0 @@ | |||||
| <html> | |||||
| <head> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>JProbe Tasks</title> | |||||
| </head> | |||||
| <body> | |||||
| <h1><a name="jprobe">JProbe</a></h1> | |||||
| <p>by</p> | |||||
| <ul> | |||||
| <li>Stephane Bailliez (<a href="mailto:sbailliez@imediation.com">sbailliez@imediation.com</a>)</li> | |||||
| </ul> | |||||
| <h2>Introduction</h2> | |||||
| <p>This task runs the tools from the JProbe suite.<br> | |||||
| For more information, visit <a href="http://www.sitraka.com">http://www.sitraka.com</a>. | |||||
| An evaluation version is available for download if you already don't own it. | |||||
| </p> | |||||
| <p>This task has been written using JProbe Suite Server Side 3.0.</p> | |||||
| <p>It is highly recommended to read the JProbe documentation to understand | |||||
| the values of the command line arguments described below. This | |||||
| document is less complete than the manual, it only gives the basic information | |||||
| and is not intended as a replacement to the manual. | |||||
| </p> | |||||
| <h2>Tasks</h2> | |||||
| <table border="0" cellspacing="0" cellpadding="3"> | |||||
| <tr> | |||||
| <td><b>Task</b></td> | |||||
| <td><b>Description</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td><a href="#jpcoverage">JPCoverage</a></td> | |||||
| <td>Measure coverage of Java code.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td><a href="#jpcovmerge">JPCovMerge</a></td> | |||||
| <td>Merge different snapshots into one.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td><a href="#jpcovreport">JPCovReport</a></td> | |||||
| <td>Create a report from a snapshot</td> | |||||
| </tr> | |||||
| </table> | |||||
| <hr> | |||||
| <h2><a name="jpcoverage">JPCoverage</a></h2> | |||||
| Perform code covering functions by comparing source code line execution to the program�s source code as a whole. | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">home</td> | |||||
| <td valign="top">The directory where JProbe is installed.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">vm</td> | |||||
| <td valign="top"> | |||||
| Indicates which virtual machine to run. | |||||
| Must be one of "jdk117", "jdk118" or "java2".If "java2" is specified, the user is | |||||
| also required to specify a path via <tt>javaexe</tt>, otherwise it will check if | |||||
| the current executing VM is 1.2+ and use its java.home property to determine its | |||||
| location.</td> | |||||
| <td align="center" valign="top">No, default to embedded VM if 1.2+</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">javaexe</td> | |||||
| <td valign="top">The path to the java executable.</td> | |||||
| <td align="center" valign="top">No, use only for java2 vm.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">applet</td> | |||||
| <td valign="top">Run an applet. The default is false, unless the file under | |||||
| analysis ends with htm or html.</td> | |||||
| <td align="center" valign="top">No, default is "false".</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">seedname</td> | |||||
| <td valign="top">Seed name for the temporary snapshot files (files will be named | |||||
| seed.jpc, seed1.jpc, seed2.jpc, ...)</td> | |||||
| <td align="center" valign="top">No, default to "snapshot"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">exitprompt</td> | |||||
| <td valign="top">Toggles display of the console prompt: "Press Enter to close | |||||
| this window." "always": Always displays the prompt. "never": Never displays the | |||||
| prompt. "error": Only displays prompt after an error.</td> | |||||
| <td align="center" valign="top">No, default is "never"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">finalsnapshot</td> | |||||
| <td valign="top">Type of snapshot to send at program termination. Must be one | |||||
| of "none","coverage","all"</td> | |||||
| <td align="center" valign="top">No, default to "coverage"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">recordfromstart</td> | |||||
| <td valign="top">Must be one of "coverage", "all", "none". If you want | |||||
| Coverage to start analyzing as soon as the program begins to run, use "all". | |||||
| If not, select "none".</td> | |||||
| <td align="center" valign="top">No, default to "coverage"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">warnlevel</td> | |||||
| <td valign="top">Set warning level (0-3, where 0 is the least amount of warnings).</td> | |||||
| <td align="center" valign="top">No, default to 0</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">snapshotdir</td> | |||||
| <td valign="top">The path to the directory where snapshot files are stored. | |||||
| Choose a directory that is reachable by both the remote and local computers, | |||||
| and enter the same path on the command line and in the viewer.</td> | |||||
| <td align="center" valign="top">No, default to current directory</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">workingdir</td> | |||||
| <td valign="top">The physical path to the working directory for the VM.</td> | |||||
| <td align="center" valign="top">No, default is current directory.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">tracknatives</td> | |||||
| <td valign="top">Test native methods. Note that testing native methods with | |||||
| Java 2 disables the JIT</td> | |||||
| <td align="center" valign="top">No, default to "false".</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">classname</td> | |||||
| <td valign="top">the name of the class to analyze.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3><a name="nested">Nested Elements</a></h3> | |||||
| <h4>classpath</h4> | |||||
| <p><code>jpcoverage</code> supports a nested <code><classpath></code> | |||||
| element, that represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>jvmarg</h4> | |||||
| <p>Additional parameters may be passed to the VM via nested <code><jvmarg></code> | |||||
| attributes, for example:</p> | |||||
| <pre></pre> | |||||
| <blockquote> | |||||
| <pre><jpcoverage home="c:\jprobe" classname="MyClass"> | |||||
| <jvmarg value="-classic"/> | |||||
| <classpath path="."/> | |||||
| </jpcoverage> | |||||
| </pre> | |||||
| </blockquote> | |||||
| would run the coverage on "MyClass" in classic mode VM. | |||||
| <p><code><jvmarg></code> allows all attributes described in <a | |||||
| href="../using.html#arg">Command line arguments</a>.</p> | |||||
| <h4>arg</h4> | |||||
| <p> | |||||
| Parameters may be passed to the executed class via nested <tt><arg></tt> | |||||
| attributes, as described in <a href="../using.html#arg">Command line arguments</a>. | |||||
| </p> | |||||
| <h4>socket</h4> | |||||
| <p>Define a host and port to connect to if you want to do remote viewing. | |||||
| </p> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">host</td> | |||||
| <td valign="top">the host name/ip of the machine on which the Viewer is running</td> | |||||
| <td align="center">No, default to localhost</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">port</td> | |||||
| <td valign="top">The port number on which you will connect to the Viewer</td> | |||||
| <td align="center">No, default to 4444</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4>filters</h4> | |||||
| <p>Defines class/method filters based on pattern matching. | |||||
| The syntax for filters is similar to a <a href="../CoreTypes/fileset.html">fileset</a>. | |||||
| </p> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">defaultexclude</td> | |||||
| <td valign="top">As a default, the coverage excludes all classes and methods. | |||||
| Default filters are equivalent to | |||||
| <pre> | |||||
| <filters> | |||||
| <exclude class="*" method="*"/> | |||||
| </filters> | |||||
| </pre> | |||||
| </td> | |||||
| <td align="center">No, default to "true"</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p> | |||||
| As seen above, nested elements are <b><tt>include</tt></b> and <b><tt>exclude</tt></b> | |||||
| with a <tt>name</tt> attribute. | |||||
| </p> | |||||
| <blockquote> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">class</td> | |||||
| <td valign="top">The class mask as a simple regular expression</td> | |||||
| <td align="center">No, defaults to "*"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">method</td> | |||||
| <td valign="top">The method mask as a simple regular expression</td> | |||||
| <td align="center">No, defaults to "*"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">enabled</td> | |||||
| <td valign="top">is the filter enabled?</td> | |||||
| <td align="center">No, defaults to true</td> | |||||
| </tr> | |||||
| </table> | |||||
| </blockquote> | |||||
| <h3>Example of filters</h3> | |||||
| <blockquote> | |||||
| <pre> | |||||
| <filters> | |||||
| <include class="com.mycompany.*" method="*"/> | |||||
| <exclude class="com.mycompany.MyClass" method="test*"/> | |||||
| </filters></pre> | |||||
| </blockquote> | |||||
| reports the coverage on all packages, classes and methods from <tt>com.mycompany</tt> | |||||
| except all methods starting by <tt>test</tt> on the class <tt>MyClass</tt> | |||||
| in the package <tt>com.mycompany</tt> | |||||
| <h4>triggers</h4> | |||||
| <p>Define a number of events to use for interacting with the collection | |||||
| of data performed during coverage. For example you may run a whole application | |||||
| but only decide to collect data once it reaches a certain method and once it | |||||
| exits another one.</p> | |||||
| <p> | |||||
| The only type of nested element is the <tt>method</tt> element (triggers are performed | |||||
| on method) and it has the following attributes: | |||||
| </p> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">name</td> | |||||
| <td valign="top">The name of the method(s) as a regular expression. The name | |||||
| is the fully qualified name on the form <tt>package.classname.method</tt></td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">event</td> | |||||
| <td valign="top">the event on the method that will trigger the action. Must be | |||||
| "enter" or "exit".</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">action</td> | |||||
| <td valign="top">the action to execute. Must be one of "clear", | |||||
| "pause", "resume", "snapshot", "suspend", | |||||
| or "exit". They respectively clear recording, pause recording, | |||||
| resume recording, take a snapshot, suspend the recording and exit the program. | |||||
| </td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Example of triggers</h3> | |||||
| <blockquote> | |||||
| <pre><triggers> | |||||
| <method name="ClassName.*()" event="enter" action="snapshot"/> | |||||
| <method name="ClassName.MethodName()" event="exit" action="exit"/> | |||||
| </triggers> | |||||
| </pre> | |||||
| </blockquote> | |||||
| <p>Will take a snapshot when it enters any method of the class <tt>ClassName</tt> | |||||
| and will exit the program once it exits the method <tt>MethodName</tt> of the | |||||
| same class.</p> | |||||
| <hr> | |||||
| <h2><a name="jpcovmerge">JPCovMerge</a></h2> | |||||
| <h3>Description</h3> | |||||
| <p>Perform the merge of several snapshots into a single one.</p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">home</td> | |||||
| <td valign="top">The directory where JProbe is installed.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">tofile</td> | |||||
| <td valign="top">the output filename that will be the result | |||||
| of the name.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">verbose</td> | |||||
| <td valign="top">Perform the merge in verbose mode giving | |||||
| details about the snapshot processing.</td> | |||||
| <td align="center" valign="top">No. Default to false</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p> | |||||
| <tt>jpcovmerge</tt> collects snapshots using the nested <a href="../CoreTypes/fileset.html"><code><FileSet></code></a> | |||||
| element. | |||||
| </p> | |||||
| <h3>Example of merge</h3> | |||||
| <blockquote> | |||||
| <pre><jpcovmerge home="c:\jprobe" tofile="merge.jpc" verbose="true"> | |||||
| <fileset dir="./snapshots"> | |||||
| <include name="snap*.jpc"/> | |||||
| </fileset> | |||||
| </jpcovmerge> | |||||
| </pre> | |||||
| </blockquote> | |||||
| <p> | |||||
| would run the merge in verbose mode on all snapshot files starting by <tt>snap</tt> in the | |||||
| directory <tt>snapshots</tt>. The resulting file will be named <tt>merge.jpc</tt>. | |||||
| </p> | |||||
| <hr> | |||||
| <h2><a name="jpcovreport">JPCovReport</a></h2> | |||||
| <h3>Description</h3> | |||||
| <p>Generate a readable/printable report of a snapshot. Note that you will need <a href="http://jakarta.apache.org/oro/index.html">Jakarta | |||||
| Oro</a> in Ant classpath, to run the <tt>reference</tt> feature.</p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">home</td> | |||||
| <td valign="top">The directory where JProbe is installed.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">format</td> | |||||
| <td valign="top">The format of the generated report. Must be "xml", "html" or "text"</td> | |||||
| <td align="center" valign="top">No, default to "html"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">type</td> | |||||
| <td valign="top">The type of report to be generated. Must be "executive", | |||||
| "summary", "detailed" or "verydetailed"</td> | |||||
| <td align="center" valign="top">No. Default to "detailed"</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">percent</td> | |||||
| <td valign="top">A numeric value for the threshold for printing methods. Must | |||||
| be between 0 and 100.</td> | |||||
| <td align="center" valign="top">No, default to 100</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">snapshot</td> | |||||
| <td valign="top">The name of the snapshot file that is the source to the report.</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">tofile</td> | |||||
| <td valign="top">The name of the generated output file</td> | |||||
| <td align="center" valign="top">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">includesource</td> | |||||
| <td valign="top">Include text of the source code lines. Only applies to | |||||
| format="xml" and type="verydetailed"</td> | |||||
| <td align="center" valign="top">No. Defaults to "yes"</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4>sourcepath</h4> | |||||
| <p> | |||||
| Path to source files can be set via nested sourcepath elements that are <a href="../using.html#path">PATH like structures</a>. | |||||
| </p> | |||||
| <h4>reference (only applies to format="xml")</h4> | |||||
| <p>A reference is a set of classes whose coverage information will be checked | |||||
| against. Since Coverage is only able to give you information about loaded | |||||
| classes, it will only report classes that were at least used in some points in | |||||
| your tests, | |||||
| therefore you will not be able to know what classes are not exercised at all | |||||
| during your tests. The reference is an additional feature that will analyze the | |||||
| bytecode of all classes in a given classpath that match some filters and modify | |||||
| the XML report accordingly. In short, it will: | |||||
| </p> | |||||
| <ul> | |||||
| <li>remove the classes that do not exists in the reference classpath. (For | |||||
| example you might have in your report some helper test classes that you do | |||||
| not want to appear in the report, but are unable to filter without adding | |||||
| hundred of filters for all your classes).</li> | |||||
| <li>add classes that exists in the reference set and match the filters but are | |||||
| not reported.</li> | |||||
| <li>remove abstract methods that are incorrectly reported in JProbe 3.0 | |||||
| (should be fixed in a later SP)</li> | |||||
| <li>remove classes/methods that do not match the filters.</li> | |||||
| </ul> | |||||
| <blockquote> | |||||
| <h4>classpath | |||||
| </h4> | |||||
| <p> | |||||
| Path to the reference set of files can be set via nested classpath elements that are <a href="../using.html#path">PATH like structures</a>. | |||||
| </p> | |||||
| <h4>filters | |||||
| </h4> | |||||
| <p>Nested elements are <b><tt>include</tt></b> and <b><tt>exclude</tt></b> | |||||
| with a <tt>class </tt>and <tt>method </tt>attribute. | |||||
| </p> | |||||
| </blockquote> | |||||
| <blockquote> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td width="12%" valign="top"><b>Attribute</b></td> | |||||
| <td width="78%" valign="top"><b>Description</b></td> | |||||
| <td width="10%" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">class</td> | |||||
| <td valign="top">The class mask as a simple regular expression</td> | |||||
| <td align="center">No, default to *</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">method</td> | |||||
| <td valign="top">The method mask as a simple regular expression</td> | |||||
| <td align="center">No, default to *</td> | |||||
| </tr> | |||||
| </table> | |||||
| </blockquote> | |||||
| <h3>Example of report</h3> | |||||
| <blockquote> | |||||
| <pre> | |||||
| <jpcovreport home="c:\jprobe" snapshot="merge.jpc" format="xml" tofile="result.xml"> | |||||
| <sourcepath path="./src"/> | |||||
| <reference> | |||||
| <classpath path="./bin/classes"/> | |||||
| <filters> | |||||
| <include class="com.mycompany.*"/> | |||||
| <exclude class="com.mycompany.MyClass" method="test*"/> | |||||
| </filters> | |||||
| </reference> | |||||
| </jpcovreport> | |||||
| </pre> | |||||
| </blockquote><p> | |||||
| would generate the report of the file <tt>merge.jpc</tt> and write it to <tt>result.xml</tt> | |||||
| using the source path <tt>src</tt>. As well, it will modify the result.xml by | |||||
| analyzing all classes in the <tt>./bin/classes</tt> that are port of the package | |||||
| <tt>com.mycompany</tt> except the method that start by <tt>test</tt> from the class <tt>MyClass</tt>. | |||||
| </p> | |||||
| <h3>Recommendation</h3> | |||||
| <p>If you generate your main code and your testcases in a separate directory, | |||||
| say bin/classes and test/classes. You should mostly end up with a reference such | |||||
| as:</p> | |||||
| <blockquote> | |||||
| <pre><reference> | |||||
| <classpath path="./bin/classes"/> | |||||
| </reference></pre> | |||||
| </blockquote> | |||||
| <p>With such a reference, your XML report will be cleaned up against parasite | |||||
| classes from your testcases (that as a common practice, generally match the | |||||
| exact package structure of the class you exercise).</p> | |||||
| <h3>HTML reports</h3> | |||||
| <p>You will find in Ant etc directory a stylesheet called coverage-frames.xsl. | |||||
| This file can be used to generate a framed report a la javadoc similar to the | |||||
| one for JUnit. It needs either Xalan 1.2.2 or Xalan 2.x.</p> | |||||
| <p>Xalan 1.2.2 (you must have xalan.jar and bsf.jar in your classpath) | |||||
| </p> | |||||
| <pre><style processor="xalan" in="./reports/xml/results.xml" out="./reports/html/dummy.file" | |||||
| style="${ant.home}/etc/coverage-frames.xsl"> | |||||
| <param name="output.dir" expression="'${basedir}/reports/html'"/> | |||||
| </style></pre> | |||||
| <p>Xalan 2.x (note the parameter without single quote)</p> | |||||
| <pre><style processor="trax" in="./reports/xml/results.xml" out="./reports/html/dummy.file" | |||||
| style="${ant.home}/etc/coverage-frames.xsl"> | |||||
| <param name="output.dir" expression="${basedir}/reports/html"/> | |||||
| </style></pre> | |||||
| <hr> | |||||
| <p align="center">Copyright © 2001-2002,2004-2005 The Apache Software Foundation. All rights | |||||
| Reserved.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -1,138 +0,0 @@ | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Language" content="en-us"> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>MAudit Task</title> | |||||
| </head> | |||||
| <body> | |||||
| <h2><a name="maudit">MAudit</a></h2> | |||||
| <ul> | |||||
| <li>Stephane Bailliez (<a href="mailto:sbailliez@imediation.com">sbailliez@imediation.com</a>)</li> | |||||
| </ul> | |||||
| <h3>Requirements</h3> | |||||
| <p>This task requires Metamata Development environment 2.0/Webgain Quality Analyzer 2.0. | |||||
| An evaluation version is available at <a href="http://www.webgain.com/products/quality_analyzer/">Webgain</a>. | |||||
| , <a href="http://jakarta.apache.org/oro/">Jakarta Oro</a> and a XML parser (via JAXP).</p> | |||||
| <h3>Description</h3> | |||||
| <p> | |||||
| Invokes the Metamata Audit/ Webgain Quality Analyzer on a set of Java files. | |||||
| </p> | |||||
| <p> | |||||
| <i>maudit</i> performs static analysis of the Java source code and byte code files to find and report | |||||
| errors of style and potential problems related to performance, maintenance and robustness. | |||||
| . As a convenience, a stylesheet is given in <tt>etc</tt> directory, so that an HTML report can be generated from the XML file. | |||||
| </p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | |||||
| <td valign="top"><b>Description</b></td> | |||||
| <td align="center" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">tofile</td> | |||||
| <td valign="top">The XML file to which the Audit result should be written to.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">metamatahome</td> | |||||
| <td valign="top">The home directory containing the Metamata distribution.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">fix</td> | |||||
| <td valign="top"> | |||||
| Automatically fix certain errors (those marked as fixable in the manual). | |||||
| </td> | |||||
| <td valign="top" align="center">No.Default to false.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">list</td> | |||||
| <td valign="top"> | |||||
| Creates listing file for each audited file. A .maudit file will be generated in the | |||||
| same location as the source file. | |||||
| </td> | |||||
| <td valign="top" align="center">No. Default to false.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">unused</td> | |||||
| <td valign="top"> | |||||
| Finds declarations unused in search paths. It will look for unused global declarations | |||||
| in the source code within a use domain specified by the <tt>searchpath</tt> element. | |||||
| </td> | |||||
| <td valign="top" align="center">No. Default to false.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">maxmemory</td> | |||||
| <td valign="top">Set the maximum memory for the JVM. this is a convenient | |||||
| way to set the -mx or -Xmx argument.</td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Nested elements</h3> | |||||
| <h4>jvmarg</h4> | |||||
| <p>Additional parameters may be passed to the VM via nested <code><jvmarg></code> | |||||
| attributes. <code><jvmarg></code> allows all attributes described in | |||||
| <a href="../using.html#arg">Command line arguments</a>.</p> | |||||
| <p> | |||||
| You can avoid using the <code><jvmarg></code> by adding these empty | |||||
| entries to <code>metamata.properties</code> located at <code>${metamata.home}/bin</code> | |||||
| </p> | |||||
| <pre>metamata.classpath= | |||||
| metamata.sourcepath= | |||||
| metamata.baseclasspath= | |||||
| </pre> | |||||
| </p> | |||||
| <h4>classpath</h4> | |||||
| <p>Sets class path (also source path unless one explicitly set). Overrides | |||||
| METAPATH/CLASSPATH environment variables. The <tt>classpath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>sourcepath</h4> | |||||
| <p>Sets source path. Overrides the SOURCEPATH environment variable. The <tt>sourcepath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>sourcepath</h4> | |||||
| <p>Sets the search path to use as the use domain when looking for unused global declarations. The <tt>searchpath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>fileset</h4> | |||||
| <p>Sets the Java files to audit via a <a href="../CoreTypes/fileset.html">FILESET</a> structure. | |||||
| Whatever the filter is, only the files that ends with <i>.java</i> will be included for processing. | |||||
| Note that the base directory used for the fileset MUST be the root of the source files otherwise | |||||
| package names deduced from the file path will be incorrect. | |||||
| </p> | |||||
| <h3>Example</h3> | |||||
| <pre> <maudit tofile="c:/metamata/examples/auditexamples/audit.xml" | |||||
| metamatahome="c:/metamata" fix="yes"> | |||||
| <classpath> | |||||
| <pathelement location="c:/metamata/examples/auditexamples"/> | |||||
| </classpath> | |||||
| <sourcepath> | |||||
| <pathelement location="c:/metamata/examples/auditexamples"/> | |||||
| </sourcepath> | |||||
| <fileset dir="c:/metamata/examples/auditexamples"> | |||||
| <include name="*.java"/> | |||||
| </fileset> | |||||
| </maudit></pre> | |||||
| <p> | |||||
| This invokes Metamata Audit installed in <tt>c:/metamata</tt> on the audit examples | |||||
| and fix automatically the fixable errors. | |||||
| </p> | |||||
| <h3>Generating a report</h3> | |||||
| As a convenience, there is an XSL file(mmetrics-frames.xsl) that allows you to generate a full framed HTML report of the metrics. | |||||
| You can find it in the <i>etc</i> directory of Ant. As it uses the Xalan redirect extensions, you will need Xalan and Xerces to run it. | |||||
| The stylesheet takes an <i>output.dir</i> parameter (otherwise it will be generated | |||||
| in the current directory), it can be run in Ant as follows: | |||||
| <pre> | |||||
| <style in=java "${audit.xml}" style="maudit-frames.xsl" out="null.tmp"> | |||||
| <param name="output.dir" expression="${report.dir}"/> | |||||
| </style> | |||||
| </pre> | |||||
| <hr> | |||||
| <p align="center">Copyright © 2001-2002,2004-2005 The Apache Software Foundation. All rights | |||||
| Reserved.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -1,123 +0,0 @@ | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Language" content="en-us"> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>MMetrics Task</title> | |||||
| </head> | |||||
| <body> | |||||
| <h2>MMetrics</h2> | |||||
| <ul> | |||||
| <li>Stephane Bailliez (<a href="mailto:sbailliez@imediation.com">sbailliez@imediation.com</a>)</li> | |||||
| </ul> | |||||
| <h3>Requirements</h3> | |||||
| <p>This task requires Metamata Development environment 2.0/Webgain Quality Analyzer 2.0. | |||||
| An evaluation version is available at <a href="http://www.webgain.com/products/quality_analyzer/">Webgain</a>. | |||||
| (Though you will not be able to use Metrics from the command line if you do not have a registered version). | |||||
| You also need a TRaX compliant processor(such as <a href="http://xml.apache.org/xalan-j/">Xalan 2.x</a>) via JAXP 1.1</p> | |||||
| <h3>Description</h3> | |||||
| <p> | |||||
| Invokes the Metamata Metrics / WebGain Quality Analyzer source code | |||||
| analyzer on a set of Java files. | |||||
| </p> | |||||
| <p> | |||||
| <i>mmetrics</i> will compute the metrics of a set of Java files and write the results to an XML | |||||
| file. As a convenience, a stylesheet is given in <tt>etc</tt> directory, so that an HTML report can be generated from the XML file. | |||||
| </p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | |||||
| <td valign="top"><b>Description</b></td> | |||||
| <td align="center" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">metamatahome</td> | |||||
| <td valign="top">The home directory containing the Metamata distribution.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">tofile</td> | |||||
| <td valign="top">The XML were the resulting metrics will be written to.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">granularity</td> | |||||
| <td valign="top">Metrics granularity of the source files. Must be either | |||||
| <i>files</i> (compilation-units), <i>types</i> (types and compilation-units) or <i>methods</i> | |||||
| (methods, types and compilation-units). | |||||
| </td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">maxmemory</td> | |||||
| <td valign="top">Set the maximum memory for the JVM. this is a convenient | |||||
| way to set the -mx or -Xmx argument.</td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Nested elements</h3> | |||||
| For specifying the source code to analyze, you can either use a <tt>path</tt> or <tt>fileset</tt> elements (though a single path element is preferred, see note below). | |||||
| <h4>jvmarg</h4> | |||||
| <p>Additional parameters may be passed to the VM via nested <code><jvmarg></code> | |||||
| attributes. <code><jvmarg></code> allows all attributes described in <a href="../using.html#arg">Command | |||||
| line arguments</a>.</p> | |||||
| <h4>classpath</h4> | |||||
| <p>Sets class path (also source path unless one explicitly set). Overrides | |||||
| METAPATH/CLASSPATH environment variables. The <tt>classpath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>sourcepath</h4> | |||||
| <p>Sets source path. Overrides the SOURCEPATH environment variable. The <tt>sourcepath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>path</h4> | |||||
| <p>Sets the list of directories to analyze the code for metrics.;It represents a <a href="../using.html#path">PATH structure</a>.</p> | |||||
| <h4>fileset</h4> | |||||
| <p>Sets a set of files to analyze for metrics.source It represents a <a href="../CoreTypes/fileset.html">FILESET structure</a>.</p> | |||||
| <p> | |||||
| <font color="#FF0000"> | |||||
| Note: For the sake of readability, it is highly recommended to analyze for a single unique directory instead than | |||||
| using filesets or several directories. Otherwise there will be multiple metrics outputs without any way to know | |||||
| what metrics refers to what source. Chance are also that the XML handler that does some heuristic will be confused | |||||
| by the different outputs. | |||||
| </font> | |||||
| </p> | |||||
| <h3>Example</h3> | |||||
| <pre> <mmetrics tofile="mmetrics.xml" | |||||
| metamatahome="c:/metamata" | |||||
| granularity="methods"> | |||||
| <classpath> | |||||
| <pathelement location="c:/metamata/examples/metricsexamples"/> | |||||
| </classpath> | |||||
| <sourcepath> | |||||
| <pathelement location="c:/metamata/examples/metricsexamples"/> | |||||
| </sourcepath> | |||||
| <path> | |||||
| <pathelement location="c:/metamata/examples/metricsexamples"/> | |||||
| </path> | |||||
| </mmetrics></pre> | |||||
| <p> | |||||
| This invokes Metamata Metrics installed in <tt>c:/metamata</tt> on the metrics example. | |||||
| (Note that here, classpath and sourcepath are not normally not needed) | |||||
| </p> | |||||
| <h3>Generating a report</h3> | |||||
| As a convenience, there is an XSL file(mmetrics-frames.xsl) that allows you to generate a full framed HTML report of the metrics. | |||||
| You can find it in the <i>etc</i> directory of Ant. As it uses the Xalan redirect extensions, you will need Xalan and Xerces to run it. | |||||
| The stylesheet takes an <i>output.dir</i> parameter (otherwise it will be generated | |||||
| in the current directory), it can be run in Ant as follows: | |||||
| <pre> | |||||
| <style in=java "${metrics.xml}" style="mmetrics-frames.xsl" out="null.tmp"> | |||||
| <param name="output.dir" expression="${report.dir}"/> | |||||
| </style> | |||||
| </pre> | |||||
| <hr> | |||||
| <p align="center">Copyright © 2001-2002,2004-2005 The Apache Software Foundation. All rights | |||||
| Reserved.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -1,120 +0,0 @@ | |||||
| <!-- saved from url=(0022)http://internet.e-mail --> | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Language" content="en-us"> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>MParse Task</title> | |||||
| </head> | |||||
| <body> | |||||
| <h2><a name="mparse">MParse</a></h2> | |||||
| <p>by</p> | |||||
| <ul> | |||||
| <li>Stephane Bailliez (<a href="mailto:sbailliez@imediation.com">sbailliez@imediation.com</a>)</li> | |||||
| </ul> | |||||
| <h3>Requirements</h3> | |||||
| <p>This task requires Metamata Development environment 2.0 freely available at <a href="http://www.metamata.com">Metamata</a>.</p> | |||||
| <h3>Description</h3> | |||||
| <p> | |||||
| Invokes the Metamata <a HREF="http://www.metamata.com/parse.html">MParse</a> compiler | |||||
| compiler on a grammar file. | |||||
| </p> | |||||
| <p> | |||||
| To use the <i>mparse</i> task, set the <i>target</i> attribute to the name of the | |||||
| grammar file to process. You also need to specify the directory containing | |||||
| the Metamata installation using the <i>metamatahome</i> attribute, so that Ant | |||||
| can find the MParse classes. | |||||
| </p> | |||||
| <p> | |||||
| This task only invokes MParse if the grammar file is newer than the generated | |||||
| Java files. MParse assumes that the Java class name of the generated parser | |||||
| is the same as the name of the grammar file, less the .jj extension. | |||||
| </p> | |||||
| <p>For additional information about MParse, please consult the online manual available <a href="http://download.metamata.com/parse.pdf">here</a> | |||||
| (PDF) | |||||
| </p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | |||||
| <td valign="top"><b>Description</b></td> | |||||
| <td align="center" valign="top"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">target</td> | |||||
| <td valign="top">The .jj grammar file to process. It will only be processed | |||||
| if the grammar is newer than the corresponding .java file.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">metamatahome</td> | |||||
| <td valign="top">The home directory containing the Metamata distribution.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">verbose</td> | |||||
| <td valign="top"> | |||||
| Enable all messages | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">debugparser</td> | |||||
| <td valign="top"> | |||||
| Enables parser debugging | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">debugscanner</td> | |||||
| <td valign="top"> | |||||
| Enables scanner debugging | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">cleanup</td> | |||||
| <td valign="top">Remove the intermediate Sun | |||||
| JavaCC file created during the transformation of the grammar file.</td> | |||||
| <td valign="top" align="center">No. Default to false</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">maxmemory</td> | |||||
| <td valign="top">Set the maximum memory for the JVM. this is a convenient | |||||
| way to set the -mx or -Xmx argument.</td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Nested elements</h3> | |||||
| <h4>jvmarg</h4> | |||||
| <p>Additional parameters may be passed to the VM via nested <code><jvmarg></code> | |||||
| attributes. <code><jvmarg></code> allows all attributes described in <a href="../using.html#arg">Command | |||||
| line arguments</a>.</p> | |||||
| <h4>classpath</h4> | |||||
| <p>Sets class path (also source path unless one explicitly set). Overrides | |||||
| METAPATH/CLASSPATH environment variables. The <tt>classpath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h4>sourcepath</h4> | |||||
| <p>Sets source path. Overrides the SOURCEPATH environment variable. The <tt>sourcepath</tt> element represents a <a href="../using.html#path">PATH like | |||||
| structure</a>.</p> | |||||
| <h3>Example</h3> | |||||
| <pre> <mparse target="c:/metamata/examples/parseexamples/javagrammars/singlefile/JavaParser.jj" | |||||
| metamatahome="c:/metamata" cleanup="true"> | |||||
| <classpath> | |||||
| <pathelement location="c:/metamata/examples/"/> | |||||
| </classpath> | |||||
| </mparse></pre> | |||||
| <p> | |||||
| This invokes Metamata MParse installed in <tt>c:/metamata</tt> on one of the grammar file | |||||
| example <tt>(JavaParser.jj)</tt> | |||||
| and cleans up the intermediate Sun JavaCC file. | |||||
| </p> | |||||
| <hr> | |||||
| <p align="center">Copyright © 2001,2004-2005 The Apache Software Foundation. All rights | |||||
| Reserved.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -40,13 +40,9 @@ | |||||
| <a href="OptionalTasks/jjdoc.html">JJDoc</a><br> | <a href="OptionalTasks/jjdoc.html">JJDoc</a><br> | ||||
| <a href="OptionalTasks/jjtree.html">JJTree</a><br> | <a href="OptionalTasks/jjtree.html">JJTree</a><br> | ||||
| <a href="OptionalTasks/jlink.html"><i>Jlink</i></a><br> | <a href="OptionalTasks/jlink.html"><i>Jlink</i></a><br> | ||||
| <a href="OptionalTasks/jpcoverage.html">JProbe Coverage</a><br> | |||||
| <a href="OptionalTasks/junit.html">JUnit</a><br> | <a href="OptionalTasks/junit.html">JUnit</a><br> | ||||
| <a href="OptionalTasks/junitreport.html">JUnitReport</a><br> | <a href="OptionalTasks/junitreport.html">JUnitReport</a><br> | ||||
| <a href="OptionalTasks/mmetrics.html">Metamata Metrics</a><br> | |||||
| <a href="OptionalTasks/maudit.html">Metamata Audit</a><br> | |||||
| <a href="OptionalTasks/mimemail.html"><i>MimeMail</i></a><br> | <a href="OptionalTasks/mimemail.html"><i>MimeMail</i></a><br> | ||||
| <a href="OptionalTasks/mparse.html">MParse</a><br> | |||||
| <a href="OptionalTasks/native2ascii.html">Native2Ascii</a><br> | <a href="OptionalTasks/native2ascii.html">Native2Ascii</a><br> | ||||
| <a href="OptionalTasks/netrexxc.html">NetRexxC</a><br> | <a href="OptionalTasks/netrexxc.html">NetRexxC</a><br> | ||||
| <a href="OptionalTasks/perforce.html">Perforce Tasks</a><br> | <a href="OptionalTasks/perforce.html">Perforce Tasks</a><br> | ||||
| @@ -184,29 +184,6 @@ documentation.</p> | |||||
| package".</p></td> | package".</p></td> | ||||
| </tr> | </tr> | ||||
| <tr valign="top"> | |||||
| <td nowrap><a href="OptionalTasks/jpcoverage.html">JProbe</a></td> | |||||
| <td><p>These tasks run the tools from the | |||||
| <a href="http://www.sitraka.com">JProbe</a> suite. This task was written | |||||
| using JProbe Suite Server Side 3.0.</p></td> | |||||
| </tr> | |||||
| <tr valign="top"> | |||||
| <td nowrap><a href="OptionalTasks/mmetrics.html">MMetrics</a></td> | |||||
| <td><p>Computes the metrics of a set of Java source files, using the | |||||
| <a href="http://www.webgain.com/products/quality_analyzer/"> | |||||
| Metamata Metrics/WebGain Quality Analyzer</a> source-code analyzer, | |||||
| and writes the results to an XML file.</p></td> | |||||
| </tr> | |||||
| <tr valign="top"> | |||||
| <td nowrap><a href="OptionalTasks/maudit.html">Maudit</a></td> | |||||
| <td><p>Performs static analysis on a set of Java source-code and | |||||
| byte-code files, using the | |||||
| <a href="http://www.webgain.com/products/quality_analyzer/"> | |||||
| Metamata Metrics/WebGain Quality Analyzer</a> source-code | |||||
| analyzer.</p></td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <p></p> | <p></p> | ||||
| @@ -911,12 +888,6 @@ documentation.</p> | |||||
| <td><p>Define a new task as a macro built-up upon other tasks.</p></td> | <td><p>Define a new task as a macro built-up upon other tasks.</p></td> | ||||
| </tr> | </tr> | ||||
| <tr valign="top"> | |||||
| <td nowrap><a href="OptionalTasks/mparse.html">MParse</a></td> | |||||
| <td><p>Invokes the Metamata <a HREF="http://www.metamata.com/parse.html"> | |||||
| MParse</a> compiler-compiler on a grammar file.</p></td> | |||||
| </tr> | |||||
| <tr valign="top"> | <tr valign="top"> | ||||
| <td nowrap><a href="OptionalTasks/native2ascii.html"> | <td nowrap><a href="OptionalTasks/native2ascii.html"> | ||||
| Native2Ascii</a></td> | Native2Ascii</a></td> | ||||
| @@ -132,17 +132,11 @@ javah=org.apache.tools.ant.taskdefs.optional.Javah | |||||
| jdepend=org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask | jdepend=org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask | ||||
| jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc | jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc | ||||
| jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree | jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree | ||||
| jpcoverage=org.apache.tools.ant.taskdefs.optional.sitraka.Coverage | |||||
| jpcovmerge=org.apache.tools.ant.taskdefs.optional.sitraka.CovMerge | |||||
| jpcovreport=org.apache.tools.ant.taskdefs.optional.sitraka.CovReport | |||||
| jsharpc=org.apache.tools.ant.taskdefs.optional.dotnet.JSharp | jsharpc=org.apache.tools.ant.taskdefs.optional.dotnet.JSharp | ||||
| jspc=org.apache.tools.ant.taskdefs.optional.jsp.JspC | jspc=org.apache.tools.ant.taskdefs.optional.jsp.JspC | ||||
| junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask | junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask | ||||
| junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator | junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator | ||||
| makeurl=org.apache.tools.ant.taskdefs.MakeUrl | makeurl=org.apache.tools.ant.taskdefs.MakeUrl | ||||
| maudit=org.apache.tools.ant.taskdefs.optional.metamata.MAudit | |||||
| mmetrics=org.apache.tools.ant.taskdefs.optional.metamata.MMetrics | |||||
| mparse=org.apache.tools.ant.taskdefs.optional.metamata.MParse | |||||
| native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii | native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii | ||||
| netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC | netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC | ||||
| p4add=org.apache.tools.ant.taskdefs.optional.perforce.P4Add | p4add=org.apache.tools.ant.taskdefs.optional.perforce.P4Add | ||||
| @@ -1,350 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.File; | |||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | |||||
| import java.io.PrintWriter; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.DirectoryScanner; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.taskdefs.Execute; | |||||
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; | |||||
| import org.apache.tools.ant.types.Commandline; | |||||
| import org.apache.tools.ant.types.CommandlineJava; | |||||
| import org.apache.tools.ant.types.FileSet; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||||
| /** | |||||
| * Somewhat abstract framework to be used for other metama 2.0 tasks. | |||||
| * This should include, audit, metrics, cover and mparse. | |||||
| * | |||||
| * For more information, visit the website at | |||||
| * <a href="http://www.metamata.com">www.metamata.com</a> | |||||
| * | |||||
| */ | |||||
| public abstract class AbstractMetamataTask extends Task { | |||||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||||
| /** | |||||
| * The user classpath to be provided. It matches the -classpath of the | |||||
| * command line. The classpath must includes both the <tt>.class</tt> and the | |||||
| * <tt>.java</tt> files for accurate audit. | |||||
| */ | |||||
| protected Path classPath = null; | |||||
| /** the path to the source file */ | |||||
| protected Path sourcePath = null; | |||||
| /** | |||||
| * Metamata home directory. It will be passed as a <tt>metamata.home</tt> property | |||||
| * and should normally matches the environment property <tt>META_HOME</tt> | |||||
| * set by the Metamata installer. | |||||
| */ | |||||
| protected File metamataHome = null; | |||||
| /** the command line used to run MAudit */ | |||||
| protected CommandlineJava cmdl = new CommandlineJava(); | |||||
| /** the set of files to be audited */ | |||||
| protected Vector fileSets = new Vector(); | |||||
| /** the options file where are stored the command line options */ | |||||
| protected File optionsFile = null; | |||||
| // this is used to keep track of which files were included. It will | |||||
| // be set when calling scanFileSets(); | |||||
| protected Hashtable includedFiles = null; | |||||
| public AbstractMetamataTask() { | |||||
| } | |||||
| /** initialize the task with the classname of the task to run */ | |||||
| protected AbstractMetamataTask(String className) { | |||||
| cmdl.setVm(JavaEnvUtils.getJreExecutable("java")); | |||||
| cmdl.setClassname(className); | |||||
| } | |||||
| /** | |||||
| * the metamata.home property to run all tasks. | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setHome(final File value) { | |||||
| this.metamataHome = value; | |||||
| } | |||||
| /** | |||||
| * The home directory containing the Metamata distribution; required | |||||
| */ | |||||
| public void setMetamatahome(final File value) { | |||||
| setHome(value); | |||||
| } | |||||
| /** | |||||
| * Sets the class path (also source path unless one explicitly set). | |||||
| * Overrides METAPATH/CLASSPATH environment variables. | |||||
| */ | |||||
| public Path createClasspath() { | |||||
| if (classPath == null) { | |||||
| classPath = new Path(getProject()); | |||||
| } | |||||
| return classPath; | |||||
| } | |||||
| /** | |||||
| * Sets the source path. | |||||
| * Overrides the SOURCEPATH environment variable. | |||||
| */ | |||||
| public Path createSourcepath() { | |||||
| if (sourcePath == null) { | |||||
| sourcePath = new Path(getProject()); | |||||
| } | |||||
| return sourcePath; | |||||
| } | |||||
| /** | |||||
| * Additional optional parameters to pass to the JVM. | |||||
| * You can avoid using the <code><jvmarg></code> by adding these empty | |||||
| * entries to <code>metamata.properties</code> located at <code>${metamata.home}/bin</code> | |||||
| * | |||||
| * <pre>metamata.classpath= | |||||
| * metamata.sourcepath= | |||||
| * metamata.baseclasspath= | |||||
| * </pre> | |||||
| */ | |||||
| public Commandline.Argument createJvmarg() { | |||||
| return cmdl.createVmArgument(); | |||||
| } | |||||
| /** | |||||
| * Set the maximum memory for the JVM; optional. | |||||
| * -mx or -Xmx depending on VM version | |||||
| */ | |||||
| public void setMaxmemory(String max) { | |||||
| cmdl.setMaxmemory(max); | |||||
| } | |||||
| /** | |||||
| * The java files or directory to audit. | |||||
| * Whatever the filter is, only the files that end | |||||
| * with .java will be included for processing. | |||||
| * Note that the base directory used for the fileset | |||||
| * MUST be the root of the source files otherwise package names | |||||
| * deduced from the file path will be incorrect. | |||||
| */ | |||||
| public void addFileSet(FileSet fs) { | |||||
| fileSets.addElement(fs); | |||||
| } | |||||
| /** execute the command line */ | |||||
| public void execute() throws BuildException { | |||||
| try { | |||||
| setUp(); | |||||
| ExecuteStreamHandler handler = createStreamHandler(); | |||||
| execute0(handler); | |||||
| } finally { | |||||
| cleanUp(); | |||||
| } | |||||
| } | |||||
| /** check the options and build the command line */ | |||||
| protected void setUp() throws BuildException { | |||||
| checkOptions(); | |||||
| // set the classpath as the jar file | |||||
| File jar = getMetamataJar(metamataHome); | |||||
| final Path cp = cmdl.createClasspath(getProject()); | |||||
| cp.createPathElement().setLocation(jar); | |||||
| // set the metamata.home property | |||||
| final Commandline.Argument vmArgs = cmdl.createVmArgument(); | |||||
| vmArgs.setValue("-Dmetamata.home=" + metamataHome.getAbsolutePath()); | |||||
| // retrieve all the files we want to scan | |||||
| includedFiles = scanSources(new Hashtable()); | |||||
| //String[] entries = sourcePath.list(); | |||||
| //includedFiles = scanSources(new Hashtable(), entries); | |||||
| log(includedFiles.size() + " files added for audit", Project.MSG_VERBOSE); | |||||
| // write all the options to a temp file and use it ro run the process | |||||
| Vector options = getOptions(); | |||||
| optionsFile = createTmpFile(); | |||||
| generateOptionsFile(optionsFile, options); | |||||
| Commandline.Argument args = cmdl.createArgument(); | |||||
| args.setLine("-arguments " + optionsFile.getAbsolutePath()); | |||||
| } | |||||
| /** | |||||
| * create a stream handler that will be used to get the output since | |||||
| * metamata tools do not report with convenient files such as XML. | |||||
| */ | |||||
| protected abstract ExecuteStreamHandler createStreamHandler(); | |||||
| /** execute the process with a specific handler */ | |||||
| protected void execute0(ExecuteStreamHandler handler) throws BuildException { | |||||
| final Execute process = new Execute(handler); | |||||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||||
| process.setCommandline(cmdl.getCommandline()); | |||||
| try { | |||||
| if (process.execute() != 0) { | |||||
| throw new BuildException("Metamata task failed."); | |||||
| } | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Failed to launch Metamata task", e); | |||||
| } | |||||
| } | |||||
| /** clean up all the mess that we did with temporary objects */ | |||||
| protected void cleanUp() { | |||||
| if (optionsFile != null) { | |||||
| optionsFile.delete(); | |||||
| optionsFile = null; | |||||
| } | |||||
| } | |||||
| /** return the location of the jar file used to run */ | |||||
| protected final File getMetamataJar(File home) { | |||||
| return new File(home, "lib/metamata.jar"); | |||||
| } | |||||
| /** validate options set */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| // do some validation first | |||||
| if (metamataHome == null || !metamataHome.exists()) { | |||||
| throw new BuildException("'home' must point to Metamata home directory."); | |||||
| } | |||||
| File jar = getMetamataJar(metamataHome); | |||||
| if (!jar.exists()) { | |||||
| throw new BuildException(jar + " does not exist. Check your metamata installation."); | |||||
| } | |||||
| } | |||||
| /** return all options of the command line as string elements */ | |||||
| protected abstract Vector getOptions(); | |||||
| protected void generateOptionsFile(File tofile, Vector options) throws BuildException { | |||||
| FileWriter fw = null; | |||||
| try { | |||||
| fw = new FileWriter(tofile); | |||||
| PrintWriter pw = new PrintWriter(fw); | |||||
| final int size = options.size(); | |||||
| for (int i = 0; i < size; i++) { | |||||
| pw.println(options.elementAt(i)); | |||||
| } | |||||
| pw.flush(); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Error while writing options file " + tofile, e); | |||||
| } finally { | |||||
| if (fw != null) { | |||||
| try { | |||||
| fw.close(); | |||||
| } catch (IOException ignored) { | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| protected Hashtable getFileMapping() { | |||||
| return includedFiles; | |||||
| } | |||||
| /** | |||||
| * convenient method for JDK 1.1. Will copy all elements from src to dest | |||||
| */ | |||||
| protected static final void addAllVector(Vector dest, Enumeration files) { | |||||
| while (files.hasMoreElements()) { | |||||
| dest.addElement(files.nextElement()); | |||||
| } | |||||
| } | |||||
| protected final File createTmpFile() { | |||||
| File tmpFile = FILE_UTILS | |||||
| .createTempFile("metamata", ".tmp", getProject().getBaseDir()); | |||||
| tmpFile.deleteOnExit(); | |||||
| return tmpFile; | |||||
| } | |||||
| /** | |||||
| * @return the list of .java files (as their absolute path) that should | |||||
| * be audited. | |||||
| */ | |||||
| protected Hashtable scanSources(Hashtable map) { | |||||
| Hashtable files = new Hashtable(); | |||||
| for (int i = 0; i < fileSets.size(); i++) { | |||||
| FileSet fs = (FileSet) fileSets.elementAt(i); | |||||
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||||
| ds.scan(); | |||||
| String[] f = ds.getIncludedFiles(); | |||||
| log(i + ") Adding " + f.length + " files from directory " | |||||
| + ds.getBasedir(), Project.MSG_VERBOSE); | |||||
| for (int j = 0; j < f.length; j++) { | |||||
| String pathname = f[j]; | |||||
| if (pathname.endsWith(".java")) { | |||||
| File file = new File(ds.getBasedir(), pathname); | |||||
| // file = project.resolveFile(file.getAbsolutePath()); | |||||
| String classname = pathname.substring(0, pathname.length() - ".java".length()); | |||||
| classname = classname.replace(File.separatorChar, '.'); | |||||
| files.put(file.getAbsolutePath(), classname); // it's a java file, add it. | |||||
| } | |||||
| } | |||||
| } | |||||
| return files; | |||||
| } | |||||
| protected Hashtable scanSources(final Hashtable mapping, final String[] entries) { | |||||
| final Vector javaFiles = new Vector(512); | |||||
| for (int i = 0; i < entries.length; i++) { | |||||
| final File f = new File(entries[i]); | |||||
| if (f.isDirectory()) { | |||||
| DirectoryScanner ds = new DirectoryScanner(); | |||||
| ds.setBasedir(f); | |||||
| ds.setIncludes(new String[]{"**/*.java"}); | |||||
| ds.scan(); | |||||
| String[] included = ds.getIncludedFiles(); | |||||
| for (int j = 0; j < included.length; j++) { | |||||
| javaFiles.addElement(new File(f, included[j])); | |||||
| } | |||||
| } else if (entries[i].endsWith(".java")) { | |||||
| javaFiles.addElement(f); | |||||
| } | |||||
| } | |||||
| // do the mapping paths/classname | |||||
| final int count = javaFiles.size(); | |||||
| for (int i = 0; i < count; i++) { | |||||
| File file = (File) javaFiles.elementAt(i); | |||||
| String pathname = Path.translateFile(file.getAbsolutePath()); | |||||
| String classname = pathname.substring(0, pathname.length() - ".java".length()); | |||||
| classname = classname.replace(File.separatorChar, '.'); | |||||
| mapping.put(pathname, classname); | |||||
| } | |||||
| return mapping; | |||||
| } | |||||
| } | |||||
| @@ -1,320 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.File; | |||||
| import java.io.FileOutputStream; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| 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.FileSet; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| /** | |||||
| * Invokes the Metamata Audit/ Webgain Quality Analyzer on a set of Java files. | |||||
| * <p> | |||||
| * <i>maudit</i> performs static analysis of the Java source code and byte | |||||
| * code files to find and report errors of style and potential problems related | |||||
| * to performance, maintenance and robustness. As a convenience, a stylesheet | |||||
| * is given in <tt>etc</tt> directory, so that an HTML report can be generated | |||||
| * from the XML file. | |||||
| * | |||||
| */ | |||||
| public class MAudit extends AbstractMetamataTask { | |||||
| /* As of Metamata 2.0, the command line of MAudit is as follows: | |||||
| Usage | |||||
| maudit <option>... <path>... [-unused <search-path>...] | |||||
| Parameters | |||||
| path File or directory to audit. | |||||
| search-path File or directory to search for declaration uses. | |||||
| 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. | |||||
| -exit -x Exits after the first error. | |||||
| -fix -f Automatically fixes certain errors. | |||||
| -fullpath Prints full path for locations. | |||||
| -help -h Prints help and exits. | |||||
| -list -l Creates listing file for each audited file. | |||||
| -offsets -off Offset and length for locations. | |||||
| -output -o <file> Prints output to file. | |||||
| -quiet -q Suppresses copyright and summary messages. | |||||
| -sourcepath <path> Sets source path. Overrides SOURCEPATH. | |||||
| -tab -t Prints a tab character after first argument. | |||||
| -unused -u Finds declarations unused in search paths. | |||||
| -verbose -v Prints all messages. | |||||
| -version -V Prints version and exits. | |||||
| */ | |||||
| //---------------------- PUBLIC METHODS ------------------------------------ | |||||
| /** pattern used by maudit to report the error for a file */ | |||||
| /** RE does not seems to support regexp pattern with comments so i'm stripping it*/ | |||||
| // (?:file:)?((?#filepath).+):((?#line)\\d+)\\s*:\\s+((?#message).*) | |||||
| static final String AUDIT_PATTERN = "(?:file:)?(.+):(\\d+)\\s*:\\s+(.*)"; | |||||
| private File outFile = null; | |||||
| private Path searchPath = null; | |||||
| private Path rulesPath = null; | |||||
| private boolean fix = false; | |||||
| private boolean list = false; | |||||
| private boolean unused = false; | |||||
| // add a bunch of undocumented options for the task | |||||
| private boolean quiet = false; | |||||
| private boolean exit = false; | |||||
| private boolean offsets = false; | |||||
| private boolean verbose = false; | |||||
| private boolean fullsemanticize = false; | |||||
| /** default constructor */ | |||||
| public MAudit() { | |||||
| super("com.metamata.gui.rc.MAudit"); | |||||
| } | |||||
| /** | |||||
| * The XML file to which the Audit result should be written to; required | |||||
| */ | |||||
| public void setTofile(File outFile) { | |||||
| this.outFile = outFile; | |||||
| } | |||||
| /** | |||||
| * Automatically fix certain errors | |||||
| * (those marked as fixable in the manual); | |||||
| * optional, default=false | |||||
| */ | |||||
| public void setFix(boolean flag) { | |||||
| this.fix = flag; | |||||
| } | |||||
| /** | |||||
| * Creates listing file for each audited file; optional, default false. | |||||
| * When set, a .maudit file will be generated in the | |||||
| * same location as the source file. | |||||
| */ | |||||
| public void setList(boolean flag) { | |||||
| this.list = flag; | |||||
| } | |||||
| /** | |||||
| * Finds declarations unused in search paths; optional, default false. | |||||
| * It will look for unused global declarations | |||||
| * in the source code within a use domain specified by the | |||||
| * <tt>searchpath</tt> element. | |||||
| */ | |||||
| public void setUnused(boolean flag) { | |||||
| this.unused = flag; | |||||
| } | |||||
| /** | |||||
| * flag to suppress copyright and summary messages; default false. | |||||
| * internal/testing only | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setQuiet(boolean flag) { | |||||
| this.quiet = flag; | |||||
| } | |||||
| /** | |||||
| * flag to tell the task to exit after the first error. | |||||
| * internal/testing only | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setExit(boolean flag) { | |||||
| this.exit = flag; | |||||
| } | |||||
| /** | |||||
| * internal/testing only | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setOffsets(boolean flag) { | |||||
| this.offsets = flag; | |||||
| } | |||||
| /** | |||||
| * flag to print all messages; optional, default false. | |||||
| * internal/testing only | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setVerbose(boolean flag) { | |||||
| this.verbose = flag; | |||||
| } | |||||
| /** | |||||
| * internal/testing only | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setFullsemanticize(boolean flag) { | |||||
| this.fullsemanticize = flag; | |||||
| } | |||||
| /** | |||||
| * classpath for additional audit rules | |||||
| * these must be placed before metamata.jar !! | |||||
| */ | |||||
| public Path createRulespath() { | |||||
| if (rulesPath == null) { | |||||
| rulesPath = new Path(getProject()); | |||||
| } | |||||
| return rulesPath; | |||||
| } | |||||
| /** | |||||
| * search path to use for unused global declarations; | |||||
| * required when <tt>unused</tt> is set. | |||||
| */ | |||||
| public Path createSearchpath() { | |||||
| if (searchPath == null) { | |||||
| searchPath = new Path(getProject()); | |||||
| } | |||||
| return searchPath; | |||||
| } | |||||
| /** | |||||
| * create the option vector for the command | |||||
| */ | |||||
| protected Vector getOptions() { | |||||
| Vector options = new Vector(512); | |||||
| // add the source path automatically from the fileset. | |||||
| // to avoid redundancy... | |||||
| for (int i = 0; i < fileSets.size(); i++) { | |||||
| FileSet fs = (FileSet) fileSets.elementAt(i); | |||||
| Path path = createSourcepath(); | |||||
| File dir = fs.getDir(getProject()); | |||||
| path.setLocation(dir); | |||||
| } | |||||
| // 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()); | |||||
| } | |||||
| // suppress copyright msg when running, we will let it so that this | |||||
| // will be the only output to the console if in xml mode | |||||
| if (quiet) { | |||||
| options.addElement("-quiet"); | |||||
| } | |||||
| if (fullsemanticize) { | |||||
| options.addElement("-full-semanticize"); | |||||
| } | |||||
| if (verbose) { | |||||
| options.addElement("-verbose"); | |||||
| } | |||||
| if (offsets) { | |||||
| options.addElement("-offsets"); | |||||
| } | |||||
| if (exit) { | |||||
| options.addElement("-exit"); | |||||
| } | |||||
| if (fix) { | |||||
| options.addElement("-fix"); | |||||
| } | |||||
| options.addElement("-fullpath"); | |||||
| // generate .maudit files much more detailed than the report | |||||
| // I don't like it very much, I think it could be interesting | |||||
| // to get all .maudit files and include them in the XML. | |||||
| if (list) { | |||||
| options.addElement("-list"); | |||||
| } | |||||
| if (sourcePath != null) { | |||||
| options.addElement("-sourcepath"); | |||||
| options.addElement(sourcePath.toString()); | |||||
| } | |||||
| addAllVector(options, includedFiles.keys()); | |||||
| if (unused) { | |||||
| options.addElement("-unused"); | |||||
| options.addElement(searchPath.toString()); | |||||
| } | |||||
| return options; | |||||
| } | |||||
| /** | |||||
| * validate the settings | |||||
| */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| super.checkOptions(); | |||||
| if (unused && searchPath == null) { | |||||
| throw new BuildException("'searchpath' element must be set when " | |||||
| + "looking for 'unused' declarations."); | |||||
| } | |||||
| if (!unused && searchPath != null) { | |||||
| log("'searchpath' element ignored. 'unused' attribute is disabled.", | |||||
| Project.MSG_WARN); | |||||
| } | |||||
| if (rulesPath != null) { | |||||
| cmdl.createClasspath(getProject()).addExisting(rulesPath); | |||||
| } | |||||
| } | |||||
| protected ExecuteStreamHandler createStreamHandler() throws BuildException { | |||||
| // if we didn't specify a file, then use a screen report | |||||
| if (outFile == null) { | |||||
| return new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_ERR); | |||||
| } | |||||
| ExecuteStreamHandler handler = null; | |||||
| OutputStream out = null; | |||||
| try { | |||||
| out = new FileOutputStream(outFile); | |||||
| handler = new MAuditStreamHandler(this, out); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException(e); | |||||
| } finally { | |||||
| FileUtils.close(out); | |||||
| } | |||||
| return handler; | |||||
| } | |||||
| protected void cleanUp() throws BuildException { | |||||
| super.cleanUp(); | |||||
| // at this point if -list is used, we should move | |||||
| // the .maudit file since we cannot choose their location :( | |||||
| // the .maudit files match the .java files | |||||
| // we'll use includedFiles to get the .maudit files. | |||||
| /*if (out != null) { | |||||
| // close it if not closed by the handler... | |||||
| }*/ | |||||
| } | |||||
| } | |||||
| @@ -1,86 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.File; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.util.StringUtils; | |||||
| import org.apache.tools.ant.util.regexp.RegexpMatcher; | |||||
| import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; | |||||
| /** | |||||
| * Parser that will parse an output line of MAudit and return an | |||||
| * interpreted violation if any. | |||||
| * | |||||
| * <p> | |||||
| * MAudit is supposed to be configured with -fullpath so that it can | |||||
| * correctly locate the file and attribute violation to the appropriate | |||||
| * file (there might be several classes with the same name in | |||||
| * different packages) | |||||
| * </p> | |||||
| * | |||||
| */ | |||||
| final class MAuditParser { | |||||
| /** pattern used by maudit to report the error for a file */ | |||||
| /** RE does not seems to support regexp pattern with comments so i'm stripping it*/ | |||||
| // (?:file:)?((?#filepath).+):((?#line)\\d+)\\s*:\\s+((?#message).*) | |||||
| private static final String AUDIT_PATTERN = "(?:file:)?(.+):(\\d+)\\s*:\\s+(.*)"; | |||||
| /** matcher that will be used to extract the info from the line */ | |||||
| private final RegexpMatcher matcher; | |||||
| MAuditParser() { | |||||
| /** the matcher should be the Oro one. I don't know about the other one */ | |||||
| matcher = (new RegexpMatcherFactory()).newRegexpMatcher(); | |||||
| matcher.setPattern(AUDIT_PATTERN); | |||||
| } | |||||
| /** | |||||
| * Parse a line obtained from MAudit. | |||||
| * @param line a line obtained from the MAudit output. | |||||
| * @return the violation corresponding to the displayed line | |||||
| * or <tt>null</tt> if it could not parse it. (might be a | |||||
| * message info or copyright or summary). | |||||
| */ | |||||
| Violation parseLine(String line) { | |||||
| Vector matches = matcher.getGroups(line); | |||||
| if (matches == null) { | |||||
| return null; | |||||
| } | |||||
| final String file = (String) matches.elementAt(1); | |||||
| Violation violation = new Violation(); | |||||
| violation.file = file; | |||||
| violation.line = (String) matches.elementAt(2); | |||||
| violation.error = (String) matches.elementAt(3); | |||||
| // remove the pathname from any messages and let the classname only. | |||||
| final int pos = file.lastIndexOf(File.separatorChar); | |||||
| if ((pos != -1) && (pos != file.length() - 1)) { | |||||
| String filename = file.substring(pos + 1); | |||||
| violation.error = StringUtils.replace(violation.error, | |||||
| "file:" + file, filename); | |||||
| } | |||||
| return violation; | |||||
| } | |||||
| /** the inner class used to report violation information */ | |||||
| static final class Violation { | |||||
| String file; | |||||
| String line; | |||||
| String error; | |||||
| } | |||||
| } | |||||
| @@ -1,226 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.BufferedReader; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.io.InputStreamReader; | |||||
| import java.io.OutputStream; | |||||
| import java.util.Date; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Vector; | |||||
| import javax.xml.parsers.DocumentBuilder; | |||||
| import javax.xml.parsers.DocumentBuilderFactory; | |||||
| 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.LogOutputStream; | |||||
| import org.apache.tools.ant.taskdefs.StreamPumper; | |||||
| import org.apache.tools.ant.util.DOMElementWriter; | |||||
| import org.apache.tools.ant.util.DateUtils; | |||||
| import org.w3c.dom.Document; | |||||
| import org.w3c.dom.Element; | |||||
| /** | |||||
| * This is a very bad stream handler for the MAudit task. | |||||
| * All report to stdout that does not match a specific report pattern is dumped | |||||
| * to the Ant output as warn level. The report that match the pattern is stored | |||||
| * in a map with the key being the filepath that caused the error report. | |||||
| * <p> | |||||
| * The limitation with the choosen implementation is clear: | |||||
| * <ul> | |||||
| * <li>it does not handle multiline report( message that has \n ). the part until | |||||
| * the \n will be stored and the other part (which will not match the pattern) | |||||
| * will go to Ant output in Warn level. | |||||
| * <li>it does not report error that goes to stderr. | |||||
| * </ul> | |||||
| * | |||||
| */ | |||||
| class MAuditStreamHandler implements ExecuteStreamHandler { | |||||
| /** parent task */ | |||||
| private MAudit task; | |||||
| /** reader for stdout */ | |||||
| private BufferedReader br; | |||||
| /** | |||||
| * this is where the XML output will go, should mostly be a file | |||||
| * the caller is responsible for flushing and closing this stream | |||||
| */ | |||||
| private OutputStream xmlOut = null; | |||||
| /** error stream, might be useful to spit out error messages */ | |||||
| private OutputStream errStream; | |||||
| /** thread pumping out error stream */ | |||||
| private Thread errThread; | |||||
| /** | |||||
| * the multimap. The key in the map is the filepath that caused the audit | |||||
| * error and the value is a vector of MAudit.Violation entries. | |||||
| */ | |||||
| private Hashtable auditedFiles = new Hashtable(); | |||||
| /** program start timestamp for reporting purpose */ | |||||
| private Date program_start; | |||||
| MAuditStreamHandler(MAudit task, OutputStream xmlOut) { | |||||
| this.task = task; | |||||
| this.xmlOut = xmlOut; | |||||
| } | |||||
| /** Ignore. */ | |||||
| public void setProcessInputStream(OutputStream os) { | |||||
| } | |||||
| /** Ignore. */ | |||||
| public void setProcessErrorStream(InputStream is) { | |||||
| errStream = new LogOutputStream(task, Project.MSG_ERR); | |||||
| errThread = createPump(is, errStream); | |||||
| } | |||||
| /** Set the inputstream */ | |||||
| public void setProcessOutputStream(InputStream is) throws IOException { | |||||
| br = new BufferedReader(new InputStreamReader(is)); | |||||
| } | |||||
| /** Invokes parseOutput. This will block until the end :-(*/ | |||||
| public void start() throws IOException { | |||||
| program_start = new Date(); | |||||
| errThread.start(); | |||||
| parseOutput(br); | |||||
| } | |||||
| /** | |||||
| * Pretty dangerous business here. It serializes what was extracted from | |||||
| * the MAudit output and write it to the output. | |||||
| */ | |||||
| public void stop() { | |||||
| // make sure to flush err stream | |||||
| try { | |||||
| errThread.join(); | |||||
| } catch (InterruptedException e) { | |||||
| } | |||||
| try { | |||||
| errStream.flush(); | |||||
| } catch (IOException e) { | |||||
| } | |||||
| // serialize the content as XML, move this to another method | |||||
| // this is the only code that could be needed to be overriden | |||||
| Document doc = getDocumentBuilder().newDocument(); | |||||
| Element rootElement = doc.createElement("classes"); | |||||
| Enumeration keys = auditedFiles.keys(); | |||||
| Hashtable filemapping = task.getFileMapping(); | |||||
| final Date now = new Date(); | |||||
| rootElement.setAttribute("snapshot_created", | |||||
| DateUtils.format(now, DateUtils.ISO8601_DATETIME_PATTERN)); | |||||
| rootElement.setAttribute("elapsed_time", | |||||
| String.valueOf(now.getTime() - program_start.getTime())); | |||||
| rootElement.setAttribute("program_start", | |||||
| DateUtils.format(now, DateUtils.ISO8601_DATETIME_PATTERN)); | |||||
| rootElement.setAttribute("audited", | |||||
| String.valueOf(filemapping.size())); | |||||
| rootElement.setAttribute("reported", | |||||
| String.valueOf(auditedFiles.size())); | |||||
| int errors = 0; | |||||
| while (keys.hasMoreElements()) { | |||||
| String filepath = (String) keys.nextElement(); | |||||
| Vector v = (Vector) auditedFiles.get(filepath); | |||||
| String fullclassname = (String) filemapping.get(filepath); | |||||
| if (fullclassname == null) { | |||||
| task.getProject().log("Could not find class mapping for " | |||||
| + filepath, Project.MSG_WARN); | |||||
| continue; | |||||
| } | |||||
| int pos = fullclassname.lastIndexOf('.'); | |||||
| String pkg = (pos == -1) ? "" : fullclassname.substring(0, pos); | |||||
| String clazzname = (pos == -1) ? fullclassname : fullclassname.substring(pos + 1); | |||||
| Element clazz = doc.createElement("class"); | |||||
| clazz.setAttribute("package", pkg); | |||||
| clazz.setAttribute("name", clazzname); | |||||
| final int violationCount = v.size(); | |||||
| clazz.setAttribute("violations", String.valueOf(violationCount)); | |||||
| errors += violationCount; | |||||
| for (int i = 0; i < violationCount; i++) { | |||||
| MAuditParser.Violation violation = (MAuditParser.Violation) v.elementAt(i); | |||||
| Element error = doc.createElement("violation"); | |||||
| error.setAttribute("line", violation.line); | |||||
| error.setAttribute("message", violation.error); | |||||
| clazz.appendChild(error); | |||||
| } | |||||
| rootElement.appendChild(clazz); | |||||
| } | |||||
| rootElement.setAttribute("violations", String.valueOf(errors)); | |||||
| // now write it to the outputstream, not very nice code | |||||
| DOMElementWriter domWriter = new DOMElementWriter(); | |||||
| try { | |||||
| domWriter.write(rootElement, xmlOut); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException(e); | |||||
| } | |||||
| } | |||||
| protected static DocumentBuilder getDocumentBuilder() { | |||||
| try { | |||||
| return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||||
| } catch (Exception exc) { | |||||
| throw new ExceptionInInitializerError(exc); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a stream pumper to copy the given input stream to the given output stream. | |||||
| */ | |||||
| protected Thread createPump(InputStream is, OutputStream os) { | |||||
| final Thread result = new Thread(new StreamPumper(is, os)); | |||||
| result.setDaemon(true); | |||||
| return result; | |||||
| } | |||||
| /** read each line and process it */ | |||||
| protected void parseOutput(BufferedReader br) throws IOException { | |||||
| String line = null; | |||||
| final MAuditParser parser = new MAuditParser(); | |||||
| while ((line = br.readLine()) != null) { | |||||
| final MAuditParser.Violation violation = parser.parseLine(line); | |||||
| if (violation != null) { | |||||
| addViolation(violation.file, violation); | |||||
| } else { | |||||
| // this doesn't match..report it as info, it could be | |||||
| // either the copyright, summary or a multiline message (damn !) | |||||
| task.log(line, Project.MSG_INFO); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** add a violation entry for the file */ | |||||
| private void addViolation(String file, MAuditParser.Violation entry) { | |||||
| Vector violations = (Vector) auditedFiles.get(file); | |||||
| // if there is no decl for this file yet, create it. | |||||
| if (violations == null) { | |||||
| violations = new Vector(); | |||||
| auditedFiles.put(file, violations); | |||||
| } | |||||
| violations.addElement(entry); | |||||
| } | |||||
| } | |||||
| @@ -1,265 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| 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; | |||||
| /** | |||||
| * Computes the metrics of a set of Java files and write the results to an XML | |||||
| * file. As a convenience, a stylesheet is given in <tt>etc</tt> directory, | |||||
| * so that an HTML report can be generated from the XML file. | |||||
| * <p> | |||||
| * 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 :-( | |||||
| * | |||||
| * | |||||
| */ | |||||
| 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(getProject()); | |||||
| } | |||||
| 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; | |||||
| } | |||||
| } | |||||
| @@ -1,409 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.BufferedReader; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.io.InputStreamReader; | |||||
| import java.io.OutputStream; | |||||
| import java.io.OutputStreamWriter; | |||||
| import java.text.DecimalFormat; | |||||
| import java.text.NumberFormat; | |||||
| import java.text.ParseException; | |||||
| import java.util.Date; | |||||
| import java.util.EmptyStackException; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Stack; | |||||
| import java.util.Vector; | |||||
| import javax.xml.transform.OutputKeys; | |||||
| import javax.xml.transform.Transformer; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.sax.SAXTransformerFactory; | |||||
| import javax.xml.transform.sax.TransformerHandler; | |||||
| import javax.xml.transform.stream.StreamResult; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; | |||||
| import org.apache.tools.ant.util.DateUtils; | |||||
| import org.xml.sax.Attributes; | |||||
| import org.xml.sax.SAXException; | |||||
| import org.xml.sax.helpers.AttributesImpl; | |||||
| /** | |||||
| * A handy metrics handler. Most of this code was done only with the | |||||
| * screenshots on the documentation since the evaluation version as | |||||
| * of this writing does not allow to save metrics or to run it via | |||||
| * command line. | |||||
| * <p> | |||||
| * This class can be used to transform a text file or to process the | |||||
| * output stream directly. | |||||
| * | |||||
| */ | |||||
| public class MMetricsStreamHandler implements ExecuteStreamHandler { | |||||
| /** CLASS construct, it should be named something like 'MyClass' */ | |||||
| private static final String CLASS = "class"; | |||||
| /** package construct, it should be look like 'com.mycompany.something' */ | |||||
| private static final String PACKAGE = "package"; | |||||
| /** FILE construct, it should look like something 'MyClass.java' or 'MyClass.class' */ | |||||
| private static final String FILE = "file"; | |||||
| /** METHOD construct, it should looke like something 'doSomething(...)' or 'doSomething()' */ | |||||
| private static final String METHOD = "method"; | |||||
| private static final String[] ATTRIBUTES = { | |||||
| "name", "vg", "loc", "dit", "noa", "nrm", "nlm", "wmc", | |||||
| "rfc", "dac", "fanout", "cbo", "lcom", "nocl"}; | |||||
| /** reader for stdout */ | |||||
| private InputStream metricsOutput; | |||||
| /** | |||||
| * this is where the XML output will go, should mostly be a file | |||||
| * the caller is responsible for flushing and closing this stream | |||||
| */ | |||||
| private OutputStream xmlOutputStream; | |||||
| /** metrics handler */ | |||||
| private TransformerHandler metricsHandler; | |||||
| /** the task */ | |||||
| private Task task; | |||||
| /** | |||||
| * the stack where are stored the metrics element so that they we can | |||||
| * know if we have to close an element or not. | |||||
| */ | |||||
| private Stack stack = new Stack(); | |||||
| /** initialize this handler */ | |||||
| MMetricsStreamHandler(Task task, OutputStream xmlOut) { | |||||
| this.task = task; | |||||
| this.xmlOutputStream = xmlOut; | |||||
| } | |||||
| /** Ignore. */ | |||||
| public void setProcessInputStream(OutputStream p1) throws IOException { | |||||
| } | |||||
| /** Ignore. */ | |||||
| public void setProcessErrorStream(InputStream p1) throws IOException { | |||||
| } | |||||
| /** Set the inputstream */ | |||||
| public void setProcessOutputStream(InputStream is) throws IOException { | |||||
| metricsOutput = is; | |||||
| } | |||||
| public void start() throws IOException { | |||||
| // create the transformer handler that will be used to serialize | |||||
| // the output. | |||||
| TransformerFactory factory = TransformerFactory.newInstance(); | |||||
| if (!factory.getFeature(SAXTransformerFactory.FEATURE)) { | |||||
| throw new IllegalStateException("Invalid Transformer factory feature"); | |||||
| } | |||||
| try { | |||||
| metricsHandler = ((SAXTransformerFactory) factory).newTransformerHandler(); | |||||
| metricsHandler.setResult(new StreamResult(new OutputStreamWriter(xmlOutputStream, "UTF-8"))); | |||||
| Transformer transformer = metricsHandler.getTransformer(); | |||||
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); | |||||
| // start the document with a 'metrics' root | |||||
| final Date now = new Date(); | |||||
| metricsHandler.startDocument(); | |||||
| AttributesImpl attr = new AttributesImpl(); | |||||
| attr.addAttribute("", "company", "company", "CDATA", "metamata"); | |||||
| attr.addAttribute("", "snapshot_created", "snapshot_created", "CDATA", | |||||
| DateUtils.format(now, DateUtils.ISO8601_DATETIME_PATTERN)); | |||||
| // attr.addAttribute("", "elapsed_time", "elapsed_time", "CDATA", | |||||
| // String.valueOf(now.getTime() - program_start.getTime())); | |||||
| attr.addAttribute("", "program_start", "program_start", "CDATA", | |||||
| DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN)); | |||||
| metricsHandler.startElement("", "metrics", "metrics", attr); | |||||
| // now parse the whole thing | |||||
| parseOutput(); | |||||
| } catch (Exception e) { | |||||
| throw new BuildException(e); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Pretty dangerous business here. | |||||
| */ | |||||
| public void stop() { | |||||
| try { | |||||
| // we need to pop everything and close elements that have not been | |||||
| // closed yet. | |||||
| while (stack.size() > 0) { | |||||
| ElementEntry elem = (ElementEntry) stack.pop(); | |||||
| metricsHandler.endElement("", elem.getType(), elem.getType()); | |||||
| } | |||||
| // close the root | |||||
| metricsHandler.endElement("", "metrics", "metrics"); | |||||
| // document is finished for good | |||||
| metricsHandler.endDocument(); | |||||
| } catch (SAXException e) { | |||||
| e.printStackTrace(); | |||||
| throw new IllegalStateException(e.getMessage()); | |||||
| } | |||||
| } | |||||
| /** read each line and process it */ | |||||
| protected void parseOutput() throws IOException, SAXException { | |||||
| BufferedReader br = new BufferedReader(new InputStreamReader(metricsOutput)); | |||||
| String line = null; | |||||
| while ((line = br.readLine()) != null) { | |||||
| processLine(line); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Process a metrics line. If the metrics is invalid and that this is not | |||||
| * the header line, it is display as info. | |||||
| * @param line the line to process, it is normally a line full of metrics. | |||||
| */ | |||||
| protected void processLine(String line) throws SAXException { | |||||
| if (line.startsWith("Construct\tV(G)\tLOC\tDIT\tNOA\tNRM\tNLM\tWMC\tRFC\tDAC\tFANOUT\tCBO\tLCOM\tNOCL")) { | |||||
| return; | |||||
| } | |||||
| try { | |||||
| MetricsElement elem = MetricsElement.parse(line); | |||||
| startElement(elem); | |||||
| } catch (ParseException e) { | |||||
| //e.printStackTrace(); | |||||
| // invalid lines are sent to the output as information, it might be anything, | |||||
| task.log(line, Project.MSG_INFO); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Start a new construct. Elements are popped until we are on the same | |||||
| * parent node, then the element type is guessed and pushed on the | |||||
| * stack. | |||||
| * @param elem the element to process. | |||||
| * @throws SAXException thrown if there is a problem when sending SAX events. | |||||
| */ | |||||
| protected void startElement(MetricsElement elem) throws SAXException { | |||||
| // if there are elements in the stack we possibly need to close one or | |||||
| // more elements previous to this one until we got its parent | |||||
| int indent = elem.getIndent(); | |||||
| if (stack.size() > 0) { | |||||
| ElementEntry previous = (ElementEntry) stack.peek(); | |||||
| // close nodes until you got the parent. | |||||
| try { | |||||
| while (indent <= previous.getIndent() && stack.size() > 0) { | |||||
| stack.pop(); | |||||
| metricsHandler.endElement("", previous.getType(), previous.getType()); | |||||
| previous = (ElementEntry) stack.peek(); | |||||
| } | |||||
| } catch (EmptyStackException ignored) { | |||||
| } | |||||
| } | |||||
| // ok, now start the new construct | |||||
| String type = getConstructType(elem); | |||||
| Attributes attrs = createAttributes(elem); | |||||
| metricsHandler.startElement("", type, type, attrs); | |||||
| // make sure we keep track of what we did, that's history | |||||
| stack.push(new ElementEntry(type, indent)); | |||||
| } | |||||
| /** | |||||
| * return the construct type of the element. We can hardly recognize the | |||||
| * type of a metrics element, so we are kind of forced to do some black | |||||
| * magic based on the name and indentation to recognize the type. | |||||
| * @param elem the metrics element to guess for its type. | |||||
| * @return the type of the metrics element, either PACKAGE, FILE, CLASS or | |||||
| * METHOD. | |||||
| */ | |||||
| protected String getConstructType(MetricsElement elem) { | |||||
| // ok no doubt, it's a file | |||||
| if (elem.isCompilationUnit()) { | |||||
| return FILE; | |||||
| } | |||||
| // same, we're sure it's a method | |||||
| if (elem.isMethod()) { | |||||
| return METHOD; | |||||
| } | |||||
| // if it's empty, and none of the above it should be a package | |||||
| if (stack.size() == 0) { | |||||
| return PACKAGE; | |||||
| } | |||||
| // ok, this is now black magic time, we will guess the type based on | |||||
| // the previous type and its indent... | |||||
| final ElementEntry previous = (ElementEntry) stack.peek(); | |||||
| final String prevType = previous.getType(); | |||||
| final int prevIndent = previous.getIndent(); | |||||
| final int indent = elem.getIndent(); | |||||
| // we're just under a file with a bigger indent so it's a class | |||||
| if (prevType.equals(FILE) && indent > prevIndent) { | |||||
| return CLASS; | |||||
| } | |||||
| // we're just under a class with a greater or equals indent, it's a class | |||||
| // (there might be several classes in a compilation unit and inner classes as well) | |||||
| if (prevType.equals(CLASS) && indent >= prevIndent) { | |||||
| return CLASS; | |||||
| } | |||||
| // we assume the other are package | |||||
| return PACKAGE; | |||||
| } | |||||
| /** | |||||
| * Create all attributes of a MetricsElement skipping those who have an | |||||
| * empty string | |||||
| */ | |||||
| protected Attributes createAttributes(MetricsElement elem) { | |||||
| AttributesImpl impl = new AttributesImpl(); | |||||
| int i = 0; | |||||
| String name = ATTRIBUTES[i++]; | |||||
| impl.addAttribute("", name, name, "CDATA", elem.getName()); | |||||
| Enumeration metrics = elem.getMetrics(); | |||||
| for (; metrics.hasMoreElements(); i++) { | |||||
| String value = (String) metrics.nextElement(); | |||||
| if (value.length() > 0) { | |||||
| name = ATTRIBUTES[i]; | |||||
| impl.addAttribute("", name, name, "CDATA", value); | |||||
| } | |||||
| } | |||||
| return impl; | |||||
| } | |||||
| /** | |||||
| * helper class to keep track of elements via its type and indent | |||||
| * that's all we need to guess a type. | |||||
| */ | |||||
| private static final class ElementEntry { | |||||
| private String type; | |||||
| private int indent; | |||||
| ElementEntry(String type, int indent) { | |||||
| this.type = type; | |||||
| this.indent = indent; | |||||
| } | |||||
| public String getType() { | |||||
| return type; | |||||
| } | |||||
| public int getIndent() { | |||||
| return indent; | |||||
| } | |||||
| } | |||||
| } | |||||
| class MetricsElement { | |||||
| private static final NumberFormat METAMATA_NF; | |||||
| private static final NumberFormat NEUTRAL_NF; | |||||
| static { | |||||
| METAMATA_NF = NumberFormat.getInstance(); | |||||
| METAMATA_NF.setMaximumFractionDigits(1); | |||||
| NEUTRAL_NF = NumberFormat.getInstance(); | |||||
| if (NEUTRAL_NF instanceof DecimalFormat) { | |||||
| ((DecimalFormat) NEUTRAL_NF).applyPattern("###0.###;-###0.###"); | |||||
| } | |||||
| NEUTRAL_NF.setMaximumFractionDigits(1); | |||||
| } | |||||
| private int indent; | |||||
| private String construct; | |||||
| private Vector metrics; | |||||
| MetricsElement(int indent, String construct, Vector metrics) { | |||||
| this.indent = indent; | |||||
| this.construct = construct; | |||||
| this.metrics = metrics; | |||||
| } | |||||
| public int getIndent() { | |||||
| return indent; | |||||
| } | |||||
| public String getName() { | |||||
| return construct; | |||||
| } | |||||
| public Enumeration getMetrics() { | |||||
| return metrics.elements(); | |||||
| } | |||||
| public boolean isCompilationUnit() { | |||||
| return (construct.endsWith(".java") || construct.endsWith(".class")); | |||||
| } | |||||
| public boolean isMethod() { | |||||
| return (construct.endsWith("(...)") || construct.endsWith("()")); | |||||
| } | |||||
| public static MetricsElement parse(String line) throws ParseException { | |||||
| final Vector metrics = new Vector(); | |||||
| int pos; | |||||
| // i'm using indexOf since I need to know if there are empty strings | |||||
| // between tabs and I find it easier than with StringTokenizer | |||||
| while ((pos = line.indexOf('\t')) != -1) { | |||||
| String token = line.substring(0, pos); | |||||
| // only parse what coudl be a valid number. ie not constructs nor no value | |||||
| /*if (metrics.size() != 0 || token.length() != 0) { | |||||
| Number num = METAMATA_NF.parse(token); // parse with Metamata NF | |||||
| token = NEUTRAL_NF.format(num.doubleValue()); // and format with a neutral NF | |||||
| }*/ | |||||
| metrics.addElement(token); | |||||
| line = line.substring(pos + 1); | |||||
| } | |||||
| metrics.addElement(line); | |||||
| // there should be exactly 14 tokens (1 name + 13 metrics), if not, there is a problem ! | |||||
| if (metrics.size() != 14) { | |||||
| throw new ParseException("Could not parse the following line as " | |||||
| + "a metrics: -->" + line + "<--", -1); | |||||
| } | |||||
| // remove the first token it's made of the indentation string and the | |||||
| // construct name, we'll need all this to figure out what type of | |||||
| // construct it is since we lost all semantics :( | |||||
| // (#indent[/]*)(#construct.*) | |||||
| String name = (String) metrics.elementAt(0); | |||||
| metrics.removeElementAt(0); | |||||
| int indent = 0; | |||||
| pos = name.lastIndexOf('/'); | |||||
| if (pos != -1) { | |||||
| name = name.substring(pos + 1); | |||||
| indent = pos + 1; // indentation is last position of token + 1 | |||||
| } | |||||
| return new MetricsElement(indent, name, metrics); | |||||
| } | |||||
| } | |||||
| @@ -1,275 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.File; | |||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | |||||
| import java.io.PrintWriter; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.taskdefs.Execute; | |||||
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; | |||||
| import org.apache.tools.ant.taskdefs.LogStreamHandler; | |||||
| import org.apache.tools.ant.types.Commandline; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||||
| /** | |||||
| * Simple Metamata MParse task. | |||||
| * Based on the original written by | |||||
| * <a href="mailto:thomas.haas@softwired-inc.com">Thomas Haas</a>. | |||||
| * | |||||
| * This version was written for Metamata 2.0 available at | |||||
| * <a href="http://www.metamata.com">http://www.metamata.com</a> | |||||
| * | |||||
| * @todo make a subclass of AbstractMetaMataTask | |||||
| */ | |||||
| public class MParse extends AbstractMetamataTask { | |||||
| private File targetFile = null; | |||||
| private boolean verbose = false; | |||||
| private boolean debugparser = false; | |||||
| private boolean debugscanner = false; | |||||
| private boolean cleanup = false; | |||||
| /** The .jj file to process; required. */ | |||||
| public void setTarget(File targetFile) { | |||||
| this.targetFile = targetFile; | |||||
| } | |||||
| /** set verbose mode */ | |||||
| public void setVerbose(boolean flag) { | |||||
| verbose = flag; | |||||
| } | |||||
| /** set scanner debug mode; optional, default false */ | |||||
| public void setDebugscanner(boolean flag) { | |||||
| debugscanner = flag; | |||||
| } | |||||
| /** set parser debug mode; optional, default false */ | |||||
| public void setDebugparser(boolean flag) { | |||||
| debugparser = flag; | |||||
| } | |||||
| /** Remove the intermediate Sun JavaCC file | |||||
| * ; optional, default false. | |||||
| */ | |||||
| public void setCleanup(boolean value) { | |||||
| cleanup = value; | |||||
| } | |||||
| public MParse() { | |||||
| cmdl.setVm(JavaEnvUtils.getJreExecutable("java")); | |||||
| cmdl.setClassname("com.metamata.jj.MParse"); | |||||
| } | |||||
| /** execute the command line */ | |||||
| public void execute() throws BuildException { | |||||
| try { | |||||
| setUp(); | |||||
| ExecuteStreamHandler handler = createStreamHandler(); | |||||
| _execute(handler); | |||||
| } finally { | |||||
| cleanUp(); | |||||
| } | |||||
| } | |||||
| /** return the default stream handler for this task */ | |||||
| protected ExecuteStreamHandler createStreamHandler() { | |||||
| return new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_INFO); | |||||
| } | |||||
| /** | |||||
| * check the options and build the command line | |||||
| */ | |||||
| protected void setUp() throws BuildException { | |||||
| checkOptions(); | |||||
| // set the classpath as the jar files | |||||
| File[] jars = getMetamataLibs(); | |||||
| final Path cp = cmdl.createClasspath(getProject()); | |||||
| for (int i = 0; i < jars.length; i++) { | |||||
| cp.createPathElement().setLocation(jars[i]); | |||||
| } | |||||
| // set the metamata.home property | |||||
| final Commandline.Argument vmArgs = cmdl.createVmArgument(); | |||||
| vmArgs.setValue("-Dmetamata.home=" + metamataHome.getAbsolutePath()); | |||||
| // write all the options to a temp file and use it ro run the process | |||||
| Vector opts = getOptions(); | |||||
| String[] options = new String[ opts.size() ]; | |||||
| opts.copyInto(options); | |||||
| optionsFile = createTmpFile(); | |||||
| generateOptionsFile(optionsFile, options); | |||||
| Commandline.Argument args = cmdl.createArgument(); | |||||
| args.setLine("-arguments " + optionsFile.getAbsolutePath()); | |||||
| } | |||||
| /** execute the process with a specific handler */ | |||||
| protected void _execute(ExecuteStreamHandler handler) throws BuildException { | |||||
| // target has been checked as a .jj, see if there is a matching | |||||
| // java file and if it is needed to run to process the grammar | |||||
| String pathname = targetFile.getAbsolutePath(); | |||||
| int pos = pathname.length() - ".jj".length(); | |||||
| pathname = pathname.substring(0, pos) + ".java"; | |||||
| File javaFile = new File(pathname); | |||||
| if (javaFile.exists() && targetFile.lastModified() < javaFile.lastModified()) { | |||||
| getProject().log("Target is already build - skipping (" + targetFile + ")"); | |||||
| return; | |||||
| } | |||||
| final Execute process = new Execute(handler); | |||||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||||
| process.setCommandline(cmdl.getCommandline()); | |||||
| try { | |||||
| if (process.execute() != 0) { | |||||
| throw new BuildException("Metamata task failed."); | |||||
| } | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Failed to launch Metamata task: ", e); | |||||
| } | |||||
| } | |||||
| /** clean up all the mess that we did with temporary objects */ | |||||
| protected void cleanUp() { | |||||
| if (optionsFile != null) { | |||||
| optionsFile.delete(); | |||||
| optionsFile = null; | |||||
| } | |||||
| if (cleanup) { | |||||
| String name = targetFile.getName(); | |||||
| int pos = name.length() - ".jj".length(); | |||||
| name = "__jj" + name.substring(0, pos) + ".sunjj"; | |||||
| final File sunjj = new File(targetFile.getParent(), name); | |||||
| if (sunjj.exists()) { | |||||
| getProject().log("Removing stale file: " + sunjj.getName()); | |||||
| sunjj.delete(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * return an array of files containing the path to the needed | |||||
| * libraries to run metamata. The file are not checked for | |||||
| * existence. You should do this yourself if needed or simply let the | |||||
| * forked process do it for you. | |||||
| * @return array of jars/zips needed to run metamata. | |||||
| */ | |||||
| protected File[] getMetamataLibs() { | |||||
| Vector files = new Vector(); | |||||
| files.addElement(new File(metamataHome, "lib/metamata.jar")); | |||||
| files.addElement(new File(metamataHome, "bin/lib/JavaCC.zip")); | |||||
| File[] array = new File[ files.size() ]; | |||||
| files.copyInto(array); | |||||
| return array; | |||||
| } | |||||
| /** | |||||
| * validate options set and resolve files and paths | |||||
| * @throws BuildException thrown if an option has an incorrect state. | |||||
| */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| // check that the home is ok. | |||||
| if (metamataHome == null || !metamataHome.exists()) { | |||||
| throw new BuildException("'metamatahome' must point to Metamata home directory."); | |||||
| } | |||||
| metamataHome = getProject().resolveFile(metamataHome.getPath()); | |||||
| // check that the needed jar exists. | |||||
| File[] jars = getMetamataLibs(); | |||||
| for (int i = 0; i < jars.length; i++) { | |||||
| if (!jars[i].exists()) { | |||||
| throw new BuildException(jars[i] | |||||
| + " does not exist. Check your metamata installation."); | |||||
| } | |||||
| } | |||||
| // check that the target is ok and resolve it. | |||||
| if (targetFile == null || !targetFile.isFile() | |||||
| || !targetFile.getName().endsWith(".jj")) { | |||||
| throw new BuildException("Invalid target: " + targetFile); | |||||
| } | |||||
| targetFile = getProject().resolveFile(targetFile.getPath()); | |||||
| } | |||||
| /** | |||||
| * return all options of the command line as string elements | |||||
| * @return an array of options corresponding to the setted options. | |||||
| */ | |||||
| protected Vector getOptions() { | |||||
| Vector options = new Vector(); | |||||
| if (verbose) { | |||||
| options.addElement("-verbose"); | |||||
| } | |||||
| if (debugscanner) { | |||||
| options.addElement("-ds"); | |||||
| } | |||||
| if (debugparser) { | |||||
| options.addElement("-dp"); | |||||
| } | |||||
| if (classPath != null) { | |||||
| options.addElement("-classpath"); | |||||
| options.addElement(classPath.toString()); | |||||
| } | |||||
| if (sourcePath != null) { | |||||
| options.addElement("-sourcepath"); | |||||
| options.addElement(sourcePath.toString()); | |||||
| } | |||||
| options.addElement(targetFile.getAbsolutePath()); | |||||
| return options; | |||||
| } | |||||
| /** | |||||
| * write all options to a file with one option / line | |||||
| * @param tofile the file to write the options to. | |||||
| * @param options the array of options element to write to the file. | |||||
| * @throws BuildException thrown if there is a problem while writing | |||||
| * to the file. | |||||
| */ | |||||
| protected void generateOptionsFile(File tofile, String[] options) throws BuildException { | |||||
| FileWriter fw = null; | |||||
| try { | |||||
| fw = new FileWriter(tofile); | |||||
| PrintWriter pw = new PrintWriter(fw); | |||||
| for (int i = 0; i < options.length; i++) { | |||||
| pw.println(options[i]); | |||||
| } | |||||
| pw.flush(); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Error while writing options file " + tofile, e); | |||||
| } finally { | |||||
| if (fw != null) { | |||||
| try { | |||||
| fw.close(); | |||||
| } catch (IOException ignored) { | |||||
| // ignore | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,127 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2003-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| /** | |||||
| * Base class that deals with JProbe version incompatibilities. | |||||
| * | |||||
| * @since Ant 1.6 | |||||
| * | |||||
| */ | |||||
| public abstract class CovBase extends Task { | |||||
| private File home; | |||||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||||
| private boolean isJProbe4 = false; | |||||
| private static boolean isDos = Os.isFamily("dos"); | |||||
| /** | |||||
| * The directory where JProbe is installed. | |||||
| * @param value the JProbe directory | |||||
| */ | |||||
| public void setHome(File value) { | |||||
| this.home = value; | |||||
| } | |||||
| /** | |||||
| * Get the JProbe directory. | |||||
| * @return the JProbe directory | |||||
| */ | |||||
| protected File getHome() { | |||||
| return home; | |||||
| } | |||||
| /** | |||||
| * Get the location of the JProbe coverage jar file. | |||||
| * @return the location of the JProbe coverage jar file | |||||
| */ | |||||
| protected File findCoverageJar() { | |||||
| File loc = null; | |||||
| if (isJProbe4) { | |||||
| loc = FILE_UTILS.resolveFile(home, "lib/coverage.jar"); | |||||
| } else { | |||||
| loc = FILE_UTILS.resolveFile(home, "coverage/coverage.jar"); | |||||
| if (!loc.canRead()) { | |||||
| File newLoc = FILE_UTILS.resolveFile(home, "lib/coverage.jar"); | |||||
| if (newLoc.canRead()) { | |||||
| isJProbe4 = true; | |||||
| loc = newLoc; | |||||
| } | |||||
| } | |||||
| } | |||||
| return loc; | |||||
| } | |||||
| /** | |||||
| * Find the JProbe executable. | |||||
| * @param relativePath the name of the executuable without the trailing .exe on dos | |||||
| * @return the absolute path to the executable | |||||
| */ | |||||
| protected String findExecutable(String relativePath) { | |||||
| if (isDos) { | |||||
| relativePath += ".exe"; | |||||
| } | |||||
| File loc = null; | |||||
| if (isJProbe4) { | |||||
| loc = FILE_UTILS.resolveFile(home, "bin/" + relativePath); | |||||
| } else { | |||||
| loc = FILE_UTILS.resolveFile(home, relativePath); | |||||
| if (!loc.canRead()) { | |||||
| File newLoc = FILE_UTILS.resolveFile(home, "bin/" + relativePath); | |||||
| if (newLoc.canRead()) { | |||||
| isJProbe4 = true; | |||||
| loc = newLoc; | |||||
| } | |||||
| } | |||||
| } | |||||
| return loc.getAbsolutePath(); | |||||
| } | |||||
| /** | |||||
| * Create a temporary file. | |||||
| * @param prefix a prefix to use in the filename | |||||
| * @return a File reference to the temporary file | |||||
| */ | |||||
| protected File createTempFile(String prefix) { | |||||
| return FILE_UTILS.createTempFile(prefix, ".tmp", null); | |||||
| } | |||||
| /** | |||||
| * Get the param file arguement. | |||||
| * This checks the version of jprobe to return the correct name of | |||||
| * the parameter. | |||||
| * @return the name of the argument | |||||
| */ | |||||
| protected String getParamFileArgument() { | |||||
| return "-" + (!isJProbe4 ? "jp_" : "") + "paramfile="; | |||||
| } | |||||
| /** | |||||
| * Are we running on a version of JProbe 4.x or higher? | |||||
| * @return true if we are running JProbe 4 or higher | |||||
| */ | |||||
| protected boolean isJProbe4Plus() { | |||||
| return isJProbe4; | |||||
| } | |||||
| } | |||||
| @@ -1,204 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | |||||
| import java.io.PrintWriter; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.DirectoryScanner; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.taskdefs.Execute; | |||||
| import org.apache.tools.ant.taskdefs.LogStreamHandler; | |||||
| import org.apache.tools.ant.types.Commandline; | |||||
| import org.apache.tools.ant.types.FileSet; | |||||
| /** | |||||
| * Runs the snapshot merge utility for JProbe Coverage. | |||||
| * | |||||
| * @ant.task name="jpcovmerge" category="metrics" | |||||
| */ | |||||
| public class CovMerge extends CovBase { | |||||
| /** the name of the output snapshot */ | |||||
| private File tofile = null; | |||||
| /** the filesets that will get all snapshots to merge */ | |||||
| private Vector filesets = new Vector(); | |||||
| private boolean verbose; | |||||
| /** | |||||
| * Set the output snapshot file. | |||||
| * @param value the snapshot file | |||||
| */ | |||||
| public void setTofile(File value) { | |||||
| this.tofile = value; | |||||
| } | |||||
| /** | |||||
| * If true, perform the merge in verbose mode giving details | |||||
| * about the snapshot processing. | |||||
| * @param flag if true perform the merge in verbose mode | |||||
| */ | |||||
| public void setVerbose(boolean flag) { | |||||
| this.verbose = flag; | |||||
| } | |||||
| /** | |||||
| * add a fileset containing the snapshots to include. | |||||
| * @param fs nested fileset element | |||||
| */ | |||||
| public void addFileset(FileSet fs) { | |||||
| filesets.addElement(fs); | |||||
| } | |||||
| //---------------- the tedious job begins here | |||||
| /** Constructor for CovMerge. */ | |||||
| public CovMerge() { | |||||
| } | |||||
| /** | |||||
| * Execute the jpcovmerge by providing a parameter file. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| public void execute() throws BuildException { | |||||
| checkOptions(); | |||||
| File paramfile = createParamFile(); | |||||
| try { | |||||
| Commandline cmdl = new Commandline(); | |||||
| cmdl.setExecutable(findExecutable("jpcovmerge")); | |||||
| if (verbose) { | |||||
| cmdl.createArgument().setValue("-v"); | |||||
| } | |||||
| cmdl.createArgument().setValue(getParamFileArgument() | |||||
| + paramfile.getAbsolutePath()); | |||||
| if (isJProbe4Plus()) { | |||||
| // last argument is the output snapshot - JProbe 4.x | |||||
| // doesn't like it in the parameter file. | |||||
| cmdl.createArgument().setValue(tofile.getPath()); | |||||
| } | |||||
| LogStreamHandler handler | |||||
| = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN); | |||||
| Execute exec = new Execute(handler); | |||||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||||
| exec.setCommandline(cmdl.getCommandline()); | |||||
| // JProbe process always return 0 so we will not be | |||||
| // able to check for failure ! :-( | |||||
| int exitValue = exec.execute(); | |||||
| if (Execute.isFailure(exitValue)) { | |||||
| throw new BuildException("JProbe Coverage Merging failed (" + exitValue + ")"); | |||||
| } | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Failed to run JProbe Coverage Merge: " + e); | |||||
| } finally { | |||||
| //@todo should be removed once switched to JDK1.2 | |||||
| paramfile.delete(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Check for mandatory options. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| if (tofile == null) { | |||||
| throw new BuildException("'tofile' attribute must be set."); | |||||
| } | |||||
| // check coverage home | |||||
| if (getHome() == null || !getHome().isDirectory()) { | |||||
| throw new BuildException("Invalid home directory. Must point to JProbe home directory"); | |||||
| } | |||||
| File jar = findCoverageJar(); | |||||
| if (!jar.exists()) { | |||||
| throw new BuildException("Cannot find Coverage directory: " + getHome()); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the snapshots from the filesets. | |||||
| * @return an array of snapshot files | |||||
| */ | |||||
| protected File[] getSnapshots() { | |||||
| Vector v = new Vector(); | |||||
| final int size = filesets.size(); | |||||
| for (int i = 0; i < size; i++) { | |||||
| FileSet fs = (FileSet) filesets.elementAt(i); | |||||
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||||
| ds.scan(); | |||||
| String[] f = ds.getIncludedFiles(); | |||||
| for (int j = 0; j < f.length; j++) { | |||||
| String pathname = f[j]; | |||||
| File file = new File(ds.getBasedir(), pathname); | |||||
| file = getProject().resolveFile(file.getPath()); | |||||
| v.addElement(file); | |||||
| } | |||||
| } | |||||
| File[] files = new File[v.size()]; | |||||
| v.copyInto(files); | |||||
| return files; | |||||
| } | |||||
| /** | |||||
| * Create the parameters file that contains all file to merge | |||||
| * and the output filename. | |||||
| * @return the parameters file | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| protected File createParamFile() throws BuildException { | |||||
| File[] snapshots = getSnapshots(); | |||||
| File file = createTempFile("jpcovm"); | |||||
| file.deleteOnExit(); | |||||
| FileWriter fw = null; | |||||
| try { | |||||
| fw = new FileWriter(file); | |||||
| PrintWriter pw = new PrintWriter(fw); | |||||
| for (int i = 0; i < snapshots.length; i++) { | |||||
| pw.println(snapshots[i].getAbsolutePath()); | |||||
| } | |||||
| if (!isJProbe4Plus()) { | |||||
| // last file is the output snapshot - JProbe 4.x doesn't | |||||
| // like it in the parameter file. | |||||
| pw.println(getProject().resolveFile(tofile.getPath())); | |||||
| } | |||||
| pw.flush(); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("I/O error while writing to " + file, e); | |||||
| } finally { | |||||
| if (fw != null) { | |||||
| try { | |||||
| fw.close(); | |||||
| } catch (IOException ignored) { | |||||
| // Ignore Exception | |||||
| } | |||||
| } | |||||
| } | |||||
| return file; | |||||
| } | |||||
| } | |||||
| @@ -1,410 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.Vector; | |||||
| import javax.xml.transform.OutputKeys; | |||||
| import javax.xml.transform.Result; | |||||
| import javax.xml.transform.Source; | |||||
| import javax.xml.transform.Transformer; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.dom.DOMSource; | |||||
| import javax.xml.transform.stream.StreamResult; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.taskdefs.Execute; | |||||
| import org.apache.tools.ant.taskdefs.LogStreamHandler; | |||||
| import org.apache.tools.ant.types.Commandline; | |||||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.w3c.dom.Document; | |||||
| /** | |||||
| * Runs the JProbe Coverage 3.0 snapshot merge utility. | |||||
| * | |||||
| * @ant.task name="jpcovreport" category="metrics" | |||||
| */ | |||||
| public class CovReport extends CovBase { | |||||
| /* | |||||
| jpcoverport [options] -output=file -snapshot=snapshot.jpc | |||||
| jpcovreport [options] [-paramfile=file] -output=<fileName> -snapshot=<fileName> | |||||
| Generate a report based on the indicated snapshot | |||||
| -paramfile=file | |||||
| A text file containing the report generation options. | |||||
| -format=(html|text|xml) defaults to html | |||||
| The format of the generated report. | |||||
| -type=(executive|summary|detailed|verydetailed) defaults to detailed | |||||
| The type of report to be generated. For -format=xml, | |||||
| use -type=verydetailed to include source code lines. | |||||
| Note: A very detailed report can be VERY large. | |||||
| -percent=num Min 1 Max 101 Default 101 | |||||
| An integer representing a percentage of coverage. | |||||
| Only methods with test case coverage less than the | |||||
| percentage are included in reports. | |||||
| -filters=string | |||||
| A comma-separated list of filters in the form | |||||
| <package>.<class>:V, where V can be I for Include or | |||||
| E for Exclude. For the default package, omit <package>. | |||||
| -filters_method=string | |||||
| Optional. A comma-separated list of methods that | |||||
| correspond one-to-one with the entries in -filters. | |||||
| -output=string Must be specified | |||||
| The absolute path and file name for the generated | |||||
| report file. | |||||
| -snapshot=string Must be specified | |||||
| The absolute path and file name of the snapshot file. | |||||
| -inc_src_text=(on|off) defaults to on | |||||
| Include text of the source code lines. | |||||
| Only applies for -format=xml and -type=verydetailed. | |||||
| -sourcepath=string defaults to . | |||||
| A semicolon-separated list of source paths. | |||||
| /* | |||||
| /** format of generated report, optional */ | |||||
| private String format = null; | |||||
| /** the name of the output snapshot, mandatory */ | |||||
| private File tofile = null; | |||||
| /** type of report, optional */ | |||||
| private String type = null; | |||||
| /** threshold value for printing methods, optional */ | |||||
| private Integer percent = null; | |||||
| /** comma separated list of filters (???)*/ | |||||
| private String filters = null; | |||||
| /** name of the snapshot file to create report from */ | |||||
| private File snapshot = null; | |||||
| /** sourcepath to use */ | |||||
| private Path sourcePath = null; | |||||
| /** include the text for each line of code (xml report verydetailed)*/ | |||||
| private boolean includeSource = true; | |||||
| private Path coveragePath = null; | |||||
| /** */ | |||||
| private Reference reference = null; | |||||
| /** Enumerated type for format attribute. */ | |||||
| public static class ReportFormat extends EnumeratedAttribute { | |||||
| /** @see EnumeratedAttribute#getValues() */ | |||||
| public String[] getValues() { | |||||
| return new String[]{"html", "text", "xml"}; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * set the format of the report: "html", "text", or "xml" | |||||
| * @param value an enumerated <code>ReportFormat</code> value | |||||
| */ | |||||
| public void setFormat(ReportFormat value) { | |||||
| this.format = value.getValue(); | |||||
| } | |||||
| /** Enumerated type for type attribute. */ | |||||
| public static class ReportType extends EnumeratedAttribute { | |||||
| /** @see EnumeratedAttribute#getValues() */ | |||||
| public String[] getValues() { | |||||
| return new String[]{"executive", "summary", "detailed", "verydetailed"}; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * The type of report to be generated: "executive", "summary", | |||||
| * "detailed" or "verydetailed". | |||||
| * @param value an enumerated <code>ReportType</code> value | |||||
| */ | |||||
| public void setType(ReportType value) { | |||||
| this.type = value.getValue(); | |||||
| } | |||||
| /** | |||||
| * If true, include text of the source code lines. | |||||
| * Only applies to format="xml" and type="verydetailed" | |||||
| * @param value a <code>boolean</code> value | |||||
| */ | |||||
| public void setIncludesource(boolean value) { | |||||
| this.includeSource = value; | |||||
| } | |||||
| /** | |||||
| * A numeric value for the threshold for printing methods. | |||||
| * Must be between 0 and 100. | |||||
| * @param value an <code>Integer</code> value | |||||
| */ | |||||
| public void setPercent(Integer value) { | |||||
| this.percent = value; | |||||
| } | |||||
| /** | |||||
| * set the filters | |||||
| * @param values a <code>String</code> value | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setFilters(String values) { | |||||
| this.filters = values; | |||||
| } | |||||
| /** | |||||
| * Adds a path to source files. | |||||
| * @return a path to be configured | |||||
| */ | |||||
| public Path createSourcepath() { | |||||
| if (sourcePath == null) { | |||||
| sourcePath = new Path(getProject()); | |||||
| } | |||||
| return sourcePath.createPath(); | |||||
| } | |||||
| /** | |||||
| * The name of the snapshot file that is the source to the report. | |||||
| * @param value the snapshot file | |||||
| */ | |||||
| public void setSnapshot(File value) { | |||||
| this.snapshot = value; | |||||
| } | |||||
| /** | |||||
| * The name of the generated output file. | |||||
| * @param value the output file | |||||
| */ | |||||
| public void setTofile(File value) { | |||||
| this.tofile = value; | |||||
| } | |||||
| /** | |||||
| * @return a path to be configured | |||||
| * @todo needs to be removed | |||||
| * @ant.element ignore="true" | |||||
| */ | |||||
| public Path createCoveragepath() { | |||||
| if (coveragePath == null) { | |||||
| coveragePath = new Path(getProject()); | |||||
| } | |||||
| return coveragePath.createPath(); | |||||
| } | |||||
| /** | |||||
| * Adds a set of classes whose coverage information will be | |||||
| * checked against. | |||||
| * @return a <code>CovReport.Reference</code> object to be configured | |||||
| */ | |||||
| public Reference createReference() { | |||||
| if (reference == null) { | |||||
| reference = new Reference(); | |||||
| } | |||||
| return reference; | |||||
| } | |||||
| /** Constructor for CovReport. */ | |||||
| public CovReport() { | |||||
| } | |||||
| /** | |||||
| * Check for mandatory options. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| if (tofile == null) { | |||||
| throw new BuildException("'tofile' attribute must be set."); | |||||
| } | |||||
| if (snapshot == null) { | |||||
| throw new BuildException("'snapshot' attribute must be set."); | |||||
| } | |||||
| if (getHome() == null) { | |||||
| throw new BuildException("'home' attribute must be set to JProbe home directory"); | |||||
| } | |||||
| File jar = findCoverageJar(); | |||||
| if (!jar.exists()) { | |||||
| throw new BuildException("Cannot find Coverage directory: " + getHome()); | |||||
| } | |||||
| if (reference != null && !"xml".equals(format)) { | |||||
| log("Ignored reference. It cannot be used in non XML report."); | |||||
| reference = null; // nullify it so that there is no ambiguity | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Execute the task. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| public void execute() throws BuildException { | |||||
| checkOptions(); | |||||
| try { | |||||
| Commandline cmdl = new Commandline(); | |||||
| // we need to run Coverage from his directory due to dll/jar issues | |||||
| cmdl.setExecutable(findExecutable("jpcovreport")); | |||||
| String[] params = getParameters(); | |||||
| for (int i = 0; i < params.length; i++) { | |||||
| cmdl.createArgument().setValue(params[i]); | |||||
| } | |||||
| // use the custom handler for stdin issues | |||||
| LogStreamHandler handler | |||||
| = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN); | |||||
| Execute exec = new Execute(handler); | |||||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||||
| exec.setCommandline(cmdl.getCommandline()); | |||||
| int exitValue = exec.execute(); | |||||
| if (Execute.isFailure(exitValue)) { | |||||
| throw new BuildException("JProbe Coverage Report failed (" | |||||
| + exitValue + ")"); | |||||
| } | |||||
| log("coveragePath: " + coveragePath, Project.MSG_VERBOSE); | |||||
| log("format: " + format, Project.MSG_VERBOSE); | |||||
| if (reference != null && "xml".equals(format)) { | |||||
| reference.createEnhancedXMLReport(); | |||||
| } | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Failed to execute JProbe Coverage Report.", e); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the parameters for the executable. | |||||
| * @return an array of parameters | |||||
| */ | |||||
| protected String[] getParameters() { | |||||
| Vector v = new Vector(); | |||||
| if (format != null) { | |||||
| v.addElement("-format=" + format); | |||||
| } | |||||
| if (type != null) { | |||||
| v.addElement("-type=" + type); | |||||
| } | |||||
| if (percent != null) { | |||||
| v.addElement("-percent=" + percent); | |||||
| } | |||||
| if (filters != null) { | |||||
| v.addElement("-filters=" + filters); | |||||
| } | |||||
| v.addElement("-output=" + getProject().resolveFile(tofile.getPath())); | |||||
| v.addElement("-snapshot=" + getProject().resolveFile(snapshot.getPath())); | |||||
| // as a default -sourcepath use . in JProbe, so use project . | |||||
| if (sourcePath == null) { | |||||
| sourcePath = new Path(getProject()); | |||||
| sourcePath.createPath().setLocation(getProject().resolveFile(".")); | |||||
| } | |||||
| v.addElement("-sourcepath=" + sourcePath); | |||||
| if ("verydetailed".equalsIgnoreCase(format) && "xml".equalsIgnoreCase(type)) { | |||||
| v.addElement("-inc_src_text=" + (includeSource ? "on" : "off")); | |||||
| } | |||||
| String[] params = new String[v.size()]; | |||||
| v.copyInto(params); | |||||
| return params; | |||||
| } | |||||
| /** | |||||
| * An inner class for the reference element. | |||||
| */ | |||||
| public class Reference { | |||||
| protected Path classPath; | |||||
| protected ReportFilters filters; | |||||
| /** | |||||
| * Create a path for the reference. | |||||
| * @return a path to be configured | |||||
| */ | |||||
| public Path createClasspath() { | |||||
| if (classPath == null) { | |||||
| classPath = new Path(CovReport.this.getProject()); | |||||
| } | |||||
| return classPath.createPath(); | |||||
| } | |||||
| /** | |||||
| * An nested element to include/exclude classes/methods. | |||||
| * @return ReportFilters to be configured | |||||
| */ | |||||
| public ReportFilters createFilters() { | |||||
| if (filters == null) { | |||||
| filters = new ReportFilters(); | |||||
| } | |||||
| return filters; | |||||
| } | |||||
| /** | |||||
| * Create the xml report. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| protected void createEnhancedXMLReport() throws BuildException { | |||||
| // we need a classpath element | |||||
| if (classPath == null) { | |||||
| throw new BuildException("Need a 'classpath' element."); | |||||
| } | |||||
| // and a valid one... | |||||
| String[] paths = classPath.list(); | |||||
| if (paths.length == 0) { | |||||
| throw new BuildException( | |||||
| "Coverage path is invalid. It does not contain any existing path."); | |||||
| } | |||||
| // and we need at least one filter include/exclude. | |||||
| if (filters == null || filters.size() == 0) { | |||||
| createFilters(); | |||||
| log("Adding default include filter to *.*()", Project.MSG_VERBOSE); | |||||
| ReportFilters.Include include = new ReportFilters.Include(); | |||||
| filters.addInclude(include); | |||||
| } | |||||
| try { | |||||
| log("Creating enhanced XML report", Project.MSG_VERBOSE); | |||||
| XMLReport report = new XMLReport(CovReport.this, tofile); | |||||
| report.setReportFilters(filters); | |||||
| report.setJProbehome(new File(getHome().getParent())); | |||||
| Document doc = report.createDocument(paths); | |||||
| TransformerFactory tfactory = TransformerFactory.newInstance(); | |||||
| Transformer transformer = tfactory.newTransformer(); | |||||
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); | |||||
| transformer.setOutputProperty(OutputKeys.METHOD, "xml"); | |||||
| Source src = new DOMSource(doc); | |||||
| Result res = new StreamResult(tofile); | |||||
| transformer.transform(src, res); | |||||
| } catch (Exception e) { | |||||
| throw new BuildException("Error while performing enhanced XML " | |||||
| + "report from file " + tofile, e); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,522 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| import java.io.PrintWriter; | |||||
| import java.io.StringWriter; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.taskdefs.Execute; | |||||
| import org.apache.tools.ant.taskdefs.LogStreamHandler; | |||||
| import org.apache.tools.ant.types.Commandline; | |||||
| import org.apache.tools.ant.types.CommandlineJava; | |||||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||||
| import org.apache.tools.ant.types.FileSet; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||||
| /** | |||||
| * Runs Sitraka JProbe Coverage. | |||||
| * | |||||
| * Options are pretty numerous, you'd better check the manual for a full | |||||
| * descriptions of options. (not that simple since they differ from the online | |||||
| * help, from the usage command line and from the examples...) | |||||
| * <p> | |||||
| * For additional information, visit <a href="http://www.sitraka.com">www.sitraka.com</a> | |||||
| * | |||||
| * @ant.task name="jpcoverage" category="metrics" | |||||
| */ | |||||
| public class Coverage extends CovBase { | |||||
| protected Commandline cmdl = new Commandline(); | |||||
| protected CommandlineJava cmdlJava = new CommandlineJava(); | |||||
| protected String function = "coverage"; | |||||
| protected String seedName; | |||||
| protected File inputFile; | |||||
| protected File javaExe; | |||||
| protected String vm; | |||||
| protected boolean applet = false; | |||||
| /** this is a somewhat annoying thing, set it to never */ | |||||
| protected String exitPrompt = "never"; | |||||
| protected Filters filters = new Filters(); | |||||
| protected Triggers triggers; | |||||
| protected String finalSnapshot = "coverage"; | |||||
| protected String recordFromStart = "coverage"; | |||||
| protected File snapshotDir; | |||||
| protected File workingDir; | |||||
| protected boolean trackNatives = false; | |||||
| protected Socket socket; | |||||
| protected int warnLevel = 0; | |||||
| protected Vector filesets = new Vector(); | |||||
| //--------- setters used via reflection -- | |||||
| /** | |||||
| * Set the seed name for snapshot file. Can be null, default to snap. | |||||
| * @param value a <code>String</code> value | |||||
| */ | |||||
| public void setSeedname(String value) { | |||||
| seedName = value; | |||||
| } | |||||
| /** | |||||
| * Set the input file. | |||||
| * @param value a <code>File</code> value | |||||
| * @ant.attribute ignore="true" | |||||
| */ | |||||
| public void setInputfile(File value) { | |||||
| inputFile = value; | |||||
| } | |||||
| /** | |||||
| * Path to the java executable. | |||||
| * @param value the path to the java executable | |||||
| */ | |||||
| public void setJavaexe(File value) { | |||||
| javaExe = value; | |||||
| } | |||||
| /** | |||||
| * Enumerated type corresponding to the javavms known by the task. | |||||
| */ | |||||
| public static class Javavm extends EnumeratedAttribute { | |||||
| /** | |||||
| * Get the valid javavms names. | |||||
| * @return an array of strings = "java2", "jdk118", and "jdk117" | |||||
| */ | |||||
| public String[] getValues() { | |||||
| return new String[]{"java2", "jdk118", "jdk117"}; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Indicates which virtual machine to run: "jdk117", "jdk118" or "java2". | |||||
| * Can be null, default to "java2". | |||||
| * @param value an enumerated value | |||||
| */ | |||||
| public void setVm(Javavm value) { | |||||
| vm = value.getValue(); | |||||
| } | |||||
| /** | |||||
| * If true, run an applet. | |||||
| * @param value a <code>boolean</code> value | |||||
| */ | |||||
| public void setApplet(boolean value) { | |||||
| applet = value; | |||||
| } | |||||
| /** | |||||
| * Toggles display of the console prompt: always, error, never | |||||
| * @param value when to display the prompt - "always", "error" or "never" | |||||
| */ | |||||
| public void setExitprompt(String value) { | |||||
| exitPrompt = value; | |||||
| } | |||||
| /** | |||||
| * Defines class/method filters based on pattern matching. | |||||
| * The syntax is filters is similar to a fileset. | |||||
| * @return the filters to be configured | |||||
| */ | |||||
| public Filters createFilters() { | |||||
| return filters; | |||||
| } | |||||
| /** | |||||
| * Defines events to use for interacting with the | |||||
| * collection of data performed during coverage. | |||||
| * | |||||
| * For example you may run a whole application but only decide | |||||
| * to collect data once it reaches a certain method and once it | |||||
| * exits another one. | |||||
| * @return the triggers to be configured | |||||
| */ | |||||
| public Triggers createTriggers() { | |||||
| if (triggers == null) { | |||||
| triggers = new Triggers(); | |||||
| } | |||||
| return triggers; | |||||
| } | |||||
| /** | |||||
| * Define a host and port to connect to if you want to do | |||||
| * remote viewing. | |||||
| * @return the socket to be configured | |||||
| */ | |||||
| public Socket createSocket() { | |||||
| if (socket == null) { | |||||
| socket = new Socket(); | |||||
| } | |||||
| return socket; | |||||
| } | |||||
| /** | |||||
| * Enumerated type for finalsnapshot attribute. | |||||
| */ | |||||
| public static class Finalsnapshot extends EnumeratedAttribute { | |||||
| /** | |||||
| * Get the valid strings for the attribute. | |||||
| * @return an array of strings - "coverage", "none" and "all" | |||||
| */ | |||||
| public String[] getValues() { | |||||
| return new String[]{"coverage", "none", "all"}; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Type of snapshot to send at program termination: none, coverage, all. | |||||
| * Can be null, default to none | |||||
| * @param value a <code>String</code> value | |||||
| */ | |||||
| public void setFinalsnapshot(String value) { | |||||
| finalSnapshot = value; | |||||
| } | |||||
| /** | |||||
| * Enumerated type for recordfromstart attribute. | |||||
| */ | |||||
| public static class Recordfromstart extends EnumeratedAttribute { | |||||
| /** | |||||
| * Get the valid strings for the attribute. | |||||
| * @return an array of strings - "coverage", "none" and "all" | |||||
| */ | |||||
| public String[] getValues() { | |||||
| return new String[]{"coverage", "none", "all"}; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Set the recordfromstart attribute, valid values are | |||||
| * "all", "coverage", or "none". | |||||
| * @param value an enumerated type having the correct values. | |||||
| */ | |||||
| public void setRecordfromstart(Recordfromstart value) { | |||||
| recordFromStart = value.getValue(); | |||||
| } | |||||
| /** | |||||
| * Set warning level (0-3, where 0 is the least amount of warnings). | |||||
| * @param value an <code>Integer</code> value | |||||
| */ | |||||
| public void setWarnlevel(Integer value) { | |||||
| warnLevel = value.intValue(); | |||||
| } | |||||
| /** | |||||
| * The path to the directory where snapshot files are stored. | |||||
| * Choose a directory that is reachable by both the remote | |||||
| * and local computers, and enter the same path on the command-line | |||||
| * and in the viewer. | |||||
| * @param value the snapshot directory | |||||
| */ | |||||
| public void setSnapshotdir(File value) { | |||||
| snapshotDir = value; | |||||
| } | |||||
| /** | |||||
| * The physical path to the working directory for the VM. | |||||
| * @param value the working directory | |||||
| */ | |||||
| public void setWorkingdir(File value) { | |||||
| workingDir = value; | |||||
| } | |||||
| /** | |||||
| * If true, track native methods. | |||||
| * @param value a <code>boolean</code> value | |||||
| */ | |||||
| public void setTracknatives(boolean value) { | |||||
| trackNatives = value; | |||||
| } | |||||
| // | |||||
| /** | |||||
| * Adds a JVM argument. | |||||
| * @return a command line argument to configure | |||||
| */ | |||||
| public Commandline.Argument createJvmarg() { | |||||
| return cmdlJava.createVmArgument(); | |||||
| } | |||||
| /** | |||||
| * Adds a command argument. | |||||
| * @return a command line argument to configure | |||||
| */ | |||||
| public Commandline.Argument createArg() { | |||||
| return cmdlJava.createArgument(); | |||||
| } | |||||
| /** | |||||
| * classpath to run the files. | |||||
| * @return a Path to configure | |||||
| */ | |||||
| public Path createClasspath() { | |||||
| return cmdlJava.createClasspath(getProject()).createPath(); | |||||
| } | |||||
| /** | |||||
| * classname to run as standalone or runner for filesets. | |||||
| * @param value a <code>String</code> value for the classname | |||||
| */ | |||||
| public void setClassname(String value) { | |||||
| cmdlJava.setClassname(value); | |||||
| } | |||||
| /** | |||||
| * the classnames to execute. | |||||
| * @param fs a nested fileset element | |||||
| */ | |||||
| public void addFileset(FileSet fs) { | |||||
| filesets.addElement(fs); | |||||
| } | |||||
| //---------------- the tedious job begins here | |||||
| /** | |||||
| * Constructor for Coverage. | |||||
| */ | |||||
| public Coverage() { | |||||
| } | |||||
| /** | |||||
| * Execute the jplauncher by providing a parameter file. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| public void execute() throws BuildException { | |||||
| File paramfile = null; | |||||
| // if an input file is used, all other options are ignored... | |||||
| if (inputFile == null) { | |||||
| checkOptions(); | |||||
| paramfile = createParamFile(); | |||||
| } else { | |||||
| paramfile = inputFile; | |||||
| } | |||||
| try { | |||||
| // we need to run Coverage from his directory due to dll/jar issues | |||||
| cmdl.setExecutable(findExecutable("jplauncher")); | |||||
| cmdl.createArgument().setValue("-jp_input=" + paramfile.getAbsolutePath()); | |||||
| // use the custom handler for stdin issues | |||||
| LogStreamHandler handler = new CoverageStreamHandler(this); | |||||
| Execute exec = new Execute(handler); | |||||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||||
| exec.setCommandline(cmdl.getCommandline()); | |||||
| int exitValue = exec.execute(); | |||||
| if (Execute.isFailure(exitValue)) { | |||||
| throw new BuildException("JProbe Coverage failed (" + exitValue + ")"); | |||||
| } | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Failed to execute JProbe Coverage.", e); | |||||
| } finally { | |||||
| //@todo should be removed once switched to JDK1.2 | |||||
| if (inputFile == null && paramfile != null) { | |||||
| paramfile.delete(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Check what is necessary to check, Coverage will do the job for us. | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| protected void checkOptions() throws BuildException { | |||||
| // check coverage home | |||||
| if (getHome() == null || !getHome().isDirectory()) { | |||||
| throw new BuildException("Invalid home directory. Must point to JProbe home directory"); | |||||
| } | |||||
| File jar = findCoverageJar(); | |||||
| if (!jar.exists()) { | |||||
| throw new BuildException("Cannot find Coverage directory: " + getHome()); | |||||
| } | |||||
| // make sure snapshot dir exists and is resolved | |||||
| if (snapshotDir == null) { | |||||
| snapshotDir = new File("."); | |||||
| } | |||||
| snapshotDir = getProject().resolveFile(snapshotDir.getPath()); | |||||
| if (!snapshotDir.isDirectory() || !snapshotDir.exists()) { | |||||
| throw new BuildException("Snapshot directory does not exists :" + snapshotDir); | |||||
| } | |||||
| if (workingDir == null) { | |||||
| workingDir = new File("."); | |||||
| } | |||||
| workingDir = getProject().resolveFile(workingDir.getPath()); | |||||
| // check for info, do your best to select the java executable. | |||||
| // JProbe 3.0 fails if there is no javaexe option. So | |||||
| if (javaExe == null && (vm == null || "java2".equals(vm))) { | |||||
| if (vm == null) { | |||||
| vm = "java2"; | |||||
| } | |||||
| javaExe = new File(JavaEnvUtils.getJreExecutable("java")); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * return the command line parameters. Parameters can either be passed | |||||
| * to the command line and stored to a file (then use the -jp_input=<filename>) | |||||
| * if they are too numerous. | |||||
| * @return the command line parameters | |||||
| */ | |||||
| protected String[] getParameters() { | |||||
| Vector params = new Vector(); | |||||
| params.addElement("-jp_function=" + function); | |||||
| if (vm != null) { | |||||
| params.addElement("-jp_vm=" + vm); | |||||
| } | |||||
| if (javaExe != null) { | |||||
| params.addElement("-jp_java_exe=" + getProject().resolveFile(javaExe.getPath())); | |||||
| } | |||||
| params.addElement("-jp_working_dir=" + workingDir.getPath()); | |||||
| params.addElement("-jp_snapshot_dir=" + snapshotDir.getPath()); | |||||
| params.addElement("-jp_record_from_start=" + recordFromStart); | |||||
| params.addElement("-jp_warn=" + warnLevel); | |||||
| if (seedName != null) { | |||||
| params.addElement("-jp_output_file=" + seedName); | |||||
| } | |||||
| params.addElement("-jp_filter=" + filters.toString()); | |||||
| if (triggers != null) { | |||||
| params.addElement("-jp_trigger=" + triggers.toString()); | |||||
| } | |||||
| if (finalSnapshot != null) { | |||||
| params.addElement("-jp_final_snapshot=" + finalSnapshot); | |||||
| } | |||||
| params.addElement("-jp_exit_prompt=" + exitPrompt); | |||||
| //params.addElement("-jp_append=" + append); | |||||
| params.addElement("-jp_track_natives=" + trackNatives); | |||||
| //.... now the jvm | |||||
| // arguments | |||||
| String[] vmargs = cmdlJava.getVmCommand().getArguments(); | |||||
| for (int i = 0; i < vmargs.length; i++) { | |||||
| params.addElement(vmargs[i]); | |||||
| } | |||||
| // classpath | |||||
| Path classpath = cmdlJava.getClasspath(); | |||||
| if (classpath != null && classpath.size() > 0) { | |||||
| params.addElement("-classpath " + classpath.toString()); | |||||
| } | |||||
| // classname (runner or standalone) | |||||
| if (cmdlJava.getClassname() != null) { | |||||
| params.addElement(cmdlJava.getClassname()); | |||||
| } | |||||
| // arguments for classname | |||||
| String[] args = cmdlJava.getJavaCommand().getArguments(); | |||||
| for (int i = 0; i < args.length; i++) { | |||||
| params.addElement(args[i]); | |||||
| } | |||||
| String[] array = new String[params.size()]; | |||||
| params.copyInto(array); | |||||
| return array; | |||||
| } | |||||
| /** | |||||
| * create the parameter file from the given options. The file is | |||||
| * created with a random name in the current directory. | |||||
| * @return the file object where are written the configuration to run | |||||
| * JProbe Coverage | |||||
| * @throws BuildException thrown if something bad happens while writing | |||||
| * the arguments to the file. | |||||
| */ | |||||
| protected File createParamFile() throws BuildException { | |||||
| //@todo change this when switching to JDK 1.2 and use File.createTmpFile() | |||||
| File file = createTempFile("jpcov"); | |||||
| file.deleteOnExit(); | |||||
| log("Creating parameter file: " + file, Project.MSG_VERBOSE); | |||||
| // options need to be one per line in the parameter file | |||||
| // so write them all in a single string | |||||
| StringWriter sw = new StringWriter(); | |||||
| PrintWriter pw = new PrintWriter(sw); | |||||
| String[] params = getParameters(); | |||||
| for (int i = 0; i < params.length; i++) { | |||||
| pw.println(params[i]); | |||||
| } | |||||
| pw.flush(); | |||||
| log("JProbe Coverage parameters:\n" + sw.toString(), Project.MSG_VERBOSE); | |||||
| // now write them to the file | |||||
| FileWriter fw = null; | |||||
| try { | |||||
| fw = new FileWriter(file); | |||||
| fw.write(sw.toString()); | |||||
| fw.flush(); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Could not write parameter file " + file, e); | |||||
| } finally { | |||||
| if (fw != null) { | |||||
| try { | |||||
| fw.close(); | |||||
| } catch (IOException ignored) { | |||||
| // Ignore Exception | |||||
| } | |||||
| } | |||||
| } | |||||
| return file; | |||||
| } | |||||
| /** specific pumper to avoid those nasty stdin issues */ | |||||
| static class CoverageStreamHandler extends LogStreamHandler { | |||||
| CoverageStreamHandler(Task task) { | |||||
| super(task, Project.MSG_INFO, Project.MSG_WARN); | |||||
| } | |||||
| /** | |||||
| * there are some issues concerning all JProbe executable | |||||
| * In our case a 'Press ENTER to close this window..." will | |||||
| * be displayed in the current window waiting for enter. | |||||
| * So I'm closing the stream right away to avoid problems. | |||||
| */ | |||||
| public void setProcessInputStream(OutputStream os) { | |||||
| try { | |||||
| os.close(); | |||||
| } catch (IOException ignored) { | |||||
| // Ignore exception | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,172 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.util.Vector; | |||||
| /** | |||||
| * Filters information from coverage, somewhat similar to a <tt>FileSet</tt>. | |||||
| * | |||||
| */ | |||||
| public class Filters { | |||||
| /** default regexp to exclude everything */ | |||||
| public static final String DEFAULT_EXCLUDE = "*.*():E"; | |||||
| /** say whether we should use the default excludes or not */ | |||||
| protected boolean defaultExclude = true; | |||||
| /** user defined filters */ | |||||
| protected Vector filters = new Vector(); | |||||
| /** Constructor for Filters. */ | |||||
| public Filters() { | |||||
| } | |||||
| /** | |||||
| * Automatically exclude all classes and methods | |||||
| * unless included in nested elements; optional, default true. | |||||
| * @param value a <code>boolean</code> value | |||||
| */ | |||||
| public void setDefaultExclude(boolean value) { | |||||
| defaultExclude = value; | |||||
| } | |||||
| /** | |||||
| * include classes and methods in the analysis | |||||
| * @param incl an nested Include object | |||||
| */ | |||||
| public void addInclude(Include incl) { | |||||
| filters.addElement(incl); | |||||
| } | |||||
| /** | |||||
| * exclude classes and methods from the analysis | |||||
| * @param excl an nested Exclude object | |||||
| */ | |||||
| public void addExclude(Exclude excl) { | |||||
| filters.addElement(excl); | |||||
| } | |||||
| /** | |||||
| * Get a comma separated list of filters. | |||||
| * @return a comma separated list of filters | |||||
| */ | |||||
| public String toString() { | |||||
| StringBuffer buf = new StringBuffer(); | |||||
| final int size = filters.size(); | |||||
| if (defaultExclude) { | |||||
| buf.append(DEFAULT_EXCLUDE); | |||||
| if (size > 0) { | |||||
| buf.append(','); | |||||
| } | |||||
| } | |||||
| for (int i = 0; i < size; i++) { | |||||
| buf.append(filters.elementAt(i).toString()); | |||||
| if (i < size - 1) { | |||||
| buf.append(','); | |||||
| } | |||||
| } | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * an includes or excludes element | |||||
| */ | |||||
| public abstract static class FilterElement { | |||||
| protected String clazz; | |||||
| protected String method = "*"; // default is all methods | |||||
| protected boolean enabled = true; // default is enable | |||||
| /** | |||||
| * this one is deprecated. | |||||
| * @param value a <code>String</code> value | |||||
| * @ant.task ignore="true" | |||||
| */ | |||||
| public void setName(String value) { | |||||
| clazz = value; | |||||
| } | |||||
| /** | |||||
| * The classname mask as a simple regular expression; | |||||
| * optional, defaults to "*" | |||||
| * @param value a <code>String</code> value | |||||
| */ | |||||
| public void setClass(String value) { | |||||
| clazz = value; | |||||
| } | |||||
| /** | |||||
| * The method mask as a simple regular expression; | |||||
| * optional, defaults to "*" | |||||
| * @param value a <code>String</code> value | |||||
| */ | |||||
| public void setMethod(String value) { | |||||
| method = value; | |||||
| } | |||||
| /** | |||||
| * enable or disable the filter; optional, default true | |||||
| * @param value a <code>boolean</code> value | |||||
| */ | |||||
| public void setEnabled(boolean value) { | |||||
| enabled = value; | |||||
| } | |||||
| /** | |||||
| * The classname and the method. | |||||
| * @return the classname and the method - "class.method()" | |||||
| */ | |||||
| public String toString() { | |||||
| return clazz + "." + method + "()"; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * A class for the nested include element. | |||||
| */ | |||||
| public static class Include extends FilterElement { | |||||
| /** | |||||
| * The classname and method postfixed with ":I" and (#) if not | |||||
| * enabled. | |||||
| * @return a string version of this filter that can be used on the commandline | |||||
| */ | |||||
| public String toString() { | |||||
| return super.toString() + ":I" + (enabled ? "" : "#"); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * A class for the nested exclude element. | |||||
| */ | |||||
| public static class Exclude extends FilterElement { | |||||
| /** | |||||
| * The classname and method postfixed with ":E" and (#) if not | |||||
| * enabled. | |||||
| * @return a string version of this filter that can be used on the commandline | |||||
| */ | |||||
| public String toString() { | |||||
| return super.toString() + ":E" + (enabled ? "" : "#"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,164 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.util.regexp.RegexpMatcher; | |||||
| import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; | |||||
| /** | |||||
| * Filters information from coverage, somewhat similar to a <tt>FileSet</tt>. | |||||
| * | |||||
| */ | |||||
| public class ReportFilters { | |||||
| /** user defined filters */ | |||||
| protected Vector filters = new Vector(); | |||||
| /** cached matcher for each filter */ | |||||
| protected Vector matchers = null; | |||||
| /** Constructor for ReportFilters. */ | |||||
| public ReportFilters() { | |||||
| } | |||||
| /** | |||||
| * Add an include nested element. | |||||
| * @param incl an include filter element | |||||
| */ | |||||
| public void addInclude(Include incl) { | |||||
| filters.addElement(incl); | |||||
| } | |||||
| /** | |||||
| * Add an exclude nested element. | |||||
| * @param excl an exclude filter element | |||||
| */ | |||||
| public void addExclude(Exclude excl) { | |||||
| filters.addElement(excl); | |||||
| } | |||||
| /** | |||||
| * Get the number of nested filters. | |||||
| * @return the number | |||||
| */ | |||||
| public int size() { | |||||
| return filters.size(); | |||||
| } | |||||
| /** | |||||
| * Check whether a given <classname><method>() is accepted by the list | |||||
| * of filters or not. | |||||
| * @param methodname the full method name in the format <classname><method>() | |||||
| * @return true if the methodname passes the list of filters | |||||
| */ | |||||
| public boolean accept(String methodname) { | |||||
| // I'm deferring matcher instantiations at runtime to avoid computing | |||||
| // the filters at parsing time | |||||
| if (matchers == null) { | |||||
| createMatchers(); | |||||
| } | |||||
| boolean result = false; | |||||
| // assert filters.size() == matchers.size() | |||||
| final int size = filters.size(); | |||||
| for (int i = 0; i < size; i++) { | |||||
| FilterElement filter = (FilterElement) filters.elementAt(i); | |||||
| RegexpMatcher matcher = (RegexpMatcher) matchers.elementAt(i); | |||||
| if (filter instanceof Include) { | |||||
| result = result || matcher.matches(methodname); | |||||
| } else if (filter instanceof Exclude) { | |||||
| result = result && !matcher.matches(methodname); | |||||
| } else { | |||||
| //not possible | |||||
| throw new IllegalArgumentException("Invalid filter element: " | |||||
| + filter.getClass().getName()); | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /** should be called only once to cache matchers */ | |||||
| protected void createMatchers() { | |||||
| RegexpMatcherFactory factory = new RegexpMatcherFactory(); | |||||
| final int size = filters.size(); | |||||
| matchers = new Vector(); | |||||
| for (int i = 0; i < size; i++) { | |||||
| FilterElement filter = (FilterElement) filters.elementAt(i); | |||||
| RegexpMatcher matcher = factory.newRegexpMatcher(); | |||||
| String pattern = filter.getAsPattern(); | |||||
| matcher.setPattern(pattern); | |||||
| matchers.addElement(matcher); | |||||
| } | |||||
| } | |||||
| /** default abstract filter element class */ | |||||
| public abstract static class FilterElement { | |||||
| protected String clazz = "*"; // default is all classes | |||||
| protected String method = "*"; // default is all methods | |||||
| /** | |||||
| * Set the class name to match | |||||
| * Default is match all classes | |||||
| * @param value the classname to match | |||||
| */ | |||||
| public void setClass(String value) { | |||||
| clazz = value; | |||||
| } | |||||
| /** | |||||
| * Set the method name to match. | |||||
| * Default is "*", match all methods | |||||
| * @param value the method name to match | |||||
| */ | |||||
| public void setMethod(String value) { | |||||
| method = value; | |||||
| } | |||||
| /** | |||||
| * Get a regular expression matching this filter. | |||||
| * @return a regular expression pattern matching this filer. | |||||
| */ | |||||
| public String getAsPattern() { | |||||
| StringBuffer buf = new StringBuffer(toString()); | |||||
| StringUtil.replace(buf, ".", "\\."); | |||||
| StringUtil.replace(buf, "*", ".*"); | |||||
| StringUtil.replace(buf, "(", "\\("); | |||||
| StringUtil.replace(buf, ")", "\\)"); | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * Get this object as a string. | |||||
| * The form is ClassName.method(). | |||||
| * @return this filter as a string. | |||||
| */ | |||||
| public String toString() { | |||||
| return clazz + "." + method + "()"; | |||||
| } | |||||
| } | |||||
| /** concrete include class */ | |||||
| public static class Include extends FilterElement { | |||||
| } | |||||
| /** concrete exclude class */ | |||||
| public static class Exclude extends FilterElement { | |||||
| } | |||||
| } | |||||
| @@ -1,60 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| /** | |||||
| * Define a host and port to connect to if you want to do remote viewing. | |||||
| * <tt><socket/></tt> defaults to host 127.0.0.1 and port 4444 | |||||
| * | |||||
| * Otherwise it requires the host and port attributes to be set: | |||||
| * <tt> | |||||
| * <socket host="e;175.30.12.1"e; port="e;4567"e;/> | |||||
| * </tt> | |||||
| */ | |||||
| public class Socket { | |||||
| /** default to localhost */ | |||||
| private String host = "127.0.0.1"; | |||||
| /** default to 4444 */ | |||||
| private int port = 4444; | |||||
| /** | |||||
| * the host name/ip of the machine on which the Viewer is running; | |||||
| * defaults to localhost. | |||||
| * @param value the home name/ip | |||||
| */ | |||||
| public void setHost(String value) { | |||||
| host = value; | |||||
| } | |||||
| /** | |||||
| * Optional port number for the viewer; default is 4444 | |||||
| * @param value the port number | |||||
| */ | |||||
| public void setPort(Integer value) { | |||||
| port = value.intValue(); | |||||
| } | |||||
| /** | |||||
| * if no host is set, returning ':<port>', will take localhost | |||||
| * @return "host:port" | |||||
| */ | |||||
| public String toString() { | |||||
| return host + ":" + port; | |||||
| } | |||||
| } | |||||
| @@ -1,46 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| /** | |||||
| * String utilities method. | |||||
| */ | |||||
| public final class StringUtil { | |||||
| /** private constructor, it's a utility class */ | |||||
| private StringUtil() { | |||||
| } | |||||
| /** | |||||
| * Replaces all occurences of <tt>find</tt> with <tt>replacement</tt> in the | |||||
| * source StringBuffer. | |||||
| * @param src the original string buffer to modify. | |||||
| * @param find the string to be replaced. | |||||
| * @param replacement the replacement string for <tt>find</tt> matches. | |||||
| */ | |||||
| public static void replace(StringBuffer src, String find, String replacement) { | |||||
| int index = 0; | |||||
| while (index < src.length()) { | |||||
| index = src.toString().indexOf(find, index); | |||||
| if (index == -1) { | |||||
| break; | |||||
| } | |||||
| src.delete(index, index + find.length()); | |||||
| src.insert(index, replacement); | |||||
| index += replacement.length() + 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,153 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| /** | |||||
| * Trigger information. It will return as a command line argument by calling | |||||
| * the <tt>toString()</tt> method. | |||||
| * | |||||
| */ | |||||
| public class Triggers { | |||||
| protected Vector triggers = new Vector(); | |||||
| /** Constructor of Triggers. */ | |||||
| public Triggers() { | |||||
| } | |||||
| /** | |||||
| * add a method trigger | |||||
| * @param method a method to trigger on | |||||
| */ | |||||
| public void addMethod(Method method) { | |||||
| triggers.addElement(method); | |||||
| } | |||||
| /** | |||||
| * Get the command line option of the form | |||||
| * -jp_trigger=ClassName.*():E:S,ClassName.MethodName():X:X | |||||
| * @return a trigger option | |||||
| */ | |||||
| public String toString() { | |||||
| StringBuffer buf = new StringBuffer(); | |||||
| final int size = triggers.size(); | |||||
| for (int i = 0; i < size; i++) { | |||||
| buf.append(triggers.elementAt(i).toString()); | |||||
| if (i < size - 1) { | |||||
| buf.append(','); | |||||
| } | |||||
| } | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * A trigger for the coverage report | |||||
| */ | |||||
| public static class Method { | |||||
| protected String name; | |||||
| protected String event; | |||||
| protected String action; | |||||
| protected String param; | |||||
| /** | |||||
| * The name of the method(s) as a regular expression. The name | |||||
| * is the fully qualified name on the form <tt>package.classname.method</tt> | |||||
| * required. | |||||
| * @param value the fully qualified name | |||||
| */ | |||||
| public void setName(String value) { | |||||
| name = value; | |||||
| } | |||||
| /** | |||||
| * the event on the method that will trigger the action. Must be | |||||
| * "enter" or "exit" | |||||
| * required. | |||||
| * @param value the event - either "enter" or "exit" | |||||
| */ | |||||
| public void setEvent(String value) { | |||||
| if (EVENT_MAP.get(value) == null) { | |||||
| throw new BuildException("Invalid event, must be one of " + EVENT_MAP); | |||||
| } | |||||
| event = value; | |||||
| } | |||||
| /** | |||||
| * The action to execute; required. Must be one of "clear", | |||||
| * "pause", "resume", "snapshot", "suspend", | |||||
| * or "exit". They respectively clear recording, pause recording, | |||||
| * resume recording, take a snapshot, suspend the recording and exit the program. | |||||
| * @param value the action - "clear", "pause", "resume", "snapshot", "suspend" | |||||
| * or "exit" | |||||
| * @throws BuildException on error | |||||
| */ | |||||
| public void setAction(String value) throws BuildException { | |||||
| if (ACTION_MAP.get(value) == null) { | |||||
| throw new BuildException("Invalid action, must be one of " + ACTION_MAP); | |||||
| } | |||||
| action = value; | |||||
| } | |||||
| /** | |||||
| * A alphanumeric custom name for the snapshot; optional. | |||||
| * @param value the custom name for the snapshot | |||||
| */ | |||||
| public void setParam(String value) { | |||||
| param = value; | |||||
| } | |||||
| /** | |||||
| * @return <name>:<event>:<action>[:param] | |||||
| */ | |||||
| public String toString() { | |||||
| StringBuffer buf = new StringBuffer(); | |||||
| buf.append(name).append(":"); //@todo name must not be null, check for it | |||||
| buf.append(EVENT_MAP.get(event)).append(":"); | |||||
| buf.append(ACTION_MAP.get(action)); | |||||
| if (param != null) { | |||||
| buf.append(":").append(param); | |||||
| } | |||||
| return buf.toString(); | |||||
| } | |||||
| } | |||||
| /** mapping of actions to cryptic command line mnemonics */ | |||||
| private static final Hashtable ACTION_MAP = new Hashtable(3); | |||||
| /** mapping of events to cryptic command line mnemonics */ | |||||
| private static final Hashtable EVENT_MAP = new Hashtable(3); | |||||
| static { | |||||
| ACTION_MAP.put("enter", "E"); | |||||
| ACTION_MAP.put("exit", "X"); | |||||
| // clear|pause|resume|snapshot|suspend|exit | |||||
| EVENT_MAP.put("clear", "C"); | |||||
| EVENT_MAP.put("pause", "P"); | |||||
| EVENT_MAP.put("resume", "R"); | |||||
| EVENT_MAP.put("snapshot", "S"); | |||||
| EVENT_MAP.put("suspend", "A"); | |||||
| EVENT_MAP.put("exit", "X"); | |||||
| } | |||||
| } | |||||
| @@ -1,615 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import java.io.FileInputStream; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.NoSuchElementException; | |||||
| import java.util.Vector; | |||||
| import javax.xml.parsers.DocumentBuilder; | |||||
| import javax.xml.parsers.DocumentBuilderFactory; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.util.JAXPUtils; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.ClassFile; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.ClassPathLoader; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.MethodInfo; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.Utils; | |||||
| import org.w3c.dom.Document; | |||||
| import org.w3c.dom.Element; | |||||
| import org.w3c.dom.Node; | |||||
| import org.w3c.dom.NodeList; | |||||
| import org.xml.sax.InputSource; | |||||
| /** | |||||
| * Little hack to process XML report from JProbe. It will fix | |||||
| * some reporting errors from JProbe 3.0 and makes use of a reference | |||||
| * classpath to add classes/methods that were not reported by JProbe | |||||
| * as being used (ie loaded) | |||||
| * | |||||
| */ | |||||
| public class XMLReport { | |||||
| /** task caller, can be null, used for logging purpose */ | |||||
| private Task task; | |||||
| /** the XML file to process just from CovReport */ | |||||
| private File file; | |||||
| /** jprobe home path. It is used to get the DTD */ | |||||
| private File jprobeHome; | |||||
| /** parsed document */ | |||||
| private Document report; | |||||
| /** | |||||
| * mapping of class names to <code>ClassFile</code>s from the reference | |||||
| * classpath. It is used to filter the JProbe report. | |||||
| */ | |||||
| private Hashtable classFiles; | |||||
| /** mapping package name / package node for faster access */ | |||||
| private Hashtable pkgMap; | |||||
| /** mapping classname / class node for faster access */ | |||||
| private Hashtable classMap; | |||||
| /** method filters */ | |||||
| private ReportFilters filters; | |||||
| /** | |||||
| * Create a new XML report, logging will be on stdout. | |||||
| * @param file the file to place the report in | |||||
| */ | |||||
| public XMLReport(File file) { | |||||
| this(null, file); | |||||
| } | |||||
| /** | |||||
| * Create a new XML report, logging done on the task. | |||||
| * @param task the task to use for logging | |||||
| * @param file the file to place the report in | |||||
| */ | |||||
| public XMLReport(Task task, File file) { | |||||
| this.file = file; | |||||
| this.task = task; | |||||
| } | |||||
| /** | |||||
| * Set the JProbe home path. Used to get the DTD. | |||||
| * @param home the JProbe directory | |||||
| */ | |||||
| public void setJProbehome(File home) { | |||||
| jprobeHome = home; | |||||
| } | |||||
| /** | |||||
| * set the filters attribute. | |||||
| * @param filters a filtersreport value | |||||
| */ | |||||
| public void setReportFilters(ReportFilters filters) { | |||||
| this.filters = filters; | |||||
| } | |||||
| /** create node maps so that we can access node faster by their name */ | |||||
| protected void createNodeMaps() { | |||||
| pkgMap = new Hashtable(); | |||||
| classMap = new Hashtable(); | |||||
| // create a map index of all packages by their name | |||||
| // @todo can be done faster by direct access. | |||||
| NodeList packages = report.getElementsByTagName("package"); | |||||
| final int pkglen = packages.getLength(); | |||||
| log("Indexing " + pkglen + " packages"); | |||||
| for (int i = pkglen - 1; i > -1; i--) { | |||||
| Element pkg = (Element) packages.item(i); | |||||
| String pkgname = pkg.getAttribute("name"); | |||||
| int nbclasses = 0; | |||||
| // create a map index of all classes by their fully | |||||
| // qualified name. | |||||
| NodeList classes = pkg.getElementsByTagName("class"); | |||||
| final int classlen = classes.getLength(); | |||||
| log("Indexing " + classlen + " classes in package " + pkgname); | |||||
| for (int j = classlen - 1; j > -1; j--) { | |||||
| Element clazz = (Element) classes.item(j); | |||||
| String classname = clazz.getAttribute("name"); | |||||
| if (pkgname != null && pkgname.length() != 0) { | |||||
| classname = pkgname + "." + classname; | |||||
| } | |||||
| int nbmethods = 0; | |||||
| NodeList methods = clazz.getElementsByTagName("method"); | |||||
| final int methodlen = methods.getLength(); | |||||
| for (int k = methodlen - 1; k > -1; k--) { | |||||
| Element meth = (Element) methods.item(k); | |||||
| StringBuffer methodname = new StringBuffer(meth.getAttribute("name")); | |||||
| methodname.delete(methodname.toString().indexOf("("), | |||||
| methodname.toString().length()); | |||||
| String signature = classname + "." + methodname + "()"; | |||||
| if (filters.accept(signature)) { | |||||
| log("kept method:" + signature); | |||||
| nbmethods++; | |||||
| } else { | |||||
| clazz.removeChild(meth); | |||||
| } | |||||
| } | |||||
| // if we don't keep any method, we don't keep the class | |||||
| if (nbmethods != 0 && classFiles.containsKey(classname)) { | |||||
| log("Adding class '" + classname + "'"); | |||||
| classMap.put(classname, clazz); | |||||
| nbclasses++; | |||||
| } else { | |||||
| pkg.removeChild(clazz); | |||||
| } | |||||
| } | |||||
| if (nbclasses != 0) { | |||||
| log("Adding package '" + pkgname + "'"); | |||||
| pkgMap.put(pkgname, pkg); | |||||
| } else { | |||||
| pkg.getParentNode().removeChild(pkg); | |||||
| } | |||||
| } | |||||
| log("Indexed " + classMap.size() + " classes in " + pkgMap.size() + " packages"); | |||||
| } | |||||
| /** | |||||
| * Create the whole new document. | |||||
| * @param classPath the classpath | |||||
| * @return a dom document | |||||
| * @throws Exception on error | |||||
| */ | |||||
| public Document createDocument(String[] classPath) throws Exception { | |||||
| // Iterate over the classpath to identify reference classes | |||||
| classFiles = new Hashtable(); | |||||
| ClassPathLoader cpl = new ClassPathLoader(classPath); | |||||
| Enumeration e = cpl.loaders(); | |||||
| while (e.hasMoreElements()) { | |||||
| ClassPathLoader.FileLoader fl = (ClassPathLoader.FileLoader) e.nextElement(); | |||||
| ClassFile[] classes = fl.getClasses(); | |||||
| log("Processing " + classes.length + " classes in " + fl.getFile()); | |||||
| // process all classes | |||||
| for (int i = 0; i < classes.length; i++) { | |||||
| classFiles.put(classes[i].getFullName(), classes[i]); | |||||
| } | |||||
| } | |||||
| // Load the JProbe coverage XML report | |||||
| DocumentBuilder dbuilder = newBuilder(); | |||||
| InputSource is = new InputSource(new FileInputStream(file)); | |||||
| if (jprobeHome != null) { | |||||
| File dtdDir = new File(jprobeHome, "dtd"); | |||||
| is.setSystemId(JAXPUtils.getSystemId(dtdDir)); | |||||
| } | |||||
| report = dbuilder.parse(is); | |||||
| report.normalize(); | |||||
| // create maps for faster node access (also filters out unwanted nodes) | |||||
| createNodeMaps(); | |||||
| // Make sure each class from the reference path ends up in the report | |||||
| Enumeration classes = classFiles.elements(); | |||||
| while (classes.hasMoreElements()) { | |||||
| ClassFile cf = (ClassFile) classes.nextElement(); | |||||
| serializeClass(cf); | |||||
| } | |||||
| // update the document with the stats | |||||
| update(); | |||||
| return report; | |||||
| } | |||||
| /** | |||||
| * JProbe does not put the java.lang prefix for classes | |||||
| * in this package, so used this nice method so that | |||||
| * I have the same signature for methods | |||||
| * @param method info on a method | |||||
| * @return a method signature with the "java.lang" prefixes removed from | |||||
| * the method arguments | |||||
| */ | |||||
| protected String getMethodSignature(MethodInfo method) { | |||||
| StringBuffer buf = new StringBuffer(method.getName()); | |||||
| buf.append("("); | |||||
| String[] params = method.getParametersType(); | |||||
| for (int i = 0; i < params.length; i++) { | |||||
| String type = params[i]; | |||||
| int pos = type.lastIndexOf('.'); | |||||
| if (pos != -1) { | |||||
| String pkg = type.substring(0, pos); | |||||
| if ("java.lang".equals(pkg)) { | |||||
| params[i] = type.substring(pos + 1); | |||||
| } | |||||
| } | |||||
| buf.append(params[i]); | |||||
| if (i != params.length - 1) { | |||||
| buf.append(", "); | |||||
| } | |||||
| } | |||||
| buf.append(")"); | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * Convert to a CovReport-like signature - <classname>.<method>(). | |||||
| * @param clazz the class to use | |||||
| * @param method the method to use | |||||
| * @return the CovReport-like signature | |||||
| */ | |||||
| protected String getMethodSignature(ClassFile clazz, MethodInfo method) { | |||||
| StringBuffer buf = new StringBuffer(clazz.getFullName()); | |||||
| buf.append("."); | |||||
| buf.append(method.getName()); | |||||
| buf.append("()"); | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * Do additional work on an element to remove abstract methods that | |||||
| * are reported by JProbe 3.0 | |||||
| * @param classFile the class to use | |||||
| * @param classNode information on the class | |||||
| */ | |||||
| protected void removeAbstractMethods(ClassFile classFile, Element classNode) { | |||||
| MethodInfo[] methods = classFile.getMethods(); | |||||
| Hashtable methodNodeList = getMethods(classNode); | |||||
| // assert xmlMethods.size() == methods.length() | |||||
| final int size = methods.length; | |||||
| for (int i = 0; i < size; i++) { | |||||
| MethodInfo method = methods[i]; | |||||
| String methodSig = getMethodSignature(method); | |||||
| Element methodNode = (Element) methodNodeList.get(methodSig); | |||||
| if (methodNode != null | |||||
| && Utils.isAbstract(method.getAccessFlags())) { | |||||
| log("\tRemoving abstract method " + methodSig); | |||||
| classNode.removeChild(methodNode); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Create an empty method element with its cov.data values. | |||||
| * @param method jprobe info on a method | |||||
| * @return the method element | |||||
| */ | |||||
| protected Element createMethodElement(MethodInfo method) { | |||||
| String methodsig = getMethodSignature(method); | |||||
| Element methodElem = report.createElement("method"); | |||||
| methodElem.setAttribute("name", methodsig); | |||||
| // create the method cov.data element | |||||
| Element methodData = report.createElement("cov.data"); | |||||
| methodElem.appendChild(methodData); | |||||
| methodData.setAttribute("calls", "0"); | |||||
| methodData.setAttribute("hit_lines", "0"); | |||||
| methodData.setAttribute("total_lines", String.valueOf(method.getNumberOfLines())); | |||||
| return methodElem; | |||||
| } | |||||
| /** | |||||
| * Create an empty package element with its default cov.data (0). | |||||
| * @param pkgname the packet name | |||||
| * @return the package element | |||||
| */ | |||||
| protected Element createPackageElement(String pkgname) { | |||||
| Element pkgElem = report.createElement("package"); | |||||
| pkgElem.setAttribute("name", pkgname); | |||||
| // create the package cov.data element / default | |||||
| // must be updated at the end of the whole process | |||||
| Element pkgData = report.createElement("cov.data"); | |||||
| pkgElem.appendChild(pkgData); | |||||
| pkgData.setAttribute("calls", "0"); | |||||
| pkgData.setAttribute("hit_methods", "0"); | |||||
| pkgData.setAttribute("total_methods", "0"); | |||||
| pkgData.setAttribute("hit_lines", "0"); | |||||
| pkgData.setAttribute("total_lines", "0"); | |||||
| return pkgElem; | |||||
| } | |||||
| /** | |||||
| * Create an empty class element with its default cov.data (0). | |||||
| * @param classFile jprobe class info | |||||
| * @return an class element | |||||
| */ | |||||
| protected Element createClassElement(ClassFile classFile) { | |||||
| // create the class element | |||||
| Element classElem = report.createElement("class"); | |||||
| classElem.setAttribute("name", classFile.getName()); | |||||
| // source file possibly does not exist in the bytecode | |||||
| if (null != classFile.getSourceFile()) { | |||||
| classElem.setAttribute("source", classFile.getSourceFile()); | |||||
| } | |||||
| // create the cov.data elem | |||||
| Element classData = report.createElement("cov.data"); | |||||
| classElem.appendChild(classData); | |||||
| // create the class cov.data element | |||||
| classData.setAttribute("calls", "0"); | |||||
| classData.setAttribute("hit_methods", "0"); | |||||
| classData.setAttribute("total_methods", "0"); | |||||
| classData.setAttribute("hit_lines", "0"); | |||||
| classData.setAttribute("total_lines", "0"); | |||||
| return classElem; | |||||
| } | |||||
| /** | |||||
| * serialize a classfile into XML. | |||||
| * @param classFile the class file to serialize | |||||
| */ | |||||
| protected void serializeClass(ClassFile classFile) { | |||||
| // the class already is reported so ignore it | |||||
| String fullclassname = classFile.getFullName(); | |||||
| log("Looking for '" + fullclassname + "'"); | |||||
| Element clazz = (Element) classMap.get(fullclassname); | |||||
| // ignore classes that are already reported, all the information is | |||||
| // already there. | |||||
| if (clazz != null) { | |||||
| log("Ignoring " + fullclassname); | |||||
| removeAbstractMethods(classFile, clazz); | |||||
| return; | |||||
| } | |||||
| // ignore interfaces files, there is no code in there to cover. | |||||
| if (Utils.isInterface(classFile.getAccess())) { | |||||
| return; | |||||
| } | |||||
| Vector methods = getFilteredMethods(classFile); | |||||
| // no need to process, there are no methods to add for this class. | |||||
| if (methods.size() == 0) { | |||||
| return; | |||||
| } | |||||
| String pkgname = classFile.getPackage(); | |||||
| // System.out.println("Looking for package " + pkgname); | |||||
| Element pkgElem = (Element) pkgMap.get(pkgname); | |||||
| if (pkgElem == null) { | |||||
| pkgElem = createPackageElement(pkgname); | |||||
| report.getDocumentElement().appendChild(pkgElem); | |||||
| pkgMap.put(pkgname, pkgElem); // add the pkg to the map | |||||
| } | |||||
| // this is a brand new class, so we have to create a new node | |||||
| // create the class element | |||||
| Element classElem = createClassElement(classFile); | |||||
| pkgElem.appendChild(classElem); | |||||
| int total_lines = 0; | |||||
| int total_methods = 0; | |||||
| final int count = methods.size(); | |||||
| for (int i = 0; i < count; i++) { | |||||
| // create the method element | |||||
| MethodInfo method = (MethodInfo) methods.elementAt(i); | |||||
| if (Utils.isAbstract(method.getAccessFlags())) { | |||||
| continue; // no need to report abstract methods | |||||
| } | |||||
| Element methodElem = createMethodElement(method); | |||||
| classElem.appendChild(methodElem); | |||||
| total_lines += method.getNumberOfLines(); | |||||
| total_methods++; | |||||
| } | |||||
| // create the class cov.data element | |||||
| Element classData = getCovDataChild(classElem); | |||||
| classData.setAttribute("total_methods", String.valueOf(total_methods)); | |||||
| classData.setAttribute("total_lines", String.valueOf(total_lines)); | |||||
| // add itself to the node map | |||||
| classMap.put(fullclassname, classElem); | |||||
| } | |||||
| /** | |||||
| * Get the methods from a classFile that pass the filters. | |||||
| * @param classFile the class file to get the methods from | |||||
| * @return the list of methods | |||||
| */ | |||||
| protected Vector getFilteredMethods(ClassFile classFile) { | |||||
| MethodInfo[] methodlist = classFile.getMethods(); | |||||
| Vector methods = new Vector(methodlist.length); | |||||
| for (int i = 0; i < methodlist.length; i++) { | |||||
| MethodInfo method = methodlist[i]; | |||||
| String signature = getMethodSignature(classFile, method); | |||||
| if (filters.accept(signature)) { | |||||
| methods.addElement(method); | |||||
| log("keeping " + signature); | |||||
| } else { | |||||
| // log("discarding " + signature); | |||||
| } | |||||
| } | |||||
| return methods; | |||||
| } | |||||
| /** update the count of the XML, that is accumulate the stats on | |||||
| * methods, classes and package so that the numbers are valid | |||||
| * according to the info that was appended to the XML. | |||||
| */ | |||||
| protected void update() { | |||||
| int calls = 0; | |||||
| int hit_methods = 0; | |||||
| int total_methods = 0; | |||||
| int hit_lines = 0; | |||||
| int total_lines = 0; | |||||
| // use the map for access, all nodes should be there | |||||
| Enumeration e = pkgMap.elements(); | |||||
| while (e.hasMoreElements()) { | |||||
| Element pkgElem = (Element) e.nextElement(); | |||||
| String pkgname = pkgElem.getAttribute("name"); | |||||
| Element[] classes = getClasses(pkgElem); | |||||
| int pkg_calls = 0; | |||||
| int pkg_hit_methods = 0; | |||||
| int pkg_total_methods = 0; | |||||
| int pkg_hit_lines = 0; | |||||
| int pkg_total_lines = 0; | |||||
| //System.out.println("Processing package '" + pkgname + "': " | |||||
| // + classes.length + " classes"); | |||||
| for (int j = 0; j < classes.length; j++) { | |||||
| Element clazz = classes[j]; | |||||
| String classname = clazz.getAttribute("name"); | |||||
| if (pkgname != null && pkgname.length() != 0) { | |||||
| classname = pkgname + "." + classname; | |||||
| } | |||||
| // there's only cov.data as a child so bet on it | |||||
| Element covdata = getCovDataChild(clazz); | |||||
| try { | |||||
| pkg_calls += Integer.parseInt(covdata.getAttribute("calls")); | |||||
| pkg_hit_methods += Integer.parseInt(covdata.getAttribute("hit_methods")); | |||||
| pkg_total_methods += Integer.parseInt(covdata.getAttribute("total_methods")); | |||||
| pkg_hit_lines += Integer.parseInt(covdata.getAttribute("hit_lines")); | |||||
| pkg_total_lines += Integer.parseInt(covdata.getAttribute("total_lines")); | |||||
| } catch (NumberFormatException ex) { | |||||
| log("Error parsing '" + classname + "' (" + j + "/" | |||||
| + classes.length + ") in package '" + pkgname + "'"); | |||||
| throw ex; | |||||
| } | |||||
| } | |||||
| Element covdata = getCovDataChild(pkgElem); | |||||
| covdata.setAttribute("calls", String.valueOf(pkg_calls)); | |||||
| covdata.setAttribute("hit_methods", String.valueOf(pkg_hit_methods)); | |||||
| covdata.setAttribute("total_methods", String.valueOf(pkg_total_methods)); | |||||
| covdata.setAttribute("hit_lines", String.valueOf(pkg_hit_lines)); | |||||
| covdata.setAttribute("total_lines", String.valueOf(pkg_total_lines)); | |||||
| calls += pkg_calls; | |||||
| hit_methods += pkg_hit_methods; | |||||
| total_methods += pkg_total_methods; | |||||
| hit_lines += pkg_hit_lines; | |||||
| total_lines += pkg_total_lines; | |||||
| } | |||||
| Element covdata = getCovDataChild(report.getDocumentElement()); | |||||
| covdata.setAttribute("calls", String.valueOf(calls)); | |||||
| covdata.setAttribute("hit_methods", String.valueOf(hit_methods)); | |||||
| covdata.setAttribute("total_methods", String.valueOf(total_methods)); | |||||
| covdata.setAttribute("hit_lines", String.valueOf(hit_lines)); | |||||
| covdata.setAttribute("total_lines", String.valueOf(total_lines)); | |||||
| } | |||||
| /** | |||||
| * Search for an element with the tag "cov.data" in the children | |||||
| * of the parent element and return it. | |||||
| * @param parent the parent element to search in | |||||
| * @return the "cov.data" element | |||||
| * @throws NoSuchElementException if unable to find a cov.data element | |||||
| */ | |||||
| protected Element getCovDataChild(Element parent) { | |||||
| NodeList children = parent.getChildNodes(); | |||||
| int len = children.getLength(); | |||||
| for (int i = 0; i < len; i++) { | |||||
| Node child = children.item(i); | |||||
| if (child.getNodeType() == Node.ELEMENT_NODE) { | |||||
| Element elem = (Element) child; | |||||
| if ("cov.data".equals(elem.getNodeName())) { | |||||
| return elem; | |||||
| } | |||||
| } | |||||
| } | |||||
| throw new NoSuchElementException("Could not find 'cov.data' " | |||||
| + "element in parent '" + parent.getNodeName() + "'"); | |||||
| } | |||||
| /** | |||||
| * Get the method elements of an class element. | |||||
| * @param clazz the element to search it | |||||
| * @return a name to element map of methods | |||||
| */ | |||||
| protected Hashtable getMethods(Element clazz) { | |||||
| Hashtable map = new Hashtable(); | |||||
| NodeList children = clazz.getChildNodes(); | |||||
| int len = children.getLength(); | |||||
| for (int i = 0; i < len; i++) { | |||||
| Node child = children.item(i); | |||||
| if (child.getNodeType() == Node.ELEMENT_NODE) { | |||||
| Element elem = (Element) child; | |||||
| if ("method".equals(elem.getNodeName())) { | |||||
| String name = elem.getAttribute("name"); | |||||
| map.put(name, elem); | |||||
| } | |||||
| } | |||||
| } | |||||
| return map; | |||||
| } | |||||
| /** | |||||
| * Get the class elements of an package element. | |||||
| * @param pkg the element to search it | |||||
| * @return an array of class elements | |||||
| */ | |||||
| protected Element[] getClasses(Element pkg) { | |||||
| Vector v = new Vector(); | |||||
| NodeList children = pkg.getChildNodes(); | |||||
| int len = children.getLength(); | |||||
| for (int i = 0; i < len; i++) { | |||||
| Node child = children.item(i); | |||||
| if (child.getNodeType() == Node.ELEMENT_NODE) { | |||||
| Element elem = (Element) child; | |||||
| if ("class".equals(elem.getNodeName())) { | |||||
| v.addElement(elem); | |||||
| } | |||||
| } | |||||
| } | |||||
| Element[] elems = new Element[v.size()]; | |||||
| v.copyInto(elems); | |||||
| return elems; | |||||
| } | |||||
| /** | |||||
| * Get the package elements of an snapshot element. | |||||
| * @param snapshot the element to search it | |||||
| * @return an array of package elements | |||||
| */ | |||||
| protected Element[] getPackages(Element snapshot) { | |||||
| Vector v = new Vector(); | |||||
| NodeList children = snapshot.getChildNodes(); | |||||
| int len = children.getLength(); | |||||
| for (int i = 0; i < len; i++) { | |||||
| Node child = children.item(i); | |||||
| if (child.getNodeType() == Node.ELEMENT_NODE) { | |||||
| Element elem = (Element) child; | |||||
| if ("package".equals(elem.getNodeName())) { | |||||
| v.addElement(elem); | |||||
| } | |||||
| } | |||||
| } | |||||
| Element[] elems = new Element[v.size()]; | |||||
| v.copyInto(elems); | |||||
| return elems; | |||||
| } | |||||
| private static DocumentBuilder newBuilder() { | |||||
| try { | |||||
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | |||||
| factory.setIgnoringComments(true); | |||||
| factory.setValidating(false); | |||||
| return factory.newDocumentBuilder(); | |||||
| } catch (Exception e) { | |||||
| throw new ExceptionInInitializerError(e); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a message to the associated task. | |||||
| * @param message a <code>String</code> attribute | |||||
| */ | |||||
| public void log(String message) { | |||||
| if (task == null) { | |||||
| //System.out.println(message); | |||||
| } else { | |||||
| task.log(message, Project.MSG_DEBUG); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,169 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka.bytecode; | |||||
| import java.io.DataInputStream; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ClassCPInfo; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.Utf8CPInfo; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.attributes.AttributeInfo; | |||||
| /** | |||||
| * Object representing a class. | |||||
| * | |||||
| * Information are kept to the strict minimum for JProbe reports so | |||||
| * that not too many objects are created for a class, otherwise the | |||||
| * JVM can quickly run out of memory when analyzing a great deal of | |||||
| * classes and keeping them in memory for global analysis. | |||||
| * | |||||
| */ | |||||
| public final class ClassFile { | |||||
| private MethodInfo[] methods; | |||||
| private String sourceFile; | |||||
| private String fullname; | |||||
| private int access_flags; | |||||
| /** | |||||
| * Constructor for ClassFile. | |||||
| * @param is the input stream containing the class. | |||||
| * @throws IOException on error | |||||
| */ | |||||
| public ClassFile(InputStream is) throws IOException { | |||||
| DataInputStream dis = new DataInputStream(is); | |||||
| ConstantPool constantPool = new ConstantPool(); | |||||
| /* int magic = */ dis.readInt(); // 0xCAFEBABE | |||||
| /* int minor = */ dis.readShort(); | |||||
| /* int major = */ dis.readShort(); | |||||
| constantPool.read(dis); | |||||
| constantPool.resolve(); | |||||
| // class information | |||||
| access_flags = dis.readShort(); | |||||
| int thisClass = dis.readShort(); | |||||
| fullname = ((ClassCPInfo) constantPool.getEntry( | |||||
| thisClass)).getClassName().replace('/', '.'); | |||||
| /* int super_class = */ dis.readShort(); | |||||
| // skip interfaces... | |||||
| int count = dis.readShort(); | |||||
| dis.skipBytes(count * 2); // short | |||||
| // skip fields... | |||||
| int numFields = dis.readShort(); | |||||
| for (int i = 0; i < numFields; i++) { | |||||
| // 3 short: access flags, name index, descriptor index | |||||
| dis.skip(2 * 3); | |||||
| // attribute list... | |||||
| int attributesCount = dis.readUnsignedShort(); | |||||
| for (int j = 0; j < attributesCount; j++) { | |||||
| dis.skipBytes(2); // skip attr_id (short) | |||||
| int len = dis.readInt(); | |||||
| dis.skipBytes(len); | |||||
| } | |||||
| } | |||||
| // read methods | |||||
| int methodCount = dis.readShort(); | |||||
| methods = new MethodInfo[methodCount]; | |||||
| for (int i = 0; i < methodCount; i++) { | |||||
| methods[i] = new MethodInfo(); | |||||
| methods[i].read(constantPool, dis); | |||||
| } | |||||
| // get interesting attributes. | |||||
| int attributesCount = dis.readUnsignedShort(); | |||||
| for (int j = 0; j < attributesCount; j++) { | |||||
| int attrId = dis.readShort(); | |||||
| int len = dis.readInt(); | |||||
| String attrName = Utils.getUTF8Value(constantPool, attrId); | |||||
| if (AttributeInfo.SOURCE_FILE.equals(attrName)) { | |||||
| int nameIndex = dis.readShort(); | |||||
| sourceFile = ((Utf8CPInfo) constantPool.getEntry(nameIndex)).getValue(); | |||||
| } else { | |||||
| dis.skipBytes(len); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the access flags of the class. | |||||
| * @return the flags | |||||
| */ | |||||
| public int getAccess() { | |||||
| return access_flags; | |||||
| } | |||||
| /** | |||||
| * Get the source filename | |||||
| * @return the source filename | |||||
| */ | |||||
| public String getSourceFile() { | |||||
| return sourceFile; | |||||
| } | |||||
| /** | |||||
| * Get the methods of the class. | |||||
| * @return the methods | |||||
| */ | |||||
| public MethodInfo[] getMethods() { | |||||
| return methods; | |||||
| } | |||||
| /** | |||||
| * Get the full name of the class. | |||||
| * @return the full name | |||||
| */ | |||||
| public String getFullName() { | |||||
| return fullname; | |||||
| } | |||||
| /** | |||||
| * Get the name of the class (minus package name) | |||||
| * @return the name | |||||
| */ | |||||
| public String getName() { | |||||
| String name = getFullName(); | |||||
| int pos = name.lastIndexOf('.'); | |||||
| if (pos == -1) { | |||||
| return ""; | |||||
| } | |||||
| return name.substring(pos + 1); | |||||
| } | |||||
| /** | |||||
| * Get the package name of the class. | |||||
| * @return the package name | |||||
| */ | |||||
| public String getPackage() { | |||||
| String name = getFullName(); | |||||
| int pos = name.lastIndexOf('.'); | |||||
| if (pos == -1) { | |||||
| return ""; | |||||
| } | |||||
| return name.substring(0, pos); | |||||
| } | |||||
| } | |||||
| @@ -1,349 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka.bytecode; | |||||
| import java.io.BufferedInputStream; | |||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.ByteArrayOutputStream; | |||||
| import java.io.File; | |||||
| import java.io.FileInputStream; | |||||
| import java.io.FilenameFilter; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.NoSuchElementException; | |||||
| import java.util.StringTokenizer; | |||||
| import java.util.Vector; | |||||
| import java.util.zip.ZipEntry; | |||||
| import java.util.zip.ZipFile; | |||||
| /** | |||||
| * Core of the bytecode analyzer. It loads classes from a given classpath. | |||||
| * | |||||
| */ | |||||
| public class ClassPathLoader { | |||||
| /** A null loader */ | |||||
| public static final FileLoader NULL_LOADER = new NullLoader(); | |||||
| /** the list of files to look for */ | |||||
| private File[] files; | |||||
| /** | |||||
| * create a new instance with a given classpath. It must be urls | |||||
| * separated by the platform specific path separator. | |||||
| * @param classPath the classpath to load all the classes from. | |||||
| */ | |||||
| public ClassPathLoader(String classPath) { | |||||
| StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator); | |||||
| Vector entries = new Vector(); | |||||
| while (st.hasMoreTokens()) { | |||||
| File file = new File(st.nextToken()); | |||||
| entries.addElement(file); | |||||
| } | |||||
| files = new File[entries.size()]; | |||||
| entries.copyInto(files); | |||||
| } | |||||
| /** | |||||
| * create a new instance with a given set of urls. | |||||
| * @param entries valid file urls (either .jar, .zip or directory) | |||||
| */ | |||||
| public ClassPathLoader(String[] entries) { | |||||
| files = new File[entries.length]; | |||||
| for (int i = 0; i < entries.length; i++) { | |||||
| files[i] = new File(entries[i]); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * create a new instance with a given set of urls | |||||
| * @param entries file urls to look for classes (.jar, .zip or directory) | |||||
| */ | |||||
| public ClassPathLoader(File[] entries) { | |||||
| files = entries; | |||||
| } | |||||
| /** the interface to implement to look up for specific resources */ | |||||
| public interface FileLoader { | |||||
| /** | |||||
| * the file url that is looked for .class files. | |||||
| * @return the file | |||||
| */ | |||||
| File getFile(); | |||||
| /** | |||||
| * Return the set of classes found in the file. | |||||
| * @return the list of classes | |||||
| * @throws IOException on error | |||||
| */ | |||||
| ClassFile[] getClasses() throws IOException; | |||||
| } | |||||
| /** | |||||
| * @return the set of <tt>FileLoader</tt> loaders matching the given classpath. | |||||
| */ | |||||
| public Enumeration loaders() { | |||||
| return new LoaderEnumeration(); | |||||
| } | |||||
| /** | |||||
| * return the whole set of classes in the classpath. Note that this method | |||||
| * can be very resource demanding since it must load all bytecode from | |||||
| * all classes in all resources in the classpath at a time. | |||||
| * To process it in a less resource demanding way, it is maybe better to | |||||
| * use the <tt>loaders()</tt> that will return loader one by one. | |||||
| * | |||||
| * @return the hashtable containing ALL classes that are found in the given | |||||
| * classpath. Note that the first entry of a given classname will shadow | |||||
| * classes with the same name (as a classloader does) | |||||
| * @throws IOException on error | |||||
| */ | |||||
| public Hashtable getClasses() throws IOException { | |||||
| Hashtable map = new Hashtable(); | |||||
| Enumeration e = loaders(); | |||||
| while (e.hasMoreElements()) { | |||||
| FileLoader loader = (FileLoader) e.nextElement(); | |||||
| System.out.println("Processing " + loader.getFile()); | |||||
| long t0 = System.currentTimeMillis(); | |||||
| ClassFile[] classes = loader.getClasses(); | |||||
| long dt = System.currentTimeMillis() - t0; | |||||
| System.out.println("" + classes.length + " classes loaded in " + dt + "ms"); | |||||
| for (int j = 0; j < classes.length; j++) { | |||||
| String name = classes[j].getFullName(); | |||||
| // do not allow duplicates entries to preserve 'classpath' behavior | |||||
| // first class in wins | |||||
| if (!map.containsKey(name)) { | |||||
| map.put(name, classes[j]); | |||||
| } | |||||
| } | |||||
| } | |||||
| return map; | |||||
| } | |||||
| /** the loader enumeration that will return loaders */ | |||||
| private class LoaderEnumeration implements Enumeration { | |||||
| private int index = 0; | |||||
| public boolean hasMoreElements() { | |||||
| return index < files.length; | |||||
| } | |||||
| public Object nextElement() { | |||||
| if (index >= files.length) { | |||||
| throw new NoSuchElementException(); | |||||
| } | |||||
| File file = files[index++]; | |||||
| if (!file.exists()) { | |||||
| return new NullLoader(file); | |||||
| } | |||||
| if (file.isDirectory()) { | |||||
| // it's a directory | |||||
| return new DirectoryLoader(file); | |||||
| } else if (file.getName().endsWith(".zip") || file.getName().endsWith(".jar")) { | |||||
| // it's a jar/zip file | |||||
| return new JarLoader(file); | |||||
| } | |||||
| return new NullLoader(file); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * useful methods to read the whole input stream in memory so that | |||||
| * it can be accessed faster. Processing rt.jar and tools.jar from JDK 1.3.1 | |||||
| * brings time from 50s to 7s. | |||||
| * @param is the inout stream to cache | |||||
| * @return the cached input stream | |||||
| * @throws IOException on error | |||||
| */ | |||||
| public static InputStream getCachedStream(InputStream is) throws IOException { | |||||
| final InputStream bis = new BufferedInputStream(is); | |||||
| final byte[] buffer = new byte[8192]; | |||||
| final ByteArrayOutputStream bos = new ByteArrayOutputStream(2048); | |||||
| int n; | |||||
| bos.reset(); | |||||
| while ((n = bis.read(buffer, 0, buffer.length)) != -1) { | |||||
| bos.write(buffer, 0, n); | |||||
| } | |||||
| is.close(); | |||||
| return new ByteArrayInputStream(bos.toByteArray()); | |||||
| } | |||||
| } | |||||
| /** a null loader to return when the file is not valid */ | |||||
| final class NullLoader implements ClassPathLoader.FileLoader { | |||||
| private File file; | |||||
| NullLoader() { | |||||
| this(null); | |||||
| } | |||||
| NullLoader(File file) { | |||||
| this.file = file; | |||||
| } | |||||
| public File getFile() { | |||||
| return file; | |||||
| } | |||||
| public ClassFile[] getClasses() throws IOException { | |||||
| return new ClassFile[0]; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * jar loader specified in looking for classes in jar and zip | |||||
| * @todo read the jar manifest in case there is a Class-Path | |||||
| * entry. | |||||
| */ | |||||
| final class JarLoader implements ClassPathLoader.FileLoader { | |||||
| private File file; | |||||
| JarLoader(File file) { | |||||
| this.file = file; | |||||
| } | |||||
| public File getFile() { | |||||
| return file; | |||||
| } | |||||
| public ClassFile[] getClasses() throws IOException { | |||||
| ZipFile zipFile = new ZipFile(file); | |||||
| Vector v = new Vector(); | |||||
| Enumeration entries = zipFile.entries(); | |||||
| while (entries.hasMoreElements()) { | |||||
| ZipEntry entry = (ZipEntry) entries.nextElement(); | |||||
| if (entry.getName().endsWith(".class")) { | |||||
| InputStream is = ClassPathLoader.getCachedStream(zipFile.getInputStream(entry)); | |||||
| ClassFile classFile = new ClassFile(is); | |||||
| is.close(); | |||||
| v.addElement(classFile); | |||||
| } | |||||
| } | |||||
| ClassFile[] classes = new ClassFile[v.size()]; | |||||
| v.copyInto(classes); | |||||
| return classes; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * directory loader that will look all classes recursively | |||||
| * @todo should discard classes which package name does not | |||||
| * match the directory ? | |||||
| */ | |||||
| final class DirectoryLoader implements ClassPathLoader.FileLoader { | |||||
| private File directory; | |||||
| private static final FilenameFilter DIRECTORY_FILTER = new DirectoryFilter(); | |||||
| private static final FilenameFilter CLASS_FILTER = new ClassFilter(); | |||||
| DirectoryLoader(File dir) { | |||||
| directory = dir; | |||||
| } | |||||
| public File getFile() { | |||||
| return directory; | |||||
| } | |||||
| public ClassFile[] getClasses() throws IOException { | |||||
| Vector v = new Vector(127); | |||||
| Vector files = listFiles(directory, CLASS_FILTER, true); | |||||
| final int filesCount = files.size(); | |||||
| for (int i = 0; i < filesCount; i++) { | |||||
| File file = (File) files.elementAt(i); | |||||
| InputStream is = null; | |||||
| try { | |||||
| is = ClassPathLoader.getCachedStream(new FileInputStream(file)); | |||||
| ClassFile classFile = new ClassFile(is); | |||||
| is.close(); | |||||
| is = null; | |||||
| v.addElement(classFile); | |||||
| } finally { | |||||
| if (is != null) { | |||||
| try { | |||||
| is.close(); | |||||
| } catch (IOException ignored) { | |||||
| // Ignore Exception | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| ClassFile[] classes = new ClassFile[v.size()]; | |||||
| v.copyInto(classes); | |||||
| return classes; | |||||
| } | |||||
| /** | |||||
| * List files that obeys to a specific filter recursively from a given base | |||||
| * directory. | |||||
| * @param directory the directory where to list the files from. | |||||
| * @param filter the file filter to apply | |||||
| * @param recurse tells whether or not the listing is recursive. | |||||
| * @return the list of <tt>File</tt> objects that applies to the given | |||||
| * filter. | |||||
| */ | |||||
| public static Vector listFiles(File directory, FilenameFilter filter, boolean recurse) { | |||||
| if (!directory.isDirectory()) { | |||||
| throw new IllegalArgumentException(directory + " is not a directory"); | |||||
| } | |||||
| Vector list = new Vector(512); | |||||
| listFilesTo(list, directory, filter, recurse); | |||||
| return list; | |||||
| } | |||||
| /** | |||||
| * List and add files to a given list. As a convenience it sends back the | |||||
| * instance of the list given as a parameter. | |||||
| * @param list the list of files where the filtered files should be added | |||||
| * @param directory the directory where to list the files from. | |||||
| * @param filter the file filter to apply | |||||
| * @param recurse tells whether or not the listing is recursive. | |||||
| * @return the list instance that was passed as the <tt>list</tt> argument. | |||||
| */ | |||||
| private static Vector listFilesTo(Vector list, File directory, | |||||
| FilenameFilter filter, boolean recurse) { | |||||
| String[] files = directory.list(filter); | |||||
| for (int i = 0; i < files.length; i++) { | |||||
| list.addElement(new File(directory, files[i])); | |||||
| } | |||||
| files = null; // we don't need it anymore | |||||
| if (recurse) { | |||||
| String[] subdirs = directory.list(DIRECTORY_FILTER); | |||||
| for (int i = 0; i < subdirs.length; i++) { | |||||
| listFilesTo(list, new File(directory, subdirs[i]), filter, recurse); | |||||
| } | |||||
| } | |||||
| return list; | |||||
| } | |||||
| } | |||||
| /** Convenient filter that accepts only directory <tt>File</tt> */ | |||||
| final class DirectoryFilter implements FilenameFilter { | |||||
| public boolean accept(File directory, String name) { | |||||
| File pathname = new File(directory, name); | |||||
| return pathname.isDirectory(); | |||||
| } | |||||
| } | |||||
| /** convenient filter to accept only .class files */ | |||||
| final class ClassFilter implements FilenameFilter { | |||||
| public boolean accept(File dir, String name) { | |||||
| return name.endsWith(".class"); | |||||
| } | |||||
| } | |||||
| @@ -1,197 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka.bytecode; | |||||
| import java.io.DataInputStream; | |||||
| import java.io.IOException; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.attributes.AttributeInfo; | |||||
| /** | |||||
| * Method info structure. | |||||
| * @todo give a more appropriate name to methods. | |||||
| * | |||||
| */ | |||||
| public final class MethodInfo { | |||||
| private int accessFlags; | |||||
| private int loc = -1; | |||||
| private String name; | |||||
| private String descriptor; | |||||
| /** Constructor for MethodInfo. */ | |||||
| public MethodInfo() { | |||||
| } | |||||
| /** | |||||
| * Read the method info from a data input stream. | |||||
| * @param constantPool a constant pool | |||||
| * @param dis the data input stream | |||||
| * @throws IOException on error | |||||
| */ | |||||
| public void read(ConstantPool constantPool, DataInputStream dis) throws IOException { | |||||
| accessFlags = dis.readShort(); | |||||
| int name_index = dis.readShort(); | |||||
| name = Utils.getUTF8Value(constantPool, name_index); | |||||
| int descriptor_index = dis.readShort(); | |||||
| descriptor = Utils.getUTF8Value(constantPool, descriptor_index); | |||||
| int attributes_count = dis.readUnsignedShort(); | |||||
| for (int i = 0; i < attributes_count; i++) { | |||||
| int attr_id = dis.readShort(); | |||||
| String attr_name = Utils.getUTF8Value(constantPool, attr_id); | |||||
| int len = dis.readInt(); | |||||
| if (AttributeInfo.CODE.equals(attr_name)) { | |||||
| readCode(constantPool, dis); | |||||
| } else { | |||||
| dis.skipBytes(len); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Read a code from a data input stream. | |||||
| * @param constantPool a constant pool | |||||
| * @param dis the data input stream | |||||
| * @throws IOException on error | |||||
| */ | |||||
| protected void readCode(ConstantPool constantPool, DataInputStream dis) throws IOException { | |||||
| // skip max_stack (short), max_local (short) | |||||
| dis.skipBytes(2 * 2); | |||||
| // skip bytecode... | |||||
| int bytecode_len = dis.readInt(); | |||||
| dis.skip(bytecode_len); | |||||
| // skip exceptions... 1 exception = 4 short. | |||||
| int exception_count = dis.readShort(); | |||||
| dis.skipBytes(exception_count * 4 * 2); | |||||
| // read attributes... | |||||
| int attributes_count = dis.readUnsignedShort(); | |||||
| for (int i = 0; i < attributes_count; i++) { | |||||
| int attr_id = dis.readShort(); | |||||
| String attr_name = Utils.getUTF8Value(constantPool, attr_id); | |||||
| int len = dis.readInt(); | |||||
| if (AttributeInfo.LINE_NUMBER_TABLE.equals(attr_name)) { | |||||
| // we're only interested in lines of code... | |||||
| loc = dis.readShort(); | |||||
| // skip the table which is 2*loc*short | |||||
| dis.skip(loc * 2 * 2); | |||||
| } else { | |||||
| dis.skipBytes(len); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the access flags. | |||||
| * @return the access flags | |||||
| */ | |||||
| public int getAccessFlags() { | |||||
| return accessFlags; | |||||
| } | |||||
| /** | |||||
| * Get the name. | |||||
| * @return the name | |||||
| */ | |||||
| public String getName() { | |||||
| return name; | |||||
| } | |||||
| /** | |||||
| * Get the descriptor. | |||||
| * @return the descriptor | |||||
| */ | |||||
| public String getDescriptor() { | |||||
| return descriptor; | |||||
| } | |||||
| /** | |||||
| * Get the full signature of the method. | |||||
| * This is the return type, the name and the parameters. | |||||
| * @return the full signature | |||||
| */ | |||||
| public String getFullSignature() { | |||||
| return getReturnType() + " " + getShortSignature(); | |||||
| } | |||||
| /** | |||||
| * Get the short signature of the method. | |||||
| * This is just the name and the parameters. | |||||
| * @return the short signature | |||||
| */ | |||||
| public String getShortSignature() { | |||||
| StringBuffer buf = new StringBuffer(getName()); | |||||
| buf.append("("); | |||||
| String[] params = getParametersType(); | |||||
| for (int i = 0; i < params.length; i++) { | |||||
| buf.append(params[i]); | |||||
| if (i != params.length - 1) { | |||||
| buf.append(", "); | |||||
| } | |||||
| } | |||||
| buf.append(")"); | |||||
| return buf.toString(); | |||||
| } | |||||
| /** | |||||
| * Get the return type. | |||||
| * @return the return type | |||||
| */ | |||||
| public String getReturnType() { | |||||
| return Utils.getMethodReturnType(getDescriptor()); | |||||
| } | |||||
| /** | |||||
| * Get the paramaters types. | |||||
| * @return an array of types | |||||
| */ | |||||
| public String[] getParametersType() { | |||||
| return Utils.getMethodParams(getDescriptor()); | |||||
| } | |||||
| /** | |||||
| * Get the number of lines in the method. | |||||
| * @return the number of lines | |||||
| */ | |||||
| public int getNumberOfLines() { | |||||
| return loc; | |||||
| } | |||||
| /** | |||||
| * Get the access flags as a string. | |||||
| * @return the access flags. | |||||
| */ | |||||
| public String getAccess() { | |||||
| return Utils.getMethodAccess(accessFlags); | |||||
| } | |||||
| /** | |||||
| * Return a string represention of this object. | |||||
| * @return the access, and the full signature | |||||
| */ | |||||
| public String toString() { | |||||
| StringBuffer sb = new StringBuffer(); | |||||
| sb.append("Method: ").append(getAccess()).append(" "); | |||||
| sb.append(getFullSignature()); | |||||
| return sb.toString(); | |||||
| } | |||||
| } | |||||
| @@ -1,394 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka.bytecode; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool; | |||||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.Utf8CPInfo; | |||||
| /** | |||||
| * Utilities mostly to manipulate methods and access flags. | |||||
| * | |||||
| */ | |||||
| public final class Utils { | |||||
| /** public access flag */ | |||||
| public static final short ACC_PUBLIC = 1; | |||||
| /** private access flag */ | |||||
| public static final short ACC_PRIVATE = 2; | |||||
| /** protected access flag */ | |||||
| public static final short ACC_PROTECTED = 4; | |||||
| /** static access flag */ | |||||
| public static final short ACC_STATIC = 8; | |||||
| /** final access flag */ | |||||
| public static final short ACC_FINAL = 16; | |||||
| /** super access flag */ | |||||
| public static final short ACC_SUPER = 32; | |||||
| /** synchronized access flag */ | |||||
| public static final short ACC_SYNCHRONIZED = 32; | |||||
| /** volatile access flag */ | |||||
| public static final short ACC_VOLATILE = 64; | |||||
| /** transient access flag */ | |||||
| public static final short ACC_TRANSIENT = 128; | |||||
| /** native access flag */ | |||||
| public static final short ACC_NATIVE = 256; | |||||
| /** interface access flag */ | |||||
| public static final short ACC_INTERFACE = 512; | |||||
| /** abstract access flag */ | |||||
| public static final short ACC_ABSTRACT = 1024; | |||||
| /** strict access flag */ | |||||
| public static final short ACC_STRICT = 2048; | |||||
| /** private constructor */ | |||||
| private Utils() { | |||||
| } | |||||
| /** | |||||
| * return an UTF8 value from the pool located a a specific index. | |||||
| * @param pool the constant pool to look at | |||||
| * @param index index of the UTF8 value in the constant pool | |||||
| * @return the value of the string if it exists | |||||
| * @throws ClassCastException if the index is not an UTF8 constant. | |||||
| */ | |||||
| public static String getUTF8Value(ConstantPool pool, int index) { | |||||
| return ((Utf8CPInfo) pool.getEntry(index)).getValue(); | |||||
| } | |||||
| /** | |||||
| * parse all parameters from a descritor into fields of java name. | |||||
| * @param descriptor of a method. | |||||
| * @return the parameter list of a given method descriptor. Each string | |||||
| * represent a java object with its fully qualified classname or the | |||||
| * primitive name such as int, long, ... | |||||
| */ | |||||
| public static String[] getMethodParams(String descriptor) { | |||||
| int i = 0; | |||||
| if (descriptor.charAt(i) != '(') { | |||||
| throw new IllegalArgumentException("Method descriptor should start with a '('"); | |||||
| } | |||||
| Vector params = new Vector(); | |||||
| StringBuffer param = new StringBuffer(); | |||||
| i++; | |||||
| while ((i = descriptor2java(descriptor, i, param)) < descriptor.length()) { | |||||
| params.add(param.substring(0)); | |||||
| param = new StringBuffer(); | |||||
| if (descriptor.charAt(i) == ')') { | |||||
| i++; | |||||
| break; | |||||
| } | |||||
| } | |||||
| String[] array = new String[params.size()]; | |||||
| params.copyInto(array); | |||||
| return array; | |||||
| } | |||||
| /** | |||||
| * return the object type of a return type. | |||||
| * @param descriptor the description symbol | |||||
| * @return get the return type objet of a given descriptor | |||||
| */ | |||||
| public static String getMethodReturnType(String descriptor) { | |||||
| int pos = descriptor.indexOf(')'); | |||||
| StringBuffer rettype = new StringBuffer(); | |||||
| descriptor2java(descriptor, pos + 1, rettype); | |||||
| return rettype.toString(); | |||||
| } | |||||
| /** | |||||
| * Parse a single descriptor symbol and returns it java equivalent. | |||||
| * @param descriptor the descriptor symbol. | |||||
| * @param i the index to look at the symbol in the descriptor string | |||||
| * @param sb the stringbuffer to return the java equivalent of the symbol | |||||
| * @return the index after the descriptor symbol | |||||
| */ | |||||
| public static int descriptor2java(String descriptor, int i, StringBuffer sb) { | |||||
| // get the dimension | |||||
| StringBuffer dim = new StringBuffer(); | |||||
| for (; descriptor.charAt(i) == '['; i++) { | |||||
| dim.append("[]"); | |||||
| } | |||||
| // now get the type | |||||
| switch (descriptor.charAt(i)) { | |||||
| case 'B': | |||||
| sb.append("byte"); | |||||
| break; | |||||
| case 'C': | |||||
| sb.append("char"); | |||||
| break; | |||||
| case 'D': | |||||
| sb.append("double"); | |||||
| break; | |||||
| case 'F': | |||||
| sb.append("float"); | |||||
| break; | |||||
| case 'I': | |||||
| sb.append("int"); | |||||
| break; | |||||
| case 'J': | |||||
| sb.append("long"); | |||||
| break; | |||||
| case 'S': | |||||
| sb.append("short"); | |||||
| break; | |||||
| case 'Z': | |||||
| sb.append("boolean"); | |||||
| break; | |||||
| case 'V': | |||||
| sb.append("void"); | |||||
| break; | |||||
| case 'L': | |||||
| // it is a class | |||||
| int pos = descriptor.indexOf(';', i + 1); | |||||
| String classname = descriptor.substring(i + 1, pos).replace('/', '.'); | |||||
| sb.append(classname); | |||||
| i = pos; | |||||
| break; | |||||
| default: | |||||
| //@todo, yeah this happens because I got things like: | |||||
| // ()Ljava/lang/Object; and it will return and ) will be here | |||||
| // think about it. | |||||
| //ooooops should never happen | |||||
| //throw new IllegalArgumentException("Invalid descriptor | |||||
| // symbol: '" + i + "' in '" + descriptor + "'"); | |||||
| } | |||||
| sb.append(dim.toString()); | |||||
| return ++i; | |||||
| } | |||||
| /** | |||||
| * check for abstract access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is abstact access | |||||
| */ | |||||
| public static boolean isAbstract(int accessFlags) { | |||||
| return (accessFlags & ACC_ABSTRACT) != 0; | |||||
| } | |||||
| /** | |||||
| * check for public access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is public access | |||||
| */ | |||||
| public static boolean isPublic(int accessFlags) { | |||||
| return (accessFlags & ACC_PUBLIC) != 0; | |||||
| } | |||||
| /** | |||||
| * check for a static access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is static access | |||||
| */ | |||||
| public static boolean isStatic(int accessFlags) { | |||||
| return (accessFlags & ACC_STATIC) != 0; | |||||
| } | |||||
| /** | |||||
| * check for native access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is native access | |||||
| */ | |||||
| public static boolean isNative(int accessFlags) { | |||||
| return (accessFlags & ACC_NATIVE) != 0; | |||||
| } | |||||
| /** | |||||
| * check for class access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is class access | |||||
| */ | |||||
| public static boolean isClass(int accessFlags) { | |||||
| return !isInterface(accessFlags); | |||||
| } | |||||
| /** | |||||
| * check for strict access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is strict access | |||||
| */ | |||||
| public static boolean isStrict(int accessFlags) { | |||||
| return (accessFlags & ACC_STRICT) != 0; | |||||
| } | |||||
| /** | |||||
| * check for interface access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is interface access | |||||
| */ | |||||
| public static boolean isInterface(int accessFlags) { | |||||
| return (accessFlags & ACC_INTERFACE) != 0; | |||||
| } | |||||
| /** | |||||
| * check for private access | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is private access | |||||
| */ | |||||
| public static boolean isPrivate(int accessFlags) { | |||||
| return (accessFlags & ACC_PRIVATE) != 0; | |||||
| } | |||||
| /** | |||||
| * check for transient flag | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is transient access | |||||
| */ | |||||
| public static boolean isTransient(int accessFlags) { | |||||
| return (accessFlags & ACC_TRANSIENT) != 0; | |||||
| } | |||||
| /** | |||||
| * check for volatile flag | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is volatile access | |||||
| */ | |||||
| public static boolean isVolatile(int accessFlags) { | |||||
| return (accessFlags & ACC_VOLATILE) != 0; | |||||
| } | |||||
| /** | |||||
| * check for super flag | |||||
| * @param accessFlags access flag | |||||
| * @return true if there the super flag is set | |||||
| */ | |||||
| public static boolean isSuper(int accessFlags) { | |||||
| return (accessFlags & ACC_SUPER) != 0; | |||||
| } | |||||
| /** | |||||
| * check for protected flag | |||||
| * @param accessFlags access flags | |||||
| * @return true if there is protected access | |||||
| */ | |||||
| public static boolean isProtected(int accessFlags) { | |||||
| return (accessFlags & ACC_PROTECTED) != 0; | |||||
| } | |||||
| /** | |||||
| * chck for final flag | |||||
| * @param accessFlags access flags | |||||
| * @return true if there the final flag is set | |||||
| */ | |||||
| public static boolean isFinal(int accessFlags) { | |||||
| return (accessFlags & ACC_FINAL) != 0; | |||||
| } | |||||
| /** | |||||
| * check for synchronized flag | |||||
| * @param accessFlags access flags | |||||
| * @return true if there the synchronized flag is set | |||||
| */ | |||||
| public static boolean isSynchronized(int accessFlags) { | |||||
| return (accessFlags & ACC_SYNCHRONIZED) != 0; | |||||
| } | |||||
| /** | |||||
| * return the method access flag as java modifiers | |||||
| * @param accessFlags access flags | |||||
| * @return the access flags as modifier strings | |||||
| */ | |||||
| public static String getMethodAccess(int accessFlags) { | |||||
| StringBuffer sb = new StringBuffer(); | |||||
| if (isPublic(accessFlags)) { | |||||
| sb.append("public "); | |||||
| } else if (isPrivate(accessFlags)) { | |||||
| sb.append("private "); | |||||
| } else if (isProtected(accessFlags)) { | |||||
| sb.append("protected "); | |||||
| } | |||||
| if (isFinal(accessFlags)) { | |||||
| sb.append("final "); | |||||
| } | |||||
| if (isStatic(accessFlags)) { | |||||
| sb.append("static "); | |||||
| } | |||||
| if (isSynchronized(accessFlags)) { | |||||
| sb.append("synchronized "); | |||||
| } | |||||
| if (isNative(accessFlags)) { | |||||
| sb.append("native "); | |||||
| } | |||||
| if (isAbstract(accessFlags)) { | |||||
| sb.append("abstract "); | |||||
| } | |||||
| return sb.toString().trim(); | |||||
| } | |||||
| /** | |||||
| * return the field access flag as java modifiers | |||||
| * @param accessFlags access flags | |||||
| * @return the access flags as modifier strings | |||||
| */ | |||||
| public static String getFieldAccess(int accessFlags) { | |||||
| StringBuffer sb = new StringBuffer(); | |||||
| if (isPublic(accessFlags)) { | |||||
| sb.append("public "); | |||||
| } else if (isPrivate(accessFlags)) { | |||||
| sb.append("private "); | |||||
| } else if (isProtected(accessFlags)) { | |||||
| sb.append("protected "); | |||||
| } | |||||
| if (isFinal(accessFlags)) { | |||||
| sb.append("final "); | |||||
| } | |||||
| if (isStatic(accessFlags)) { | |||||
| sb.append("static "); | |||||
| } | |||||
| if (isVolatile(accessFlags)) { | |||||
| sb.append("volatile "); | |||||
| } | |||||
| if (isTransient(accessFlags)) { | |||||
| sb.append("transient "); | |||||
| } | |||||
| return sb.toString().trim(); | |||||
| } | |||||
| /** | |||||
| * return the class access flag as java modifiers | |||||
| * @param accessFlags access flags | |||||
| * @return the access flags as modifier strings | |||||
| */ | |||||
| public static String getClassAccess(int accessFlags) { | |||||
| StringBuffer sb = new StringBuffer(); | |||||
| if (isPublic(accessFlags)) { | |||||
| sb.append("public "); | |||||
| } else if (isProtected(accessFlags)) { | |||||
| sb.append("protected "); | |||||
| } else if (isPrivate(accessFlags)) { | |||||
| sb.append("private "); | |||||
| } | |||||
| if (isFinal(accessFlags)) { | |||||
| sb.append("final "); | |||||
| } | |||||
| if (isSuper(accessFlags)) { | |||||
| sb.append("/*super*/ "); | |||||
| } | |||||
| if (isInterface(accessFlags)) { | |||||
| sb.append("interface "); | |||||
| } | |||||
| if (isAbstract(accessFlags)) { | |||||
| sb.append("abstract "); | |||||
| } | |||||
| if (isClass(accessFlags)) { | |||||
| sb.append("class "); | |||||
| } | |||||
| return sb.toString().trim(); | |||||
| } | |||||
| } | |||||
| @@ -1,57 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2002,2004-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.attributes; | |||||
| /** | |||||
| * Attribute info structure that provides base methods | |||||
| * | |||||
| */ | |||||
| public interface AttributeInfo { | |||||
| /** The source file attribute */ | |||||
| String SOURCE_FILE = "SourceFile"; | |||||
| /** The constant value attribute */ | |||||
| String CONSTANT_VALUE = "ConstantValue"; | |||||
| /** The code attribute */ | |||||
| String CODE = "Code"; | |||||
| /** The exceptions attribute */ | |||||
| String EXCEPTIONS = "Exceptions"; | |||||
| /** The line number table attribute */ | |||||
| String LINE_NUMBER_TABLE = "LineNumberTable"; | |||||
| /** The local variable table attribute */ | |||||
| String LOCAL_VARIABLE_TABLE = "LocalVariableTable"; | |||||
| /** The inner classes attribute */ | |||||
| String INNER_CLASSES = "InnerClasses"; | |||||
| /** The source dir attribute */ | |||||
| String SOURCE_DIR = "SourceDir"; | |||||
| /** The synthetic attribute */ | |||||
| String SYNTHETIC = "Synthetic"; | |||||
| /** The deprecated attribute */ | |||||
| String DEPRECATED = "Deprecated"; | |||||
| /** The unknown attribute */ | |||||
| String UNKNOWN = "Unknown"; | |||||
| } | |||||
| @@ -1,69 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2002,2004 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.metamata; | |||||
| import java.io.File; | |||||
| import junit.framework.TestCase; | |||||
| import org.apache.tools.ant.util.StringUtils; | |||||
| /** | |||||
| * Test for the Audit parser. | |||||
| * | |||||
| */ | |||||
| public class MAuditParserTest extends TestCase { | |||||
| private MAuditParser parser; | |||||
| public MAuditParserTest(String s) { | |||||
| super(s); | |||||
| } | |||||
| protected void setUp() { | |||||
| parser = new MAuditParser(); | |||||
| } | |||||
| public void testViolation() { | |||||
| String line = "file:\\WebGain\\QA\\examples\\auditexamples\\Vector.java:55: Array declarators (\"[]\") should be placed with their component types and not after field/method declarations (5.27)."; | |||||
| // the replace is done to simulate a platform dependant separator since | |||||
| // the parser may do some magic with the file separator | |||||
| line = StringUtils.replace(line, "\\", File.separator); | |||||
| MAuditParser.Violation violation = parser.parseLine(line); | |||||
| assertEquals("\\WebGain\\QA\\examples\\auditexamples\\Vector.java", | |||||
| StringUtils.replace(violation.file, File.separator, "\\")); | |||||
| assertEquals("55", violation.line); | |||||
| assertEquals("Array declarators (\"[]\") should be placed with their component types and not after field/method declarations (5.27).", violation.error); | |||||
| } | |||||
| public void testNonViolation(){ | |||||
| String line = "Audit completed with 36 violations."; | |||||
| Object violation = parser.parseLine(line); | |||||
| assertNull(violation); | |||||
| } | |||||
| public void testFilePathInViolation(){ | |||||
| String line = "file:\\WebGain\\QA\\examples\\auditexamples\\Hashtable.java:302: Loop variable defined at file:\\WebGain\\QA\\examples\\auditexamples\\Hashtable.java:300 is being modified (5.16)."; | |||||
| line = StringUtils.replace(line, "\\", File.separator); | |||||
| MAuditParser.Violation violation = parser.parseLine(line); | |||||
| assertEquals("\\WebGain\\QA\\examples\\auditexamples\\Hashtable.java", | |||||
| StringUtils.replace(violation.file, File.separator, "\\")); | |||||
| assertEquals("302", violation.line); | |||||
| assertEquals("Loop variable defined at Hashtable.java:300 is being modified (5.16).", violation.error); | |||||
| } | |||||
| } | |||||
| @@ -1,82 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2004,2006 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import junit.framework.TestCase; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.ClassFile; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.MethodInfo; | |||||
| /** | |||||
| * Nothing special about this testcase... | |||||
| * | |||||
| */ | |||||
| public class ClassFileTest extends TestCase { | |||||
| public ClassFileTest(String s) { | |||||
| super(s); | |||||
| } | |||||
| public void testVector() throws IOException { | |||||
| String classname = ClassTest.class.getName().replace('.', '/') + ".class"; | |||||
| InputStream is = getClass().getClassLoader().getResourceAsStream(classname); | |||||
| assertNotNull("Unable to find resource " + classname + "in caller classloader"); | |||||
| ClassFile clazzfile = new ClassFile(is); | |||||
| assertEquals("ClassTest", clazzfile.getName()); | |||||
| assertEquals("ClassFileTest.java", clazzfile.getSourceFile()); | |||||
| MethodInfo[] methods = clazzfile.getMethods(); | |||||
| assertEquals(3, methods.length); | |||||
| assertHasMethod("void <init>()", 1, methods); | |||||
| assertHasMethod("void testTwoLines()", 2, methods); | |||||
| assertHasMethod("void testOneLine()", 3, methods); | |||||
| } | |||||
| protected void assertHasMethod(String methodsig, int line, MethodInfo[] methods) { | |||||
| boolean found = false; | |||||
| for (int i = 0; i < methods.length; i++) { | |||||
| MethodInfo method = methods[i]; | |||||
| if (methodsig.equals(method.getFullSignature())) { | |||||
| assertTrue(methodsig, method.getNumberOfLines() >= line); | |||||
| return; | |||||
| } | |||||
| } | |||||
| fail("Could not find method " + methodsig); | |||||
| } | |||||
| } | |||||
| class ClassTest { | |||||
| // 2 lines | |||||
| public ClassTest() { | |||||
| } | |||||
| // 2 lines | |||||
| public void testTwoLines() { | |||||
| System.out.println("This is 1 line"); | |||||
| } | |||||
| // 1 line | |||||
| public void testOneLine() { | |||||
| try { | |||||
| throw new Exception(); | |||||
| } catch (Exception e) { | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,44 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001,2003-2004,2006 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.util.Hashtable; | |||||
| import junit.framework.TestCase; | |||||
| import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.ClassPathLoader; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| /** | |||||
| * Minimal testing for the classpath loader.. | |||||
| * | |||||
| */ | |||||
| public class ClassPathLoaderTest extends TestCase { | |||||
| public ClassPathLoaderTest(String s) { | |||||
| super(s); | |||||
| } | |||||
| public void testgetClasses() throws Exception { | |||||
| // good performance test...load all classes in rt.jar | |||||
| Path p = new Path(null); | |||||
| p.addJavaRuntime(); | |||||
| ClassPathLoader cl = new ClassPathLoader(p.toString()); | |||||
| Hashtable map = cl.getClasses(); | |||||
| assertTrue(map.size() > 0); | |||||
| } | |||||
| } | |||||
| @@ -1,103 +0,0 @@ | |||||
| /* | |||||
| * Copyright 2001-2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.optional.sitraka; | |||||
| import java.io.File; | |||||
| import java.io.FileNotFoundException; | |||||
| import java.io.OutputStream; | |||||
| import java.net.URL; | |||||
| import javax.xml.transform.OutputKeys; | |||||
| import javax.xml.transform.Transformer; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.dom.DOMSource; | |||||
| import javax.xml.transform.stream.StreamResult; | |||||
| import junit.framework.TestCase; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.w3c.dom.Document; | |||||
| import org.w3c.dom.Node; | |||||
| import org.w3c.dom.NodeList; | |||||
| /** | |||||
| * Ensure that reference classpath feature is working fine... | |||||
| */ | |||||
| public class XMLReportTest extends TestCase { | |||||
| /** helper for some File/URL connversions */ | |||||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||||
| public XMLReportTest(String s) { | |||||
| super(s); | |||||
| } | |||||
| protected File getFile(String name) throws FileNotFoundException { | |||||
| URL url = getClass().getResource(name); | |||||
| if (url == null) { | |||||
| throw new FileNotFoundException("Unable to load '" + name + "' from classpath"); | |||||
| } | |||||
| return new File(FILE_UTILS.fromURI(url.toString())); | |||||
| } | |||||
| public void testCreateDocument() throws Exception { | |||||
| // this is a sample from running Ant include data for java.* only | |||||
| File reportFile = getFile("/taskdefs/optional/sitraka/covreport-test.xml"); | |||||
| XMLReport report = new XMLReport(reportFile); | |||||
| ReportFilters filters = new ReportFilters(); | |||||
| ReportFilters.Include incl = new ReportFilters.Include(); | |||||
| incl.setClass("java.util.Vector"); | |||||
| incl.setMethod("set*"); | |||||
| filters.addInclude(incl); | |||||
| report.setReportFilters(filters); | |||||
| Path p = new Path(null); | |||||
| p.addJavaRuntime(); | |||||
| Document doc = report.createDocument(p.list()); | |||||
| Node snapshot = doc.getDocumentElement(); | |||||
| assertEquals("snapshot", snapshot.getNodeName()); | |||||
| // there is only java.util | |||||
| NodeList packages = doc.getElementsByTagName("package"); | |||||
| assertEquals(1, packages.getLength()); | |||||
| assertEquals("java.util", packages.item(0).getAttributes().getNamedItem("name").getNodeValue()); | |||||
| // there is only Vector | |||||
| NodeList classes = doc.getElementsByTagName("class"); | |||||
| assertEquals(1, classes.getLength()); | |||||
| assertEquals("Vector", classes.item(0).getAttributes().getNamedItem("name").getNodeValue()); | |||||
| // there are 3 set* methods | |||||
| // set(int, Object) | |||||
| // setSize(int) | |||||
| // setElementAt(Object, int) | |||||
| NodeList methods = doc.getElementsByTagName("method"); | |||||
| assertEquals(3, methods.getLength()); | |||||
| //dump(doc, System.out); | |||||
| } | |||||
| /** | |||||
| * might be useful to spit out the document | |||||
| * it's a nightmare to navigate in a DOM structure in a debugger. | |||||
| */ | |||||
| protected void dump(Document doc, OutputStream out) throws Exception { | |||||
| TransformerFactory tfactory = TransformerFactory.newInstance(); | |||||
| Transformer transformer = tfactory.newTransformer(); | |||||
| transformer.setOutputProperty(OutputKeys.INDENT, "no"); | |||||
| transformer.setOutputProperty(OutputKeys.METHOD, "xml"); | |||||
| transformer.transform(new DOMSource(doc), new StreamResult(out)); | |||||
| } | |||||
| } | |||||