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

It seems to me that you have several misconceptions about the OSGi modularity layer:

   * Import-Package and Require-Bundle have nothing to do with the life
     cycle (i.e., activation) of a bundle; they are resolve-time issues
   * Import-Package does not create an unversioned, open bucket for
     classes. Packages resolved to Import-Packages are explicitly
     assumed to be self-contained. And it is also possible to declare
     groupings of the self-contained packages using "uses" constraints,
     to prevent different packages from different bundles to be mixed
     and matched. Still, it is never the case that a single package
     will be mixed from multiple bundles via
     Import-Package/Export-Package. Additionally, imported/exported
     packages are fully versioned and bundles can provide and use
     different versions at the same time within the same VM; the only
     limitation is that a given bundle cannot see two versions of the
     same package at the same time, but two different bundles can each
     see a different version without any difficulty.
   * Services are not singletons. Services can also be versioned in the
     sense that two different providers can use and export different
     versions of the service package; thus, different versions of the
     service may appear in the service registry at the same time.
     However, bundles will only be able to see the services which match
     the version of the service packages that they have imported.
   * A bundle is not a closed collection of code, but can be extended
     with fragments.

-> richard

Alex Blewitt wrote:
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.


equinox-dev mailing list