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
Related
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.
I have a sling Servlet (and various other components) running inside an OSGi bundle inside AEM / Apache Felix.
eg:
#SlingServlet(
label = "XXXX - SSO Post Servlet",
metatype = true,
methods = {"POST"},
name = "XXXX.core.components.SlingPostServlet",
paths = {"/services/SSOPost"}
)
public class SlingPostServlet extends SlingAllMethodsServlet {
//etc
My components work as expected, maven is able to build, bundle and deploy the entire project fine.
My issue is that updates to my components are not activated until I restart the entire AEM instance. I have tried refreshing OSGi packages, restarting the bundle, and as many likely UI actions to achieve this effect as I can think of, but no luck.
Any ideas? I'm hoping its a simple config issue/ button I am not aware of.
Thanks.
The bundle is started but the event might not be active. It should get activated when the service is actually used. We can use the #Component(immediate=true) annotation to activate the component when the bundle gets started
Try deleting the old jar first, and then deploy the new jar. This works for me most of the times, but not always.
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.
I have an OSGi bundle (deployed into Karaf 2.2.4) that starts a Camel (2.10.0) context. The Camel context's routebuilder has some xquery endpoint URIs such as
"xquery:classpath:Dir1/Dir2/example.xq"
When the context tried to resolve that URI, it failed since the Camel bundle is not in the same classpath as where the .xq file resides. So, I created a url expand function that turns
"xquery:classpath:..."
into
"xquery:bundle://42.0:6/..."
since I had dealt with bundle URIs and the OsgiBundleResourcePatternResolver earlier in my project when dealing with a ClassPathScanningCandidateComponentProvider (Spring 3.1.1). Unfortunately, I can't seem to find a way to make Camel's XQueryComponent use my OsgiBundleResourcePatternResolver.
Am I going about this the right way? Is there an easier way to do this?
If I am, how can I make sure the XQueryComponent can understand a bundle: URI?
Also, is it possible for me to make sure any camel component can understand a bundle: URI?
You application that has the Camel route with the above xquery endpoint, would need to import the package where the xq file is located, eg the package that represents "Dir1.Dir2".
So in the META-INF/MANIFEST.MF which has the OSGi imports|exports. You should have an import for that given package.
And to answer your 3 bullets
No, see above
You would need to extend this component and add your own logic for the "bundle"
No, not really, as you would need to add logic to camel-core/camel-core-osgi.
Also the bundle id of an application can change, so its not advised to refer to a bundle by its id. And you cannot assign the bundle id, that is self assigned by the osgi container.
Thanks to Claus' answer, I was able to realize that my .xq file was not in the right directory in its .jar.
Dir1 resided in root of its .jar file. While running the application in a non-OSGi web container worked fine, Karaf appears to be more strict regarding where resources should be in my .war file. I moved the .xq files to WEB-INF/classes/Dir1/... and now am no longer receiving FileNotFoundExceptions when the code uses xquery:classpath:Dir1/Dir2/example.xq
Here's the scenario:
I have a bundle 'BundleA' installed and started in an OSGi container. A new version of BundleA is available. BundleA is provisioned using Felix Bundle Repository. The new version of BundleA declares a new package level requirement on a package from 'BundleB'.
Before I update BundleA (using OBR's deploy()) I stop BundleA because I want all threads to stop running and the deactivator provides this ability.
When I perform a deploy() on BundleA, BundleB is also installed, as expected.
I then programmatically start() BundleA again, and BundleA starts. But BundleB is 'resolved', not 'active'. I can manually start BundleB and it works as expected.
Is this expected, related to a way I am programmatically calling OSGi API, or did something go wrong?
That's the expected default behavior.
You can enable automatic activation of bundles as soon as any class from them is loaded. In order to do so, you need to set the Bundle-ActivationPolicy: lazy header.
In Eclipse that's the checkbox "Activate this plug-in when one of its classes is loaded" in the Manifest editor on the Overview page.
The OSGi framework does not automatically start bundles. (It will restart previously started bundles on framework launch however.) The framework does not know anything about start dependencies between bundles and bundles should not require a certain start order. As Gunnar mentioned, you can use activation policy to trigger lazy activation but that will not do anything if you have not called start on the bundle with the lazy activation policy.