Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a way to override (required) capabilities generated from DS annotations #2429

Closed
oliverlietz opened this issue Apr 24, 2018 · 17 comments

Comments

@oliverlietz
Copy link

I'm currently working on a larger task where I adjust all required and provided capabilities in Apache Sling to allow Karaf/Sling feature resolution: SLING-7546 Take requirements for services into account.

We have one component, OsgiObservationBridge, which translates resource changes/events to OSGi Event Admin events for legacy consumers. This component should only get active when an EventHandler is present.

bnd creates for

    @Reference(name = "handlers",
            cardinality=ReferenceCardinality.AT_LEAST_ONE,
            policy=ReferencePolicy.DYNAMIC,
            service=EventHandler.class,
            target="(|(event.topics=org/apache/sling/api/resource/Resource/*)(event.topics=org/apache/sling/api/resource/ResourceProvider/*))")

the (technical correct) required capability

osgi.service;filter:="(objectClass=org.osgi.service.event.EventHandler)";effective:=active;cardinality:=multiple

But of course the required capability should be optional:

osgi.service;filter:="(objectClass=org.osgi.service.event.EventHandler)";effective:=active;cardinality:=multiple;resolution:=optional

There is no way to override this capability with an instruction in a bnd.bnd file. All capabilities are added to MANIFEST.MF.

@bjhargrave
Copy link
Member

Did you try -dsannotations-options: norequirements in your bnd file?

the (technical correct) required capability

osgi.service;filter:="(objectClass=org.osgi.service.event.EventHandler)";effective:=active;cardinality:=multiple

Note, the technically correct requirement is optional with respect to framework resolving since it is effective:=active.

@oliverlietz
Copy link
Author

Did you try -dsannotations-options: norequirements in your bnd file?

This disables requirements for all DS components of the bundle which is not desired.

Note, the technically correct requirement is optional with respect to framework resolving since it is effective:=active.

Karaf's feature resolver behaves differently than framework resolving (see SubsystemResolveContext):

    @Override
    public boolean isEffective(Requirement requirement) {
        boolean isServiceReq = ServiceNamespace.SERVICE_NAMESPACE.equals(requirement.getNamespace());
        return !(isServiceReq && FeaturesService.ServiceRequirementsBehavior.Disable == serviceRequirements);
    }

Still need a way to get rid of the required capability.

@bjhargrave
Copy link
Member

This disables requirements for all DS components of the bundle which is not desired.

This is the only level of control we have for generation of requirements. There is no way to control it for a specific reference on a component. I imagine a @NoRequirement annotation could be defined by Bnd to do this, but someone would need to make the PR to propose such a change.

@oliverlietz
Copy link
Author

I'm in favor of a more general approach (instructions in bnd file override generated ones), but I struggle to find a place where to hook in such logic. Source lacks documentation and I'm not much familiar with it yet.

@bjhargrave
Copy link
Member

You could write your own Analyzer plugin which can post-process the Require-Capability header value to remove the generated requirement in preference to your requirement from the bnd file.

@oliverlietz
Copy link
Author

Sure, but that wouldn't help others having same or similar issues (found when searching for a solution).
The quickest but least sustainable way is removing DS from OsgiObservationBridge and using low-level OSGi API.

@bjhargrave
Copy link
Member

cardinality=ReferenceCardinality.AT_LEAST_ONE in the example means the service requirement is not optional.

@bjhargrave
Copy link
Member

Closing.

@rotty3000
Copy link
Contributor

rotty3000 commented May 11, 2018 via email

@oliverlietz
Copy link
Author

@bjhargrave, what's the point? No EventHandler with matching event.topics is totally fine for the bundle and shouldn't prevent resolving.

@bjhargrave
Copy link
Member

No EventHandler with matching event.topics is totally fine for the bundle and shouldn't prevent resolving.

The component declares cardinality=ReferenceCardinality.AT_LEAST_ONE which means zero is not acceptable to the component. So the service requirement for the component is not optional.

Further more, effective:=active requirements never prevent bundles from resolving in the framework.

@oliverlietz
Copy link
Author

The component declares cardinality=ReferenceCardinality.AT_LEAST_ONE which means zero is not acceptable to the component. So the service requirement for the component is not optional.

Right, the component should only get activated when at least one EventHandler with matching event.topics is present.

Further more, effective:=active requirements never prevent bundles from resolving in the framework.

See my comment regarding Karaf resolver – Karaf doesn't resolve a feature containing the bundle with OsgiObservationBridge.

@timothyjward
Copy link
Contributor

Right, the component should only get activated when at least one EventHandler with matching event.topics is present.

Which means that from this bundle’s perspective the EventHandler service is mandatory. This is an implementation decision that the author of the bundle has made to use DS to control lifecycle at the expense of not supporting a zero entry whiteboard.

Karaf doesn’t resolve a feature containing the bundle with OSGiObservationBridge

That’s because you’ve got the requirements in the feature backwards. The feature should not require the bridge bundle. The bundle that provides the EventHandler should require an osgi.implementation capability which is provided by the bridge. That way the bridge is deployed as needed, and its service requirement is satisfied by the bundle that requires the implementation capability.

This is the standard pattern for whiteboards in OSGi (see also the Http and JAX-RS whiteboards).

@oliverlietz
Copy link
Author

@timothyjward, thanks for your explanation, but OSGiObservationBridge is for supporting legacy clients in a real world application and I'm fine with rewriting it without using DS (see my comment) if bnd is unable to provide support for this and similar use cases – but looks like @rotty3000 is right (testing with 4.0.0-SNAPSHOT right now). Thanks!

@realPyR3X
Copy link

I'm also having this issue and looking for a way to resolve it. I have a component I'd like to remain in the resolve state until AT_LEAST_ONE is satisfied and the component activated. However, Karaf will not deploy my feature that includes this bundle for that to happen.

@djencks
Copy link
Contributor

djencks commented Jan 9, 2019 via email

@oliverlietz
Copy link
Author

I have just added a plugin for bnd to remove parameters from bundle headers, see FELIX-6019.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants