OSGi Tutorial

Preview:

DESCRIPTION

OSGi Tutorial. Matthias lübken, akquinet www.akuinet.de & Peter Kriens, aQute www.aQute.biz. Content. I– Setting up Eclipse and the OSGi Platform II – OSGi Background III– OSGi Technology IV– OSGi Concepts V – Hello world VI - Launching a Framework - PowerPoint PPT Presentation

Citation preview

OSGi Tutorial

Matthias lübken, akquinet

www.akuinet.de

&

Peter Kriens, aQute

www.aQute.biz

Content

I – Setting up Eclipse and the OSGi PlatformII – OSGi BackgroundIII – OSGi TechnologyIV – OSGi ConceptsV – Hello worldVI - Launching a FrameworkVII - Component Interaction and CollaborationIIX – Service ComponentsIX – Using the HTTP ServiceX – Making a PortalXI – Creating a content providerXII – Final

Section I – Setting up Eclipse and the OSGi

Platform

Setup: Your Infrastructure

Create a new workspaceImport all the projects and make a copyFind where your Eclipse installation residesCopy the bnd.jar file to the eclipse/dropins directoryRestart EclipseSelect your new workspace

Your Workspace

Verify bnd is installed

Section II - OSGi Background

What is the OSGi Service Platform?

A Java framework for developing (remotely) deployed service applications, that require:

Reliability

Large scale distribution

Wide range of devices

CollaborativeCreated through a collaboration of industry leaders

IBM, Ericsson, Nokia, Sony, Telcordia, Samsung, ProSyst, Gatespace, BenQ, Nortel, Oracle, Sybase, Espial, and many more

Spec 4.+ publicly available at www.osgi.org …Cool!

Why the OSGi Service Platform?

What problems does the OSGi Service Platform address?

Modularity!

The limited (binary) software portability problem

The complexity of building heterogeneous software systems

Supporting the myriad of configuration, variations, and customizations required by today’s devices

Managing the software on the device

Problems: Limited Binary Software Portability

Lack of portability causes

Market friction: No large market of reusable components and applications

Reduced qualityUnnecessary constraints on hardware and software architectures

CPUs differ widely in cost and performance

Linux is nice, but it is sub-optimal for smaller devicesBenefits of the OSGi Platform

Applications run unmodified on different hardware and software architectures due to a formal specification of all relevant aspects

The OSGi Specifications gives you choice!

Problems: Complexity of Software

PR

OD

UC

TIV

ITY

COMPLEXITY AND SIZE

ASSEMBLY

STRUCTURED PROGRAMMING

SERVICE ORIENTED PROGRAMMING

OBJECT ORIENTED PROGRAMMING

Problems: Limits of Object Oriented Technology

Objects are great, but oh, the tangled webs we weaves …Coupling severely limits reusability

Using a generic object, can drag in a large number of other objects

Creates overly large systems after a certain complexity is reachedFlexibility must be built in by the programmer

Plug-in architecturesComponent architectures like OSGi minimize the coupling that is created by OO

Software complexity

Section III - OSGi Technology

Architecture

Applications / modules share a single Java VMBetter class loading e.g. versioningIsolation/security between applicationsCommunication & collaboration between applicationsLife cycle management

install, start, stop, update, etc.

Layering

Defined in a number of layers

OS + Hardware

Java Execution Env

Module

Life Cycle

Service

SECURITY

Applications (bundles)

Layers: Execution Environment

Provides a defined context for applicationsDefines the available class library Not bound to a concrete JREOSGi Minimum EE

Matches most Java profilesFramework need OSGi MinimumImplementations can use more

CLDC/MIDP

J2SE

CDC/FP

OSGIMIN.

Layers: Module Layer

Specifies class loading and packaging Modularization with classloadersProtectionVersioning

BUNDLE

BUNDLEBUNDLE

BUNDLE

BUNDLE

BUNDLE

BUNDLE

