Browse Source

removal of the jprobe and metamata tasks.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@405267 13f79535-47bb-0310-9956-ffa450edef68
master
Antoine Levy-Lambert 19 years ago
parent
commit
72b360356e
36 changed files with 5 additions and 16793 deletions
  1. +5
    -1
      WHATSNEW
  2. +0
    -10
      build.xml
  3. +0
    -545
      docs/manual/OptionalTasks/jpcoverage.html
  4. +0
    -138
      docs/manual/OptionalTasks/maudit.html
  5. +0
    -123
      docs/manual/OptionalTasks/mmetrics.html
  6. +0
    -120
      docs/manual/OptionalTasks/mparse.html
  7. +0
    -4
      docs/manual/optionaltasklist.html
  8. +0
    -29
      docs/manual/tasksoverview.html
  9. +0
    -9949
      src/etc/testcases/taskdefs/optional/sitraka/covreport-test.xml
  10. +0
    -6
      src/main/org/apache/tools/ant/taskdefs/defaults.properties
  11. +0
    -350
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/AbstractMetamataTask.java
  12. +0
    -320
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAudit.java
  13. +0
    -86
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAuditParser.java
  14. +0
    -226
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAuditStreamHandler.java
  15. +0
    -265
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MMetrics.java
  16. +0
    -409
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MMetricsStreamHandler.java
  17. +0
    -275
      src/main/org/apache/tools/ant/taskdefs/optional/metamata/MParse.java
  18. +0
    -127
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovBase.java
  19. +0
    -204
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovMerge.java
  20. +0
    -410
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java
  21. +0
    -522
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Coverage.java
  22. +0
    -172
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Filters.java
  23. +0
    -164
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/ReportFilters.java
  24. +0
    -60
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Socket.java
  25. +0
    -46
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/StringUtil.java
  26. +0
    -153
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Triggers.java
  27. +0
    -615
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java
  28. +0
    -169
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/ClassFile.java
  29. +0
    -349
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/ClassPathLoader.java
  30. +0
    -197
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/MethodInfo.java
  31. +0
    -394
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/Utils.java
  32. +0
    -57
      src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/attributes/AttributeInfo.java
  33. +0
    -69
      src/testcases/org/apache/tools/ant/taskdefs/optional/metamata/MAuditParserTest.java
  34. +0
    -82
      src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/ClassFileTest.java
  35. +0
    -44
      src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/ClassPathLoaderTest.java
  36. +0
    -103
      src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReportTest.java

+ 5
- 1
WHATSNEW View File

@@ -81,7 +81,11 @@ Changes that could break older environments:

* 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:
-----------


+ 0
- 10
build.xml View File

@@ -195,8 +195,6 @@
<or>
<filename name="${optional.package}/junit/Xalan2Executor*"/>
<filename name="${optional.package}/TraXLiaison*"/>
<filename name="${optional.package}/sitraka/**"/>
<filename name="${optional.package}/metamata/MMetrics*"/>
<filename name="${optional.package}/XsltTest*"/>
<filename name="${type.package}/XMLCatalogBuildFileTest*"/>
</or>
@@ -225,7 +223,6 @@
<or>
<filename name="${regexp.package}/JakartaOro*"/>
<filename name="${optional.package}/perforce/*"/>
<filename name="${optional.package}/metamata/MAudit*"/>
</or>
</selector>

@@ -1654,8 +1651,6 @@
time dependencies -->
<exclude name="${optional.package}/ReplaceRegExpTest.java"
unless="some.regexp.support"/>
<exclude name="${optional.package}/sitraka/*.java"
unless="some.regexp.support"/>
<exclude name="${ant.package}/types/selectors/ContainsRegexpTest.java"
unless="some.regexp.support"/>
<exclude name="${ant.package}/types/mappers/RegexpPatternMapperTest.java"
@@ -1684,9 +1679,6 @@
if="tests.are.on.system.classpath"/>
<exclude name="${optional.package}/junit/JUnitClassLoaderTest.java"
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???? -->
<exclude name="${optional.package}/PvcsTest.java"/>

@@ -1743,8 +1735,6 @@
unless="tests.and.ant.share.classloader"/>
<exclude name="${optional.package}/TraXLiaisonTest.java"
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"
unless="tests.and.ant.share.classloader"/>
<exclude name="${taskdefs.package}/ProtectedJarMethodsTest.java"


+ 0
- 545
docs/manual/OptionalTasks/jpcoverage.html View File

@@ -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 &quot;snapshot&quot;</td>
</tr>

