Going Native with the
OSGi Service Layer
Sascha Zelzer
About Me
●

●

Post-doctoral researcher at the German Cancer Research
Center (DKFZ)
Interested in
–

Medical Image Processing
and Analysis

–

Modularity and interoperability

–

Large scale C++ systems

–

OSGi technology

●

Several years of Java and C++ programming experience

●

OSGi Invited Researcher

●

Participant in the Native OSGi specification effort
Outline
●

Motivation for native OSGi – like frameworks

●

Challenges
–

Conceptual

–

Language

●

History and Requirements

●

The C++ Micro Services Project
–

Architecture

–

Features

●

Use Cases

●

Excursion: Native OSGi

●

Roadmap & Summary
Motivation
●

●

●

●

●

Common C++ software toolkit for medical imaging (MITK)
Researchers develop their algorithms in shared libraries
(modules)
High potential for
reuse of common
services
Modularity and
interoperability are
key points
OSGi provides
established means
to handle modularity
and flexibility
Sascha Zelzer

29/10/13
Motivation
However
●

●

●

Medical image processing is traditionally done in C++
(Java and Python are gaining popularity)
Large existing code bases written in C++
Full blown OSGi framework (even if available for C++)
considered too intrusive and heavy-weight

●

C/C++ developers are very conservative

●

Lack of a migration path towards full OSGi support
Still, there is a need for strong modularity!

Sascha Zelzer

29/10/13
Challenges
OSGi layers are coupled to Java specifics
●

Module Layer
–
–

●

Class loading architecture (visibility of classes)
Dependency resolution (package wiring)

Life-cycle Layer
–
–

●

Lazy activation
Updates

Service Layer
–

●

Nothing crucial

Security Layer
–

Based on the Java 2 security architecture
Sascha Zelzer

29/10/13
Conceptual Challenge – Module Layer
●

Bundles are represented by JAR files with meta-data

●

Code is organized in packages

●

Bundles export and import Java packages

●

●

Visibility is controlled
via meta-data and
custom class loaders
OSGi takes care of
the correct wiring

Platform independent:
●

Meta-data

●

Embedded resources
Sascha Zelzer

29/10/13
Conceptual Challenge – Life Cycle
●

Elaborate bundle life-cycle and dependency resolution

●

Lazy activation triggered by class loading

●

Bundle updates at runtime

Platform independent:
●

Activation

●

Life-cycle listeners

Sascha Zelzer

29/10/13
Language Challenges
●

Garbage collector VS Destructors

●

Generics VS Templates

●

Thread-safety (without third-party libraries)

●

Common base class (Object in Java)

ServiceRegistration<?> BundleContext.registerService(
java.lang.String clazz, java.lang.Object service, …);

ServiceRegistration<?> BundleContext::registerService(
const std::string& clazz, Object* service, …);

Sascha Zelzer

29/10/13
Internal History
●

The CTK Plugin Framework (started 2007/2008)
–

Full C++ OSGi implementation (except Security Layer)

–

Qt dependency

●

C++ developers like shared libraries, but frameworks not so much

●

Full dynamism was rarely needed

●

Service registry and bundle activator solved a couple of issues
(e.g. dependencies between singletons)
Service registry and basic module layer support
useful throughout the whole code-base!

Sascha Zelzer

29/10/13
Requirements
●

No third-party dependencies (only the STL)

●

Cross-platform support (Linux, Windows, MacOS)

●

C++98 compliance (use C++11 features if available)

●

Type-safe API (no void* or client dynamic_cast calls)

●

Full Service Layer support

●

Module Layer support without its dynamics

Sascha Zelzer

29/10/13
C++ Micro Services
●

Developed and © German Cancer Research Center

●

Is a “OSGi Lite” implementation in C++

●

Apache License 2.0

●

GitHub hosted

Sascha Zelzer

29/10/13
C++ Micro Services - Architecture
The CppMicroServices library uses standard shared libraries
●

