You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@karaf.apache.org by Kevin Schmidt <kt...@gmail.com> on 2017/09/01 22:26:52 UTC

Class resolved/found on Karaf start but not on bundle restart

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

Re: Class resolved/found on Karaf start but not on bundle restart

Posted by Timothy Ward <ti...@paremus.com>.
Hi Kevin,

> I was not aware the framework could not wire the package when resolving the bundle even if the package is present and exported.

This is true only for optional imports and can occur if the exported package has an incompatible version, or if a uses constraint prevents the class space from being compatible.

> It is also confusing that the framework reports it has been resolved.  That reporting resolved when not isn’t a bug?

When a bundle has been resolved it means that the OSGi framework has been able to find a valid wiring for all of the mandatory package imports for that bundle, optional imports may, or may not also have been wired, but they are optional so they must not prevent resolution from succeeding. Once this process has completed then your bundle is RESOLVED and able to load classes. A resolved wiring will not change* until the bundle is refreshed or uninstalled. You can introspect the wiring of a bundle using the bundle wiring API. 

Regards,

Tim

*There are a couple of ways in which package wires can be added dynamically at runtime, but no wires can ever be changed or removed.

> On 4 Sep 2017, at 16:13, Kevin Schmidt <kt...@gmail.com> wrote:
> 
> Tim,
> 
> Thanks for the catch.  I'm dealing with some third party libs that aren't OSGi bundles and having to do stuff with declaring things optional and this one slipped into the mix.
> 
> I was not aware the framework could not wire the package when resolving the bundle even if the package is present and exported.  It is also confusing that the framework reports it has been resolved.  That reporting resolved when not isn't a bug?  This is what was confusing.
> 
> And yes, it really is the optional service I care about.
> 
> Thanks for the link to the talk as well.  A good refresher.
> 
> Kevin
> 
> 
> 
> On Mon, Sep 4, 2017 at 1:51 AM, Timothy Ward <tim.ward@paremus.com <ma...@paremus.com>> wrote:
> 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 <ktschmidt@gmail.com <ma...@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. <http://10.0.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
>> 
>> 
> 
> 


Re: Class resolved/found on Karaf start but not on bundle restart

Posted by Kevin Schmidt <kt...@gmail.com>.
Tim,

Thanks for the catch.  I'm dealing with some third party libs that aren't
OSGi bundles and having to do stuff with declaring things optional and this
one slipped into the mix.

I was not aware the framework could not wire the package when resolving the
bundle even if the package is present and exported.  It is also confusing
that the framework reports it has been resolved.  That reporting resolved
when not isn't a bug?  This is what was confusing.

And yes, it really is the optional service I care about.

Thanks for the link to the talk as well.  A good refresher.

Kevin



On Mon, Sep 4, 2017 at 1:51 AM, Timothy Ward <ti...@paremus.com> wrote:

> 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 <kt...@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
>
>
>
>

Re: Class resolved/found on Karaf start but not on bundle restart

Posted by Timothy Ward <ti...@paremus.com>.
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 <kt...@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
> 
>