OSGi Bundle Installation Bootstrapping - osgi

I am reading "OGSi in Action" where in an interesting comment has been made :
"The module layer uses the metadata in bundles to make sure all their dependencies are satisfied before they can be used. This symbiotic relationship creates a chicken-and-egg situation when you want to use your bundles; to use a bundle you have to install it, but to
install a bundle you must have a bundle context, which are only given to bundles."
The book goes to great length in explaining bundle dependency resolution , but the "chicken and egg" scenario described above hasnt really been explored further. To install a bundle , BundleContext is needed, which is only provided to bundles. So who created the first "bootstrapping" bundle ? Is this contained in the "shells" that are provided (using packageAdmin?) ? PackageAdmin has
Bundle getBundle(Class clazz);
and Bundle can provide the BundleContext, but the bundle has to be installed first ... and so on !!
How does this work ?

See the Framework Launching API which provides the launcher with access to the system bundle's Bundle Context to install the "first" bundles.

From the javadoc of Bundle.getBundleContext():
If this bundle is not in the STARTING, ACTIVE, or STOPPING states or
this bundle is a fragment bundle, then this bundle has no valid
BundleContext. This method will return null if this bundle has no
valid BundleContext.
I do not know what the writer of the book thought about. If you install a bundle programmatically, you install it via the bundle context of other bundle.
With all my respect, I think this paragraph is wrong. This "chicken and egg" philosophical question could be raised in case of the system bundle. However, I do not think that answering the unnecessary question would give a better understanding for the reader, who wants to get started with OSGi.

Related

OSGi : Bundle Activation

Conceptually, what does it mean to “activate a bundle” in OSGi (e.g. what operations are done on a bundle to activate it). What happens, exactly?
If the bundle has a BundleActivator then the start method of it is called.
Frameworks like declarative services might also watch the bundle status and activate components declared in the bundle.

java.util.ServiceConfigurationError Provider not a subtype while using OSGi bundle

I'm creating a Liferay 7.1 OSGi bundle, which has some external dependencies in it. In consideration of time, we opted to embed the external JAR in our OSGi Bundle. I've managed to create a bnd file, which includes all of the ElasticSearch dependencies, and put them on the bundle classpath. I've used the source-code from github (https://github.com/liferay/liferay-portal/blob/master/modules/apps/portal-search-elasticsearch6/portal-search-elasticsearch6-impl/build.gradle) and the bnd.bnd file, to check what's imported.
When activating the bundle, an exception is thrown:
The activate method has thrown an exception
java.util.ServiceConfigurationError: org.elasticsearch.common.xcontent.XContentBuilderExtension: Provider org.elasticsearch.common.xcontent.XContentElasticsearchExtension not a subtype
at java.util.ServiceLoader.fail(ServiceLoader.java:239)
at java.util.ServiceLoader.access$300(ServiceLoader.java:185)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376)
at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
at org.elasticsearch.common.xcontent.XContentBuilder.<clinit>(XContentBuilder.java:118)
at org.elasticsearch.common.settings.Setting.arrayToParsableString(Setting.java:1257)
The XContentBuilderExtension is from the elasticsearch-x-content-6.5.0.jar,
the XContentElasticsearchExtension class, is included in the elasticsearch-6.5.0.jar. Both are Included Resources, and have been put on the classpath.
The Activate-method initializes a TransportClient in my other jar, hence it happens on activation ;).
Edit:
I've noticed that this error does NOT occur when installing this the first time, or when the portal restarts. So it only occurs when I uninstall and reinstall the bundle. (This is functionality I really prefer to have!). Maybe a stupid thought.. But could it be that there is some 'hanging thread'? That the bundle is not correctly installed, or that the TransportClient still is alive? I'm checking this out. Any hints are welcome!
Edit 2:
I'm fearing this is an incompatibility between SPI and OSGi? I've checked: The High Level Rest Client has the same issue. (But then with another Extension). I'm going to try the Low-Level Rest Client. This should work, as there are minimal dependencies, I'm guessing. I'm still very curious on why the incompatibility is there. I'm certainly no expert on OSGi, neither on SPI. (Time to learn new stuff!)
Seems like a case where OSGi uses your bundle to solve a dependency from another bundle, probably one that used your bundle to solve a package when the system started.
Looking at the symptoms: it does not occur when booting or restarts. Also it is not a subtype.
When OSGi uses that bundle to solve a dependency, it will keep a copy around, even when you remove it. When the bundle comes back a package that was previously used by another bundle may still be around and you can have the situation where a class used has two version of itself, from different classloaders, meaning they are not the same class and therefore, not a subtype.
Expose only the necessary to minimize the effects of this. Import only if needs importing. If you are using Liferay Gradle configuration to include the bundle inside, stop - it's a terrible way to include as it exposes a lot. If using the bnd file to include a resource and create an entry for the adicional classpath location, do not expose if not necessary. If you have several bundles using one as dependency, make sure about the version they use and if the exchange objects from the problematic class, if they do, than extra care is required.
PS: you can include attributes when exporting and/or importing in order to be more specific and avoid using packages from the wrong origin.
You can have 2 elastic search connections inside one Java app and Liferay is by default not exposing the connection that it holds.
A way around it is to rebuild the Liferay ES connector. It's not a big deal because you don't need to change the code only the OSGi descriptor to expose more services.
I did it in one POC project and worked fine. The tricky thing is to rebuild the Liferay jar but that was explained by Pettry by his google like search blog posts. https://community.liferay.com/blogs/-/blogs/creating-a-google-like-search (it is a series but it's kind of hard to navigate in the new Liferay blogs but Google will probably help) Either way it is all nicely documented here https://github.com/peerkar/liferay-gsearch
the only thing then what needs to be done is to add org.elasticsearch.* in the bnd.bnd file in the export section. You will then be able to work with the native elastic API.