Layers: Life Cycle Layer 1

System Bundle represents the FrameworkProvides an API for managing bundles

Install

Resolve

Start

Stop

Refresh

Update

Uninstall

BUNDLE

XBUNDLE

X-V2

BUNDLEB

BUNDLEM

BUNDLEA

SYSTEMBUNDLE

STATE (ACTIVE OR NOT)

MANAGES

Layers: Life Cycle Layer 2

Bundle Activator is called at startupImplements two methods:

start(): Initialize and return quickly

stop(): CleanupBundle Context to access framework Start Level service to control the start/stop of groups of applications

INSTALLED

RESOLVED

UNINSTALLED

ACTIVE

STOPPING

STARTING

Layers: Service Layer

Inside-VM service modelDiscover

based on interface or propertiesBind

to one or more services by

program control,

default rules, or

deployment configurationService Oriented Architectures (SOA) confusion

Web services bind and discover over the net

OSGi binds and discovers inside a Java VM

Why services?

Collaboration modelSeparate contract from implementationDynamically discover and bind available implementations Components are reusableAllows alternate implementations

SERVICE CONTRACT

COMPONENTPROVIDES

USES

1188

UPNPINITIAL PROVISIONING

NAME SPACEJINI

START LEVELIO CONNECTOR

WIRE ADMINXML PARSER

MEASUREMENT & STATEPOSITION

EXECUTION ENV.

APPLICATION MANAGERFOREIGN APP. ACCESS

SIGNED BUNDLESDECLARATIVE SERVICESDEVICE MANAGEMENT

SECURITY POLICIESFRAMEWORK LAYERINGINITIAL PROVISIONING

UPNPCONDITIONAL PERMISSIONS

2000 2001 2003 2006

R1

R2

R3

R4H

OM

E A

UTO

MA

TIO

N

VEH

ICLE

MO

BIL

E

FRAMEWORKHTTPLOG

DEVICE ACCESS

PACKAGE ADMINCONFIGURATION ADMIN

PERMISSION ADMINUSER ADMIN

PREFERENCESMETATYPE

SERVICE TRACKER

STANDARD SERVICES EVOLUTION

Layers: The Security Layer

Based on Java 2 security

Permissions

Bundle signing

And a number of extra rulesDynamicFully under control of the operator

Fully controlled systems

Fully open systems

The OSGi Implementations

Major Framework vendors are

ProSyst

Gatespace Telematics

IBM

Siemens

EspialOpen source implementations

Apache Felix

Eclipse Equinox

Gatespace KnopflerfishSee http://www.aqute.biz/osgi for an overview

Benefits

Components are small

Easier to make, maintain and understandComponents are minimally coupled to other components

Gives reusabilityCollaborative model

Allows reuseWide Adoption

Bigger market, more components availableExcellent model for customizations and variations

What Did We Learn

The OSGi Service Platform is kind of a Java Operating System

Execution Environment

Module layer

Service Layer

SecurityIt simplifies:

Deployment problems

Software composition

Software managementImplemented by many vendors and open source groups

Section IV - OSGi concepts

Framework Entities

OSGI FRAMEWORK

BUNDLE A{…} = SERVICE, DEFINED BY

JAVA INTERFACEBUNDLE B

{…}

BUNDLE C{…}

= BUNDLE

Bundles & Services

A bundle is the deliverable application

Like a Windows EXE file

Content is a JAR fileA bundle registers 0..n servicesA service ...

is specified by an interface

may be implemented by multiple bundles

is bound to the bundle life-cycle

BUNDLE A{…}

BUNDLE B{…}

What is in a Bundle?

A bundle contains (normally in a JAR file):

Manifest (bundle meta data)

Code (classes in packages)

Resources (other files in the JAR file)

What Happens With a Bundle?

The framework:

Reads the manifest

Installs code and resources

Resolves dependencies

Controls life cycle

During runtime the framework:

