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

On 30/03/06, Peter Kriens <Peter.Kriens@xxxxxxxx> wrote:
> First I am not sure why Xerces or Crimson needs to be started? My
> assumption always was that they implement JAXP ...

It was meant as an example that would easily be understood in terms of
an interface and separate implementations, as opposed to other issues
specifically related to XML parsing.

> A client should only bind to the package it uses, in this case
> javax.xml.parsers. Initialization ordering can be handled by using the
> XML service.

This is the key problem, for me. A package is an open-ended bucket, to
which not only this bundle, but *any* bundle, can contribute classes
to. It's an implementation facet. There's nothing to stop other
bundles inserting (or attempting to replace) items in this package on
a piecemeal basis. A bundle, on the other hand, is a closed collection
of code that I can depend on as a black-box unit. A package is *not* a
black box.

It works fine in the lowest level a-service-is-just-a-single-interface
(see other comments regarding LogService) because then your package is
trivial, and there's only one interface in it. However, almost all
bundles are complex containers that can have many different aspects to
their code. You don't want to have to specify a complex service (or
indeed, not a service at all) as an open-ended package just because
that's the only way it can work. What's to stop two separate bundles
contributing overlapping code to the same package? Which one 'wins' in
that situation? Can I provide the equivalent of aspect-oriented
programming simply by replacing the contents of a package because it's
been made open by the use of liberal export/import packages?

> I am not sure I understand your comments about Linux? This sounds
> awfully close to how it works with services. I express my dependency
> on javax.xml.parsers and look for the DocumentBuilderFactory and
> SAXParserFactory services. Depending on the installed bundle set and
> imported package version I get the parser my deployer wanted me to use.

My mentioning of the Linux alternatives was another system that uses a
way of providing a loose coupling between systems that can be replaced
at run-time. But it's not the same as services. An OSGi service can be
started or stopped independently of bundles that depend on it; they
may not even be able to acquire a service, even though the package is
there. On the other hand, if I have a bundle dependency, then I can
guarantee that that bundle is started before mine is and will remain
started for the lifetime of my bundle.

> Your virtual bundle creates a meeting point to break the coupling between
> the client and the implementation. This is EXACTLY the purpose of the
> service model.

It's the same purpose, but they differ in implementation. Bundles are
explicitly tied together by their lifecycle; services aren't. Bundles
define a closed set of code which may span multiple packages without
being infected with other code; import-packages use an open set of
code which allows any bundle to contribute detritus to a package which
may be subsequently installed. Bundles can be versioned;
import-packages can't be. Furthermore, you're assuming that there is a
service here; there's no reason to assume that that's the case. I may
just want to be able to (say) parse Atom feeds, and I don't really
care how. What I want is to be able to switch implementations that
conform to a common API, *not* a common package.

> So you can have your cake and eat it too with services. You can use
> import-package which is much more robust over time than require bundle,
> and you can easily switch implementation packages by managing the set
> of installed bundles.

Yes, I believe that you are. It's not that what you say can't be done
with services (it can) but it's what else can/cannot be done. I could
have (say) an AtomParser that picked apart XML and returned me Atom
entries either as an OSGi service (imported with Import-Package), or
use the concept of virtual bundles. However, just because you can do
that in either way it doesn't mean they're equivalent. If I were using
Import-Package and the OSGi services, then I could contribute or
replace code from that service by having a second bundle with an
Export-Package. Secondly, I couldn't have two separate bundles that
depend on different versions of an AtomParser. If they were bundles, I
could have a versioned dependency so that one depended on a
Virtual-Bundle: AtomService [1.0.0,2.0.0), and then another than
bundle that depended on Virtual-Bundle: AtomService [2.0.0,3.0.0) in
the same VM. The Service-based Import-Package has (in effect) a
singleton version which prevents others from being loaded in the same
VM. Furthermore, I could use this in such a way that one bundle used
MyAtomParser, whilst another bundle used YourAtomParser, and a third
that depended on the virtual bundle AtomParser and used a
(deterministic preferred) version.

The other assumption -- that package = a service -- isn't necessarily
valid. For example, I might choose to provide interfaces for
atom.AtomParser and atom.AtomGenerator. But just because they happen
to be in the same package, it doesn't necessarily mean that they
should be co-deployed. Using Import-Package/Export-Package, how would
clients necessarily know which (sub)set of classes are used? On the
other hand, I could provide two bundles which had the same package,
and define dependencies on each of those bundles.

That's why I suggested the idea of virtual bundles. They allow the
same functionality as services, but without the potential problems.