View | Details | Raw Unified | Return to bug 40678
Collapse All | Expand All

(-)src/tests/antunit/taskdefs/macrodef-element-test.xml (+41 lines)
Line 0 Link Here
1
<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
2
  <import file="../antunit-base.xml" />
3
4
  <target name="test-simple">
5
    <macrodef name="attrlist">
6
      <sequential>
7
        <attribute name="a"/>
8
        <attribute name="b"/>
9
      </sequential>
10
    </macrodef>
11
    <macrodef name="use-attrlist">
12
      <attrlist/>
13
      <sequential>
14
        <property name="simple-prop" value="@{a}:@{b}"/>
15
      </sequential>
16
    </macrodef>
17
    <use-attrlist a="a" b="B"/>
18
    <au:assertTrue>
19
      <equals arg1="a:B" arg2="${simple-prop}"/>
20
    </au:assertTrue>
21
  </target>
22
23
  <target name="test-path">
24
    <macrodef name="fs-list">
25
      <sequential>
26
        <fileset dir="truncate" includes="*.xml"/>
27
        <fileset dir="exec" includes="*.xml"/>
28
      </sequential>
29
    </macrodef>
30
    <path id="d-path">
31
      <fs-list/>
32
    </path>
33
    <path id="e-path">
34
      <fileset dir="truncate" includes="*.xml"/>
35
      <fileset dir="exec" includes="*.xml"/>
36
    </path>
37
    <au:assertTrue>
38
      <equals arg1="${toString:d-path}" arg2="${toString:e-path}"/>
39
    </au:assertTrue>
40
  </target>
41
</project>
(-)src/main/org/apache/tools/ant/UnknownElement.java (-44 / +64 lines)
Lines 182-201 Link Here
182
            if (getWrapper().getId() != null) {
182
            if (getWrapper().getId() != null) {
183
                this.getOwningTarget().replaceChild(this, (Task) realThing);
183
                this.getOwningTarget().replaceChild(this, (Task) realThing);
184
            }
184
            }
185
       }
185
        }
186
186
187
188
        // configure attributes of the object and it's children. If it is
189
        // a task container, defer the configuration till the task container
190
        // attempts to use the task
191
192
        if (task != null) {
187
        if (task != null) {
193
            task.maybeConfigure();
188
            task.maybeConfigure();
194
        } else {
189
        } else {
195
            getWrapper().maybeConfigure(getProject());
190
            getWrapper().maybeConfigure(getProject());
196
        }
191
        }
197
192
198
        handleChildren(realThing, getWrapper());
193
        handleChildren(realThing, null);
199
    }
194
    }
200
195
201
    /**
196
    /**
Lines 308-313 Link Here
308
        children.add(child);
303
        children.add(child);
309
    }
304
    }
310
305
306
    private void recurHandleChild(
307
        ComponentHelper helper, Object parent, UnknownElement child) {
308
        IntrospectionHelper ih = IntrospectionHelper.getHelper(
309
            getProject(), parent.getClass());
310
311
        if (!ih.supportsReflectElement(getNamespace(), child.getComponentName())
312
            &&!ih.isContainer()
313
            && helper.getDefinition(child.getComponentName()) != null) {
314
            Class componentClass = helper.getComponentClass(
315
                child.getComponentName());
316
            if ((componentClass != null)
317
                && (MacroFragment.class.isAssignableFrom(componentClass))) {
318
                child.maybeConfigure();
319
320
                MacroFragment macroFragment = (MacroFragment) child.realThing;
321
322
                List replaced = macroFragment.getUnknownElements(child);
323
                for (Iterator i = replaced.iterator(); i.hasNext();) {
324
                    recurHandleChild(
325
                        helper, parent, (UnknownElement) i.next());
326
                }
327
                return;
328
            }
329
        }
330
        // not a macro fragment - a "Normal" element
331
        try {
332
            if (!handleChild(
333
                    getNamespace(), ih, parent, child)) {
334
                if (!(parent instanceof TaskContainer)) {
335
                    ih.throwNotSupported(getProject(), parent,
336
                                         child.getTag());
337
                } else {
338
                    // a task container - anything could happen
339
                    // - just add the child to the container
340
                    TaskContainer container = (TaskContainer) parent;
341
                    container.addTask(child);
342
                }
343
            }
344
        } catch (UnsupportedElementException ex) {
345
            throw new BuildException(
346
                getWrapper().getElementTag()
347
                + " doesn't support the nested \"" + ex.getElement()
348
                + "\" element.", ex);
349
        }
350
    }
351
311
    /**
352
    /**
312
     * Creates child elements, creates children of the children
353
     * Creates child elements, creates children of the children
313
     * (recursively), and sets attributes of the child elements.
354
     * (recursively), and sets attributes of the child elements.
Lines 315-364 Link Here
315
     * @param parent The configured object for the parent.
356
     * @param parent The configured object for the parent.
316
     *               Must not be <code>null</code>.
357
     *               Must not be <code>null</code>.
317
     *
358
     *
318
     * @param parentWrapper The wrapper containing child wrappers
359
     * @param notUsed Not used.(kept for BC reasons)
319
     *                      to be configured. Must not be <code>null</code>
320
     *                      if there are any children.
321
     *
360
     *
322
     * @exception BuildException if the children cannot be configured.
361
     * @exception BuildException if the children cannot be configured.
323
     */