Calls the Bundle Activator start() & stop()

Manages the class path

Handles the service dependencies

BUNDLE A{…}

SECTION V - HELLO WORLD

First Project:Create

Create a new Java Project

Name, up to you

(examples use my.project)

Defaults are OKNext

First Project: Classpath

Source: ok

First Project: Classpath

Projects: nothingLibraries, we need to addthe osgi.jar. This can be found in the aQute.tutorial.runtimeproject, in the repo directoryAdd JARs -> selectChoose the repo directory

Create a Hello (and Goodbye) World Bundle

Create a Hello (and Goodbye) World Bundle

Create a Java source called World.java

Select src folder * > New > Class

Create a Hello (and Goodbye) World Bundle

Set package name: my.projectSet Class Name: WorldAdd Interfaces: Add …

BundleActivatorFinish

Source code for Hello/Goodbye World

The source should look similar to ... fill in the // TODO blocksstart – Called when the bundle is startedstop – When the bundle is stopped Some tips

F3 > Will jump to the selected type (click BundleActivator, and then F3)

Control-Shift-T > Will show a source of a type (class)

Control-Shift-R > Will show a source of a resource

package my.project;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class World implements BundleActivator {

public void start(BundleContext context) throws Exception {System.out.println(“Hello World”); }

public void stop(BundleContext context) throws Exception { System.out.println(“Goodbye World”); }}

Manifest code for Hello/Goodbye World

Each JAR file has a manifest

http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.htmlA manifest is a text file that provides meta information about the JAR file.

Used for versioning and JAR file signing.A manifest consists of a set of headers and values.

For example, Manifest-Version: 1Unrecognized headers are ignored by the Java VM, this makes it possible to extend the manifestThe OSGi specifications have declared manydifferent headers

Vendor information

Imported and Exported packages

Native code

Hello World (and Goodbye)

A bundle needs a manifest. The bnd plugin can create this for you (and verify its headers for validity!)You have to create a bnd file in the project directory. * > New > File

bnd.bndLikely opens a separate applications

Open with Properties Editor

You can make this an association for *.bnd files (see Eclipse Preferences)

Real code! Hello World (and Goodbye)

Add:

Private-Package. Defines the packages that should be included in your bundle You can use wildcards

my.project.*

Bundle-Activator, my.project.World

Create the bundle by selecting the bnd file, then * > Make BundleThis creates a JAR file, which is your first bundle!

Private-Package: my.project.*Bundle-Activator: \ my.project.World

Bnd Translation

The bnd plugin translates the bnd.bnd file to the manifest, and embeds in the JAR fileuppercase HEADERS ARE copied to the manifest

Private-Package: my.projectBundle-Activator: \ my.project.World

Manifest-Version 1.0 Bnd-LastModified 1220347055030 Bundle-Activator my.project.World Bundle-ManifestVersion 2 Bundle-Name my.project Bundle-SymbolicName my.project Bundle-Version 0 Created-By 1.5.0_13 (Apple Inc.) Import-Package org.osgi.framework;version="1.3" Private-Package my.project Tool Bnd-0.0.265

BND

BND

Import-Package is calculated from the referred MATCHED classes:

* (all) is default, !com.acme.* means do not import VERY GOOD DEFAULTS!

VERY LITTLE HEADERS NEED SPECIFYINGExport package expressions are matched against all packages on the class pathSIMPLIFIED SYNTAX FOR DECLARATIVE SERVICESUSEFUL IN:

ANT, ECLIPSE, COMMAND LINE, MAVENFull manual:

http://www.aqute.biz/Code/Bnd

See What We Created

Double click on the my.project.jar shows contexts of Manifest.MF.

Section VI - Launch a Framework

Launch a Framework

Debug -> Open Debug Dialog …Select EquinoxFw (in Java Applications)

This launch file is provided by the aQute.tutorial.runtime project.

