<?xml version="1.0"?>
<document>

    <properties>
        <title>On Task Configuring in Ant2</title>
        <author email="peter@apache.org">Peter Donald</author>
    </properties>

    <body>

        <section name="Introduction">
            <p>This section will describe in detail the mechanism via which tasks are
            configured. Configuration is the name given to the stage in tasks
            lifecycle via which the XML representation is mapped onto the task 
            object.</p>
        </section>

        <section name="Names">

            <p>When mapping the XML representation on to the task object you
            need to be able map the names as they appear in the XML to the 
            names as they appear in the Java code. The process is for generating
            a java name from the xml name is as follows.</p>
            <ol>
              <li>Capitalize the first character of name.</li>
              <li>Find any '-' characters in XML name and remove character and
              capitalize the following letter. (And there must be a following 
              letter)</li>
            </ol>
            <p>Some example mappings;</p>
            <source>
my-name    ===&gt;   MyName
aString    ===&gt;   AString
Basedir    ===&gt;   Basedir
baseDir    ===&gt;   BaseDir
url        ===&gt;   Url</source>
            <p>Note that the above transformation is lossy and as such the 
            following XML names all map to the same Java name. The ant1.x mapping 
            is similarly lossy and in practice this has not been an issue.</p>
            <source>
base-dir   ===&gt;   BaseDir
Base-dir   ===&gt;   BaseDir
baseDir    ===&gt;   BaseDir
BaseDir    ===&gt;   BaseDir</source>
            <p><i>NOTE: We should really resolve this and either disallow '-' characters 
            or disallow uppercase or something. (PD)</i></p>
        </section>

        <section name="Resolving Values">
            <p>The first stage of mapping the XML representation to the task
            is resolving all text data. The text data that needs to be resolved 
            include the values of attributes and the content.</p>
            <p>Resolution consists of expanding any property references in the text
            data. Property references are identified as starting with the token 
            &quot;${&quot; and finishing with another &quot;}&quot; token. The text 
            in between is the name of a property. The value of the property replaces
            the sequence of text starting with the &quot;${&quot; token and finishing 
            with the &quot;}&quot; token.</p>
            <p>Note that the value of the property may not be a string. If the text data
            contains text (or other property references) to either side of the property
            reference then it must be <a href="converter.html">converted</a> to a 
            String.</p>
        </section>

        <section name="Modeller">
            <p>Currently the representation of object are stored in a hierarchial 
            tree of <code>org.apache.myrmidon.api.metadata.ModelElement</code>
            objects. Each ModelElement has a number of attributes and can have
            either content or sub-elements.</p>
            <p>In most cases it is the responsibility of the runtime to map 
            the ModelElement onto an object. However in some cases it may be useful 
            for the object to get access to it's own model and for it to explicitly
            manage it's own configuration. In this case the object should implement
            the <code>org.apache.myrmidon.api.metadata.Modeller</code> interface
            which will provide the mechanism for the object to receive its own 
            representation and configure itself.</p>
            <p>Note that the Modeller mechanism should be avoided if possible
            as it adds considerable complexity to the implementing object.</p>
        </section>

        <section name="Attributes">
            <p>To map an XML attribute on to a Java object, the name of the 
            attribute is mapped to a java name and prefixed with the string
            &quot;set&quot;. The resulting string is then used to look up a 
            method with a single parameter.</p>
            <p>For example, for the attribute &quot;world&quot; would result
            in a lookup of a method named &quot;setWorld&quot; with a single
            parameter.</p>
            <p>If multiple methods were matched during the lookup then an 
            exception is thrown indicating ambiguity. Theres is an exception
            to this rule that allows 2 methods to be matched if one of the 
            methods takes a <code>java.lang.String</code> parameter. The method
            that has the <code>java.lang.String</code> parameter is ignored and 
            the other method would be chosen. This exception is allowed as it is 
            common practice for a task to evolve from String parameters to more 
            strongly typed parameters.</p>
            <p>The resolved text data of the attribute must be 
            <a href="converter.html">converted</a> to the type of the matched 
            methods parameter. For example, if the &quot;setWorld&quot; method
            took a parameter of type <code>java.io.File</code> then the resolved
            text data must be converted into a <code>java.io.File</code>. The
            conversion is done by the Converter architecture that is more fully 
            described in the <a href="converter.html">Converter HOWTO</a>.</p>
            <p>After the value is converted to the correct type the method is 
            invoked with the converted value.</p>
        </section>

        <section name="Content">
            <p>The XML representation of object can have either have nested
            elements or nested text (content) but not both. To add the content
            to an object a method named "content" with one parameter is looked 
            up. The resolved text data for content is then 
            <a href="converter.html">converted</a> to the type of the parameter
            and passed in via the method.</p>
        </section>

        <section name="Element">
            <p>Mapping an ModelElement onto a java object is a series of steps.
            If the ModelElement name ends with the string &quot;-ref&quot; then 
            it is treated as a reference element - see the <em>Referrenced 
            Elements</em> section. Otherwise, the element is first attempted to 
            be mapped as a <em>Named Element</em> and if no match is found via 
            that method it tries to treat the element as a <em>Typed Element</em>.</p>
        <subsection name="Named Elements">
            <p>To map a named ModelElement on to a Java object, the name of 
            the element is mapped to a java name and prefixed with the string
            &quot;add&quot;. The resulting string is then used to look up a 
            method with a single parameter.</p>

            <p>For example, for the attribute &quot;geometry&quot; would result
            in a lookup of a method named &quot;addGeometry&quot; with a single
            parameter. If multiple methods were matched during the lookup then an 
            exception is thrown indicating ambiguity. If no methods were found that
            match name then skip down to configuring &quot;typed&quot; elements.</p>

            <p>The type of the methods single parameter is then examined to determine
            what happens next. There are two valid situations, if neither of these are 
            satisfied, then an exception is thrown.</p>
            <ul>
              <li>The parameters type is <code>org.apache.myrmidon.api.metadata.ModelElement</code></li>
              <li>The parameters type is a concrete class</li>
            </ul>
            <p>1. If the parameter has a type of <code>org.apache.myrmidon.api.metadata.ModelElement</code>
            then the un-modified model representation of element is passed to object by invoking
            the adder method.</p>
            <p>2. If the parameters type is concrete then an instance of the parameter is 
            instantiated using the default constructor. This created object is then configured 
            in the same manner as task using the elements representation as the model. After
            the object is configured it is passed into object by invoking the adder method.</p>
        </subsection>
        <subsection name="Referrenced Elements">
            <p>A referenced element is one that has a name ending in 
            &quot;-ref&quot; and has a single attribute &quot;name&quot;
            and no content or child elements.</p>

            <p>The value of the &quot;name&quot; attribute is the name of a property. 
            The value of this property is retrieved from the TaskContext.</p>

            <p>Like with <em>Named Elements</em> the name of the element (minus
            the &quot;-ref&quot; part) is mapped to a java name and prefixed with the string
            &quot;add&quot;. The resulting string is then used to look up a 
            method with a single parameter. If multiple methods were matched during the lookup then an 
            exception is thrown indicating ambiguity.</p>

            <p>The value retrieved from the TaskContext is then converted to the type 
            of the methods parameter and the add method is invoked with the converted value.</p>
            
            <p>An example usage is the following;</p>
            <source><![CDATA[

            <my-task ...>
              <classpath-ref name="project.class.path"/>
            </my-task>

]]></source>
        </subsection>
        <subsection name="Typed Elements">
            <p>&quot;Typed&quot; elements can also be added to an object. A typed element 
            is one in which the name of the element actually refers to a type rather than the 
            name of the adder to call.</p>
            <p>For example, you may wish to allow a task to add arbitrary instances of the 
            Condition role to a task. So instead of adding methods such as 
            <code>addAnd(AndCondition)</code>, <code>addOr(OrCondition)</code> and
            <code>addXor(XorCondition)</code> you can instead add a single method 
            <code>add(Condition)</code>. This vastly simplifies the amount of work required
            to write tasks that take conditions. More importantly it allows end-users to 
            extend the number of elements selected by task. For instance if the user wanted
            a &quot;nand&quot; condition they could write the Nand type use it in their build
            file. For a discussion on roles and types see the <a href="types.html">Types
            HOWTO</a>.</p>
            <p>To use a Typed adder there must be a single method named &quot;add&quot; that
            has a single parameter. The parameter <em>MUST</em> be an abstract interface and
            must be registered as a role. The name of the element is then used to lookup the
            a type in the TypeManager with a role matching the interface name.</p>

            <p>For example if an element named &quot;nand&quot; was added to an object that had 
            an adder with the signature <code>void add( Condition condition )</code> then 
            the type named &quot;nand&quot; in the role &quot;Condition&quot; would be looked up.
            An instance of the type would then be created using the default constructor and the
            created object would be configured and then adder to object using adder.</p>

        </subsection>
        </section>
    </body>
</document>
