1 / 78

The OSGi Complete

Explore lesser-known OSGi services with practical examples based on Equinox, contributed by ProSyst. Learn about Wire Admin, Declarative Services, IO Connector, Initial Provisioning. Understand the importance and functionality of each service.

javiert
Download Presentation

The OSGi Complete

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. The OSGi Complete Dr. Pavlin Dobrev Research and Development Manager, ProSyst Labs EOOD Eclipse Equinox Committer p.dobrev@prosyst.com Stoyan Boshev Department Manager Development Tools, ProSyst Labs EOOD Eclipse Equinox Committer s.boshev@prosyst.com

  2. Contents • Introduction and Services Overview • OSGi Wire Admin Service Specification • OSGi Declarative Services Specification • OSGi IO Connector Service Specification • OSGi Initial Provisioning • Conclusions and Future Work

  3. Introduction • The aim of the tutorial is to present several not well known OSGi services and to promote them to the Eclipse community. • Special attention will be given to the code snippets and programming examples. • The applications presented here are based on Equinox.

  4. Donated Services from ProSyst • Implementations of: • OSGi Wire Admin Service Specification • OSGi Declarative Services Specification • OSGi IO Connector Service Specification • OSGi Initial Provisioning • Quality of the implementations: • Production ready code used in many projects • All services successfully pass the corresponding OSGi test cases.

  5. Donation History • EclipseCon 2007 – ProSyst declares the intention for donation of missing OSGi Services implementations. • July 2007 – Service code is contributed to Equinox Incubator. • September 2007 – All IP logs are resolved. • February 2008 – after successfully passed Graduation Review all components will be included in the Ganymede Simultaneous Release started from Milestone 6. The components can be downloaded from Eclipse Equinox web site. • Pavlin Dobrev and Stoyan Boshev will support them as committers.

  6. OSGi Service Implementations Overview 1/2 • OSGi Wire Admin Service Specification • An administrative service that is used to control a wiring topology • Used to wire components that produce data to components which consume data. • OSGi IO Connector Service Specification • Adopts the javax.microedition.io package as a basic communication infrastructure. • In J2ME, the Connector framework can be extended by the vendor of the Virtual Machine, but cannot be extended at run-time by bundle code. • This specification defines a service that adopts the flexible model of the Connector framework, but allows bundles to extend it.

  7. OSGi Service Implementations Overview 2/2 • OSGi Declarative Services Specification • Uses a declarative model for publishing, finding and binding to OSGi services. • Simplifies the task of authoring OSGi services by performing the work of registering the service and handling service dependencies. • OSGi Initial Provisioning Specification • Defines how the Management Agent can make its way to the Service Platform, and gives a structured view of the problems and their corresponding resolution methods. • Enables the management of a Service Platform by an Operator, and (optionally) to hand over the management of the Service Platform later to another Operator.

  8. OSGi Wire Admin Service Specification - Theory • The Wire Admin service is an administrative service that is used to control a wiring topology in the OSGi Service Platform • Bundles participate in this wiring process by registering services that produce or consume data. The Wire Admin service wires the services that produce data to services which consume data • The Wire Admin service is designed to cooperate closely with the Configuration Admin service.

  9. OSGi Wire Admin – Problems to be Solved • When a bundle wants to use a service and there are several implementations available, the bundle will receive one at random. • After a bundle has started using a service, the framework is no longer in control of the volume or type of data that is transferred. • If an administrator wants to make a bundle stop using a service, the only way is either to stop the producer or the consumer of the service.

  10. OSGi Wire Admin Service Specification - Solution • Wire Admin Service is between the producer and the consumer of the service • The Wire Admin Service controls the connection and the data • Typical data-producing service can be, for example, one that represents some physical device.It produces information about its current status. • Typical data-consumerscan be detectors, gauges,user interfaces, etc.

  11. OSGi Wire Admin Service – Objects 1/4 • Producer - A service object that generates information to be used by a Consumer service • Consumer - A service object that receives information generated by a Producer service • Wire - An object created by the Wire Admin service that defines an association between a Producer service and a Consumer service. Multiple Wire objects can exist between the same Producer and Consumer pair • WireAdmin - The service that provides methods to create, update, remove, and list Wire objects.

  12. OSGi Wire Admin Service – Objects 2/4 • WireAdminListener -A service that receives events from the Wire Admin service when the Wire object is manipulated or used. • WireAdminEvent - The event that is sent to a WireAdminListener object, describing the details of what happened. • Configuration Properties - Properties that are associated with a Wire object and that contain identity and configuration information set by the administrator of the Wire Admin service. • PID - The Persistent Identity as defined in the Configuration Admin specification.

  13. OSGi Wire Admin Service – Objects 3/4 • Flavors - The different data types that can be used to exchange information between Producer and Consumer services. • Composite Producer/Consumer - A Producer/ Consumer service that can generate/accept different kinds of values. • Envelope - An interface for objects that can identify a value that is transferred over the wire. Envelope objects contain also a scope name that is used to verify access permissions. • Scope - A set of names that categorizes the kind of values contained in Envelope objects for security and selection purposes.

  14. OSGi Wire Admin Service – Objects 4/4 • Basic Envelope - A concrete implementation of the Envelope interface. • WirePermission - A Permission sub-class that is used to verify if a Consumer service or Producer service has permission for specific scope names. • Composite Identity - A name that is agreed betweena composite Consumer and Producer service to identify the kind of objects that they can exchange.

  15. org.osgi.service.wiring package: Source: OSGi Specification

  16. Creating a Producer Service 1/2 • A producer service must implement and register the org.osgi.service.wireadmin.Producer interface. Its polled(Wire) method should return the data outputsent across the wires. • The consumersConnected(Wire[]) method actualizes the list of connected wires.

  17. Creating a Producer Service 2/2 • Each producer may be registered with the following properties: • org.osgi.framework.Constants.SERVICE_PID - the service PID of the producer (mandatory) • WireConstants.WIREADMIN_PRODUCER_FLAVORS - the object classes created by the producer. It takes Class[] values. • WireConstants.WIREADMIN_PRODUCER_FILTERS - (if the producer will handle the filtering) the data filters. • WireConstants.WIREADMIN_PRODUCER_COMPOSITE - (for composite producers only) the service PIDs of the composite consumers it will communicate with. • WireConstants.WIREADMIN_PRODUCER_SCOPE - (for composite producers only) the data types the producer will create.

  18. Example Producer 1/2 • The following example creates a producer for String output. This is indicated by the value of the org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS registration property. The service is also registered with the producer.all PID. The only output it sends is a single String. It will be received by consumers connected with wires to this producer. ... public void start (BundleContext bc) throws BundleException { Hashtable props = new Hashtable(); //the producer will be sending String data (flavors) Class[] flavors = new Class[] {String.class}; props.put(WireConstants.WIREADMIN_PRODUCER_FLAVORS, flavors); //the producer PID property props.put("service.pid", "producer.all"); reg = bc.registerService(Producer.class.getName(), this, props); }

  19. Example Producer 2/2 /** If there are connected wires, updates them with the produced values */ public void consumersConnected(Wire[] wires) { if (wires != null) { for (int i = 0; i < wires.length; i++) { wires[i].update(polled(wires[i])); } } } /** This method is responsible for creating the output */ public Object polled(Wire wire) { String output = "Hello there! This is the producer speaking!"; return output; } }

  20. Filtering the Data Output • By the producer - The producer can be implemented so as to filter the data for sending (its polled method should be implemented so as to produce only values corresponding to the necessary filter). In this case, it must be registered with the WireConstants.WIREADMIN_PRODUCER_FILTERS property. • By the connecting wire - In this case, the Wire Admin will create the Wire with the WireConstants.WIREADMIN_FILTER property; the producer must NOT have the WireConstants.WIREADMIN_PRODUCER_FILTERS property simultaneously!

  21. Filtering the Data Output by the Producer ... Hashtable props = new Hashtable(3); Class[] flavors = new Class[] {Double.class}; //the producer registers for Double data output props.put(WireConstants.WIREADMIN_PRODUCER_FLAVORS, flavors); props.put(WireConstants.SERVICE_PID, "producer.that.filters"); // set this registration property with some value //to indicate that filtering is performed by the producer props.put(WireConstants.WIREADMIN_PRODUCER_FILTERS, "some.value"); bc.registerService(Producer.class.getName(), this, props); ... //the data is sent only if it is no smaller than 25 public Object polled(Wire wire) { return (currentTemperature >= 25.d) ? new Double(currentTemperature) : null; }

  22. Value Based Filters • WireConstants.WIREVALUE_CURRENT ("wirevalue.current") - Indicates the current value available on the wire • WireConstants.WIREVALUE_PREVIOUS ("wirevalue.previous") - Indicates the previous value passed across the wire • WireConstants.WIREVALUE_DELTA_ABSOLUTE ("wirevalue.delta.absolute") - The absolute (always positive) difference between the last update and the current value • WireConstants.WIREVALUE_DELTA_RELATIVE ("wirevalue.delta.relative") - The relative difference is (current_value - previous_value ) / current. • WireConstants.WIREVALUE_ELAPSED ("wirevalue.elapsed") -for constructing time-based filters. It represents the elapsed time in milliseconds between the current value and the previous value sent by the producer.

  23. Creating a Consumer Service • A consumer service must implement and register the org.osgi.service.wireadmin.Consumer interface. It may have the following list of registration properties: • org.osgi.framework.Constants.SERVICE_PID - the service PID of the consumer (mandatory) • WireConstants.WIREADMIN_CONSUMER_FLAVORS - the consumed data object classes (flavors). • WireConstants.WIREADMIN_CONSUMER_COMPOSITE - (only for composite consumers) the service PIDs of the producers this service will communicate with • WireConstants.WIREADMIN_CONSUMER_SCOPE - (only for composite consumers) the list of descriptive data types consumed by the service.

  24. Example Consumer ... public void start(BundleContext bc) throws BundleException { Hashtable prop = new Hashtable(); //this property shows that the consumer will accept any data types prop.put(WireConstants.WIREADMIN_CONSUMER_FLAVORS, new Class[] {Object.class}); //the identifier property of the consumer prop.put("service.pid", "consumer.all"); //registering the service on the framework reg = bc.registerService(Consumer.class.getName(), this, prop); }

  25. Example Consumer /** Watches the list of wires*/ public void producersConnected(Wire[] wires) { if (wires == null) { System.out.println("Not connected to any wires"); } else { System.out.println("Connected to " + wires.length + " wires"); } } /** Receives the new data whenever such are available */ public void updated(Wire wire, Object value) { System.out.println("Updated " + wire + " with value " + value); }

  26. Creating Wire using Wireadmin // getting a WireAdmin service reference waRef = bc.getServiceReference(WireAdmin.class.getName()); // getting the WireAdmin Service Implementation wa = (WireAdmin) bc.getService(waRef); // create wire wire = wa.createWire("producer.all", "consumer.all", new Hashtable());

  27. Creating Wire // getting a Configuration Admin service reference saRef = bc.getServiceReference(ConfigurationAdmin.class.getName()); ca = (ConfigurationAdmin) bc.getService(saRef); try { // Create Factory Configuration c=ca.createFactoryConfiguration("equinox.wireadmin.fpid", "initial@reference:file:plugins/org.eclipse.equinox.wireadmin_0.1.0.jar/"); Hashtable props = new Hashtable(); props.put("wireadmin.consumer.pid", "consumer.all"); props.put("wireadmin.producer.pid", "producer.all"); c.update(props); } catch (IOException e) { throw new BundleException("Configuration Admin Exception!" + e.getMessage()); }

  28. Creating Composite Producers/Consumers 1/2 • Composite consumers and producers have additional registration properties besides those for ordinary producers and consumers. See the corresponding descriptions for details. • Such composite services exchange data in the form of org.osgi.service.wireadmin.Envelope objects (flavors). An Envelope wraps a number of data types, for example: "front left door status", "rear left door status" and "airbag status".

  29. Creating Composite Producers/Consumers 2/2 • The org.osgi.service.wireadmin package provides the following class implementing the Envelope interface: • BasicEnvelope - this class can be used as a basic implementation of the Envelope interface. Source: OSGi Specification

  30. Example – Implementing Composite Producer . . . private String[] scope = new String[] {"current.date","hello","bye"}; private Class[] flavors = new Class[] {Envelope.class}; . . . /** Registering the service with the necessary props */ java.util.Hashtable props = new java.util.Hashtable(); //the data types transmitted by this producer props.put(WireConstants.WIREADMIN_PRODUCER_SCOPE,scope); props.put(org.osgi.framework.Constants.SERVICE_PID,"test.producer"); //this property indicates the PIDs of the consumers that the producer will communicate with props.put(WireConstants.WIREADMIN_PRODUCER_COMPOSITE, new String[] {"test.consumer"}); //for composite services, the value of this property must be Envelope props.put(WireConstants.WIREADMIN_PRODUCER_FLAVORS, flavors); bc.registerService(Producer.class.getName(),this,props); . . . public Object polled(Wire wire) { String date = new java.util.Date().toString(); BasicEnvelope envelope = new BasicEnvelope(date,"test.producer","current.date"); System.out.println("Message from the producer: My current date is "+envelope.getValue()); return envelope; }

  31. Creating a WireAdmin Listener • The WireAdminListener interface allows you to receive WireAdminEvent-s notifying of changes in the state of the wire. The WireAdminEvent class provides the following types of events and their correspondent class fields: • creating a new Wire object - WIRE_CREATED • connecting an existing Wire object - WIRE_CONNECTED • updating an existing Wire object with new properties - WIRE_UPDATED • transferring a new value over the Wire object - WIRE_TRACE • disconnecting an existing Wire object - WIRE_DISCONNECTED • deleting an existing wire - WIRE_DELETED • a Producer service method has thrown an exception - PRODUCER_EXCEPTION • a Consumer service method has thrown an exception - CONSUMER_EXCEPTION

  32. Creating a WireAdmin Listener - Code Example public void start(BundleContext bc) { //bitwise OR of the event types Integer bitmask = new Integer(WireAdminEvent.PRODUCER_EXCEPTION | WireAdminEvent.CONSUMER_EXCEPTION); Hashtable props = new Hashtable(); props.put(WireConstants.WIREADMIN_EVENTS, bitmask); reg = bc.registerService(WireAdminListener.class.getName(), this, props); } // WireAdminListener implementation public void wireAdminEvent(WireAdminEvent e) { switch (e.getType()) { case WireAdminEvent.PRODUCER_EXCEPTION: // do some work break; case WireAdminEvent.CONSUMER_EXCEPTION: // do some work break; } } }

  33. OSGi WireAdmin Summary • Used to wire components that produce data to components which consume data • Data can be: • Simple • Composite • Data can be filtered: • By the producer • By the Wire itself • Additionally you can listen for WireAdmin Events

  34. OSGi Declarative Services Specification • What are Declarative Services? • Service component model • Represent components and their dependencies to services • A component may provide a service and/or may consume a service • Declarative representation in XMLs • Service component runtime (SCR) • Processes the components of the activated bundles • Manages the lifecycle of the components based on changes in: • dependent services • configurations (Configuration Admin Service Specification) • bundles state

  35. Service Component Runtime relations Source: OSGi Specification

  36. Component Life Cycle 1/2 • Enabled state • It is bound to its bundle life cycle • Can be initially controlled by the component description (attribute “enabled”) • Can be controlled programatically by using the ComponentContext methods enableComponent(String) and disableComponent(String) • Satisfied state • A component is satisfied when: • It is enabled • All of its references are satisfied

  37. Component Life Cycle 2/2 • Activation • Activating a component consists of the following steps performed by SCR: • Load the component implementation class • Create the component instance and component context • Bind the target services • Call the activate method, if present • Deactivation • Deactivating a component consists of the following steps performed by SCR: • Call the deactivate method, if present • Unbind any bound services • Release all references to the component instance and component context

  38. First steps using Declarative services • Steps required to create a component that provides a service: • Create the service interface • Create the implementation of the interface • Write the component description XML • Add the component description to the “Service-Component” manifest header

  39. Declarative Services – Step By Step 1,2/4 • Write the service interface: package simple.service; public interface HelloService { public void hello(); } • Write the service implementation: package simple.service.impl; import simple.service.HelloService; public class HelloServiceImpl implements HelloService { public void hello() { System.out.println("Hello components!"); } }

  40. Provide an XML with the component description 3/4 <?xml version="1.0" encoding="UTF-8"?><scr:component name="HelloServiceComponent" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"><!-- The component's implementation class--> <implementation class="simple.service.impl.HelloServiceImpl"/> <service><!--The interface of the service provided by the component--> <provide interface="simple.service.HelloService"/> </service> </scr:component>

  41. Header in Bundle Manifest 4/4 • Use Service-Component header in the manifest to declare the XML description: Service-Component: <path to the XML document's location> • For example Service-Component: OSGI-INF/Hello.xml

  42. References to services 1/4 • Accessing services • Lookup strategy • Component implementations must have activate(ComponentContext) and deactivate(ComponentContext) methods • use ComponentContext to locate services • Event strategy (binder methods) • The component defines bind and unbind methods for each reference • These methods can have as parameter ServiceReference or the type specified by the reference’s interface attribute

  43. References to services 2/4 • Reference cardinality • “cardinality” is an optional attribute of the “reference” element • It defines the reference’s multiplicity and optionality • Possible cardinality values: 0..1 – Optional and unary 1..1 – Mandatory and unary (Default) 0..n – Optional and multiple 1..n – Mandatory and multiple

  44. References to services 3/4 • Reference policy • Static • The default policy of a reference • Components are reactivated on each change of its reference • Simple but expensive • Not suitable for references with cardinality 0..n or 1..n • Dynamic • More complex to handle • SCR updates the bound service of a component without reactivating it

  45. References to services 4/4 • Selecting target services • Use the “target” attribute to define a filter to constrain the services that match the reference • The “target” is an LDAP filter Example: <reference name=“AppFactory" interface="org.osgi.service.component.ComponentFactory" target="(component.factory=my.application)" />

  46. Lookup Strategy for Getting Services 1/3 • Write a reference element in the component's description XML to declare the referenced service(s) • Get the component's ComponentContext object passed as an argument to the component's activate() method • Call the locateService or locateServices method of the ComponentContext

  47. Lookup Strategy for Getting Services 2/3 <?xml version="1.0" encoding="UTF-8"?> <scr:component name="HelloServiceLookup" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"><implementation class="simple.service.reference.HelloServiceLookup"/><reference name="helloService" interface="simple.service.HelloService"/> </scr:component>

  48. Lookup Strategy for Getting Services 3/3 public class HelloServiceLookup { ComponentContext cc; protected void activate(ComponentContext ctxt){ this.cc = ctxt; } public void useService() { HelloService helloService = (HelloService) cc.locateService("helloService"); helloService.hello(); } protected void deactivate(ComponentContext ctxt){ this.cc = null; } }

  49. Event Strategy for Getting Services 1/3 • Write binding and unbinding methods • Declare them in the reference element of the component description • SCR passes the referenced service as an argument of the bind and unbind methods

  50. Event Strategy for Getting Services 2/3 ... public class HelloServiceBind { HelloService helloService; public void setHelloService(HelloService helloService){ this.helloService = helloService; } public void unsetHelloService(HelloService helloService){ this.helloService = null; } protected void activate(ComponentContext ctxt){ //note that lookupService() is not called helloService.hello(); } ...

More Related