Ant 2.0 Proposal

Code Name - Frantic

Frantic hardly describes the proposal process...more like my coding and design efforts! I am relatively new to Ant and the mail list, and I have posted several emails recently regarding the use of DOM in the future of Ant. Once I discovered the mail archive (thanks Simeon), I had a chance to notice that many of my questions were asked before. My extemporaneous emails were not without consequence it seems. After writing one of them it set some wheels in motion for what I hope is a useful addition to the current (and growing) number of proposals for Ant 2.0.

I think the concept behind Ant should be changed to be a "Task Execution Engine", and the concept of Project and Target can be generalized into a specific form of a Task.

 

The email list has received some requests from developers to extend Ant to support different problem domains. Peter Donald has latched onto this issue and I understand that he has incorporated some of these ideas into his Ant proposal. I also have seen some very impressive DOM support integrated into Antidote, an elegant basis for a GUI editor crafted by Simeon Fitch. Sim achieves a great deal of flexibility by using the W3C DOM as a superclass to his Project/Target/Task objects. He has, in effect, abstracted each of these "core" Ant objects until they are simply DOM nodes.

Peter's and Sim's ideas struck a chord and I thought that Peter's desire to allow Ant to break free from the Build domain and into Install domains by extending Ant, could be achieved by looking at the problem from a different point of view. As I stated in my email, we can achieve a much higher degree of flexibility in Ant by generalizing more.

Design Proposal

I believe that Ant 2.0 should be re-termed a Task Execution Engine, and the core of Ant becomes the Engine and the Task. This seems a little radical considering that the Project/Target/Task object model has served us so well in Ant 1.x, however it is very clear that Project and Target are simple another type of Task.

An enormous amount of code has been added to maintain Project and Target as separate classes with distinct, hard-coded behaviors. From the proof-of-concept code that I have been developing, I am inspired by how much more elegant the code becomes when this simplified model is realized.

Having a base Task interface that all Tasks implement will also offer a generalized approach that benefits GUI's in much the same manner that the DOM has helped Antidote. Also, by making Task an interface instead of a class, we can finally free ourselves of implementation specifics.

As I was writing the concept code, it struck me that I was too worried about the XML. Simeon Fitch mentioned in an email in early December, the possibility of storing build scripts in a database. I think this, along with various comments about DOM dependencies from Peter Donald, Jose Alberto Fernandez, and Stefan Bodewig made me realize that Core Ant shouldn't care where the build script lives or in which format it is stored. It is the object model that is primarily important.

The Task

The cornerstone of this proposal hinges on the Task Interface. It is the only type of external object that the Execution Engine knows how to handle. It is in this simplicity that the most powerful Ant can be realized.

The Task is an object that is aware of it's place in ahierarchy. To this end it is aware of its parent and its children. Please note that this is a runtime dependency and a scripting language (or the Task itself) can dynamically change the relationship of Tasks.

Figure 1

Key to being able to manipulate Tasks at runtime is some sort of naming conventions. Currently in the Frantic design is the concept of a Task name. Tasks, being hierarchical, can be thought of as a directory structure (see figure 1). If each Task is assigned a name that is unique among its siblings, we can then have a powerful means of locating and referencing a particular Task anywhere in the hierarchy.

For example, the Property Task below the Target named "build" has a name of "prop3", however its "fully-qualified" name is /root/build/prop3. The root of a Task execution list is "/" and the tag name, in our example /root. In the concept source code I use this principal of hierarchical naming to support dependencies. Currently, I am treating these Task names as directories and not as files. This should perhaps change slightly to the filename approach. In the directory-based approach, a sibling is named "../sibling". It would be more convenient to not require the "../". In fact, I think I have convinced myself of this.

Task Discovery

I haven't coded this portion, however I plan on basing it on Duncan's idea of using the Jar manifests to locate and identify tasks on the classpath. I was first exposed to this technique in the OpenTools API of Borland's JBuilder IDE, and I have since used it on a large project for a consulting customer.

The classpath is scanned at runtime to locate all directories and jar files. These directories and jar files will have a manifest file that will contain manifest entries that serve to tie a string token to the Task implementation class responsible for that token. Directories cannot have manifests per se, but we will utilize a file, one-level up from the directory, with a name "directory-name.mf". This file will be in the format of a manifest file. This will allow developers to create and test new Tasks without the burden of having to make a Jar archive every time.