<tr>
<td valign="top">exitprompt</td>
<td valign="top">Toggles display of the console prompt: &quot;Press Enter to close
this window.&quot; &quot;always&quot;: Always displays the prompt. &quot;never&quot;: Never displays the
prompt. &quot;error&quot;: 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 &quot;none&quot;,&quot;coverage&quot;,&quot;all&quot;</td>
<td align="center" valign="top">No, default to &quot;coverage&quot;</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 &quot;false&quot;.</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>&lt;classpath&gt;</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>&lt;jvmarg&gt;</code>
attributes, for example:</p>

<pre></pre>
<blockquote>
<pre>&lt;jpcoverage home=&quot;c:\jprobe&quot; classname=&quot;MyClass&quot;&gt;
&lt;jvmarg value=&quot;-classic&quot;/&gt;
&lt;classpath path=&quot;.&quot;/&gt;
&lt;/jpcoverage&gt;
</pre>
</blockquote>
would run the coverage on &quot;MyClass&quot; in classic mode VM.

<p><code>&lt;jvmarg&gt;</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>&lt;arg&gt;</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>
&lt;filters&gt;
&lt;exclude class=&quot;*&quot; method=&quot;*&quot;/&gt;
&lt;/filters&gt;
</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>
&lt;filters&gt;
&lt;include class=&quot;com.mycompany.*&quot; method=&quot;*&quot;/&gt;
&lt;exclude class=&quot;com.mycompany.MyClass&quot; method=&quot;test*&quot;/&gt;
&lt;/filters&gt;</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
&quot;enter&quot; or &quot;exit&quot;.</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 &quot;clear&quot;,
&quot;pause&quot;, &quot;resume&quot;, &quot;snapshot&quot;, &quot;suspend&quot;,
or &quot;exit&quot;. 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>&lt;triggers&gt;
&lt;method name=&quot;ClassName.*()&quot; event=&quot;enter&quot; action=&quot;snapshot&quot;/&gt;
&lt;method name=&quot;ClassName.MethodName()&quot; event=&quot;exit&quot; action=&quot;exit&quot;/&gt;
&lt;/triggers&gt;
</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>&lt;FileSet&gt;</code></a>
element.
</p>

<h3>Example of merge</h3>
<blockquote>
<pre>&lt;jpcovmerge home=&quot;c:\jprobe&quot; tofile=&quot;merge.jpc&quot; verbose=&quot;true&quot;&gt;
&lt;fileset dir=&quot;./snapshots&quot;&gt;
&lt;include name=&quot;snap*.jpc&quot;/&gt;
&lt;/fileset&gt;
&lt;/jpcovmerge&gt;
</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 &quot;xml&quot;, &quot;html&quot; or &quot;text&quot;</td>
<td align="center" valign="top">No, default to &quot;html&quot;</td>
</tr>
<tr>
<td valign="top">type</td>
<td valign="top">The type of report to be generated. Must be &quot;executive&quot;,
&quot;summary&quot;, &quot;detailed&quot; or &quot;verydetailed&quot;</td>
<td align="center" valign="top">No. Default to &quot;detailed&quot;</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=&quot;xml&quot; and type=&quot;verydetailed&quot;</td>
<td align="center" valign="top">No. Defaults to &quot;yes&quot;</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=&quot;xml&quot;)</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&nbsp; <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>
&lt;jpcovreport home="c:\jprobe" snapshot="merge.jpc" format="xml" tofile="result.xml"&gt;
&lt;sourcepath path="./src"/&gt;
&lt;reference&gt;
&lt;classpath path="./bin/classes"/&gt;
&lt;filters&gt;
&lt;include class="com.mycompany.*"/&gt;
&lt;exclude class="com.mycompany.MyClass" method="test*"/&gt;
&lt;/filters&gt;
&lt;/reference&gt;
&lt;/jpcovreport&gt;
</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>&lt;reference&gt;
&nbsp;&nbsp;&nbsp; &lt;classpath path="./bin/classes"/&gt;
&lt;/reference&gt;</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>&lt;style processor="xalan" in="./reports/xml/results.xml" out="./reports/html/dummy.file"
style="${ant.home}/etc/coverage-frames.xsl"&gt;
&lt;param name="output.dir" expression="'${basedir}/reports/html'"/&gt;
&lt;/style&gt;</pre>
<p>Xalan 2.x (note the parameter without single quote)</p>
<pre>&lt;style processor="trax" in="./reports/xml/results.xml" out="./reports/html/dummy.file"
style="${ant.home}/etc/coverage-frames.xsl"&gt;
&nbsp; &lt;param name="output.dir" expression="${basedir}/reports/html"/&gt;
&lt;/style&gt;</pre>

