Control Unit Admin Bundle

The Control Unit Admin Bundle delivers means for unified access and management of different types of devices and services.

Contents:


Bundle Information

Bundle JAR

The JAR of the Control Unit Admin Bundle is cuadmin.jar, located in the bundles installation directory.

Import

Package Exporter Description
com.prosyst.util.pool System Bundle/
ProSyst Util Full Bundle
The object pool utility for reusing objects.
com.prosyst.util.ref ProSyst Util Bundle/
ProSyst Util Full Bundle
The log reference utility for generation of log messages.
org.mbs.services.metatype ProSyst Metatype Bundle The Metadata Manager service for management of metadata.
org.osgi.util.tracker OSGi Library Bundle The OSGi Service Tracker utility.

Export

Package Description
org.mbs.services.cu The Control Unit Admin service for management of control units.
org.mbs.services.cu.spi The Control Unit Provider API for implementation of control units.


Services

Control Unit Admin

The Control Unit Admin service provides access to management operations on available control unit instances. The Control Unit Admin service is published in the OSGi framework under the org.mbs.services.cu.ControlUnitAdmin interface. See the "How to Manage Control Units" chapter for more information on the Control Unit Admin usage.

Metadata Plugin

The Control Unit Admin Bundle registers a Metadata Plugin for the "Control-Unit" metadata type. The ProSyst Metatype Bundle associates the Control Unit Admin Bundle with control unit metadata and asks it if to continue processing of newly defined metadata or not. See the description of the ProSyst Metatype Bundle for more information on Metadata Plugins.


System Properties

The Control Unit Admin Bundle uses the following system properties:

System Property Description
mbs.cuadmin.debug Turns on/off generation of debug information about the runtime operation of the Control Unit Admin Bundle.
mbs.cuadmin.metatype.store If true, the control unit metatype (see "Control Unit Metatypes") is cached by the metatype service and thus it avoids parsing the XML file once more, when calling the metatype again. The default value of this property is false.

To use successfully the above system properties, you have to specify them:

For more information about using system properties, refer to the "System Properties" document from "Getting Started".


Control Unit Paradigm

Goals of the Control Unit Paradigm

The control unit paradigm aims to unify the control of miscellaneous units. In an OSGi framework, the paradigm introduces a common interface to manage different types of controllable modules - these can be devices handled by appropriate drivers, software modules, etc.

Imagine the following situation:

You are to manage X10 and LON devices registered by the appropriate drivers in an OSGi-enabled device. The APIs for contacting X10 and LON devices may significantly differ. To be able to call the devices, you must have good knowledge of both technologies and perform complex operations on managed devices. If you should contact another category of devices, for example UPnP, you will be obliged to learn another Java API.

ProSyst designed the control unit paradigm and its API to solve such troubles and to save you time and efforts in using too many and too different APIs in order to control units running in the OSGi framework environment. Through the API, developers can refer to abstract control units sharing common and comprehensive operation model regardless of specifics of the underlying APIs.

The control unit paradigm introduces a management application, called Control Unit Admin, which provides convenient access to available control units, delivered by different providers, and means for their control.

Cooperation with the Device Driver Model

The control unit abstraction fits well into the device driver model. A control unit can be used for representing a device as a service in the framework.

Where it is possible, the base driver for a given protocol, apart from functioning as a conventional driver as defined in the OSGi Device Access Specification, registers every discovered device as a control unit instance in the Control Unit Admin.

Where the semantics of the protocol does not provide enough information (for example in a OneWire network), refining drivers do the mapping between control units and devices.


Structure of a Control Unit

The structure that a control unit can have is illustrated in Figure 2.

Control unit components
Figure 1: Structure of a control unit.

State Variables and Actions

A control unit is a collection of state variables and actions. State variables reflect control unit's specific parameters, for example: an X10 lamp may have a state variable for indicating on and off, and have unique ID within the control unit scope and value of certain type. You can only get a state variable's value by making a query. Direct modification with a new value is not supported. If the state variable's value can be changed from outside, the control unit should provide an action for such an operation.