362
     */
324
    protected void handleChildren(
363
    protected void handleChildren(
325
        Object parent,
364
        Object parent,
326
        RuntimeConfigurable parentWrapper)
365
        RuntimeConfigurable notUsed)
327
        throws BuildException {
366
        throws BuildException {
367
        if (children == null) {
368
            return;
369
        }
370
371
        ComponentHelper helper = ComponentHelper.getComponentHelper(
372
            getProject());
373
328
        if (parent instanceof TypeAdapter) {
374
        if (parent instanceof TypeAdapter) {
329
            parent = ((TypeAdapter) parent).getProxy();
375
            parent = ((TypeAdapter) parent).getProxy();
330
        }
376
        }
331
377
332
        String parentUri = getNamespace();
378
        for (Iterator i = children.iterator(); i.hasNext();) {
333
        Class parentClass = parent.getClass();
379
            recurHandleChild(helper, parent, (UnknownElement) i.next());
334
        IntrospectionHelper ih = IntrospectionHelper.getHelper(getProject(), parentClass);
335
336
337
        if (children != null) {
338
            Iterator it = children.iterator();
339
            for (int i = 0; it.hasNext(); i++) {
340
                RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
341
                UnknownElement child = (UnknownElement) it.next();
342
                try {
343
                    if (!handleChild(
344
                            parentUri, ih, parent, child, childWrapper)) {
345
                        if (!(parent instanceof TaskContainer)) {
346
                            ih.throwNotSupported(getProject(), parent,
347
                                                 child.getTag());
348
                        } else {
349
                            // a task container - anything could happen - just add the
350
                            // child to the container
351
                            TaskContainer container = (TaskContainer) parent;
352
                            container.addTask(child);
353
                        }
354
                    }
355
                } catch (UnsupportedElementException ex) {
356
                    throw new BuildException(
357
                        parentWrapper.getElementTag()
358
                        + " doesn't support the nested \"" + ex.getElement()
359
                        + "\" element.", ex);
360
                }
361
            }
362
        }
380
        }
363
    }
381
    }
