This document contains a programmer's guide to managing software components and their characteristics through the Front-end Software Repository API.

It is represented by the com.prosyst.mprm.admin.softrepository and com.prosyst.mprm.admin.softrepository.task packages.

Overview

The Software Repository provides an easy-to-use API for managing different file types and their characteristics.

Deployment units in the Software Repository are represented by com.prosyst.mprm.admin.softrepository.ClientBundle objects. You can use a ClientBundle object to add resources to it and manage its general characteristics.

Adding, Removing and Updating Deployment Units

A deployment unit represents a collection of client bundles in the Software Repository and it exists only if it has at least one client bundle.

To place a client bundle in the repository, your application can use the two-phase import process that consists of the following steps:

  1. Identification – Open the client bundle file by using the openBundleFile(InputStream is, Dictionary data) method of the ImportSession. The arguments passed to this method are:
    • is – The input stream to the client bundle.

    • data – The Dictionary of all known properties that describe the software artifact represented by the input stream. It may contain the following properties:

      • SoftwareRepository.FILE_TYPE – Indicates the file format of the client bundle. The property values can be a String. The Software Repository uses the value of this property to find the appropriate ImportFileHandler that will be able to handle this file. If the Dictionary does not contain such property all handlers are taken into consideration.

      • SoftwareRepository.FILE_NAME – Indicates the name of the deployment unit. It takes a String value. This property is used to extract the file extension from the name of the deployment unit and use it to find the proper ImportFileHandler.

        If the client bundle location is correct, the method returns a file identifier with a long value. Next, retrieve the client bundles as com.prosyst.mprm.admin.softrepository.IdentifiedBundleInfo instances by using the identifyBundles method of ImportSession, call the getReports method of the returned RepositoryTask object with argument -1. The getReports method will return relevant BundleReport objects. For each BundleReport invoke the getClientBundle method, cast it to IdentifiedBundleInfo and copy the IdentifiedBundleInfo object into a IdentifiedBundleInfo[] as shown in the listing below. 

  2. Processing – Add the identified client bundles to the Software Repository by invoking the importBundles(IdentifiedBundleInfo[] identifiedInfo) method of the ImportSession interface which takes as parameters the identifiedInfo retrieved in the first step. This method returns a RepositoryTask instance that may be used to monitor the process of importing. In order to obtain notifications for the importing process, the application should implement and register a TaskListener service interface. 

    Following is an example of developing an application that adds a new client bundle to the Software Repository. 

    import java.io.FileInputStream;
    import java.util.Dictionary;
    import java.util.Hashtable;
     
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceReference;
    import com.prosyst.mprm.admin.softrepository.ClientBundle;
    import com.prosyst.mprm.admin.softrepository.IdentifiedBundleInfo;
    import com.prosyst.mprm.admin.softrepository.ImportSession;
    import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
    import com.prosyst.mprm.admin.softrepository.SoftwareRepositoryException;
    import com.prosyst.mprm.admin.softrepository.task.RepositoryTask;
     
    public class ClientBundleTest implements BundleActivator{
     
    ClientBundle bundle = null;
    SoftwareRepository srep = null;
    ServiceReference srepRef = null;
    FileInputStream inputStream = null;
    String bundle_to_add = "D:/Job_Programming/mybundle.jar";
    ImportSession session = null;
    RepositoryTask task_import = null;
    public void start(BundleContext bc) throws Exception {
     
    // Retrieve the Software Repository as an OSGi service from the framework
    srepRef = bc.getServiceReference(SoftwareRepository.class.getName());
    if (srepRef != null) {
    srep = (SoftwareRepository) bc.getService(srepRef);
    }
    // Use the Software Repository to obtain a new Import Session
    // instance
    session = srep.getImportSession();
    // Setting properties that will be used during client bundle
    // identification
    Dictionary data = new Hashtable();
    data.put(SoftwareRepository.FILE_NAME, "mybundle.jar");
    data.put(SoftwareRepository.FILE_TYPE, "OSGi Bundle");
    inputStream = new FileInputStream(bundle_to_add);
     
    try {
    // Identifying the client bundle represented by the
    // input stream by using the available data
    session.openBundleFile(inputStream, data);
    RepositoryTask task = session.identifyBundles();
    BundleReport reports[] = task.getReports(-1);
    IdentifiedBundleInfo[] bundles = new IdentifiedBundleInfo[reports.length];
    for(int i = 0; i < reports.length; i++) {
    bundles[i] = (IdentifiedBundleInfo) reports[i].getBundle();
    }
    // Adding the client bundle to the Software Repository database
    session.importBundles(bundles);
     
    } catch (SoftwareRepositoryException sre) {
    sre.printStackTrace();
    }
    }
    public void stop(BundleContext bc) throws Exception {
     
    // Releasing all used resources
    if (srepRef != null) {
    bc.ungetService(srepRef);
    }
    }
    }

