Add design notes git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270844 13f79535-47bb-0310-9956-ffa450edef68master
@@ -0,0 +1,49 @@ | |||||
<project name="build-site" default="docs" basedir="."> | |||||
<!-- Initialization properties --> | |||||
<property name="project.name" value="mutant"/> | |||||
<property name="docs.src" location="xdocs"/> | |||||
<property name="docs.dest" location="docs"/> | |||||
<property name="project.file" value="stylesheets/project.xml" /> | |||||
<property name="site.dir" location="../../../jakarta-site2" /> | |||||
<property name="templ.path" location="xdocs/stylesheets" /> | |||||
<property name="velocity.props" location="${docs.src}/velocity.properties" /> | |||||
<path id="anakia.classpath"> | |||||
<fileset dir="${site.dir}/lib"> | |||||
<include name="*.jar"/> | |||||
</fileset> | |||||
</path> | |||||
<target name="prepare"> | |||||
<available classname="org.apache.velocity.anakia.AnakiaTask" | |||||
property="AnakiaTask.present"> | |||||
<classpath refid="anakia.classpath"/> | |||||
</available> | |||||
</target> | |||||
<target depends="prepare" name="prepare-error" unless="AnakiaTask.present"> | |||||
<echo> | |||||
AnakiaTask is not present! Please check to make sure that | |||||
velocity.jar is in your classpath. | |||||
</echo> | |||||
</target> | |||||
<target name="docs" depends="prepare-error" if="AnakiaTask.present"> | |||||
<taskdef name="anakia" classname="org.apache.velocity.anakia.AnakiaTask"> | |||||
<classpath refid="anakia.classpath"/> | |||||
</taskdef> | |||||
<anakia basedir="${docs.src}" destdir="${docs.dest}/" | |||||
extension=".html" style="./site.vsl" | |||||
projectFile="${project.file}" | |||||
excludes="**/stylesheets/** faq.xml" | |||||
includes="**/*.xml" | |||||
lastModifiedCheck="true" | |||||
templatePath="${templ.path}" | |||||
velocityPropertiesFile="${velocity.props}"> | |||||
</anakia> | |||||
</target> | |||||
<target name="all" depends="docs"/> | |||||
</project> |
@@ -0,0 +1,694 @@ | |||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |||||
<!-- Content Stylesheet for Site --> | |||||
<!-- start the processing --> | |||||
<html> | |||||
<head> | |||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> | |||||
<meta name="author" value="Conor MacNeill"> | |||||
<meta name="email" value="conor@apache.org"> | |||||
<title>The Jakarta Site - Mutant Design Notes</title> | |||||
</head> | |||||
<body bgcolor="#ffffff" text="#000000" link="#525D76"> | |||||
<table border="0" width="100%" cellspacing="0"> | |||||
<!-- TOP IMAGE --> | |||||
<tr> | |||||
<td colspan="2"> | |||||
<a href="http://jakarta.apache.org"><img src="http://jakarta.apache.org/images/jakarta-logo.gif" align="left" border="0"/></a> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<table border="0" width="100%" cellspacing="4"> | |||||
<tr><td colspan="2"> | |||||
<hr noshade="" size="1"/> | |||||
</td></tr> | |||||
<tr> | |||||
<!-- LEFT SIDE NAVIGATION --> | |||||
<td valign="top" nowrap="true"> | |||||
<p><strong>Apache Ant</strong></p> | |||||
<ul> | |||||
<li> <a href="./index.html">Front Page</a> | |||||
</li> | |||||
<li> <a href="./antnews.html">News</a> | |||||
</li> | |||||
<li> <a href="./manual/index.html">Documentation</a> | |||||
</li> | |||||
<li> <a href="./external.html">External Tools and Tasks</a> | |||||
</li> | |||||
<li> <a href="./resources.html">Resources</a> | |||||
</li> | |||||
<li> <a href="./faq.html">Ant FAQ</a> | |||||
</li> | |||||
<li> <a href="./problems.html">Having Problems?</a> | |||||
</li> | |||||
</ul> | |||||
<p><strong>Download</strong></p> | |||||
<ul> | |||||
<li> <a href="http://jakarta.apache.org/site/binindex.html">Binaries</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/sourceindex.html">Source Code</a> | |||||
</li> | |||||
</ul> | |||||
<p><strong>Jakarta</strong></p> | |||||
<ul> | |||||
<li> <a href="http://jakarta.apache.org/site/news.html">News & Status</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/mission.html">Mission</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/guidelines.html">Guidelines Notes</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/faqs.html">FAQs</a> | |||||
</li> | |||||
</ul> | |||||
<p><strong>Get Involved</strong></p> | |||||
<ul> | |||||
<li> <a href="http://jakarta.apache.org/site/getinvolved.html">Overview</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/cvsindex.html">CVS Repositories</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/mail.html">Mailing Lists</a> | |||||
</li> | |||||
<li> <a href="http://jakarta.apache.org/site/library.html">Reference Library</a> | |||||
</li> | |||||
<li> <a href="http://nagoya.apache.org/bugzilla/enter_bug.cgi?product=Ant">Bug Database</a> | |||||
</li> | |||||
<li> <a href="http://nagoya.apache.org/bugzilla/enter_bug.cgi?product=Ant&bug_severity=Enhancement">Enhancement Requests</a> | |||||
</li> | |||||
</ul> | |||||
</td> | |||||
<td align="left" valign="top"> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Mutant Design Notes"><strong>Mutant Design Notes</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
This is a brief, albeit rambling description of Mutant. | |||||
Mutant has many experimental ideas which may or may not prove useful. | |||||
I'll try to describe what is there and let anyone who is interested | |||||
comment. Mutant is still immature. You'll notice that there is, at this | |||||
time, just one task, a hacked version of the echo task, which I have | |||||
been using to test out ideas. Most tasks would end up being pretty | |||||
similar to their Ant 1.x version. | |||||
</p> | |||||
<p> | |||||
OK, let me start with some of the motivating requirements. There are of | |||||
coure many Ant2 requirements but I want to focus on these two for now. | |||||
Mutant does also address many of the other Ant2 requirements. | |||||
</p> | |||||
<p> | |||||
I'll use the terms Ant and mutant somewhat interchangeably - just | |||||
habit, not an assumption of any sort. | |||||
</p> | |||||
<p> | |||||
One of the things which is pretty difficult in Ant 1.x is the | |||||
management of classpaths and classloaders. For example, today the | |||||
antlr task requires the antlr classes in the classpath used to start | |||||
ant. I'm talking here about the classpath built up in the ant.bat/ant | |||||
script launchers. At the same time, the checkstyle task | |||||
which uses antlr won't run if the antlr classes are in the classpath | |||||
because then those classes cannot "see" the classes in the taskdef's | |||||
classpath. | |||||
</p> | |||||
<p> | |||||
Another requirement I have is extensibility. In Ant 1.x this is | |||||
difficult because whenever a new type is created, each task which | |||||
needs to support this type must be changed to provide the new addXXX | |||||
method. The ejbjar task is on example of this problem with its concept of vendor | |||||
specific tools. The zip/jar task, with its support for different types | |||||
of fileset, is another. The addition of the classfileset to Ant requires | |||||
a change to the zip task. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Mutant Initialization"><strong>Mutant Initialization</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
Mutant defines a classloader hierarchy somewhat similar to that used | |||||
in Tomcat 4. Tasks join into this hierarchy at a particular point to | |||||
ensure they have visibility of the necessary interface classes and no | |||||
visibility of the Ant core itself. There is nothing particularly novel | |||||
about this approach, but tasks are able to request certain additional resources | |||||
as we will see later. | |||||
</p> | |||||
<p> | |||||
Mutant starts with two jars. One is the start.jar which contains just | |||||
one class, Main.java which establishes the initial configuration and | |||||
then runs the appropriate front end command line class. If a different | |||||
front end was desired, a different launch class, in its own jar, would | |||||
be used. This would perhaps configure the classloader hierarchy somewhat | |||||
differently and start the approriate GUI front end class. | |||||
</p> | |||||
<p> | |||||
The second jar, init.jar, provides a number of initialisation utilities. These | |||||
are used by Main.java to setup Ant and would also be used by any other front end | |||||
to configure Ant. The important class here is the | |||||
InitConfig which communicates the state of Ant at startup into the the core of | |||||
Ant when it starts up. Main determines the location of ANT_HOME based on the | |||||
location of the start classes and then populates the InitConfig with both | |||||
classloaders and information about the location of various jars and config | |||||
files. | |||||
</p> | |||||
<p> | |||||
At the top of the classloader hierarchy | |||||
are the bootstrap and system classloaders. I won't really | |||||
distinguish between these in mutant. Combined they provide the JDK | |||||
classes, plus the classes from the init and start jars. One objective is | |||||
to keep the footprint of the init and start jars small so they do not | |||||
require any external classes, which may then become visible lower in the | |||||
hierarchy. Main does not explicitly create these loaders, of course, but | |||||
just adds a reference to the init config as system class loader | |||||
</p> | |||||
<p> | |||||
The next jar is for the common area. This provides interface definitions | |||||
and utility classes for use by both the core and by tasks/types etc. It | |||||
is loaded from ANT_HOME/lib/common/*.jar. Typically this is just | |||||
lib/common/common.jar but any other jars in here are loaded. This | |||||
pattern is used in the construction of all of the classloaders. | |||||
</p> | |||||
<p> | |||||
Next up is the core loader. It includes the lib/antcore/antcore.jar plus | |||||
any others including the XML parser jars. Mutant's core does not assume that | |||||
the project model will come from an XML description but XML facilities | |||||
are needed in the core for reading in Ant library defs and config files. | |||||
The parser jar locations are also stored in the init config. This lets | |||||
the jars be added to any Ant library that wants to use Ant's XML parser | |||||
rather than providing its own. Similarly tools.jar's location is | |||||
determined automatically and added to the config for use by tasks which | |||||
request it. I'll go into more detail when discussing the antlib processing. | |||||
</p> | |||||
<p> | |||||
The final jar that is loaded is the jar for the frontend - cli.jar. This | |||||
is not passed in init config since these classes are not visible to the | |||||
core and are not needed by it. So the hierarchy is | |||||
<pre> | |||||
jdk classes | |||||
| | |||||
start/init | |||||
| | |||||
common | |||||
| | |||||
antcore | |||||
| | |||||
cli | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Task classloaders generally will come in at common, hiding the core classes, front | |||||
end and XML parser classes from tasks. | |||||
</p> | |||||
<p> | |||||
Once Main has setup the initConfig, it creates the front end commandline | |||||
class and launches mutant proper, passing it the command line args and | |||||
the init config. | |||||
</p> | |||||
<p> | |||||
A GUI would typically replace start.jar and the cli.jar with its own | |||||
versions which manage model construction from GUI processes rather than | |||||
from XML files. It may be possible to move some of Main.java's | |||||
processing into init.jar if it is useful to other front ends. I haven't | |||||
looked at that balance. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Mutant Frontend"><strong>Mutant Frontend</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
The front end is responsible for coordinating execution of Ant. It | |||||
manages command line arguments, builds a model of the Project to be | |||||
evaluated and coordinates the execution services of the core. cli.jar | |||||
contains not only the front-end code but also the XML parsing code for | |||||
building a project model from an XML description. Other front ends may | |||||
choose to build project models in different ways. Commandline is pretty | |||||
similar to Ant 1.x's Main.java - it handles arguments, building loggers, | |||||
listeners, defines, etc - actually I haven't fully implemented | |||||
command line defines in | |||||
mutant yet but it would be similar to Ant 1.x. | |||||
</p> | |||||
<p> | |||||
Commandline then moves to building a project model from the XML | |||||
representation. I have just expanded the approach in Ant 1's | |||||
ProjectHelper for XML parsing, moving away from a stack of inner classes. | |||||
The classes in the front end XML parsing use some XML utility base | |||||
classes from the core. | |||||
</p> | |||||
<p> | |||||
The XML parsing handles two elements at parse time. One is the <ref> | |||||
element which is used for project references - that is relationships | |||||
between project files. The referenced project is parsed as well. The | |||||
second is the <include> element which includes either another complete | |||||
project or a project <fragment> directly into the project. All the other | |||||
elements are used to build a project model which is later processed in | |||||
the core. | |||||
</p> | |||||
<p> | |||||
The project model itself is organized like this | |||||
</p> | |||||
<p> | |||||
<ul> | |||||
<li>A project contains</li> | |||||
<ul> | |||||
<li>named references to other projects</li> | |||||
<li>targets</li> | |||||
<li>build elements (tasks, type instances)</li> | |||||
</ul> | |||||
<li>A target contains</li> | |||||
<ul> | |||||
<li>build elements (tasks, type instances)</li> | |||||
</ul> | |||||
<li>A build element contains</li> | |||||
<ul> | |||||
<li>build elements (nested elements)</li> | |||||
</ul> | |||||
</ul> | |||||
</p> | |||||
<p> | |||||
So, for now the project model contains top level tasks and type | |||||
instances. I'm still thinking about those and property scoping | |||||
especially in the face of project refs and property overrides. Anyway, | |||||
the running of these tasks is currently disabled. | |||||
</p> | |||||
<p> | |||||
Once the model is built, the commandline creates an execution manager | |||||
instance, passing it the initConfig built by Main.jar. It adds build | |||||
listeners and then starts the build using the services of the | |||||
ExecutionManager. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Ant Libraries"><strong>Ant Libraries</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
Before we get into execution proper, I'll deal with the structure of an | |||||
ant library and how it works. An antlibrary is a jar file with a library | |||||
descriptor located in META-INF/antlib.xml. This defines what | |||||
typedefs/taskdefs/converters the library makes available to Ant. The | |||||
classes or at least some of the classes for the library will normally be | |||||
available in the jar. The descriptor looks like this (I'll provide two | |||||
examples here) | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<antlib libid="ant.io" | |||||
home="http://jakarta.apache.org/ant" | |||||
isolated="true"> | |||||
<typedef name="thread" classname="java.lang.Thread"/> | |||||
<taskdef name="echo" classname="org.apache.ant.taskdef.io.Echo"/> | |||||
<converter classname="org.apache.ant.taskdef.io.FileConverter"/> | |||||
</antlib> | |||||
<antlib libid="ant.file" | |||||
home="http://jakarta.apache.org/ant" | |||||
reqxml="true" reqtools="true" extends="ant.io" | |||||
isolated="true"> | |||||
<taskdef name="copy" classname="org.apache.ant.file.copy"/> | |||||
</antlib> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
the "libid" attribute is used to globally identify a library. It is used | |||||
in Ant to pick which tasks you want to make available to a build file. | |||||
As the number of tasks available goes up, this is used to prevent name | |||||
collisions, etc. The name is constructed similarly to a Java package name - | |||||
i.e Reverse DNS order. | |||||
</p> | |||||
<p> | |||||
The "home" attribute is a bit of fluff unused by mutant to allow tools | |||||
to manage libraries and update them etc. More thought could go into | |||||
this. | |||||
</p> | |||||
<p> | |||||
"reqxml" allows a library to say that it wants to use Ant's XML parser | |||||
classes. Note that these will be coming from the library's classloader | |||||
so they will not, in fact, be the same runtime classes as used in Ant's core, | |||||
but it saves tasks packaging their own XML parsers. | |||||
</p> | |||||
<p> | |||||
"reqtools" allows a library to specify that it uses classes from Sun's | |||||
tools.jar file. Again, if tools.jar is available it will be added to the | |||||
list of classes in the library's classloader | |||||
</p> | |||||
<p> | |||||
"extends" allows for a single "inheritance" style relationship between | |||||
libraries. I'm not sure how useful this may be yet but it seems | |||||
important for accessing common custom types. It basically translates | |||||
into the class loader for this library using the one identified in | |||||
extends as its parent. | |||||
</p> | |||||
<p> | |||||
"isolate" specifies that each task created from this libary comes from | |||||
its own classloader. This can be used with tasks derived from Java | |||||
applications which have static initialisers. This used to be an issue | |||||
with the Anakia task, for example. Similarly it could be used to ensure that | |||||
tool.jar classes are unloaded to stop memory leaks. Again this is | |||||
experimental so may not prove ultimately useful. | |||||
</p> | |||||
<p> | |||||
The <typedef> in the example creates a <thread> type. That is just a bit of fun which | |||||
I'll use in an example later. It does show the typedefing of a type from | |||||
outside the ant library however. | |||||
</p> | |||||
<p> | |||||
<taskdef> is pretty obvious. It identifies a taskname with a class from | |||||
the library. The import task, which I have not yet implemented will | |||||
allow this name to be aliased - something like | |||||
</p> | |||||
<p> | |||||
<import libid="ant.file" task="echo" alias="antecho"/> | |||||
</p> | |||||
<p> | |||||
Tasks are not made available automatically. The build file must state | |||||
which tasks it wants to use using an <import> task. This is similar to | |||||
Java's import statement. Similarly classes whose ids start with "ant." | |||||
are fully imported at the start of execution. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Mutant Configuration"><strong>Mutant Configuration</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
When mutant starts execution, it reads in a config file. Actually it | |||||
attempts to read two files, one from $ANT_HOME/conf/antconfig.xml and | |||||
another from $HOME/.ant/antconfig.xml. Others could be added even | |||||
specified in the command line. These config files are used to provide | |||||
two things - libpaths and task dirs. | |||||
</p> | |||||
<p> | |||||
Taskdirs are locations to search for additional ant libraries. As people | |||||
bundle Ant tasks and types with their products, it will not be practical | |||||
to bundle all this into ANT_HOME/lib. These additional dirs are scanned | |||||
for ant libraries. All .zip/.jar/.tsk files which contain the | |||||
META-INF/antlib.xml file will be processed. | |||||
</p> | |||||
<p> | |||||
Sometimes, of course, the tasks and the libraries upon which they depend | |||||
are not produced by the same people. It is not feasible to go in and | |||||
edit manifests to connect the ant library with its required support | |||||
jars, so the libpath element in the config file is used to specify | |||||
additional paths to be added to a library's classloader. An example | |||||
config would be | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<antconfig> | |||||
<libpath libid="ant.file" path="fubar"/> | |||||
<libpath libid="ant.file" url="http://fubar"/> | |||||
</antconfig> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Obviously other information can be added to the config - standard | |||||
property values, compiler prefs, etc. I haven't done that yet. User | |||||
level config override system level configs. | |||||
</p> | |||||
<p> | |||||
So, when a ant library creates a classloader, it will take a number of | |||||
URLS. One is the task library itself, the XML parser classes if | |||||
requested, the tools.jar if requested, and any additional libraries | |||||
specified in the <antconfig>. The parent loader is the common loader | |||||
from the initconfig. unless this library is an extending library. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Mutant Execution"><strong>Mutant Execution</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
Execution of a build is provided by the core through two key classes. | |||||
One if the ExecutionManager and the other is the ExecutionFrame. An | |||||
execution frame is created for each project in the project model | |||||
hierarchy. It represents the execution state of the project - data | |||||
values, imported tasks, typedefs, taskdefs, etc. | |||||
</p> | |||||
<p> | |||||
The ExecutionManager begins by reading configs, searching for ant | |||||
libraries, configuring and appending any additional paths, etc. It then | |||||
creates a root ExecutionFrame which represents the root project. when a | |||||
build is commenced, the project model is validated and then passed to | |||||
the ExecutionFrame. | |||||
</p> | |||||
<p> | |||||
the ExecutionFrame is the main execution class. When it is created it | |||||
imports all ant libraries with ids that start with ant.*. All others are | |||||
available but must be explicitly imported with <import> tasks. When the | |||||
project is passed in, ExecutionFrames are created for any referenced | |||||
projects. This builds an ExecutionFrame hierarchy which parallels the | |||||
project hierarchy. Each <ref> uses a name to identify the referenced | |||||
project. All property and target references use these reference names to | |||||
identify the particular frame that hold the data. As an example, look at | |||||
this build file | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir=".." doc:Hello="true"> | |||||
<ref project="test.ant" name="reftest"/> | |||||
<target name="test" depends="reftest:test2"> | |||||
<echo message="hello"/> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Notice the depends reference to the test2 target in the test.ant project | |||||
file. I am still using the ":" as a separator for refs. It doesn't | |||||
collide with XML namespaces so that should be OK. | |||||
</p> | |||||
<p> | |||||
Execution proceeds by determining the targets in the various frames | |||||
which need to be executed. The appropriate frame is requested to execute | |||||
the target's tasks and type instances. The imports for the frame are | |||||
consulted to determine what is the approrpiate library and class from | |||||
that library. A classloader is fetched, the class is instantiated, | |||||
introspected and then configured from the corresponding part of the | |||||
project model. Ant 1.x's IntrospectionHelper has been split into two - | |||||
the ClassIntrospector and the Reflector. When the task is being | |||||
configured, the context classloader is set. Similarly it is set when the | |||||
task is being executed. Types are handled similarly. When a type in | |||||
instantiated or a task executed, and they support the appropriate | |||||
interface, they will be passed a context through which they can access | |||||
the services of the core. Currently the context is an interface although | |||||
I have wondered if an abstract class may be better to handle expansion | |||||
of the services available over time. | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="#525D76"> | |||||
<font color="#ffffff" face="arial,helvetica,sanserif"> | |||||
<a name="Introspection and Polymorphism"><strong>Introspection and Polymorphism</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
<p> | |||||
Introspection is not a lot different from Ant 1.x. After some thought I | |||||
have dropped the createXXX method to allow for polymorphic type support, discussed | |||||
below. setXXX methods, coupled with an approriate string to | |||||
type converter are used for attributes. addXXX methods are used for | |||||
nested elements. All of the value setting has been moved to a Reflector | |||||
object. Object creation for addXXX methods is no longer provided in the | |||||
reflector class, just the storage of the value. This allows support for | |||||
add methods defined in terms of interfaces. For example, the hacked Echo | |||||
task I am using has this definition | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
/** | |||||
* testing | |||||
* | |||||
* @param runnable testing | |||||
*/ | |||||
public void addRun(Runnable runnable) { | |||||
log("Adding runnable of type " | |||||
+ runnable.getClass().getName(), MessageLevel.MSG_WARN); | |||||
} | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
So when mutant encounteres a nested element it does the following checks | |||||
</p> | |||||
<p> | |||||
Is the value specified by reference? | |||||
</p> | |||||
<p> | |||||
<run ant:refid="test"/> | |||||
</p> | |||||
<p> | |||||
Is it specified by as a polymorphic type? | |||||
</p> | |||||
<p> | |||||
<run ant:type="thread"/> | |||||
</p> | |||||
<p> | |||||
or is it just a normal run o' the mill nested element, which is | |||||
instantiated by a zero arg constructor. | |||||
</p> | |||||
<p> | |||||
Note the use of the ant namespace for the metadata. In essence the | |||||
nested element name <run> identifies the add method to be used, while | |||||
the refId or type elements specify the actual instance or type to be | |||||
used. The ant:type identifies an Ant datatype to be instantiated. If | |||||
neither is specified, the type that is expected by the identified | |||||
method, addRun in this case, is used to create an instance. In this case | |||||
that would fail. | |||||
</p> | |||||
<p> | |||||
Polymorphism, coupled with typedefs is one way, and a good way IMHO, of | |||||
solving the extensibility of tasks such as ejbjar. | |||||
</p> | |||||
<p> | |||||
OK, that is about the size of it. Let me finish with two complete build | |||||
files and the result of running mutant on them. | |||||
</p> | |||||
<h3>build.ant</h3> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir=".." doc:Hello="true"> | |||||
<ref project="test.ant" name="reftest"/> | |||||
<target name="test" depends="reftest:test2"> | |||||
<echo message="hello"/> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<h3>test.ant</h3> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir="." doc:Hello="true"> | |||||
<target name="test2"> | |||||
<thread ant:id="testit"/> | |||||
<echo message="hello2"> | |||||
<run ant:refid="testit"> | |||||
</run> | |||||
</echo> | |||||
<echo message="hello3"> | |||||
<run ant:type="thread"> | |||||
</run> | |||||
</echo> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
If I run mutant via a simple script which has just one line | |||||
</p> | |||||
<p> | |||||
java -jar /home/conor/dev/mutant/dist/lib/start.jar $* | |||||
</p> | |||||
<p> | |||||
I get this | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
test2: | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello2 | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello3 | |||||
test: | |||||
[echo] hello | |||||
BUILD SUCCESSFUL | |||||
Total time: 0 seconds | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Lets change the <run> definition to | |||||
</p> | |||||
<p> | |||||
<run/> in test.ant and the result becomes | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
test2: | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello2 | |||||
BUILD FAILED | |||||
/home/conor/dev/mutant/test/test.ant:10: | |||||
No element can be created for nested element <run>. | |||||
Please provide a value by reference or specify the value type | |||||
</pre> | |||||
</p> | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
</td> | |||||
</tr> | |||||
<!-- FOOTER --> | |||||
<tr><td colspan="2"> | |||||
<hr noshade="" size="1"/> | |||||
</td></tr> | |||||
<tr><td colspan="2"> | |||||
<div align="center"><font color="#525D76" size="-1"><em> | |||||
Copyright © 2000-2002, Apache Software Foundation | |||||
</em></font></div> | |||||
</td></tr> | |||||
</table> | |||||
</body> | |||||
</html> | |||||
<!-- end the processing --> | |||||
@@ -0,0 +1,607 @@ | |||||
<?xml version="1.0"?> | |||||
<document> | |||||
<properties> | |||||
<author email="conor@apache.org">Conor MacNeill</author> | |||||
<title>Mutant Design Notes</title> | |||||
</properties> | |||||
<body> | |||||
<section name="Mutant Design Notes"> | |||||
<p> | |||||
This is a brief, albeit rambling description of Mutant. | |||||
Mutant has many experimental ideas which may or may not prove useful. | |||||
I'll try to describe what is there and let anyone who is interested | |||||
comment. Mutant is still immature. You'll notice that there is, at this | |||||
time, just one task, a hacked version of the echo task, which I have | |||||
been using to test out ideas. Most tasks would end up being pretty | |||||
similar to their Ant 1.x version. | |||||
</p> | |||||
<p> | |||||
OK, let me start with some of the motivating requirements. There are of | |||||
coure many Ant2 requirements but I want to focus on these two for now. | |||||
Mutant does also address many of the other Ant2 requirements. | |||||
</p> | |||||
<p> | |||||
I'll use the terms Ant and mutant somewhat interchangeably - just | |||||
habit, not an assumption of any sort. | |||||
</p> | |||||
<p> | |||||
One of the things which is pretty difficult in Ant 1.x is the | |||||
management of classpaths and classloaders. For example, today the | |||||
antlr task requires the antlr classes in the classpath used to start | |||||
ant. I'm talking here about the classpath built up in the ant.bat/ant | |||||
script launchers. At the same time, the checkstyle task | |||||
which uses antlr won't run if the antlr classes are in the classpath | |||||
because then those classes cannot "see" the classes in the taskdef's | |||||
classpath. | |||||
</p> | |||||
<p> | |||||
Another requirement I have is extensibility. In Ant 1.x this is | |||||
difficult because whenever a new type is created, each task which | |||||
needs to support this type must be changed to provide the new addXXX | |||||
method. The ejbjar task is on example of this problem with its concept of vendor | |||||
specific tools. The zip/jar task, with its support for different types | |||||
of fileset, is another. The addition of the classfileset to Ant requires | |||||
a change to the zip task. | |||||
</p> | |||||
</section> | |||||
<section name="Mutant Initialization"> | |||||
<p> | |||||
Mutant defines a classloader hierarchy somewhat similar to that used | |||||
in Tomcat 4. Tasks join into this hierarchy at a particular point to | |||||
ensure they have visibility of the necessary interface classes and no | |||||
visibility of the Ant core itself. There is nothing particularly novel | |||||
about this approach, but tasks are able to request certain additional resources | |||||
as we will see later. | |||||
</p> | |||||
<p> | |||||
Mutant starts with two jars. One is the start.jar which contains just | |||||
one class, Main.java which establishes the initial configuration and | |||||
then runs the appropriate front end command line class. If a different | |||||
front end was desired, a different launch class, in its own jar, would | |||||
be used. This would perhaps configure the classloader hierarchy somewhat | |||||
differently and start the approriate GUI front end class. | |||||
</p> | |||||
<p> | |||||
The second jar, init.jar, provides a number of initialisation utilities. These | |||||
are used by Main.java to setup Ant and would also be used by any other front end | |||||
to configure Ant. The important class here is the | |||||
InitConfig which communicates the state of Ant at startup into the the core of | |||||
Ant when it starts up. Main determines the location of ANT_HOME based on the | |||||
location of the start classes and then populates the InitConfig with both | |||||
classloaders and information about the location of various jars and config | |||||
files. | |||||
</p> | |||||
<p> | |||||
At the top of the classloader hierarchy | |||||
are the bootstrap and system classloaders. I won't really | |||||
distinguish between these in mutant. Combined they provide the JDK | |||||
classes, plus the classes from the init and start jars. One objective is | |||||
to keep the footprint of the init and start jars small so they do not | |||||
require any external classes, which may then become visible lower in the | |||||
hierarchy. Main does not explicitly create these loaders, of course, but | |||||
just adds a reference to the init config as system class loader | |||||
</p> | |||||
<p> | |||||
The next jar is for the common area. This provides interface definitions | |||||
and utility classes for use by both the core and by tasks/types etc. It | |||||
is loaded from ANT_HOME/lib/common/*.jar. Typically this is just | |||||
lib/common/common.jar but any other jars in here are loaded. This | |||||
pattern is used in the construction of all of the classloaders. | |||||
</p> | |||||
<p> | |||||
Next up is the core loader. It includes the lib/antcore/antcore.jar plus | |||||
any others including the XML parser jars. Mutant's core does not assume that | |||||
the project model will come from an XML description but XML facilities | |||||
are needed in the core for reading in Ant library defs and config files. | |||||
The parser jar locations are also stored in the init config. This lets | |||||
the jars be added to any Ant library that wants to use Ant's XML parser | |||||
rather than providing its own. Similarly tools.jar's location is | |||||
determined automatically and added to the config for use by tasks which | |||||
request it. I'll go into more detail when discussing the antlib processing. | |||||
</p> | |||||
<p> | |||||
The final jar that is loaded is the jar for the frontend - cli.jar. This | |||||
is not passed in init config since these classes are not visible to the | |||||
core and are not needed by it. So the hierarchy is | |||||
<pre> | |||||
jdk classes | |||||
| | |||||
start/init | |||||
| | |||||
common | |||||
| | |||||
antcore | |||||
| | |||||
cli | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Task classloaders generally will come in at common, hiding the core classes, front | |||||
end and XML parser classes from tasks. | |||||
</p> | |||||
<p> | |||||
Once Main has setup the initConfig, it creates the front end commandline | |||||
class and launches mutant proper, passing it the command line args and | |||||
the init config. | |||||
</p> | |||||
<p> | |||||
A GUI would typically replace start.jar and the cli.jar with its own | |||||
versions which manage model construction from GUI processes rather than | |||||
from XML files. It may be possible to move some of Main.java's | |||||
processing into init.jar if it is useful to other front ends. I haven't | |||||
looked at that balance. | |||||
</p> | |||||
</section> | |||||
<section name="Mutant Frontend"> | |||||
<p> | |||||
The front end is responsible for coordinating execution of Ant. It | |||||
manages command line arguments, builds a model of the Project to be | |||||
evaluated and coordinates the execution services of the core. cli.jar | |||||
contains not only the front-end code but also the XML parsing code for | |||||
building a project model from an XML description. Other front ends may | |||||
choose to build project models in different ways. Commandline is pretty | |||||
similar to Ant 1.x's Main.java - it handles arguments, building loggers, | |||||
listeners, defines, etc - actually I haven't fully implemented | |||||
command line defines in | |||||
mutant yet but it would be similar to Ant 1.x. | |||||
</p> | |||||
<p> | |||||
Commandline then moves to building a project model from the XML | |||||
representation. I have just expanded the approach in Ant 1's | |||||
ProjectHelper for XML parsing, moving away from a stack of inner classes. | |||||
The classes in the front end XML parsing use some XML utility base | |||||
classes from the core. | |||||
</p> | |||||
<p> | |||||
The XML parsing handles two elements at parse time. One is the <ref> | |||||
element which is used for project references - that is relationships | |||||
between project files. The referenced project is parsed as well. The | |||||
second is the <include> element which includes either another complete | |||||
project or a project <fragment> directly into the project. All the other | |||||
elements are used to build a project model which is later processed in | |||||
the core. | |||||
</p> | |||||
<p> | |||||
The project model itself is organized like this | |||||
</p> | |||||
<p> | |||||
<ul> | |||||
<li>A project contains</li> | |||||
<ul> | |||||
<li>named references to other projects</li> | |||||
<li>targets</li> | |||||
<li>build elements (tasks, type instances)</li> | |||||
</ul> | |||||
<li>A target contains</li> | |||||
<ul> | |||||
<li>build elements (tasks, type instances)</li> | |||||
</ul> | |||||
<li>A build element contains</li> | |||||
<ul> | |||||
<li>build elements (nested elements)</li> | |||||
</ul> | |||||
</ul> | |||||
</p> | |||||
<p> | |||||
So, for now the project model contains top level tasks and type | |||||
instances. I'm still thinking about those and property scoping | |||||
especially in the face of project refs and property overrides. Anyway, | |||||
the running of these tasks is currently disabled. | |||||
</p> | |||||
<p> | |||||
Once the model is built, the commandline creates an execution manager | |||||
instance, passing it the initConfig built by Main.jar. It adds build | |||||
listeners and then starts the build using the services of the | |||||
ExecutionManager. | |||||
</p> | |||||
</section> | |||||
<section name="Ant Libraries"> | |||||
<p> | |||||
Before we get into execution proper, I'll deal with the structure of an | |||||
ant library and how it works. An antlibrary is a jar file with a library | |||||
descriptor located in META-INF/antlib.xml. This defines what | |||||
typedefs/taskdefs/converters the library makes available to Ant. The | |||||
classes or at least some of the classes for the library will normally be | |||||
available in the jar. The descriptor looks like this (I'll provide two | |||||
examples here) | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<antlib libid="ant.io" | |||||
home="http://jakarta.apache.org/ant" | |||||
isolated="true"> | |||||
<typedef name="thread" classname="java.lang.Thread"/> | |||||
<taskdef name="echo" classname="org.apache.ant.taskdef.io.Echo"/> | |||||
<converter classname="org.apache.ant.taskdef.io.FileConverter"/> | |||||
</antlib> | |||||
<antlib libid="ant.file" | |||||
home="http://jakarta.apache.org/ant" | |||||
reqxml="true" reqtools="true" extends="ant.io" | |||||
isolated="true"> | |||||
<taskdef name="copy" classname="org.apache.ant.file.copy"/> | |||||
</antlib> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
the "libid" attribute is used to globally identify a library. It is used | |||||
in Ant to pick which tasks you want to make available to a build file. | |||||
As the number of tasks available goes up, this is used to prevent name | |||||
collisions, etc. The name is constructed similarly to a Java package name - | |||||
i.e Reverse DNS order. | |||||
</p> | |||||
<p> | |||||
The "home" attribute is a bit of fluff unused by mutant to allow tools | |||||
to manage libraries and update them etc. More thought could go into | |||||
this. | |||||
</p> | |||||
<p> | |||||
"reqxml" allows a library to say that it wants to use Ant's XML parser | |||||
classes. Note that these will be coming from the library's classloader | |||||
so they will not, in fact, be the same runtime classes as used in Ant's core, | |||||
but it saves tasks packaging their own XML parsers. | |||||
</p> | |||||
<p> | |||||
"reqtools" allows a library to specify that it uses classes from Sun's | |||||
tools.jar file. Again, if tools.jar is available it will be added to the | |||||
list of classes in the library's classloader | |||||
</p> | |||||
<p> | |||||
"extends" allows for a single "inheritance" style relationship between | |||||
libraries. I'm not sure how useful this may be yet but it seems | |||||
important for accessing common custom types. It basically translates | |||||
into the class loader for this library using the one identified in | |||||
extends as its parent. | |||||
</p> | |||||
<p> | |||||
"isolate" specifies that each task created from this libary comes from | |||||
its own classloader. This can be used with tasks derived from Java | |||||
applications which have static initialisers. This used to be an issue | |||||
with the Anakia task, for example. Similarly it could be used to ensure that | |||||
tool.jar classes are unloaded to stop memory leaks. Again this is | |||||
experimental so may not prove ultimately useful. | |||||
</p> | |||||
<p> | |||||
The <typedef> in the example creates a <thread> type. That is just a bit of fun which | |||||
I'll use in an example later. It does show the typedefing of a type from | |||||
outside the ant library however. | |||||
</p> | |||||
<p> | |||||
<taskdef> is pretty obvious. It identifies a taskname with a class from | |||||
the library. The import task, which I have not yet implemented will | |||||
allow this name to be aliased - something like | |||||
</p> | |||||
<p> | |||||
<import libid="ant.file" task="echo" alias="antecho"/> | |||||
</p> | |||||
<p> | |||||
Tasks are not made available automatically. The build file must state | |||||
which tasks it wants to use using an <import> task. This is similar to | |||||
Java's import statement. Similarly classes whose ids start with "ant." | |||||
are fully imported at the start of execution. | |||||
</p> | |||||
</section> | |||||
<section name="Mutant Configuration"> | |||||
<p> | |||||
When mutant starts execution, it reads in a config file. Actually it | |||||
attempts to read two files, one from $ANT_HOME/conf/antconfig.xml and | |||||
another from $HOME/.ant/antconfig.xml. Others could be added even | |||||
specified in the command line. These config files are used to provide | |||||
two things - libpaths and task dirs. | |||||
</p> | |||||
<p> | |||||
Taskdirs are locations to search for additional ant libraries. As people | |||||
bundle Ant tasks and types with their products, it will not be practical | |||||
to bundle all this into ANT_HOME/lib. These additional dirs are scanned | |||||
for ant libraries. All .zip/.jar/.tsk files which contain the | |||||
META-INF/antlib.xml file will be processed. | |||||
</p> | |||||
<p> | |||||
Sometimes, of course, the tasks and the libraries upon which they depend | |||||
are not produced by the same people. It is not feasible to go in and | |||||
edit manifests to connect the ant library with its required support | |||||
jars, so the libpath element in the config file is used to specify | |||||
additional paths to be added to a library's classloader. An example | |||||
config would be | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<antconfig> | |||||
<libpath libid="ant.file" path="fubar"/> | |||||
<libpath libid="ant.file" url="http://fubar"/> | |||||
</antconfig> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Obviously other information can be added to the config - standard | |||||
property values, compiler prefs, etc. I haven't done that yet. User | |||||
level config override system level configs. | |||||
</p> | |||||
<p> | |||||
So, when a ant library creates a classloader, it will take a number of | |||||
URLS. One is the task library itself, the XML parser classes if | |||||
requested, the tools.jar if requested, and any additional libraries | |||||
specified in the <antconfig>. The parent loader is the common loader | |||||
from the initconfig. unless this library is an extending library. | |||||
</p> | |||||
</section> | |||||
<section name="Mutant Execution"> | |||||
<p> | |||||
Execution of a build is provided by the core through two key classes. | |||||
One if the ExecutionManager and the other is the ExecutionFrame. An | |||||
execution frame is created for each project in the project model | |||||
hierarchy. It represents the execution state of the project - data | |||||
values, imported tasks, typedefs, taskdefs, etc. | |||||
</p> | |||||
<p> | |||||
The ExecutionManager begins by reading configs, searching for ant | |||||
libraries, configuring and appending any additional paths, etc. It then | |||||
creates a root ExecutionFrame which represents the root project. when a | |||||
build is commenced, the project model is validated and then passed to | |||||
the ExecutionFrame. | |||||
</p> | |||||
<p> | |||||
the ExecutionFrame is the main execution class. When it is created it | |||||
imports all ant libraries with ids that start with ant.*. All others are | |||||
available but must be explicitly imported with <import> tasks. When the | |||||
project is passed in, ExecutionFrames are created for any referenced | |||||
projects. This builds an ExecutionFrame hierarchy which parallels the | |||||
project hierarchy. Each <ref> uses a name to identify the referenced | |||||
project. All property and target references use these reference names to | |||||
identify the particular frame that hold the data. As an example, look at | |||||
this build file | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir=".." doc:Hello="true"> | |||||
<ref project="test.ant" name="reftest"/> | |||||
<target name="test" depends="reftest:test2"> | |||||
<echo message="hello"/> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Notice the depends reference to the test2 target in the test.ant project | |||||
file. I am still using the ":" as a separator for refs. It doesn't | |||||
collide with XML namespaces so that should be OK. | |||||
</p> | |||||
<p> | |||||
Execution proceeds by determining the targets in the various frames | |||||
which need to be executed. The appropriate frame is requested to execute | |||||
the target's tasks and type instances. The imports for the frame are | |||||
consulted to determine what is the approrpiate library and class from | |||||
that library. A classloader is fetched, the class is instantiated, | |||||
introspected and then configured from the corresponding part of the | |||||
project model. Ant 1.x's IntrospectionHelper has been split into two - | |||||
the ClassIntrospector and the Reflector. When the task is being | |||||
configured, the context classloader is set. Similarly it is set when the | |||||
task is being executed. Types are handled similarly. When a type in | |||||
instantiated or a task executed, and they support the appropriate | |||||
interface, they will be passed a context through which they can access | |||||
the services of the core. Currently the context is an interface although | |||||
I have wondered if an abstract class may be better to handle expansion | |||||
of the services available over time. | |||||
</p> | |||||
</section> | |||||
<section name="Introspection and Polymorphism"> | |||||
<p> | |||||
Introspection is not a lot different from Ant 1.x. After some thought I | |||||
have dropped the createXXX method to allow for polymorphic type support, discussed | |||||
below. setXXX methods, coupled with an approriate string to | |||||
type converter are used for attributes. addXXX methods are used for | |||||
nested elements. All of the value setting has been moved to a Reflector | |||||
object. Object creation for addXXX methods is no longer provided in the | |||||
reflector class, just the storage of the value. This allows support for | |||||
add methods defined in terms of interfaces. For example, the hacked Echo | |||||
task I am using has this definition | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
/** | |||||
* testing | |||||
* | |||||
* @param runnable testing | |||||
*/ | |||||
public void addRun(Runnable runnable) { | |||||
log("Adding runnable of type " | |||||
+ runnable.getClass().getName(), MessageLevel.MSG_WARN); | |||||
} | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
So when mutant encounteres a nested element it does the following checks | |||||
</p> | |||||
<p> | |||||
Is the value specified by reference? | |||||
</p> | |||||
<p> | |||||
<run ant:refid="test"/> | |||||
</p> | |||||
<p> | |||||
Is it specified by as a polymorphic type? | |||||
</p> | |||||
<p> | |||||
<run ant:type="thread"/> | |||||
</p> | |||||
<p> | |||||
or is it just a normal run o' the mill nested element, which is | |||||
instantiated by a zero arg constructor. | |||||
</p> | |||||
<p> | |||||
Note the use of the ant namespace for the metadata. In essence the | |||||
nested element name <run> identifies the add method to be used, while | |||||
the refId or type elements specify the actual instance or type to be | |||||
used. The ant:type identifies an Ant datatype to be instantiated. If | |||||
neither is specified, the type that is expected by the identified | |||||
method, addRun in this case, is used to create an instance. In this case | |||||
that would fail. | |||||
</p> | |||||
<p> | |||||
Polymorphism, coupled with typedefs is one way, and a good way IMHO, of | |||||
solving the extensibility of tasks such as ejbjar. | |||||
</p> | |||||
<p> | |||||
OK, that is about the size of it. Let me finish with two complete build | |||||
files and the result of running mutant on them. | |||||
</p> | |||||
<h3>build.ant</h3> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir=".." doc:Hello="true"> | |||||
<ref project="test.ant" name="reftest"/> | |||||
<target name="test" depends="reftest:test2"> | |||||
<echo message="hello"/> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<h3>test.ant</h3> | |||||
<p> | |||||
<pre> | |||||
<project default="test" basedir="." doc:Hello="true"> | |||||
<target name="test2"> | |||||
<thread ant:id="testit"/> | |||||
<echo message="hello2"> | |||||
<run ant:refid="testit"> | |||||
</run> | |||||
</echo> | |||||
<echo message="hello3"> | |||||
<run ant:type="thread"> | |||||
</run> | |||||
</echo> | |||||
</target> | |||||
</project> | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
If I run mutant via a simple script which has just one line | |||||
</p> | |||||
<p> | |||||
java -jar /home/conor/dev/mutant/dist/lib/start.jar $* | |||||
</p> | |||||
<p> | |||||
I get this | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
test2: | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello2 | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello3 | |||||
test: | |||||
[echo] hello | |||||
BUILD SUCCESSFUL | |||||
Total time: 0 seconds | |||||
</pre> | |||||
</p> | |||||
<p> | |||||
Lets change the <run> definition to | |||||
</p> | |||||
<p> | |||||
<run/> in test.ant and the result becomes | |||||
</p> | |||||
<p> | |||||
<pre> | |||||
test2: | |||||
[echo] Adding runnable of type java.lang.Thread | |||||
[echo] hello2 | |||||
BUILD FAILED | |||||
/home/conor/dev/mutant/test/test.ant:10: | |||||
No element can be created for nested element <run>. | |||||
Please provide a value by reference or specify the value type | |||||
</pre> | |||||
</p> | |||||
</section> | |||||
</body> | |||||
</document> | |||||
@@ -0,0 +1,50 @@ | |||||
<?xml version="1.0" encoding="ISO-8859-1"?> | |||||
<project name="Jakarta Site" | |||||
href="http://jakarta.apache.org/"> | |||||
<title>The Jakarta Site</title> | |||||
<!-- uncomment and put your project logo here! | |||||
<logo href="http://jakarta.apache.org/images/jakarta-logo.gif">The Jakarta Project</logo> | |||||
--> | |||||
<body> | |||||
<menu name="Apache Ant"> | |||||
<item name="Front Page" | |||||
href="/index.html"/> | |||||
<item name="News" | |||||
href="/antnews.html"/> | |||||
<item name="Documentation" | |||||
href="/manual/index.html"/> | |||||
<item name="External Tools and Tasks" | |||||
href="/external.html"/> | |||||
<item name="Resources" | |||||
href="/resources.html"/> | |||||
<item name="Ant FAQ" | |||||
href="/faq.html"/> | |||||
<item name="Having Problems?" | |||||
href="/problems.html"/> | |||||
</menu> | |||||
<menu name="Download"> | |||||
<item name="Binaries" href="/site/binindex.html"/> | |||||
<item name="Source Code" href="/site/sourceindex.html"/> | |||||
</menu> | |||||
<menu name="Jakarta"> | |||||
<item name="News & Status" href="/site/news.html"/> | |||||
<item name="Mission" href="/site/mission.html"/> | |||||
<item name="Guidelines Notes" href="/site/guidelines.html"/> | |||||
<item name="FAQs" href="/site/faqs.html"/> | |||||
</menu> | |||||
<menu name="Get Involved"> | |||||
<item name="Overview" href="/site/getinvolved.html"/> | |||||
<item name="CVS Repositories" href="/site/cvsindex.html"/> | |||||
<item name="Mailing Lists" href="/site/mail.html"/> | |||||
<item name="Reference Library" href="/site/library.html"/> | |||||
<item name="Bug Database" href="http://nagoya.apache.org/bugzilla/enter_bug.cgi?product=Ant"/> | |||||
<item name="Enhancement Requests" href="http://nagoya.apache.org/bugzilla/enter_bug.cgi?product=Ant&bug_severity=Enhancement"/> | |||||
</menu> | |||||
</body> | |||||
</project> |
@@ -0,0 +1,81 @@ | |||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |||||
<!-- Content Stylesheet for Site --> | |||||
## Defined variables | |||||
#set ($bodybg = "#ffffff") | |||||
#set ($bodyfg = "#000000") | |||||
#set ($bodylink = "#525D76") | |||||
#set ($bannerbg = "#525D76") | |||||
#set ($bannerfg = "#ffffff") | |||||
#set ($subbannerbg = "#828DA6") | |||||
#set ($subbannerfg = "#ffffff") | |||||
#set ($tablethbg = "#039acc") | |||||
#set ($tabletdbg = "#a0ddf0") | |||||
<!-- start the processing --> | |||||
#document() | |||||
<!-- end the processing --> | |||||
## This is where the common page macro's live | |||||
#macro ( subsection $subsection) | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="$subbannerbg"> | |||||
<font color="$subbannerfg" face="arial,helvetica,sanserif"> | |||||
<a name="$subsection.getAttributeValue("name")"><strong>$subsection.getAttributeValue("name")</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
#foreach ( $items in $subsection.getChildren() ) | |||||
#if ($items.getName().equals("img")) | |||||
#image ($items) | |||||
#elseif ($items.getName().equals("source")) | |||||
#source ($items) | |||||
#elseif ($items.getName().equals("table")) | |||||
#table ($items) | |||||
#else | |||||
$xmlout.outputString($items) | |||||
#end | |||||
#end | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
#end | |||||
#macro ( section $section) | |||||
<table border="0" cellspacing="0" cellpadding="2" width="100%"> | |||||
<tr><td bgcolor="$bannerbg"> | |||||
<font color="$bannerfg" face="arial,helvetica,sanserif"> | |||||
<a name="$section.getAttributeValue("name")"><strong>$section.getAttributeValue("name")</strong></a> | |||||
</font> | |||||
</td></tr> | |||||
<tr><td> | |||||
<blockquote> | |||||
#foreach ( $items in $section.getChildren() ) | |||||
#if ($items.getName().equals("img")) | |||||
#image ($items) | |||||
#elseif ($items.getName().equals("source")) | |||||
#source ($items) | |||||
#elseif ($items.getName().equals("table")) | |||||
#table ($items) | |||||
#elseif ($items.getName().equals("subsection")) | |||||
#subsection ($items) | |||||
#else | |||||
$xmlout.outputString($items) | |||||
#end | |||||
#end | |||||
</blockquote> | |||||
</td></tr> | |||||
</table> | |||||
#end | |||||
#macro (document) | |||||
#header() | |||||
#set ($allSections = $root.getChild("body").getChildren("section")) | |||||
#foreach ( $section in $allSections ) | |||||
#section ($section) | |||||
#end | |||||
#footer() | |||||
#end |
@@ -0,0 +1,196 @@ | |||||
## This is where the common macro's live | |||||
#macro ( table $table) | |||||
<table> | |||||
#foreach ( $items in $table.getChildren() ) | |||||
#if ($items.getName().equals("tr")) | |||||
#tr ($items) | |||||
#end | |||||
#end | |||||
</table> | |||||
#end | |||||
#macro ( tr $tr) | |||||
<tr> | |||||
#foreach ( $items in $tr.getChildren() ) | |||||
#if ($items.getName().equals("td")) | |||||
#td ($items) | |||||
#elseif ($items.getName().equals("th")) | |||||
#th ($items) | |||||
#end | |||||
#end | |||||
</tr> | |||||
#end | |||||
#macro ( td $value) | |||||
#if ($value.getAttributeValue("colspan")) | |||||
#set ($colspan = $value.getAttributeValue("colspan")) | |||||
#end | |||||
#if ($value.getAttributeValue("rowspan")) | |||||
#set ($rowspan = $value.getAttributeValue("rowspan")) | |||||
#end | |||||
<td bgcolor="$tabletdbg" colspan="$!colspan" rowspan="$!rowspan" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
#if ($value.getText().length() != 0 || $value.hasChildren()) | |||||
$xmlout.outputString($value, true) | |||||
#else | |||||
| |||||
#end | |||||
</font> | |||||
</td> | |||||
#end | |||||
#macro ( th $value) | |||||
#if ($value.getAttributeValue("colspan")) | |||||
#set ($colspan = $value.getAttributeValue("colspan")) | |||||
#end | |||||
#if ($value.getAttributeValue("rowspan")) | |||||
#set ($rowspan = $value.getAttributeValue("rowspan")) | |||||
#end | |||||
<td bgcolor="$tablethbg" colspan="$!colspan" rowspan="$!rowspan" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
#if ($value.getText().length() != 0 || $value.hasChildren()) | |||||
$xmlout.outputString($value, true) | |||||
#else | |||||
| |||||
#end | |||||
</font> | |||||
</td> | |||||
#end | |||||
#macro ( projectanchor $name $value ) | |||||
#if ($value.startsWith("http://")) | |||||
<a href="$value">$name</a> | |||||
#elseif ($value.startsWith("/site")) | |||||
<a href="http://jakarta.apache.org$value">$name</a> | |||||
#else | |||||
<a href="$relativePath$value">$name</a> | |||||
#end | |||||
#end | |||||
#macro ( metaauthor $author $email ) | |||||
<meta name="author" value="$author"> | |||||
<meta name="email" value="$email"> | |||||
#end | |||||
#macro ( image $value ) | |||||
#if ($value.getAttributeValue("width")) | |||||
#set ($width=$value.getAttributeValue("width")) | |||||
#end | |||||
#if ($value.getAttributeValue("height")) | |||||
#set ($height=$value.getAttributeValue("height")) | |||||
#end | |||||
#if ($value.getAttributeValue("align")) | |||||
#set ($align=$value.getAttributeValue("align")) | |||||
#end | |||||
<img src="$relativePath$value.getAttributeValue("src")" | |||||
width="$!width" height="$!height" align="$!align"> | |||||
#end | |||||
#macro ( source $value) | |||||
<div align="left"> | |||||
<table cellspacing="4" cellpadding="0" border="0"> | |||||
<tr> | |||||
<td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
<td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
<td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
</tr> | |||||
<tr> | |||||
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
<td bgcolor="#ffffff"><pre>$escape.getText($value.getText())</pre></td> | |||||
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
</tr> | |||||
<tr> | |||||
<td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
<td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
<td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> | |||||
</tr> | |||||
</table> | |||||
</div> | |||||
#end | |||||
#macro ( makeProject ) | |||||
#set ($menus = $project.getChild("body").getChildren("menu")) | |||||
#foreach ( $menu in $menus ) | |||||
<p><strong>$menu.getAttributeValue("name")</strong></p> | |||||
<ul> | |||||
#foreach ( $item in $menu.getChildren() ) | |||||
#set ($name = $item.getAttributeValue("name")) | |||||
<li>#projectanchor($name $item.getAttributeValue("href"))</li> | |||||
#end | |||||
</ul> | |||||
#end | |||||
#end | |||||
#macro (getProjectImage) | |||||
#if ($project.getChild("logo")) | |||||
<td align="left"> | |||||
<a href="http://jakarta.apache.org"><img src="http://jakarta.apache.org/images/jakarta-logo.gif" border="0"/></a> | |||||
</td> | |||||
<td align="right"> | |||||
#set ( $logoString = $project.getChild("logo").getAttributeValue("href") ) | |||||
#if ( $logoString.startsWith("/") ) | |||||
<a href="$project.getAttributeValue("href")"><img src="$relativePath$logoString" alt="$project.getChild("logo").getText()" border="0"/></a> | |||||
#else | |||||
<a href="$project.getAttributeValue("href")"><img src="$relativePath/$logoString" alt="$project.getChild("logo").getText()" border="0"/></a> | |||||
#end | |||||
</td> | |||||
#else | |||||
<td colspan="2"> | |||||
<a href="http://jakarta.apache.org"><img src="http://jakarta.apache.org/images/jakarta-logo.gif" align="left" border="0"/></a> | |||||
</td> | |||||
#end | |||||
#end | |||||
#macro (header) | |||||
<html> | |||||
<head> | |||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> | |||||
#set ($authors = $root.getChild("properties").getChildren("author")) | |||||
#foreach ( $au in $authors ) | |||||
#metaauthor ( $au.getText() $au.getAttributeValue("email") ) | |||||
#end | |||||
<title>$project.getChild("title").getText() - $root.getChild("properties").getChild("title").getText()</title> | |||||
</head> | |||||
<body bgcolor="$bodybg" text="$bodyfg" link="$bodylink"> | |||||
<table border="0" width="100%" cellspacing="0"> | |||||
<!-- TOP IMAGE --> | |||||
<tr> | |||||
#getProjectImage() | |||||
</tr> | |||||
</table> | |||||
<table border="0" width="100%" cellspacing="4"> | |||||
<tr><td colspan="2"> | |||||
<hr noshade="" size="1"/> | |||||
</td></tr> | |||||
<tr> | |||||
<!-- LEFT SIDE NAVIGATION --> | |||||
<td valign="top" nowrap="true"> | |||||
#makeProject() | |||||
</td> | |||||
<td align="left" valign="top"> | |||||
#end | |||||
#macro (footer) | |||||
</td> | |||||
</tr> | |||||
<!-- FOOTER --> | |||||
<tr><td colspan="2"> | |||||
<hr noshade="" size="1"/> | |||||
</td></tr> | |||||
<tr><td colspan="2"> | |||||
<div align="center"><font color="$bodylink" size="-1"><em> | |||||
Copyright © 2000-2002, Apache Software Foundation | |||||
</em></font></div> | |||||
</td></tr> | |||||
</table> | |||||
</body> | |||||
</html> | |||||
#end |
@@ -0,0 +1,2 @@ | |||||
file.resource.loader.path=xdocs/stylesheets | |||||
velocimacro.library=templates.vm |