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 <d...@apache.org> 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 <jus...@justinedelson.com>
> 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 <d...@apache.org> 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
>
>

Reply via email to