364
382
Lines 535-544 Link Here
535
    private boolean handleChild(
553
    private boolean handleChild(
536
        String parentUri,
554
        String parentUri,
537
        IntrospectionHelper ih,
555
        IntrospectionHelper ih,
538
        Object parent, UnknownElement child,
556
        Object parent, UnknownElement child) {
539
        RuntimeConfigurable childWrapper) {
557
        RuntimeConfigurable childWrapper = child.getWrapper();
558
540
        String childName = ProjectHelper.genComponentName(
559
        String childName = ProjectHelper.genComponentName(
541
            child.getNamespace(), child.getTag());
560
            child.getNamespace(), child.getTag());
561
542
        if (ih.supportsNestedElement(parentUri, childName)) {
562
        if (ih.supportsNestedElement(parentUri, childName)) {
543
            IntrospectionHelper.Creator creator =
563
            IntrospectionHelper.Creator creator =
544
                ih.getElementCreator(
564
                ih.getElementCreator(
Lines 563-569 Link Here
563
                ((ProjectComponent) realChild).setLocation(child.getLocation());
583
                ((ProjectComponent) realChild).setLocation(child.getLocation());
564
            }
584
            }
565
            childWrapper.maybeConfigure(getProject());
585
            childWrapper.maybeConfigure(getProject());
566
            child.handleChildren(realChild, childWrapper);
586
            child.handleChildren(realChild, null);
567
            creator.store();
587
            creator.store();
568
            return true;
588
            return true;
569
        }
589
        }
(-)src/main/org/apache/tools/ant/MacroFragment.java (+34 lines)
Line 0 Link Here
1
/*
2
 *  Licensed to the Apache Software Foundation (ASF) under one or more
3
 *  contributor license agreements.  See the NOTICE file distributed with
4
 *  this work for additional information regarding copyright ownership.
5
 *  The ASF licenses this file to You under the Apache License, Version 2.0
6
 *  (the "License"); you may not use this file except in compliance with
7
 *  the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 *  Unless required by applicable law or agreed to in writing, software
12
 *  distributed under the License is distributed on an "AS IS" BASIS,
13
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 *  See the License for the specific language governing permissions and
15
 *  limitations under the License.
16
 *
17
 */
18
19
package org.apache.tools.ant;
20
21
import java.util.List;
22
23
/**
24
 * An interface for a task/type that can be used to
25
 * inject a list of unknown elements into a build file.
26
 */
27
public interface MacroFragment {
28
    /**
29
     * Convert the unknown element into a list of ues.
30
     * @param el the unknown element to convert.
31
     * @return the list of unknown elements.
32
     */
33
    List getUnknownElements(UnknownElement el);
34
}
(-)src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (-27 / +65 lines)
Lines 32-37 Link Here
32
import org.apache.tools.ant.BuildException;
32
import org.apache.tools.ant.BuildException;
33
import org.apache.tools.ant.DynamicAttribute;
33
import org.apache.tools.ant.DynamicAttribute;
34
import org.apache.tools.ant.ProjectHelper;
34
import org.apache.tools.ant.ProjectHelper;
35
import org.apache.tools.ant.MacroFragment;
35
import org.apache.tools.ant.RuntimeConfigurable;
36
import org.apache.tools.ant.RuntimeConfigurable;
36
import org.apache.tools.ant.Target;
37
import org.apache.tools.ant.Target;
37
import org.apache.tools.ant.Task;
38
import org.apache.tools.ant.Task;
Lines 45-51 Link Here
45
 * the parameter values in attributes and text.
46
 * the parameter values in attributes and text.
46
 * @since Ant 1.6
47
 * @since Ant 1.6
47
 */
48
 */
48
public class MacroInstance extends Task implements DynamicAttribute, TaskContainer {
49
public class MacroInstance extends Task
50
    implements DynamicAttribute, TaskContainer, MacroFragment {
49
    private MacroDef macroDef;
51
    private MacroDef macroDef;
50
    private Map      map = new HashMap();
52
    private Map      map = new HashMap();
51
    private Map      nsElements = null;
53
    private Map      nsElements = null;
Lines 72-77 Link Here
72
    }
74
    }
73
75
74
    /**
76
    /**
77
     * Get the unknown elements to inject into the build document.
78
     * @param el the unknown element this is this fragment.
79
     * @return the replacement list of unknown elements.
80
     */
81
    public List getUnknownElements(UnknownElement el) {
82
        try {
83
            doParams();
84
            return copy(getMacroDef().getNestedTask(), false).getChildren();
85
        } finally {
86
            clearParams();
87
        }
88
    }
89
90
    /**
75
     * A parameter name value pair as a xml attribute.
91
     * A parameter name value pair as a xml attribute.
76
     *
92
     *
77
     * @param name the name of the attribute
93
     * @param name the name of the attribute
Lines 93-113 Link Here
93
    }
109
    }
94
110
95
    private Map getNsElements() {
111
    private Map getNsElements() {
96
        if (nsElements == null) {
112
        return nsElements;
97
            nsElements = new HashMap();
113
    }
98
            for (Iterator i = macroDef.getElements().entrySet().iterator();
114
99
                 i.hasNext();) {
115
    private void doNsElements() {
100
                Map.Entry entry = (Map.Entry) i.next();
116
        nsElements = new HashMap();
101
                nsElements.put((String) entry.getKey(),
117
        for (Iterator i = macroDef.getElements().entrySet().iterator();
102
                               entry.getValue());
118
             i.hasNext();) {
103
                MacroDef.TemplateElement te = (MacroDef.TemplateElement)
119
            Map.Entry entry = (Map.Entry) i.next();
104
                    entry.getValue();
120
            nsElements.put((String) entry.getKey(),
105
                if (te.isImplicit()) {
121
                           entry.getValue());
106
                    implicitTag = te.getName();
122
            MacroDef.TemplateElement te = (MacroDef.TemplateElement)
107
                }
123
                entry.getValue();
124
            if (te.isImplicit()) {
125
                implicitTag = te.getName();
108
            }
126
            }
109
        }
127
        }
110
        return nsElements;
111
    }
128
    }
112
129
113
    /**
130
    /**
Lines 119-125 Link Here
119
        unknownElements.add(nestedTask);
136
        unknownElements.add(nestedTask);
120
    }
137
    }
121
138
122
    private void processTasks() {
139
    /**
140
     * process the nested elements of this macro instance.
141
     * Ensure that the correspond to the elements definitions
142
     * in the macrodef.
143
     * If the there is one nested elemtent of implicit type, then
144
     * there is no processsing.
145
     */
146
    private void processNestedElements() {
123
        if (implicitTag != null) {
147
        if (implicitTag != null) {
124
            return;
148
            return;
125
        }
149
        }
Lines 242-248 Link Here
242
        this.text = text;
266
        this.text = text;
243
    }
267
    }
244
268
245
    private UnknownElement copy(UnknownElement ue, boolean nested) {
269
    /**
270
     * Copy an unknown element, substituting in macro attributes.
271
     * @param ue the unknown element to replace.
272
     * @return the copied unknown element.
273
     */
274
    private  UnknownElement copy(UnknownElement ue, boolean nested) {
246
        UnknownElement ret = new UnknownElement(ue.getTag());
275
        UnknownElement ret = new UnknownElement(ue.getTag());
247
        ret.setNamespace(ue.getNamespace());
276
        ret.setNamespace(ue.getNamespace());
248
        ret.setProject(getProject());
277
        ret.setProject(getProject());
Lines 329-344 Link Here
329
        return ret;
358
        return ret;
330
    }
359
    }
331
360
332
    /**
361
    /** setup parameters */
333
     * Execute the templates instance.
362
    private void doParams() {
334
     * Copies the unknown element, substitutes the attributes,
335
     * and calls perform on the unknown element.
336
     *
337
     */
338
    public void execute() {
339
        presentElements = new HashMap();
363
        presentElements = new HashMap();
340
        getNsElements();
364
        doNsElements();
341
        processTasks();
365
        processNestedElements();
342
        localAttributes = new Hashtable();
366
        localAttributes = new Hashtable();
343
        Set copyKeys = new HashSet(map.keySet());
367
        Set copyKeys = new HashSet(map.keySet());
344
        for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) {
368
        for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) {
Lines 386-392 Link Here
386
                "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ")
410
                "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ")
387
                + copyKeys);