The Software Repository provides the developer with an opportunity to import client bundles using a one-phase process. It is characterized by the direct import of a specific client bundle to the repository. The registered Software Repository Content Plug-ins assign the imported client bundles their global and content IDs, version and concrete type.

To add a client bundle to the repository using the one-phase process, call the importBundles(InputStream is, Dictionary data) method of the Software Repository for asynchronous import or the importBundlesSync(InputStream is, Dictionary data) one for synchronous import. Both take as parameters the InputStream that is used to read the client bundles and the Dictionary holding general information about their characteristics. The properties which can be placed in the dictionary are:

  • SoftwareRepository.FILE_NAME – Indicates the name of the imported file. It is used to extract the file extension which is needed to find the proper Content Plug-ins for handling the file content.
  • SoftwareRepository.FILE_TYPE – Indicates the file type of the imported client bundle which is used for searching Content Plug-ins registered with such a property.
  • SoftwareRepository.CONCRETE_BUNDLE_TYPE – Indicates the concrete client bundle type and is used to discover the Content Plug-ins registered to handle software components with such concrete type.
  • SoftwareRepository.GENERAL_BUNDLE_TYPE – Indicates the general client bundle type and is used to find the registered Content Plug-ins which can process the specific client bundle.
  • SoftwareRepository.UPDATE_BUNDLE – Indicates how the specific client bundle should replace an existing one in the repository that has the same content ID. In case this property is not included in the Dictionary, the Software Repository imports the client bundle as a new deployment unit. This property can have the following values:
    • SoftwareRepository.ALL_VERSIONS – All client bundles having the same content ID must be replaced with the current software components.
    • SoftwareRepository.SAME_VERSION – Only client bundles having the same version and content ID must be replaced with the current client bundles.
    • SoftwareRepository.SMALLER_VERSION – Only deployment units having lower versions than the imported client bundles and the same content ID, must be replaced.

After the import process completes the Software Repository will save persistently the information received for the client bundle during the importing as well as its file content.

To remove a client bundle from the Software Repository, use the deleteBundle(String bundleId, boolean deleteAnyway, boolean deleteOwnComponents) method of the SoftwareRepository interface for asynchronous removal and deleteBundleSync(String bundleId, boolean deleteAnyway, boolean deleteOwnComponents) to do it in synchronous way. The methods take the following parameters:

  • bundleId – The identifier of the client bundle to be deleted.
  • deleteAnyway – A flag indicating when false that a notification about the deleting of the client bundle is sent to the user and no further action will be taken until the user's response is received. Otherwise, the selected client bundle is deleted and a warning is sent. This flag is considered only if the client bundle is a member of a composition or it is of interest to some other bundle.
  • deleteOwnComponents – A flag indicating when true that in case the client bundle represents a composition, all its components which do not participate in other compositions, are removed from the repository. Otherwise, only the composite client bundle is removed.

Using Basic Deployment Unit Properties

This part of the document contains guidelines for accessing the basic deployment unit properties.

Display Name and Vendor

Invoke the getDisplayName(Locale locale) or getVendor(Locale locale) methods to retrieve the display name and vendor of specific client bundle with the specified locale.

