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

Reply via email to