[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[equinox-dev] RequiresBundle, ImportPackage and virtual providers

I was speaking with John Fallows after the conference regarding the
differences between Requires-Bundle and Import-Package, and what they
can/can't be used for. From what I currently understand,
Requires-Bundle allows an ordering between two implementations such
that one implementation must be brought up/started before another; and
that regardless of the contents of the bundle, I get access to only
what that bundle provides to me.

On the other hand, if I use Import-Package, I can gain access to
classs defined in that package, regardless of which bundle they happen
to be in. This is handy if refactorings have occured where classes
have moved between bundles but have the old name. However,
Import-Package is looser since it's not necessarily the case that the
other bundle has been started by the time the requester needs access
to it.

It sems to me like Import-Package is being promoted since it allows a
looser coupling between the client bundle and the server bundle (for
want of better terminology). In other words, with something like an
XML parser, I could have an import for javax.xml, and then I could
substitute either Xerces or Crimson since both would export those
packages.

However, I don't think that last approach works tremendously well.
Firstly, the import package is specific to a particular package, and
it's quite likely that the implementation of the service is going to
be in a different package from the interfaces in any case. (For a
single-interface type service, it might be OK. This may be more common
in embedded OSGi environments but may not scale well to larger
systems.) Secondly, you do want to semantically ensure that an XML
service is available (though perhaps not caring which one) if you are
intending to use it, so you would need to have some kind of
relationship between bundles.

Linux packages handle this quite neatly with alternatives (on some
systems). For commonly (re)implemented packages (Java and TeX being
examples), the executables in /usr/bin are symlinks to entries in
/etc/alternatives. These are then symlinks to a particular
implementation, and you can switch between alternatives (which updates
the links in /etc/alternatives). Debian's package management system
handles this by providing different debian packages (ala bundles) that
define a dependency on a virtual package, and implementations provide
that virtual package. Clients are then expressed on the virtual
dependency, but don't specifically recommend any particular
implementation.

It seems that this would be suitable for bundles, as well. I could define:

Bundle-SymbolicName: org.example.client
Requires-Bundle: org.xml.parser

and

Bundle-SymbolicName: org.example.service.xml.parser
Provides-VirtualBundle: org.xml.parser

The bundle starting code could read in the serivce bundle, and set up
a virtual bundle for org.xml.parser that essentially was a
duplicate/symlink of org.example.service.xml.parser, which could
probably be done at bundle discovery time. This would mean that the
org.example.service.xml.parser would have to be started before
org.example.client, since it's a bundle dependency, but you've still
got the same portability between implementations that Import-Package
aims to solve.

The reason I believe this solution is more elegant than using Import-Package is:
1) It defines a lifecycle dependency, which ensures that it gets
started/stopped when the client needs it
2) It doesn't permit accidental importing of classes that happen to be
in the same package in other bundles
3) There's no ambiguity if two bundles export the same package, since
there can only be one bundle with a given symbolic name (virtual or
otherwise). Of course, some mechanism would need to be implemented to
deterministically pick between two bundles that provided the same
virtual bundle; either through versioning or singleton of the virtual
bundle
4) The implementation of the service doesn't have to be in any
particular package, just the shared interface/classes (e.g. xmlApis).
It may even be the case that these APIs are factored into their own
bundle to allow multiple implementations to use the same set of
interfaces

I think Import-Package has its uses for dealing with 'split bundles'
after a refactoring, but I think a virtual-bundle approach would be
better for decoupling client/service implementations.

Alex.