Runtime flexibility of OSGi

To get started with OSGi, thought of asking this since this become unclear to me.
If you have runtime code change as a requirement, OSGi is probably the only possible way to achieve this using Java.
from https://mondula.com/2016/01/11/osgi-benefits-and-drawbacks/
How the runtime flexibility is maintained in OSGi technically?
This is a large question that would be impractical to fully answer here. The following is a simplified overview.
OSGi allocates a Java ClassLoader for each resolved bundle. When a bundle is updated, OSGi first sends a stop signal to the bundle, allowing it to release resources and prepare to be garbage collected.
The new bundle is then re-resolved against its requirements, which may have changed compared to the previous version. Assuming the new version still resolves (i.e. its requirements are still satisfied) then OSGi allocates a new ClassLoader, uses that to load the classes in the bundle, and if the bundle has an activator and was in ACTIVE state before the update, sends a start signal to the newly loaded activator.

osgi same class but classcastexception

Getting an issue where class A cannot be cast to class A in osgi. Point is this class A is not being exported in any other bundle as well as where it is created. In the pom for exported-package it is mentioned "!A" so A is not exported. Still we get the issue. A re-install of the bundle works though. Cant recreate the issue and then suddenly it is back again . Any ideas.
The class is an entity class and internal - not in any other project
In maven-bundle-plugin we have
<Private-Package>
com.xxx.yyy.entity.*
</Private-Package>
<Export-Package>
!com.xxx.yyy.entity.*
</Export-Package>
We had similar issues when we used technologies that had String-Class caches without direct wiring to the bundle of the Class.
Let's say there is Bundle A and Bundle T (technology). Bundle A is updated and but the classes that were loaded during the first time Bundle A was started are still in the cache of Bundle T.
This can become really magical if there is a technology in the OSGi container that updates bundles during their restart. One typical case is when a technology wants to do bytecode manipulation on classes. It implements a Bundle Weaving Hook, but it must update all of the relevant bundles that were started before the magical technology bundle to be able to catch the classloadings. An example of such magical technology is Apache Aries Proxy.
Btw.: A stacktrace and some source code would help a lot to see in which technology the issue appears.

Maintaining OSGi bundle's state manually

Is there any approach via we can maintain and control OSGi bundles' state manually via code?
I have a requirement where in I need to download, copy and install/activate/deactivate/delete OSGi bundles in run time environment.
Any help/references will be appreciated.
Thanks!
You install a bundle with BundleContext.install by supplying a URL or an InputStream. As result you get a Bundle. In Bundle you can then call start(), stop() and uninstall(). You get the BundleContext inside the Activator of any already existing bundle.
http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/BundleContext.html

Resources