How to clean OSGi bundles cache at runtime - java

I have following sample scenario ... (please note that I can implement the scenario using services but I'm trying some things)
An OSGi bundle with an Activator class (name it "client") and another OSGi bundle that is a simple library (name it "server") exposing a method named callMe(). In the start() method of the "client" there is a call to the callMe() method of the "server". Of course the "server" bundle exposes the package where we have the class with callMe() method and the "client" bundle has it as imported package.
Starting the OSGi framework without the two bundles installed, I install the "client" bundle first and when I try to execute start() method the following error is shown :
org.osgi.framework.BundleException: Unresolved constraint in bundle org.example.helloworld [4]: Unable to resolve 4.0: missing requirement [4.0] osgi.wiring.package; (osgi.wiring.package=org.example.helloworldlib)
It's right because the "server" bundle isn't neither installed nor resolved.
Now, I install "server" bundle and recall start() on "client" : this time all works fine because the "server" bundle is installed so the "client" can be resolved, activated and it can call callMe() method on "server".
After that I uninstall the "server" bundle leaving the "client". The strange thing is now ... stop the "client" and re-start() it ... the "client" works ! It's able to call the callMe() method of "server" even if I uninstalled it before ! I know that OSGi framework has a bundle cache so it seems that "server" bundle is in the cache but why it's not showed in the bundles list ?
Is it possible to clean the cache at runtime ?
Paolo.

OSGi builds the wiring to needed packages when a bundles goes to the state resolved. It then keeps these wirings until refresh is called.
So it is completely normal that the client keeps working when you uninstall the server bundle.
When you call refresh the resolve step is done again. So at this point the client fails to resolve. As far as I know the wiring is not cached on disk.
So if you uninstall server and restart the framework client should also fail to resolve.

Related

Osgi ServiceMix ClassCastException

I am having trouble with ServiceMix 5.5.2.
I have a bundle A that contain a class test.java.Root.class and after update of other bundle in ServiceMix my bundle A says:
ClassCastException : class test.java.Root can t be cast to test.java.Root
It the same class...
I know that the real problem is that this class was loading twice by different ClassLoader but I don't know why and when: the class is inside the jar and the package is not exported.
I have done refresh on the bundle but nothing work. Only a ServiceMix restart work :(
How can I find (before restarting and avoid restarting) all references of the class and where reference are still possibly in use?
Does ServiceMix propose Karaf command to see this?

Registering services inside OSGi extension bundles

I'm playing with OSGi framework extension bundles in order to fully understand them.
After looking at the OSGi R6 specification (3.15 and 4.2.4.1) I've sucessfully invoked the "start" method of the ExtensionBundleActivator. Now I'm trying to register a service inside such activator. However, when I trying to consume such service, the reference annotation fails to connect the service.
Here's my code ('ve changed the name of the bundle, but it shouldn't matter):
public class ExtensionBundleActivator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("start extension bundle activator!");
context.registerService(
BundleExample.class.getName(),
new BundleExampleImpl(),
new Hashtable<>(new HashMap<>()));
}
#Override
public void stop(BundleContext context) throws Exception {
//service automatically unregistered
}
}
And here's the manifest of such extension bundle:
Manifest-Version: 1.0
Bnd-LastModified: 1476436248622
Build-Jdk: 1.8.0_91
Built-By: massi
Bundle-ClassPath: .
Bundle-ManifestVersion: 2
Bundle-Name: extensionbundleexample
Bundle-SymbolicName: com.massimobono.microsi.extensionbundleexample
Bundle-Version: 0.0.1.SNAPSHOT
Conditional-Package: com.massimobono.microsi.common.*;
Created-By: Apache Maven Bundle Plugin
ExtensionBundle-Activator: com.massimobono.microsi.bundleexample.imp
l.ExtensionBundleActivator
Fragment-Host: system.bundle; extension:=framework
Provide-Capability: osgi.service;objectClass:List<String>="com.massimobo
no.microsi.bundleexample.BundleExample"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Service-Component: OSGI-INF/com.massimobono.microsi.bundleexample.im
pl.ExtensionBundleExample.xml
Tool: Bnd-3.0.0.201509101326
The consuming bundle (part of the bundle):
#Reference(cardinality=ReferenceCardinality.OPTIONAL)
public BundleExample actualBundleExample;
#Activate
public void activate() {
System.out.println("activating " + this.getClass().getSimpleName() + "with actual bundle set to "+ this.actualBundleExample);
}
My question is: What am I doing wrong? Why the consumer can't detect the registered service of the extension bundle? Or maybe I'm just doing something the framework forbids... in this case is it impossible to provide a service from an extension bundle? How can I interact with the code within the extension bundle (aka accessing something inside the extension bundle itself)?
Here some notes:
I'm using felix as OSGi implementation;
Both "ExtensionBundleExample" and "BundleExample" are loaded inside the auto-process folder of felix (the default one is "bundle" but I tweaked the config.properties to use "corebundles" folder;
The output corretly show "start extension bundle activator!" but when it's time to display the reference of actualBundleExample, the output shows "null";
the optional cardinality of BundleExample is used for testing purposing: I just wanted to invoke the "acivator" method the consumer component has (in order to see the System.out.println console;
from my previous question I understand extension bundles are a niche inside the OSGi framework, but I want to understand them nonetheless: I find the lack of examples on the internet regarding this topic quite annoying;
Thanks for any reply!
The primary purpose of extension bundles is for framework extensions, absolutely not for regular usage. I.e. extension bundles are often tightly coupled to a framework. The reason is that many rules do not count for extension bundles because they are on the "wrong" side of the fence. There are few examples for very good reasons. You should not use them unless you really know what you're doing because most of the OSGi rules do not apply.
That said. My expectation is that the package you use for the BundleExample differs between the extension bundle (comes from the class path) and the DS example exported by some bundle. Since they come from different class loaders OSGi considers them different services because you would get a class loader exception when you tried to use it.
You can solve this by letting the framework export this package.
Just a guess.

starting slf4j bundle doesn't start on felix

I have felix-framework-5.0.1 and I'm trying to start slf4j-api-1.6.0.jar bundle into felix isgi container.
in felix console I'm typing install file:bundle/slf4j-api-1.6.0.jar
I'm getting a message Bundle ID: 42
then I'm trying to start the bundle start 42
I'm getting the message
org.osgi.framework.BundleException: Unable to resolve slf4j.api [42](R 42.0): missing requirement [slf4j.api [42](R 42.0)] osgi.wiring.package; (&(osgi.wiring.p
ackage=org.slf4j.impl)(version>=1.5.5)) Unresolved requirements: [[slf4j.api [42](R 42.0)] osgi.wiring.package; (&(osgi.wiring.package=org.slf4j.impl)(version>=
1.5.5))]
g!
Can any body help me? how can I start slf4j bundle into felix?
slf4j-api needs org.slf4j.impl package. This package is included into every slf4j implementations like slf4j-simple, slf4j-logback, etc.
The implementation bundles need org.slf4j package that comes from the API artifact. There is a cross-reference. This can work only due to the reason that implementations are fragment bundles of the API. When the implementation is installed together with the API, they will have a common classloader and they will be resolved together. Both of their requirements will be satisfied.
In short: You must choose one of the implementations and install that as well. E.g.: slf4j-simple.
You should use the same version of API and implementation to satisfy their "cross requirement".
Your library contains the following 3 packages (link):
org.slf4j
org.slf4j.helpers
org.slf4j.spi
but you have to have an additional library that will contain org.slf4j.impl package.
Also, from manifest file you can see what packages are exported (Export-Package) (they are visible by other bundles) and what packages are imported (Import-Package) (they have to be accessible for the given bundle). Sometimes the given package have to be from bundle with the correct version.
If you cannot find correct bundle maybe this page will help you.

OSGI, OSGI - bundle and Hazelcast deserialization class not found exception

My Question is
I have two osgi bundles, In which one bundle has hazelcast (3.3 version) jar and I have exported all the packages in it... which means the other bundle can use all the packages of hazelcast available in first bundle.
So what I planned is,
-> One bundle is for keeping the hazelcast jar as common bundle.
-> Other bundle is for performing the business operations in which the first bundle will be the dependent bundle for this,
I have the hazelcast xml which has a serialization factory mapping in it.
Note : The serialization factory class is there in other bundle (Not in hazelcast jar bundle), So what happens is when I start the hazelcast server, It clearly says that the serialization factory class is not found.
com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: com.test.beans.SerializableFactory
at com.hazelcast.nio.serialization.SerializationServiceBuilder.buildDataSerializableFactories(SerializationServiceBuilder.java:290)
at com.hazelcast.nio.serialization.SerializationServiceBuilder.addConfigDataSerializableFactories(SerializationServiceBuilder.java:247)
at com.hazelcast.nio.serialization.SerializationServiceBuilder.build(SerializationServiceBuilder.java:169)
at com.hazelcast.instance.Node.createSerializationService(Node.java:193)
at com.hazelcast.instance.Node.<init>(Node.java:140)
at com.hazelcast.instance.HazelcastInstanceImpl.<init>(HazelcastInstanceImpl.java:120)
at com.hazelcast.instance.HazelcastInstanceFactory.constructHazelcastInstance(HazelcastInstanceFactory.java:153)
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:136)
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:112)
at com.hazelcast.core.Hazelcast.newHazelcastInstance(Hazelcast.java:58)
For your INFORMATION, I already tried config.setClassloader