<hr>
<p align="center">Copyright &copy; 2001-2002,2004-2005 The Apache Software Foundation. All rights
Reserved.</p>
</body>
</html>

+ 0
- 138
docs/manual/OptionalTasks/maudit.html View File

@@ -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>&lt;jvmarg&gt;</code>
attributes. <code>&lt;jvmarg&gt;</code> allows all attributes described in
<a href="../using.html#arg">Command line arguments</a>.</p>
<p>
You can avoid using the <code>&lt;jvmarg&gt;</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> &lt;maudit tofile=&quot;c:/metamata/examples/auditexamples/audit.xml&quot;
metamatahome=&quot;c:/metamata&quot; fix=&quot;yes&quot;&gt;
&lt;classpath&gt;
&lt;pathelement location=&quot;c:/metamata/examples/auditexamples&quot;/&gt;
&lt;/classpath&gt;
&lt;sourcepath&gt;
&lt;pathelement location=&quot;c:/metamata/examples/auditexamples&quot;/&gt;
&lt;/sourcepath&gt;
&lt;fileset dir=&quot;c:/metamata/examples/auditexamples&quot;&gt;
&lt;include name=&quot;*.java&quot;/&gt;
&lt;/fileset&gt;
&lt;/maudit&gt;</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>
&lt;style in=java &quot;${audit.xml}&quot; style=&quot;maudit-frames.xsl&quot; out="null.tmp"&gt;
&lt;param name=&quot;output.dir&quot; expression=&quot;${report.dir}&quot;/&gt;
&lt;/style&gt;
</pre>

<hr>
<p align="center">Copyright &copy; 2001-2002,2004-2005 The Apache Software Foundation. All rights
Reserved.</p>
</body>
</html>

+ 0
- 123
docs/manual/OptionalTasks/mmetrics.html View File

@@ -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>&lt;jvmarg&gt;</code>
attributes. <code>&lt;jvmarg&gt;</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> &lt;mmetrics tofile=&quot;mmetrics.xml&quot;
metamatahome=&quot;c:/metamata&quot;
granularity=&quot;methods&quot;&gt;
&lt;classpath&gt;
&lt;pathelement location=&quot;c:/metamata/examples/metricsexamples&quot;/&gt;
&lt;/classpath&gt;
&lt;sourcepath&gt;
&lt;pathelement location=&quot;c:/metamata/examples/metricsexamples&quot;/&gt;
&lt;/sourcepath&gt;
&lt;path&gt;
&lt;pathelement location=&quot;c:/metamata/examples/metricsexamples&quot;/&gt;
&lt;/path&gt;
&lt;/mmetrics&gt;</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>
&lt;style in=java &quot;${metrics.xml}&quot; style=&quot;mmetrics-frames.xsl&quot; out="null.tmp"&gt;
&lt;param name=&quot;output.dir&quot; expression=&quot;${report.dir}&quot;/&gt;
&lt;/style&gt;
</pre>
<hr>
<p align="center">Copyright &copy; 2001-2002,2004-2005 The Apache Software Foundation. All rights
Reserved.</p>
</body>
</html>

+ 0
- 120
docs/manual/OptionalTasks/mparse.html View File

@@ -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>&lt;jvmarg&gt;</code>
attributes. <code>&lt;jvmarg&gt;</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. &nbsp;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.&nbsp;The <tt>sourcepath</tt> element represents a <a href="../using.html#path">PATH like
structure</a>.</p>
<h3>Example</h3>
<pre> &lt;mparse target=&quot;c:/metamata/examples/parseexamples/javagrammars/singlefile/JavaParser.jj&quot;
metamatahome=&quot;c:/metamata&quot; cleanup=&quot;true&quot;&gt;
&lt;classpath&gt;
&lt;pathelement location=&quot;c:/metamata/examples/&quot;/&gt;
&lt;/classpath&gt;
&lt;/mparse&gt;</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 &copy; 2001,2004-2005 The Apache Software Foundation. All rights
Reserved.</p>
</body>
</html>

+ 0
- 4
docs/manual/optionaltasklist.html View File

@@ -40,13 +40,9 @@
<a href="OptionalTasks/jjdoc.html">JJDoc</a><br>
<a href="OptionalTasks/jjtree.html">JJTree</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/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/mparse.html">MParse</a><br>
<a href="OptionalTasks/native2ascii.html">Native2Ascii</a><br>
<a href="OptionalTasks/netrexxc.html">NetRexxC</a><br>
<a href="OptionalTasks/perforce.html">Perforce Tasks</a><br>


