Control Unit Generator Support Bundle

The Control Unit Generator Support Bundle offers a class library to developers for easier implementation of control units.

Contents:


Bundle Information

Bundle JAR

The Control Unit Generator Support Bundle is packed in the cugenerator.jar JAR file from the bundles installation directory.

Import

Package Exporter Description
com.prosyst.util.timer ProSyst Util Bundle/
ProSyst Util Full Bundle
The Timer Service for receiving notifications over a certain time period.
org.osgi.service.cm OSGi Library Bundle The OSGi Configuration Admin API for definition and management of configurable bundle properties.
org.osgi.service.metatype The OSGi Metatype for definition of metadata.
org.mbs.services.metatype ProSyst Metatype Bundle The Metadata Manager service for management of metadata.
org.mbs.services.cu Control Unit Admin Bundle The Control Unit Admin API for management of control units.
org.mbs.services.cu.spi The Control Unit Provider API for implementation of control units.

Export

Package Description
org.mbs.services.cu.generator The Control Unit Generator API which extends the control unit paradigm by adding model-controller functionality.


Managed Service

The Control Unit Generator Support Bundle registers an org.osgi.service.cm.ManagedService service in the OSGi framework for exporting properties configurable through the OSGi Configuration Admin Service. The dictionary of configurable properties is available under the mbs.generator.token.pid PID. For more information on bundle configurable properties, refer to the Config Bundle description.


Control Unit Generator API

The Control Unit Generator API, represented by the org.mbs.services.cu.generator package, is targeted to control unit implementations.


Figure 1: Control Unit Generator API structure.

According to the Control Unit Generator API, a control unit implementation can be split into a model and a controller. The model-controller approach allows separation of data persistence from data control and tolerates reuse of control unit models.

The model, ControlUnitModel, represents the control unit's state. It wraps the unit's state variables and handles notification of subscribed listeners upon state variable changes.

The controller implements the control unit's actions. The actual implementation of these actions is outside the scope of the Control Unit Generator API - it is responsibility of control unit providers to implement the operations hidden behind control unit actions.

Provide a Control Unit Model

The Control Unit Generator API provides a default implementation of a control unit model (DefaultControlUnitModel) with the most common functionality included. However, when this model is created, by default it does not hold any default values of state variables. They should be explicitly defined through an extended protected Hashtable getModelInitValues (Hashtable table) method, which should retrieve the Hashtable to put data into from the getModelInitValues method of the DefaultControlUnitModel superclass.

import java.util.Hashtable;
import org.mbs.services.cu.generator.DefaultControlUnitModel; 
 
public class TunerControlUnitModel extends DefaultControlUnitModel { public static final String SVAR_TUNER_STATE = "tuner_state";
public TunerControlUnitModel(String cuType, String cuId) { super(cuType, cuId); }
protected Hashtable getModelInitValues(Hashtable table) { table = super.getModelInitValues(table); table.put(SVAR_TUNER_STATE, new Integer(0)); return table; }
}
Listing 1: Providing control unit model

Provide a Control Unit Controller

The Control Unit Generator API maps control unit actions to specific Java methods within a controller. A control unit provider has two options in specifying Java methods for control unit's actions:

import org.mbs.services.cu.generator.TokenControlUnit;
public class TunerControlUnitController {
  TunerControlUnitModel model = null;
  TokenControlUnit tokenCu = null;
         
  protected TunerControlUnitController(TunerControlUnitModel model, 
TokenControlUnit tokenCu) { this.model = model; this.tokenCu = tokenCu; }
public void _cu_setState(int state) { model.updateSV(TunerControlUnitModel.SVAR_TUNER_STATE,new Integer(state)); } public void _cu_lock(String tokenID, int tokenPriority) { tokenCu.lock(tokenID, new Integer(tokenPriority)); }
}
Listing 2: Providing control unit control unit controller.

Note: Avoid situation of having methods with identical names. For example set_vloume method, returned by getActions and _cu_set_volume. There may occur problems when using different VMs, because of the different Reflection implemetation.

Instantiate Default Control Unit Implementation

If you want to have a Managed Control Unit for a single control unit instance, you can instantiate the DefaultControlUnit class, passing the model and controller. If you no longer need the DefaultControlUnit instance, call its release method to free allocated resources.

