karaf-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Timothy Ward <tim.w...@paremus.com>
Subject Re: Class resolved/found on Karaf start but not on bundle restart
Date Mon, 04 Sep 2017 08:51:46 GMT
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.


Tim Ward

> On 1 Sep 2017r , at 23:26, Kevin Schmidt <ktschmidt@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"
> 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
> 	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

View raw message