Re: Predictable order of bundle resolution
Yes, Justin, that is correct. Cohort A will get an update that will contain the new/updated bundles and so becomes Cohort A' which will be similar to Cohort B in that regard. However updates of Bundle C must still be compatible with the Cohort A. To go more into detail: * Bundle A providing org.foo is Open Source and publicly available, so installations of Cohort A can keep it updated. * Bundle B is publicly available but not Open Source * Bundle D, the implementation is not publicly available An alternative would be to provide a public implementation of Bundle D and embed it into the deployment of the feature that contains Bundle C. But instead of that we can also use Dynamic-ImportPackage until Cohort A gets unsupported and has to migrate to Cohort A'. Hope that makes the use case a little clearer. -Dirk On Fri, 15 Oct 2021 at 12:01, Justin Edelson wrote: > > Hi Dirk, > Possibly I misunderstood the invariants in your situation. Here's what I > understood: > > * There's a set of installations with Bundle A (that exports org.foo) and > *not* Bundle B (that exports org.bar) -- let's call this Install Cohort A > * There's a set of installations with Bundle A and Bundle B -- let's call > this Install Cohort B > * You have no way to install Bundle B on Install Cohort A. > * You have no way to update either Bundle A or Bundle B on either cohort. > * You can install and update *other* bundles. > > But it sounds like that last bullet was not correct. You can only > install/update *exactly one* bundle (Bundle C). Is that correct? > > Regards, > Justin > > On Fri, Oct 15, 2021 at 5:01 AM Dirk Rudolph wrote: > > > Ok I understand, thanks. > > > > Unfortunately, I cannot guarantee that my consumer Bundle C is only > > used in installations that have all the other bundles installed yet, > > due to backward compatibility reasons. > > > > I will go for dynamic imports for now and once we drop support for the > > older versions and support only those that have the necessary > > bundles/packages installed, I will change it again. > > > > Regards, > > - Dirk > > > > On Fri, 15 Oct 2021 at 10:47, Neil Bartlett wrote: > > > > > > The implementation of the resolver will be different depending on the > > OSGi > > > Framework implementation, so you're really getting into the weeds if you > > > start relying on those internals. > > > > > > If one of your bundle's imports is optional, then by definition your > > bundle > > > has to work when that import is not wired. The Framework is not required > > to > > > give you a wiring for the import even if a compatible export appears to > > be > > > available. > > > > > > I agree with Justin that services are the answer, but I disagree a little > > > with the structure of his solution, there is no need for a shim. Here is > > > what I would do: > > > > > > * Bundle A (for "API") exports both packages org.foo and org.bar. Both of > > > these are pure APIs without implementation, so there is no cost to > > > exporting both packages. > > > * Either bundle A or another bundle (A') provides a service implementing > > > the org.foo API, e.g. org.foo.Service. > > > * Bundle B (for "Bonus"?) imports package org.bar and provides a service > > > implementing the org.bar API, e.g. org.bar.BonusService. > > > * Bundle C ("Consumer") imports both packages org.foo and org.bar. > > Neither > > > of these are optional imports so they are always wired. C attempts to > > find > > > a service instance implementing the BonusService, but if it doesn't find > > > that then it can fall back to the inferioer org.foo.Service instance. > > > > > > This can be easily modelled as a Declarative Services component with one > > > mandatory reference to org.foo.Service, and an optional+greedy reference > > to > > > the org.bar.BonusService. > > > > > > Neil > > > > > > > > > > > > > > > > > > On Fri, 15 Oct 2021 at 08:40, Dirk Rudolph wrote: > > > > > > > Thanks for the suggestion Justin. > > > > > > > > What if I cannot guarantee that the Shim API Bundle exists on all > > > > installations, same as Bundle B? That would mean the org.shim import > > > > in Bundle C is optional again. > > > > > > > > In fact I have a Bundle D already implementing both APIs from Bundle A > > > > and B and registering the implementation as a service of both. > > > > > > > > Bundle A > > > > interface org.foo.Service {} > > > > > > > > Bundle B > > > > interface org.bar.ServiceExt extends org.foo.Service {} > > > > > > > > Bundle D > > > > @Component(service = {org.foo.Service,org.bar.ServiceExt}) class > > > > ServiceImpl implements ServiceExt {} > > > > > > > > So Bundle B always resolves, at least wired to Bundle A and so the > > > > service from Bundle D is used with the org.foo API. > > > > > > > > If I understand the StatefulResolver correctly, it uses a ThreadPool > > > > as executor for the ResolverImpl, meaning it may happen that bundles > > > > do not alway get resolved in the same order. If so I would assume the > >
Re: Predictable order of bundle resolution
Hi Dirk, Possibly I misunderstood the invariants in your situation. Here's what I understood: * There's a set of installations with Bundle A (that exports org.foo) and *not* Bundle B (that exports org.bar) -- let's call this Install Cohort A * There's a set of installations with Bundle A and Bundle B -- let's call this Install Cohort B * You have no way to install Bundle B on Install Cohort A. * You have no way to update either Bundle A or Bundle B on either cohort. * You can install and update *other* bundles. But it sounds like that last bullet was not correct. You can only install/update *exactly one* bundle (Bundle C). Is that correct? Regards, Justin On Fri, Oct 15, 2021 at 5:01 AM Dirk Rudolph wrote: > Ok I understand, thanks. > > Unfortunately, I cannot guarantee that my consumer Bundle C is only > used in installations that have all the other bundles installed yet, > due to backward compatibility reasons. > > I will go for dynamic imports for now and once we drop support for the > older versions and support only those that have the necessary > bundles/packages installed, I will change it again. > > Regards, > - Dirk > > On Fri, 15 Oct 2021 at 10:47, Neil Bartlett wrote: > > > > The implementation of the resolver will be different depending on the > OSGi > > Framework implementation, so you're really getting into the weeds if you > > start relying on those internals. > > > > If one of your bundle's imports is optional, then by definition your > bundle > > has to work when that import is not wired. The Framework is not required > to > > give you a wiring for the import even if a compatible export appears to > be > > available. > > > > I agree with Justin that services are the answer, but I disagree a little > > with the structure of his solution, there is no need for a shim. Here is > > what I would do: > > > > * Bundle A (for "API") exports both packages org.foo and org.bar. Both of > > these are pure APIs without implementation, so there is no cost to > > exporting both packages. > > * Either bundle A or another bundle (A') provides a service implementing > > the org.foo API, e.g. org.foo.Service. > > * Bundle B (for "Bonus"?) imports package org.bar and provides a service > > implementing the org.bar API, e.g. org.bar.BonusService. > > * Bundle C ("Consumer") imports both packages org.foo and org.bar. > Neither > > of these are optional imports so they are always wired. C attempts to > find > > a service instance implementing the BonusService, but if it doesn't find > > that then it can fall back to the inferioer org.foo.Service instance. > > > > This can be easily modelled as a Declarative Services component with one > > mandatory reference to org.foo.Service, and an optional+greedy reference > to > > the org.bar.BonusService. > > > > Neil > > > > > > > > > > > > On Fri, 15 Oct 2021 at 08:40, Dirk Rudolph wrote: > > > > > Thanks for the suggestion Justin. > > > > > > What if I cannot guarantee that the Shim API Bundle exists on all > > > installations, same as Bundle B? That would mean the org.shim import > > > in Bundle C is optional again. > > > > > > In fact I have a Bundle D already implementing both APIs from Bundle A > > > and B and registering the implementation as a service of both. > > > > > > Bundle A > > > interface org.foo.Service {} > > > > > > Bundle B > > > interface org.bar.ServiceExt extends org.foo.Service {} > > > > > > Bundle D > > > @Component(service = {org.foo.Service,org.bar.ServiceExt}) class > > > ServiceImpl implements ServiceExt {} > > > > > > So Bundle B always resolves, at least wired to Bundle A and so the > > > service from Bundle D is used with the org.foo API. > > > > > > If I understand the StatefulResolver correctly, it uses a ThreadPool > > > as executor for the ResolverImpl, meaning it may happen that bundles > > > do not alway get resolved in the same order. If so I would assume the > > > implementation should repeat the resolution once a bundle fulfilling > > > an optional requirement gets resolved (greedy behaviour). Is that the > > > case? I haven't found anything about that in the specs. > > > > > > Regards, > > > Dirk > > > > > > > > > > > > > > > > > > > > > On Fri, 15 Oct 2021 at 00:09, Justin Edelson > > > > wrote: > > > > > > > > Hi Dirk, > > > > This is a possibly impractical suggestion in your context, but have > you > > > > thought about modeling this as services? Something like: > > > > > > > > Bundle A (ID: 200) > > > > - Export-Package: org.foo;version=1.0.0 > > > > > > > > Bundle B (ID: 210) > > > > - Import-Package: org.foo;version="[1.0,2)" > > > > - Export-Package: org.bar;version=1.0.0 > > > > > > > > Shim API Bundle: > > > > - Export-Package: org.shim;version=1.0.0 > > > > > > > > Shim for Bundle A Bundle > > > > - Import-Package: > org.shim;version="[1.0.0,2)",org.foo;version="[1.0,2)" > > > > > > > > Shim for Bundle B Bundle > > > > - Import-Package: > org.shim;version="[1.0.0,2)",org.bar;version="[1.0,2)" > > > > > > > > Bund
Re: Predictable order of bundle resolution
Ok I understand, thanks. Unfortunately, I cannot guarantee that my consumer Bundle C is only used in installations that have all the other bundles installed yet, due to backward compatibility reasons. I will go for dynamic imports for now and once we drop support for the older versions and support only those that have the necessary bundles/packages installed, I will change it again. Regards, - Dirk On Fri, 15 Oct 2021 at 10:47, Neil Bartlett wrote: > > The implementation of the resolver will be different depending on the OSGi > Framework implementation, so you're really getting into the weeds if you > start relying on those internals. > > If one of your bundle's imports is optional, then by definition your bundle > has to work when that import is not wired. The Framework is not required to > give you a wiring for the import even if a compatible export appears to be > available. > > I agree with Justin that services are the answer, but I disagree a little > with the structure of his solution, there is no need for a shim. Here is > what I would do: > > * Bundle A (for "API") exports both packages org.foo and org.bar. Both of > these are pure APIs without implementation, so there is no cost to > exporting both packages. > * Either bundle A or another bundle (A') provides a service implementing > the org.foo API, e.g. org.foo.Service. > * Bundle B (for "Bonus"?) imports package org.bar and provides a service > implementing the org.bar API, e.g. org.bar.BonusService. > * Bundle C ("Consumer") imports both packages org.foo and org.bar. Neither > of these are optional imports so they are always wired. C attempts to find > a service instance implementing the BonusService, but if it doesn't find > that then it can fall back to the inferioer org.foo.Service instance. > > This can be easily modelled as a Declarative Services component with one > mandatory reference to org.foo.Service, and an optional+greedy reference to > the org.bar.BonusService. > > Neil > > > > > > On Fri, 15 Oct 2021 at 08:40, Dirk Rudolph wrote: > > > Thanks for the suggestion Justin. > > > > What if I cannot guarantee that the Shim API Bundle exists on all > > installations, same as Bundle B? That would mean the org.shim import > > in Bundle C is optional again. > > > > In fact I have a Bundle D already implementing both APIs from Bundle A > > and B and registering the implementation as a service of both. > > > > Bundle A > > interface org.foo.Service {} > > > > Bundle B > > interface org.bar.ServiceExt extends org.foo.Service {} > > > > Bundle D > > @Component(service = {org.foo.Service,org.bar.ServiceExt}) class > > ServiceImpl implements ServiceExt {} > > > > So Bundle B always resolves, at least wired to Bundle A and so the > > service from Bundle D is used with the org.foo API. > > > > If I understand the StatefulResolver correctly, it uses a ThreadPool > > as executor for the ResolverImpl, meaning it may happen that bundles > > do not alway get resolved in the same order. If so I would assume the > > implementation should repeat the resolution once a bundle fulfilling > > an optional requirement gets resolved (greedy behaviour). Is that the > > case? I haven't found anything about that in the specs. > > > > Regards, > > Dirk > > > > > > > > > > > > > > On Fri, 15 Oct 2021 at 00:09, Justin Edelson > > wrote: > > > > > > Hi Dirk, > > > This is a possibly impractical suggestion in your context, but have you > > > thought about modeling this as services? Something like: > > > > > > Bundle A (ID: 200) > > > - Export-Package: org.foo;version=1.0.0 > > > > > > Bundle B (ID: 210) > > > - Import-Package: org.foo;version="[1.0,2)" > > > - Export-Package: org.bar;version=1.0.0 > > > > > > Shim API Bundle: > > > - Export-Package: org.shim;version=1.0.0 > > > > > > Shim for Bundle A Bundle > > > - Import-Package: org.shim;version="[1.0.0,2)",org.foo;version="[1.0,2)" > > > > > > Shim for Bundle B Bundle > > > - Import-Package: org.shim;version="[1.0.0,2)",org.bar;version="[1.0,2)" > > > > > > Bundle C > > > - Import-Package: org.shim;version="[1.0.0,2)" > > > > > > The Shim API bundle exports a service interface that is implemented in > > both > > > "Shim for Bundle A Bundle" and "Shim for Bundle B Bundle" (backed by the > > > corresponding org.foo or org.bar API). The service in "Shim for Bundle B > > > Bundle" has a higher service ranking. The service reference in Bundle C > > > would (assuming it was properly set up) get one or the other. > > > > > > Regards, > > > Justin > > > > > > On Thu, Oct 14, 2021 at 1:40 PM Dirk Rudolph wrote: > > > > > > > Hi, > > > > > > > > tldr; is the order in which bundles get resolved predictable? > > > > > > > > We are facing issues with the usage of optional imports. Sometimes an > > > > optionally imported package gets wired and sometimes it doesn't. > > > > Refreshing the consuming bundle's package imports after startup always > > > > works to get the wiring done right. > > > > > > > > Consider the follow
Re: Predictable order of bundle resolution
The implementation of the resolver will be different depending on the OSGi Framework implementation, so you're really getting into the weeds if you start relying on those internals. If one of your bundle's imports is optional, then by definition your bundle has to work when that import is not wired. The Framework is not required to give you a wiring for the import even if a compatible export appears to be available. I agree with Justin that services are the answer, but I disagree a little with the structure of his solution, there is no need for a shim. Here is what I would do: * Bundle A (for "API") exports both packages org.foo and org.bar. Both of these are pure APIs without implementation, so there is no cost to exporting both packages. * Either bundle A or another bundle (A') provides a service implementing the org.foo API, e.g. org.foo.Service. * Bundle B (for "Bonus"?) imports package org.bar and provides a service implementing the org.bar API, e.g. org.bar.BonusService. * Bundle C ("Consumer") imports both packages org.foo and org.bar. Neither of these are optional imports so they are always wired. C attempts to find a service instance implementing the BonusService, but if it doesn't find that then it can fall back to the inferioer org.foo.Service instance. This can be easily modelled as a Declarative Services component with one mandatory reference to org.foo.Service, and an optional+greedy reference to the org.bar.BonusService. Neil On Fri, 15 Oct 2021 at 08:40, Dirk Rudolph wrote: > Thanks for the suggestion Justin. > > What if I cannot guarantee that the Shim API Bundle exists on all > installations, same as Bundle B? That would mean the org.shim import > in Bundle C is optional again. > > In fact I have a Bundle D already implementing both APIs from Bundle A > and B and registering the implementation as a service of both. > > Bundle A > interface org.foo.Service {} > > Bundle B > interface org.bar.ServiceExt extends org.foo.Service {} > > Bundle D > @Component(service = {org.foo.Service,org.bar.ServiceExt}) class > ServiceImpl implements ServiceExt {} > > So Bundle B always resolves, at least wired to Bundle A and so the > service from Bundle D is used with the org.foo API. > > If I understand the StatefulResolver correctly, it uses a ThreadPool > as executor for the ResolverImpl, meaning it may happen that bundles > do not alway get resolved in the same order. If so I would assume the > implementation should repeat the resolution once a bundle fulfilling > an optional requirement gets resolved (greedy behaviour). Is that the > case? I haven't found anything about that in the specs. > > Regards, > Dirk > > > > > > > On Fri, 15 Oct 2021 at 00:09, Justin Edelson > wrote: > > > > Hi Dirk, > > This is a possibly impractical suggestion in your context, but have you > > thought about modeling this as services? Something like: > > > > Bundle A (ID: 200) > > - Export-Package: org.foo;version=1.0.0 > > > > Bundle B (ID: 210) > > - Import-Package: org.foo;version="[1.0,2)" > > - Export-Package: org.bar;version=1.0.0 > > > > Shim API Bundle: > > - Export-Package: org.shim;version=1.0.0 > > > > Shim for Bundle A Bundle > > - Import-Package: org.shim;version="[1.0.0,2)",org.foo;version="[1.0,2)" > > > > Shim for Bundle B Bundle > > - Import-Package: org.shim;version="[1.0.0,2)",org.bar;version="[1.0,2)" > > > > Bundle C > > - Import-Package: org.shim;version="[1.0.0,2)" > > > > The Shim API bundle exports a service interface that is implemented in > both > > "Shim for Bundle A Bundle" and "Shim for Bundle B Bundle" (backed by the > > corresponding org.foo or org.bar API). The service in "Shim for Bundle B > > Bundle" has a higher service ranking. The service reference in Bundle C > > would (assuming it was properly set up) get one or the other. > > > > Regards, > > Justin > > > > On Thu, Oct 14, 2021 at 1:40 PM Dirk Rudolph wrote: > > > > > Hi, > > > > > > tldr; is the order in which bundles get resolved predictable? > > > > > > We are facing issues with the usage of optional imports. Sometimes an > > > optionally imported package gets wired and sometimes it doesn't. > > > Refreshing the consuming bundle's package imports after startup always > > > works to get the wiring done right. > > > > > > Consider the following bundles: > > > > > > Bundle A (ID: 200) > > > - Export-Package: org.foo;version=1.0.0 > > > > > > Bundle B (ID: 210) > > > - Import-Package: org.foo;version="[1.0,2)" > > > - Export-Package: org.bar;version=1.0.0 > > > > > > Bundle C (ID: 500) > > > - Import-Package: > > > > org.foo;version="[1.0,2)",org.bar;version="[1.0,2)";resolution:=optional > > > > > > All bundles have the same startlevel (20), in case it matters (?). > > > > > > Our use-case is that Bundle C used to use an API provided by Bundle A, > > > which got improved and extended into a new API provided by Bundle B. > > > Not all installations provide Bundle B, but all provide Bundle A. > > > Bundle C now prefers the
Re: Predictable order of bundle resolution
Thanks for the suggestion Justin. What if I cannot guarantee that the Shim API Bundle exists on all installations, same as Bundle B? That would mean the org.shim import in Bundle C is optional again. In fact I have a Bundle D already implementing both APIs from Bundle A and B and registering the implementation as a service of both. Bundle A interface org.foo.Service {} Bundle B interface org.bar.ServiceExt extends org.foo.Service {} Bundle D @Component(service = {org.foo.Service,org.bar.ServiceExt}) class ServiceImpl implements ServiceExt {} So Bundle B always resolves, at least wired to Bundle A and so the service from Bundle D is used with the org.foo API. If I understand the StatefulResolver correctly, it uses a ThreadPool as executor for the ResolverImpl, meaning it may happen that bundles do not alway get resolved in the same order. If so I would assume the implementation should repeat the resolution once a bundle fulfilling an optional requirement gets resolved (greedy behaviour). Is that the case? I haven't found anything about that in the specs. Regards, Dirk On Fri, 15 Oct 2021 at 00:09, Justin Edelson wrote: > > Hi Dirk, > This is a possibly impractical suggestion in your context, but have you > thought about modeling this as services? Something like: > > Bundle A (ID: 200) > - Export-Package: org.foo;version=1.0.0 > > Bundle B (ID: 210) > - Import-Package: org.foo;version="[1.0,2)" > - Export-Package: org.bar;version=1.0.0 > > Shim API Bundle: > - Export-Package: org.shim;version=1.0.0 > > Shim for Bundle A Bundle > - Import-Package: org.shim;version="[1.0.0,2)",org.foo;version="[1.0,2)" > > Shim for Bundle B Bundle > - Import-Package: org.shim;version="[1.0.0,2)",org.bar;version="[1.0,2)" > > Bundle C > - Import-Package: org.shim;version="[1.0.0,2)" > > The Shim API bundle exports a service interface that is implemented in both > "Shim for Bundle A Bundle" and "Shim for Bundle B Bundle" (backed by the > corresponding org.foo or org.bar API). The service in "Shim for Bundle B > Bundle" has a higher service ranking. The service reference in Bundle C > would (assuming it was properly set up) get one or the other. > > Regards, > Justin > > On Thu, Oct 14, 2021 at 1:40 PM Dirk Rudolph wrote: > > > Hi, > > > > tldr; is the order in which bundles get resolved predictable? > > > > We are facing issues with the usage of optional imports. Sometimes an > > optionally imported package gets wired and sometimes it doesn't. > > Refreshing the consuming bundle's package imports after startup always > > works to get the wiring done right. > > > > Consider the following bundles: > > > > Bundle A (ID: 200) > > - Export-Package: org.foo;version=1.0.0 > > > > Bundle B (ID: 210) > > - Import-Package: org.foo;version="[1.0,2)" > > - Export-Package: org.bar;version=1.0.0 > > > > Bundle C (ID: 500) > > - Import-Package: > > org.foo;version="[1.0,2)",org.bar;version="[1.0,2)";resolution:=optional > > > > All bundles have the same startlevel (20), in case it matters (?). > > > > Our use-case is that Bundle C used to use an API provided by Bundle A, > > which got improved and extended into a new API provided by Bundle B. > > Not all installations provide Bundle B, but all provide Bundle A. > > Bundle C now prefers the optionally available API of Bundle B but > > falls back to the API provided by Bundle A if Bundle B is not > > available. > > > > I think the usage of optional imports is reasonable here, or are there > > alternatives besides using dynamic imports? > > > > Thanks, > > > > - Dirk > > > > - > > To unsubscribe, e-mail: users-unsubscr...@felix.apache.org > > For additional commands, e-mail: users-h...@felix.apache.org > > > > - To unsubscribe, e-mail: users-unsubscr...@felix.apache.org For additional commands, e-mail: users-h...@felix.apache.org
Re: Predictable order of bundle resolution
Hi Dirk, This is a possibly impractical suggestion in your context, but have you thought about modeling this as services? Something like: Bundle A (ID: 200) - Export-Package: org.foo;version=1.0.0 Bundle B (ID: 210) - Import-Package: org.foo;version="[1.0,2)" - Export-Package: org.bar;version=1.0.0 Shim API Bundle: - Export-Package: org.shim;version=1.0.0 Shim for Bundle A Bundle - Import-Package: org.shim;version="[1.0.0,2)",org.foo;version="[1.0,2)" Shim for Bundle B Bundle - Import-Package: org.shim;version="[1.0.0,2)",org.bar;version="[1.0,2)" Bundle C - Import-Package: org.shim;version="[1.0.0,2)" The Shim API bundle exports a service interface that is implemented in both "Shim for Bundle A Bundle" and "Shim for Bundle B Bundle" (backed by the corresponding org.foo or org.bar API). The service in "Shim for Bundle B Bundle" has a higher service ranking. The service reference in Bundle C would (assuming it was properly set up) get one or the other. Regards, Justin On Thu, Oct 14, 2021 at 1:40 PM Dirk Rudolph wrote: > Hi, > > tldr; is the order in which bundles get resolved predictable? > > We are facing issues with the usage of optional imports. Sometimes an > optionally imported package gets wired and sometimes it doesn't. > Refreshing the consuming bundle's package imports after startup always > works to get the wiring done right. > > Consider the following bundles: > > Bundle A (ID: 200) > - Export-Package: org.foo;version=1.0.0 > > Bundle B (ID: 210) > - Import-Package: org.foo;version="[1.0,2)" > - Export-Package: org.bar;version=1.0.0 > > Bundle C (ID: 500) > - Import-Package: > org.foo;version="[1.0,2)",org.bar;version="[1.0,2)";resolution:=optional > > All bundles have the same startlevel (20), in case it matters (?). > > Our use-case is that Bundle C used to use an API provided by Bundle A, > which got improved and extended into a new API provided by Bundle B. > Not all installations provide Bundle B, but all provide Bundle A. > Bundle C now prefers the optionally available API of Bundle B but > falls back to the API provided by Bundle A if Bundle B is not > available. > > I think the usage of optional imports is reasonable here, or are there > alternatives besides using dynamic imports? > > Thanks, > > - Dirk > > - > To unsubscribe, e-mail: users-unsubscr...@felix.apache.org > For additional commands, e-mail: users-h...@felix.apache.org > >