[DS] Allow a DS managed Service to modify there own ServiceProperties
Closed this issue · 10 comments
Original bug ID: BZ#3068
From: @juergen-albert
Reported version: R7
Comment author: @juergen-albert
The ComponentContext already allows a Service to disable itself. Thus it would make sense to add a methode to update its own properties.
Comment author: @bjhargrave
(In reply to Jürgen Albert from comment BZ#0)
The ComponentContext already allows a Service to disable itself. Thus it
would make sense to add a methode to update its own properties.
I think that has enablement is rather orthogonal to updating one's own component properties.
A component's service properties are its component properties (less private properites). And a component's component properties are set externally to the component (xml description, config admin, component factory).
We have many times discussed and rejected allowing a component to modify its own properties. Look in bugzilla history.
DS is not designed to handle all service use cases. A service modifying its own service properties is outside the design scope for DS.
Comment author: @juergen-albert
I know, we had this discussion before. But I still don't see the reason why. The outside world can dictate how I have to look to to everyone during my whole lifetime, but I can't. The only choice a service component has is suicide or add a unnecessary second service registration for itself.
The introduction of the service changecount shows that component properties are subject to change and I wouldn't know how to explain to somebody, why they are not allowed to adjust thier own properties.
If I use DS or the ConfigAdmin to configure e.g. a pooled DatabaseConnectionFactory, the component should be able to use there own service properties to tell e.g. how many connections are still available or if we lost the ping to the database server.
Comment author: @bjhargrave
(In reply to Jürgen Albert from comment BZ#2)
I know, we had this discussion before. But I still don't see the reason why.
Did you do the research and read the old bug reports? I think the reasons are spelled out.
As I mentioned, service properties == component properties. Component properties influence references via target filters. If a component can change it component properties, it can thus change its references and its use by other services (which may depend upon service property values). This means DS must then respond to the component changing its service properties. It can become a cycle since service properties are no longer declarative but are imperative.
One of the design points of DS is that the model is declarative and that DS is in charge of the components and their life cycle. DS sets the component properties and DS manages the service registration. In fact, DS registers the service before any code in the component ever executes due to the lazy nature of DS components. So if a component can alter it service properties, this can only be done after the service is registered and just as the component instance is being activated to provide to service object to someone who wants the service based upon the current service properties. If the component can then change the service properties, the current service user, for whom the component instance is being created, may then not want the service. This is made worse by bundle and prototype service scope since there can be multiple component instances behind one service registration. So which component instance gets to change the service properties for the one service registration? What if each component instance makes different decisions about what the service properties of the one service registration should be?
The way DS manages the life cycle of components and the service registration mean that it is not reasonable to allow a component instance to alter the service properties.
Felix SCR once had a non-standard feature to allow a component instance to alter the service properties by returning a Map from the activate method. (I think use of this feature is now discouraged.)
Comment author: @timothyjward
As BJ has pointed out, changing your own service properties from inside a component is not a good idea.
Also the examples given:
the component should be able to use there own service properties to tell e.g.
how many connections are still available or
if we lost the ping to the database server
Both of these things are dynamically changing data (particularly the number of connections in the pool) and using service properties to signal them is a very bad idea. Also, if the pool loses the ping to the database server then it should be unregistered (it's not able to do its job as a service). The service registry is not a messaging/event bus and should not be used to signal these sorts of things.
Comment author: @tverbele
(In reply to Jürgen Albert from comment BZ#2)
If I use DS or the ConfigAdmin to configure e.g. a pooled
DatabaseConnectionFactory, the component should be able to use there own
service properties to tell e.g. how many connections are still available or
if we lost the ping to the database server.
This is actually a perfect use case for using the cluster information specification. Register a NodeStatus service for the database server, and make the available connections one of the metrics available through getMetrics(). The bundle that registers the NodeStatus is responsible for the ping and unregisters the NodeStatus when ping is lost. You can then depend on this NodeStatus service to tie yourself to the lifecycle/availability of the database.
Comment author: @timothyjward
(In reply to Tim Verbelen from comment BZ#5)
(In reply to Jürgen Albert from comment BZ#2)
If I use DS or the ConfigAdmin to configure e.g. a pooled
DatabaseConnectionFactory, the component should be able to use there own
service properties to tell e.g. how many connections are still available or
if we lost the ping to the database server.This is actually a perfect use case for using the cluster information
specification. Register a NodeStatus service for the database server, and
make the available connections one of the metrics available through
getMetrics(). The bundle that registers the NodeStatus is responsible for
the ping and unregisters the NodeStatus when ping is lost. You can then
depend on this NodeStatus service to tie yourself to the
lifecycle/availability of the database.
This is a much better way to handle connection availability, with or without the Cluster Information specification!
Comment author: @bjhargrave
Another way to think of this is that a component is really a source of service objects for the service factory used by DS when registering the service. There is a 1..N relationship between the service registration done by DS and the component instances(service objects). Since a component instance is not the service registrant, but is rather the service object, it is at the wrong level to control the details of the service registration (including service properties).
This is a core design principle of DS with the implication that component instances cannot modify service properties. If you have a design problem that requires modification of service properties, then DS is not a solution choice available for that design problem.
Comment author: @cziegeler
Just as additional info, the Apache Felix implementation still supports this through so called extensions. I recently tried to get rid of this special implementation as it's complicating the code quiet a bit, has some hard to fix bugs etc. However, it seems that there are consumers of this.
Still, for the reasons mentioned here and elsewhere by others already I don't think this is a good idea
Comment author: @bjhargrave
Closing.