+ 0
- 29
docs/manual/tasksoverview.html View File

@@ -184,29 +184,6 @@ documentation.</p>
package&quot;.</p></td>
</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>

<p></p>
@@ -911,12 +888,6 @@ documentation.</p>
<td><p>Define a new task as a macro built-up upon other tasks.</p></td>
</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">
<td nowrap><a href="OptionalTasks/native2ascii.html">
Native2Ascii</a></td>


+ 0
- 9949
src/etc/testcases/taskdefs/optional/sitraka/covreport-test.xml
File diff suppressed because it is too large
View File


+ 0
- 6
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -132,17 +132,11 @@ javah=org.apache.tools.ant.taskdefs.optional.Javah
jdepend=org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask
jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc
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
jspc=org.apache.tools.ant.taskdefs.optional.jsp.JspC
junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator
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
netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC
p4add=org.apache.tools.ant.taskdefs.optional.perforce.P4Add


+ 0
- 350
src/main/org/apache/tools/ant/taskdefs/optional/metamata/AbstractMetamataTask.java View File

@@ -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>&lt;jvmarg&gt;</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;
}

}

+ 0
- 320
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAudit.java View File

@@ -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...
}*/
}

}


+ 0
- 86
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAuditParser.java View File

@@ -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;
}
}

+ 0
- 226
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAuditStreamHandler.java View File

@@ -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);
}

}

+ 0
- 265
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MMetrics.java View File

@@ -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;
}

}

+ 0
- 409
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MMetricsStreamHandler.java View File

@@ -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);
}
}


+ 0
- 275
src/main/org/apache/tools/ant/taskdefs/optional/metamata/MParse.java View File

@@ -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
}
}
}
}
}

+ 0
- 127
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovBase.java View File

@@ -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;
}
}

+ 0
- 204
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovMerge.java View File

@@ -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;
}

}

+ 0
- 410
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java View 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);
}
}
}
}

+ 0
- 522
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Coverage.java View File

@@ -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=&lt;filename&gt;)
* 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
}
}
}

}

+ 0
- 172
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Filters.java View File

@@ -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 ? "" : "#");
}
}
}




+ 0
- 164
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/ReportFilters.java View File

@@ -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 &lt;classname&gt;&lt;method&gt;() is accepted by the list
* of filters or not.
* @param methodname the full method name in the format &lt;classname&gt;&lt;method&gt;()
* @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 {
}
}


+ 0
- 60
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Socket.java View File

@@ -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>&lt;socket/&gt;</tt> defaults to host 127.0.0.1 and port 4444
*
* Otherwise it requires the host and port attributes to be set:
* <tt>
* &lt;socket host=&quote;175.30.12.1&quote; port=&quote;4567&quote;/&gt;
* </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 ':&lt;port&gt;', will take localhost
* @return "host:port"
*/
public String toString() {
return host + ":" + port;
}
}

+ 0
- 46
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/StringUtil.java View File

@@ -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;
}
}
}

+ 0
- 153
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/Triggers.java View File

@@ -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
* &quot;enter&quot; or &quot;exit&quot;
* 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 &quot;clear&quot;,
* &quot;pause&quot;, &quot;resume&quot;, &quot;snapshot&quot;, &quot;suspend&quot;,
* or &quot;exit&quot;. 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");
}

}

+ 0
- 615
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java View File

@@ -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 - &lt;classname&gt;&#046;&lt;method&gt;().
* @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);
}
}

}


+ 0
- 169
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/ClassFile.java View File

@@ -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);
}

}

+ 0
- 349
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/ClassPathLoader.java View File

@@ -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");
}
}

+ 0
- 197
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/MethodInfo.java View File

@@ -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();
}
}

+ 0
- 394
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/Utils.java View File

@@ -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();
}
}




+ 0
- 57
src/main/org/apache/tools/ant/taskdefs/optional/sitraka/bytecode/attributes/AttributeInfo.java View File

@@ -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";
}

+ 0
- 69
src/testcases/org/apache/tools/ant/taskdefs/optional/metamata/MAuditParserTest.java View File

@@ -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);
}

}

+ 0
- 82
src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/ClassFileTest.java View File

@@ -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) {
}
}
}

+ 0
- 44
src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/ClassPathLoaderTest.java View File

@@ -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);
}

}

+ 0
- 103
src/testcases/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReportTest.java View File

@@ -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));
}
}

Loading…
Cancel
Save