OSGi Component Models and Frameworks Declarative Services Reading

  • Slides: 53
Download presentation
OSGi Component Models and Frameworks. Declarative Services

OSGi Component Models and Frameworks. Declarative Services

Reading • Ch. 1: OSGi revealed • Ch 2: Mastering modularity • Ch 3:

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

Outline • Review of concepts: – Components, Models, Frameworks • Evaluation of OSGi as

Outline • Review of concepts: – Components, Models, Frameworks • Evaluation of OSGi as a component model: – Mapping of concepts – Limitations • Advanced component frameworks over OSGi: – General requirements and solutions – Case study: OSGi Declarative Services

Component Concepts Review • Components are software building blocks which can be independently deployed

Component Concepts Review • Components are software building blocks which can be independently deployed and have explicit dependencies; they provide functionality via interfaces and may require functionality provided by other components via their interfaces. • A component model describes what a component looks like, how it interacts with other components, and what capabilities it has (such as lifecycle or configuration management) • A component framework implements the runtime needed to support a component model and execute the components

OSGi as a component model • The core OSGi specification defines a component model

OSGi as a component model • The core OSGi specification defines a component model and the framework for executing the corresponding components • special kind of component model, called a serviceoriented component model • Component = bundle, unit of deployment • Model = OSGi specification • Framework = OSGi frameworks (different implementations) • Provided and Required Interfaces ? - OSGi Services are similar with these • In OSGi, the logical bundle (the component) is equated with the physical bundle (the module) and this means there can be only one component per module and, further, only one component instance.

Module Dependencies Import-package P 1 Bundle. A Export-package P 1 Bundle. B • module-level

Module Dependencies Import-package P 1 Bundle. A Export-package P 1 Bundle. B • module-level dependencies are explicitly specified (import-package and export-package in manifest file) and automatically managed and matched by the framework

Module Dependencies Import Greeting. Implem Export Greeting IGreeting • Imported and exported packages cannot

Module Dependencies Import Greeting. Implem Export Greeting IGreeting • Imported and exported packages cannot be assimilated with provided and required interfaces of a component