Should OSGi fragments export packages contributed to their host?

I noticed a fragment I have uses a Export-Package directive for the package that is contributed to its host:
Fragment-Host: org.eclipse.jetty.osgi.boot
Export-Package: org.eclipse.jetty.osgi.boot.utils;version="1.0.1.felix"
-buildpath: osgi.core;version=4.3.0,\
org.eclipse.jetty.osgi.boot;version=7.6.1.v20120215
-sources: false
Import-Package: !org.eclipse.jetty.osgi.boot.utils.internal,\
*
This bundle contributes some extra classes into the org.eclipse.jetty.osgi.boot.utils package in the host.
Ideally I think I should strive to keep packages private where possible, but what about this case? None of the rest of my code requires org.eclipse.jetty.osgi.boot.utils.
From the OSGi core specification (6.0):
A host bundle's class path is searched before a fragment's class path.
"This bundle contributes a new org.eclipse.jetty.osgi.boot.utils with classes that override those of the host"
Fragment bundles cannot override the classes of the host bundle (if that was what you meant).
If a package is not intended to use by other bundles, it should not be exported. The host bundle can see the classes and resources of its attached fragment bundle, but only if it does not have the same class or resource.
The accepted answer of #balazs-zsoldos:
Fragment bundles cannot override the classes of the host bundle
...is correct in this specific case, but it is not true in general. A more nuanced answer would be that fragments cannot override the host bundle's classes unless the host bundle has been configured to allow it (which in your case the org.eclipse.jetty.osgi.boot bundle is not).
The way you configure the host bundle to allow it is by using the Bundle-ClassPath header. Let's assume you have a host bundle A with an attached fragment B, and A has the following manifest entry:
Bundle-ClassPath: contrib,.
Suppose the bundle classloader is asked to look for class pack.Z in bundle A. The bundle classloader will search in the following order:
A:contrib/pack/Z.class
B:contrib/pack/Z.class
A:pack/Z.class
B:pack/Z.class
So you can see that if your contrib directory in A is empty or non-existent, then the bundle classloader will try and load B:contrib/pack/Z.class before it will try and load A:pack/Z.class. But as you can see, this is only possible if A was explicitly built to allow it.

Categories