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.
Moreover the hivedoc generation needs a resolved registry definition
too and can't operate on the internal objects.
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.
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.
Achim