The actions of a control unit are the commands that the control unit can execute, such as turning a lamp on and off. An action has ID, unique within the control unit scope, and may have input and/or output arguments.

Control Unit Interface and State

The collection of state variable IDs and types and of action IDs form the interface of the control unit. The current values of control unit's state variables determine the present state of the control unit.

The control unit paradigm provides a unified, well-known way to monitor the state of and execute an action on a control unit resulting in a state change. Thus, although there is a great flexibility in what operations can be invoked on units and the state variables they provide, applications can manage control units in a uniform way, without the need to bind to specific knowledge about underlying resources.

Control Unit Type and ID

Each control unit instance has associated type and ID. The control unit's type identifies its interface. It is possible to have many control unit instances of the same type, sharing the same set of state variable and action identifiers, but in different states. The control unit ID has to be unique in the scope of the corresponding type.

Version of the Control Unit Type

The interface of control units of a specific type may evolve between its successive implementations - for example, the newer version of the implementation may add some new state variables and actions. To support this scenario, the control unit type may be supplemented with version. This allows additional attributes and actions to be added without the need of introducing a new type. Newer versions of a given type should be backward compatible with the older ones. In this way an older management application may still run with the new type version, taking benefit only from the type's older features, while newer applications will be able to take advantage of the new features provided by the extended type.

All control units of the same type exported at a time in the OSGi framework should have the same version.

Control Unit Metatypes

In order to use a specific control unit, an application has to know its interface. In general, there are two ways to deliver this knowledge:

The description of a control unit interface is called control unit metatype and is supplied by a Metatype Provider. Control unit metatyping relies on the ProSyst Metatype support which in turn is based on the OSGi Metatype Specification. For details on the format and definition of control unit metadata, see the "How to Provide Control Units" chapter.

Control Unit Hierarchies

You can build a nested structure of control units, convenient for logical grouping of units and especially useful for representing more complex resources - devices, hardware and software systems, which may be decomposed to a hierarchy of sub-components, achieving arbitrary level of granularity. For example, a control unit hierarchy may be defined to represent a controller with several devices attached to it.

The relation between parent and child control units is "soft", that is, built only on the properties specifying the parent types and IDs. This means that parent control units do not need to know their children, but a child control unit has to know its parents.

The Control Unit Admin is capable of lookup for parent or child control units saving each management application the efforts for matching child and parent IDs.

Control Unit Inheritance

A control unit interface can extend a super control unit, meaning that it inherits all state variables and actions of its superior.


Control Unit Architecture Model

Figure 2 illustrates the architecture of the control unit paradigm.

Control unit abstraction
Figure 2: Control unit architecture.

Basically, the usage model of the control unit abstraction outlines two development roles: one of a developer who writes a bundle which uses control units; and one of a developer that implements a control unit. Users of the control unit paradigm work straight with the control units by calling the common methods of the Control Unit Admin instead of different methods provided in different APIs.

The control unit abstraction is not bound to any visual representation of the data it carries. It does not require any special GUI components, and it does not put any restrictions on the visual applications that use it. Developers may build user interfaces in Swing, HTML, XML, PGUI , mGUI or any other library of graphical components.

Provider Layer

The Provider Layer of the control unit paradigm contains control unit provider applications. Control unit providers map miscellaneous manageable entities (devices, applications, services, etc.) to control units.

The control unit paradigm includes a special API, Control Unit Provider API, for creation of control units, accessible through the Control Unit Admin, and for interaction with the Admin Layer. The Control Unit Provider API components are included in the org.mbs.services.cu.spi package. For more information on plugging new control units, refer to the "How to Provide Control Units" chapter.

Admin Layer

