ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Jose Alberto Fernandez" <jalbe...@cellectivity.com>
Subject RE: Roles (was: antlib)
Date Mon, 28 Apr 2003 13:37:37 GMT
> From: Costin Manolache [mailto:cmanolache@yahoo.com]
> 
> Jose Alberto Fernandez wrote:
> 
> > What does it all mean? It means we can now write a task, 
> well typed, which
> > can be accept different XML subelements depending on the 
> declarations of
> > other objects present on the build. The vendor specific elements of
> > <ejbjar>, <jspc> and others are typical examples of where 
> this capability
> > can be very useful. Other parts of core could benefit of course.
> 
> Let me see if I understand corectly what you want. 
> 
> You'll have a task TaskA, with a method "addRoleB". 
> And in XML:
> 
>   <taskA ...>
>      <implementationB1 >
>   </taskA>
> 
> TaskA doesn't know anything about the implementation - it 
> will only use an
> interface ( or base class ) "RoleB" as parameter.
>  
> 
> I assume you will need some way to associate the tag 
> <implementationB1> with 
> a particular class - and this can be very well be done currently with 
> <taskdef> or <typedef> ( or with the new "role" declaration 
> if you want ).

The declaration of the class for <implementationB1> as a member of the
role is what you do equivalent to <taskdef> or <typedef>.

> In any case, all you really need is the tag name and the 
> class name - the
> roles will be available as interfaces or superclasses. 
> Nothing special for
> this association.
> 

No. If you do it this way it would mean that you cannot expose diferent names
for the same class depending on the role. It will also mean that thing that
just happen to implement a role (just because of some inheritance) will be
made available even though it makes little sense doing so. Ex. <if>.

<if> is a task. It makes little sense to allow it as a condition,
 but because it is implemented by subclassing ConditionBase
which would implement the role for conditions, it would mean you will
declare it in the condition role. (This seems wrong in principle).

Secondly, since classes do not need to implement the interface but
may be adapted, you cannot assume much there either.

> The second part is making IntrospectionHelper recognize  a child that
> doesn't fit the current patterns ( i.e. no addImplementationB1 ), and
> instead of reporting an error look up the child by the name 
> and create the
> type, then check the interfaces implemented by the class and 
> see if any
> method in the parent matches. 
> 
> Is there anything else ?
> 

You can only check for those interfaces where the class was registered
to use that element name (you cannot blindly look at all possible
interfaces).

> 
> > 2) What do they do that is no possible in ANT:
> > 
> > They allow IntrospectionHelper to connect an XML subelement 
> eventhough
> > introspection cannot find a create or add/Configured method for it.
> > It is a well typed methanism, the parent object will only be passed
> > objects that it knows how to deal with. And the parent 
> object does not
> > need to have any knowledge of what currently available 
> members are on the
> > role.
> 
> Yes, parent needs one addXXX method with a typed parameter, 
> and the child 
> needs to be matched against it. 
> 
> 
> What I don't understand is why should we just use the 
> existing typedef and
> just add this new pattern to IntrospectionHelper.
> 

Because the proposal declares on a Role by role basis. There is
no assumption the same name will be used for all roles,
nor that you want to always register all possible roles.

> 
> 
> > Also notice that Roles do not supercede 
> DynamicConfigurator. On one hand
> > roles let external implementations to be considered as possible
> > subelements of a parent object, on the other hand, 
> DynamicConfigurator
> > allows a node to decide given its current state what is the 
> meaning of a
> > particular element. This cannot be done by roles in the 
> general case, and
> > that is good.
> > 
> 
> 
> > Usage of Roles:
> > ==============
> > The principle is very simple:
> > 
> > a) A role is defined by an interface. This interface is the 
> parameter
> > for a new special family of addConfigured(<interface>) methods.
> 
> +1 on role defined by an interface ( or base class - I don't 
> see any reason 
> to restrict it to only interfaces ).
> 

Looks neater :-). But I have no big hangups as long as we can clearly
distinguish between named element add/create methods and the ones for roles.

> I'm not sure a special name is actually required ( 
> addConfigured) - just an
> add or set method with the interface/class as parameter, and 
> then match
> them on type.
> 

the idea of using "addConfigured" as the name in because I think we
need to be clear on the parsing rules for this objects. Allowing
passing not configured objects seem to make little sense since
the implementation is completely blackboxed to the parent node.
Also, "set" methods are for attributes only (has that changed?)
so they do not apply here.

