ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Adam Murdoch" <adammurdoch...@yahoo.com>
Subject RE: [PATCH] myrmidon task configurer
Date Sun, 30 Dec 2001 14:19:37 GMT


> From: Peter Donald [mailto:peter@apache.org]
> 
> > * Allow an object (task or data type) to override parts of its
> > configuration process.
> >
> > This would be an alternative to implementing Configurable 
> (which requires
> > the object to deal with configuring itself entirely).
> 
> It should be possible for a task or any object to only have it's 
> subelements 
> Configurable and where that is not the case there will be a base utility 
> class (see AbstractTaskContainer) to help do the configuring. 
> This utility 
> class will allow the task to call back into the configurer to do the 
> configuring. AbstractTaskContainer is not real easy atm but it 
> sort of shows 
> what I was aiming at. 
> 
> WOuld this be enough for you ?
> 

Not quite.  You certainly *could* do this with Configurable - the issue is that it's an all
or nothing approach.  If an object (task or data type) implements Configurable, then it has
to take care of configuring itself, and all its nested objects.  It also needs to take care
of resolving properties and doing type conversions (and presumably the new stuff like reference
handling and polymorphism).  Granted, using AbstractTaskContainer makes it easier to do this
if the object in question happens to be a task.  Not much good for a nested type, however.

What I'd like to do is provide a mechanism where a class can modify its introspector, without
needing to implement Configurable (and hence Composable and Contexualizable).

E.g:

public class SomeDataType extends AbstractDataType
{
  /** @deprecated Needed for backwards compatibility - use {@link #setSomeAttr(File)} instead.
*/
  public void setSomeAttr(String value) { ... }

  public void setSomeAttr(File value) { ... }

  /** Returns the configurer to use for this class. */
  public static ObjectConfigurer getConfigurer()
  {
      DefaultObjectConfigurer configurer = new DefaultConfigurer(SomeDataType.class);

      // Force the introspector to use the File setter method for "some-attr"
      configurer.enableAttribute("some-attr", File.class);

      return configurer;
  }
}

> > The plan is to allow a class to provide a customised introspector (an
> > ObjectConfigurer) via a static method - getConfigurer(), say.  
> This would
> > allow a class to do simple things like:
> >
> >   - Explicitly choose an overloaded setter/adder/creator method 
> to use when
> > there's more than one.
> >   - Ignore certain setter/adder/creator methods.
> >   - Map text content to a particular attribute (e.g. "message" 
> in the <log>
> > task).
> 
> I think all of the above should be done via some sort of TaskInfo object.
> 

Absolutely.

TaskInfo seemed a bit too far off, and the introspector was somewhere to deal with this kind
of stuff in the meantime.  Thinking about it some more, maybe starting on TaskInfo might be
a better thing to do.

> >   - Deal with attributes or elements whose names are only known 
> at runtime
> > (e.g. compiler adaptors).
> 
> This is something that still needs to be figured out. Hopefully the above 
> utility class would be enough to make this easy.
> 

Moving towards a polymorphic, type-based set-up will reduce the need for this kind of stuff.
 Maybe at that point we could simply say that there's no such thing as an "unknown" attribute
or element.

> > * Deal with references.
> >
> > Have the configurer resolve (and type check) references to data types,
> > rather than forcing the object do it.  An adder method would be 
> passed an
> > object, and whether that object was obtained by reference, or 
> created and
> > configured inline, the parent object doesn't know or care.
> 
> +10000
> 
> The two ways I proposed for doing this were basically recognizing 
> some magic 
> constructs. 
> 
> One construct would be that any element/attribute name that ended 
> with "-ref" 
> would have the "-ref" part removed and the normal attribute/element 
> configuration process would proceed except that it would use the 
> reference.
> 
> The other constrct is just recognizing the case where an element has one 
> attribute named refid and treat it specially.
> 
> I favour the first method as it deals with attributes and elements and is 
> generally easier IMHO but the second method is more standard to 
> our current 
> approach. 
> 
> What do you think?
> 

Not entirely clear on how elements are handled in the first method.  Want to expand on it
a bit?

> > This raises the issue of ownership, and immutability - maybe a 
> clone gets
> > passed to the adder methods.
> 
> Hmmm .. haven't really though much about this but to fit in with 
> the rest of 
> the model you probably should not be passing a clone...
> 

Depends what the model says about whether shared objects can be changed by the objects that
use them.  A good model would say that they can't be, an evil model would say that they can
be.

Cloning was just a thought of how we might enforce that - give each object its own private
copy, and isolate them from side effects.  Alternatively, we could just say "well, don't change
shared stuff, please", or we could stick to immutable data types, or we could not bother.

> > * Polymorphic types.
> >
> > This was raised a few months ago and it is truely an excellent 
> idea.  This
> > would allow the configurer to pass an adder method, an object 
> of any class
> > that is assignable to the declared type.  As Peter pointed out, 
> this would
> > neatly solve the adaptor problem that is being discussed.
> 
> +1
> 

I'm wondering how we would represent this in the build file?

Some options:

<javac>
   <compiler type="jikes" .. config .. />
</javac>

<javac>
   <compiler>
       <jikes .. config .. />
   <compiler/>
</javac>

<javac>
   <jikes .. config .. />
</javac>

The 3rd option won't work if there's more than one element that can take a "jikes" data type.
 Maybe we use the 1st option, and allow the 3rd one if its unambiguous.

> > * Lifecycle management.
> >
> > It would be handy if the lifecycle of nested objects was handled by the
> > container, rather than forcing the parent object to do it.  Not the
> > configurer's job, necessarily.
> 
> Can you give a use case for this?
> 

Logging would be the main one - say I want to do logging in some deeply nested obect, I need
to have something pass me a Logger.  Ideally, my object would simply implement LogEnabled,
and the container would supply the object with a Logger as part of its "initialisation". 
The alternative would be for the object's parent to supply the logger - this would be bad,
as it would force the parent to be LogEnabled.

Note: "container" == Ant, "object's parent" == every data type or task that recursively includes
the nested object, written by a bunch of different task developers.

It's possible that a data type might need other components, or the task context, to do its
work.  Again, having the container supply these would be a good thing.


Adam


--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message