The Admin Layer acts as an intermediary between provided control units and applications wishing to manage them. The Admin Layer directly calls control unit providers over the Control Unit Provider API and makes provided control units available to applications over the Control Unit Admin API (defined in the org.mbs.services.cu package). The basic component of the Admin Layer is the Control Unit Admin module, which "translates" raw control units into more sophisticated entries. For more information on managing control units through the Control Unit Admin, refer to the "Managing Control Units" chapter.

Application Layer

The Application Layer consists of custom applications working with control units. Such application may be generic management applications, which provide control and monitoring of all available control units in the OSGi framework, or may be applications, specialized in interacting with particular type(s) of control units.

How to Provide Control Units

This chapter discusses the basic concepts in implementing control units by using the Control Unit Provider API (org.mbs.services.cu.spi). Basically, the control unit paradigm outlines two approaches: implement a Managed Control Unit for associating a control unit instance with a single entity or implement a Control Unit Factory, capable of producing and managing multiple control unit instances of the same type. The factory approach allows a provider to produce a large number of control units without loading the OSGi framework registry.

Tip: You can use the Control Unit Generator API and the Control Unit Generator tool to provide Managed Control Units and Control Unit Factories.

Implement a Managed Control Unit

Managed Control Units should implement and register an org.mbs.services.cu.spi.ManagedControlUnit service object in the OSGi framework. A Managed Control Unit is restricted to have only one parent and cannot use the mechanism for definition of constructors, destructors and finders.

The Managed Control Unit service should have the following registration properties with string keys and values, available as fields of the ControlConstants interface:

Implement a Control Unit Factory

Besides providing multiple control units, a Control Unit Factory can also offer methods for constructing and destroying control unit instances. This can be useful if some initial information is necessary to start managing an entity (see also "Control Unit Constructors" and "Control Unit Destructors"). For example, if a user wants to control devices manageable through a Control Unit Factory and the user is the only one having the knowledge how to contact the devices. To manage a device, the user asks the Control Unit Factory to create a control unit for it passing the known contact parameters. Thereafter the device can be managed through the newly created unit. When the device is disconnected or no further management is needed, the user asks the Control Unit Factory to destroy it.

Another beneficial option of a Control Unit Factory is the ability to define custom finder methods for retrieving control units. Such methods can give an optimal and efficient way for control unit searching. For more information on definition of finder methods, refer to "Control Unit Finders".

A Control Unit Factory service should be registered with the following properties in the OSGi framework:

Define Control Unit Metadata

A control unit provider should describe the interface of control units of a given type through metadata. Supplied metadata is loaded in the Control Unit Admin, which management applications can use in combination with the Metadata Manager of the ProSyst Metatype Bundle for passing and retrieving information in a correct way.

Control Unit Metadata Specifics

Control unit metadata is based on the ProSyst Metatype API and should describe a specific control unit type.

The metatype of a Managed Control Unit describes the control unit itself and of a Control Unit Factory - the interface of the control unit instances, which the factory is able to produce.

Control unit metatypes are handled by the ProSyst Metatype Bundle, which implements the OSGi Metatype Specification and supports the ProSyst Metatype API. The bundle's Metadata Manager processes available control unit metatypes and delivers the information to the Control Unit Admin Bundle.

The following lines outline the most important and typical entries, required for a control unit metatype. Detailed description of all metatype entries is available in the description of the ProSyst Metatype Bundle.

A control unit metatype can be access through a Metatype Provider whose ID (i.e. PID) is equal to the control unit type. The control unit is represented by an ObjectClassDefinition whose ID should be also equal to the control unit type. Name, description and icon can be used for control unit representation in a UI application.

AttributeDefinitions within the control unit ObjectClassDefinition describe the state variables. A state variable AttributeDefinition has an ID, type, cardinality and additional key/value constraining properties. Name, description and option labels/values can be used in a UI application.

If the control unit has one or more parents, their type should be specified by a special attribute with ID "mbs.parent.type" of type String, cardinality equal to the number of parents (maximum Integer.MAX_VALUE) and default value indicating the types of parent control units.

