Provides information about the RM Provisioning APIs.
Provides the following provisioning APIs:

  • Frontend Provisioning API – Enables backend bundles and non-RM applications/systems to access provisioning information
  • OSGi Device Provisioning API – Enables developing custom provisioning info providers and provisioning storage components, which provide provisioning properties on the OSGi device side.

The basic concepts of the RM provisioning is described in the Initial Provisioning of OSGi Devices document from Conceptual Guide. The user interface for adding devices to the system is described in Registering New OSGi Devices from User's Guide.

Frontend Provisioning API

The Frontend Provisioning API provides means for:

  • Discovering OSGi devices running in the local network.
  • Creating a custom provisioning agent suitable for the specifics of a particular OSGi device.
  • Getting information about the optional administration features stored in the software repository.
  • Getting information about the HTTP and HTTPS ports opened by a particular backend server host.

The Frontend Provisioning API usually works in co-operation with the OSGi Device Manager API (the foundation API for managing OSGi devices). Through the OSGi Device Control API you can register and manage the discovered devices. 

Accessing the API

The Frontend Provisioning API is held in the com.prosyst.mprm.admin.provisioning package. Its main interface is the ProvisioningManager.
The ProvisioningManager interface is implemented and registered as a service by the Provisioning Bundle Backend Side (packages/osgidm.provisioning.be.jar).
Developers can also use the lib/api/osgidm-api.jar archive for development and compilation of applications based on the Provisioning API.
The ProvisioningManager interface can be accessed in two ways:

  • On the RM backend as a service on the backend framework by other bundles. You use the methods defined by the OSGi Framework specification.

Obtaining the Provisioning API as a service from a custom backend bundle:

import com.prosyst.mprm.admin.provisioning.*;
import org.osgi.framework.*;
 
. . .
private BundleContext bc;
private ServiceReference ref;
private ProvisioningManager prvMan;
 
. . .
ref = bc.getServiceReference(ProvisioningManager.class.getName());
if(ref != null) {
prvMan = (ProvisioningManager) bc.getService(ref);
. . .//Do some work with the obtained Provisioning Manager
}
  • Through the remote access client (RAC) from a destination remote to the RM backend. The RAC class libraries to use are lib/rac/system-rac.jar and lib/rac/osgidm-rac.jar. See the Remote Access to RM for more information about using a remote access client.

Obtaining the Provisioning API from a non-RM application:

import com.prosyst.mprm.admin.provisioning.*;
import com.prosyst.mprm.rac.RemoteAccessClient;
 
. . .
private RemoteAccessClient rac;
private ProvisioningManager prvMan;
 
. . .//Obtaining a connected rac object in the appropriate way
prvMan = (ProvisioningManager) rac.getService(ProvisioningManager.class.getName());
. . .//Do some work with the obtained Provisioning Manager


From now on, we shall assume that we have a reference to a ProvisioningManager object called prvMan and shall reuse it in the following examples illustrating the usage of the Frontend Provisioning API.

Discovering OSGi Devices

The multicast discovery of OSGi devices is a feature specific to the Provisioning Agent. It allows you to discover devices and retrieve information about their host addresses, enabled provisioning schemes and occupied ports. This information can be used for supplying correct registration properties for the devices when you add it to the RM system.
To perform an OSGi device discovery, invoke the discoverGateways(String context, String host, int port, int timeout) method of ProvisioningManager. The arguments taken by this method are:

  • context – Indicates the part of the device management tree whose management servers will participate in the OSGi device discovery. For example, if you supply "ROOT/Sofia", the management server responsible for "ROOT/Sofia/Office1/Accountants" and the MS responsible for "ROOT/Sofia/Office1/Sales" as well as all other MSs responsible for some part of the "ROOT/Sofia" context will perform OSGi device discovery.
  • host and port – Define the multicast address and port (default is 7777) for the discovery. The multicast host and port on which a particular device is joined are specified locally on the OSGi device by means of system properties.
  • timeout – Defines the timeout for the discovery.


Discovering OSGi Devices:

DiscoveredGateway[] discovered = prvMan.discoverGateways("ROOT",
"225.0.0.0",
8888,
500);
System.out.println("Number of successfully discovered devices: " +
discovered.length);



Adding the Retrieved Information to the Device's Registration Properties

The discovery results are returned in the form of a com.prosyst.mprm.admin.provisioning.DiscoveredGateway array. The DiscoveredGateway object provides useful information about the device that will facilitate its registration in the RM system. You can learn about:

  • The device host – This is done through the getAddress() method
  • Is the device managed by an RM system – This can be done using the isManaged() method
  • The device ID – This is done using the getGatewayId() method
  • Is a particular provisioning scheme enabled on the device – This can be done through the isSchemeAllowed(int scheme) method. The scheme argument can be:
  • ProvisioningManager.HTTP for HTTP scheme
  • ProvisioningManager.HTTPS for HTTPS scheme
  • ProvisioningManager.RSH for RSH scheme

