osgi tutorial
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 PresentationTRANSCRIPT
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