If the control unit is designed to inherit another, "super" control unit, that is, acquire all attributes of its "superior", the the control unit metatype should contain an attribute with ID "super", type String, cardinality 0 and default value indicating the type of the super control unit.

An ObjectClassDefinition within the ObjectClassDefinition of the control unit holds the metadata of a control unit action. Input and output arguments should be defined as AttributeDefinitions with modifier "modifier" equal respectively to "in" and "out".

Following is a summarized structure of a control unit metatype:

Export Control Unit Metadata

In order to export the metadata, describing a control unit type, you have two options:

Supported Data Types

The Control Unit Admin supports the following data types of state variables and action arguments:

Predefined Actions

Optionally, control unit providers can support several predefined actions, described in the next paragraphs.

State Variable Setters

A control unit provider can support setter actions for specific state variables with action IDs in the form of $set.<state_var_id>, where <state_var_id> must be the ID of the state variable the setter action is intended for. Such an action must have a single input argument of the same type as the associated state variable and no output arguments.

Control Unit Finders

A control unit provider can implement one or more actions for filtering control units, called finders, in a Control Unit Factory. Such an action must have ID prefixed by $find. (ControlConstants.FINDER_PREFIX) and can take arbitrary number and type of arguments. The Control Unit Admin does executes a finder action in a special way - by invoking the findControlUnits method of the Control Unit Factory with arguments compliant with the finder action's metadata.

Control Unit Constructors

A constructor action can be defined for explicit creation of control units in a Control Unit Factory. Such an action is whose ID starts with $create. (ControlConstants.CONSTRUCTOR_PREFIX). and may have arbitrary number and type of arguments. The Control Unit Admin calls a constructor through the createControlUnit method of the Control Unit Factory.

Control Unit Destructors

By analogy with constructor actions, a Control Unit Factory can support a single destructor action, whose ID starts with $destroy (ControlConstants.DESTRUCTOR) and has no arguments, for explicit removal of control units. The Control Unit Admin executes the destructor action through the destroyControlUnit method of the Control Unit Factory.

Notify Control Unit Admin of Changes

Both a Managed Control Unit and a Control Unit Factory should notify the Control Unit Admin of changes concerning state variables as well as a Control Unit Factory provide notification of created/destroyed control units and of attachment to/detachment from parents as well. The Control Unit Admin will then notify interested listeners of custom applications.

When the Control Unit Admin detects a new Managed Control Unit or Control Unit Factory, it registers a callback instance (org.mbs.services.cu.spi.CUAdminCallback) in the Managed Control Unit or in the Control Unit Factory by calling the unit's or factory's setControlUnitCallback method.

When there are changes in the control unit's state variables, the Managed Control Unit should call the stateVariableChanged method of the CUAdminCallback instance passing the new variable value.

A Control Unit Factory should inform the Control Unit Admin of the following changes in the control units it maintains:

Examples of Provided Control Units

Managed Control Unit Example

The following example contains a simple Managed Control Unit of type "tuner" and ID "test.cu". For simplicity the control unit has one state variable, showing the current state of the tuner, and one action changing the state variable.

ManagedControlUnit Implementation. Listing 1.1 contains the implementation of the ManagedControlUnit interface. The invokeAction method, called by the Control Unit Admin on request from a management application, changes the value of the state variable and notifies the Control Unit Admin of the change by using the supplied CUAdminCallback instance.