This starts an Equinox Framework with the Apache Felix fileinstall.jar bundle as only bundle.The fileinstall.jar bundle watches the work directory for bundles

Any bundle in this directory will be installed and started

Removed bundles will be uninstalled

This is not an OSGi “standard”, it is just a Felix bundleInstalling and uninstalling is therefore simply managing the aQute.tutorial.runtime/work directory

Copy & Paste a file: gets installed

Delete a file: gets uninstalled

Launch a Framework

Debug -> Debug Dialog …-> Debug

Run the Hello World bundle

The launch runs a Framework consoleJust copy (Copy and Paste) the my.project.jar to the work directory

See “Hello World” in the console

Type “ss” (show status)

Look at the active bundles

the number for the my.project bundle. This is the bundle-id.

Run the Hello World bundle

Type “stop <bundle-id>”

See the “Goodbye world”

The “Hello World” appears again because the fileinstall.jar bundle starts the bundle again

Eclipse Self Hosted Target Environment

Eclipse also provides the Plugin Development Environment (PDE) besides the Java Development Environment (JDE) that we used so far.Plugins are bundles and the PDE is therefore usable to make bundles

Handles dependencies

Generates JARs

Launches an Equinox Framework from a Target definition

What Did We Learn

The unit of deployment of an OSGi Service Platform is a bundleHow to create a bundle with the bnd pluginHow to launch an Equinox environment with a defined set of bundles, and manage it with the fileinstall.jar bundleHow to start/stop bundlesHow the Equinox console worksWhy the Eclipse Self Hosting is not used

Section VII – Component collaboration

Collaborative model

OSGi is more than an Applet, MIDlet, Xlet runnerBundles can collaborate through:

service objects

package sharingFind and track service objects dynamically Framework fully manages this collaboration

Dependencies, security

Collaborative model

BUNDLEBUNDLE

JAVA

OPERATING SYSTEM

HARDWARE

OSGI FRAMEWORK

SERVICEREGISTRY

PACKAGESPACKAGES

Collaborative model

JAVA

OPERATING SYSTEM

HARDWARE

JAVA APPLICATION MANAGER

SERVICEREGISTRY

PACKAGESPACKAGES

MIDLET,XLET,

ORAPPLET

MIDLET,XLET,

ORAPPLET

NO NATIVE CODE

NO PACKAGE MANAGEMENT(VERSIONS!)

NO COLLABORATION

NO MANAGEMENT BUNDLES

Class Path Issues

Standard Java:

Linear search in jars and directories

OSGi:

Network of class loaders

controlled by manifest headers

Q

P

R

P

Q-1.0

Q

Q-2.0

EXPORTED PACKAGE

IMPORTED PACKAGE WIRE

CONSTRAINT

Package Resolution example

Bundle AExport org.osgi.service.log com.ibm.service.log com.ibm.j9Import javax.management javax.servlet.http

Framework org.osgi.framework javax.management

Bundle BExport ericsson.osgi javax.servlet javax.servlet.httpImport org.osgi.service.log javax.management

B RESOLVED

A RESOLVED

Service Specifics 1

A service

a POJO

registered by a bundle

used by other bundles

specified by a Java interface

SERVICE

BIND REGISTER

LISTEN

Service Specifics 2

Different cardinalities

1..1, 0..1, 0..nCan be discovered dynamically

Active search with query filter

Listener interfaceDynamic! Services can go away at any time!

package org.osgi.service.log;import org.osgi.framework.ServiceReference;public interface LogService { static final int LOG_ERROR= 1; static final int LOG_WARNING= 2; static final int LOG_INFO= 3; static final int LOG_DEBUG= 4; void log(int level, String message); void log(int level, String message, Throwable exception); void log(ServiceReference sr,int level, String message); void log(ServiceReference sr, int level, String message, Throwable exception);}

Service Specifics 3

Extensive notifications for life cyclesUnique idService Permission if security is enabledProperties

Powerful query language