import java.util.Hashtable; 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.mbs.services.cu.ControlConstants;
import org.mbs.services.cu.generator.*;


public class DefaultControlUnitActivator implements BundleActivator { DefaultControlUnit cu = null; TunerControlUnitModel model = null; TunerControlUnitController controller = null; private static final String CU_TYPE = "tuner"; private static final String CU_ID = "test.cu";
public void start(BundleContext bc) throws Exception { model = new TunerControlUnitModel(CU_TYPE, CU_ID); controller = new TunerControlUnitController(model, tokenCu); cu = new DefaultControlUnit(model, controller); Hashtable regProps = new Hashtable(); regProps.put(ControlConstants.TYPE, CU_TYPE); regProps.put(ControlConstants.ID, CU_ID); cu.registerService(bc, regProps); }
public void stop(BundleContext bc) throws Exception { cu.unregisterService(); cu.release();
cu = null; } }
Listing 3: Instantiating DefaultControlUnit.

Instantiate Default Control Unit Factory Implementation

If you need multiple control unit instances of produced by a Control Unit Factory, you can use the default Control Unit Factory implementation which the Control Unit Generator API offers - DefaultControlUnitFactory. However, if your factory should support constructor, finder and/or destructor actions, you should extend the createControlUnit, findControlUnits and destroyControlUnit methods as these methods does not provide such functionality by default.

import org.mbs.services.cu.ControlUnit;
import org.mbs.services.cu.generator.DefaultControlUnit;
import org.mbs.services.cu.generator.DefaultControlUnitFactory; 

public class TunerControlUnitFactory extends DefaultControlUnitFactory { public static final String CU_$CREATE_ = "$create."; public TunerControlUnitFactory(String cuType) { super(cuType); }
public String createControlUnit(String constructorId, Object arguments) { if(CU_$CREATE_.equals(constructorId)) { return $create_((String)arguments); } else { return super.createControlUnit(constructorId, arguments);} } private String $create_(String cuId) { TunerControlUnitModel model = new TunerControlUnitModel(super.getType(), cuId); TunerControlUnitController controller = new TunerControlUnitController(model); DefaultControlUnit cu = new DefaultControlUnit(model, controller); addControlUnit(cu); return cu.getId(); }
}
Listing 4.1: Extending DefaultControlUnitFactory with constructor and finder actions.

  TunerControlUnitFactory factory = null;
private final String CU_TYPE = "tuner";
. . .
factory = new TunerControlUnitFactory(CU_TYPE);
int cuCounter = 0; while (cuCounter < 6) { factory.createControlUnit(TunerControlUnitFactory.CU_$CREATE_,
Integer.toString(cuCounter)); cuCounter++; }
. . .
Listing 4.2: Instantiating DefaultControlUnitFactory.

Register a Service in the OSGi Framework

Having supplied the components, necessary to provide control units through the Control Unit Generator API, you can proceed with registration of the DefaultControlUnit or DefaultControlUnitFactory instance as a service in the OSGi framework. Both control unit provider entities implement a ready-to-use mechanism for service registration and unregistration, defined by the ServiceObject abstract class.

To publish the DefaultControlUnit or DefaultControlUnitFactory service, invoke its registerService method with arguments the org.osgi.framework.BundleContext object, allocated for your control unit provider bundle, and your custom service registration properties. To remove the DefaultControlUnit or DefaultControlUnitFactory service from the OSGi framework registry, simply call the service's unregister method.