This method can help you decide which particular scheme to use for the device's provisioning.

A particular scheme is enabled on the device if the corresponding URL handler is installed in it. The HTTP and the File schemes are always considered enabled (although the File scheme is not commonly used for backend-pushing of provisioning information) as they supported by most JVMs. 

  • The ports occupied by the HTTP and HTTPS servers running on the device- This information helps you establish initial contact with the device over HTTP or HTTPS. It is obtained using the getHttpPort() and getHttpsPort() methods respectively. If no HTTP/HTTPS server is running on the device, the returned port will have value -1.
  • The MS that discovered the device – This is done using the getDiscovererMS() method.

Let's show how the information contained in the discovery results can be used for registering the OSGi device.
In the following listing we shall create a java.util.Hashtable object. Its goal will be to store properties that will be used by the OSGi Device Control API to register the device. After that, in a series of code listings, we shall fill the hashtable with properties obtained through the provisioning API.
The listing shows using the information retrieved during the discovery to add the first part of correct registration properties. In this code example we extract the information about each discovered device from the returned array (see the "Discovering OSGi Devices" listing above), and add it to the device's properties. We need to register only unmanaged devices, so if the device is managed, all other steps are skipped.
This listing adds the following information to the registration properties (com.prosyst.mprm.admin.gateways.RegistrationProperties) of discovered devices:

  • OSGi device host – Added as a value to the RegistrationProperties.GATEWAY_HOST property
  • Initial contact port – Added as a value to the RegistrationProperties.GATEWAY_PORT property. We check if there is an HTTPS Service running on the device, and if it is, set the HTTPS port as a value to this property. Otherwise, the HTTP port is set.
  • Provisioning scheme – Added as a value to the RegistrationProperties.PROVISIONING_SCHEME property. Like with the initial contact, we prefer to use the HTTPS provisioning scheme, so we check if this scheme is enabled on the device. If it is, we set it as a value to this property, otherwise HTTP scheme is set (always considered enabled).


Filling registration properties using the information retrieved during the discovery:

Hashtable regProps = new Hashtable();
System.out.println("Device discovery results:");
for(int i=0; i<discovered.length; i++) {
 
//we shall register only the unmanaged devices
if(!discovered[i].isManaged()) {
//adding the device host to the properties
String host = discovered[i].getAddress();
regProps.put(RegistrationProperties.GATEWAY_HOST, host);
 
/******************** defining the port for initial contact *************/
//checking if the device has an HTTPS server running
// because we want the initial contact to be over HTTPS
String httpsPort = discovered[i].getHttpsPort();
 
if(httpsPort != -1) {
regProps.put(RegistrationProperties.GATEWAY_PORT, httpsPort);
} else {
//if the device has no HTTPS service, HTTP-based initial contact will be used
String httpPort = discovered[i].getHttpPort();
regProps.put(RegistrationProperties.GATEWAY_PORT, httpPort);
}
/********************* end of initial contact part ****************************/
 
/********************* defining the provisioning scheme ***********************/
//checking if HTTPS provisioning scheme is enabled
//because this is our preferred scheme
boolean httpsAllowed = discovered[i].isSchemeAllowed(ProvisioningManager.HTTPS);
 
if(httpsAllowed) {
regProps.put(RegistrationProperties.PROVISIONING_SCHEME, "https");
System.out.println("Device will be registered using https provisioning scheme");
 
} else {
//the HTTP provisioning scheme is always considered enabled
regProps.put(RegistrationProperties.PROVISIONING_SCHEME, "http");
System.out.println("Device will be registered using http provisioning scheme");
}
/******************** end of provisioning scheme defining **********************/
 
. . .//Continue with the filling of registration properties
}
}


Obtaining the Available Optional Features

The list of optional features with which a device can be provisioned changes dynamically depending on the optional feature bundles stored in the Software Repository. For more information about creating an optional feature, refer to Properties for Enabling the Optional Administration Features of RM.
To get the currently available optional features, invoke the getOptionalFeatures() method of ProvisioningManager. This method returns the available features as a Dictionary with the format:
<key_for_the_feature>, <human_readable_name_of_the_feature>
Getting the optional features from the repository:


//Getting all optional features
Dictionary optFeatures = prvMan.getOptionalFeatures();

Adding the Found Optional Features to the Device's Registration Properties

