The OSGi Device Provisioning API is hold in the com.prosyst.mprm.gateway.provisioning package. It allows creating two OSGi device components: provisioning info providers and provisioning storages. Their goal is to provide provisioning information to the Provisioning Service on the device.
Creating Provisioning Info Providers
A provisioning info provider must implement the com.prosyst.mprm.gateway.provisioning.ProvisioningInfoProvider interface. Then, the info provider can be deployed as a service in the OSGi framework in two ways:
Implement the Provisioning Info Provider
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.
If you intend to pack the info provider within the Initial Provisioning bundle, the class implementing ProvisioningInfoProvider should implement org.osgi.framework.BundleActivator as well, as the provisioning agent will call the start and stop methods inherited from BundleActivator.
Listing 1 shows the implementation of the init method, reading provisioning properties from a smart card. 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.
Listing 1. The init method implementation in the Provisioning Demo
import java.util.*;
import import java.io.ByteArrayInputStream;
import org.osgi.framework.*;
import com.prosyst.mprm.gateway.provisioning.ProvisioningInfoProvider;
import com.prosyst.mprm.gateway.provisioning.ProvisioningInfoProvider;
import opencard.opt.iso.fs.FileAccessCardService;
import opencard.opt.iso.fs.CardFilePath;
import opencard.opt.iso.fs.CardFile;
. . .
private CardFilePath configFilePath = new CardFilePath( ":3f00:0815:0817");
/**
* 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 in the Provisioning Agent bundle's manifest. As a result, the provisioning agent will register the providers from the headers as services in the OSGi framework.
The PrvInfo-Providers 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 as follows:
PrvInfo-Providers: <info_provider_impl>;<provider_ranking>[,<info_provider_impl>;<provider_ranking>]
where:
Creating Provisioning Storages
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 deploy it in one of the following ways:
See "Packing the Custom Provisioning Storage" below for more information.
Implement the Provisioning Storage
The getStoredInfo() method is invoked by the Provisioning Service to collect all stored properties. This is done the first time it starts using this storage 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.
If you are going to pack the storage inside the Initial Provisioning bundle, the class implementing ProvisioningStorage must also implement org.osgi.framework.BundleActivator. The provisioning agent will call the start and stop methods inherited from BundleActivator to activate and deactivate the operation of the storage.
Packing the Custom Provisioning Storage
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 as follows:
Prv-Storage: <storage_implementation>
Where <storage_implementation> must point to the Java class name of the desired ProvisioningStorage implementation.
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.