Getting logging/debugging information out of Felix framework? - debugging

I am trying to launch the Felix OSGI Framework using AutoProcessor.process(...) to load my OSGI bundles. I have specified the directory containing the bundles using the felix.auto.deploy.dir property.
When that directory is empty I get no messages at all from Felix. When there are bundles in it I get a not very helpful stack dump.
How does one tell the Felix framework to output logging/debugging information? What I really want is for AutoProcessor to tell me which bundle it is working on when the stack dump occurs.
I have tried setting felix.log.level to 4; I have tried setting up an org.osgi.framework.FrameworkListener and an org.osgi.framework.BundleListener; and I have tried specifying a Logger with felix.log.logger; but Felix remains stubbornly taciturn.
So what's the secret trick?

After removing the duplicate org.osgi.core bundle as mentioned above, I tried once more to set up
an org.osgi.framework.FrameworkListener,
an org.osgi.framework.BundleListener, and
an org.osgi.framework.ServiceListener
on the framework that I had created. All 3 listener types fired and I was able to examine and log information from the events passed in as arguments.

Related

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.

Set a bundle start level programatically on embedded Apache Felix 5

I have embedded Apache Felix 5.0.0 in an application I'm building.
When installing the bundles to the Felix framework object, I have no way of setting the bundles start level from code, and I read everywhere that people do it by hand using Gogo, but because I'm going to automatically install and start the bundles, I'd like to be able to set the start level from my code.
How can I do that? I've read about some StartLevel class and such, but I have found no actual working code that shows how to use it to set the bundle start level.
I guess you have a Framework instance if you use embedded Felix. In this case I think the following could work:
Bundle bundle = framework.getBundleContext().installBundle(location);
BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
bundleStartLevel.setStartLevel(xxx);

Does Apache Felix FileInstall works for dynamic configuration of an application?

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.

OSGI Embedded Equinox - Bundle to access pojos not instantiated in osgi framework

I have a server side application and want to embed an osgi framework into for dynamic bundle loading.
Suppose I want to expose a QuoteImpl implementing IQuote(instantiated as part of the server container bootstrap/Spring) to be used by different Bundles.
Q1. Is there a clean way of exposing server-application instances to Bundles ? (btw because of legacy it is not possible to make server code into bundle :) and donot want to make entire application osgi'ed.
Tried exposing via a service and bundle to cast into an IQuote. Not sure I am doing it well but fails with unresolved compilation problems as IQuote resides in the core app projects as opposed to the bundle project. any ideas?
Yes the way to do this is with a service. The "host" application would publish the service and the bundles inside OSGi would consume the service in the normal way.
The key to get this working is that the service API (i.e. the package containing IQuote) must be exported by the host application through the system bundle exports. You can control this by setting the org.osgi.framework.system.packages.extra property when you create the embedded OSGi framework. I wrote a blog post on this subject that should help you get started (look for the heading "Exposing Application Packages").
You state that you have compilation problems. To fix those it's necessary to know how you have structured your projects and build system.
This is how I embedded Equinox OSGi runtime in my Java class. I suppose you could do the same. https://github.com/sarxos/equinox-launcher/blob/master/src/main/java/com/github/sarxos/equinox/Launcher.java

Using FreeMarker with Apache Sling

I'm using a Content Repository (Adobe CQ5) that has Apache Sling underneath. I'd like to render web pages using FreeMarker instead of JSP.
For that to work should I upload the OSGi Freemarker extension to Sling, which is to be found in the contribution part of Sling source code, or should I upload an OSGi version of Freemarker instead? Both jars implement the interface javax.script.ScriptEngineFactory so I don't know which one to use, or to upload both.
I managed to get Freemarker working on CQ5.3 by doing the following:
get the source from svn checkout http://svn.apache.org/repos/asf/sling/trunk sling
go to the contrib/scripting/freemarker and remove all the logging and slf4j references from FreemarkerScriptEngine.java - it throws a 500 error due to NoClassDefFoundException - I think there is a conflict between CQ5 and a version of slf4j included in Freemarker (I didn't dig to find out what was wrong)
build it and install, it should appear in the Sling console under bundles and in the 'script engines' page, and let you use .ftl scripts now.
I did it slightly differently by creating the bundle inside CQ5, importing the code and adding a stock freemarker.jar into the bundle but this should work too as it's basically the same thing.
The problem I had was that the script engine does get listed but the logging prevents it from running, that's why you need to remove the log & slf4j from the engine.
I don't know about the OSGi version of Freemarker; we created our own bundling of Freemarker specially for Sling. If you have success using the OSGi version of Freemarker let us know ;-)
Testing is easy: Just install the bundle through the Web Console and check for the supported Script Engines in the Web Console Configuration Status. If you see the Freemarker Engine listed there, it should work.

Resources