OSGi: What's the difference between Import-Package/Export-Package and Require-Capability/Provide Capability?
When we started with OSGi in 1998 we had some clear requirements but of course, no clear view of what would come out of it. So we started to explicitly model the requirements and capabilities we had: packages. The Import-Package requires a capability and that capability is provided by an Export-Package.
In 2003 Eclipse wanted to start using OSGi but they need a facility to require another bundle, they did not like the idea of exporting and importing all their packages. Actually, at that time they failed to see the benefit of packages. To satisfy them we added Require-Bundle and Fragment-Host (another one of their desires that turned out not to be so good.)
After we specified OSGi 4.x with these extensions we starting thinking about a repository, Richard had developed the Oscar Bundle Repository. Analyzing the situation with the new headers in OSGi 4.0 it became clear that the implementation of Import-Package looked a lot like Require-Bundle, and even resembled Fragment-Host processing.
In 2006 Richard S. Hall and I wrote RFC 112 proposing a more generic model that captured the semantics of the existing dependency model but was not specific for each type of requirement. I.e. for the Framework resolver the Import-Package and Require-Bundle only differ in their namespace. Thinking of Import-Package as a generic requirement and Export-Package as a generic capability made the repository model extremely simple. Even better, it was extendable since we could always add more namespaces. This made the resolver completely independent of the actual namespaces used.
After some very heated discussions, the OSGi Core Platform Expert Group decided to accept the basic idea and developed the Requirements and Capabilities specifications. Although this was originally a model for the repository, it turned out to be highly useful for the Framework itself. We decided therefore to adapt the existing specifications to this model. OSGi 4.3 internally models the Import-Package, Export-Package, Require-Bundle, etc. as requirements and capabilities of a resource (the bundle). For backward compatibility, we kept the existing headers but they are internally translated to requirements and capabilities.
Then finally to the answer to your question. Over time the OSGi specifications added more and more namespaces. A namespace is like a type for a Requirement and a Capability. It defines the semantics of a set of properties of a Capability in that namespace. A Requirement is a filter expression that is asserted on those properties. A Resource has a set of Capabilities that are provided to the runtime when all its Requirements are satisfied. It is the task of the Resolver to find a set of resources that are all satisfied with each other's capabilities and capabilities provided by the runtime.
For example, we added the osgi.ee
namespace that defines exactly on what VM's the bundle can run. We added the osgi.extender
namespace that models a dependency on an external program like the Service Component Runtime (SCR). Most SCR components do not require any package from the SCR itself, we tried hard to make them as independent as possible. However, a SCR component will sit useless unless some bundle in the runtime provides the SCR functionality. Notice that this cannot use Require-Bundle because there are multiple implementations of SCR. I think there are about 20 namespaces. Each namespace is defined in a Namespace
class.
This model has given the OSGi a number of advantages:
- Cohesion Although the specification has added many namespaces the resolver implementations never had to change since they worked on the generic model.
- Fine-Grained OSGi bundles are unique in how they describe their dependencies in a very fine-grained way. All module systems I know tend to use the simple module-to-module dependency that does not allow substitution.
- Flexible Since the Framework reifies the dependencies between bundles it is possible in runtime to leverage these dependencies. For example, in OSGi enRoute I linked a bundle to its web page traversing these runtime wirings.
I personally consider the Requirements and Capability model of OSGi one of its best kept secrets. As far as I can see it could be used in a lot of areas to improve many development projects into the world of software engineering.
The only disappointing part in this question is that I thought we'd described this pretty well in the Core specification? :-)
The requirements and capabilities model is an extension of the Import/Export package model. Actually you can express a package import as a requirement and a package export as a capability.
Exporting / Importing packages allows for loose coupling. You export an API and the client imports it. This way the client only needs to know about the API so loose coupling is achieved.
At a later stage when you assemble the application out of bundles this loose coupling makes it difficult to automate the process.
If you just provide your client bundle to a resolver then it can only automatically find that you need the bundle that provides the API. If the implementation of the API is in a different bundle then the resolver has no way to know that you need it.
This is where requirements can help. Let's take the HTTP Whiteboard model. A bundle that want to publish a servlet needs to import the servlet api package but is also needs to express that it wants an implementation of the osgi http whiteboard.
This can be expressed by the requirement with namespace="osgi.implementation", name="osgi.http", version="1.1.0". As this is difficult to writer by hand there is annotation support for it.
@HttpWhiteboardServletPattern("/myservlet")
@Component(service = Servlet.class)
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.getWriter().println("Hello");
}
}
The annotation @HttpWhiteboardServletPattern indirectly translates to the requirement above.
So when you build a bundle with this class it will import the servlet api package and also have a requirement for an http whiteboard implementation.
Now if you look at an implementation bundle like the felix http service you will see that it provide the capability for the whiteboard impl.
So if you have a OSGi repository with your bundle, the servlet API and the felix http service. Then the resolver can provide you with a complete application if you only give it your bundle.