I'm exploring how OSGI is implemented for the last couple of weeks. I know that each bundle uses its own class loader to load its classes. As part of my investigation, I understood that parent of every bundle's class loader is null i.e boot class loader.
System.out.println("ClassInBundle class is loaded by "+ClassInBundle.class.getClassLoader());
System.out.println("ClassInBundle parent class is "+ClassInBundle.class.getClassLoader().getParent());
Output for above code which is in bundle samplebundle is
ClassInBundle class is loaded by com.sample.bundle.samplebundle [34]
ClassInBundle parent class is null
and for imports in a bundle, it maintains a map of packagename=>classloader so that it can delegate requests to the correct class loader
Bundle SB = felix.getBundleContext().getBundle(0);
List<BundleWire> sbwires=SB.adapt(BundleWiring.class).getRequiredWires(null);
List<BundleWire> li=bundle.adapt(BundleWiring.class).getRequiredWires(null);
for(BundleWire i : li){
System.out.println(i);
}
The output for the above code is
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (osgi.wiring.package=com.test.packag) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.8.0)(!(version>=2.0.0))) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework.wiring)(version>=1.2.0)(!(version>=2.0.0))) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.ee; (&(osgi.ee=JavaSE)(version=1.6)) -> [org.apache.felix.framework [0](R 0)]
As you can see in the first line of above output, the package com.test.packag is added as FelixConstants.FRAMEWORK_SYSTEMPACKAGES and the bundle samplebundle is wired to system bundle[0] for com.test.packag.
So, I wanted to understand how system bundle[0] can access system packages which are loaded by different class loader(App class loader). Not only that all the core classes of OSGI like Bundle, BundleActivator, Felix are also loaded by App class loader. So, I tried debugging the Felix code to understand whether the system bundle is delegating the loadClass() requests to App class loader. Unfortunately, while debugging I observed m_wiring variable of BundleWiringImpl class, I noticed that classloader of system bundle is null(which is not possible because boot class loader only loads java.* packages).
please correct my understanding if I'm wrong.
My questions here are
what is the class loader of system_bundle[0] and what is its parent class loader?
if the parent of the system_bundle class loader is not App class loader, is system bundle also maintaining the map of package=>classloader to load classes which are loaded by app class loader?
what exactly is the hierarchy of class loaders(bundle class loaders, system class loader, boot class loader, and app class loader)?
Thank you.
Normally the OSGi Framework (aka the System Bundle) is loaded by the application loader and therefore has visibility of everything else on the application loader, and its parents i.e. the extension loader and the boot loader.
It actually depends on how you write your launcher. You can embed OSGi into any standard Java application simply by instantiating a FrameworkFactory and using it to launch a Framework. When you do this, the OSGi framework is just another library on the classpath and it has visibility of the same set of classes as your own code.
You can make things as simple or as fancy as you like. For example you could embed an OSGi Framework into a Servlet deployed in a J2EE application server... in that case the system bundle will have visibility to all the types available in the Web Application, as controlled by the contents of WEB-INF. You could even embed an OSGi Framework into a bundle deployed to another OSGi Framework... OSGi inception!
In all these cases, the Framework can choose what set of packages to export. These packages become available to be imported by bundles inside that Framework. By default the packages exported are the standard set of JavaSE packages for the relevant JavaSE version, but you can augment with additional application-level packages.
Related
Error 500: java.lang.NoSuchMethodError: oracle/jdbc/OracleConnection.createOracleArray(Ljava/lang/String;Ljava/lang/Object;)Ljava/sql/Array; (loaded from file:/sysap/oracle/instantclient_11_2/ojdbc6.jar by com.ibm.ws.bootstrap.ExtClassLoader#96620801) called from class com.model.dao.TypeKeysDAO (loaded from file:/opt/WebSphere/8_5/AppServerBase1/profiles/AppServerBase1/installedApps/System_Cell/MyEnterprise.ear/MyEnterpriseWeb.war/WEB-INF/classes/ by com.ibm.ws.classloader.CompoundClassLoader#3edbaa21
The old copy of the JDBC jar appears to be associated with a JDBC provider defined in your configuration. The error message indicates that the class was loaded by WebSphere's ExtClassLoader, which is the loader that contains JDBC driver class paths. You'll need to remove the old JDBC provider, update its class path, or make it an "isolated" resource provider (which gives it a separate class loader that must be explicitly associated with an application) in order to get it out of the view of your application.
If there's some technical reason that you need ojdbc6.jar in the resource provider class path but need to reference ojdbc8.jar just within your application (not through a server-configured datasource), then you'll need to do some class loader configuration wizardry to make it work. The most reliable solution would be to create a shared library containing the new jar, set it to use an isolated class loader, and associate it with your EAR or WAR.
ojdbc6.jar is definitely there in the class path of the application. To locate from where it's loaded, you can login to the WebSphere Application server console (https://localhost:<admin-port>/ibm/console) and check the class loading details of your application.
This will show the list of classes/jars that are loaded for your application. Locate ojdbc6.jar from the list and see it's path.
You either would have added the ojdbc6.jar as a shared library or bundled in along with your Application (WEB-INF/lib directory) OR mentioned it in the class loader of the server itself.
file:/sysap/oracle/instantclient_11_2/ojdbc6.jar this is the sharedlibrary referenced by the EAR. I have added the ojdbc8.jar in this location and now the issue is fixed.
I am facing an issue related to linkage when i deployed my application websphere 8.5
Error in the XML parsing of the included Input Stream: java.lang.LinkageError: loading constraint violation when resolving method "javax/xml/parsers/SAXParser.parse(Lorg/xml/sax/InputSource;Lorg/xml/sax/helpers/DefaultHandler;)V" : loader "com/ibm/ws/classloader/CompoundClassLoader#aa54261e" of class "com/XMLParser/CreateParser" and loader "com/ibm/oti/vm/BootstrapClassLoader#1c4565b7" of class "javax/xml/parsers/SAXParser" have different types for the method signature.
I have the following jars in my class path.
I have set the loader to PARENT_LAST.
I tried to debug the class alone using a main method and found that it is taking the impl of saxparser of jdk 1.5 rt.jar and it is working as expected. After deploying the ear it is throwing the exception while the code hits the SAXParser.parse(InputSoruce,DefaultHandler) method.
jaxb-impl 2.2.6,
jaxb-libs-1.0.5,
jaxb-xjc-2.0EA3,
dom4j-1.1,
sax 2.0.1
Does any one have any idea about this problem?
Your class loader has visibility to two copies of org.xml.sax. The first because you've included the SAX APIs in your PARENT_LAST class loader, and the second indirectly via javax.xml.parsers in the JRE. You either need to remove the SAX API JAR from your application or you need to add the javax.xml (and perhaps more) APIs + impl to your application.
I know that the specification exactly defines it but cannot get what is the reason for this:
A class space is then all classes reachable from a given bundle’s class loader.
Thus, a class space for a given bundle can contain classes from:
• The parent class loader (normally java.* packages from the boot class path)
• Imported packages
• Required bundles
• The bundle's class path (private packages)
• Attached fragments
Let's assume:
A bundle declares "import-package: a"
There is a local class a.X in this bundle
There is a class a.X in another bundle
new a.X() would load the class from another bundle.
What is the reason that imported classes take precedence over bundle classes? Is it just a consequent continuation of java hierarchical class loading policy?
This is actually a core aspect of OSGi.
Sharing classes
The whole import/export mechanism is intended to let different bundles use the same class when communicating. Same in this case means not only binary equal, but loaded by the same class loader (recall that every bundle has its own class loader). If the bundle's own classes would be favored over imported ones, bundles would not be able to 'agree' on which copy of a class to use.
But... why?
Why would you have a copy of a class, which you also intend to import?
Consider a situation in which you want to do some logging, so you import org.osgi.service.log, but it's not a vital aspect, you can happily run without a LogService present. Now,
if you would only import the package, your bundle would fail to resolve, and thus fail to start, and
if you would only include the class, you would never use the other bundle's LogService class, so you cannot use the service (this is the agreeing part).
In this situation, you both import and include the class, so you can run in either situation, using your own copy when no one else has one, and sharing a copy if someone else does. You can even choose to export your copy, and let the framework decide.
As a sidenote, this is exactly the reason you should (almost) always import what you export.
I Followed this tutorial for my Restlet server in the Google App Engine: http://wiki.restlet.org/docs_2.0/13-restlet/21-restlet/318-restlet/303-restlet.html It works fine with the GWT client.
Now i'm trying to build a jse2 desktop client with OSGi and Restlet.
The code for the Restlet client in the OSGi bundle stay's the same as the tutorail provided.
When i start the OSGi Felix framework i also start the org.restlet.jar bundle who's exporting the restlet framework packages and i start a bundle with this code given in the toturail:
ClientResource cr = new ClientResource("localhost:8888/contacts/123");
// Get the Contact object
ContactResource resource = cr.wrap(ContactResource.class);
Contact contact = resource.retrieve();
The ContactResoure interface is in the same package as the bundle activator but i still get this strange message: java.lang.IllegalArgumentException: interface nl.nhl.minor.crm.desktop.restlet.ContactResource is not visible from class loader
Is this problem related to OSGi or to Restlet? And how can I solve this problem?
The manifest files for the OSGi bundles are created by the maven bundle plugin.
The correct way of loading a class is easy:
ClientResource cr = new ClientResource("http://127.0.0.1:8888/contacts/123");
Class<ContactResource> clazs = (Class<ContactResource>) cr.getClass().getClassLoader().loadClass("your.package.name.ClassName");
cr.wrap(clazs);
This solution give you a other problem, the class isn't imported by the org.restlet bundle.
See import package without edit the manifest file in org.restlet for my question about that problem.
I'm in the process of upgrading my application the latest release of Eclipse Equinox 3.7 and associated libraries. I'm excited to have the generic support in OSGi 4.3 and digging the new Bundle.adapt() concepts. I've run into one stumbling block.
Previously, I've used PackageAdmin.getBundle(Class) to find out which bundle loaded which classes. I have to do this due to some RMI object serialization usage.
QUESTION: Is there an way to accomplish the same result, mapping Class to Bundle, using the new BundleWiring API?
I realize that PackageAdmin is probably not going away anytime soon, but I hate deprecation warnings.
Kinda embarrassed that I didn't find this the first time I looked through the document. Answering my own question for completeness.
From the core specification PDF ...
Section 3.9.9 - Finding an Object’s Bundle
There are scenarios where a bundle is required in code that has no access to a Bundle Context. For this
reason, the framework provides the following methods:
Framework Util – Through the FrameworkUtil class with the getBundle(Class) method. The
framework provides this method to allow code to find the bundle of an object without having the
permission to get the class loader. The method returns null when the class does not originate from
a bundle.
Class Loader – An OSGi framework must ensure that the class loader of a class that comes from a
bundle implements the BundleReference interface. This allows legacy code to find an object’s
bundle by getting its class loader and casting it to a BundleReference object, which provides
access to the Bundle. However, this requires the code to have the permission to access the class
loader. The following code fragment shows how to obtain a Bundle object from any object.
ClassLoader cl = target.getClassLoader();
if ( cl instanceof BundleReference ) {
BundleReference ref = (BundleReference) cl;
Bundle b = ref.getBundle();
...
}
In an OSGi system, not all objects belong to the framework. It is therefore possible to get hold of a
class loader that does not implement the BundleReference interface, for example the boot class path
loader.