osgi bootcamp - part 2

51
OSGi Bootcamp Day 2 Jan Willem Janssen

Upload: jan-willem-janssen

Post on 23-Feb-2017

132 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: OSGi bootcamp - part 2

OSGi Bootcamp Day 2

Jan Willem Janssen

Page 2: OSGi bootcamp - part 2

Agenda

• OSGi design patterns

• Managing service dependencies

• more convenient options for easily managing service dependencies

• The compendium

• some sample services, sending and receiving events with EventAdmin and using and implementing the Log Service

Page 3: OSGi bootcamp - part 2

Design Patterns for OSGi

• Null-object pattern

• Whiteboard pattern

• Singleton services

• Aspect services

• Adapter services

• Resource adapter services

Page 4: OSGi bootcamp - part 2

Null Object Pattern

An object that implements a certain interface, can be safely invoked and does nothing

http://en.wikipedia.org/wiki/Null_Object_pattern

Page 5: OSGi bootcamp - part 2

Whiteboard Pattern

“don’t call us... we’ll call you”

http://www.osgi.org/wiki/uploads/Links/whiteboard.pdf

Page 6: OSGi bootcamp - part 2

Singleton Services

• Binds logic in a single instance

get()getVersions()get(version)store(Document)

Document Repository

Singleton

Storagerequires

Page 7: OSGi bootcamp - part 2

Singleton Services

manager.add(createComponent() .setInterface(DocumentRepository.class.getName(), null)

.setImplementation(DocumentRepositoryImpl.class)

.add(createServiceDependency()

.setService(Storage.class)));manager.add(createComponent()

.setInterface(Storage.class.getName(), null) .setImplementation(FileBasedStorage.class)

);

Page 8: OSGi bootcamp - part 2

Singleton Services

• What if I don’t want singletons?

• org.osgi.framework.ServiceFactory

• org.osgi.framework.PrototypeServiceFactory

• the consumer of the service is oblivious to this!

Page 9: OSGi bootcamp - part 2

• Transparently inject an interceptor service 

• "in front of" all services matching a filter

Aspect Services

get()getVersions()get(version)store(Document)

Repository CacheAspect

get()getVersions()get(version)store(Document)

Repository

intercepts

Page 10: OSGi bootcamp - part 2

Aspect Services

manager.add(createAspectService(DocumentRepository.class,

null /* filter */, 10 /* ranking */, null /* autoConfig */ ).setImplementation(DocumentRepositoryCache.class));

Page 11: OSGi bootcamp - part 2

Adapter Services

• Start an instance of the adapter service for any

• "adaptee" service matching a filter

getCacheHits()setSize()setTTL()flush()

Repository CacheManageable

Adapter

get()getVersions()get(version)store(Document)

Repository Cache

adapts

Page 12: OSGi bootcamp - part 2

Adapter Services

manager.add(createAdapterService(MyService.class, null),

.setInterface(MyAdapterInterface.class.getName(), null /* filter */),

.setImplementation(AdapterImpl.class)) );

Page 13: OSGi bootcamp - part 2

Resource Adapters

• Start an instance of a Resource Driven Service for all resources matching a filter

• resources: any valid URL

play()pause()stop()

Audio TrackResourceAdapter

MP3Fileadapts

Page 14: OSGi bootcamp - part 2

Resource Adapters