Shared objects (.so) in ELF format on Linux

●

Dynamic Link Libraries (.dll) in PE format on Windows

●

Dynamic Libraries (.dylib) in MachO format on MacOS

The dynamic linker is a
sophisticated program
handling
●

Dependency resolution

●

Symbol versioning

●

Library initialization

Sascha Zelzer

29/10/13
Module Layer – Dynamic Linker
The dynamic linker of the OS handles
●

Symbol visibility
–

GCC / Clang use __attribute__((visibility (“default”))

–

MSVC uses
__declspec(dllexport)

●

●

●

●

Dependency resolution
Symbol lookup (based on
link-time dependencies)
Less powerful dependency
versioning
No flat classpath issues as
in Java OSGi Lite!
Sascha Zelzer

29/10/13
Life Cycle – Dynamic Linker
The life-cycle is handled by the dynamic
linker too
●

●

Sequential state diagram
Successfully reaches the ACTIVE
state or fails completely

●

No lazy activation

●

No library updates at runtime

●

Activation via static initialization

●

Deactivation via static de-initialization

●

Life-cycle events available

Sascha Zelzer

29/10/13
Service Layer - Templates
●

Type-safe templated API
–

–

Any class can be used as a service interface

–

No custom dynamic_cast calls necessary

–
●

No base class for service interfaces or service
implementations required

Pointer magic hidden from the API user

API is almost identical to the OSGi specifications

Sascha Zelzer

29/10/13
Example – Type Safety
ServiceRegistration and ServiceReference classes
are templates:
struct IMyService { virtual ~IMyService(); };
US_DECLARE_SERVICE_INTERFACE(IMyService,"org.me.IMyService")
struct MyService : public IMyService {};
MyService myService;
ServiceRegistration<IMyService> reg =
context->RegisterService<IMyService>(&myService);
ServiceReference<IMyService> ref =
context->GetServiceReference<IMyService>();
IMyService* service = context->GetService(ref);
context->UngetService(ref);
reg.Unregister();

Sascha Zelzer

29/10/13
Example – Object Lifetime
●

Implicitly shared objects

●

Almost no raw pointers for library objects in the API

ServiceRegistration<IMyService> reg =
context->RegisterService<IMyService>(&myService);
ServiceReference<IMyService> ref =
context->GetServiceReference<IMyService>();

Sascha Zelzer

29/10/13
Example – Auto Loading
Library A
struct IMyService {};

Library B

Library C

struct MyService :
public IMyService {};

IMyService* service =
ctxt->GetService(...);

Loading of Library A triggers auto-loading of associated
libraries.
Sascha Zelzer

29/10/13
Example – Listeners
●

Listeners for library (bundle) events

●

Listeners for service events

Use a member function pointer
context->AddServiceListener(this, &MyClass::ServiceChanged);
void ServiceChanged(const ServiceEvent event) {…}

Or any “callable” object (functors, lambdas, etc.)
struct MyFunctorialListener {
void operator() (const ServiceEvent event) {…}
};
context->AddServiceListener(MyFunctorialListener());

Sascha Zelzer

29/10/13
Example - Resources
●

The generic resources system allows

●

Embedding arbitrary data

●

Compression if a specific threshold is reached

●

Modelling an embedded resources file system

●

Access via STL compatible streams
ModuleResource resource = module->GetResource("conf.props");
ModuleResourceStream resourceStream(resource);
std::string line;
while (std::getline(resourceStream, line))
{
std::cout << line << std::endl;
}

Sascha Zelzer

29/10/13
Example – JSON Meta-data
●

Library meta-data can be added via a JSON file

●

Embedded as a resource and parsed at load-time

●

Arbitrary key-value pairs, accessible via the module API
{
"module.version" : "1.0.2",
"module.description" : "This module provides a service",
"authors" : [ "John Doe", "Douglas Reynolds", "Daniel Kim" ],
"rating" : 5
}
Module* module = context->GetModule();
int r = ref_any_cast<int>(module->GetProperty("rating"));

Sascha Zelzer

29/10/13
Example – RFC 195 Service Scopes
●

●

In OSGi, services are singletons (sharing state) or bundle
specific (ServiceFactory)
RFC 195 formalizes service scopes
–

Singleton and Bundle Scope: As usual

–

Prototype Scope (new): Create service instances based on a
prototype on demand

class MyFactory : public PrototypeServiceFactory {…};
context->RegisterService<IMyService>(myFactory);
ServiceReference<IMyService> ref =
context->GetServiceReference<IMyService>();
ServiceObjects<IMyService> objects =
context->GetServiceObjects(ref);
IMyService* myService = objects.GetService();
objects.UngetService(myService);
Sascha Zelzer

29/10/13
Example – LDAP Filter DSL
Creating LDAP filter strings in Java is error-prone.
Filter example: “(&(name=Ben)(!(count=1)))”
context.createFilter("(&(name=Ben)(!(count=1))");

LDAPFilter filter(
LDAPProp("name") == "Ben" && LDAPProp("count") != 1
);

Sascha Zelzer

29/10/13
More

●

Global library specific GetModuleContext() function for
easy context retrieval

●

Hooks for framework log messages

●

Full static linking support

Sascha Zelzer

29/10/13
Use Cases
DS4Cpp
●

●

●

A declarative services framework in C++ based on
CppMicroServices
Contributed by Global Vision Systems
Introduces similar dependency-injection patterns across
their Java and C++ code-base

Interest from various technical companies
●

Embedded systems

●

Avionics and sensoring

●

Military sub-contractors working on mission-critical software

●

Medical Imaging (e.g. Mint Medical)
Sascha Zelzer

29/10/13
Use Case - MITK
●

Injection of an Activator class in all shared libraries

●

Conversion of singletons to services

●

Increased cohesion by embedding resources

●

●

Decreased coupling
via interfaces and
services
Auto-loading of
libraries providing
service
implementations

Sascha Zelzer

29/10/13
Use Case - MITK
●

●

●

Whiteboard pattern for interaction event listener
Hardware devices (like range cameras and optical tracker)
modelled as services
File reader writer
services with
prototype scope

Sascha Zelzer

29/10/13
Native OSGi
●

Several C/C++ implementations have been created
–
–

CTK Plugin Framework (C++, Qt based)

–

Apache Celix (C)

–

Nostrum (C++, POSIX)

–

SOF (C++, CORBA remoting)

–
●

CppMicroServices (C++)

Poco OSP (commercial)

Developers joined forces and created RFP 156 Native
OSGi for standardization of a native C/C++ API
–

RFP 156 will be voted on in November

–

RFC workis about to be started

–

CppMicroServices is field-testing a native service-layer API
Sascha Zelzer

29/10/13
Roadmap
Release 2.0
●

Service hooks

Ecosystem
●

Configuration Admin

●

Device Access

●

Event Admin

●

Remote Services

Native OSGi
●

Specify the Service Layer API

●

Work on a native Module Layer
Sascha Zelzer

29/10/13
Summary
●

OSGi Lite is well accepted by C++ developers

●

Less complexity due to the missing module layer

●

●

●

●

Less flexibility and
dynamism
C++ OSGi API
can be very close
to the Java version
Used in and
interest from
various domains
API should converge
with Native OSGi
efforts in the future
Sascha Zelzer

29/10/13
URLs
C++ Micro Service
●

Homepage http://cppmicroservices.org

●

GitHub https://github.com/saschazelzer/CppMicroServices

●

Blog http://blog.cppmicroservices.org

RFP 156 – Native OSGi
●

Bug https://www.osgi.org/bugzilla/show_bug.cgi?id=165

●

Document https://github.com/osgi/design/tree/master/rfps

Sascha Zelzer

29/10/13
Thank You!
Questions?

Sascha Zelzer

29/10/13

Going Native With The OSGi Service Layer - Sascha Zelzer

  • 1.
    Going Native withthe OSGi Service Layer Sascha Zelzer
  • 2.
    About Me ● ● Post-doctoral researcherat the German Cancer Research Center (DKFZ) Interested in – Medical Image Processing and Analysis – Modularity and interoperability – Large scale C++ systems – OSGi technology ● Several years of Java and C++ programming experience ● OSGi Invited Researcher ● Participant in the Native OSGi specification effort
  • 3.
    Outline ● Motivation for nativeOSGi – like frameworks ● Challenges – Conceptual – Language ● History and Requirements ● The C++ Micro Services Project – Architecture – Features ● Use Cases ● Excursion: Native OSGi ● Roadmap & Summary
  • 4.
    Motivation ● ● ● ● ● Common C++ softwaretoolkit for medical imaging (MITK) Researchers develop their algorithms in shared libraries (modules) High potential for reuse of common services Modularity and interoperability are key points OSGi provides established means to handle modularity and flexibility Sascha Zelzer 29/10/13
  • 5.
    Motivation However ● ● ● Medical image processingis traditionally done in C++ (Java and Python are gaining popularity) Large existing code bases written in C++ Full blown OSGi framework (even if available for C++) considered too intrusive and heavy-weight ● C/C++ developers are very conservative ● Lack of a migration path towards full OSGi support Still, there is a need for strong modularity! Sascha Zelzer 29/10/13
  • 6.
    Challenges OSGi layers arecoupled to Java specifics ● Module Layer – – ● Class loading architecture (visibility of classes) Dependency resolution (package wiring) Life-cycle Layer – – ● Lazy activation Updates Service Layer – ● Nothing crucial Security Layer – Based on the Java 2 security architecture Sascha Zelzer 29/10/13
  • 7.
    Conceptual Challenge –Module Layer ● Bundles are represented by JAR files with meta-data ● Code is organized in packages ● Bundles export and import Java packages ● ● Visibility is controlled via meta-data and custom class loaders OSGi takes care of the correct wiring Platform independent: ● Meta-data ● Embedded resources Sascha Zelzer 29/10/13
  • 8.
    Conceptual Challenge –Life Cycle ● Elaborate bundle life-cycle and dependency resolution ● Lazy activation triggered by class loading ● Bundle updates at runtime Platform independent: ● Activation ● Life-cycle listeners Sascha Zelzer 29/10/13
  • 9.
    Language Challenges ● Garbage collectorVS Destructors ● Generics VS Templates ● Thread-safety (without third-party libraries) ● Common base class (Object in Java) ServiceRegistration<?> BundleContext.registerService( java.lang.String clazz, java.lang.Object service, …); ServiceRegistration<?> BundleContext::registerService( const std::string& clazz, Object* service, …); Sascha Zelzer 29/10/13
  • 10.
    Internal History ● The CTKPlugin Framework (started 2007/2008) – Full C++ OSGi implementation (except Security Layer) – Qt dependency ● C++ developers like shared libraries, but frameworks not so much ● Full dynamism was rarely needed ● Service registry and bundle activator solved a couple of issues (e.g. dependencies between singletons) Service registry and basic module layer support useful throughout the whole code-base! Sascha Zelzer 29/10/13
  • 11.
    Requirements ● No third-party dependencies(only the STL) ● Cross-platform support (Linux, Windows, MacOS) ● C++98 compliance (use C++11 features if available) ● Type-safe API (no void* or client dynamic_cast calls) ● Full Service Layer support ● Module Layer support without its dynamics Sascha Zelzer 29/10/13
  • 12.
    C++ Micro Services ● Developedand © German Cancer Research Center ● Is a “OSGi Lite” implementation in C++ ● Apache License 2.0 ● GitHub hosted Sascha Zelzer 29/10/13
  • 13.
    C++ Micro Services- Architecture The CppMicroServices library uses standard shared libraries ● Shared objects (.so) in ELF format on Linux ● Dynamic Link Libraries (.dll) in PE format on Windows ● Dynamic Libraries (.dylib) in MachO format on MacOS The dynamic linker is a sophisticated program handling ● Dependency resolution ● Symbol versioning ● Library initialization Sascha Zelzer 29/10/13
  • 14.
    Module Layer –Dynamic Linker The dynamic linker of the OS handles ● Symbol visibility – GCC / Clang use __attribute__((visibility (“default”)) – MSVC uses __declspec(dllexport) ● ● ● ● Dependency resolution Symbol lookup (based on link-time dependencies) Less powerful dependency versioning No flat classpath issues as in Java OSGi Lite! Sascha Zelzer 29/10/13
  • 15.
    Life Cycle –Dynamic Linker The life-cycle is handled by the dynamic linker too ● ● Sequential state diagram Successfully reaches the ACTIVE state or fails completely ● No lazy activation ● No library updates at runtime ● Activation via static initialization ● Deactivation via static de-initialization ● Life-cycle events available Sascha Zelzer 29/10/13
  • 16.
    Service Layer -Templates ● Type-safe templated API – – Any class can be used as a service interface – No custom dynamic_cast calls necessary – ● No base class for service interfaces or service implementations required Pointer magic hidden from the API user API is almost identical to the OSGi specifications Sascha Zelzer 29/10/13
  • 17.
    Example – TypeSafety ServiceRegistration and ServiceReference classes are templates: struct IMyService { virtual ~IMyService(); }; US_DECLARE_SERVICE_INTERFACE(IMyService,"org.me.IMyService") struct MyService : public IMyService {}; MyService myService; ServiceRegistration<IMyService> reg = context->RegisterService<IMyService>(&myService); ServiceReference<IMyService> ref = context->GetServiceReference<IMyService>(); IMyService* service = context->GetService(ref); context->UngetService(ref); reg.Unregister(); Sascha Zelzer 29/10/13
  • 18.
    Example – ObjectLifetime ● Implicitly shared objects ● Almost no raw pointers for library objects in the API ServiceRegistration<IMyService> reg = context->RegisterService<IMyService>(&myService); ServiceReference<IMyService> ref = context->GetServiceReference<IMyService>(); Sascha Zelzer 29/10/13
  • 19.
    Example – AutoLoading Library A struct IMyService {}; Library B Library C struct MyService : public IMyService {}; IMyService* service = ctxt->GetService(...); Loading of Library A triggers auto-loading of associated libraries. Sascha Zelzer 29/10/13
  • 20.
    Example – Listeners ● Listenersfor library (bundle) events ● Listeners for service events Use a member function pointer context->AddServiceListener(this, &MyClass::ServiceChanged); void ServiceChanged(const ServiceEvent event) {…} Or any “callable” object (functors, lambdas, etc.) struct MyFunctorialListener { void operator() (const ServiceEvent event) {…} }; context->AddServiceListener(MyFunctorialListener()); Sascha Zelzer 29/10/13
  • 21.
    Example - Resources ● Thegeneric resources system allows ● Embedding arbitrary data ● Compression if a specific threshold is reached ● Modelling an embedded resources file system ● Access via STL compatible streams ModuleResource resource = module->GetResource("conf.props"); ModuleResourceStream resourceStream(resource); std::string line; while (std::getline(resourceStream, line)) { std::cout << line << std::endl; } Sascha Zelzer 29/10/13
  • 22.
    Example – JSONMeta-data ● Library meta-data can be added via a JSON file ● Embedded as a resource and parsed at load-time ● Arbitrary key-value pairs, accessible via the module API { "module.version" : "1.0.2", "module.description" : "This module provides a service", "authors" : [ "John Doe", "Douglas Reynolds", "Daniel Kim" ], "rating" : 5 } Module* module = context->GetModule(); int r = ref_any_cast<int>(module->GetProperty("rating")); Sascha Zelzer 29/10/13
  • 23.
    Example – RFC195 Service Scopes ● ● In OSGi, services are singletons (sharing state) or bundle specific (ServiceFactory) RFC 195 formalizes service scopes – Singleton and Bundle Scope: As usual – Prototype Scope (new): Create service instances based on a prototype on demand class MyFactory : public PrototypeServiceFactory {…}; context->RegisterService<IMyService>(myFactory); ServiceReference<IMyService> ref = context->GetServiceReference<IMyService>(); ServiceObjects<IMyService> objects = context->GetServiceObjects(ref); IMyService* myService = objects.GetService(); objects.UngetService(myService); Sascha Zelzer 29/10/13
  • 24.
    Example – LDAPFilter DSL Creating LDAP filter strings in Java is error-prone. Filter example: “(&(name=Ben)(!(count=1)))” context.createFilter("(&(name=Ben)(!(count=1))"); LDAPFilter filter( LDAPProp("name") == "Ben" && LDAPProp("count") != 1 ); Sascha Zelzer 29/10/13
  • 25.
    More ● Global library specificGetModuleContext() function for easy context retrieval ● Hooks for framework log messages ● Full static linking support Sascha Zelzer 29/10/13
  • 26.
    Use Cases DS4Cpp ● ● ● A declarativeservices framework in C++ based on CppMicroServices Contributed by Global Vision Systems Introduces similar dependency-injection patterns across their Java and C++ code-base Interest from various technical companies ● Embedded systems ● Avionics and sensoring ● Military sub-contractors working on mission-critical software ● Medical Imaging (e.g. Mint Medical) Sascha Zelzer 29/10/13
  • 27.
    Use Case -MITK ● Injection of an Activator class in all shared libraries ● Conversion of singletons to services ● Increased cohesion by embedding resources ● ● Decreased coupling via interfaces and services Auto-loading of libraries providing service implementations Sascha Zelzer 29/10/13
  • 28.
    Use Case -MITK ● ● ● Whiteboard pattern for interaction event listener Hardware devices (like range cameras and optical tracker) modelled as services File reader writer services with prototype scope Sascha Zelzer 29/10/13
  • 29.
    Native OSGi ● Several C/C++implementations have been created – – CTK Plugin Framework (C++, Qt based) – Apache Celix (C) – Nostrum (C++, POSIX) – SOF (C++, CORBA remoting) – ● CppMicroServices (C++) Poco OSP (commercial) Developers joined forces and created RFP 156 Native OSGi for standardization of a native C/C++ API – RFP 156 will be voted on in November – RFC workis about to be started – CppMicroServices is field-testing a native service-layer API Sascha Zelzer 29/10/13
  • 30.
    Roadmap Release 2.0 ● Service hooks Ecosystem ● ConfigurationAdmin ● Device Access ● Event Admin ● Remote Services Native OSGi ● Specify the Service Layer API ● Work on a native Module Layer Sascha Zelzer 29/10/13
  • 31.
    Summary ● OSGi Lite iswell accepted by C++ developers ● Less complexity due to the missing module layer ● ● ● ● Less flexibility and dynamism C++ OSGi API can be very close to the Java version Used in and interest from various domains API should converge with Native OSGi efforts in the future Sascha Zelzer 29/10/13
  • 32.
    URLs C++ Micro Service ● Homepagehttp://cppmicroservices.org ● GitHub https://github.com/saschazelzer/CppMicroServices ● Blog http://blog.cppmicroservices.org RFP 156 – Native OSGi ● Bug https://www.osgi.org/bugzilla/show_bug.cgi?id=165 ● Document https://github.com/osgi/design/tree/master/rfps Sascha Zelzer 29/10/13
  • 33.