The feature key (<key_for_the_feature>) can be used as the name to a property added to the provisioning Dictionary of OSGi devices. If the value of this property is set to "true", the agent bundle corresponding to this property will be activated on the device during the provisioning. If set to "false" or unavailable, the corresponding optional feature will not be activated on the device.
We shall illustrate the above explanation with a code listing adding the obtained optional features (as in the above listing "Getting the optional features from the repository") to the registration properties stored in the regProps hashtable. Note that in the following listing the feature keys are added to the hashtable, not the feature names. The feature names are only user-friendly descriptions of the optional features, so we shall only print them in the system output to show the list of available features found.
Adding the optional feature keys to the registration properties:


/* Retrieving the information from the optFeatures Dictionary
* and adding it to the registration properties of the device */
Enumeration el = optFeatures.keys();
System.out.println("Optional features available:");
while(el.hasMoreElements()) {
String key = (String) el.nextElement();
String value = (String) optFeatures.get(key);
//Adding the feature keys to the device registration props
regProps.put(key, "true");
//Printing the feature descriptions
System.out.println(value);
}


When you have added all necessary properties to the regProps hashtable, pass the regProps object to the registerOSGiDevice method of the OSGi Device Manager service. For more information refer to OSGi Device Manager API.

Creating a Custom Provisioning Agent

The Provisioning API allows you to create a custom provisioning agent supplied with all necessary properties for the management of the device through RM. A custom agent created through this API has the following features:

  • It can be used on a device based on any of the currently available releases of the OSGi Service Platform Specification (1.0, 2.0, 3.0 and 4.0)
  • It contains two types of provisioning info providers: File Info Provider and Environment Info Provider. This means that the provisioning agent can accept provisioning properties passed as text available in a props.txt file in the agent's JAR file, and as system properties
  • The properties supplied to the provisioning agent will be stored in the props.txt file in the agent's JAR file

A provisioning agent created in this way must be delivered and activated on the target OSGi device in a non-RM way. 


To create a custom provisioning agent, invoke the createProvisioningAgent(String provisioningUrl, Dictionary regProps, String[] includeX509RootCerts) method of the ProvisioningManager object. The method's arguments are:

  • provisioningUrl – The backend URL from which the device will be able to download the RM agents. This argument actually determines the value of the provisioning.reference property. See Initial Provisioning: Provisioning Properties for details about the syntax of this URL.

  • regProps – The provisioning properties that will be stored in the provisioning agent

  • includeX509RootCerts – The certificates unique names (as they are into Certificate Manager) that are to be set into provisioning Dictionary as ProvisioningService.PROVISIONING_ROOTX509.

The following listing illustrates creating a provisioning agent with all properties we have added in the previous examples. We shall reuse the same regProps object we have filled with properties before. The first argument of createProvisioningAgent, the provisioning URL, is constructed by concatenating the MS host, MS's HTTP port and the provisioning alias (/prvsetup).

Creating a custom provisioning agent:

InputStream is = prvMan.createProvisioningAgent("http://remote.psb:"/*the MS host*/ +
prvMan.getHttpPort("myHostId")/*the HTTP port used by the MS*/ +
"/prvsetup",/*the provisioning alias*/
regProps,/*the registration props*/
new String[] {"mPRM_Cert"});
 
/*Saving the provisioning agent as a JAR file*/
FileOutputStream fos = new FileOutputStream("myProvAgent.jar");
byte[] buff = new byte[1024];
int count = is.read(buff);
while (count != -1) {
fos.write(buff, 0, count);
count = is.read(buff);
}
fos.close();
is.close();



OSGi Device Provisioning API

The OSGi Device Provisioning API is placed in the com.prosyst.mprm.gateway.provisioning package. It allows creating two Bosch Digital-specific OSGi device components: provisioning info providers and Provisioning Storages. Their goal is to provide provisioning information to the Provisioning Service on the device side.

Creating a Provisioning Info Provider


A provisioning info provider must implement the com.prosyst.mprm.gateway.provisioning.ProvisioningInfoProvider interface. After that, if the provider will be packed in a bundle other than the provisioning agent, the provider implementation must be registered as an OSGi service. If the provider will be packed in the default Bosch Digital provisioning agent, then it must be specified in the Prv-Providers manifest header, see Packing the Provisioning Info Provider Inside the Provisioning Agent.

The init(ProvisioningService prvServ) method of the ProvisioningInfoProvider interface is invoked by the Provisioning Service when this provider is registered. It should return a Dictionary object holding all properties defined by this provider.

The following listing shows the implementation of the init method. It provides provisioning properties only when the smart card is inserted (i.e. when the File Access Card service is registered), and reads them from the smart card. If no smart card is available, no properties are pushed.