manager.add(createResourceAdapterService(

"(path=*.mp3)" /* filter */, false /* propagate */, null /* callbackInstance */, “changed" /* callbackMethod */) .setInterface(AudioTrack.class, null) .setImplementation(MP3AudioTrack.class)));

Page 15: OSGi bootcamp - part 2

Dependency Management

• Components need other services before:

• they can publish their own service

• they can do their work

• Complex dependency graphs

• hard to manage by hand

• lots of boilerplate code

Page 16: OSGi bootcamp - part 2

Dependency Management

Bundle

Component StorageService

LogService

En5tyStore

Page 17: OSGi bootcamp - part 2

Dependency Libraries

• Blueprint Services

• spring inspired

• XML

• Declarative Services

• OSGi standard

• annotation/XML based

Page 18: OSGi bootcamp - part 2

Dependency Libraries

• iPOJO

• similar to DS

• extends OSGi service lifecycle

• Dependency Manager

• annotation/API-based

• runtime control

Page 19: OSGi bootcamp - part 2

Dependency Manager

• API based dependency management

• optional and required dependencies

• supports extensible types of dependencies:

• service dependency

• configuration dependency

• change dependencies dynamically at runtime

Page 20: OSGi bootcamp - part 2

Dependency Manager

• Extend DependencyActivatorBase, override init() and destroy()

• Talk to the DependencyManager to:

• create a new service object and:

• set any service interface and properties;

• set the implementation class;

• add any service or configuration dependencies and:

• make it required or optional

• refer to a specific service or configuration

Page 21: OSGi bootcamp - part 2

public class SampleComparator implements Comparator { private volatile LogService m_log; public int compare(Object o1, Object o2) { return o1.equals(o2) ? 0 : -1; }

void start() { m_log.log(LogService.LOG_INFO, "Hello there!"); }}

Dependency Manager - Example

Page 22: OSGi bootcamp - part 2

public class Activator extends DependencyActivatorBase { public void init(BundleContext context, DependencyManager dm) { dm.add( createComponent() .setInterface(Comparator.class.getName(), null) .setImplementation(SampleComparator.class) .add(createServiceDependency() .setService(LogService.class) .setRequired(false))); }}

Dependency Manager - Example

Page 23: OSGi bootcamp - part 2

@Componentpublic class SampleComparator implements Comparator { @ServiceDependency private volatile LogService m_log; public int compare(Object o1, Object o2) { return o1.equals(o2) ? 0 : -1; }

@Start void start() { m_log.log(LogService.LOG_INFO, "Hello there!"); }}

Dependency Manager - Example

Page 24: OSGi bootcamp - part 2

• Add the DM annotation processor to bnd:-plugin: \ ${ext.repositories.-plugin},\ org.apache.felix.dm.annotation.plugin.bnd.AnnotationPlugin;\ path:=${plugin-dir}/org.apache.felix.dependencymanager.annotation.jar

Dependency Manager - Example

Page 25: OSGi bootcamp - part 2

Dependency Manager

• Create one or more components: manager.add(createComponent() ...

• Use POJOs to implement services: .setImplementation(MyPOJO.class)

• Optionally define the service interfaces: .setInterface(MySvc.class.getName, props)

• Add dependencies

Page 26: OSGi bootcamp - part 2

Service Dependencies• Are defined using the DependencyManager:

.add(createServiceDependency() ...

• Can be optional or required: .setRequired(boolean)

• Track a specific service: .setService(LogService.class, “(name=mine)”)

• Can be injected into an instance: .setAutoConfig(true) // this is the default

• Can trigger callbacks on the instance: .setCallbacks(“addService”, “removeService”) // NOTE: callbacks can define any of the following parameters: (ServiceReference reference, Object service)

Page 27: OSGi bootcamp - part 2

Dependency Life Cyclestart

Installed

start

Resolved

Ac/veUninstalled

end

install

stop

uninstall Ac/ve

Wai/ng6for6required

Monitoring6op/onal

ac/vatedeac/vate

Page 28: OSGi bootcamp - part 2

Dependency Activation

• If the reference to the implementation is a class, instantiate it, otherwise directly use the reference

• Invoke the init() method on the instance

• Inject all required and optional dependencies, using NullObjects where appropriate, and any BundleContext or ServiceRegistration

• Invoke the start() method on the instance

Page 29: OSGi bootcamp - part 2

OSGi compendium

Log

HTTP

Device Access

Configuration Admin

Preferences

Metatype

Wire AdminUser Admin

IO Connector

Initial Provisioning

UPnP™ Device

Declarative Services

Event Admin Service Tracker

XML Parser

Position

Measurement and State

Execution Environment Spec

Remote Services

Deployment Admin

Blueprint Container

Page 30: OSGi bootcamp - part 2

Log ServiceThe Log Service Interface Log Service Specification Version 1.3

6-698 OSGi Service Platform Release 4

Figure 101.1 Log Service Class Diagram org.osgi.service.log package

101.2 The Log Service Interface

The LogService interface allows bundle developers to log messages that can

be distributed to other bundles, which in turn can forward the logged

entries to a file system, remote system, or some other destination.

The LogService interface allows the bundle developer to:

• Specify a message and/or exception to be logged.

• Supply a log level representing the severity of the message being logged.

This should be one of the levels defined in the LogService interface but it

may be any integer that is interpreted in a user-defined way.

• Specify the Service associated with the log requests.

By obtaining a LogService object from the Framework service registry, a

bundle can start logging messages to the LogService object by calling one of

the LogService methods. A Log Service object can log any message, but it is

primarily intended for reporting events and error conditions.

The LogService interface defines these methods for logging messages:

• log( int, Str ing) – This method logs a simple message at a given log level.

• log( int, Str ing , Throwable) – This method logs a message with an

exception at a given log level.

• log(Serv iceReference, int , St r ing) – This method logs a message asso-

ciated with a specific service.

• log(Serv iceReference, int , St r ing , Throwable) – This method logs a

message with an exception associated with a specific service.

While it is possible for a bundle to call one of the log methods without pro-

viding a ServiceReference object, it is recommended that the caller supply

the ServiceReference argument whenever appropriate, because it provides

important context information to the operator in the event of problems.

<<interface>>LogService

<<interface>>LogReaderService

<<interface>>LogEntry

<<interface>>LogListener

a Log Reader Service impl.

LogEntry impl

a Log user bundle

a Log Serviceimpl

a Log reader user

Log a message

Store a message in the log for retrieval

message log

send new log entry

retrieve log

1 1

1

0..n (impl dependent maximum)

1

0..n

LogEntry has references toServiceReference,Throwable and Bundle

or registerlistener

Bundle usingLog Service

Bundle usingLog ReaderService

Log implementation bundle

Page 31: OSGi bootcamp - part 2

Log Service

• an update of this spec is coming!

• tries to solve many of the problems:

• static logger

• dynamic reconfiguration per logger

• align API with SLF4J

Page 32: OSGi bootcamp - part 2

Event Admin

• Publish subscribe

• Asynchronous and synchronous

• Hierarchical topics

• Decouple event creation and handling

Page 33: OSGi bootcamp - part 2

Event Admin

Bundle

Component,invoking,a,service

Bundle

Componentproviding,a,service

method,call

MyService

Bundle

EventAdmin-implementa0on

Bundle

Component-listening-for-

events

EventAdminBundle

Component-publishing-an-

event(a)synch-event

EventHandler

Page 34: OSGi bootcamp - part 2

Listen to Events

• Create an EventHandler that listens to all events

• Launch it in a framework that has an Event Admin implementation running

Page 35: OSGi bootcamp - part 2

Event Admin - Exampleclass MySubscriber extends DependencyActivatorBase implements EventHandler { static final String[] topics ={ "com/acme/*", "org/osgi/service/log/LogEntry/*" }; public void init(BundleContext context, DependencyManager dm) { Dictionary dict = new Hashtable(); dict.put(EventConstants.EVENT_TOPIC, topics); dict.put(EventConstants.EVENT_FILTER, "(bundle.symbolicName=com.acme.*)"); dm.add(createComponent() .setInterface(EventHandler.class.getName(), dict) .setImplementation(SampleComparator.class); } @Override public void handleEvent(Event event) { //... }}

Page 36: OSGi bootcamp - part 2

Sending events

• Add a service dependency to EventAdmin

• Use either sendEvent() or postEvent() to send events

Page 37: OSGi bootcamp - part 2

Event Admin - Example

public class EventPublishingService { private volatile EventAdmin m_eventAdmin; private volatile LogService m_log;

public void someLogic() { if (m_eventAdmin != null) { Dictionary properties = new Hashtable(); properties.put("timestamp", new Date()); m_eventAdmin.postEvent( new Event("com/acme/timer", properties)); } else { m_log.log(LogService.LOG_INFO, "unable to send event: no event admin!"); } }}

Page 38: OSGi bootcamp - part 2

Configuration Admin

• contains externally configurable settings for a service;

• service is identified by its PID (persistent ID)

• allows management systems to configure all settings;

• settings can be created even before the actual bundle is installed.

Bundle

Component

ManagedServiceservice.pid6=6nl.luminis.store

Page 39: OSGi bootcamp - part 2

Configuration Admin

• Used for:

• dynamically configuring singleton services (ManagedService)

• creating new services based on configuration (ManagedServiceFactory)

Page 40: OSGi bootcamp - part 2

Configuration Admin

port=8080protocol=RESTpublic=true

PID=connector

style=winxpcolorset=silver

PID=gui

Configura?onAdmin

getConfigura?on()listConfigura?ons()

Configura?on

getProper?es()update()delete()

manageEconfigura?ons no?fiesEofEchanges

ManagedService

updated()

ServicePID=connector

Configura?onEManager

Page 41: OSGi bootcamp - part 2

Configuration Dependenciespublic class MyConfiguredService implements ManagedService { private volatile String m_name;

@Override public void updated(Properties props) throws ConfigurationException { // check given properties if (props == null) { m_name = "<default>"; } else { // update local settings Object v = props.get("name"); if (v instanceof String) { m_name = (String) v; } else { throw new ConfigurationException("name", "must be a string!"); } } } // …}

Page 42: OSGi bootcamp - part 2

Configuration Dependencies

• Configuration updates are optional, but what about required configurations?

• DependencyManager can help:

• define a configuration dependency

• our component is started only when the configuration becomes available

• updated(props) is invoked before other life cycle methods of DM

Page 43: OSGi bootcamp - part 2

Configuration Dependencies

// Define in the init() of your activator:manager.add(createService() .setImplementation(MyConfiguredService.class) .add(createConfigurationDependency()

.setPid("my.service.pid")));

Page 44: OSGi bootcamp - part 2

HTTP service

• provides Servlet API

• whiteboard style registration of:

• listeners

• filters

• servlets

Page 45: OSGi bootcamp - part 2

HTTP service Example

public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setStatus(HttpServletResponse.SC_OK); resp.getWriter().print("Hello World"); resp.flushBuffer(); }}

Page 46: OSGi bootcamp - part 2

HTTP serviceExample

// Define in the init() of your activator:Properties props = new Properties();props.put("osgi.http.whiteboard.servlet.pattern", "/hello");

manager.add(createService() .setInterface(Servlet.class.getName(), props) .setImplementation(MyServlet.class));

Page 47: OSGi bootcamp - part 2

OSGi tooling

• The popularity of frameworks depend on their ease of use

• OSGi development lacked in this area for long

Page 48: OSGi bootcamp - part 2

OSGi tooling

• Enter Bndtools:

• actively developed plugin for Eclipse

• makes it really easy to develop for/with OSGi:

• automatic rebuilding of bundles

• hot-deployment of bundles

• very good support for semantic versioning

Page 49: OSGi bootcamp - part 2

OSGi tooling

• demo

Page 50: OSGi bootcamp - part 2

Books

• Building Modular Cloud Apps with OSGi

• Paul Bakker & Bert Ertman

• Java Application Architecture Modularity Patterns with Examples using OSGi

• Kirk Knoernschild

Page 51: OSGi bootcamp - part 2

Links

• https://github.com/jawi/osgi-tutorial contains the demo project as shown during the demo

• http://bndtools.org/ the home of the Bndtools plugin for Eclipse

• http://bnd.bndtools.org/ contains lots of information about the nitty-gritty details of Bnd

• http://luminis.eu my current employer