Global ID and Version

The Software Repository offers methods for getting the global identifier and the version of a specified client bundle. Client bundles with the same concrete type, global ID and version cannot exist at the same time in the Software Repository. Use the getGlobalId() and getVersion() methods on the desired ClientBundle instance.

Concrete Type

To get the Concrete Type of particular client bundle, use the getConcreteType() method on the corresponding software component. In case you want to obtain all available Concrete Type in the Software Repository, call the getConcreteTypes() method of the Software Repository interface.

State and Upload Time

You can get the state and upload time of a deployment unit by using the getState() and getUploadTime() methods on a particular ClientBundle object.

Managing Client Bundle Custom Properties

Client bundles having specific concrete type can have custom properties which are described through the "Control Unit" abstraction. For more information about the Control Unit concept refer to the Bosch IoT Gateway Software documentation. .

The Software Repository provides the getRootCUType() method for retrieving the parent control unit type for a given concrete type. Using the Control Unit API child control units can be managed.

Following is an example of how to list the child control units representing the custom properties of all client bundles with "OSGi Bundle" concrete type.

import org.mbs.services.cu.ControlUnitAdmin;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
 
import com.prosyst.mprm.admin.softrepository.ConcreteBundleType;
import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
 
 
public class CustomPropertiesManagement implements BundleActivator {
 
ControlUnitAdmin cuAdmin;
ServiceReference cuAdminRef;
 
ServiceReference srRef;
SoftwareRepository sr;
 
// Method inherited from BundleActivator
public void start(BundleContext bc) throws Exception {
 
// Retrieve the ControlUnitAdmin service from the OSGi framework
cuAdminRef = bc.getServiceReference(ControlUnitAdmin.class.getName());
if (cuAdminRef != null) {
cuAdmin = (ControlUnitAdmin) bc.getService(cuAdminRef);
}
 
// Retrieve the SoftwareRepository service from the OSGi framework
srRef = bc.getServiceReference(SoftwareRepository.class.getName());
if (srRef != null) {
sr = (SoftwareRepository) bc.getService(srRef);
}
 
ConcreteBundleType concreteType = sr.getConcreteBundleType("OSGi Bundle");
// Retrieve and print the parent control unit for the "OSGi Bundle" concrete type
String cuRoot = concreteType.getRootCUType();
System.out.println("Root CU type is : " + cuRoot);
String[] subCus = cuAdmin.getSubControlUnitTypes(cuRoot);
// Retrieve and print all defined child control unit types for the parent control unit
System.out.println("Component CU types are : ");
for (int a = 0; subCus != null && a < subCus.length; a++) {
System.out.println(subCus[a] + "\n");
}
}
 
// Method inherited from BundleActivator
public void stop(BundleContext bc) throws Exception {
if (cuAdminRef != null) {
bc.ungetService(cuAdminRef);
cuAdminRef = null;
}
cuAdmin = null;
if (srRef != null) {
bc.ungetService(srRef);
srRef = null;
}
sr = null;
}
}

Managing Required Capabilities

Required capabilities are among the main software component attributes provided by the Software Repository. They are used to find the most suitable software component for a specific device. The Platform Profile Manager module is responsible for the matching of the client bundle requirements to the capabilities offered by the client device. This is acquired by comparing their values.

To get the available required capabilities names, call the getRequirementNames() method on the ClientBundle instance. It returns a Set containing all requirement property names available for the client bundle. Invoke the getRequirement(String name) method on the corresponding requirement property name, to retrieve its values. The method returns a List object.

The Software Repository presents two methods for setting required capabilities of a specific client bundle:

  • setRequirement(String name, List requirements) – Adds a new pair of required capabilities to the existing ones with a name property and a list of requirements values. In case the requirement property already exists and the list of requirements contains different values, the existing requirement values are replaced with this list.
  • setRequirements(Dictionary requirements) – Replaces the existing requirement pairs with the provided requirements. The keys of the Dictionary are strings representing the requirements' names and the values are Lists containing the requirement capability values.

