Upload
landon-doyle
View
243
Download
3
Tags:
Embed Size (px)
Citation preview
aQuteOSGi Bootcamp
Workshop Exercise
By Peter KriensCEO aQute
OSGi Technology Officer andOSGi Fellow
©1999-2003 aQute, All Rights Reserved
Setting Up The Environment
• The CD contains all the tools you need:– Java 1.4.1– Eclipse 2.0.2– Exercise projects with source (ex dir)– Framework fwx.exe
• Also available on the network \\ziggy\fwx
• Install Java 1.4.1, Install Eclipse
• Copy the workshop dir to c:\fwx
©1999-2003 aQute, All Rights Reserved
What Will We Do?
• These exercises take a step by step approach to make a larger program
• This program is a “See your buddies” Web page viewer
• Each participant will make a Web page
• This web page is automatically registered with all participants portal's
• With Zero Administration …
©1999-2003 aQute, All Rights Reserved
Overview
app2
app3 app1
app4
Browser
app 1app 2app 3app 4
SP 2
SP 3
SP 4
SP 1
multicast
©1999-2003 aQute, All Rights Reserved
Architecture: Classes
ActivatorDistributor
Link
HttpTrackerTracks httpservers
findsbuddies
<<interface>>Http Service
ServiceTracker
Thread<<interface>>BundleActivator
Tracks buddies Registers page
Portal Tracks portal entries
Registers /portal page
LogService
Logs messages
HttpContext
©1999-2003 aQute, All Rights Reserved
What Will We Learn?
• Using Eclipse
• Constructing an OSGi bundle
• Class path management
• Using the Log service
• Tracking of the Http Services
• Registering a servlet
• Using the demo portal
• Networking code
©1999-2003 aQute, All Rights Reserved
1.1 Hello World Bundle
• Create a simple bundle printing "Hello World" and "Goodbye World" at start and stop
• What will you learn?– Construct a BundleActivator class– Add a correct Manifest– Place it all in a JAR file– Starting the Framework– Install/Uninstall a bundle
©1999-2003 aQute, All Rights Reserved
1.1 Back to Basics: Hello World
Activator
The Activator class will print “Hello World” when the bundle is started and “Goodbye World” when it stops.
<<interface>>BundleActivator
©1999-2003 aQute, All Rights Reserved
1.1 Getting Started
• Assumptions– Eclipse 2.0.2 (check in Help:About, 2.0.0 does not
work!) installed– Started Eclipse
©1999-2003 aQute, All Rights Reserved
1.1 Eclipse
©1999-2003 aQute, All Rights Reserved
1.1 Getting Started
• Create new Java Project– File:New:Project– Java Project, Next– Name is “ws”– Default location, Next– Libraries, Add external jars,
• servlet.jar, osgi.jar (from where you copied the files. c:\fwx\osgi.jar)
– Attach source (select osgi.jar), Finish
©1999-2003 aQute, All Rights Reserved
1.1 Add External Jar
©1999-2003 aQute, All Rights Reserved
1.1 Setup Activator class
• Add Package– File:New:Package– Name, aQute.world.congress
©1999-2003 aQute, All Rights Reserved
1.1 Setup Activator
• Add new class
• File:New:Class– Package, aQute.world.congress– Name, Activator– Interfaces
• Add BundleActivator
• Finish
• Eclipse will open a generated source file
©1999-2003 aQute, All Rights Reserved
1.1 Activator class setup
©1999-2003 aQute, All Rights Reserved
1.1 Write Hello/Goodbye World
• Fill in the System.out.println(“...”) in the appropriate places
• Save the file (File:Save or control-S)– This automatically compiles, so correct any errors
©1999-2003 aQute, All Rights Reserved
1.1 Create The Manifest
• We only define what class to start: Activator
• File:New:File, name it Manifest.mf – Store in aQute.world.congress package/folder
• Manifest MUST end with 2 empty lines!!• Fill in (and save):
Manifest-Version: 1.0Bundle-Activator: aQute.world.congress.Activator
©1999-2003 aQute, All Rights Reserved
1.1 Create Manifest
©1999-2003 aQute, All Rights Reserved
1.1 Create Bundle JAR file!
• Select “ws” in left pane
• Press right mouse button
• Select Export
• Select JAR File
• Next
©1999-2003 aQute, All Rights Reserved
1.1 Create JAR File
• Export Destination– Name it ws.jar– Save the JAR in the load directory
where you copied fwx,e.g. c:\fwx\load
• Next
©1999-2003 aQute, All Rights Reserved
1.1 Create JAR file
• Deselect “with compile errors”
• Save the description in the “ws” workspace, under the name bundle.jardesc
• Next
©1999-2003 aQute, All Rights Reserved
1.1 Create JAR file
• Set to use existing Manifest– Select Manifest.mf
• Finish
• (It is OK to create theload directory)
©1999-2003 aQute, All Rights Reserved
1.1 Starting A Framework
• The fwx.jar is the OSGi Reference Framework with all the R3 services reference implementations– This Framework is not optimized, nor industrialized– It expires in 60 days– Contact a vendor for a real framework
• To start it, open a window on its directory and double click it
• It will automatically start all bundles in the load directory– This is not standard but implemented in a bundle
©1999-2003 aQute, All Rights Reserved
1.1 Starting the Framework
©1999-2003 aQute, All Rights Reserved
1.1 Restarting
• You can restart the bundle by – select the bundle.jardesc– Right mouse: Create Jar
• This works because the fileinstall bundle on the Framework will detect that the JAR file is modified in the load directory
• This will automatically update the bundle in the Framework (look at the console)
©1999-2003 aQute, All Rights Reserved
1.1 What Did We Learn?
• We learned how to create a real bundle
• This bundle needed– An Activator class– A Manifest
• These components were packed in a JAR file
• This JAR file was installed and started on an OSGi Framework with the fileinstaller bundle
• The console was used to see the start and stop methods
©1999-2003 aQute, All Rights Reserved
1.2 Using the Log Service
• Instead of using the console, change the code to use the Log Service from the registry
• What will you learn in this exercise?– Use a service from another bundle– Import packages from another bundle– Get a service from the registry– Use the log service– Find out the methods of a service
©1999-2003 aQute, All Rights Reserved
1.2 Using The Log Service
Activator
We will now use a service: The Log Service
<<interface>>BundleActivator
LogService
Logs messages
©1999-2003 aQute, All Rights Reserved
org.osgi.service.log v1.1Log Service
• Simple and small Log service for operator
• 4 Levels– INFO, DEBUG, WARNING, ERROR
• Automatically logs framework events in a defined way
• Other bundles can access log history– Management bundle– Length implementation dependent
• Used also for accounting, notifications
©1999-2003 aQute, All Rights Reserved
org.osgi.service.log v1.1Log Service
a log usera log user a log readera log reader
LogServiceLogService LogEntryLogEntry LogListenerLogListener LogReaderService
LogReaderService
a log service impl.
a log service impl.
A log entryimpl.
A log entryimpl.
A log readerimpl.
A log readerimpl.
Log Service Impl. bundle
Log a message
Store a message for retrieval and broadcast
Message log
Send new log entry
Retrieve log
A loguser bundle
A logreaderusing bundle
©1999-2003 aQute, All Rights Reserved
1.2 Prepare for the Log Service
• Save the BundleContext parameter in a context instance variable
BundleContext context;public void start(BundleContext context) { this.context = context; ...}
©1999-2003 aQute, All Rights Reserved
1.2 The log() method
• Add a log() method to the Activator class:
void log( String msg, Throwable exception ) { ServiceReference ref = context.getServiceReference( LogService.class.getName() ); LogService log = null; if ( ref != null ) { log =(LogService) context.getService(ref); if ( log != null ) { if ( exception == null ) log.log( LogService.LOG_INFO, msg ); else log.log( LogService.LOG_ERROR, msg, exception ); } context.ungetService(ref); return; } System.out.println( msg + " : " + exception );}
©1999-2003 aQute, All Rights Reserved
1.2 Use the log method
• Replace the calls to System.out with calls to the log() method
public void start(BundleContext context) { this.context = context; log( "Hello world", null );}public void stop(BundleContext context){ log( "Goodbye world", null );}
©1999-2003 aQute, All Rights Reserved
1.2 Organize Imports
• Source:Organize Imports
• This will automatically add the necessary import statements
©1999-2003 aQute, All Rights Reserved
1.2 Contents of LogService
• How can you find out what the LogService can do for you?
– Use the Javadoc (on the CD)– Click on the type, open context menu (right mouse
button) and select "Open Declaration"– Use the Ctrl-Space function in Eclipse
©1999-2003 aQute, All Rights Reserved
1.2 Finding The Methods
Type Ctrl-Space
©1999-2003 aQute, All Rights Reserved
1.2 Importing
• We use the Log Service, this requires the import of the org.osgi.service.log package
• This is indicated in the Manifest file with the Import-Package manifest header
• This header may contain any number of packages, separated with a comma, and optionally with a specification-version modifier
©1999-2003 aQute, All Rights Reserved
1.2 Modify The Manifest
• Edit Manifest.mf
• Add Import-Package for– org.osgi.service.log
Manifest-Version: 1.0Bundle-Activator: aQute.world.congress.ActivatorImport-Package: org.osgi.framework, org.osgi.service.log;specification-version=1.0
©1999-2003 aQute, All Rights Reserved
1.2 Using the Log Service
• Save the source file (correct compile errors)
• Select bundle.jardesc, right menu, Create JAR
• Check the console of fwx:– Goodbye world– But no Hello world … This is now in the log– Where is the log????
©1999-2003 aQute, All Rights Reserved
1.2 Viewing the Log Service
• Open a telnet session– Start:Run:telnet localhost 2011
• This opens a simple OSGi console/debugger
• Type– log
©1999-2003 aQute, All Rights Reserved
1.2 The console
• The console bundle has many functions– exports - shows package export/import– lsb - list bundles– lss - list services (can use filter)– install <uri> - install– uninstall <id>– update bundle <id>– help
• Can be extended by other bundles, see org.osgi.tools.command.CommandProvider
©1999-2003 aQute, All Rights Reserved
1.2 Changing the version
• Verify what happens when the specfication version is modified
• Set the version to 1.8 and create the JAR file
©1999-2003 aQute, All Rights Reserved
1.2 What Did We Learn?
• Using the Log Service
• Importing a package, with version specification
• Getting a service from the registry
• Using the OSGi console bundle
©1999-2003 aQute, All Rights Reserved
1.2a Using the Service Tracker
• Track the OSGi Log Service with a Service Tracker
• What will we learn?
• How to efficiently track a service
• Assure that a temporary absence of a service does not disrupt our program
• The org.osgi.util.tracker.ServiceTracker utility
©1999-2003 aQute, All Rights Reserved
1.2a Use the ServiceTracker
• Create a ServiceTracker for the log
ServiceTracker tracker;
public void start(BundleContext context) { this.context = context; tracker = new ServiceTracker( context,
LogService.class.getName(), null ); tracker.open();}
©1999-2003 aQute, All Rights Reserved
1.2a Use The ServiceTracker
• Change the log() method to use the tracker
void log( String msg, Throwable exception ) { try { LogService log =(LogService) tracker.waitForService(15000); if ( exception == null ) log.log( LogService.LOG_INFO, msg ); else log.log( LogService.LOG_ERROR, msg, exception ); return; } catch ( InterruptedException ie ) {} System.out.println( msg + " : " + exception );}
©1999-2003 aQute, All Rights Reserved
1.2a What Did We Learn?
• We now correctly handling the coming and going of services
• Using a ServiceTracker simplifies the coding of services that are obtained from the registry
• The use of the log is now robust
©1999-2003 aQute, All Rights Reserved
1.3 Using the Http Service
• Register a static HTML page with the local Http Service
• What will we learn?
• Use the ServiceTracker more extensively
• How to register a static HTML page with the Http Service
• How to implement the HttpContext
©1999-2003 aQute, All Rights Reserved
1.3 Publishing a page
HttpTrackerTracks httpservers
<<interface>>Http Service
ServiceTracker
Registers page
Registers /portal page
Activator
<<interface>>BundleActivator
LogService
Logs messages
HttpContext
©1999-2003 aQute, All Rights Reserved
org.osgi.service.http v1.1Http Service
• Provides web access to bundles
• A powerful servlet runner– Supports Servlets Version 2.1
• Very simple to export static pages and files (like images)
• Automatically unregisters servlets when bundle is stopped
©1999-2003 aQute, All Rights Reserved
org.osgi.service.http v1.1Http Service
Impl. Of Httpcontext
Impl. Of Httpcontext
Impl. Of servlet
Impl. Of servlet
HttpContextHttpContext NameSpaceException
NameSpaceException HttpServiceHttpService
javax.servlet.Servlet
javax.servlet.Servlet
Default impl.HttpContext
Default impl.HttpContext
Resourceregistration
Resourceregistration
Servletregistration
Servletregistration
Bundles main code
Bundles main code
javax.servlet.Request/Response
javax.servlet.Request/Response
NameSpacealias
NameSpacealias
An Http Serviceimpl.
An Http Serviceimpl.
©1999-2003 aQute, All Rights Reserved
1.3 Create An Html Page
• File:New:File– Directory, aQute/world/congress– Call it page.html
• Edit it (select page.html, Open With:Text Editor)
<html> <head> <title>My Demo HTML page</title> </head> <body> <h1>My Demo</h1> This is aQute's (use your own name!) demo page </body></html>
©1999-2003 aQute, All Rights Reserved
1.3 Create an HTML Page
©1999-2003 aQute, All Rights Reserved
1.3 Create HttpTracker
• HttpTracker tracks Http Service objects and adds a “page.html” to every Http Service
• It extends ServiceTracker to simplify tracking– Object addingService(ServiceReference)– void modifiedService(ServiceReference,Object)– void removedService(ServiceReference,Object)
• Create new class aQute.world.congress.HttpTracker that extends ServiceTracker, implements HttpContext
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• And it needs a variable, constructor, add:
Activator activator;
public HttpTracker( Activator activator, BundleContext context ) { super( context, HttpService.class.getName(),null); this.activator = activator;}
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• addingService
public Object addingService( ServiceReference reference ) { HttpService http = (HttpService)super.addingService(reference); try { http.registerResources("/mydemo", "", this ); } catch( NamespaceException e ) { activator.log( "Cannot register because “
+ “name is already in use: /mydemo", e ); } return http;}
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• Modify the getResource method to return resources from the package
public URL getResource(String name) { try { URL url = getClass().getResource( name.substring(1) ); return url; } catch( Exception e ) { e.printStackTrace(); } return null;}
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• handlSecurity returns false. This means deny access, change it to return true.
public boolean handleSecurity( HttpServletRequest request, HttpServletResponse response) throws IOException { return true;}
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• Organize Imports
• Save it
• Add an instance variable for the Http Tracker to Activator class
• And add the following lines to the start() method http = new HttpTracker( this, context );http.open();
HttpTracker http;
©1999-2003 aQute, All Rights Reserved
1.3 Clean-up
// Add to stop methodhttp.close();
©1999-2003 aQute, All Rights Reserved
1.3 Modify The Manifest
• Add Import-Package for– org.osgi.util.tracker– org.osgi.service.http– javax.servlet.http, javax.servlet
Manifest-Version: 1.0Bundle-Activator: aQute.world.congress.ActivatorImport-Package: org.osgi.framework, org.osgi.service.log,org.osgi.util.tracker, org.osgi.service.http,javax.servlet.http, javax.servlet
©1999-2003 aQute, All Rights Reserved
1.3 Add HttpTracker class
• Save open files
• Select bundle.jardesc– Create JAR
• Open a browser and surf into– http://localhost/mydemo/page.html
• Ensure that your HTTP proxy is off!– IE : Tools : Internet Options : Connections : Lan
settings
©1999-2003 aQute, All Rights Reserved
1.3 What Did We Learn?
• Understanding how the ServiceTracker can be used to track services and execute a task for the registration and un-registration of a service
• Understanding the HttpContext
• Serving static pages from the local web server
©1999-2003 aQute, All Rights Reserved
1.3a Use The Portal
• Register our page with a local portal bundle using the white board approach
• What will we learn?
• Using the White Board approach
• Using the provided portal with our page
• Understand service registration properties
©1999-2003 aQute, All Rights Reserved
1.3a Use The Portal
Activator HttpTrackerTracks httpservers
<<interface>>Http Service
ServiceTracker
<<interface>>BundleActivator
Registers page
Portal
Registers /portal page
LogService
Logs messages
HttpContext
©1999-2003 aQute, All Rights Reserved
1.3a The Nursery Portal
• Not an official OSGi specification (Nursery)
• Uses the White Board approach to collect pages
• Properties are used to convey the information
• The portal is not a service in the registry
• Clients should register any service with the right properties
• Minimizes dependencies
©1999-2003 aQute, All Rights Reserved
1.3a Portal Mechanism
Registry
Bundle A{ }
register
Portalbundle
Events: register, unregister
Bundle C{ }
Bundle B{ }
Any objectget
urltitledescription
http://...My PageA demonst...
properties
Filter (url=*)
Properties
©1999-2003 aQute, All Rights Reserved
1.3a Portal
• In the start() method, add the following code:
String host= InetAddress.getLocalHost().getHostName();if ( System.getProperty( "org.osgi.service.http.port" ) != null ) host += ":" + System.getProperty( "org.osgi.service.http.port" );
Dictionary properties = new Hashtable();properties.put( "title", "Local Demo Page" ); properties.put( "description", "This page demonstrates my skills!" );properties.put( "url", "http://" + host + "/mydemo/page.html" );context.registerService( String.class.getName(), "dummy", properties );
©1999-2003 aQute, All Rights Reserved
1.3a Portal
• Verify that your page is registered at the portal– http://localhost:8000/portal
©1999-2003 aQute, All Rights Reserved
1.3a What Did We Learn
• How to register a service
• The ideas behind the white board– Use the Framework registry as a private registry– Minimized dependencies
• Use of the portal
©1999-2003 aQute, All Rights Reserved
1.4 Finding Your Buddies
• Announce the page URL with a multicast on the network and register the received URLs with the portal
• What will you learn?
• How to register a service
• How send out multicast packages
• Using a background thread to receive packages
• Minimize consequences in the light of errors
©1999-2003 aQute, All Rights Reserved
1.4 Finding Your Buddies
HttpTrackerTracks httpservers
<<interface>>Http Service
ServiceTracker
Registers page
Portal
Registers /portal page
Activator
<<interface>>BundleActivator
LogService
Logs messages
Distributor
Link
findsbuddies
Thread
Tracks buddies
Tracks portal entries
HttpContext
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
• Add a new class Distributor– Package aQute.world.congress– Extends Thread
• This class will open a UDP socket
• Will listen to all Datagram’s on port 2014
• Forwards all datagrams to the activator
• Sends an announce datagram every 5 seconds
• Simple mechanism to dynamically discover others
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
• Add Instance variable declarations
boolean active = true;DatagramSocket socket;byte outgoing[];Activator activator;
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
• Add Constructor
Distributor( Activator activator, String outgoing ) { super("distributor"); this.activator = activator; this.outgoing = outgoing.getBytes();}
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
public void run() { while ( active ) try { socket = new DatagramSocket( 2014 ); socket.setSoTimeout( 5000 ); activator.log("Discovery starts.", null); … inner loop … see next slide socket.close(); socket = null; } catch(Exception e) { activator.log( "Main discover loop exit", e ); if ( active ) try { Thread.currentThread().sleep(1000); } catch( Exception x) {} } activator.log("Discovery quits.", null);}
• The run() method is the body of the thread. It will loop until the active flag becomes false. It uses the socket timeout to regularly send an announce
©1999-2003 aQute, All Rights Reserved
• The inner loop of the run() method receives the package and handles errors
1.4 Add Distributor class
while ( active ) try { DatagramPacket packet = new DatagramPacket(new byte[256], 256); socket.receive(packet); String incoming = new String( packet.getData(), 0, packet.getLength()); activator.process( new Link(incoming) ); }catch(InterruptedIOException e) { announce();} catch(Exception e) { if ( active ) activator.log( "Receving remote “ + “service packets, ignoring ", e );}
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
• The announce method is called on the timeout
void announce() throws IOException { DatagramSocket announce = new DatagramSocket(); DatagramPacket packet = new DatagramPacket( outgoing, outgoing.length, InetAddress.getByName("255.255.255.255"), 2014 ); announce.send(packet); }
©1999-2003 aQute, All Rights Reserved
1.4 Add Distributor class
• And the last close method resets the active flag and closes the port.
• Organize imports
• Save– Unresolved method in Activator: process
void close() { active = false; socket.close();}
©1999-2003 aQute, All Rights Reserved
1.4 Add Link class
• Add a Link class
• The Link class just holds the buddy info together.Hashtable properties = new Hashtable();ServiceRegistration registration;
Link( String msg ) { StringTokenizer tz =
new StringTokenizer( msg, "|" ); properties.put( "title", tz.nextToken() ); properties.put( "description",tz.nextToken()); properties.put( "url", tz.nextToken() ); }
©1999-2003 aQute, All Rights Reserved
1.4 Add Link class
• Register method, for a new discovered buddy
• Modify method, when old buddy, new message
void register( BundleContext context ) { registration = context.registerService( Link.class.getName(), this, properties );}
void modify( Link link ) { registration.setProperties(link.properties);}
©1999-2003 aQute, All Rights Reserved
1.4 Add Link class
• Unregister when link is gone
• To get the unique key
void unregister() { registration.unregister();}
Object getUrl(){ return properties.get( "url" ); }
©1999-2003 aQute, All Rights Reserved
1.4 Process method in Activator
• The process method adds a buddy to the portal
• The portal tracks “url” service property.
• Edit Activator, add process methodHashtable links = new Hashtable();void process( Link link ) { Link existing = (Link) links.get( link.getUrl() ); if ( existing != null ) existing.modify( link ); else { link.register( context ); links.put( link.getUrl(), link ); existing = link; }}
©1999-2003 aQute, All Rights Reserved
1.4 Add and Start the Distributor
// Add to start methodString host= InetAddress.getLocalHost().getHostAddress();if ( System.getProperty(
"org.osgi.service.http.port" ) != null )host += ":" + System.getProperty(
"org.osgi.service.http.port" );
distributor = new Distributor( this, "My Title|My Own Description|http://" + host +
"/mydemo/page.html" );distributor.start();
©1999-2003 aQute, All Rights Reserved
1.4 Clean-up (stop method)
// Add to stop methoddistributor.close();
©1999-2003 aQute, All Rights Reserved
1.4 Find the buddies
• Organize imports for all files
• Build JAR
• Browse to:– http://localhost:8000/portal
• You should see your own page, and with any luck pages from your buddies
©1999-2003 aQute, All Rights Reserved
2 OSGi Management
• Make a web based management application
• What will we learn?– Create a servlet– Register a servlet with the Http Service– How to find out about the configuration of the
Framework– Start/Stop/Uninstall/Update bundles– Install bundles– Using XML, XSLT and HTML (a bit :-)
©1999-2003 aQute, All Rights Reserved
2 Management Agent
• Implemented as a servlet that generates XML with all the bundle information
<top> <error>message</error> <!-- optional --> <bundle id="…" location="…" name="…" state="…"> … description … </bundle></top>
• Accepts the following parameters:– action: start/stop/update/uninstall/install– uri:<uri for installing a bundle> (only present with
install)– bundleId: <id>
©1999-2003 aQute, All Rights Reserved
2 Management Agent
• Create a new project called "ma" (management agent)
• Add the osgi.jar and servlet.jar libraries (Properties:libraries)
©1999-2003 aQute, All Rights Reserved
2 Creating the Activator
• Copy the Activator from the previous exercise to the "ma" project– Notice the automatic package renaming!
• Modify the Activator:– The portal registration (but keep it, it is handy)– Remove the distributor related code
• Ignore the errors for the moment
©1999-2003 aQute, All Rights Reserved
2 Management Agent
• Copy the HttpTracker from the previous exercise• Modify the HttpTracker.addingService method,
we must register a servlet now:
public Object addingService( ServiceReference reference ) { HttpService http = (HttpService)super.addingService(reference); try { http.registerResources("/agent", "", this ); http.registerServlet("/agent/servlet", new AgentServlet(activator,context), null, this ); } catch( NamespaceException e ) { activator.log( "Name is already in use /agent", e ); } catch( Exception e ) { activator.log( "Unexpected exception ", e ); } return http;}
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• Create an AgentServlet class, it extends the HttpServlet class
BundleContextcontext;Activatoractivator;
AgentServlet( Activator activator, BundleContext context ) { this.context = context; this.activator = activator;}
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• The doGet method is called for an HTTP GET request:
public void doGet( HttpServletRequest rq, HttpServletResponse rsp ) throws IOException { String bundleId = rq.getParameter("bundle"); String action = rq.getParameter("action"); String uri = rq.getParameter("uri");// if install rsp.setContentType("text/xml");
PrintWriter pw = new PrintWriter( rsp.getWriter()); prolog(pw); pw.println( "<top>" ); doAction(bundleId, action, uri, pw); listBundles(pw); pw.println( "</top>" ); pw.close();}
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• List all the existing bundles as XML
public void listBundles(PrintWriter pw) { Bundle bundles[] = context.getBundles(); for ( int i=0; i<bundles.length; i++ ) { Bundle bundle = bundles[i]; Dictionary p = bundle.getHeaders(); String name = get(p,"Bundle-Name", "?" ); String description = get(p,"Bundle-Description", "?" ); pw.println( "<bundle" +" location='" + bundle.getLocation() + "'" +" name='" + name + "'" +" id='" + bundle.getBundleId() + "'" +" state='" + bundle.getState() + "'" +">"); pw.println( escape( description ) ); pw.println( "</bundle>"); }}
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• Perform the actual action indicated in the "action" parameter:
public void doAction(String bid,Stringaction,String uri,PrintWriter pw){ Bundle bundle = null; try { if (bid!= null ) bundle = context.getBundle( Long.parseLong(bid)); if ( action!= null ) { if ( action.equals("start") ) bundle.start(); else if ( action.equals("stop") ) bundle.stop(); else if ( action.equals("update") ) bundle.update(); else if ( action.equals("uninstall") ) bundle.uninstall(); else if ( action.equals("install") ) context.installBundle( uri ); }} catch( BundleException e ) { error(action, pw, bundle, e, e.getNestedException()); } catch( Exception e ) { error(action, pw, bundle, e, null );}}
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• Support methods:
public void error(String action, PrintWriter pw, Bundle bundle, Exception e, Throwable nested) { pw.println( "<error class='" + e.getClass().getName() + "' action='" + action+ "' bundle='" + bundle + "'>" ); pw.println( escape(e.getMessage()) ); pw.println( "</error>" );}public void prolog(PrintWriter pw) { pw.println("<?xml version='1.0' encoding='UTF-8'?>" ); pw.println( "<?xml-stylesheet type='text/xsl' title='Compact' href='agent.xsl'?>" );}String get( Dictionary p, String key, String dflt ) { String result = (String) p.get( key ); if ( result != null ) return result; return dflt; }
©1999-2003 aQute, All Rights Reserved
2 AgentServlet
• The escape() method is needed to prevent <&> from ending up in an attribute or text, confusing the XML parser.
String escape( String source ) { // Should escape the entities like <, >, & StringBuffer sb = new StringBuffer(); for ( int i=0; i<source.length(); i++ ) { char c = source.charAt(i); switch(c) { case '&': sb.append( "&" ); break; case '<': sb.append( "<" ); break; case '>': sb.append( ">" ); break; default: sb.append( c ); }} return sb.toString(); }
©1999-2003 aQute, All Rights Reserved
2 XSL
• Notice the second line in the prolog:
<?xml-stylesheet type='text/xsl' title='Compact' href='agent.xsl'?>
• This is an instruction to the browser to use XML StyLe Transformation. XSL transforms the XML to HTML. This requires an XSL file called agent.xsl
• Copy this file from the CD (this is not an XSL course!)
• This page is served in our getResource in the HttpTracker
©1999-2003 aQute, All Rights Reserved
2 Management Agent
• Create the Manifest
• Create the JAR file (Export:Jar)
• Surf to http://localhost:8000/agent/servlet
• Or to http://localhost:8000/portal and select the management agent
• Simple isn't it?
©1999-2003 aQute, All Rights Reserved
2 What did we learn?
• We created a servlet that generates XML
• The XML was derived from the actual bundle configuration
• Servlet parameters were used to start/stop/install/uninstall/update bundles
• XSL was used to make XML
©1999-2003 aQute, All Rights Reserved
Conclusion
• Surprisingly little code is necessary to perform interesting functions
• Coupling to other parts is minimal because OSGi specified interfaces are intermediates
• Tools are available to simplify creation of manifest and bundle files
• This is only the beginning ...
©1999-2003 aQute, All Rights Reserved
Vendors With Tools & Courses
• Acunia - www.acunia.com
• aQute - www.aQute.se
• IBM - www.ibm.com/embedded
• Gatespace - www.gatespace.com
• ProSyst - www.prosyst.com
• Atinav - www.atinav.com
• Espial - www.espial.com
• See for more www.osgi.org