osgi / osgi

OSGi Specification Project Build Repository. Specification, API, implementation, and TCK source code.
https://docs.osgi.org/
Apache License 2.0
101 stars 40 forks source link

Add requirements and capabilities to the OSGi Feature specification #556

Open bosschaert opened 1 year ago

bosschaert commented 1 year ago

OSGi Feature models inherit all requirements and capabilities from the bundles specified in them.

However there are use-cases for providing additional caps/reqs over and above what the bundles provide.

For example a collection of bundles could be providing an implementation of some technology, and as such should be providing the osgi.implementation capability. There is no single bundle provides this, its the combination of bundles that does. In such case providing the capability on the level of a feature binding these bundles together could be useful.

An example for additional requirements comes from the feature launcher area. A feature might have a requirement to run in a certain environment, which could be a certain Java version running a certain OSGi version, but it might also for example require existing OSGi technology to be present in its target runtime, such as Declarative Services, which can be done by adding a requirement on the osgi.extender=osgi.component capability.

Being able to declare additional capabilities and requirements in OSGi Features was originally part of the Feature specification design, but it was removed due to time constraints. This issue here is to now go ahead and bring them in.

bjhargrave commented 1 year ago

Such requirements and capabilities would not be visible in the framework wiring at runtime since features are not artifacts the framework is aware of. So no bundle could depend upon a feature capability. So adding req/cap to features is only useful for feature resolving including feature merges.

bosschaert commented 1 year ago

A synthesized bundle could be added to the framework by an entity like the launcher that contains the extra capabilities so that the runtime resolver sees them, but yes my primary use-case is around resolution of features.

timothyjward commented 1 year ago

my primary use-case is around resolution of features.

I think that for Feature resolution having feature-level requirements and capabilities is probably superfluous. The resolving party will have to fully process every bundle to be sure that things really do resolve.

The situation where it may be helpful is when providing a non-resolved runtime and you want to express a high level dependency, e.g. "this feature provides a Servlet Whiteboard" and "this feature needs a servlet whiteboard".

The existing specification allows for custom extensions, and I have used one to provide a basic "require bundle" type dependency by identity. If this could be made less brittle as part of the standard then that would be nice, but only if the additional complexity is not too high.

laeubi commented 1 year ago

I'd like to CC @grgrzybek here as it was discussed in the last spec call and I think Apache Karaf is a perfect example of an eco-system where feature requirement are important to the runtime and there are a lot of big companies actually using Karaf and it is just a perfect example on how one can really leverage the full power of OSGi.

So I'd like to encourage everyone to think a bit outside of the box, probably trying it it live (maybe @grgrzybek can give a short live-demo at next spec call as well?), especially the karaf-console is just great :100:

Such requirements and capabilities would not be visible in the framework wiring at runtime since features are not artifacts the framework is aware of.

While the "framework wiring" to its bare minimum only knows about bundles, the same concept can easily be expanded to Features as well, and there are currently two concepts:

Both of them provide things a bundle can not describe:

So features are user visible items shaped in a way the user can understand and manage without needing to know the details (bundles, configs, other features,...) but the share the same concepts e.g. features are part of repositories. and the might require other features or other "requirements" and they might provide capabilities (even to bundles) so one likes to resolve them to find whats missing...

grgrzybek commented 1 year ago

Thanks for notice @laeubi. This week I'll show some examples about how Karaf deals with the features and their reqs/caps.

jbonofre commented 1 year ago

FYI, req/cap support has been added on Features Service starting from Karaf 4.x. Actually, Karaf 4.x was a big refactoring of the features service, introducing the new features resolver (based on Felix Resolver). It collects the capabilities from features (aggregating bundles capabilities and features ) and then use these capabilities when installing feature has requirements (from bundles or feature itself again). It's pretty powerful but it also has some drawbacks (for me, the problem is mostly about the requirements definitions which are not always complete, making the state unpredictable depending of the features installed, that's why we plan to add a "flat" resolver support to simplify the resolution). As I worked (and still working on it), I would be more than happy to participate in this feature specification effort.