The following source example sets a required capability to the client bundle added to the Software Repository in the first example by replacing the existing required capabilities (if any). 

import java.util.*;
import org.osgi.framework.*;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.prosyst.mprm.admin.softrepository.ClientBundle;
import com.prosyst.mprm.admin.softrepository.ImportSession;
import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
import com.prosyst.mprm.admin.softrepository.SoftwareRepositoryException;
import com.prosyst.mprm.admin.softrepository.task.RepositoryTask;
import com.prosyst.mprm.data.Enumerator;
 
public class RequiredCapabilitiesTest implements BundleActivator {
 
ClientBundle myBundle = null;
SoftwareRepository srep = null;
ServiceReference srepRef = null;
 
public void start(BundleContext bc) throws Exception {
 
// Retrieve the Software Repository
...
// Get the client bundle installed in the first listing.
Enumerator client_bundles = srep.listBundles("OSGi Bundle");
while (client_bundles.hasMoreElements()) {
myBundle = (ClientBundle) client_bundles.nextElement();
if (myBundle.getGlobalId().equals("My Client Bundle")) {
// Invoke the begin() method that signals about forthcoming
// changes in the corresponding client bundle and saves them
// in the local storage
myBundle.begin();
// Storing the new requirement and its values in a Dictionary
String req_property = "My Requirement";
String[] req_values = { "value_1", "value_2", "value_3" };
List list_req_values = Arrays.asList(req_values);
// Setting a new requirement to the client bundle
myBundle.setRequirement(req_property, list_req_values);
// Invoke the commit() method to save the changes
// in the database
myBundle.commit();
}
}
}
public void stop(BundleContext bc) throws Exception {
 
// Releasing all used resources
...
}
}

To remove a single required capability, call the removeRequirement(String name) method on the desired client bundle passing the name of the requirement to be removed.

To remove required capabilities of a specific client bundle, use the setRequirements(Dictionary requirements) method passing a null parameter.

For more information about the Platform Profile Manager, refer to the system architecture section in the Basic Principles of the Software Repository guide and to the Device Platform Capabilities conceptual guide.

Managing Dependencies

The Software Repository is able to resolve the dependencies of specific client bundles prior to their delivering and installation on a client device. This is acquired by taking into account the platform requirements of the client bundle.

Device Capabilities

To get the capabilities which a client bundle adds to the existing device capabilities, call the getCapabilities() method on a ClientBundle instance. The method returns a javax.provisioning.Capabilities instance which can be used to retrieve the names of the existing capabilities and their values.

To edit client bundle capabilities, use one of the following methods:

  • setCapabilities(Dictionary capabilities) – Replaces the existing capabilities with new pairs. In the java.util.Dictionary parameter place a String capability name and a List containing the capability values.
  • setCapability(String name, List capability) – Adds a new capability value to an existing client bundle capability.


Use the setCapabilities(Dictionary capabilities) method passing null as parameter to remove the available capabilities of a specific client bundle. In case you want to remove a single capability, invoke the removeCapability(String name) method passing the name of the desired client bundle capability.

Dependencies Resolving

You can use the functionality of the Software Repository to resolve the dependencies of a specific software component. There are two groups of methods related to dependencies resolution.

The first type of methods resolves dependencies and return a ClientBundle[] containing client bundles suitable for the specified device capabilities:

  • resolveDependencies(String[] contentIds, javax.provisioning.Capabilities capabilities)

  • resolveDependencies(String[] contentIds, javax.provisioning.Capabilities capabilities, List matchPolicies)

  • resolveDependencies(String[] bundleIds, javax.provisioning.Capabilities capabilities, String[] allowedTypes, String[] allowedBundleIDs)

