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 |