import org.mbs.services.cu.spi.CUAdminCallback;
import org.mbs.services.cu.spi.ManagedControlUnit;
public class MyManagedControlUnit implements ManagedControlUnit {
  private CUAdminCallback callback = null;
  // Constant for the control unit ID
protected static final String CU_ID = "test.cu";
// Constant for the control unit type protected static final String CU_TYPE = "tuner"; // Constant for the control unit's state variable
protected static final String TUNER_STATE = "tuner_state";
// Constant for the control unit's action protected static final String SET_ACTION = "setState"; private int tuner_state = -1;
  public void setControlUnitCallback(CUAdminCallback callback) {
this.callback = callback;
}
  public String getId() {
return CU_ID;
}
  public String getType() {
return CU_TYPE;
}
  public Object invokeAction(String actionId, Object args) throws Exception {
if ((actionId.equals(SET_ACTION)) && (args instanceof Integer)) {
tuner_state = ((Integer) args).intValue();
// Notifying the Control Unit Admin
// of the state variable change
callback.stateVariableChanged(CU_TYPE, CU_ID,
TUNER_STATE, new Integer(tuner_state)); } return null; }
  public Object queryStateVariable(String arg0) {
return new Integer(tuner_state);
}
}
Listing 1.1: Implementing a ManagedControlUnit.

Managed Control Unit Registration. Listing 1.2 contains is a bundle activator, which registers the Managed Control Unit in the OSGi service registry, specifying the control unit's type and ID as service registration properties.

import java.util.Hashtable;
import org.mbs.services.cu.ControlConstants;
import org.mbs.services.cu.spi.ManagedControlUnit;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.metatype.MetaTypeProvider;
public class MyControlUnitActivator implements BundleActivator {
  private ServiceRegistration cuReg = null;
private MyManagedControlUnit myCU = null;
  public void start(BundleContext bc) throws Exception {
// Registering the Managed Control Unit as a service
myCU = new MyManagedControlUnit();
Hashtable regProps = new Hashtable();
regProps.put(ControlConstants.TYPE, MyManagedControlUnit.CU_TYPE);
regProps.put(ControlConstants.ID, MyManagedControlUnit.CU_ID);
cuReg = bc.registerService(ManagedControlUnit.class.getName(), myCU, regProps); }
  public void stop(BundleContext bc) throws Exception {
if (cuReg != null) {
cuReg.unregister();
}
myCU = null;
}
}
Listing 1.2: Registering a Managed Control Unit as a service in the OSGi framework.

Managed Control Unit Metadata. Listing 1.3 contains the metatype of the example Managed Control Unit in XML format. The metatype defines that the control unit's state variable is an integer with ID tuner_state and its action has ID setState and takes an integer input argument.

<?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> </metatype-provider>
Listing 1.3: Definition of Managed Control Unit metadata.

The metadata XML can be exported by including the following information in the Control-Unit manifest header with the metadata XML file specified as the cu.xml file within the root directory of the bundle JAR file:

Control-Unit: xml=cu.xml; pid=tuner; name=Test Control Unit; version=1.0.0

Control Unit Factory Example

Following is an example of a Control Unit Factory for type "tuner", which on startup generates 10 control unit instances. The factory also supports a constructor, which creates new control units with the specified IDs, and a finder which is able to find control instances whose IDs start with a specified string.