Manipulating Services

Access service registry with the BundleContext class ServiceRegistration represents the registration of this service

for private use of the implementer

to unregister or modify properties

ServiceReference to access the service and properties

for anyone who is interessted

ServiceRegistration registerService( String clss, Object srvc, Dictionary prprts)ServiceReference[] getServiceReferences( String clss, String fltr)Object getService( ServiceReference reference)boolean ungetService( ServiceReference rfrnc);

Services and Best Practice

Subsystem binding, like a Log Service for example

Put business logic in POJOs that are not coupled to OSGi

use Bundle Activator to bind the POJOs

use declarative services to handle the binding (discussed later)

Domain objects, like a Bluetooth service that is registered when a Bluetooth device comes into range

Use the Service Tracker class for these situationsHandle the dynamics, dynamic things will happen

Start Level service is not a way to handle dynamics

You can not control the initialization order

What Did We Learn

OSGi provides a collaboration model that is based on

Services

Package sharingSharing is complicated, but the well defined specifications make it quite painless for bundle developersServices provide a very powerful dynamic programming modelSOA, without the communication overhead!

Section IIX – Service Components

Service Components

The dynamic nature makes it complicatedThe declarative service model simplifies the handling

Dependencies are defined in an XML file

Use bnd to get simpler definition Declarative Services:

Optionally depend on one or more services

Optionally provide a service

Optionally lazy initialized

ConfigurableHands-On: Refactor Helloworld bundle to use Log Service

Service Components

Modify your project to

Change start() to activate()

And stop() to deactivate()

Note the Component Context

use the Log Service instead of System.out

Create a setlog method so DS can give us a log ServiceNext, we need to adapt our bnd.bnd file to create a component instead of an activator

package my.project;import org.osgi.service.component.*;import org.osgi.service.log.*;public class World {

LogService log; protected void activate(ComponentContext context) throws Exception {log.log(LogService.LOG_INFO, "Hello World");

} protected void deactivate(ComponentContext context) throws Exception {log.log(LogService.LOG_INFO, "Goodbye World");

} public void setLog(LogService log) {this.log = log; }}

bnd Component Header

(bnd only)Service-Component ::= clause ( ‘,’ clause ) *clause ::= definition | <resource path>definition ::= <class-name> type ? ( ‘;’ ‘dynamic:=‘ list ) ? ( ‘;’ ‘optional:=‘ list ) ? ( ‘;’ ‘multiple:=‘ list ) ? ( ‘;’ name ‘=‘ <interface-name> ) *type ::= ‘?’ /* optional dynamic */ | ‘*’ /* optional dynamic multiple */ | ‘+’ /* dynamic multiple */ | ‘~’ /* optional */

Bnd generates XML

Service-Component: \ ${p}.World; \ log=org.osgi.service.log.LogServicePrivate-Package: ${p}

<?xml version="1.0" encoding="utf-8" ?> <component name="my.project.World"> <implementation class="my.project.World"/> <reference name="log" interface="org.osgi.service.log.LogService" bind="setLog" /> </component>

OSGI-INF/my.project.component.World.xml

bnd.bnd change to :

Declarative Services

A component can be any class. No specific interface required.The activate() and deactivate() protected methods are calledDependencies must be resolvedReferences can be bound by the setXXX method

Example: At any moment in between activate() and deactivate() there is a valid Log Service because we use the default static policy

RElation DS-XML & Code

<?xml version="1.0" encoding="utf-8" ?> <component name="my.project.World"> <implementation class="my.project.World"/> <reference name="log" interface="org.osgi.service.log.LogService" bind="setLog" /> </component>

package my.project;import org.osgi.service.component.*;import org.osgi.service.log.*;public class World {LogService log; protected void activate(ComponentContext context) { log.log(LogService.LOG_INFO, "Hello World");

} protected void deactivate(ComponentContext context) { log.log(LogService.LOG_INFO, "Goodbye World");

} public void setLog(LogService log) {this.log = log;}

}

