I meet a big concern, I have several bundle.
As
bundlecore
bundleui
bundleaddoncore
bundleui needs bundlecore,
bundleaddoncore needs bundlecore
When I update bundlecore with karaf, I noticed that bundleui and bundleaddoncore still using the old version? I must restart Karaf? Is this normal? if so what is the right way to recharge the dependent bundle?
No, you don't need to restart Karaf this is typical for OSGi. The Other bundles still use the old services or reference the "old" classes. After a bundle update you need to refresh the depending bundles, only with this your bundles do get resolved again and therefore use the new bundle.
To do so you either call refresh or just refresh in the Karaf console.
Related
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.
I am developing a composite feature for Karaf (i.e. a feature that includes other features as nested elements). I want to write out configuration files for the nested features and then from the outer scope (i.e. the feature that I am writing), I want to restart the bundles included in the nested features.
How do I query a feature for all of its bundles at runtime from another bundle.
How do I dynamically restart a bundle from another bundle ?
For all two operations you need instance of org.osgi.framework.BundleContext - you can get one in your bundle activator.
To query features (and their dependent features and their bundles) you need access to Karaf's org.apache.karaf.features.FeaturesService OSGi service - for example using BundleContext's getServiceReference() method.
To get any bundle (to be able to restart it) you can get one knowing it's ID: BundleContext.getBundle("ID")
What's the proper way to refresh jira OSGi bundles?
Should I use Felix OSGi console on runtime (not available on my JIRA instance by default) ?
Refreshing from the Gogo shell is equivalent to the following code, which you can put into your own bundle:
context.getBundle(0).adapt(FrameworkWiring.class).refreshBundles(...)
So perhaps you can listen to the bundle events when new bundles are installed by JIRA UI, and call refresh using the above method.
The trick is to do the refresh only when JIRA has finished a series of installs/updates/removes. Only JIRA can really know when it is done, but perhaps you can do the refresh after waiting, say, 10 seconds after the last change.
I am trying to develop an application that can be configured by its users. I need the configuration to be done by installing/updating/stopping/uninstalling bundles. All this should be of course done dynamically during the run-time of the application.
I found a nice framework which is Apache Felix FileInstall that provides a directory in which it seems to add a bundle when you add the bundle file in the directory (update, and remove bundles similarly).
But I can see that this method does not work in my case. I need to have the bundles in the directory but to stop or even uninstall them by my application. And I want to install them when it is appropriate. This is how I am expecting the configuration of my application to be done.
Is what I am trying to achieve supported by Apache FileInstall? Am I making any wrong assumptions about this framework? What are other possible ways that would help me if Apache FileInstall is not enough? Thanks.
You don't need FileInstall for this, just use the OSGi APIs. You specifically mentioned installing, updating, stopping and uninstalling; these are supported with the following API calls respectively:
BundleContext.installBundle
Bundle.update
Bundle.stop
Bundle.uninstall
Incidentally these are exactly the same methods that are called by FileInstall to implements its directory-based bundle management.
I have an eclipse rcp application that uses gemini blueprint. It has two features and hence a feature based product. Some of our bundles depend on service that where created by the blueprint extender. But actually the blueprint extender is only resolved on startup and not activated. Today we work around this by executing code in bundle activators, that checks if the org.eclipse.gemini.blueprint.extender bundle was started and if not it gets started.
Adding the bundle to the .product with a start level of 3 and autoStart=true has no effect. I think this is because our product is feature based. Is this correct? What is the best way to autostart the extender?
You need to edit configuration/config.ini file and add the bundle you want started to the osgi.bundles property. For example:
osgi.bundles=<existing entries>, org.eclipse.gemini.blueprint.extender#3:start
Have you tried to set the start level to 0 and auto start to true?
There is a suggestion in this link.May be it can help you.