ControlUnitFactory Implementation. Listing 2.1 contains a simple implementation of the ControlUnitFactory interface. As supported control unit instances does not have any parent types, the getControlUnits and getParents methods return null. The factory does not have a destructor action, so its the destroyControlUnit method returns null as well.

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.mbs.services.cu.ControlUnit;
import org.mbs.services.cu.ControlConstants;
import org.mbs.services.cu.spi.CUAdminCallback;
import org.mbs.services.cu.spi.ControlUnitFactory;
public class MyControlUnitFactory implements ControlUnitFactory {
  protected CUAdminCallback callback = null;
// "Repository" for control unit instances
private Hashtable cus = new Hashtable();
// Constant for the control unit type
protected static final String CU_TYPE = "tuner"; // Constant for finder ID
private static final String FINDER_ACTION_ID
= ControlConstants.FINDER_PREFIX + "startWith";
// Counter for initially created control units
protected int cuCounter = 0;
  protected MyControlUnitFactory() {
init(); }
  // Creates 10 control unit instances with IDs from 0 to 9
private void init() {
while (cuCounter < 10) {
MyControlUnit cu = new MyControlUnit(Integer.toString(cuCounter), this);
cus.put(Integer.toString(cuCounter), cu);
cuCounter++;
}
}
  public void setControlUnitCalluback(CUAdminCallback callback) {
this.callback = callback;
}
  public ControlUnit getControlUnit(String cuId) {
return (ControlUnit) cus.get(cuId);
}
  public String[] getControlUnits(String arg0, String arg1) {
return listControlUnits();
}
  public String[] listControlUnits() {
String[] ids = new String[cus.size()];
Enumeration cusIndex = cus.keys();
for (int i = 0;(i < ids.length) && (cusIndex.hasMoreElements()); i++) {
ids[i] = (String) cusIndex.nextElement();
}
return ids;
}
  // Returns control units whose IDs start with the specified string
public String[] findControlUnits(String finderId, Object arguments)
throws Exception {
String[] ids = new String[cus.size()];
if (finderId != null && finderId.equals(FINDER_ACTION_ID)) {
if(arguments != null && arguments instanceof String) {
ids = listControlUnits();
Vector result = new Vector();
for (int i = 0; i < ids.length; i++) {
if (ids[i].startsWith((String)arguments)) {
result.add(ids[i]);
}
}
String[] temp = new String[result.size()];
return (String[])result.toArray(temp);
}
}
return listControlUnits();
}
  public String[] getParents(String arg0, String arg1) {
return null;
}
  public Object queryStateVariable(String cuId, String varId) {
return ((MyControlUnit) cus.get(cuId)).queryStateVariable(varId);
}
  public Object invokeAction(String cuId, String actionId, Object args)
throws Exception {
return ((MyControlUnit) cus.get(cuId)).invokeAction(actionId, args);
}
  // Creates a control unit instance with specified string ID
public String createControlUnit(String constructorId, Object args)
throws Exception {
MyControlUnit cu = null;
if (constructorId != null
&& constructorId.equals(ControlConstants.CONSTRUCTOR_PREFIX)) {
if (args != null && args instanceof String) {
cu = new MyControlUnit((String)args, this);
cus.put(cu.getId(), cu);
if (callback != null) {
callback.controlUnitEvent(ControlUnitListener.CONTROL_UNIT_ADDED,
CU_TYPE,
(String) args);
}
return cu.getId();
}
}
return null;
}
  public void destroyControlUnit(String arg0) throws Exception {        
cus.remove(cuId);
if (callback != null) {
callback.controlUnitEvent(ControlUnitListener.CONTROL_UNIT_REMOVED,
CU_TYPE,
cuId);
}
}
}
Listing 2.1: Implementing a ControlUnitFactory.

Control Unit Factory Registration. Listing 2.2 contains a bundle activator, which registers the Control Unit Factory as a service in the OSGi framework, specifying supported control unit type.

import java.util.Hashtable;
import org.mbs.services.cu.ControlConstants;
import org.mbs.services.cu.spi.ControlUnitFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

public class MyControlUnitFactoryActivator implements BundleActivator {
private ServiceRegistration cuFactReg = null;
private MyControlUnitFactory cuFact = null;

public void start(BundleContext bc) throws Exception {
cuFact = new MyControlUnitFactory();

Hashtable regProps = new Hashtable();
regProps.put(ControlConstants.TYPE, MyControlUnitFactory.CU_TYPE);
regProps.put(ControlConstants.VERSION, "1.0.0");
cuFactReg =
bc.registerService(ControlUnitFactory.class.getName(), cuFact, regProps);
}

public void stop(BundleContext bc) throws Exception {
if (cuFactReg != null) {
cuFactReg.unregister();
}
cuFact = null;
}
}
Listing 2.2: Registering the Control Unit Factory as a service in the OSGi framework.