OSGI-INF/MY.PROJECT.COMPONENT.WORLD.XML

Run the Hello World Component

Create a new JAR with bndJust copy the my.project.jar to the work directory, gets installed

Nothing happensType “ss” (show status)

Type log, …, no good

Copy from repo to work the org.osgi.impl.service.log bundle.

Type now log in console

Notice that the Hello world message appears after the log service is started

What Did We Learn

Programming with services can be complicatedThe Declarative Services model makes service programming simplerHow the component XML is constructedHow bnd provides a simplified syntaxHow to use the Log Service

Section IX – Using the Http Service

Using The Http Service

1 LISTEN FOR HTTP SERVICE

2 REGISTER AN HTTP SERVICE

3 REGISTER AN HTTP-SERVLET WITH HTTP SERVICE

4 CALL BACK WITH REQUESTS

1

23

4

Using the Http Service: a Servlet

Create a servletA Servlet must implement a doGet methodJust say “Hello World”You should add ./repo/servlet.jar from the aQute.runtime project to your classpath

package my.project;import java.io.*;import javax.servlet.http.*;class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest rq,

HttpServletResponse rsp)throws IOException {

PrintWriter pw = rsp.getWriter();pw.println("Hello World");

rsp.setContentType("text/plain"); }}

Using the Http Service: The Component

We have a static dependency on the Http Service

When it is registered, we add our servlet

We log any errors, but we assume the log can be absent, so it will be optional

package my.project;import org.osgi.service.http.*;import org.osgi.service.log.*;public class World {

volatile LogService log; HttpService http; public void setHttp(HttpService http) {

this.http = http; try {http.registerServlet("/web", new

HelloServlet(), null, null); } catch (Exception e) {

LogService log = this.log;if (log != null) {

log.log( LogService.LOG_ERROR, "Registering /web", e);} } }…

Using the Http Service: The Component

We need the unsetters and ungetters.The unsetHttp is not strictly needed because we will have a static depenencyNotice that the log is volatile because we can change it dynamically

… public void unsetHttp(HttpService http) {http.unregister("/web"); }

public void setLog(LogService log) {this.log = log; } public void

unsetLog(LogService log) {this.log = null; }}

Using the Http Service: The bnd.bnd file

We use ${p}, bnd sets this to the bundle symbolic name/project name.The reference to the Http Service is mandatoryThe reference to the Log Service is optional, note the ‘?’ at the end of the service nameCopy the jar to the work dirTry the web at

http://localhost:8081/web

Private-Package: ${p}Service-Component: \${p}.World; \ http= org.osgi.service.http.HttpService; \ log = org.osgi.service.log.LogService?

Web Component

Ah! There is no Http Service available!

Web Component

Install a web server from the repo directory (in aQute.runtime): (osgi Http jar)

This will register an Http Service at port 8081

Try to reload the pageWorks!

Section X – Making a Portal

White Board Pattern

Htpp Service is wrongly designed:

Get Http Service

Register Servlet

Track that Http Service goes away

And, Http Service must track bundle to go awayWhite Board pattern reverses this model

Register a content provider

Http Service tracks all content providers

Content provider has nothing to do except register

White Board Pattern

Based on Inversion of Control (IoC) pattern:

Don’t call us, we will call you

It is very effective because it reduces the number of couplings between bundles

Pattern:

Register a service

Let any interested bundle use itThe Whiteboard approach was discovered during finishing of R1. We were not brave enough to scrap, that is why the Log Service and Http Service are not white boardThere is a white-paper comparing a whiteboard approach with a non whiteboard approach.

http://www.osgi.org/documents/osgi_technology/whiteboard.pdf

WhiteBoard Pattern for our Portal

Portal

Designing our HtmlFragment serviceWe can use properties to provide a name and title for the HtmlFragment, so we can list themCommon practice is to define these on the service interfaceClients must register a service with this interface + the title and name property

