Access class of other OSGi bundle - osgi

My project has two bundles, lets say Bundle A and Bundle B.
Now Bundle A needs to access a class from Bundle B.
How can I do that?

There are two ways:
Add the dependency of bundle B to the Manifest of bundle A: Require-Bundle: bundle-id-of-bundle-A
Import the package of the wanted class in the Manifest of bundle A: Import-Package: package.of.your.class
In both situations, you need to export the package that contains your class in bundle B: Export-Package: package.of.your.class
Also, here's a good intro:
http://ctpjava.blogspot.com/2010/09/introduction-to-osgi.html

As #earcam wrote, it is strongly recommended to use Import-Package:.
Also, always add a version to the exported package in bundle B - this is good practice that you will appreciate later when you create the next version of bundles A and B.

Related

How to provide additional class for a package on OSGi system classpath for J2SE 1.8 profile

Inside ee.j2se-1.8 the package org.w3c.dom is included.
org.osgi.framework.system.packages = \
...
org.w3c.dom,\
...
org.osgi.framework.bootdelegation = \
...
org.w3c.*,\
org.xml.*,\
....
The bundle xml-apis_1.4.1.20140905-131237.jar contains the same package org.w3c.dom, but with one important class more ... ElementTraversal.class more.
So here my questions...
How can I provide the missing class inside my Equinox OSGi runtime?
You are suffering from the fact that people do not take packages seriously. We have a similar problem in the jta API. The version delivered by the VM is not identical to the version that is delivered as a special package.
The solution is to include the JAR with the extra packages on the class path where the framework resides. It looks like you're using bnd (good!) so this would look like:
-runpath: xml-apis__xml-apis;version="[1.4.1,2.0.0)"
If this had been a bundle with proper exports then you would have automatically gotten its exports as system packages. Looking at the packages in this bundle it seems all packages are already in the standard exports of the VM. However, if you have packages int his JAR that are not exported by the VM then you can add them as follows:
-runsystempackages: javax.xml.foo

class loading of OSGi on Required-Bundle and Imported-Package

For OSGi bundle, we can add dependencies by using Required-Bundle or Imported-Package. Now I have below case:
Both bundle A and bundle B export same packages, but bundle B with higher version, like:
bundle A:
Exported Packages:
xxx.a,
xxx.b,
xxx.c
bundle B:
Exported Packages:
xxx.a; version="5.0.0",
xxx.b; version="5.0.0",
xxx.c; version="5.0.0"
And bundle C has the dependency to package a, b, c, so it adds A in its Required-Bundle list, like
bundle C:
Required Bundles:
A
Let's assume both bundle A and B are resolved in the framework. So when resolving bundle C, which packages/classes are been loaded by C, the classes in A or classes B? I think is A. Am i right?
Yes, the packages from A are used because you require bundle A.
Please note that Require-Bundle is considered deprecated by most OSGi developers.

Karaf missing classes in bundles

I am deploying httpclient-4.3.4.jar in deploy folder of karaf. In terminal when I use command find-class HttpClients, nothing is getting listed. When use keyword find-class HttpClient, I get only follwing classes loaded for httpclient bundle. Since some of the classes are missing I am getting java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClients in one of my dependent bundles.
I need to know whey some classes are not available. If it is our own bundle, we can specify imports and exports to control the classes which we need to expose. But for external jars, why this is happening?
httpclient (202)
org/apache/http/HttpClientConnection.class
org/apache/http/client/HttpClient.class
org/apache/http/client/params/HttpClientParams.class
org/apache/http/client/utils/HttpClientUtils.class
org/apache/http/impl/AbstractHttpClientConnection.class
org/apache/http/impl/DefaultHttpClientConnection.class
org/apache/http/impl/SocketHttpClientConnection.class
org/apache/http/impl/client/AbstractHttpClient.class
org/apache/http/impl/client/AutoRetryHttpClient.class
org/apache/http/impl/client/ContentEncodingHttpClient.class
org/apache/http/impl/client/DecompressingHttpClient.class
org/apache/http/impl/client/DefaultHttpClient.class
org/apache/http/impl/client/SystemDefaultHttpClient.class
First, is it a valid OSGi bundle, without the required manifest entries and the right Package-Exports/Imports this won't work.
If you just drop it in the deploy folder it might get autowrapped, but this isn't always working. It's better to either take an existing Bundle or do install with:
osgi:install wrap:mvn:groupID/artifactID/version
All of this is also documented in the Karaf User Manual.
The installed bundle can be started with
start ID
where ID is the ID of the bundle just installed.
EDIT:
You definitely need to wrap the bundle in question, since it isn't a OSGi bundle yet.
So in your case do:
install wrap:mvn:org.apache.httpcomponents/httpclient/4.3.4
after the bundle is installed:
start ID
If you do a bundle:header after that you'll get a nice header definition.
The find class does show the HttpClient class in this bundle:
karaf#root()> find-class HttpClients
wrap_mvn_org.apache.httpcomponents_httpclient_4.3.4 (78)
org/apache/http/impl/client/HttpClients.class

