Presentation is loading. Please wait.

Presentation is loading. Please wait.

OSGi: The Lifecycle Layer. The Extender Pattern

Similar presentations


Presentation on theme: "OSGi: The Lifecycle Layer. The Extender Pattern"— Presentation transcript:

1 OSGi: The Lifecycle Layer. The Extender Pattern

2 Reading Ch.1: OSGi revealed Ch 2: Mastering modularity
Ch 3: Learning lifecycle Ch 4: Studying services Ch 11: Component models and frameworks

3 Lifecycle Management Defines the bundle lifecycle operations :
The lifecycle operations allow you to manage and evolve an application from its outside, by dynamically changing the composition of bundles inside a running framework. Defines how your bundles gain access to their execution context : Internal to an application, the lifecycle layer provides bundles with a way to interact with the OSGi framework and the facilities it provides at execution time.

4 OSGi Bundle Lifecycle

5 OSGI Console Most OSGi framework implementations have their own shells for interacting with a running framework Some OSGI Console commands: help List all available commands. ss List of all bundles together with their state and id. ss <string> List all bundles with names containing that string. start <id> Start up the bundle with a given id. stop <id> Stop the bundle with the given id. install <url> Install the bundle that the URL refers to. uninstall <id> Uninstall the bundle with the given id. diag <id> Show resolution problems for bundle with given id. exit

6

7

8 The System Bundle At execution time, the framework is represented as a bundle with an identifier of 0, called the system bundle. You don’t install the system bundle—it always exists while the framework is running. The system bundle follows the same lifecycle as normal bundles, so you can manipulate it with the same operations as normal bundles, but be careful ! Stopping the system bundle means shutting the system down.

9 The Bundle Cache When installing a bundle, the framework reads the bundle JAR file and saves a copy in a private area known as the bundle cache. This means two things: Installing a bundle into the framework is a persistent operation. After the bundle is installed, the framework no longer needs the original copy of the bundle JAR file. If you start an OSGi framework, install some bundles, shut down the framework, and then restart it, the bundles you installed will still be there in their original states In terms of your application, the bundle cache acts as the deployed configuration of the application. Your application’s configuration is the set of bundles you install into the framework

10 The Lifecycle Layer API
The lifecycle layer API is composed of three main interfaces: BundleActivator, BundleContext, and Bundle. A BundleActivator is how a bundle hooks into the lifecycle layer to become lifecycle aware, The BundleContext represents the OSGi container, offers access to all framework facilities for inspecting and modifying the framework state at execution time. Each bundle has an associated Bundle object

11 Bundle Activator The bundle activator is a class implementing the org.osgi.framework.BundleActivator interface This interface provides the bundle with a hook into the lifecycle layer and the ability to customize what happens when it’s started or stopped. The framework knows about the activator of a bundle from its manifest file: the Bundle-Activator header specifies the class implementing the activator Not all bundles need an activator! An activator is necessary only if you’re creating a bundle and wish to specifically interact with OSGi API or need to perform custom initialization/de-initialization actions.

12 The BundleActivator Interface
public interface BundleActivator { public void start(BundleContext context) throws Exception; public void stop(BundleContext context) throws Exception; } When the bundle is installed and started, the framework constructs an instance of the activator class and invokes the start() method. When the bundle is stopped, the framework invokes the stop() method. The activator instance on which start() is called is the same instance on which stop() is called. After stop() is called, the activator instance is destroyed. If the bundle is restarted after being stopped, a new activator instance is created !