package my.service;import java.io.*;import javax.servlet.http.*;public interface HtmlFragment { String NAME = "aQute.fragment.name"; String TITLE = "aQute.fragment.title"; void write(

HttpServletRequest request,PrintWriter pw) throws Exception;}

Portal

We create the servlet as inner class so that it can refer to the Bundle Context we get in the component classNotice that log is volatile because we will make it optional in the bnd.bnd file

DS can set and unset it at will from different threads

package my.project;import java.io.*;import javax.servlet.http.*;import org.osgi.framework.*;import org.osgi.service.component.*;import org.osgi.service.http.*;import org.osgi.service.log.*;import my.service.*;public class World {volatile LogService log; HttpService http; BundleContext context; protected void activate(ComponentContext context) {this.context = context

.getBundleContext(); }public void setLog(LogService log) {

this.log = log; } public void unsetLog(LogService log) {this.log = null; }…

Portal

Register the servlet and log any errors during the registration

Dont forget to unregister

public void setHttp(HttpService http) { this.http = http; try { http.registerServlet("/portal", new PortalServlet(), null, null); } catch (Exception e) { LogService log = this.log; if (log != null) { log.log(LogService.LOG_ERROR, "Registering /portal", e); } } } public void unsetHttp(HttpService http) { http.unregister("/portal"); }

Portal

The PortalServlet is where the main code is.The doGet method gets called by the Http Service implementation when a request comes inFirst we get the name and then a list of HtmlFragments.Just some HTML cruft …Print the references

…class PortalServlet extends HttpServlet { public void doGet( HttpServletRequest rq, HttpServletResponse rsp) throws IOException { PrintWriter pw = rsp.getWriter(); try { String path = getPath(rq); ServiceReference[] refs = getHtmlFragmentReferences(); pw.println( "<html><head><link rel='stylesheet' href='http://www.osgi.org/www/ osgi.css' type='text/css' / ><title>Portal</title></head>"); pw.println( "<body><table><tr><td><a href='/ portal'>Portal</a></br>\n"); ServiceReference found = doBody( pw, path, refs);…

Portal

Close the left columIf we found a matching name, let the HtmlFragment do its workClose the HTML page

… pw.println("</td><td>"); if (found != null) doHtmlFragment(rq, pw, found); pw.println( "</td></tr></table></body>"); } catch (Exception e) { doError(rsp, pw, e); } }…

Portal

getPath makes the remainder of the request path clean of slashes

Get the HtmlFragment references by creating a filter, looking for all HtmlFragment services that have the name set

private String getPath( HttpServletRequest rq) { String path = rq.getPathInfo(); if (path != null && path.startsWith("/")) path = path.substring(1); return path; } private ServiceReference[] getHtmlFragmentReferences() throws InvalidSyntaxException { String filter = String.format( "(%s=*)", HtmlFragment.NAME); ServiceReference refs[] = context .getServiceReferences( HtmlFragment.class.getName(), filter); return refs; }

Portal

The error handling to get a nicely formatted stack trace

Notice how we carefully check if the log is null. The log variable is volatile, but it could change to null between the null check and the use of it

private void doError( HttpServletResponse rsp, PrintWriter pw, Exception e) throws IOException { pw.println("<pre>"); pw.println("Error occurred\n"); e.printStackTrace(pw); pw.println("</pre>"); rsp.sendError( HttpServletResponse. SC_SERVICE_UNAVAILABLE); LogService x = log; if (x != null) { x .log( LogService.LOG_ERROR, "Error during http request", e); } }

Portal

Give the HtmlFragment a chance to write the output

private void doHtmlFragment( HttpServletRequest rq, PrintWriter pw, ServiceReference found) throws Exception { HtmlFragment HtmlFragment = (HtmlFragment) context .getService(found); if (HtmlFragment != null) { try { HtmlFragment.write(rq, pw); } finally { context.ungetService(found); } } }

Portal

Print the titles of the HtmlFragments in the service registry

private ServiceReference doBody( PrintWriter pw, String path, ServiceReference[] refs) { ServiceReference found = null; for (int i = 0; refs != null && i < refs.length; i++) { String name = (String) refs[i] .getProperty(HtmlFragment.NAME); String title = (String) refs[i] .getProperty(HtmlFragment.TITLE); if (name.equals(path)) { pw.printf("%s</br>\n", title); found = refs[i]; } else { pw .printf( "<a href=\"/portal/%s\"> %s</a></br>\n", name, title); } } return found; } }}