The methods for resolving dependencies return a ClientBundle[] object which elements answer the following search criteria provided as method arguments:

  • String[] bundleIds – The client bundle identifiers of the deployment units which dependencies are resolved. In case this argument is null or an empty array, the resolving process is suspended and an empty ClientBundle[] is returned.

  • String[] contentIds – The content IDs of the software components which dependencies are resolved. If the parameter is null or an empty array, further actions are aborted and an empty ClientBundle[] is returned.

  • javax.provisioning.Capabilities capabilities – The device capabilities that the client bundles must satisfy.

  • List matchPolicies – The discovered set of client bundles is further filtered by using a list containing javax.provisioing.MatchPolicy objects (see the JSR 124, J2EE Client Provisioning specification for more information about the MatchPolicy interface), com.prosyst.mprm.backend.softrepository.CompatibilityPolicy or com.prosyst.mprm.backend.softrepository.VersionComparePolicy objects (see the next chapter for more information on using the CompatibilityPolicy and the VersionComparePolicy interfaces). Can be null.

  • String[] allowedTypes – The concrete client bundle types that must be taken into consideration during the dependency resolving.

  • String[] allowedBundleIDs – The search area in the Software Repository is restricted to software components that have unique client bundle identifiers which can be found among the elements of this parameter.

The following couple of examples shows the basic steps that need to be taken in order to use one of the resolving characteristic of the Software Repository. The first one contains a simple implementation of the javax.provisioning.Capabilities interface which is passed as parameter in the resolveDependencies(String[] contentIds, javax.provisioning.Capabilities capabilities) method which is shown in the second one.

import java.util.*;
import javax.provisioning.Capabilities;
 
public class CapabilitiesImpl implements Capabilities {
 
private Dictionary caps;
CapabilitiesImpl(Dictionary caps) {
this.caps = caps;
if (this.caps == null) {
this.caps = new Hashtable(0);
}
ArrayList v = new ArrayList();
v.add("JDK_1.1.8");
v.add("JDK_1.2.2");
v.add("OSGi/Minimum-1.0");
this.caps.put("SoftwarePlatform.EE", v); }
public List getCapability(String name) {
return (List)caps.get(name);
}
public Set getCapabilityNames() {
HashSet set = new HashSet();
for (Enumeration e = caps.keys(); e.hasMoreElements();) {
set.add(e.nextElement());
}
return set;
}
}

The following example uses resolveDependencies(String[] contentIds, javax.provisioning.Capabilities capabilities) method for the resolving of the client bundle dependencies with parameter from the example above . 

import java.util.*;
import javax.provisioning.Capabilities;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.prosyst.mprm.admin.softrepository.ClientBundle;
import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
 
public class DependenciesResolvingTest implements BundleActivator {
 
SoftwareRepository sr = null;
ServiceReference srRef = null;
 
public void start(BundleContext bc) throws Exception {
 
srRef = bc.getServiceReference(SoftwareRepository.class.getName());
if (srRef != null) {
sr = (SoftwareRepository) bc.getService(srRef);
}
ArrayList service = new ArrayList();
service.add("com.acme.package1");
service.add("com.acme.package2");
Dictionary dict = new Hashtable();
dict.put("SoftwarePlatform.Package", service);
 
Capabilities caps = new CapabilitiesImpl(dict);
ClientBundle[] bundles = sr.resolveDependencies(
new String[] { "lamp.currentstate.notifier" }, caps);
for (int a = 0; a < bundles.length; a++) {
System.out.println(" The client bundles that satisfy the device
capabilities have the following bundle ids: \n "
+ bundles[a].getBundleID());
}
}
public void stop(BundleContext bc) throws Exception {
 
bc.ungetService(srRef);
}
}

The second group of dependencies resolution methods return a com.prosyst.mprm.admin.softrepository.resolve.ResolutionResult object containing the full resolve graph for the specified device capabilities:

  • resolveDependencies(String[] bundleIds, Capabilities capabilities, String[] allowedTypes, String[] allowedBundleIDs, int maxResults)

  • resolveRequirements(ClientBundleRequirement[] requirements, Capabilities  incompatibles, Capabilities capabilities, String[] allowedTypes, String[] allowedBundleIDs, int maxResults)