Control Unit Factory Metadata. Listing 2.3 contains the XML variant of the metadata of the "tuner" control unit type, supported by the example Control Unit Factory. It is similar to Listing 1.3 except for the definition of constructor and finder actions.

<?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>
<
locale/>
<
name>Destroy Control Unit</name>
<
id>$destroy</id>
<
description>Destroys the control unit with specified ID</description>
</
objectclass>
</
objectclass>
</
metatype-provider>
Listing 2.3: Definition of Control Unit Factory metadata.

The metadata for the Control Unit Factory above, can be specified by providing the next information in the Control-Unit manifest header:

Control-Unit: xml=factcu.xml; pid=tuner; name=Tuner Control Units; version=1.0.0


How to Manage Control Units

As previously discussed in this document, the Admin Layer, and namely the Control Unit Admin, is responsible for granting administration applications access to control unit instances. Administration applications can call the Control Unit Admin as a org.mbs.services.cu.ControlUnitAdmin service object from the OSGi framework registry.

Checking for Specific Control Unit Types

To check which control unit types are currently available, use the getControlUnitTypes method of the Control Unit Admin. If you need a specific version of a particular control unit type, call the getControlUnitTypeVersion method to check it.

Using Control Unit Metadata

To be able to use a control instance by correctly querying its state variables and invoking its actions, a management application should be aware of the control unit type metadata. As previously discussed, control unit metadata is compliant with the ProSyst Metatype API. Data defined through this API can be accessed through the Metadata Manager of the ProSyst Metatype Bundle. For more information on metadata management operations, see the description of the ProSyst Metatype Bundle.

Retrieving Control Unit Instances

An application can access a control unit of a specific type and with specific ID by using the getControlUnit method of the Control Unit Admin. The getControlUnit method returns the control unit as an org.mbs.services.cu.ControlUnit instance - by using this instance you can further invoke its actions and query its state variables.

To get the IDs of control units of a specific type, you can use the findControlUnits method by passing the type of interest and null for finder ID and arguments.

Querying State Variables

To perform a query for a state variable, call the queryStateVariable method of the Control Unit Admin. As a result, the Control Unit Admin will provide the appropriate object representing the current state variable value.

Invoking Actions

The Control Unit Admin invokes a control unit action on calling its invokeAction method, which takes as parameters the control unit type and ID, the action ID and input arguments. The method returns the result of the action according to the metadata for the action's output arguments.

Tracing Out Control Unit Hierarchies

The Control Unit Admin is capable of associating parent control units with their descendants and provide this information to interested applications.

To get the parent or sub types of a control unit type through the Control Unit Admin, you can use respectively the getParentControlUnitTypes or getSubControlUnitTypes method.

Knowing the type and ID of a control unit and the types of its parents or children, an application can get the IDs of present parent or child control units by invoking Control Unit Admin's getParentControlUnits and getSubControlUnits methods respectively.

Searching, Creating and Destroying Control Unit Instances

If supported by the control unit provider (see "Predefined Actions"), for a control unit type a management application can explicitly create and destroy a control unit instance as well as look for specific instances. The format of input and output arguments for these operations can be taken from the control unit metadata.

To create a control unit instance through a specific constructor action, call the createControlUnit method of Control Unit Admin, and to destroy a control unit instance - the destroyControlUnit method. Finder actions can be invoked through the Control Unit Admin findControlUnits method. As action ID prefixes, you can use the corresponding constants from the org.mbs.services.cu.ControlConstants interface.

Listening for Changes in Control Units

The Control Unit Admin API defines several types of listeners, which applications can implement in order to receive notifications about control unit changes.

To make control unit related listeners functional, you should register them as services in the OSGi framework. Defined listener types share a common set of service registration properties, which specify control unit types and IDs of interest as well as request synchronous event delivery:

The following listener types exist in the Control Unit Admin API:

Example of a Control Unit Management Application

