OSGi-DS: Dynamic and Optional reference to required service in DS Component, is not really dynamic

403 views
Skip to first unread message

Umesh Rajani

unread,
May 26, 2017, 5:08:00 AM5/26/17
to bndtools-users

I want to start DS component which has many services as optional, if some service is not up then also this component should start but it failed.

If I set referenced service optional cardinality then it can be activated but when I change configuration of any optional,dynamic service to valid and that service is up but it won't reflect in that service's component

@Component(immediate = true, configurationPolicy = ConfigurationPolicy.IGNORE,name="directory.comp")
public class DirectoryControllers
{
    @Reference(policy=ReferencePolicy.DYNAMIC)
        private volatile IZimbra zimbra;
        @Reference(policy=ReferencePolicy.DYNAMIC,cardinality=ReferenceCardinality.OPTIONAL)
        private volatile IOpenDJ opendj;
        @Reference(policy=ReferencePolicy.DYNAMIC,cardinality=ReferenceCardinality.OPTIONAL)
        private volatile IOpenIDM openidm;

        private ServletRegistration _registration;

        @Activate void activate(BundleContext bc) throws ServletException, NamespaceException
        {
             AppProvisioners provisioners=new AppProvisioners(zimbra,openidm,opendj);
            _registration = ServletRegistration.register(
                bc, _httpService, "/middleware",
                new ProvisioningController(_db,provisioners), 
                new UserEnrollmentController(_db,provisioners)
            );
        }
}

Here, zimbra component is dynamic so whenever I change configuration it will be affected in DirectoryControllers component, but same is not true for openidm,opendj component, of course it is optional but on changing their configuration valid, it is not affected in DirectoryControllers component


Am I missing anything which leads to this issue?


Thanks,

Umesh

Neil Bartlett

unread,
May 26, 2017, 5:27:41 AM5/26/17
to bndtool...@googlegroups.com
It looks like you pass the “zimbra” object to the constructor of AppProvisioners during your activate method, which is only invoked once. If the value of “zimbra” changes at any time later, you are missing a mechanism to inform AppProvisioners about the change.

Regards,
Neil

--
You received this message because you are subscribed to the Google Groups "bndtools-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bndtools-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Neil Bartlett

unread,
May 26, 2017, 5:33:22 AM5/26/17
to bndtool...@googlegroups.com
Sorry I got that a little wrong, but my point remains the same.

When “opendj” and “openidm” change, the AppProvisioners will still be using the values it was passed in its constructor. When “zimbra” changes, there is probably a short time during which there are zero IZimbra service available. Since the zimbra reference is mandatory, your component has to be destroyed at that point. When the IZimbra service comes back, your component will be recreated and the activate method will be invoked again, creating a new AppProvisionsers object using the new zimbra.

I think you should just change all of these references to STATIC (and the optional ones should also be GREEDY). That way your component will be recreated — and therefore AppProvisioners will be recreated — when any of those services change.


Regards,
Neil

daghan acay

unread,
May 26, 2017, 6:27:35 AM5/26/17
to bndtools-users
Hi Neil,

If my understanding is correct, below is not a correct statement 

"Since the zimbra reference is mandatory, your component has to be destroyed at that point. "

As the current code goes, activate method of DirectoryControllers will only be called once. It will never be called again  even if zimbra, opendj, openidm. Because they are all defined DYNAMIC and the DirectoryControllers will never be destroyed and due to changes. Which leads to AppProvisioner will never get a new instance.

Also, evevn if you define GREEDY in the DYNAMIC+OPTIONAL references this will not change the AppProvisioner instance. It will only refresh the binding of DirectoryControllers without reconstructing it.

I would really appraciate your feedback if I my undersatnding is wrong.

As a response to original question, I was trying to do something similar in my code, but as Peter suggested it gets too complated too quickly. You might want to refactortor your code and try to use whiteboard pattern.

Regards
-Daghan

Neil Bartlett

unread,
May 26, 2017, 6:41:07 AM5/26/17
to bndtool...@googlegroups.com
On 26 May 2017, at 11:27, daghan acay <dagha...@gmail.com> wrote:

Hi Neil,

If my understanding is correct, below is not a correct statement 

"Since the zimbra reference is mandatory, your component has to be destroyed at that point. "

As the current code goes, activate method of DirectoryControllers will only be called once. It will never be called again  even if zimbra, opendj, openidm. Because they are all defined DYNAMIC and the DirectoryControllers will never be destroyed and due to changes. Which leads to AppProvisioner will never get a new instance.

It depends how the IZimbra service changes. If the one that is currently bound becomes invalid, then the reference can bind to another available IZimbra, but ONLY if that alternative was ALREADY available when the bound service went away.

Often a service changes because the provider bundle has been updated, which means the original service goes away and then a new service comes along. So there is a gap during which no service exists. Even if this gap is only a microseconds, the component must be destroyed because that’s the definition of a mandatory reference.

In my email I did say there is “probably” a gap, but it matches the fact pattern stated by the OP.


Also, evevn if you define GREEDY in the DYNAMIC+OPTIONAL references this will not change the AppProvisioner instance. It will only refresh the binding of DirectoryControllers without reconstructing it.

The original component will be destroyed, a new one will be created and activated, therefore a new AppProvisioner will be instantiated with the new value of those references. The old instance of AppProvisioner *should* be garbage collected.

It’s possible that AppProvisioner starts a thread or something that prevents it from being GC’d, but that would be a badly behaved DS component because you’re supposed to clean up after yourself.

Neil

Neil Bartlett

unread,
May 26, 2017, 6:44:16 AM5/26/17
to bndtool...@googlegroups.com
Quick correction below… I should learn to check before sending :-)

On 26 May 2017, at 11:41, Neil Bartlett <njbar...@gmail.com> wrote:


On 26 May 2017, at 11:27, daghan acay <dagha...@gmail.com> wrote:

Hi Neil,

If my understanding is correct, below is not a correct statement 

"Since the zimbra reference is mandatory, your component has to be destroyed at that point. "

As the current code goes, activate method of DirectoryControllers will only be called once. It will never be called again  even if zimbra, opendj, openidm. Because they are all defined DYNAMIC and the DirectoryControllers will never be destroyed and due to changes. Which leads to AppProvisioner will never get a new instance.

It depends how the IZimbra service changes. If the one that is currently bound becomes invalid, then the reference can bind to another available IZimbra, but ONLY if that alternative was ALREADY available when the bound service went away.

Often a service changes because the provider bundle has been updated, which means the original service goes away and then a new service comes along. So there is a gap during which no service exists. Even if this gap is only a microseconds, the component must be destroyed because that’s the definition of a mandatory reference.

In my email I did say there is “probably” a gap, but it matches the fact pattern stated by the OP.


Also, evevn if you define GREEDY in the DYNAMIC+OPTIONAL references this will not change the AppProvisioner instance. It will only refresh the binding of DirectoryControllers without reconstructing it.

The original component will be destroyed, a new one will be created and activated, therefore a new AppProvisioner will be instantiated with the new value of those references. The old instance of AppProvisioner *should* be garbage collected.

This occurs is if you define *STATIC* + GREEDY as I recommended. If the references are still DYNAMIC then the code is still broken because the DS component will live on and never inform the AppProvisioner of any changes.
Reply all
Reply to author
Forward
0 new messages