The resolveDependencies above returns a ResolutionResult object whose elements answer the following search criteria provided as method arguments:

  • String[] bundleIds – The client bundle identifiers of the deployment units which dependencies are resolved. In case this argument is null or an empty array, the resolving process is suspended and an empty ClientBundle[] is returned.

  • String[] contentIds – The content IDs of the software components which dependencies are resolved. If the parameter is null or an empty array, further actions are aborted and an empty ClientBundle[] is returned.

  • javax.provisioning.Capabilities capabilities – The device capabilities that the client bundles must satisfy.

  • String[] allowedTypes – The concrete client bundle types that must be taken into consideration during the dependency resolving.

  • String[] allowedBundleIDs – The search area in the Software Repository is restricted to software components that have unique client bundle identifiers which can be found among the elements of this parameter.

  • int maxResults – The greatest number of resolved client bundles to return.

The resolveRequirements method provides a more convenient manner for resolving dependencies - using it will skip getting the requirements of specified client bundles. The method takes as an input argument directly the definition of client bundle requirements as a com.prosyst.mprm.admin.softrepository.ClientBundleRequirement[] object.

Requirement resolution for the resolveRequirements method is executed according to the following criteria:

  • ClientBundleRequirement requirements – The requirements which are resolved. If it is null or empty array, no resolving is made and an empty array is returned.

  • Capabilities incompatibles – The incompatibility requirements that must not be matched by the returned set. May be null.

  • Capabilities capabilities – The capabilities of the client device the found client bundles must satisfy.

  • String[] allowedTypes The concrete client bundle types that are allowed to be used taken into consideration during the requirements resolving. If it is null , no concrete type filtering is made.

  • String[] allowedBundleIDs – The search area in the Software Repository is restricted to software components that have unique client bundle identifiers which can be found among the elements of this parameter.

  • int maxResults – The greatest number of resolved client bundles to return.


Calling the methods of the ResolutionResult object will allow you to retrieve the requirements and client bundles participating in the resolution operation. The dependencies resolution result components are defined in the com.prosyst.mprm.admin.softrepository.resolve package.

Customizing the Resolving Process

Optionally, you can benefit from the Software Repository API by implementing the com.prosyst.mprm.backend.softrepository.CompatibilityPolicy interface and therefore extending the filtering options of the repository used for resolving client bundles dependencies. This interface participates in the resolving dependencies process. The CompatibilityPolicy can be registered as a service in the framework or used directly as an argument in the "resolve method" of the Software Repository. It has only one method – isCompatible(ClientBundle bundle, List currentBundles, javax.provisioning.Capabilities deviceCapabilities) which takes as arguments the currently examined bundle, a List of all bundles found until now which match the capabilities of the device and the deviceCapabilities. For example, an application can register an implementation of the CompatibilityPolicy interface which forbids the Software Repository to return client bundles which match the deviceCapabilities but have the same content id and version.

The example below provides a simple implementation of the isCompatible method, which is used to find the most suitable software components excluding the ones with the same provided capabilities.

import java.util.List;
import javax.provisioning.Capabilities;
import com.prosyst.mprm.admin.softrepository.ClientBundle;
import com.prosyst.mprm.admin.softrepository.SoftwareRepositoryException;
import com.prosyst.mprm.backend.softrepository.CompatibilityPolicy;
 
public class CompatibilityPolicyImplementation implements CompatibilityPolicy {
 
public boolean isCompatible(ClientBundle bundle, List currentBundles,
Capabilities deviceCapabilities) {
 
if (bundle == null || currentBundles == null || currentBundles.size() == 0) {
return true;
}
 
for (int i = 0; i < currentBundles.size(); i++) {
ClientBundle next = (ClientBundle) currentBundles.get(i);
if (next == null) {
continue;
}
 
try {
if (!bundle.getCapabilities().equals(next.getCapabilities())){
 
return false;
}
} catch (SoftwareRepositoryException sre) {
sre.printStackTrace();
}
}
return true;
}
}