Unable to wire proper bundle with my own bundle in wso2 app server

I am using wso2 Application Server 5.1.0.
I have deployed my own bundle having name demo-service which contains import-package definition in its manifest as below:
>Bundle-SymbolicName = demo-service
Import-Package = javax.sql,org.apache.commons.dbcp;version="[1.4,2)"
I tried to diagnose the most popular "uses conflict" in OSGi world for my case and I found that commons-dbcp_1.4.0.wso2v1.jar and commons-dbcp-1.4.jar both were converted to OSGi bundle by container and exported their packages with version "0.0.0" which can be observed from the output below:
>osgi> packages org.apache.commons.dbcp
org.apache.commons.dbcp; version="0.0.0"<commons-dbcp_1.4.0.wso2v1 [49]>
compass_2.0.1.wso2v2 [60] imports
org.wso2.carbon.core_4.1.0 [256] imports
org.wso2.carbon.registry.core_4.1.0 [377] imports
org.wso2.carbon.tenant.mgt_2.1.0 [434] imports
synapse-commons_2.1.1.wso2v3 [528] imports
synapse-core_2.1.1.wso2v3 [529] imports
org.apache.commons.dbcp; version="0.0.0"<commons_dbcp_1.4_1.0.0 [57]>
According to the requirement of my demo-service bundle it's not able to find
org.apache.commons.dbcp;version="[1.4,2)"
Is there any way to export the packages of commons-dbcp-1.4.jar after it gets converted from non-osgi bundle to osgi bundle because I need to make sure that my demo-service bundle should wire with commons-dbcp-1.4.jar..
In brief, any version of thirdparty jar I put in WSO2_HOME\repository\components\lib folder container exports it with version="0.0.0" .. which discourages the main concept for classloading of OSGi
please suggest if any workaround is possible in this case .. :)
Thanks ..
When a version is not specified while exporting packages OSGi defaults to version 0.0.0. In this case as it's automatically converting to osgi bundle it might not be having version explicitly specified. Sometimes this also helps to ensure that multiple versions of packages are not present.
In your case as you need to use the packages in the bundle put in repository\components\lib folder you could manually specify the version. The OSGi-fied bundles of the jars you put in repository\components\lib can be found in repository\components\dropins folder. Inside that bundle you will find the OSGi manifest file. In the manifest file manually specify the versions for the required packages under Export-Package category as follows.
org.apache.commons.dbcp;version=1.4.1
Then on startup, it would use these bundles and you should be able to export packages with specified version.

import package without edit the manifest file in org.restlet

I am using Restlet for my communication between my clients (JSE2) and my server(GAE).
The clients are OSGi based.
I have a shared bundle containing my resource interfaces and a bundle containing the code to wrap a resource to a ClientResource. But the org.restlet bundle doesn't import any of these bundles. I think its not the right solution to edit the manifest of the org.restlet bundle and import the shared bundle manualy. Also this is a very static solution.
Is there a beter way to import these interface so i can wrap them into a Restlet ClientResource?
This is the exception where i'm dealing with:
java.lang.ClassNotFoundException: *** Class 'crm.resources.server.restlet.ContactResource' was not found because bundle org.restlet [3] does not import 'crm.resources.server.restlet' even though bundle crm.shared.resources.server [4] does export it. To resolve this issue, add an import for 'crm.resources.server.restlet' to bundle org.restlet [3]. ***
Update: Its useless to edit the manifest because the shared bundle uses some imports from the org.restlet bundle. So when you try to start the org.restlet bundle the imported packages from the shared bundle are missing. If you start the shared bundle first, he miss the packages from the org.restlet. (I hope i'm explaining it clearly)
I understand your issue.
The best solution i came up with is to add "DynamicImport-Bundle: *" in org.restlet MANIFEST-File (2.1.2 so far).
At least, that prevents you from circular dependencies and doesn't force you to manually adjust the imports once you change your restlet application.
See also: https://github.com/restlet/restlet-framework-java/issues/6
Best regards,
Simon

Resources