grgrzybek commented 1 year ago

Here's an example repository of Karaf features:

<features name="test-features" xmlns="http://karaf.apache.org/xmlns/features/v1.5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.5.0 https://karaf.apache.org/xmlns/features/v1.5.0">

    <feature name="f1">
        <bundle>mvn:grgr.test/bundle-hs1/0.1.0.RELEASE</bundle>
        <requirement>
            servlet.contract
        </requirement>
    </feature>

    <feature name="f2">
        <bundle>mvn:jakarta.servlet/jakarta.servlet-api/4.0.4</bundle>
        <capability>
            servlet.contract;provider:=Jakarta
        </capability>
    </feature>

    <feature name="f3">
        <bundle>mvn:javax.servlet/javax.servlet-api/4.0.1</bundle>
        <capability>
            servlet.contract;provider:=Javax
        </capability>
    </feature>

</features>

In Karaf console we can do either of these:

karaf@root()> feature:install -v -t f1 f2                                                                                                                                                                                                      
Adding features: f1/[0,0.0.0],f2/[0,0.0.0]
Changes to perform:
  Region: root
    Bundles to install:
      mvn:grgr.test/bundle-hs1/0.1.0.RELEASE
      mvn:jakarta.servlet/jakarta.servlet-api/4.0.4
karaf@root()> feature:install -v -t f1 f3
Adding features: f1/[0,0.0.0],f3/[0,0.0.0]
Changes to perform:
  Region: root
    Bundles to install:
      mvn:grgr.test/bundle-hs1/0.1.0.RELEASE
      mvn:javax.servlet/javax.servlet-api/4.0.1

But we can't just install f1 feature:

karaf@root()> feature:install -v -t f1
Adding features: f1/[0,0.0.0]
org.apache.felix.resolver.reason.ReasonException: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=f1; type=karaf.feature; version="[0,0.0.0]"; filter:="(&(osgi.identity=f1)(type=karaf.feature)(version>=0.0.0)(version<=0.0.0))" [caused by: Unable to resolve f1/0.0.0: missing requirement [f1/0.0.0] servlet.contract]
    at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1341)
    at org.apache.felix.resolver.ResolverImpl.doResolve(ResolverImpl.java:433)
    at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:420)
    at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:374)
    at org.apache.karaf.features.internal.region.SubsystemResolver.resolve(SubsystemResolver.java:256)
    at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:399)
    at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1069)
    at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:1004)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.apache.felix.resolver.reason.ReasonException: Unable to resolve f1/0.0.0: missing requirement [f1/0.0.0] servlet.contract
    at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1341)
    ... 12 more
Error executing command: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=f1; type=karaf.feature; version="[0,0.0.0]"; filter:="(&(osgi.identity=f1)(type=karaf.feature)(version>=0.0.0)(version<=0.0.0))" [caused by: Unable to resolve f1/0.0.0: missing requirement [f1/0.0.0] servlet.contract]

When resolving (atomically) the features, Karaf's feature service takes features' reqs/caps into account (passing these to ordinary Felix resolver with custom resolution context). Of course bundles' reqs/caps are also taken into account.

This is just a real world example of how Karaf deals with reqs/caps at feature level and it may, but doesn't have to impact the design of OSGi feature service.

juergen-albert commented 1 year ago

@bosschaert will provide Strawman API for this suggested change. ;-)

grgrzybek commented 1 year ago

Karaf Feature bundle replacement: https://issues.apache.org/jira/browse/KARAF-5376?focusedCommentId=16431939&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16431939

laeubi commented 1 year ago

@grgrzybek I think that what in Karaf is the Feature Service would really be a great addition to the feature spec: https://github.com/apache/karaf/blob/a4d055ab4a3bfc9f2f05145c6b0a436ba0b28efd/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java

the feature is blown up a bit but basically something like:

github-actions[bot] commented 7 months ago

This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. If you feel this is something you could contribute, please have a look at our Contributor Guide. Thank you for your contribution.

laeubi commented 7 months ago

Still an issue....