Interesting... So how come DynamicTag is not compatible with Ant 1.6, when
it compiles and works fine with 1.5.1??? Sounds like an incompatible API
change to me, which hopefully will be fixed.

I have a few remarks:

1) I favor composition over inheritance. DynamicTag is designed to be
composed, either directly, or has a helper (my latest email). But your
implementation could easily be refactored a bit to also favor composition
instead of inheritance.
2) DynamicTag is lazy, thanks to UnknownElement. Your rewrite is creating
the element at parse-time, my implementation does it only at runtime. Again,
I favor delaying the instantiation and configuration. Ant should never have
mingled parsing of the XML and instantiation of the model in the first
place.
3) I'm not sure what your point #2 would not be addresses by DynamicTag.
Thanks to UnknownElement, all nested elements of a DynamicTag are resolved
according to the same exact semantic as everything in Ant. I much prefer to
rely on Ant's (much convoluted black-box) existing mechanism than invent my
own, partly because I didn't want to go into reflection (I'm a bit adverse
to it), and partly because it makes it more difficult to be adopted by Ant.
4) DynamicTag enforces the cardinality of the nested dynamic elements for
free. That's a nice goodie, but granted, more sugar than real useful.
5) Your point #4 is the new feature over DynamicTag as I understand it. I'm
not too sure it's better syntactically than explicitly having (composing)
several nested elements, each being a dynamic tag of a different type. Your
rewrite does add new reflection 'rules', making stuff happen auto-magically
thru reflection. I'm not saying it's bad, I'm pointing out it adds some,
when DynamicTag doesn't.

All that said, you achieve a similar effect, which is what I really care
about. If Ant wants to implement this feature still a third way, I'll all
for it, provided the feature is available. At least now there are two
proposals for it ;-)

Something that I wish Ant added was the notion of 'role', to partition the
task/type namespace. Both our proposals rely on <taskdef>/<typedef> to
register the extension points. But a custom selector, a custom filter, a
custom mapper, a custom buildpath (in my case) all share the same type or
task namespace (the mapping from element name to class name). There are
currently two distinct namespaces, one for tasks, and one for types, and
Costin says I'd like to merge the two, when I actually would prefer to have
N namespaces, each indexed/keyed by a 'role' string. When a task explicitly
declares to accept within it selectors for example, it simply declares it
wants instances implementing FileSelector.class from the "selectors"
namespace. So the namespace used to resolve the element name to the
classname is explicit, rather than implicit, first trying the "tasks"
namespace, and then trying the "types" namespace. Classes can of course
belong to more than one namespace; <tahoeresolver> could be both a type
("types" namespace), so it can be declared outside <buildpath> and refid'd,
but it's also a BuildPathResolver.class, of the "buildpath/resolvers"
user-defined (and documented) namespace).

I believe one (or both) of the Ant2 proposals had the notion of role, and
it's also well defined in Avalon Phoenix, so this is nothing new indeed.

Thanks Peter for your interest in this area. I hope others will also look
into it. Cheers, --DD


-----Original Message-----
From: peter reilly [mailto:[EMAIL PROTECTED] 
Sent: Monday, April 14, 2003 6:50 PM
To: [EMAIL PROTECTED]
Subject: RE: DynamicTag

Hi, I am on holidays, but have followed
this thread.

I have been playing with DynamicTag and it is
quite neat, but there are some issues with it..
I have made some modifications (well rewrite...)

1) DynamicTag uses UnknownElement. This part of ant code is
   undergoing a number of changes at the moment, and currently
   DynamicTag does not work with cvs ant.

   I extracted the stuff that unknownelement does and placed
   them in a method, this is compatible with apr12 ant cvs and with
   ant 1.5.x (tested with 1.5.2).

2) I would like to have dynamic tag behavior on the the current
   task as well as nested elements.

3) I would like to use reflection in the same way as ant uses
   reflection for setters and creators.

4) I would like to support multiple dynamic types in the same class.

I initially considered using only datatypes, but on consideration
it does make sense to have tasks as well. The problems with this
are:
   a) tasks that do not extend ant.task get wrapped by ant.taskadapter
      which may not be what is expected
   b) tasks have a more complex life cycle that datatypes (init,
      perform, execute methods)

Attached are two files : DynamicElementHelper and DynamicElementTask.

Tasks and Datatypes/Sub-elements extend DynamicElementTask. 
The signature dynamicElement(Type) is used to indicate the type that
this method will handle.
DynamicElementTask implements DynamicConfigurator, and calls
DynamicElementHelper, which looks up the tag name in the
projects tasks and datatypes, if found that, the method
uses reflection to see if the calling object has a matching
dynamicElement method for the type.

DynamicElementHelper is written so that if this idea
is considered useful, it can be used by IntrospectionHelper,
It that case, there would be no need for DynamicElementTask.


To do the original example:
    <buildpath id="tahoebuildpath">
        <tahoeresolver destdir="${destdir}"
                  dependencies="${dependencies}" 
    </buildpath>

BuildPath.java extends DynamicElementTask and adds a dynamic element
handler:

  // Creates a nested resolver
  public void dynamicElement(BuildPathResolver resolver) {
     if (this.resolver != null)
         throw new BuildException("resolver already defined");
     this.resolver = resolver;
  }

And the xml filters:

<target name="test" depends="-init" >
   <xmlchain toDir="./build/chain" extension=".xxx">
     <fileset refid="workOnStuf" />
     <filter1 attr1="v1" attr2="v2">
       <mysubelement .../>
     </filter1>
     <xincludefilter .../>
     <xmlfilter refid="other-filter"/>
   </xmlchain>
</target>

and in xml chain:

public void dynamicElement(XmlFilter filter) {
    filters.addElement(filter)
}

One may also nest the custom filters in the same way as
dynamictag by writing a new class 

public class CustomFilters extends DynamicElementTask {
   private Vector filters = new Vector();
   public void dynamicElement(XmlFilter filter) {
      filters.addElement(filter);
   }
   public Vector getFilters() { return filters;}
}

and in XmlChain:
  public void addCustomFilters(CustomFilters customFilters) {
    this.customFilters = customFilters;
  }

Cheers,

Peter

Dominique Devienne wrote:
>>Two comments:

>>1) DynamicTag is fully Ant 1.5.x compatible. No need for 1.6. Just use
it
>>along side your own classes, and you're good to go.

>>2) DynamicTag *relies* on <taskdef> or <typedef> (you can declare your
>>custom extension either way), which takes care of all the
classloading,
>>already has all the special stuff like loaderref. Any enhancement to
these
>>tasks automatically benefit DynamicTag.


Reply via email to