Attribute Validation

Brett McLaughlin introduced a very interesting techique to perform object validation using XML Schema in a series of JavaWorld articles. I can see this technique applied to Tasks as well. The user could include a schema with a special name in the jar file that accompanies the Tasks. This schema could be used at runtime to validate a Task's attributes.

I would imagine that this feature would be outside of what is considered "core" Ant.

The Execution Engine

The engine only knows how to process Task objects, and that is what makes it extremely efficient. It is modeled after how I believe a compiler, or command interpreter would function. It contains a call stack which I call a task stack, and this task stack is under complete control of the engine. This is not to say that Tasks cannot manipulate the task stack at runtime, because they do. However, all of this access takes place under the watchful eye of the execution engine.

Properties

Keeping track of properties is closely tied to the execution engine, and I modeled it in a manner consistent with how I believe compilers must work. I use the concept of a hierarchical series of hashtables that support the concept of scope in property lists.

I had originally put the concept of a property into a Task and completely implemented the bugger. It turned out during testing that my logic was flawed. It seemed to work well at first...a property defined in a Task would be available to all child Tasks, but unavailable to any ancestors. When a Task requested the latest data on a property, it would look in its property list. If it wasn't found there, it would look in its parent's list, and so on. Instant scope.

However, it became quickly apparent that properties are a "runtime" consideration. This is something that Jose Alberto Fernandez will not let any of us forget for long. :-) What I needed was to move this hierarchical chain of property lists into the engine. For each new Task executed, a new property list is created and also pushed onto the stack. It seems to work like a champ.

I also coded up key substitution into the getParameterValue() events. They seem to work fine, although I haven't worked up enough test cases to be sure.

One additional cool feature is that parameters need not only hold Strings. I thought that there would be occasions where properties will hold Tasks as well. I believe this will turn out to be a prime mechanism for creating reference id Tasks like the current FileSet objects and referring to them in other Tasks just as you would any property value.

Attributes

I haven't spent any time addresing what is currently referred to a Task's attributes in Ant 1.x. I still need to think about this concept some more, but as I dwell on what an attribute is, I keep coming back to the properties. Just like a property functions as a scoped variable, an attribute is the same thing. Albeit, its scope is limited to the Task that uses it, but so what.

Execution Events

The execution engine also supports a few key events that can occur during the execution lifecycle. Currently events exist for execution start/finish, task start/execute/finish, exceptions, and simple messaging. The messaging event allows Tasks to communicate in a standard way that will leverage the engine's event system to allow various front-ends to intelligently and appropriately process the output.

Scripting

I have no experience with incorporating a scripting engine into an engine, but I do know that this proposal should address the primary issues that surround such an integration. I think that two features which are absolutely essential are:

Provide some sort of naming convention such that a particular Task can be found given an absolute name or a name relative to another Task. This is complete and working in the concept code.

Leave all decisions regarding property evaluation and Task's knowledge of these properties until the last possible moment.

Recursive Tasks

I realize that Ant 1.x spent some clock cycles dedicated to resolving circular references in the Task definitions. I didn't spend any time on that intentionally. I am not so sure that the elimination of circular references is a good idea. Especially moving forward, with the incorporation of a scripting language, I can envision Tasks the assembler wants to execute repeatedly, perhaps even recursively. I think we should treat this the same way that any modern computer language would — caveat emptor.

Summary

There is a lot more to do with this proposal and the concept code. It has been an exciting weekend getting these thoughts down and trying to back them up. I look forward to collaborating with others on the list if they wish to help me, even though I am in proposal phase. I certainly don't know much about XML parsing and I could use some ideas on how to further my starting model. I would love to show the Ant core model built in a Builder agnostic manner. Basically, I want XML to be an option, not a requirement.

I would also be interested in perhaps building an adapter task that will allow Ant 1.x tasks to be reused unchanged in the Frantic proposal. The concept of a Task hasn't changed much, so perhaps this is a possibility.

As always, your feedback is welcome. I expect that I have missed some major holes and I would like the opportunity to work with others to plug them up!

Jim Cook
Visual XS