Two client bundles having specific concrete type can be compared using the com.prosyst.mprm.backend.softrepository.VersionComparePolicy interface. It extends the java.util.Comparator interface. Developers wishing to customize the policy for comparing client bundle versions should implement its compare(Object o1, Object o2) method. The implementation can be registered as a service in the OSGi framework with registration property VersionComparePolicy.VERSION_COMPARE_ALGORYTHM.

The versions of two client bundles can be compared by the repository in the following cases:

  • During the resolving process, if the requirements of both client bundles match to the same extent the device capabilities. The deployment unit with the highest version is chosen.
  • During the import process, if the SoftwareRepository.UPDATE_BUNDLE property is placed in the dictionary argument of the importBundles(InputStream is, Dictionary data) method with value SoftwareRepository.SMALLER_VERSION or SoftwareRepository.SAME_VERSION.


In the presence of one of these conditions, the repository checks whether the concrete type of the client bundles is provided with the ConcreteBundleType.VERSION_COMPARE_ALGORYTHM property. In case such property is available, the Software Repository tries to find the VersionComparePolicy services registered with the same value of the registration property.

Furthermore, the implementation of the VersionComparePolicy interface can be directly passed as an argument to the resolveDependencies()  method. The algorithms for version comparison provided in such a way have priority over the ones provided by the registered in the framework service implementations (if any). If more than one VersionComparePolicy implementations are passed to the resolve method, the first found policy is taken into consideration.

Querying for Deployment Units

The Software Repository API provides convenient methods for getting deployment units matching specific search criteria. Depending on the client bundle characteristics, use one of the following methods:

  • getBundle(String concreteType, String globalId, String version) – The repository is searched for deployment units having such concreteType, globalId and version. Only one ClientBundle satisfying these criteria can exist.

  • getBundles(String concreteTypeName, String contentID, String globalID) – A ClientBundle[] object is returned containing software components having the concreteTypeName, contentID and globalID general characteristics. In case any of the parameters is null, it is not taken into consideration during the search.

  • getBundles(String concreteTypeName, long parFileId) – All client bundles having the concreteTypeName concrete type and parFileId, specifying their belonging to Provisioning ARchive (PAR) file are returned.

Creating Client Bundles

By using the Software Repository API you can create a new client bundle, in case its concrete type is provided with the ConcreteBundleType.USER_CREATBLE property with value true. If the concrete type is a composite one and the described property is available, the deployment unit is considered a composition. Then it can be cast to the com.prosyst.mprm.admin.softrepository.Composition interface and different components can be added to it. Those components can have additional characteristics valid only when they are considered as parts of such deployment unit.

Call the createClientBundle(String concreteTypeName, String contentId, String globalId, String version) method of the Software Repository to create a new client bundle and add it to the repository database. The method takes the following parameters:

  • concreteTypeName – The concrete type name of the new deployment unit. The value cannot be null.
  • contentId – The logical identifier of the client bundle content. It cannot be null.
  • globalId – An optional parameter representing the global identifier of the deployment unit.
  • version – An optional argument representing the version of the client bundle. In case it is not specified, the repository considers that it has the lowest version among all existing client bundles.

Listening for Client Bundle-Specific Events

The Software Repository API allows you to add listeners to monitor the changes concerning adding, deleting and modifying its components by using the com.prosyst.mprm.admin.softrepository.SoftwareRepositoryListener interface. Developers interested in notifications about the state of the processes currently running in the repository can use the com.prosyst.mprm.admin.softrepository.task.TaskListener interface.

Software Repository Listener

Software Repository listeners listen for newly added or removed software components or other changes in the structure of the repository. To be able to take advantage of their features, implement the SoftwareRepositoryListener interface and invoke the addRepositoryListener(SoftwareRepositoryListener  listener) method of the SoftwareRepository. The method takes as parameter your implementation of the SoftwareRepositoryListener instance that will receive repository events.