411
                + copyKeys);
388
        }
412
        }
413
    }
389
414
415
    /** Clear the parameters */
416
    private void clearParams() {
417
        presentElements = null;
418
        localAttributes = null;
419
    }
420
421
    /**
422
     * Execute the templates instance.
423
     * Copies the unknown element, substitutes the attributes,
424
     * and calls perform on the unknown element.
425
     *
426
     */
427
    public void execute() {
428
        doParams();
390
        // need to set the project on unknown element
429
        // need to set the project on unknown element
391
        UnknownElement c = copy(macroDef.getNestedTask(), false);
430
        UnknownElement c = copy(macroDef.getNestedTask(), false);
392
        c.init();
431
        c.init();
Lines 401-408 Link Here
401
                throw ex;
440
                throw ex;
402
            }
441
            }
403
        } finally {
442
        } finally {
404
            presentElements = null;
443
            clearParams();
405
            localAttributes = null;
406
        }
444
        }
407
    }
445
    }
408
}
446
}
(-)src/etc/checkstyle/checkstyle-config (-3 / +3 lines)
Lines 80-87 Link Here
80
    <module name="IllegalInstantiation">
80
    <module name="IllegalInstantiation">
81
      <property name="classes" value="java.lang.Boolean"/>
81
      <property name="classes" value="java.lang.Boolean"/>
82
    </module>
82
    </module>
83
    <module name="InnerAssignment"/>
83
    <!-- <module name="InnerAssignment"/> -->
84
    <module name="MagicNumber"/>
84
    <!-- <module name="MagicNumber"/>-->
85
    <module name="MissingSwitchDefault"/>
85
    <module name="MissingSwitchDefault"/>
86
    <!-- Allow redundant throw declarations for doc purposes 
86
    <!-- Allow redundant throw declarations for doc purposes 