The SimpleControlUnitManager example class, included in Listing 3, uses the Control Unit Admin and Metadata Manager to print the state variable IDs of currently available control unit types. As the example registers itself as a Control Unit Listener service, it is also able to print state variable information for newly appeared control unit types.

import java.io.IOException;
import org.mbs.services.cu.ControlUnitAdmin;
import org.mbs.services.cu.ControlUnitListener;
import org.mbs.services.metatype.MetaDataManager;
import org.osgi.service.metatype.ObjectClassDefinition;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.MetaTypeProvider;

public class SimpleControlUnitManager implements BundleActivator, ControlUnitListener {
ServiceReference cuAdminRef = null;
ControlUnitAdmin cuAdmin = null;

ServiceReference mtdataMngrRef = null;
MetaDataManager mtdataMngr= null;

ServiceRegistration cuListenerReg = null;

// Methods inherited from BundleActivator
public void start(BundleContext bc) throws Exception {
// Getting the Control Unit Admin
cuAdminRef = bc.getServiceReference(ControlUnitAdmin.class.getName());
if (cuAdminRef != null) {
cuAdmin = (ControlUnitAdmin) bc.getService(cuAdminRef); } else { throw new Exception("[SimpleControlUnitManager] Control Unit Admin is not available!"); } // Getting the Metadata Manager mtdataMngrRef = bc.getServiceReference(MetaDataManager.class.getName()); if (mtdataMngrRef != null) { mtdataMngr = (MetaDataManager) bc.getService(mtdataMngrRef); } else { throw new Exception("[SimpleControlUnitManager] Metadata Manager is not available!"); } // Registering the Control Unit Listener
cuListenerReg = bc.registerService(ControlUnitListener.class.getName(), this, null); // Print state variable IDs for available control unit types
printInitialCUSet();
}

public void stop(BundleContext bc) throws Exception {
cuListenerReg.unregister();

bc.ungetService(mtdataMngrRef);
mtdataMngr = null;

bc.ungetService(cuAdminRef);
cuAdmin = null;
}

// A helper method for initial printing of state variable information
private void printInitialCUSet() {
String[] cuTypes = cuAdmin.getControlUnitTypes();
for (int i = 0; i < cuTypes.length; i++) {
try {
printStateVars(cuTypes[i]); } catch (IOException e) { e.printStackTrace(); } } }
// Method inherited from ControlUnitListener.
public void controlUnitEvent(int eventType,
String controlUnitType,
String controUnitId) {
if (eventType == CONTROL_UNIT_TYPE_APPEARED) {
try {
printStateVars(controlUnitType); } catch (IOException e) { e.printStackTrace(); } } } // A helper method for printing state variable information
// for the specified control unit type

private void printStateVars(String cuType) throws IOException {
// Retrieving state variable metadata
MetaTypeProvider mtp = mtdataMngr.getMetaTypeProvider(cuType, true);
ObjectClassDefinition ocd =
(ObjectClassDefinition) mtp.getObjectClassDefinition(cuType, null);
AttributeDefinition[] ads = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL); System.out.println("State variables of control unit type " + cuType); for (int i = 0; i < ads.length; i++) { System.out.println("\t ID: " + ads[i].getID()); } } }
Listing 3: Managing control units.


Tools

mBS offers convenient tools for management and generation of control units:


Previous Version of the Control Unit API

For backward compatibility, this release of the Framework Professional Edition Package includes the previous version of the Control Unit API as well. The "old" Control Unit API is available in the Control Unit Bundle whose JAR file is oldcus.jar located in the bundles installation directory. The Control Unit Bundle also contains the abstract classes from the org.mbs.services.control.util for implementing control units on top of the old Control Unit API, and the helper classes for easier processing control units' data from the org.mbs.services.control.helper package.

You can find more information about the previous version of the Control Unit API in the mBS 5.2.03 user documentation.

Note: You can use the Control Unit Converter bundle for accessing control units compliant with the previous version of the Control Unit API through the Control Unit Admin service.


References


Control Bundles