Second part of the tutorial on OSGi for people working on the INAETICS project. Explains how dependency management works in OSGi, OSGi design patterns and several of the OSGi compendium services.
Given on Saxion (Enschede) on October 16th, 2015.
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
4. 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
8. 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!
9. • Transparently inject an interceptor service
• "in front of" all services matching a filter
Aspect Services
get()
getVersions()
get(version)
store(Document)
Repository Cache
Aspect
get()
getVersions()
get(version)
store(Document)
Repository
intercepts
11. Adapter Services
• Start an instance of the adapter service for any
• "adaptee" service matching a filter
getCacheHits()
setSize()
setTTL()
flush()
Repository Cache
Manageable
Adapter
get()
getVersions()
get(version)
store(Document)
Repository Cache
adapts
13. Resource Adapters
• Start an instance of a Resource Driven Service for all
resources matching a filter
• resources: any valid URL
play()
pause()
stop()
Audio Track
Resource
Adapter
MP3
File
adapts
15. 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
18. Dependency Libraries
• iPOJO
• similar to DS
• extends OSGi service lifecycle
• Dependency Manager
• annotation/API-based
• runtime control
19. Dependency Manager
• API based dependency management
• optional and required dependencies
• supports extensible types of dependencies:
• service dependency
• configuration dependency
• change dependencies dynamically at runtime
20. 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
21. 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
22. 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
23. @Component
public 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
24. • 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
25. 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
26. 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)
28. 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
29. 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
30. Log Service
The Log Service Interface Log Service Specification Version 1.3
Figure 101.1 Log Service Class Diagram org.osgi.service.log package
<<interface>>
LogService
<<interface>>
LogReader
Service
<<interface>>
LogEntry
<<interface>>
LogListener
a Log Reader
Service impl.
LogEntry impl
a Log user bundle
a Log Service
impl
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 to
ServiceReference,
Throwable and Bundle
or register
listener
Bundle using
Log Service
Bundle using
Log Reader
Service
Log implementation bundle
31. 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
32. Event Admin
• Publish subscribe
• Asynchronous and synchronous
• Hierarchical topics
• Decouple event creation and handling
34. Listen to Events
• Create an EventHandler that listens to all events
• Launch it in a framework that has an Event Admin
implementation running
35. Event Admin - Example
class 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) {
//...
}
}
36. Sending events
• Add a service dependency to EventAdmin
• Use either sendEvent() or postEvent() to send
events
37. 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!");
}
}
}
38. 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
ManagedService
service.pid6=6nl.luminis.store
39. Configuration Admin
• Used for:
• dynamically configuring singleton services
(ManagedService)
• creating new services based on configuration
(ManagedServiceFactory)
41. Configuration Dependencies
public 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!");
}
}
}
// …
}
42. 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
43. Configuration Dependencies
// Define in the init() of your activator:
manager.add(createService()
.setImplementation(MyConfiguredService.class)
.add(createConfigurationDependency()
.setPid("my.service.pid"))
);
44. HTTP service
• provides Servlet API
• whiteboard style registration of:
• listeners
• filters
• servlets
45. 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();
}
}
46. HTTP service
Example
// 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)
);
47. OSGi tooling
• The popularity of frameworks depend on their ease of
use
• OSGi development lacked in this area for long
48. 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
50. Books
• Building Modular Cloud Apps with OSGi
• Paul Bakker & Bert Ertman
• Java Application Architecture
Modularity Patterns with Examples using OSGi
• Kirk Knoernschild
51. 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