SoftwareRepositoryListener has three methods invoked by the SoftwareRepository when the corresponding event type occurs:

  • bundleEvent(ClientBundleEvent  event) – Invoked by the repository due to a change in the lifecycle of a deployment unit, represented by a com.prosyst.mprm.admin.softrepository.ClientBundleEvent. Received events can be of type:
    • ClientBundleEvent.CLIENT_BUNDLE_CHANGED
    • ClientBundleEvent.CLIENT_BUNDLE_IMPORTED
    • ClientBundleEvent.CLIENT_BUNDLE_NOT_IMPORTED
    • ClientBundleEvent.CLIENT_BUNDLE_REMOVED
    • ClientBundleEvent.CLIENT_BUNDLE_PUBLISHED
    • ClientBundleEvent.CLIENT_BUNDLE_UNPUBLISHED
    • ClientBundleEvent.CLIENT_BUNDLE_TYPE_CHANGED
  • resourceEvent(ResourceEvent  event) – Invoked by the SoftwareRepository when a specific resource is added or removed from a software component, indicated by raising a com.prosyst.mprm.admin.softrepository.ResourceEvent event. Resource events can be of type:
    • ResourceEvent.RESOURCE_ADDED
    • ResourceEvent.RESOURCE_REMOVED
  • typeEvent(DefinedTypeEvent  event) – Invoked by the repository when a statically defined Concrete Type is changed. The possible event types are:
    • DefinedTypeEvent.DEFINED_TYPE_ADDED
    • DefinedTypeEvent.DEFINED_TYPE_REMOVED
    • DefinedTypeEvent.DEFINED_TYPE_CHANGED

To remove a Software Repository listener, call the removeRepositoryListener(SoftwareRepositoryListener listener) method.

Task Listener

Task Listeners listen for changes during the processes of adding or removing client bundles. Such a listener can be registered by calling the addTaskListener(TaskListener  listener, boolean thisTaskOnly) method of the com.prosyst.mprm.admin.softrepository.task.RepositoryTask interface (see "Adding, Removing and Updating Deployment Units" from the current document). The method takes the following arguments:

  • listener – Represents an instance of the provided implementation of the TaskListener interface that will process the received events.
  • thisTaskOnly – Indicates that only events defined in the TaskListener implementation should be received (when true). Otherwise, all task events are received.


TaskListener has a single method, event(TaskEvent event), called by the RepositoryTask when a new task event is raised.

The following examples implement a TaskListener for receiving a notification when a specific software component is added to the Software Repository. The first one implements a TaskManager:

import com.prosyst.mprm.admin.softrepository.task.RepositoryTask;
import com.prosyst.mprm.admin.softrepository.task.TaskEvent;
import com.prosyst.mprm.admin.softrepository.task.TaskListener;
 
public class MyTaskListenerImpl implements TaskListener {
 
// Method inherited from TaskListener interface
public void event(TaskEvent event) {
 
RepositoryTask task_import = event.getTask();
if (event.getType() == TaskEvent.TASK_FINISHED
&& task_import.getTaskType() == RepositoryTask.TYPE_IMPORT) {
System.out.println("Client bundle importing has finished.");
}
}
}

The second example registers a TaskListener to monitor the process of adding the software component from the example at the top of this page.

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.prosyst.mprm.admin.softrepository.task.RepositoryTask;
import com.prosyst.mprm.admin.softrepository.task.TaskListener;
...
public class ClientBundleTest implements BundleActivator {
 
MyTaskListenerImpl task_listener_impl;
RepositoryTask task_import = null;
 
public void start(BundleContext bc) throws Exception {
 
// Add a client bundle to the Software Repository as
// described in the fist example.
...
// Subscribing to events about changes in the process
// of importing the client bundle
task_listener_impl = new MyTaskListenerImpl();
task_import.addTaskListener(task_listener_impl, true);
}
public void stop(BundleContext bc) throws Exception {
// Free all resources and unregister the TaskListener
if (task_import != null) {
task_import.removeTaskListener(task_listener_impl);
task_import = null;
}
}
}



References