Don't look for what you can do with capabilities, look what capabilities do for
you :-)
The primary reason we have this model is that we tried to prevent runtime
errors. We wanted to establish a dependency graph that was not just about
depending on artifacts, but one that could specify more than that as well has
handle some of the cases that do not fit well in a transitive graph like Maven.
So never use a req/cap _unless you have a real problem_. They are a pain in the
ass and should only be used to reduce a bigger pain. So I consider your musings
about the granularity are largely moot. What pain would be mitigated by
describing a plus operator with a capability? It seems extremely unlikely that
you would compose things on that level? Same for localized strings. Clearly a
bundle that provides a German translation of a component would have a
capability for this so that it can be selected in the runtime. But is strings
would be too low.
The far majority of use cases of the req/cap model are the OSGi headers.
Require-Bundle, Import-Package, Expert-Package, Require-ExecutionEnvironment,
etc. We needed something else than Maven's transitive dependency graph because
OSGi tried to make a component model. The idea was that you assembled
components that communicated via services. Using a transitive dependency model
based on components, quickly kills reusability because the transitive
dependency tree explodes. I.e. Maven doesn't download the internet, people
download the internet ... And a large transitive graph kills the fun of reuse
as anybody knows that has to keep dragging more and more dependencies to the
installation. Worse, large graphs inevitably have version issues, that most
people actually tape over. So instead, we required a service and its package,
and allowed different components to provide an implementation. That model works
very well for the reusability but it sucks for dependencies since there no
longer is a singular dependency graph. At every dependency on a service you can
have many implementations. To create a runtime, you need to make lots of
decisions about the implementations. Since each implementation has its own
dependency graph, this is complicated, and big part of why the model can be
painful.
One thing that drove the model for me personally was my addiction to the Mac.
This was early 2000 and Windows was king. More and more applications went full
Windows because it was too hard to support them on Mac or the beginning Linux.
I was hoping that a reusable market for component with specified interfaces
would make it easy to support many platforms, or at least allow others to fill
in he gaps. I also really disliked the idea that you would provide groups of
bundles, aka features. These bundles have to live together in one framework &
VM and there are very tight dependencies that need to be managed. The problem
with features is that they don't solve the problem of combining bundles, they
just more the problem up one level and then make the problem even harder.
Therefore the idea of a resolver was born that would take _all_ requirements
into account for a given runtime. A resolver that would be able to verify that
each component would have everything it needed when deployed, preventing
dreaded 'Class Not Found' errors. At the core is basic software engineering
that makes things work in all cases, not only the ones tested.
So what are the pains the model mitigates:
– Transitive dependencies based on identity (osgi.bundle). This is more or less
the Maven model support
– Matching providers to consumers that do not have a direct dependency on
(osgi.extender, osgi.service, osgi.package, osgi.ee, osgi.contract)
– Hardware dependencies. Since you can provide capabilities from the framework,
an installation can provide unique capabilities. I.e. capabilities are
explicitly not restricted to bundles alone as you claim. This is very
interesting when you do embedded development. I.e. you could have a bundle that
requires a high resolution screen.
You seem to worry about incompatible capabilities and requirements setup.
Don't. The idea is that they are used to make sure that _before_ you deploy
your application all requirements and capabilities are checked. If you start to
do weird things and you get weird results, they invariably end in resolving
errors. As I said before, the basic idea is to minimize the use of this
technique as much as possible. For normal OSGi use, you rarely need to make
your own namespaces. When working on JPM I developed the annotations to create
requirements and capabilities directly from the code. This is a great feature
and I am happy it got standardized in R6 but you have to be extremely careful
to not go ballistic because it is so easy to use. Don't start your own
namespace until you're absolutely sure what you're doing and there is no Java
way to do it. As you seem to sense, using too many different custom namespaces
quickly turn a system into a complex nightmare.
That is why I've saved one of the very interesting qualities as last.
Capabilities carry properties and the properties of the wired capabilities are
easy to traverse in runtime with OSGi API. This makes them extremely attractive
to carry data contributed from different resources. I am quite addicted to this
but I realize it is dangerous because you can easily go too far and create a
mess. Recently, I used this to provide a bloom filter on class names on
exported packages so we can search them from repo data, and another use case
was to provide plugin metadata in bnd so you can now insert plugins from a
menu. Actually using a feature I added years ago that makes sure that any bnd
bundles in Bndtools are accessible to the plugins class loaders, which was also
based on a special capability.
So it depends on the Modularity Maturity Model (MMM) you are ... If you're very
comfortable with OSGi and your build runs very smooth then this technique can
be very useful since it allows you to find many problems very early. However,
it does require a maturity of the build that is not common in our industry. And
if there is one thing the MMM teaches is that you cannot skip the different
phases.
Generally, the best advice I have is to enjoy the many automatic fruits given
to you by bnd, based on the OSGi cap/req model. However, don't start eagerly
_looking for problems_ that fit this solution. When you have a new pain,
sometimes this is an awesome technique. Or not.
Hope this helps.
Kind regards,
Peter Kriens
> On 23 Aug 2020, at 07:01, Zyle Moore via osgi-dev <[email protected]>
> wrote:
>
> I'm trying to familiarize myself with the Capability-Requirement model.
>
> Each Capability has a Namespace, Name, and Version. The example given in the
> documentation is
>
> @Capability(
> namespace=ExtenderNamespace.EXTENDER_NAMESPACE,// "osgi.extender"
> name="osgi.component",
> version="1.3.0")
>
> This can be read as "I provide version 1.3.0 of the osgi.component capability
> of the osgi.extender namespace". There are some other common namespaces OSGi
> provides; osgi.implementation is for implementations of a specification or
> contract, and osgi.service is used to indicate that a service can be
> registered.
>
> osgi.implementation;
> osgi.implementation="osgi.cm <http://osgi.cm/>";
> version:Version="1.6"
>
> osgi.service;
> objectClass:List<String>="org.osgi.service.cm.ConfigurationAdmin"
>
> At this point, the namespace seems like a generic idea, or concept. I'm
> looking for an _implementation_ of a spec. I'm looking for a _service_ that's
> registered. These kind of overlap to me though, because an implementation of
> osgi.cm <http://osgi.cm/> seemingly includes an implementation of the
> ConfigurationAdmin service. Because these are in two different namespaces, it
> seems like there could be misconfigurations. For instance if a bundle
> provided the ConfigurationAdmin osgi.service Capability, it may not
> necessarily provide the osgi.cm <http://osgi.cm/> osgi.implementation
> Capability. The reverse may have the same issue, unless the osgi.cm
> <http://osgi.cm/> osgi.implementation Capability specifically implied the
> ConfigurationAdmin osgi.service Capability.
>
> Another example mentioned in Core 3.3.5 is for a screen with a known
> resolution.
>
> com.acme.screen;
> width:Long=640;
> height:Long=480;
> card=GeForce
>
> At this point, a "screen with a resolution" is at the same conceptual level
> as a "specification implementation" or "registered service". A screen with a
> resolution is a Capability, a specification implementation is a Capability, a
> registered service is a Capability. They are all things that a Bundle can
> provide, or require, which I believe is the conceptual level they all live
> at; provided by a Bundle, or required by a Bundle. Maybe more along the lines
> of provided by a Resource or required by a Resource, but Bundle should be
> good enough for now.
>
> So what other concepts or ideas could be provided by a Bundle, or required by
> a Bundle? Would a constant String value be something that a Bundle could
> provide or require? It seems like it, but it also doesn't seem like something
> that we would want to put in a Capability. It seems too small a concept, or
> too specific a concept to warrant a Capability. What about a localized
> String? It's a bit of a larger concept, as it includes a locale, a key, as
> well as the localized string. Something about it though still doesn't seem to
> fit well as a Capability. Perhaps it's because there's so many degrees of
> variability with the concept. An application could probably have dozens,
> hundreds, or thousands of localized strings, even within a single Bundle. But
> I wouldn't necessarily expect a Bundle to provide dozens of screen
> capabilities, let alone hundreds or thousands. Even though there are fewer
> attributes, the concept seems big enough, or complex enough, to warrant a
> Capability (width/height vs. locale, key, localized value) that can be
> Required.
>
> In the case of a Calculator application, it feels kind of weird if we were to
> have an addition, subtraction, multiplication, and division Capability. For
> some reason though, an arithmetic Capability feels more natural, same with a
> trigonometry Capability, or a geometry Capability. They exist on a level
> above the individual operations, being made up of multiple operations to
> round out the idea.
>
> In the case of a fully integrated development environment application, it
> seems like it would require so many capabilities (reading, parsing, creating,
> formatting, highlighting, source control, permissions, accelerated graphics,
> pluggable third-party components, native code execution) that it seems like
> it would become hard to manage.
>
> The question I have then, is how granular should Capabilities be? Is
> addition, or multiplication, or a specific localized string too small a
> concept for a Capability? Is a Requirement for "a development environment
> with (features)" too large a concept?
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev