This document contains a guide to providing new content types to the RM Software Repository by means of Software Repository Content Plug-ins.

Overview

The Software Repository model allows different types of software components to be represented in a unified way in order to ease their management. This is accomplished by various Content Plug-ins which are controlled by the Software Repository.

RM provides a backend Software Repository API which components from the com.prosyst.mprm.backend.softrepository package can be used by developers who want to provide a custom Content Plug-in. The most significant for the successful development of a new software component management plug-in are the com.prosyst.mprm.backend.softrepository.ImportFileHandler and com.prosyst.mprm.backend.softrepository.MetaInfoProvider interfaces.

Example of a Content Plug-in

The source examples provided in this document traces the process of developing a new Content Plug-in out with the following features:

  • The plug-in is represented in the repository with concrete client bundle type "Plain Text".
  • The software components maintained by this Content Plug-in are text files with extension .txt.
  • The content ID and the version of an imported text file handled by this plug-in are editable.

MetaInfo Provider Interface

In order to be able to process properly a file content, the Software Repository needs some metadata about it. The needed information is provided by the MetaInfo Provider which holds the characteristics of a specific client bundle concrete type.

Implement the MetaInfo Provider Interface


To provide the repository with metadata, therefore notifying it that a new concrete type with specific properties exists, implement a MetaInfo Provider, represented by the com.prosyst.mprm.backend.softrepository.MetaInfoProvider interface as shown in the following example. It implements a MetaInfo Provider for the Plain Text concrete type. 

import java.io.InputStream;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;
import javax.provisioning.BundleType;
import org.osgi.framework.ServiceRegistration;
import com.prosyst.mprm.admin.softrepository.ConcreteBundleType;
import com.prosyst.mprm.admin.softrepository.ImportFileType;
import com.prosyst.mprm.backend.softrepository.MetaInfoProvider;
 
public class MetaInfoProviderImplementation implements MetaInfoProvider {
 
InputStream icon;
ServiceRegistration sreg;
ImportFileTypeImplementation[] fileType;
 
public MetaInfoProviderImplementation() {
try {
// Specify the import file type formats managed by the plug-in,
// shown in the example
int size = 1;
fileType = new ImportFileTypeImplementation[size];
fileType[0] = new ImportFileTypeImplementation(
"A Plain Text can contain one or more text files.",
new String[] { "txt" });
// Provide an input stream for the icon that will represent
// the new Content Plug-in and the client bundles it manages
// in the Software Repository Management Tree
URL url = new URL("D:/Job_Programming/images/text_image.jpg");
icon = url.openStream();
} catch (Exception e) {
e.printStackTrace();
}
}
// Returns the general bundle managed by the plug-in
public BundleType getGeneralBundleType() {
return BundleType.TEXT;
}
// The extension of the supported file types is .txt
// and the functionality of the component is described as
// "A Plain Text can contain one or more text files."
public ImportFileType[] getImportFileFormats() {
return fileType;
}
// The description of the concrete type is set
public String getDescription() {
return "A Plain Text can contain one or more text files.";
}
public String getMimeType() {
return "text/plain";
}
// A client bundle from this concrete type can not be
// build by client bundles from other concrete types
public boolean isComposite() {
return false;
}
// The concrete type is not a composite one
public String[] getComponentContentTypes() {
return new String[0];
}
// The icon that represents the concrete type and
// its elements in the repository tree
public InputStream getIcon() {
return icon;
}
// A grouping icon is not provided
public InputStream getGroupingIcon() {
return null;
}
// The content ID and version of client bundles managed by
// this Concrete type are editable and the end user can
// create manually client bundles with this Concrete type
public Dictionary getProperties() {
Dictionary di = new Hashtable();
di.put(ConcreteBundleType.EDITABLE_CONTENT_ID, Boolean.TRUE);
di.put(ConcreteBundleType.EDITABLE_VERSION, Boolean.TRUE);
di.put(ConcreteBundleType.USER_CREATBLE, Boolean.TRUE);
di.put(ConcreteBundleType.COMPONENTS_PLURAL_NAME, "Plain Texts");
return di;
}
}


Provide File Description


Software components added to the repository can provide a description of the file that represents them. This is achieved by implementing the com.prosyst.mprm.admin.softrepository.ImportFileType interface.

The following example provides a file type implementation used in the example above.

import com.prosyst.mprm.admin.softrepository.ImportFileType;
 
public class ImportFileTypeImplementation implements ImportFileType {
 
private String description;
private String[] extensions;
 
public ImportFileTypeImplementation(String description, String[] extensions) {
this.description = description;
this.extensions = extensions;
}
// Method inherited from ImportFileType
public String getDescription() {
return description;
}
// Method inherited from ImportFileType
public String[] getExtensions() {
return extensions;
}
}


Register the MetaInfo Provider Service

Finally, having implemented the provider of meta information, you need to register it as an OSGi-compliant service on the RM backend host. The service must have at least the CONCRETE_BUNDLE_TYPE registration property to indicate the concrete type it will support.

The example below registers the implemented MetaInfo Provider as a service in the bundle activator shown in the first example.

import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
import com.prosyst.mprm.backend.softrepository.MetaInfoProvider;
 
 
public class PluginActivator implements BundleActivator {
 
MetaInfoProviderImplementation provider;
ServiceRegistration providerReg;
BundleContext bc;
// Method inherited from BundleActivator
public void start(BundleContext bc) throws Exception {
this.bc = bc;
 
// Register the MetaInfo Provider as an OSGi service
provider = new MetaInfoProviderImplementation();
Dictionary dict = new Hashtable();
dict.put(MetaInfoProvider.CONCRETE_BUNDLE_TYPE, "Plain Text");
providerReg = bc.registerService(MetaInfoProvider.class.getName(), provider,
dict);
 
}
// Method inherited from BundleActivator
public void stop(BundleContext bc) throws Exception {
 
if (providerReg != null) {
providerReg.unregister();
providerReg = null;
}
}
}

Import File Handler Interface

To extend the management scope of the Software Repository, you need to implement the com.prosyst.mprm.backend.softrepository.ImportFileHandler interface providing an Import File Handler that identifies a specific type of software components. To define the file type the handler identifies, register it with the following properties:

  • com.prosyst.mprm.admin.softrepository.SoftwareRepository.FILE_TYPE – Specifies the file type of the software components that are identified and processed by this handler.
  • com.prosyst.mprm.backend.softrepository.ImportFileHandler.FILE_EXTENSION – Specifies the file extension of the specific software component which is used by the Software Repository to discover the plug-in that will handle it.

Identify a Specific Client Bundle

When a specific file is submitted to the Software Repository, a process to find the most suitable registered ImportFileHandler begins. The file content is provided to each handler to indicate whether it can handle it. The most important method to implement from the ImportFileHandler interface is identifyClientBundles(String fileURI, BundleIdentificationSessionContext idSessionContext). It is invoked with the BundleIdentificationSessionContext object created by the repository for the specific client bundle and the URI of the file that will be processed.

The example below implements the Import File Handler interface to ensure the identifying of text files. It implements identifyClientBundlesmethod of the Import File Handler.

import java.io.InputStream;
import javax.provisioning.BundleType;
 