Portal

bnd.bnd fileHttp Service is mandatoryLog Service is optional and dynamic (?)Run itTry it on http://localhost:8081/portal

Private-Package: ${p}Export-Package: my.serviceService-Component: ${p}.World; \

http=org.osgi.service.http.HttpService; \log =org.osgi.service.log.LogService?

Portal

What Did We Do?

Section XI –Creating a Content Provider

An Agent

OSGi has an extensive API for managing the bundles in the systemWe can use our portal to show the set of bundles. All we need to do is register a HtmlFragment serviceCreate a new project:

my.agentAdd to classpath:

the my.project

osgi.jar from repo

servlet.jaradd the COmponent class

package my.agent;import my.service.*;import java.io.*;import java.util.*;import javax.servlet.http.*;import org.osgi.framework.*;import org.osgi.service.component.*;public class Component implements HtmlFragment { BundleContext context; protected void activate( ComponentContext context) { this.context = context .getBundleContext(); }

An Agent

And print the installed bundles

public void write( HttpServletRequest request, PrintWriter pw) throws Exception { pw.println("Bundles</br><table>"); Bundle[] bundles = context .getBundles(); pw.printf( "<tr><th>Id</th><th>Symbolic Name</ th><th>Location</th><th>Last Modified</th></tr>\n"); for (Bundle b : bundles) { pw.printf( "<tr><td>%s</td><td>%s</td><td> %s</td><td>%s</td></tr>\n", b.getBundleId(), b .getSymbolicName(), b .getLocation(), new Date(b .getLastModified())); } pw.println("</table>"); }}

An Agent

Create a bnd.bnd fileThe provide: directive is used to specify the service it is registered underThe properties allow you to specify propertiesTry it!

Private-Package: ${p}Service-Component: ${p}.Component;\ provide:= \ my.service.HtmlFragment; \ properties:= \"aQute.fragment.name=agent,aQute.fragment.title=Agent"

An Agent

What We Did Not Learn

Security ArchitecturePermission ManagementSigned BundlesPackage ManagementBundle Life Cycle ManagementConfiguration Management and PreferencesServlet Support/Web ServerDevice AccessEvent Manager

UPNPUSER ADMINWIRE ADMINAPPLICATION MODELDEPLOYMENT ADMIN AND AUTOCONFDEVICE MANAGEMENT TREEINITIAL PROVISIONINGPOSITION, MEASUREMENT, STATEMETATYPEAND MUCH, MUCH, MORE...

Conclusion

The OSGi R4 Specifications consists of considerable more details than elucidated in this tutorialThere are many independent OSGi implementations on the market, both commercial and open source

Apache Felix, Atinav, Eclipse Equinox, Espial, IBM SMF, Knopflerfish/Ubiserv of Gatespace, ProSyst, …

The OSGi specification are today running on mobile phones, PDAs, embedded computers, desktops, and mainframesBoth in managed and unmanaged configurationsThe OSGi specifications solve real world problemsThe OSGi Alliance is working on making the OSGi specifications the standard for portable applications. Join us!

The End

Further reading:

www.aQute.biz/OSGi/Resources

www.osgi.org

bundles.osgi.org

www.eclipse.org/osgi

www.ProSyst.com

www.osgibook.org

Recommended