Using Service Component Runtime

2019-06-08 06:47发布

I goal is to remove dependencies on OSGi from my bundles. I use felix (v 4.2.1) as impl and run it embeddable. I install org.apache.felix.scr (v. 1.6.2) bundle to have Service Component Runtime support. But when I run

 ServiceReference ref = bundleContext().getServiceReference(ScrService.class.getName());
 ScrService s = (ScrService) bundleContext().getService(ref);

I get ClassCastException: org.apache.felix.scr.impl.ComponentRegistry cannot be cast to org.apache.felix.scr.ScrService.

Okay. I will modify System Packages.

config.put(Constants.FRAMEWORK_SYSTEMPACKAGES, "org.apache.felix.scr");

Now I get

Caused by: org.osgi.framework.BundleException: Unresolved constraint in bundle org.apache.felix.scr [1]: Unable to resolve 1.0: missing requirement [1.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.4.0)(!(version>=2.0.0)))
        at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3974)
        at org.apache.felix.framework.Felix.startBundle(Felix.java:2037)
        at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)
        at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:942)
        at com.copyright.rup.communications.felix.Felix.addBundle(Felix.java:86)
        ... 28 more

How can I solve it?

1条回答
萌系小妹纸
2楼-- · 2019-06-08 07:22

I suspect your first block where you try to get hold of ScrService is on the embedding side (i.e. outside of the framework, not from within an installed bundle).

If this is the case, then you have two copies of the ScrService - one loaded from your embedding code's ClassLoader and one loaded by ClassLoader of the scr bundle when it's resolved by the framework. This is why you're seeing the ClassCastException.

You can just export what the SCR bundle's exports from the framework bundle.

Section 3.8, page 51 of the OSGi Core spec v5 states that in resolution of bundle wiring if a module has both import and export definitions of the same package then the framework will first try to resolve externally and if successful discard the overlapping export definition.

So copy the SCR runtime bundle's Export-Package manifest header as a framework property:

properties.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, 
        "org.ops4j.pax.url.mvn,org.apache.felix.scr;uses:=\"org.osgi.framework," +
        "org.osgi.service.component\";version=\"1.7\"," +
        "org.apache.felix.scr.component;status=provisional;mandatory:=status;" +
        "uses:=\"org.osgi.service.component\";version=\"1.0\"," +
        "org.osgi.service.component;uses:=\"org.osgi.framework\";version=\"1.2\"");

//Which you pass to the FrameworkFactory ...

ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);
Iterator<FrameworkFactory> iterator = loader.iterator();
Framework framework = iterator.next().newFramework(properties);
framework.start();

A couple of things to note:

  • If you're not already using ConfigurationAdmin, then also install org.osgi.compendium to ensure you have at least have the API classes for org.osgi.service.cm.* and org.osgi.service.metatype*, AFAIK these are necessary for the SCR runtime.

  • You shouldn't use Constants.FRAMEWORK_SYSTEMPACKAGES unless you're seriously customising the actual framework, instead you'd probably want to use Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA to extend what is exported by the framework bundle. (The framework implementations have pretty good defaults for FRAMEWORK_SYSTEMPACKAGES and it's normally unnecessary to modify this when embedding).

查看更多
登录 后发表回答