import com.prosyst.mprm.backend.softrepository.BundleIdentificationSessionContext;
import com.prosyst.mprm.backend.softrepository.BundleInfo;
import com.prosyst.mprm.backend.softrepository.ImportFileHandler;
 
 
public class ImportFileHandlerImplementation implements ImportFileHandler {
 
public ImportFileHandlerImplementation() { }
 
// Method inherited from ImportFileHandler
public boolean identifyClientBundles(String fileURI,
BundleIdentificationSessionContext idSessionContext) {
 
// Retrieve an input stream for reading the file content
// in order to identify its type
InputStream fileStream = idSessionContext.getResource(fileURI);
if (fileStream == null) {
return false;
}
try {
// Provide an instance of the software component with
// all necessary information for this file type set, which will
// be used by the Software Repository during the identification
// process
BundleInfo bundle = idSessionContext.createBundleInfoInstance(fileURI);
bundle.setConcreteType("Plain Text");
bundle.setVersion("1.0");
bundle.setFileDeclaration(fileURI, true);
bundle.setContentID(fileURI);
bundle.setGeneralType(BundleType.TEXT);
bundle.setMimeType("text/plain");
idSessionContext.identifyNewBundle(bundle, null);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
 
public void cancel(String fileUri) {
// Execute the proper operations for canceling the import
. . .
}
}

During the identification phase of the importing a BundleInfo instance is created by the Import File Handler. This instance is used to store the retrieved information for the imported client bundle. It is kept temporarily in the repository and allows the repository on basis of its MIME type, concrete and general type to look for registered com.prosyst.mprm.backend.softrepository.BundleIdentificationPlugin services which are able to further process the client bundle. The found BundleIdentificationPlugins identify the client bundles represented by the imported file content and allows the user to change some of the component properties before it is permanently saved.

Eventually, the client bundle is passed to a specific com.prosyst.mprm.backend.softrepository.BundleImportProcessor service instance. It is discovered by the repository through the concrete type of the component and provides more precise processing. The BundleImportProcessor is responsible for retrieving information about custom component properties (for example client bundle category, configuration, payment schemas, etc.) and use it for properly saving and managing the imported client bundle.

Furthermore, BundleImportProcessors are responsible for providing the necessary Control Unit Factories for management of the custom properties for client bundles with specific concrete type. The Software Repository tracks the newly registered Meta Info Providers and retrieves the concrete types they support. Then it registers a Control Unit Factory to represent the custom properties of the new concrete type with control unit type "mprm.sr.<client_bundle_concrete_type>.properties". All custom client bundle properties are represented as child control units of the "mprm.sr.<client_bundle_concrete_type>.properties" parent control unit. For example, if a client bundle with "OSGi Bundle" concrete type is added to the repository database, the Software Repository will create a control unit of "mprm.sr.OSGi Bundle.properties" type and control unit ID which has the same value as the Extending the Software Repository Functionality bundle ID. The manifest of the OSGi bundle will be represented as "mprm.sr.osgibundle.manifest" child control unit. To learn how to manage the custom properties of a specific client bundle, refer to the "Managing Client Bundle Custom Properties" section of the Managing Deployment Units document.

Developers interested in more precise import process should also implement and register the BundleIdentificationPlugin and the BundleImportProcessor service instances.

Asking for User Confirmation

During identification, you can implement you Import File Handler to ask for confirmation from the user prior to calling identifyNewBundle for a client bundle or for a sub-component of a client bundle. Check if user interaction is supported by calling the supportUserConfirmation method of BundleIdentificationSessionContext and then the askUserConfirmation one. To receive the result from the interaction, implement a UserInteractionCallback object and pass as argument to the supportUserConfirmation method.

Register the Import File Handler as a Service

After implementing the ImportFileHandler interface, you need to register it as a service on a RM backend host. It is recommended that the handler has at least the SoftwareRepository.FILE_TYPE and ImportFileHandler.FILE_EXTENSION service registration properties. They characterize the specific file formats this plug-in recognizes and submits for further manipulation.

The example, that follows contains the bundle activator of the created plug-in which registers the Import File Handler as an OSGi service that will identify files with .txt extension and file type Plain Text.


import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.prosyst.mprm.admin.softrepository.SoftwareRepository;
import com.prosyst.mprm.backend.softrepository.ImportFileHandler;
 
 
public class PluginActivator implements BundleActivator {
 
BundleContext bc;
ImportFileHandlerImplementation handler;
ServiceRegistration handlerReg;
 
// Method inherited from BundleActivator
public void start(BundleContext bc) throws Exception {
this.bc = bc;
handler = new ImportFileHandlerImplementation();
// Specify the registration properties of the ImportFileHandler
Hashtable props = new Hashtable(5);
props.put(ImportFileHandler.FILE_EXTENSION, "txt");
props.put(SoftwareRepository.FILE_TYPE, "Plain text");
// Register the handler on a backend framework
handlerReg = bc.registerService(ImportFileHandler.class.getName(), handler,
props);
}
 
// Method inherited from BundleActivator
public void stop(BundleContext bc) throws Exception {
 
if (handlerReg != null) {
handlerReg.unregister();
handlerReg = null;
}
}
}