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.
Related
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.
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.
if i deploy a war-file into a gemini container (e.g. virgo has one) it will be transformed on-the-fly into an osgi bundle by adding some package imports (besides other things).
Is it possible to somehow extend these default package imports using for example a bundle-listener or something like this?
regards
I would strongly recommend that you do the transformation yourself before deploying into the Gemini container, rather than forcing Gemini to do the transformation on-the-fly. First it is very easy to do; second it will be much faster to deploy; third you will be able to add the specific imports that you want.
In order to turn a standard WAR file into a WAB (Web Application Bundle) that remains compatible with traditional WAR deployment, you just need to add the following headers to the MANIFEST.MF of the WAR:
Web-ContextPath to define the context path under which the web application will be served
Set Bundle-ClassPath to WEB-INF/classes plus any JARs under WEB-INF/lib. You will have to name these explicitly e.g.: Bundle-ClassPath: WEB-INF/classes,WEB-INF/lib/a.jar,WEB-INF/lib/b.jar...
Import-Package: javax.servlet,javax.servlet.http plus anything else you want to import.
I inherited a .bnd file that has the import !javax., and my program produces runtime errors if I take out that statement. I currently need to add JavaHelp to my application, which is under javax.help.. When I have both of those imports in my .bnd and I use a class from JavaHelp, it produces a ClassNotFoundException for the specific class, like javax.help.JHelp. Is there a way to handle this situation, I feel stuck.
Bundles generally need to import all the package that do not start with "java.". This includes "javax." packages. If your bnd file explicitly does not import javax. package, then it must rely upon non-standard boot delegation configuration for the framework. That is, the boot delegation provides "free" access to javax. packages from the bundles parent classloader (likely the bootclassloader). So when you remove !javax. from the bnd file, your bundle starts to import those packages from some provider which may not be the same as whatever bootdelegation is providing.
I try to package an OSGI bundle using the maven-bundle-plugin (which uses BND).
To run properly the bundle must import a package which is not in the classpath during development (because object references will be passed to the bundle methods as "Class" references).
I do not manage to configure the "Import-Package" declaration in the pom.xml or *.bnd file so that the packe will be included in the OSGI Import-Package part of the MANIFEST. I though
Import-Package: de.foo.bar,*
should do the job, but as de.foo.bar is not in the classpath (or better not declared as an import in the code) it will not be taken to the MANIFEST.
Has anybody an idea how to force the package to be available in the OSGi Import-Package MANIFEST declaration.
Thanks and regards
Klaus
I finally found a solution
Import-Package: de.foo.bar;resolution:=optional,*
will put "de.foo.bar" in the "Import-Package" declaration of the bundle MANIFEST.MF even if the package is not imported by the bundle code.