The init method implementation in the Provisioning Demo:

. . .
 
/**
* If there are read properties they are returned to the provisioning service
* (who is the one that invokes this method) and provisioning service adds
* the properties into Provisioning Data dictionary.
*/
public Dictionary init(ProvisioningService prvService) throws Exception {
Dictionary props = cardServiceRegistered();
print("FlashCard data:\n" + props);
return props;
}
. . .
private Dictionary cardServiceRegistered() {
try {
ServiceReference ref = bc.getServiceReference(FileAccessCardService.class.getName());
if (ref != null) {
FileAccessCardService card = (FileAccessCardService)bc.getService(ref);
CardFile file = new CardFile(card, configFilePath);
byte[] data = card.read(configFilePath, 0, file.getLength());
Properties config = new Properties();
config.load(new ByteArrayInputStream(data));
 
try {
bc.ungetService(ref);
} catch (Exception e) {
print(e);
}
return config;
}
} catch (Exception e) {
print(e);
}
return null;
}
 
. . .


The get(Object propertyKey) method is invoked by the Provisioning Service if someone has queried about the value of a property that is not stored in the provisioning Dictionary. 

Packing the Provisioning Info Provider Inside the Provisioning Agent


If you want to add new internal provisioning info providers wrapped in the Provisioning Agent, you must edit the PrvInfo-Providers header of the Provisioning Agent bundle's manifest. This header determines the provider ranking in case more than one provider service is available in the framework. The default priority of the provisioning info provider could be changed by editing the value of this header. The syntax of the PrvInfo-Providers header is:

PrvInfo-Providers: <configuration_provider_implementation>;<provider_ranking>[,<configuration_provider_implementation>;<provider_ranking>]

Where <configuration_provider_implementation> is the Java class name of the com.BoschSI.mprm.gateway.provisioning.ProvisioningInfoProvider implementation. The same class must also implement org.osgi.framework.BundleActivator and must provide a public constructor having no arguments..

The <provider_ranking> part is the ranking (weight) of the provider service. The <provider_ranking> part reflects the "service.ranking" property of OSGi services with which the provider is registered. It determines the way in which the values of provisioning properties will be defined if two or more providers declare different values. For providers installed before the Provisioning Agent, the rule is this: the values of the properties provided by the provider with the higher ranking override the values of those exported by a provider with lower ranking. After the installation of the Provisioning Agent, the values available in a newly installed provider override the ones available in older ones. Therefore, each new provider overrides the property values of the previously installed providers, no matter their ranking.


Creating a Provisioning Storage

The goal of a provisioning storage, as its name suggests, is to store persistently the provisioning properties so that they will be available even after restart of the device. The Provisioning Service can use only one storage at a time. First it searches for built-in storages and, if there aren't such, searches for external ones in the framework. It picks up the first one it finds and uses it until it is unregistered. So, if you want the Provisioning Service to use your custom storage, make sure all other concurrent storages are eliminated.
To create a custom storage, implement the com.prosyst.mprm.gateway.provisioning.ProvisioningStorage interface, and register it as a service or set it as a value to the Prv-Storage manifest header of the provisioning agent.
The getStoredInfo() method is invoked by the Provisioning Service to collect all stored properties. This is done the first time it starts using this provider and each time the Provisioning Service starts up.
The store(Dictionary provisioningData) method is invoked when new provisioning data is to be stored by the Provisioning Service.

Packing the Custom Provisioning Storage Inside the Provisioning Agent

If you want to change the provisioning storage wrapped in the Provisioning Agent, change the value of the Prv-Storage header in its manifest. The format of the header is:
Prv-Storage: <configuration_storage_implementation>
Where <configuration_storage_implementation> must point to the Java class name of the desired com.prosyst.mprm.gateway.provisioning.ProvisioningStorage implementation. The same class must also implement org.osgi.framework.BundleActivator and must provide a public constructor having no arguments.
If you want to provide custom storage implementation that is not packed in the Provisioning Agent bundle, you do NOT need to include the Prv-Storage header. It is enough to export a service that publishes the ProvisioningStorage interface.

Packing a URL Handler in the Provisioning Agent


If you re-pack the Provisioning Agent bundle adding the components from a URL handler bundle to it, you will automatically provide support for the corresponding scheme when the Provisioning Agent is activated. Additionally, you have to add the following header in the Provisioning Agent's manifest:

URL-Handlers: <URL_handler_implementation>[,<URL_handler_implementation>]

Where <URL_handler_implementation> is the Java class name of the internal URL handler's org.osgi.framework.BundleActivator implementation. Note, that the <URL_handler_implementation> Java class must also provide a public constructor having no arguments. Multiple handler entries are separated by commas.