ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From William Uther <will+...@cs.cmu.edu>
Subject Re: ANT's strange semantics and proposed change
Date Fri, 25 Feb 2000 22:35:32 GMT
Hi all,

  I know you're sick of me, but I thought I'd post this before disappearing
for the weekend.  Basically, this is a more detailed proposal on a way to
change ANT's semantics.  I see this as a much more contentious issue and a
much larger change than simply adding switch.  It will break some tasks
(although they should be easy to fix).

  I've added the outline of a series of interfaces and methods to this
email.  Essentially they show the top of the task class hierarchy.

This is different from the current ANT in a few ways:
  - Most of the functionality from ProjectHelper has moved into
AbstractElement.
  - Elements are not checked for correctness until they are executed.  This
means that it is possible to have an extra argument in an XML tag and not
find out about it in a single execution.  (You could add a DTD to have the
XML parser catch this.)
  - Tasks are not constructed/set until just before they are executed, nor
are they kept around afterwards.
  - The DOM is used throughout execution and is exposed to the ANTElements.
  - Arbitrary "deep-xml" elements are expected to implement ANTElement, and
usually to subclass AbstractElement.  (as opposed to be arbitrary objects)

It is similar to the current system in a few ways:
  - The basic task structure and use of reflection to set attributes and
normal "deep-xml" is the same.  Tasks that do not use the init() method or
deep-xml should work unchanged (except for being modified to inherit from
AbstractElement).  Other tasks should be easy to fix.
  - If you inherit the init method from AbstractElement then all your
elements will be built before you are execute()ed.  (just like now).

  In the code below, Element refers to a DOM element.  I haven't compiled
this so I may have bugs/typos.  The basic concept is pretty simple.  Most
of the functionality from ProjectHelper has moved into AbstractElement.
Each AbstractElement processes its arguments and elements inside its init()
method.  The Target class overrides the init() method to process the
arguments, but not the elements.  These are not created and init()ed until
execution time.  Any other element, like the example ForEach task, can
override init() to achieve a similar effect and execute each child as they
are init()ed.

Thoughts, comments?

\x/ill          :-}

interface ANTElement {
    /**
     * Initialize this ANT element from a DOM Element.
     */
    void init(Project prj, ANTElement parent, Element elt);
}

interface TextElement {
    void addText(String text);
}

abstract class AbstractElement implements ANTElement {

    protected Project project;
    protected ANTElement parent;
    protected Element DOMelement;

    /**
     * Process the element's attributes and use calls to
this.setXxxx(String attr)
     * to set the values.
     */
    protected void processAttributes() {
        // have to implement this
    }

    /**
     * Look for an appropriate this.createXxxx() method.  Call it if one
exists.
     * Then call newElt.init(project, this, elt).
     * @returns the newly created element or null if no createXxxxx()
method exists.
     */
    protected ANTElement processKnownElement(Element elt) {
        // have to implement this
    }

    /**
     * Look for an appropriate taskdef'd ANTElement.  Then look for an
appropriate
     * this.addElement(ANTElt) method.  If one exists call it.
     * Then call newElt.init(project, this, elt).
     * @returns the newly created element
     * @throws BuildException if no appropriate addElement() method exists.
     */
    protected ANTElement processUnknownElement(Element elt) {
        // have to implement this
    }

    /**
     * Process and init any elements we contain.
     */
    protected void processElementsAndText() {
        // for each sub-node
            // if it is text and (this implements TextElement)
            addText(text);
            // if this is an element
            if (processKnownElement(Element elt) == null)
                processUnknownElement(Element elt);
            // throw a build exception if we couldn't handle it
    }

    public void init(Project prj, ANTElement parent, Element elt) {
        project = prj;
        this.parent = parent;
        DOMelement = elt;
        
        processAttributes();
        processElementsAndText();
    }
}

interface Task extends ANTElement {
    void execute();
}

class Target extends AbstractElement implements Task {

    public void init(Project prj, ANTElement parent, Element elt) {
        project = prj;
        this.parent = parent;
        DOMelement = elt;
        
        processAttributes();
        // does not process the elements until execution time
    }
    
    /**
     * Process, init and execute any elements we contain.
     */
    protected void processElementsAndText() {
        // for each sub-node
            // if it is text and (this implements TextElement)
            addText(text);
            // if this is an element
            ANTElement thisElt = processKnownElement(Element elt);
            if (thisElt == null)
                thisElt = processUnknownElement(Element elt);
            if (!(thisElt instanceof Task))
                throw new BuildException("Target can only have Task
elements");
            ((Task)thisElt).execute();
    }

    public void execute() {
        processElementsAndText(); // also executes elements as they are
processed
    }
    
    setDependancies()
    setName()
    ...
}

class ForEach extends AbstractElement implements Task {
    public void init(Project prj, ANTElement parent, Element elt) {
        project = prj;
        this.parent = parent;
        DOMelement = elt;
        
        processAttributes();
        // does not process the elements until execution time
    }
    
    /**
     * Process, init and execute any elements we contain.
     */
    protected void processElementsAndText() {
        // for each sub-node
            // if sub-node is an element
            ANTElement thisElt = processKnownElement(Element elt);
            if (thisElt == null)
                thisElt = processUnknownElement(Element elt);
            if (!(thisElt instanceof Task))
                throw new BuildException("ForEach can only have Task
Elements");
            ((Task)thisElt).execute();
    }

    public void execute() {
        // for each property setting
            // set the properties appropriatly
            processElementsAndText(); // also executes elements as they are
processed
    }

    setList()
    setVariable()
    ...
}


Mime
View raw message