> 
> 
> > b) When IntrospectionHelper fails to find a create/add 
> method for the
> > element, it will look at all the roles used in the addConfigured
> > methods and on each of those roles will try to find an 
> object declared
> > with that element-tag name. If one and only one match is found then
> > the instantiation is successful and the new object will be 
> configured;
> > otherwise it is an error and parsing stops.
> 
> I disagree here. If the role is associated with an interface, 
> then the 
> "declaration" is part of each task/type class. If you 
> implement/extend that
> interface/class - then you have this role. Any extra declaration is
> redundant - unless you want to declare a wrapper ( see below ).
> 

You do not declare a class, you declare what does the element-tag
means. I.e., "in the context of Interface X the name 'implementationB1' means to
use class Y with adaptor Z if necessary".
But "in the context of Interface P the name 'implementationB1' means to
use class Q with adaptor R if necessary".

> 
> > c) The configured object may or may not implement the Role 
> interface,
> > if it does not, an Adaptor object may be instantiated as a proxy
> > for the object. Which adaptor is used depends on how the 
> implementation
> > was declared.
> 
> +1 here - I think the "taskdef/typedef" declarations ( which 
> I would like
> merged in a single "component" declaration ) should take an 
> extra "adapter="
> attribute, to allow this wrapping. 
> 

The problem of specifying an adaptor on a declaration by declaration basis
is that the whole bussines becomes very tedious. And you have to know
for each class whether the adaptor is needed or not. In particular for datatypes
that many of then need to function as tasks also but implement nothing
they all need to define the same adaptor. Instead the adaptor association
is done when defining the role name. (This, by the way, is what in escence the
current <typedef> does).

> 
> > d) The resulting object is passed as an argument to the 
> addConfigured()
> > method.
> 
> +1 ( with the comments above ).
> 
> 
> 
> > Declaration of roles:
> > ====================
> > 
> > A role definition associates a name with an 
> (Interface,Adaptor) pair.
> > The only reason for associating a name with the role is to 
> ease notation
> > when declaring members of a role.
> 
> Why ? 
> 

For the syntax sugar reasons I explained above. In reality it is more convinient.

> All the user needs to do is associate a name with an 
> implementation class.
> You need the impl. class anyway - and so the name, but the roles will
> be available as soon as you have the impl. class. You only need an
> additional attribute if you want to wrap.
> 

As explined above this assumes the same name used everywhere, which it is
not the case.

> 
> 
> > Notice that the same interface or the same Adaptor may 
> appear in multiple
> > declarations. This only means that depending on the name 
> used the adaptor
> > of choice will be different.
> > 
> > There can only be one pair associated with each name.
> 
> I don't see any reason for that. A class can implement 
> multiple interfaces,
> so it can have multiple roles. No need to add arbitrary restrictions.
> 
> 

There is no arbitrary restriction. We are talking about the pair (interface,adaptor)
not about the implementation class for the element. Implementation classes
can implement as many interfaces as they wish. And can belong to as many of few
roles as it likes (more than the interfaces, via adaptors or less than by
not declaring on roles which are superflous).

> > Syntax:
> > ======
> > 
> > I have left out the issues of how the syntax looks like on purpose.
> > 
> > Syntax is just that and I am sure we can reach agreement somehow.
> > It is also clear that we should provide tasks to define roles
> > and declare members of roles direclty on the build.
> > 
> > 
> > Ok, this is it. If you have any strong opinons about it, 
> let me know.
> 
> 
> You already know my strong opinion.
> 
> I think we should either use <taskdef>/<typedef> - with the additional
> attribute for the adapter - or use a new element <component> 
> ( or even 
> <role> - but I don't find this very intuitive ) that will replace both
> <taskdef> and <typdef>. 
> 
> For example:
>  <component name="elementName" className="...." [adapter="...."] />
> 

I do not mind having a <component> but with the syntax:

	<role name="roleName" className="...." [adapter="...."] />

	<component name="elementName" role="roleName" classNane="....." />

<role> could be just <component role="role" .../> but I think is less clear.

I still like the syntax sugar: <roleName className="..."/> but I won't loose
sleep about it.

Jose Alberto

Mime
View raw message