Service Dependencies IGreeting. Consumer Greeting. Implem • Service-level dependencies are not explicitly specified (published

Service Dependencies IGreeting. Consumer Greeting. Implem • Service-level dependencies are not explicitly specified (published and consumed services can be seen only in code) • Service-level dependencies could be assimilated with required and provided interfaces of a component

Limitations of the OSGi Component Model • The main weakness of the OSGi component

Limitations of the OSGi Component Model • The main weakness of the OSGi component model: – Service-level dependencies are not explicit • provided and required services are seen only by inspecting all the source code – it relies on components manually managing their own service-level dependencies • A lot of boilerplate code for publishing services, locating and binding services, checking if required services are available before publishing their own provided services

Example -The Limitations of the OSGi Component Model • We want to implement following

Example -The Limitations of the OSGi Component Model • We want to implement following simple components and composition, using raw OSGI services: • a component Foo. Impl depends on service Bar and should only publish its service Foo when Bar is available org. foo Foo. Implem org. foo. barimpl Bar Foo Bar. Tracker Bar. Implem Bar Activator

Example (contd) • Interface Bar: contained in simple bundle org. foo. barapi package org.

Example (contd) • Interface Bar: contained in simple bundle org. foo. barapi package org. foo. barapi; public interface IBar { void do. Bar(); }

Example (contd) • Bar Implementation: in bundle org. foo. barimpl package org. foo. barimpl;

Example (contd) • Bar Implementation: in bundle org. foo. barimpl package org. foo. barimpl; import org. foo. barapi. IBar; public class Bar. Impl implements IBar{ public void do. Bar() { System. out. println("do bar"); } }

Example (contd) • Bundle Bar. Impl contains also an Activator class • The Activator

Example (contd) • Bundle Bar. Impl contains also an Activator class • The Activator instantiates Bar. Impl objects and publishes them in the service registry.

Example (contd) • Interface Foo: package org. foo; public interface IFoo { void do.

Example (contd) • Interface Foo: package org. foo; public interface IFoo { void do. Foo(); }

Example (contd) • Foo Implementation: package org. foo; import org. foo. barapi. IBar; public

Example (contd) • Foo Implementation: package org. foo; import org. foo. barapi. IBar; public class Foo. Impl implements IFoo{ private IBar m_bar=null; protected void set. Bar(IBar b) { m_bar=b; } protected void unset. Bar(){ m_bar=null; } public void do. Foo() { if (m_bar!=null) m_bar. do. Bar(); } }

Example (contd) • Bundle Foo contains also a Bar. Tracker that tracks Bar services.

Example (contd) • Bundle Foo contains also a Bar. Tracker that tracks Bar services. The Bar. Tracker is opened in the start of the bundle Activator. • If one is discovered, it checks whether this is the first Bar service it has found. If so, it calls the Foo. Impl. set. Bar() method prior to registering the Foo service of Foo. Impl. If more than one Bar service is found, backups are stored. • If Bar. Tracker detects that the Bar service being used has been removed, it replaces that service with one of the backups. If no backup is available, it unregisters the Foo service and calls the Foo. Impl. unset. Bar() method.

Component Frameworks over OSGi • OSGi-based component frameworks: – Allow you to explicitly describe

Component Frameworks over OSGi • OSGi-based component frameworks: – Allow you to explicitly describe provided and required services, acting as provided and required interfaces – Remove boilerplate code from user code (replacing with metadata files), framework manages composition – They are actually Dependency Injection Frameworks ! Foo Bar Foo. Implem Bar. Implem

Component Frameworks over OSGi • All Component Frameworks over OSGi define additional, component-related metadata,

Component Frameworks over OSGi • All Component Frameworks over OSGi define additional, component-related metadata, which describes the components contained in the bundle JAR file. – A component’s description defines which services it provides and which it requires • Component frameworks in OSGi are generally implemented as other bundles using the extender pattern. – They listen for bundles containing components to come and go so they can start managing the contained components – If the component’s required services are satisfied, the component framework can instantiate the component and publish its provided services into the service registry. In this way they remove boilerplate code from user bundles

Component Frameworks over OSGi

Component Frameworks over OSGi

OSGi Based Component Frameworks • There are different OSGi based component frameworks: – By

OSGi Based Component Frameworks • There are different OSGi based component frameworks: – By the OSGi Alliance: • Declarative Services: defined by the OSGi Alliance as part of the R 4 compendium specification • Blueprint Container: from the OSGi R 4. 2 Enterprise Specification, – Outside of the OSGi Alliance, a number of different component models have been built for or ported to the OSGi environment: • i. POJO: Apache Felix i. POJO http: //felix. apache. org/documentation/subprojects/apache-felixipojo. html • Google Guice peaberry http: //code. google. com/p/peaberry/

OSGi Declarative Services • “Declarative Services" (DS) is a specification from the OSGi Compendium,

OSGi Declarative Services • “Declarative Services" (DS) is a specification from the OSGi Compendium, section 112. It was introduced in Release 4. 0 and had significant improvements in R 4. 2. • It is based on the extender model. • Like all extenders, DS performs tasks on behalf of other bundles. • The DS spec defines this extender and it is implemented by frameworks. The extender bundle itself is called the “Service Component Runtime" or SCR • In Equinox, you have to install the SCR bundle which is : org. eclipse. equinox. ds_<qualifier>. jar and its dependent bundles.

Providing Services With DS • Example: The Bar. Component as a DS bundle jar

Providing Services With DS • Example: The Bar. Component as a DS bundle jar file that provides a Bar service Comp. xml Bar Manifest Bar. Implem Aditional component metadata file Manifest file with aditional header The implementation – the POJO class No need for activator, for instantiating Bar. Implem and registering as service !

Bar. Impl Manifest File Manifest-Version: 1. 0 Bundle-Manifest. Version: 2 Bundle-Name: Barimpl Bundle-Symbolic. Name:

Bar. Impl Manifest File Manifest-Version: 1. 0 Bundle-Manifest. Version: 2 Bundle-Name: Barimpl Bundle-Symbolic. Name: org. foo. barimpl Bundle-Version: 1. 0. 0. qualifier Import-Package: org. foo. barapi, org. osgi. framework; version="1. 3. 0" Bundle-Required. Execution. Environment: Java. SE-1. 7 Service-Component: component. xml The last line of the manifest file tells the SCR that this bundle contains a DS component, described in the file component. xml

Bar. Impl Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns:

Bar. Impl Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http: //www. osgi. org/xmlns/scr/v 1. 1. 0" name="Bar. Comp"> <implementation class="org. foo. barimpl. Bar. Impl"/> <service> <provide interface="org. foo. barapi. IBar"/> </service> </scr: component> You declare that the component provides the Bar service

Installing the Bar. Impl bundle

Installing the Bar. Impl bundle

Consuming Services with DS • Example: The Foo Component as a DS bundle that

Consuming Services with DS • Example: The Foo Component as a DS bundle that requires a Bar service (and provides a Foo service) Comp. xml Foo Manifest Bar Foo. Implem No need for activator and tracker !

Foo Manifest File Manifest-Version: 1. 0 Bundle-Manifest. Version: 2 Bundle-Name: Foo Bundle-Symbolic. Name: org.

Foo Manifest File Manifest-Version: 1. 0 Bundle-Manifest. Version: 2 Bundle-Name: Foo Bundle-Symbolic. Name: org. foo Bundle-Version: 1. 0. 0. qualifier Import-Package: org. foo. barapi, org. osgi. framework; version="1. 3. 0" Bundle-Required. Execution. Environment: Java. SE-1. 7 Service-Component: component. xml

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http:

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http: //www. osgi. org/xmlns/scr/v 1. 1. 0" name="Foo. Comp" immediate="true" > <implementation class="org. foo. Foo. Impl"/> <reference interface="org. foo. barapi. IBar" bind="set. Bar" unbind=“unset. Bar” cardinality="1. . 1" name="IBar" policy=“static"/> You declare that the component requires a Bar service <service> <provide interface="org. foo. IFoo"/> </service> </scr: component>

Installing the Foo bundle

Installing the Foo bundle

Stopping the Bar. Impl bundle

Stopping the Bar. Impl bundle

Components and Services • The DS component framework (SCR) automatically registers services on behalf

Components and Services • The DS component framework (SCR) automatically registers services on behalf of the component bundles if it can find a registered service for its requirements (registers a Foo service if a Bar service exists) • If the service dependency cannot be fulfilled (the Bar. Impl bundle is not activated or it is stopped) the service is unregistered

References to Services • Using lower level APIs we must write a lot of

References to Services • Using lower level APIs we must write a lot of “glue" code to bind to services. • DS replaces the glue code with simple declarations. • We declare references to services. • The reference element may contain following attributes: – name – the name of the reference – interface – required interface – bind – the name of the setter method associated with the ref – unbind – the name of the unset method for the ref – cardinality – policy

Cardinality of References • References may be Optional or Mandatory - whether the component

Cardinality of References • References may be Optional or Mandatory - whether the component can or cannot function without the reference • References may be for a single service instance (one-toone) or for an aggregate number of service instances (one-to-many) • The default cardinality is 1. . 1 meaning that we must have exactly one instance, the reference is mandatory. • A cardinality of 0. . 1 indicates that either zero or one instance is okay, the reference is optional. • A cardinality of 1. . n : With a multiple reference the bind/unbind methods are called for each individual service instance • A cardinality of 0. . n

Policies for References • Policies for updating component references: – Static: the service is

Policies for References • Policies for updating component references: – Static: the service is injected once and not changed until the component is deactivated. – Dynamic: the component is notified whenever the service comes or goes • if you use a dynamic policy, your component needs to cope with the possible issues (such as threading and synchronization) resulting from service dynamism !

Multiple References • Multiple references must use the dynamic policy. Static policy makes no

Multiple References • Multiple references must use the dynamic policy. Static policy makes no sense in their case. • Thread safety is therefore important and unavoidable with multiple references.

Dynamic Hello World with DS IGreeting. Impl 1 IGreeting [0. . n] Greeting. Consumer

Dynamic Hello World with DS IGreeting. Impl 1 IGreeting [0. . n] Greeting. Consumer IGreeting. Impl 2

Service Properties Bar myprop=two Bar. Implem 2 target=(myprop=one) Foo [1. . 1] Bar Foo.

Service Properties Bar myprop=two Bar. Implem 2 target=(myprop=one) Foo [1. . 1] Bar Foo. Implem myprop=one Bar. Implem

Bar. Impl Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns:

Bar. Impl Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http: //www. osgi. org/xmlns/scr/v 1. 1. 0" name="Bar. Comp"> <implementation class="org. foo. barimpl. Bar. Impl"/> <service> <provide interface="org. foo. barapi. IBar"/> </service> <property name="myprop" type="String" value="one"/> </scr: component> You declare that the component provides a Bar service with property myprop having the value one Properties may be used to configure a component but they also act as service properties and are automatically attached to services published by a component in the service registry.

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http:

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http: //www. osgi. org/xmlns/scr/v 1. 1. 0" name="Foo. Comp" immediate="true" > <implementation class="org. foo. Foo. Impl"/> <reference interface="org. foo. barapi. IBar“ target="(myprop=one)" bind="set. Bar" unbind=“unset. Bar” cardinality="1. . 1" name="IBar" policy=“static"/> You declare that the component requires a Bar service having a property myprop with value one <service> <provide interface="org. foo. IFoo"/> </service>

DS component lifecycle • When are components created? • When are they destroyed? •

DS component lifecycle • When are components created? • When are they destroyed? • Are there any callbacks at these stages? • How can you access the Bundle. Context if there is no Bundle. Activator?

DS component lifecycle • The component lifecycle is coupled to the lifecycle of its

DS component lifecycle • The component lifecycle is coupled to the lifecycle of its containing bundle. • Only components in activated bundles are eligible for lifecycle management. • If a bundle is stopped, the Declarative Services framework automatically deactivates all activated components contained in it.

DS component lifecycle states • Enabled—A simple Boolean flag controls whether the component is

DS component lifecycle states • Enabled—A simple Boolean flag controls whether the component is eligible for management. • Satisfied—The component is enabled, its mandatory dependencies are satisfied, any provided services are published in the service registry, but the component itself isn’t yet instantiated. • Activated—The component is enabled, its mandatory dependencies are satisfied, any provided services are published in the service registry, and the component instance has been created as a result of a request to use its service. • Modified—The configuration associated with the component has changed, and the component instance should be notified. • Deactivated—Either the component has been disabled or its mandatory dependencies are no longer satisfied, so its provided services are no longer available and its component instance, if created, is dereferenced for garbage collection.

Immediate vs delayed components • Many components, such as the Bar component, exist only

Immediate vs delayed components • Many components, such as the Bar component, exist only to provide services to other components. If no other deployed bundles consume these services, there is no need to expend resources activating the associated components. Components that provide services are delayed by default in Declarative Services. • If you look at the component declaration of the Foo component, you see that it specifies the immediate="true" attribute. This turns off the delayed behavior and forces the Declarative Services implementation to construct the Foo as soon as it’s satisfied. Otherwise, since it has no clients using it, it would not be instantiated. For components that don’t provide a service, it’s an error to set immediate to false because they would never be instantiated; instead, they’re implicitly defined as immediate components.

DS lifecycle callback methods • You define an activate() callback method to be invoked

DS lifecycle callback methods • You define an activate() callback method to be invoked by the Declarative Services framework when the component is activated, along with a corresponding deactivate() callback method to be called when the component is deactivated. • The activation and deactivation methods are optional, so if your component has no need to track its activation state, you can leave them out. • The names of callback methods (activate() and deactivate()) are defaults. If you wish to use different names you can define the names of these callback methods via attributes on the <component> XML element.

Example: Foo component with lifecycle callbacks • The Foo component in the previous example

Example: Foo component with lifecycle callbacks • The Foo component in the previous example assumes that there will be another component consuming its Foo service. • There could be also the case that the Foo component is the composed application’s entry-point, executing do. Foo() whenever it is activated. In order to implement this scenario we need to: – Declare the Foo component as immediate (already did this) – Implement the activate lifecycle callback method, containing an invocation of do. Foo(). • The Foo component metadata file is changed • The Foo. Impl class is changed

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http:

Foo Component Metadata File <? xml version="1. 0" encoding="UTF-8"? > <scr: component xmlns: scr="http: //www. osgi. org/xmlns/scr/v 1. 1. 0" name="Foo. Comp" You declare the names of the activate="start" deactivate="stop" lifecycle callback methods immediate="true"> <implementation class="org. foo. Foo. Impl"/> <reference bind="set. Bar" unbind="unset. Bar" cardinality="1. . 1" interface="org. foo. barapi. IBar" name="IBar" policy="static" target="(myprop=two)"/> <service> <provide interface="org. foo. IFoo"/> </service> </scr: component>

Foo Implementation public class Foo. Impl implements IFoo{ private IBar m_bar=null; protected void set.

Foo Implementation public class Foo. Impl implements IFoo{ private IBar m_bar=null; protected void set. Bar(IBar b) { m_bar=b; } protected void unset. Bar(){ m_bar=null; } Implementations of the public void do. Foo() { lifecycle callback methods if (m_bar!=null) m_bar. do. Bar(); } protected void start() { System. out. println(“Activate meth of comp Foo"); do. Foo(); } protected void stop() { System. out. println(“Dectivate meth of comp Foo"); } }

Summary • The OSGi framework is a component framework, where bundles are equivalent to

Summary • The OSGi framework is a component framework, where bundles are equivalent to components that interact via services. • Additional, more advanced component frameworks can be layered on top of the OSGi framework to further enhance the core component model. • Declarative Services (DS) is one of these more advanced component models over OSGi. DS manages service publication, service dependencies, and configuration dependencies on behalf of components.

Other advanced OSGi component models • Declarative Services is an OSGi specification and is

Other advanced OSGi component models • Declarative Services is an OSGi specification and is the simplest framework. It focuses on building lightweight components with quick startup times. • Blueprint is also an OSGi specification and provides features similar to Declarative Services, but with a richer configuration model. It’s familiar to developers who come from a Spring background. It focuses on building highly configurable enterprise-oriented applications • i. POJO is an open source solution that uses byte-code instrumentation of components to offer a sophisticated framework for building dynamic, service-based applications. • Mix-and-match: All these component frameworks are interoperable at execution time via services, so either can be used to implement a given service interface without impacting clients

Comparison of OSGi component models (1)

Comparison of OSGi component models (1)

Comparison of OSGi component models (2)

Comparison of OSGi component models (2)

Comparison of OSGi component models (3)

Comparison of OSGi component models (3)

Comparison of OSGi component models (4)

Comparison of OSGi component models (4)