87
    <module name="RedundantThrows">
87
    <module name="RedundantThrows">
Lines 104-110 Link Here
104
      <property name="format" value="\s+$"/>
104
      <property name="format" value="\s+$"/>
105
      <property name="message" value="Line has trailing spaces."/>
105
      <property name="message" value="Line has trailing spaces."/>
106
    </module>
106
    </module>
107
    <module name="TodoComment"/>
107
    <!-- <module name="TodoComment"/> -->
108
    <module name="UpperEll"/>
108
    <module name="UpperEll"/>
109
    <!-- allow comment suppression of checks -->
109
    <!-- allow comment suppression of checks -->
110
    <module name="FileContentsHolder"/>
110
    <module name="FileContentsHolder"/>
(-)docs/manual/CoreTasks/macrodef.html (-13 / +50 lines)
Lines 27-46 Link Here
27
    <h2><a name="macrodef">MacroDef</a></h2>
27
    <h2><a name="macrodef">MacroDef</a></h2>
28
    <h3>Description</h3>
28
    <h3>Description</h3>
29
    <p>
29
    <p>
30
      This defines a new task using a <code>&lt;sequential&gt;</code>
30
      <em>Since Ant 1.6.</em> <br />
31
      nested task as a template. Nested elements <code>&lt;attribute&gt;</code> and
31
      This defines a new element that may be used to replace a sequence
32
      <code>&lt;element&gt;</code> are used to specify attributes and elements of
32
      of elements and thus allow reuse of the elements in other
33
      the new task. These get substituted into the <code>&lt;sequential&gt;</code>
33
      parts of the build document.
34
      task when the new task is run.
34
35
      This defines a new element tag using a <code>&lt;sequential&gt;</code>
36
      nested task as a template.
37
      Nested elements <code>&lt;attribute&gt;</code> and
38
      <code>&lt;element&gt;</code> are used to specify attributes
39
      and elements of the new task. These get substituted into the
40
      <code>&lt;sequential&gt;</code>
41
      task when the new element tag is evalulated.
35
    </p>
42
    </p>
36
    <h3>Note</h3>
43
    <table border="0" width="100%">
37
    <p>
44
      <tr/>
38
      You can also use <i>prior defined</i> attributes for default-values in
45
      <tr>
39
      other attributes. See the examples.
46
        <td style="background-color:white" valign="top"><b>Note:</b></td>
40
    </p>
47
        <td style="background-color:white" valign="top">
41
    <p>
48
          You can also use <i>prior defined</i> attributes for default-values
42
      <em>since Ant 1.6</em>
49
          in other attributes. See the examples.
43
    </p>
50
        </td>
51
      </tr>
52
      <tr>
53
        <td style="background-color:white" valign="top"><b>Note:</b></td>
54
        <td style="background-color:white" valign="top">
55
          Since <em>Ant 1.8</em>, macrodef defined elements can replace
56
          arbitary nested elements and not just tasks.
57
        </td>
58
      </tr>
59
    </table>
60
44
    <h3>Parameters</h3>
61
    <h3>Parameters</h3>
45
    <table border="1" cellpadding="2" cellspacing="0">
62
    <table border="1" cellpadding="2" cellspacing="0">
46
      <tr>
63
      <tr>
Lines 370-376 Link Here
370
&lt;test one="test"/&gt;
387
&lt;test one="test"/&gt;
371
</pre>
388
</pre>
372
    </blockquote>
389
    </blockquote>
390
    <p>
391
      The following defines two filesets and then places them in
392
      two different copy tasks.
393
    </p>
394
    <blockquote>
395
<pre class=code>
396
&lt;macrodef name="sourcefiles"&gt;
397
   &lt;sequential&gt;
398
     &lt;fileset dir="src/main/java" includes="**/*.java"&gt;
399
     &lt;fileset dir="src/main/resources"/&gt;
400
   &lt;/sequential&gt;
401
&lt;/macrodef&gt;
373
402
403
&lt;copy todir="allsource"&gt;
404
   &lt;sourcefiles/&gt;
405
&lt;/copy&gt;
374
406
407
&lt;m:remote-copy remotedir="wr0t@billy:backups"&gt;
408
   &lt;sourcefiles/&gt;
409
&lt;/m:remote-copy&gt;
410
</pre>
411
    </blockquote>
375
</body>
412
</body>
376
</html>
413
</html>

Return to bug 40678