Should OSGi fragments export packages contributed to their host? - java

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.

Related

Exporting and importing same package from an osgi bundle

I have a class org.foo.Customer in an osgi bundle Bundle1 and another class
org.foo.Subscriber in another osgi bundle Bundle2 in the same osgi environment. Bundle1 exports-package org.foo .
Is it possible to import org.foo package of Bundle2 by Bundle1. Will there be any conflict during runtime as the same package is specified in export and import in the manifest file of Bundle1 .
Split packages are strongly discouraged in OSGi. If you own these bundles, you should either rename one or both packages, or join the split package into one bundle.
Bundle2 could import the split package, but then the classloader of Bundle2 would only see the classes in Bundle1, not those internally in Bundle2.
You could make one of the bundles a fragment of the other, which has the effect that they will use the same classloader. This requires changing only the manifest of the fragment bundle, and could be an option if you for some reason cannot join the bundles or change the package names.

How to use BundleWiring.findEntries() on system bundle?

I am trying to find a set of package names in all OSGi modules by using BundleWiring's findEntries() method. For all other modules, I can simply run
bundleWiring.findEntries("/" + packageName, "*.class", 2)
to get the URL's to all classes in that package.
The problem is this approach doesn't work for OSGi System Bundle (bundle 0). Through the classloader I was able to see that the classes I want are in tomcat/webapps/ROOT/WEB-INF/lib/x.jar, but how can I find the path to those classes if I am only given System Bundle as a bundle?
The packages are exported in system.packages.extra.mf
This is not possible because the system bundle is just the "outside" of OSGi. You can use an arbitrary ClassLoader to load the OSGi Framework, and ClassLoaders don't have a way to iterate the packages or classes that they know about.

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

JCE security provider in OSGi

We have a problem using a custom JCA implementation in our OSGi bundle. The JCA implementation that we are forced to use by our customer leads to a class loader memory leak. This prevents the deployment and usage of it in our bundle, because we quickly run into a perm gen space problem.
The proposed solution from the JCA provider is to put the JAR in the jre/lib/ext folder, but it is not loaded from there. This is due, as far as I know, to the OSGi (Eclipse equinox) class loader policy to have the bootstrap classloader as the parent of each bundle classloader, which excludes the extension class loader that loads from the jre/lib/ext folder. I.e. no bundle ever sees anything in the jre/lib/ext folder.
Is there a way to get Eclipse equinox to load a jar that is registered as a security provider, only once, such that all bundles or a specific bundle can see that provider? The fact that the JCA library is not unloaded via OSGi could be tolerated in this instance.
You should edit the system packages and add the packages from the JCA-custom.jar.
You can define which packages should be included in several ways.
You create a profile for equinox and define the packages. You can find examples for each jdk versions in the eclipse.osgi jar. For example, look for JavaSE-1.6.profile and try finding the entry org.osgi.framework.system.packages
You can define it as a system variable when you start your OSGi container. The system variable is the same: -Dorg.osgi.framework.system.packages=package names separated by comma

Categories