Hi Kevin,

This problem occurs because you have incorrectly marked the import for the 
“com.foo.interfaces” package as “resolution:=optional”. This package is *not* 
optional as a type from it is is injected into your blueprint bean which in 
turn means that the type must be loadable for your bundle to start.

When you mark a package import as optional then the OSGi framework is at 
liberty to not wire this package when resolving your bundle. In this case the 
refresh operation is either making the package that you want unavailable, or 
incompatible with the rest of your class space. Either way optional package 
imports are very difficult to do correctly, and usually require you to 
segregate a whole code path. You must then load this code path defensively 
using a try/catch ClassNotFoundException and be prepared for it not to exist.

Note that optional services are much easier to deal with than optional 
packages. In your case it will simply result in an empty reference list.

See also, this talk on optionality in OSGi that I gave several years ago 
<https://www.slideshare.net/mfrancis/when-is-optional-really-optional-tim-ward>.
 Sadly blueprint 1.1 never really happened as nobody was sufficiently 
interested in updating the standard.

Regards,

Tim Ward

> On 1 Sep 2017r , at 23:26, Kevin Schmidt <ktschm...@gmail.com> wrote:
> 
> Hi,
> 
> I have a strange problem with class resolution that is befuddling me.
> 
> I have a bundle A that uses services from other bundles B and C that 
> implement an interface I.  Bundle A also uses classes from bundle D.  I am 
> using blueprint for bundle A and have a reference-list defined as such:
> 
> <reference-list id="svcs" interface="com.foo.interfaces.I" 
> member-type="service-object" availability="optional"/>
> 
> And this is injected into a bean instantiated from a class found in bundle D, 
> the bean itself registered as a service.
> 
> When I start Karaf (4.1.1) all bundles start just fine and everything works.  
> The services implementing interface I from bundles B and C are all in the 
> reference-list as expected.  And I am able to restart bundle A and everything 
> comes back up fine.
> 
> However, if I do something as simple as refreshing bundle D, bundle A fails 
> to start indicating a ClassNotFoundException for interface I.  Specifically:
> 
> Unable to start blueprint container for bundle 
> com.foo.a.service/10.0.0.SNAPSHOT
> org.osgi.service.blueprint.container.ComponentDefinitionException: 
> org.osgi.service.blueprint.container.ComponentDefinitionException: Unable to 
> load class com.foo.a.Service from recipe BeanRecipe[name='serviceA']
>       at 
> org.apache.aries.blueprint.container.ServiceRecipe.createService(ServiceRecipe.java:310)[23:org.apache.aries.blueprint.core:1.8.0]
> ...
> Caused by: java.lang.ClassNotFoundException: com.foo.interfaces.I not found 
> by com.foo.a.service [401]
>       at 
> org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1550)[org.apache.felix.framework-5.6.2.jar:]
>       at 
> org.apache.felix.framework.BundleWiringImpl.access$200(BundleWiringImpl.java:79)[org.apache.felix.framework-5.6.2.jar:]
>       at 
> org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1958)[org.apache.felix.framework-5.6.2.jar:]
>       at java.lang.ClassLoader.loadClass(ClassLoader.java:357)[:1.8.0_77]
>       at 
> org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1925)[org.apache.felix.framework-5.6.2.jar:]
>       at 
> org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:978)[org.apache.felix.framework-5.6.2.jar:]
>       at 
> org.apache.aries.blueprint.container.BlueprintContainerImpl.loadClass(BlueprintContainerImpl.java:468)[23:org.apache.aries.blueprint.core:1.8.0]
>       at 
> org.apache.aries.blueprint.container.GenericType.parse(GenericType.java:137)[23:org.apache.aries.blueprint.core:1.8.0]
>       at 
> org.apache.aries.blueprint.container.AbstractServiceReferenceRecipe.loadType(AbstractServiceReferenceRecipe.java:307)[23:org.apache.aries.blueprint.core:1.8.0]
> 
> However, if I look at the headers for bundle A (#401), it shows the import of 
> the package interface I is in is resolved, e.g. the following line in the 
> imports is in black:
> 
> com.foo.interfaces;resolution:=optional,
> 
> If the headers indicates the import is resolved ok, and at Karaf startup that 
> import found the interface I, why would it fail when bundle D is refreshed?
> 
> Yes, I'm aware that if com.foo.interfaces was exported from another bundle 
> that could cause problems, and I'm double checking everything to make sure 
> that isn't the case, but I don't think there is another export of it.
> 
> How can I diagnose what where bundle A has resolved that import from and why 
> it thinks interface I cannot be found?  bundle:diag just reports the same 
> stack trace I showed above.
> 
> Using an earlier install of more of less the same bundles (but not completely 
> identical, so yes, that is a variable) in Karaf 3.0.6, everything works fine. 
>  I can restart bundle A and refresh bundle D and bundle A finds the interface 
> I and starts fine.  Did something change with Karaf 4 or the blueprint used 
> by it?
> 
> Thanks,
> 
> Kevin
> 
> 

Reply via email to