Component lifecycle support
When a component is installed, it is first resolved and then started. Resolving a component implies that all its static dependencies (i.e., the imported packages of its bundle container) are resolved (i.e., exported by some other, installed bundles).
Furthermore, when using Declarative Services, the dynamic service dependencies of a component must also be resolved in order to be able to start it (i.e., activate it). We demonstrate these two dependencies in the following example.
Revisiting the CLI Client
In this tutorial, we will revise the "CLI_Client" that was developed in the previous tutorial. In this respect, you can simply copy the code used in the previous example into a new folder and make changes as stated in the following.
The source code of the new "CLI_Client" class looks as follows:
package cy.ac.ucy.cs.osgi.tutorial5;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.osgi.service.component.ComponentContext;
import java.util.logging.Logger;
public class CLI_Client implements CommandProvider
{
private final Logger logger = Logger.getAnonymousLogger();
public CLI_Client()
{
super();
logger.info("CLI_Client: Constructed component");
}
public String getHelp()
{
return "\ttest - Tests interaction with the Runnable service";
}
protected void activate(ComponentContext componentContext)
{
logger.info("CLI_Client: activate");
}
protected void deactivate(ComponentContext componentContext)
{
logger.info("CLI_Client: deactivate");
}
private Runnable runnableService = null;
public void setRunnableService(Runnable runnableService)
{
this.runnableService = runnableService;
}
public void unsetRunnableService(Runnable runnableService)
{
this.runnableService = null;
}
public void _test(CommandInterpreter ci)
{
if(runnableService == null)
{
System.out.println("Testing failed: no Runnable service provider available");
}
else
{
System.out.println("Invoking Runnable service ...");
runnableService.run();
System.out.println("Done!");
}
}
}
The changes are marked in bold, and consist of the following additions:- Two new packages were imported (org.osgi.service.component.ComponentContext and java.util.logging.Logger)
- A logger field was defined, and an info log message was added to the constructor
- Two methods were defined, with the signature "protected void (de)activate(ComponentContext)"; both of them are simply used to output an info log message
<?xml version="1.0"?>
<component name="CLI_Client">
<implementation class="cy.ac.ucy.cs.osgi.tutorial5.CLI_Client"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="runnable_service"
interface="java.lang.Runnable"
bind="setRunnableService"
unbind="unsetRunnableService"
cardinality="1..1"
policy="dynamic"/>
</component>
Next, define the new "MANIFEST.MF" file. Note that the file is exactly the same, except for adding a new, second imported package:Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tutorial 5: CLI_Client
Bundle-SymbolicName: CLI_Client
Bundle-Version: 1.0.0
Import-Package: org.eclipse.osgi.framework.console,
org.osgi.service.component
Service-Component: OSGI-INF/CLI_Client.xml
Finally, proceed to build the "CLI_Client.jar" JAR file using the same structure as the one used for the original "CLI_Client" (we keep the name of the JAR file the same as the one of the last tutorial on purpose).Deploying the new CLI_Client
To deploy the newly developed component, copy the generated JAR file in the deployment folder and replace the one from the previous tutorial. Please note at this point that this has no implications on the running instance of the "CLI_Client" component. To update the actual new component, run the "update" command in the console, as follows:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.2.R34x_v20080826-1230
1 ACTIVE org.eclipse.equinox.ds_1.0.0.v20080427-0830
2 ACTIVE org.eclipse.equinox.util_1.0.0.v20080414
3 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203
4 ACTIVE RunnableProvider_1.0.0
5 ACTIVE RunnableConsumer_1.0.0
6 RESOLVED CLI_Client_1.0.0
osgi> update 6
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.2.R34x_v20080826-1230
1 ACTIVE org.eclipse.equinox.ds_1.0.0.v20080427-0830
2 ACTIVE org.eclipse.equinox.util_1.0.0.v20080414
3 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203
4 ACTIVE RunnableProvider_1.0.0
5 ACTIVE RunnableConsumer_1.0.0
6 INSTALLED CLI_Client_1.0.0
At this point, note how the state of the "CLI_Client" component has changed from "RESOLVED" to "INSTALLED". The "CLI_Client" component can be started again using the "start 6" command.osgi> start 6
Jan 4, 2009 7:05:14 PM cy.ac.ucy.cs.osgi.tutorial5.CLI_Client <init>
INFO: CLI_Client: Constructed component
Jan 4, 2009 7:05:14 PM cy.ac.ucy.cs.osgi.tutorial5.CLI_Client activate
INFO: CLI_Client: activate
osgi> stop 4
Jan 4, 2009 7:05:17 PM cy.ac.ucy.cs.osgi.tutorial5.CLI_Client deactivate
INFO: CLI_Client: deactivate
osgi> start 4
Jan 4, 2009 7:05:21 PM cy.ac.ucy.cs.osgi.tutorial5.CLI_Client <init>
INFO: CLI_Client: Constructed component
Jan 4, 2009 7:05:21 PM cy.ac.ucy.cs.osgi.tutorial5.CLI_Client activate
INFO: CLI_Client: activate
Interestingly, when a component is constructed, activated and deactivated, appropriate log messages appear in the console. This is the result of the OSGi framework constructing the component and invoking the "activate" and "deactivate" methods on it. This is done using a technique commonly referred to as Inversion of Control (IoC).What is even more interesting though, is that stopping and starting a different service (in this case the "RunnableProvider"), causes the component to be stopped and started automatically. This happens because the service descriptor of this updated component defines a mandatory, one-to-one dependency on the "java.lang.Runnable" service. As component with ID #4 starts and stops, the "java.lang.Runnable" service becomes unavailable and back available. Since the "RunnableProvider" is the single only component that offers this service, the Declarative Services runtime realizes that the "CLI_Client" must be deactivated first, and then activated again when the service is available again.
Homework 5.1: Build a second "java.lang.Runnable" provider, and name it "RunnableProvider2" (other than the name, it can be identical to the original "RunnableProvider"). Then deploy and start it. While both the "RunnableProvider" and the "RunnableProvider2" are both started, along with the new "CLI_Client", try to stop the used provider and note what happens to the "CLI_Client".
Homework 5.2: Discuss with a few words each possible transition in the OSGi bundle's lifecycle state diagram (from OSGi Service Platform Release 4 Version 4.1 Core Specification):

Homework 5.1: Read section 2.9 (Incremental Development) in the second chapter of Neil Bartlett's book
4 comments:
STO EKSHS SIMEIO DEN PREPEI NA YPARXEI TO ENTER DIOTI DEN TO KANEI COMPILE..
Import-Package: org.eclipse.osgi.framework.console,
org.osgi.service.component
TO org.osgi.service.component PREPEI NA EINAI DEKSIA APO TO org.eclipse.osgi.framework.console, KAI NA DIAXWRIZETAI ME TO TELEYTAIO MONO ME SPACE!!
Michael, in my experience it is possible to use "ENTER" to separate multiple values as long as the new line starts with a space (' ') character.
Gia na to lete eseis kati parapanw tha kserete, aplws sxedon se ola ta tutorials pou exete ENTER meta den exete SPACE opote den doulevoun.. Anyway, thanks gia tin pliroforia :)
Michali,
Please note that the files shown here are not exactly the same as the ones used in the code (unfortunately, the space was removed during the transformation to HTML). But following these guidelines should make your code work.
Post a Comment