public class Activator implements BundleActivator { 
TunerControlUnitFactory factory = null; private final String CU_TYPE = "tuner";
public void start(BundleContext bc) throws Exception { // Instantiating DefaultControlUnitFactory . . . Hashtable regProps = new Hashtable(); regProps.put(ControlConstants.TYPE, CU_TYPE); factory.registerService(bc, regProps); }
public void stop(BundleContext bc) throws Exception { factory.unregisterService();
String[] cuIds = factory.listControlUnits();
for (int i = 0; i < cuIds.length; i++) {
((DefaultControlUnit)factory.getControlUnit(cuIds[i])).release();
}
factory = null;
}
}
Listing 5: Registering the DefaltControlUnitFactory as a service.

Provide Metadata

To describe the structure of your control unit type, you should supply the Control Unit Admin with a control unit metatype definition.

Basically, you have two options for control unit metatype definition:

For more information on control unit metatype definition, refer to the "Define Control Unit Metadata" chapter of the Control Unit Admin Bundle.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE metatype-provider SYSTEM "metatype.dtd">
<metatype-provider>
  <objectclass>
    <locale/>
    <name>Test Control Unit</name>
    <id>tuner</id>
    <description>A simple control unit illustrating the control unit paradigm.</description>
    <attribute modifier="req">
      <name>Tuner State</name>
      <id>tuner_state</id>
	    <description>Current tuner state</description>
      <type>&int;</type>
	    <cardinality>0</cardinality>
      <value>
        <scalar>0</scalar>
	    </value>
    </attribute>
    <objectclass>
      <locale/>
<name>Set Value</name> <id>setState</id> <description>Changes the value of the Tuner State variable.</description> <attribute modifier="in"> <name>State</name> <id>state</id> <description>New tuner state</description> <type>&int;</type> <cardinality>0</cardinality> </attribute> </objectclass> <objectclass>
<locale/> <name>Constructor action</name> <id>$create.</id> <description>Creates a CU instance</description> <attribute modifier="in"> <name>CU ID</name> <id>cuId</id> <description>The ID of constructed CU</description> <type>&string;</type> <cardinality>0</cardinality> </attribute> </objectclass> <objectclass> <locale/>
<name>Finder action</name> <id>$find.startWith</id> <description>Looks for CU instances starting with the specified string.</description> <attribute modifier="in"> <name>CU ID</name> <id>cuId</id> <description>The control unit ID to look for</description> <type>&string;</type> <cardinality>0</cardinality> </attribute> </objectclass> </objectclass> </metatype-provider>
Listing 5: Control unit metadata.

Using the Access Token Mechanism

The access token mechanism is an extension to the basic control unit implementation of the Control Unit Generator API and provides functionality to handle concurrent requests for access to a control unit. The mechanism is realized by using a lock for the control unit. The Control Unit Generator API offers a ready token-enabled control unit implementation, represented by the TokenControlUnit class.

The lock is represented by an object, called token (access token). The token has two attributes:

The token ID and token priority, defined as state variables, represent the token in the control unit. If the control unit is not locked, the value of the token ID is an empty string, and the value of the token priority state variable value equals Integer.MIN_VALUE. The token-enabled control unit implementation also provides three actions (listed by ID):

The control unit implementation starts a timer when a token locks it. This timer is reset on each action invocation. The timer is stopped if the unlock action is invoked, or when the time of the timer expires. In the last case, the timer automatically unlocks the control unit.

A possible usage scenario can be in an UI application with user-specific access to control units. When a user requests access to a control unit, the UI application locks the control unit for the user and displays the corresponding information. When another user wants to use the locked control unit, through a user-specific token the UI application can check user's access rights and reject or permit access.

Using the Control Unit Generator Tool

Given a metadata XML, the Control Unit Generator tool is capable of generating the model and controller of a control unit in compliance with the Control Unit Generator API. For more information on the tool's usage, refer to the "Control Unit Generator Tool" document.


Configuration

Configuration Resources

The Managed Service, whose PID is mbs.generator.token.pid, exports a configuration dictionary with a single property setting the expiration period of the access token timer. The property has ID tokenExpiration, name Token Expiration, data type Long and default value 60000 ms.

Visual Administration

Visual administration over the Control Unit Generator Support Bundle is available in the mConsole. The configuration relies on the bundle's ManagedService service, whose configuration dictionary can be modified through the mConsole's general property editor (see also "Working with the General Property Editor" chapter from the mConsole guide).


Figure 2: Visual administration of the Control Unit Generator Support Bundle.

To validate the changes you have made on the Control Unit Generator Support Bundle, click Set. The Refresh button updates the configuration in case another framework administrator has made some changes too. The Defaults button loads the initial configuration data.

System Properties

Control Unit Generator Support Bundle uses the mbs.cu.checkInput system property. The default value of the property is false. If turned to true, when invoking an action, the action imput arguments are verified.


References


Control Bundles