Achim,
On 2/9/07, Achim Hügen <[EMAIL PROTECTED]> wrote:
Knut,
Knut Wannheden schrieb:
> Hi Achim,
>
> On 1/25/07, Achim Hügen <[EMAIL PROTECTED]> wrote:
>> I agree that it is desirable to reduce mutability.
>>
>> Most of the collections returned from any definition
>> class could be made immutable.
>> A call to Collections.unmodifiableCollection() would solve this.
>>
>> Regarding the addXxx methods I find it very helpful to use
>> the definition classes for construction and extension resolving.
>> Otherwise one would need an additional structure that represents
>> the assocations between extension points and extensions and which
>> is used during construction for resolving and constraint checking.
>> To my mind it feels like the most natural fit to add and retrieve
>> the associated objects directly from their source.
>>
>
> When *defining* a module using Java code I agree that using the
> addXxx() methods may feel more natural so it might make sense to have
> those in implementation classes. But I don't agree with that this is
> required for the extension resolving. You say that an additional
> structure would be required. As I see it this additional structure is
> already present, it's HiveMind internal counterpart to the definition
> structure. I.e. the objects Module, ServicePoint, etc. created during
> the registry construction. And that's also how it worked in HiveMind
The problem is that those objects are generic (and should stay generic)
and doesn't know anything about specific implementations of the
definition api (xml, annotations).
The ServicePoint class would have to store a schema for a xml service point
because the schema is assigned during the extension resolving phase.
I don't quite see how schemas relate to this. After all they are not
part of the definition API either. Rather this seems to tie in more
with my remark about the internal objects keeping a reference to the
respective definition object after registry construction time. See
below.
Moreover the hivedoc generation needs a resolved registry definition
too and can't operate on the internal objects.
A HiveDoc report should IMHO reflect the structure of an unresolved
registry. That's IIRC what it has done up until now. And that should
certainly be easier with an unresolved definition structure as a
starting point.
> 1.
>
>> These add methods are defined in the public interfaces.
>> RegistryDefinition#addModule
>> RegistryDefinition#addPostProcessor
>> RegistryDefinition#addRegistryInitializationListener
>> ModuleDefinition#addServicePoint
>> ModuleDefinition#addConfigurationPoint
>> ...
>> ConfigurationPointDefinition#addContribution
>> ConfigurationPointDefinition#addParser
>> ServicePointDefinition#addImplementation
>> ServicePointDefinition#addInterceptor
>>
>> Although it might be possible to shift some of them to the
>> the implementation classes, at least
>> the add-methods of RegistryDefinition and ModuleDefinition must remain.
>>
>
> Why must the add methods on these two interfaces remain?
I was wrong for ModuleDefinition and already moved them to the impl class.
So it is no longer possible to add extension points to another module.
It is still possible to add extensions and that is what they are
designed for.
> I can see
> that we need those on RegistryDefinition unless we change the
> RegistryProvider (should we move that to the definition package?) to
> something like:
>
> public interface RegistryProvider
> {
> Collection getModules();
> Collection getPostProcessors();
> Collection getRegistryInitializationListeners();
> }
>
> Of course the latter two could arguably also be moved to the
> ModuleDefinition.
>
> As far as I can understand the add methods on ModuleDefintion are
> currently used so that a RegistryProvider can augment any other module
> by first retrieving it from the RegistryDefinition. Also a
> RegistryPostProcessor can do that. I think that seems a little bit
> dangerous. I'd like to think of a module definition as sealed! I know
> that this is used in the case of the "hivemind" module but that case
> could be treated separately.
Let us not be too restrictive here. Thats more a chance but a threat.
For example you could iterate over all services and add an interceptor
to all services that match certain criterias.
That means that a user can add interceptors to private services and
contributions to private configurations. Of course marking an
extension as private is often just about hiding complexity.
I am not saying I am against this but I was not aware of this
difference to HiveMind 1. Any other opinions on this?
>
>> So, to achieve immutability in a consistent manner I would suggest
>> to use the same mechanism that is implemented in
>> RegistryInfrastructureImpl.
>> After the startup of the registry the definition classes gets locked,
>> that
>> means further modification by calls to the add methods are forbidden.
>> This requirement must be document in the interfaces and could be
>> implemented
>> in the default implementation of the definition interfaces.
>>
>> I don't expect this to make the implementation of the API more difficult
>> in any way, Knut.
>> Please take a look at the current implementations of the api: the xml
>> module specializes
>> 2 classes of the default implementation only and the annotation module
>> doesn't override
>> any implementation at all. Most of the stuff is handled by the
>> constructors.
>> I don't think that a spring implementation would require special
>> implementations
>> of the api which cannot be inherited from the default implementation.
>>
>> How do you expect the api to get simpler? Could you give an example?
>>
>
> IMHO the API would be simpler just by having fewer methods in it. The
> implementor won't have to worry about implementing the add methods
> which actually need to implement a guard just like you've done in
> ModuleDefinitionImpl to protect against unwanted modifications. Also a
> user won't get the idea that the definitions can be changed after the
> registry has been constructed.
>
> On another note I discovered that the internal objects will even after
> registry startup always maintain a reference to their respective
> definition objects which thus won't ever get garbage collected. Is
> that on purpose?
Yes, it's on purpose. On the one hand you need access to the
specific implementations of the definition api (xml, annotations)
from the constructors (see InvokeFactoryServiceConstructor).
On the other hand the definition data is rather lean, but
surely we could make some optimization there later.
One example of this you're describing is the
InvokeFactoryServiceConstructor which will query the ServicePoint for
its definition and cast it to its XML specific implementation to
retireve the schema.
Another solution would be if the ImplementationConstructor object
already had all the details it needed from the definition objects in
order for it to create the CSI. The ServicePoint would then at
registry build time be wired with this ImplementationConstructor
instead of its ServicePointDefinition. After registry construction
time the definition objects would then be garbage collected.
Regards,
--knut