I'm having a problem discovering services that are provided by some OSGi bundles that are not being activated. Let me describe the situation:
Bundle A defines interface X
Bundles B, C, and D provide services that implement interface X
These bundles' services are registered via Spring DM, so they are only created when the bundle is activated and Spring DM initialized the application context defined in the bundle
Bundle A is activated and at some point asks the service registry for services for interface X. It doesn't find any, because bundles B, C, and D haven't been moved into the ACTIVE state (they are only RESOLVED).
I cannot seem to get bundles B, C, or D to start, and therefore register their services. Forcing them to start by adding them to the config.ini is not an option, because there can be any number of bundles that are installed in the application (via an Eclipse p2-like update mechanism) that implement interface X.
The application is an Eclipse 3.5-based RCP app, using Spring 2.5.6 and Spring DM 1.2.1.
How do I force these bundles to be activated?
What you really have is a dependency hierarchy problem, your proposed hacky solution is really just a band-aid over the underlying issue.
What you should really consider is the architecture of your system, as effectively what you have is a circular dependency (re: discussion in comments your original post). You have (like it or not) A requires services from (and in some sense depends on) B and C. Meanwhile, B and C directly depend on A, and as such, cannot start until A comes up.
In the best case, you can write code in B and C to listen for the existence of A, but this at best masks (as I mentioned) the underlying issue. What you should really consider is splitting A into two bundles, let's call them A1 and A2.
A1 should provide the interface which B and C require (depend on). A2 should have listeners for the services B and C depend on. At startup, if B and C are required services, A1 must be run, but A2 may start any time later, and everything should work.
I think I've found the solution to this problem, though it feels a bit hackish.
I ran across this thread where Adrian Colyer implied that an external "bundle watcher" could be responsible for activating bundles when they are installed into the framework.
So, my solution was to:
Add a custom header to bundle B, C, and D's respective manifests, e.g., "MyApp-AutoStart: true"
Create a bundle listener that responds when a bundle is moved into the RESOLVED state, and looks for the header
If the header's value is "true," the bundle listener calls bundle.start()
Using this method, the bundles I want to be started are started without having to resort to using config.ini, and they can come and go as they please, but their services are available when queried.
Also have a look at felix fileinstall, which watches a directory for bundles and automatically installs and starts them. When a file is deleted, the bundle is stopped and uninstalled as well.
Related
Given this scenario:
Bundle A: component 1A (enabled:false)
Bundle B: component 2B
How can i enable component 1A from Bundle B or Component 2B?
I've tried to do it by using componentContext,
dsContext.enableComponent("1A");
but it seems to work only with services in the same bundle.
Your using a mechanism that is intended for management and it seems you want to use it on application level. Declarative services should be enabled/disabled through their dependencies, or through a domain specific means. You should not let another actor that enables/disables a component. Using this route you likely get very complex systems since it is difficult to control the timing and order.
Technically, you should use the Apache Felix SCR Service to control the enable/disable of a DS, this is unfortunately not yet standardized and then requires Apache Felix SCR as implementation of DS.
If you explain why you want to enable/disable other components it might be possible to point you to better solutions.
I would like to know what is "Activate this plug-in when one of its classes is loaded" check-box in Eclipse manifest editor useful for.
I thought Eclipse always use "lazy initialization" approach. Does have this option a relation to the BundleActivator class of the plugin? is initialization something different to activation?
Here is a similar question, but I don't understand it entirely.
Ticking the box causes the following header to be set in the manifest:
Bundle-ActivationPolicy: lazy
I'll start with how "pure" OSGi deals with this. IF the bundle is started with the START_ACTIVATION_POLICY flag then the bundle enters the STARTING state but the activator's start() method is not invoked and a ClassLoader is not allocated for the bundle. The bundle stays in STARTING until, for whatever reason, a class needs to be loaded from the bundle. At that point a ClassLoader is allocated and the activator (if any) is instantiated and its start() method is invoked before the requested class is loaded.
However Eclipse layers additional semantics on the top. As background, Eclipse always tries to avoid starting bundles in order to keep its start-up time minimal. A very small core set of bundles is started by default (the list is in configuration/config.ini) and one of these is called the p2 "simpleconfigurator". The simpleconfigurator looks for bundles that have the Bundle-ActivationPolicy:lazy header and it starts them with the START_ACTIVATION_POLICY flag... therefore these bundles will be "lazily" started as described above.
The important point is that all other bundles that do not contain the header will not be started at all under Eclipse. They will stay in RESOLVED state, their activators will not be invoked, and if they contain any Declarative Services component they will not be loaded. This is because Declarative Services only ever looks at bundles that are in ACTIVE or STARTING state.
Therefore the main reason to use the header is if we want to write a bundle containing Declarative Services components that need to work under Eclipse.
In other environments there is no need to use the header. Most normal OSGi apps simply start all bundles, rather than trying to selectively start a subset of bundles. Note that this doesn't mean OSGi apps don't worry about lazy loading! Declarative Services already supports lazy loading without messing around with bundle class loading triggers. In my opinion Eclipse gets this wrong and has added unnecessary complexity to the bundle lifecycle. Nevertheless if you are running in Eclipse then you have no choice but to understand and work with its limitation.
Suppose there are two OSGi bundle's A and B exporting x and y package respectively.
If there is a case where A is dependent on B's export and B on A's export which one should be started first.
And suppose one wants to get the ServiceReference from shared registry in a different class(i.e. not in Activator class) then how to initialize the BundleContext object with the current bundle's context.
This might solve the case I mentioned above, about interdependency.
Like A can use B's export in its start method of activator and B can use A's export in a different class's method when invoked
Package resolution (resolving) is different that starting and running bundles. It is very important not to conflate the two.
An OSGi framework can resolve cycles in package dependencies. So once the bundles are resolved, they can be started in some order. You need to make sure you don't design bundles to depend upon their relative start order. Which is why you use services and something like DS. Cycles in service dependencies can't be solved. So make sure you avoid such cycles.
I have a problem on 2.2.8 version of Karaf (and most probably on the earlier versions too).
I'm going to use Karaf to host the system with dynamically deployed bundles. Bundles are deployed by users and i cannot know beforehand which are they.
I expect order of the BundleActivator.start() to exactly correspond to package dependencies between bundles (dependencies of import/export packages) and planning to expect that it will be safe to assume that bundle0 will be completely initialized before bundle1 is going to be started. But it is not so - it seems that BundleActivator.start() is invoked in a "random" order and disregards package dependencies between bundles.
Sample use-case, I have 3 libs
test-lib0 - defines testlib0.ITestRoot, exports testlib0 package
test-lib1 - defines testlib1.TestRoot implements ITestRoot, exports testlib1 package
test-lib2 - uses both libs, ITestRoot and TestRoot
When Karaf is started, i see following sample output in console
karaf#root> TestLib1Activator.start()
TestLib2Activator.start()
ITestRoot: interface com.testorg.testlib0.ITestRoot - 16634462
TestRoot: class com.testorg.testlib1.TestRoot - 21576551
TestLib0Activator.start()
but i expect it should be always in this order
TestLib0Activator.start()
TestLib1Activator.start()
TestLib2Activator.start()
ITestRoot: interface com.testorg.testlib0.ITestRoot - 16634462
TestRoot: class com.testorg.testlib1.TestRoot - 21576551
I'm attaching sample project for tests. Test case: after "mvn install" just move jars from ./deploy folder to the same folder of Karaf, trace messages should appear in console.
(Note: it may work correctly from the first attempt, try one more time then :))
Sample test project
http://karaf.922171.n3.nabble.com/file/n4025256/KarafTest.zip
Note: this is cross-post from http://karaf.922171.n3.nabble.com/What-is-the-natural-start-order-for-dependent-bundle-td4025256.html
In OSGi the bundle lifecycle is installed → resolved → starting → started.
Import-Package and Export-Package only influence when the bundle goes from installed to resolved. So the framework makes sure all bundles you import packages from are resolved before your bundle but then your bundle only goes to the resolved state. Then in a second step the activators are called. So you can not assume the activators are called in the same order. If you need some initializations before your testlib2 can work then you should use OSGi services.
So If I understood your case correctly then you testlib0 defines an interface, testlib1 implements it and testlib2 wants to use the implementation. So the best way to achieve this is to publish the impl as an OSGi service in testlib1 and reference this service in testlib3. You can then use the service with a ServiceTracker or with e.g. blueprint. I have a small example that shows this: http://www.liquid-reality.de/x/DIBZ . So if you do your case like in my example blueprint makes sure that the context of testlib2 only gets started when the service is there. It will even stop testlib2 when the service goes away.
As the title suggests, I'm having problems with OSGI + Spring DM.
In my project design, i have a bundle A that requires a service svB and exports service svA. Bundle B requires svA and exports svB (among other things, of course). This seems to be causing a deadlock, as it appears both bundles are waiting for the other to go online. Is that sort of deadlock possible with Spring DM? Is there a solution to this?
This doesn't sound like a problem with Spring-DM, rather you have set yourself up for this deadlock: A depends on B, B depends on A, thus no-one can get any work done. To break out of this, you probably need to change your design, and enable either one of A or B to start without the other. Meanwhile, the other one should have some lazy-loading logic built into it (this would be your job) and continue it's start-up sequence when the other one has come online on it's own.
With OSGi Declarative Services, you are able to declare a dependency on a service but allow it to be absent at the time you are going to start (do this using the cardinality option.)