13 Activator Example import org.foo.hello.Greeting;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext ctx) { System.out.println("My Message - Started bundle Hello"); } public void stop(BundleContext ctx) { System.out.println("My Message - Stopped bundle Hello");

14 Example: Hello World Which bundle really needs an Activator ?
org.foo.hello Greeting org.foo.hello import org.foo.hello.cli Client import Activator org.foo.hello.impl org.foo.hello.impl GreetingImpl Import org.osgi.*

15 Example: Hello World Which bundle really needs an Activator ?
Not all bundles need an activator! The hello and hello.impl bundles are used in this scenario as simple libraries. They do not need activators. Still we may give them an activator (such as the one printing messages) The client bundle does not export anything; it needs an activator to start its activity. The start() method of the activator is acting as an entry point similar with a main() function.

16 ClientActivator (version 1)
public class ClientActivator implements BundleActivator { private Greeting g=null; public void start(BundleContext context) throws Exception { g= new GreetingImpl(); System.out.println(g.sayHello()); } public void stop(BundleContext context) throws Exception { System.out.println("Greeting - stop"); The start() method must return quickly ! (because only after this the bundle is ACTIVE) Threads may be created and started here if needed ! All threads must be finished at stop().

17 ClientActivator (Version 2)
public void start(BundleContext context) throws Exception { g=new GreetingImpl(); stop = false; new Thread(new Runnable() { public void run() { while (!stop) { try { Thread.sleep(8000); System.out.println(g.sayHello()); } catch (Exception e) {} } }).start(); public void stop(BundleContext context) throws Exception { stop = true;

18 The BundleContext Interface
public interface BundleContext { ... String getProperty(String key); Bundle getBundle(); Bundle installBundle(String location, InputStream input) throws BundleException; Bundle installBundle(String location) throws BundleException; Bundle getBundle(long id); Bundle[] getBundles(); void addBundleListener(BundleListener listener); void removeBundleListener(BundleListener listener); void addFrameworkListener(FrameworkListener listener); void removeFrameworkListener(FrameworkListener listener); }

19 The Bundle Interface public interface Bundle { ...
BundleContext getBundleContext(); long getBundleId(); Dictionary getHeaders(); Dictionary getHeaders(String locale); String getLocation(); int getState(); String getSymbolicName(); Version getVersion(); void start(int options) throws BundleException; void start() throws BundleException; void stop(int options) throws BundleException; void stop() throws BundleException; void update(InputStream input) throws BundleException; void update() throws BundleException; void uninstall() throws BundleException; }

20 BundleContext Example
import org.foo.hello.Greeting; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext ctx) { System.out.println("My Message - Started bundle Hello"); System.out.println("All the bundles in my context:"); Bundle[] bundles=ctx.getBundles(); for (Bundle b:bundles) { System.out.println(b.getBundleId()+" "+b.getSymbolicName()); }

21 Listening for events The lifecycle layer API provides access to a lot of information, but it isn’t easy to poll for changes; it’s much more convenient if you can be notified when changes occur. To make this possible, the OSGi framework supports two types of events: BundleEvents and FrameworkEvents. The former event type reports changes in the lifecycle of bundles, whereas the latter reports framework-related issues. You can use the normal Java listener pattern in your bundles to receive these events. The BundleContext object has methods to register BundleListener and FrameworkListener objects for receiving BundleEvent and FrameworkEvent notifications, respectively.

22 Bundle events BundleEvent.INSTALLED BundleEvent.RESOLVED
BundleEvent.STARTED BundleEvent.STOPPED BundleEvent.UPDATED BundleEvent.UNINSTALLED BundleEvent.UNRESOLVED

23 BundleListener Example
class MyBundleListener implements BundleListener { public void bundleChanged(BundleEvent event) { System.out.println("Event type="+event.getType()+ " bundle"+event.getBundle()+ " source="+event.getSource()); } public class Activator implements BundleActivator { public void start(BundleContext ctx) { System.out.println("My Message - Started bundle Hello"); ctx.addBundleListener(new MyBundleListener());

24 The Extender Pattern The goal of the extender pattern is to achieve dynamically extensible applications. The technique of the extender pattern relies on exploiting the lifecycle events (installing, resolving, starting, stopping, etc) of other bundles and the feature of defining custom attributes in bundle metadata.

25 The Extender Pattern Typically, some bundle in the application acts as the extender: it listens for bundles being started and/or stopped. When a bundle is started, the extender probes it to see if it’s an extension bundle. The extender looks in the bundle’s manifest for specific metadata it recognizes. If the bundle does contain an extension, the extension is described by the metadata. The extender reads the metadata and performs the necessary tasks on behalf of the extension bundle to integrate it into the application. The extender also listens for extension bundles to be stopped, in which case it removes the associated extensions from the application.

26 Example: Hello World Dynamically Extensible Application
The client must detect, during its runtime, if Greeting Extension bundles are activated and immediately use them If a Greeting Extension bundle is stopped the client will remove the extension A bundle is considered a Greeting Extension if: Its metadata contain the custom attributes GreetingExtensionName ExtensionClass It is expected that the extensionclass implements the interface Greeting

27 Example: Hello World Dynamically Extensible Application
org.foo.hello Greeting Extension bundle org.foo.hello.impl1 MF GreetingImpl1

28 Example: Hello World Manifest file for EnglishGreeting Extension
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Implem1 Bundle-SymbolicName: org.foo.hello.implem1 Bundle-Version: qualifier Bundle-Activator: org.foo.hello.implem1.Activator Import-Package: org.foo.hello, org.osgi.framework;version="1.3.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Greeting-Extension-Name: EnglishGreeting Extension-Class: org.foo.hello.implem1.GreetingImpl1

29 Example: Hello World Manifest file for FrenchGreeting Extension
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Implem2 Bundle-SymbolicName: org.foo.hello.implem2 Bundle-Version: qualifier Bundle-Activator: org.foo.hello.implem2.Activator Import-Package: org.foo.hello, org.osgi.framework;version="1.3.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Greeting-Extension-Name: FrenchGreeting Extension-Class: org.foo.hello.implem2.GreetingImpl2

30 Example: Hello World Dynamically Extensible Application
org.foo.hello Greeting org.foo.hello import org.foo.hello.cli org.foo.hello.impl1 Client Activator GreetingImpl1 org.foo.hello.impl2 GreetingImpl1 MF GreetingImpl2 Import org.osgi.*

31 Example: Hello World Dynamically Extensible Application
Applying the Extender Pattern: The client registers GreetingListener - a BundleListener listening for BundleEvent.STARTED and BundleEvent.STOPPED events When receiving the event notification, it will probe if the bundle that generated it is a Greeting Extension (by inspecting its metadata for the ExtensionName attribute) If the event was not generated by an extension bundle, ignore it If the bundle is an extension bundle that has to be added: Inspect metadata to know the value of the ExtensionClass attribute Request the bundle to load the extension class and instantiate it via reflection The client will get the instantiated object and use it via the Greeting interface

32 public class GreetingListener implements BundleListener {
private GreetingSet m_gs = null; public GreetingListener(GreetingSet gs) { m_gs = gs; } public void bundleChanged(BundleEvent event) { private boolean isExtension(Bundle bundle) { private void addExtension(Bundle bundle) { private void removeExtension(Bundle bundle) {

33 GreetingListener::bundleChanged
public void bundleChanged(BundleEvent event) { System.out.println("Listener: Event type=" + event.getType() + " bundle“ + event.getBundle() + " source=" + event.getSource()); Bundle bundle = event.getBundle(); if (event.getType() == BundleEvent.STARTED) { if (isExtension(bundle)) addExtension(bundle); } if (event.getType() == BundleEvent.STOPPED) { removeExtension(bundle);

34 GreetingListener::isExtension
private boolean isExtension(Bundle bundle) { Dictionary dict = bundle.getHeaders(); // Try to get the name of the extension. String name = (String) dict.get(“Greeting-Extension-Name”); // Return immediately if the bundle is not an extension. if (name == null) { System.out.println("Bundle " + bundle.getSymbolicName() + " not a Greeting Extension"); return false; } + " is a Greeting Extension"); return true;

35 GreetingListener::addExtension
private void addExtension(Bundle bundle) { System.out.println("Greeting extension will be added: " + bundle.getSymbolicName()); Dictionary dict = bundle.getHeaders(); String name = (String) dict.get(“Greeting-Extension-Name”); // Get the class of the extension. String className = (String) dict.get(“Extension-Class”); Class clazz = null; try { clazz = bundle.loadClass(className); m_gs.addGreeting(name, (Greeting) clazz.newInstance()); } catch (Exception e) { e.printStackTrace(); }

36 ClientActivator::start
public void start(BundleContext context) throws Exception { stop = false; m_gs = new GreetingSet(); context.addBundleListener(new GreetingListener(m_gs)); new Thread(new Runnable() { public void run() { while (!stop) { try { Thread.sleep(8000); String text = ""; for (Object g : m_gs.getAllGreetings()) { text = text + " " + ((Greeting) g).sayHello(); } System.out.println(text); } catch (Exception e) {} }).start();

37 Summary A bundle can only be used by installing it into a running instance of the OSGi framework. The framework associates a lifecycle state with each installed bundle The lifecycle layer API is composed of three main interfaces: BundleActivator, BundleContext, and Bundle. A BundleActivator is how a bundle hooks into the lifecycle layer to become lifecycle aware, which allows it to gain access to all framework facilities for inspecting and modifying the framework state at execution time. Monitoring bundle lifecycle events is a form of dynamic extensibility available in the OSGi framework based on the dynamically changing installed set of bundles (also known as the extender pattern).


Download ppt "OSGi: The Lifecycle Layer. The Extender Pattern"

Similar presentations


Ads by Google