Overview
The RM provides a useful mechanism for mapping management objects (MOs) of the device management tree (DMT) of an OMA DM enabled device to control units, which are the main management unit in the RM device management (see the user documentation of the Generic Device Management Package).
As described in Managing OMA DM Devices conceptual guide and in the Extending the Mobile Device Management Schema programmer's guide, the mapping of DMT MOs is done by means of special CU-DMTM files, which specify the state variables representing the nodes of the target MO and the OMA DM actions which can be executed on those nodes. In some cases, the universal means provided by the RM CU to DMT mapping are not sufficient to represent certain DMT nodes as fully-featured control units, i.e. it is not possible to map in a straightforward way a node's properties to one or more state variables and OMA DM commands to actions. In such a case, in the relevant CU-DMTM file you can declare state variable or action as "external" - for handling it the Mobile Device Manager of RM will call a specific "mapping plugin" service (can be for a state variable or for an action) available in the management server's OSGi framework. In this guide, we'll provide guidelines for implementing such a plugin service.
You can have several mapping plugins for a single control unit type, and vice versa - a single plugin associated with several control unit types.
Mapping Plugin API
The API for implementing mapping plugins is located in the com.prosyst.syncml.dm.manager.map package. It is accessible for backend application running in the OSGi framework of a management server host.
For purposes of compilation and code assistance, you might also use the files lib/api/mobile-api.jar and lib/api/syncmllib.jar, which contains the APIs of RM's Mobile Device Management Package.
Implementing a State Variable Mapping Plugin
A state variable mapping plugin should implement the com.prosyst.syncml.dm.manager.map.StateVar interface and should be registered as a service in the OSGi framework of a management server host.
Implementing the StateVar Interface
A StateVar implementation has to contain three methods - init, retrieve and getId.
Your state variable plugin can save and subsequently use the ComponentSystemContext object provided as an argument to the init method to communicate with RM's generic device management system - i.e. to retrieve specific control units and related metadata, access the generic Control Unit Database, etc. In the init method along with the ComponentSystemContext object, the RM provides the plugin with the data type of the state variable.
When the value of the state variable that your plugin is responsible for is requested by the system (e.g. as a result of a user command in the Management Console), the Mobile Device Manager will call the retrieve method of the plugin. Note that the plugin is responsible for the state variable value in the scope of the entire control unit type, that is, it is possible that the retrieve method is called concurrently for multiple devices and components.
You can use the following method's arguments for retrieving specific information from RM:
com.prosyst.mprm.impl.syncml.dm.manager.cu.DeviceCu dev- Provides access to characteristics the mobile device within the context of RM with which the handled state variable is associated. Such characteristics are device type and ID, online status, display name, etc.com.prosyst.mprm.impl.syncml.dm.manager.cu.ComponentCu cu- Provides access to the characteristics of the component control unit (mapped to a certain DMT node), that the handled state variable is associated with. Such characteristics are control unit type and ID, etc.com.prosyst.syncml.dm.manager.dmt.Dmt dmt- Represents the DMT of the target mobile device. You can retrieve the device properties saved in theDevInfomanagement object, DMT sub-trees and the properties of specific nodes. Refer to the Managing a Device's DMT document for more information on manipulating a device's DMT.com.prosyst.syncml.dm.manager.map.Namespacens - Represents a namespace (scope) allocated for the state variable. As bindings in the state variable namespace, you can get the values of all variables within the state variable definition (enclosed within <state-var></state-var>) in the relevant CU-DMTM file. As parent namespace, the RM Mobile Device Manager provides the values of the variables related to the definition of the control unit itself (the tags directly enclosed within <control-unit></control-unit>). The control unit namespace also scopes the variables included in the content of the <cu-id> tag.
Having retrieved the value of the state variable in a custom way, you have to deliver it to RM. Set the value to the com.prosyst.syncml.dm.manager.map.AsyncOpListener object provided as argument to the retrieve method - call the setResult method on success or the setError method on failure.
Registering the StateVar Service
To have the State Variable Mapping Plugin registered in the Mobile Device Manager, you have register the StateVar implementation as a service in the OSGi framework of the management server responsible for your target devices. The StateVar service of the plugin should have the following service properties, defined as fields of the com.prosyst.syncml.dm.manager.map.Member interface:
CU_TYPE_PROP ("cu.type") - A string indicating the control unit type the plugin's state variable(s) are for. Should match the type specified in the relevant CU-DMTM file.
CU_VERSION_PROP ("cu.version") - The version of the control unit interface that this plugin's state variable is compatible with.
CU_MEMBER_ID_PROP ("cu.member.id") - The string ID of the state variable handled by the plugin. Should match the state variable ID specified in the CU-DMTM file.
State Variable Mapping Plugin Example
This section offers an example implementation of a state variable mapping plugin. It is based on a custom node in the DMT of a device which holds the users of the device and their groups (both united under the term "role"). Each role has a special interior node with leaves "Name" and "Group". When a new user-specific interior node is created, its "Name" and "Group" are automatically set to, respectively, the user interior node name and to false. Generally, the plugin is associated with OSGi-enabled mobile devices, which have device type "mprm.osgi-meg.device".
Next, a state variable mapping plugin is presented, which retrieves the value of the "Name" leaf from the DMT of the requested device.
CU-DMTM File and Control Unit Metadata XML
Following is the CU-DMTM file (let's name it mprm.osgi-meg.device_Users.xml and place in the syncml/dmtm RM directory) introducing the "user" control units, which are mapped to nodes <path_to_osgi_root>/User/<roleID>, where <path_to_osgi_root> stands for the path to the root of the OSGi mobile tree (see the OSGi Mobile Specification Release 4) and <roleID> stands for the name of the role. The <path_to_osgi_root> parameter is determined as the value of the "device.property.$" node setting exported by the Mobile OSGi Device Management Package of RM. The default value of the setting is ./OSGi.
The user CUs are defined to be of type "my.user.role". Each user CU has two state variables - role, showing the role name, and isGroup, showing if the role is a group or not.
The code snippet bellow demonstrates mapping DMT nodes to control units and state variables.
<?xml version="1.0" encoding="UTF-8"?><control-unit-dmtm> <device-type>mprm.osgi-meg.device</device-type> <control-unit> <dmt-node> <path-pattern try-struct="true">{$multi:$}/User/{roleID}</path-pattern> </dmt-node> <cu-type>my.user.role</cu-type> <cu-id> <id-format>{roleID}</id-format> </cu-id> <state-var> <state-var-id>role</state-var-id> <external/> </state-var> <state-var> <state-var-id>isGroup</state-var-id> <node-attr attr-name="value">Group</node-attr> </state-var> </control-unit></control-unit-dmtm>As described in the Extending the Mobile Device Management Schema, for each control unit type contained in a CU-DMTM file, there should be a corresponding CU metadata XML file named after the control unit type (my.user.role.xml) and placed in the syncml/cu directory of RM. The next listing contains the CU metadata XML for the user control unit type.
The following code snippet demonstrates defining the CU metadata for the relevant mapping.
<?xml version="1.0" encoding="UTF-8"?><metatype-provider> <objectclass load="true"> <locale>en</locale> <name>User</name> <id>my.user.role</id> <description>User MO to CU</description> <!-- A dummy attribute defining that user CUs will be placed in a folder called "Users"--> <attribute modifier="req"> <name>nop</name> <id>nop</id> <description>NOP</description> <type>&string;</type> <cardinality>0</cardinality> <key name="unit.folder" value="Users"/> <key name="invisible" value="true"/> </attribute> <!-- Role part --> <attribute modifier="req"> <name>Role</name> <id>role</id> <description>Role name.</description> <type>&string;</type> <cardinality>0</cardinality> </attribute> <attribute modifier="req"> <name>Is Group</name> <id>isGroup</id> <description>Indicates if the role is a group or a user</description> <type>&boolean;</type> <cardinality>0</cardinality> <value><scalar>false</scalar></value> </attribute> </objectclass></metatype-provider>StateVar Implementation and Service Registration
The code snippet bellow contains the state variable mapping plugin for the "role" state variable of the example user control units. The plugin implements the StateVar interface and registers itself as a service in the management server OSGi framework for control unit type "my.user.role" and state variable "role". The plugin simply retrieves the value of the <path_to_osgi>/User/<roleID>/Name by using the Dmt object for an OMA DM device.
The following example demonstrates implementing a state variable mapping plugin.
import java.util.Hashtable;import java.util.Map;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceRegistration;import com.prosyst.mprm.backend.ms.cu.spi.component.ComponentSystemContext;import com.prosyst.mprm.impl.syncml.dm.manager.cu.ComponentCu;import com.prosyst.mprm.impl.syncml.dm.manager.cu.DeviceCu;import com.prosyst.syncml.dm.manager.dmt.Dmt;import com.prosyst.syncml.dm.manager.dmt.DmtListener;import com.prosyst.syncml.dm.manager.dmt.DmtResult;import com.prosyst.syncml.dm.manager.map.AsyncOpListener;import com.prosyst.syncml.dm.manager.map.Namespace;import com.prosyst.syncml.dm.manager.map.StateVar;public class MyStateVarPlugin implements BundleActivator, StateVar { private ServiceRegistration reg; public void start(BundleContext bc) throws Exception { Hashtable props = new Hashtable(); props.put(StateVar.CU_TYPE_PROP, "my.user.role"); props.put(StateVar.CU_MEMBER_ID_PROP, "role"); reg = bc.registerService(StateVar.class.getName(), this, props); } public void stop(BundleContext bc) throws Exception { if (reg != null) { reg.unregister(); } } public void init(ComponentSystemContext ctx, Class type) {} public void retrieve(DeviceCu device, ComponentCu component, Dmt dmt, Namespace ns, final AsyncOpListener listener) { String uri = "./OSGi/User/" + component.getControlUnitID().getControlUnitId(); Map bindings = ns.getOwnBindings(); dmt.getProperties(uri, new DmtListener(){ public void operationCompleated(DmtResult result) { String roleName = result.getProperty(result.getRootUri() + "/Name", DmtResult.PROP_VALUE); listener.setResult(roleName); } public void operationFailed(Exception exc) { listener.setError(exc); } }); } public String getId() { return "role"; }}Implementing an Action Mapping Plugin
An action mapping plugin should implement the com.prosyst.syncml.dm.manager.map.Action interface and should be registered as a service in the OSGi framework of a management server host.
Implementing the Action Interface
The structure of the Action interface that an action mapping plugin has to implement is similar to the StateVar one described in the preceding lines.
An Action implementation has to contain three methods - init, execute and getId.
Your action plugin can save and subsequently use the ComponentSystemContext object provided as an argument to the init method to communicate with RM's generic device management system - i.e. to retrieve specific control units and related metadata, access the generic Control Unit Database, etc. In the init method along with the ComponentSystemContext object, RM provides the plugin with the signature of the action (ID, name, argument names and types, etc).
When an action that your plugin is responsible for is invoked by the system (e.g. as a result of a user command in the Management Console), the Mobile Device Manager will call the execute method of the plugin. Note that the execute method will be called for each control unit instance of the corresponding type available in the system regardless of the concrete device. In mass operations executed on a group of devices, the execute method will be called for each device involved in the operation scope.
The following execute method's arguments for retrieving specific information from RM can be used:
com.prosyst.mprm.impl.syncml.dm.manager.cu.DeviceCudev - Provides access to characteristics of the mobile device within the context of RM with which the handled action is associated. Such characteristics are device type and ID, online status, display name, etc.com.prosyst.mprm.impl.syncml.dm.manager.cu.ComponentCucu - Provides access to the characteristics of the component control unit (mapped to a certain DMT node), that the handled action is associated with. Such characteristics are control unit type and ID, etc. For constructor actions, this argument is null.com.prosyst.syncml.dm.manager.dmt.Dmtdmt - Represents the DMT of the target mobile device. You can retrieve the device properties saved in theDevInfomanagement object, DMT sub-trees and the properties of specific nodes, as well as execute OMA DM operations on the tree. Refer to the Managing a Device's DMT document for more information on manipulating a device's DMT.com.prosyst.syncml.dm.manager.map.Namespacens - Represents a namespace (scope) allocated for the action. As bindings in the action namespace, you can get the following items:The values of all variables within the action definition (enclosed within <action-definition></action-definition>) in the relevant CU-DMTM file.
The arguments of the actions in the same order as provided by the
ActionSignatureobject previously passed to the plugin as an argument to theinitmethod.As parent namespace, the RM Mobile Device Manager provides the values of the variables related to the definition of the control unit itself (the tags directly enclosed within <control-unit></control-unit>). The control unit namespace also scopes the variables included in the content of the <cu-id> tag.
Having executed the action on the device in a custom way, you have to indicate the result to RM. Set the value to the com.prosyst.syncml.dm.manager.map.AsyncOpListener object provided as argument to the retrieve method - call the setResult method on success or the setError method on failure.
Registering the Action Service
Similarly to state variable mapping plugins, to have the action mapping plugin registered in the Mobile Device Manager, you have to register the Action implementation as a service in the OSGi framework of the management server responsible for your target devices. The Action service of the plugin should have the following service properties, defined as fields of the com.prosyst.syncml.dm.manager.map.Member interface:
CU_TYPE_PROP ("cu.type")- A string indicating the control unit type the plugin's action(s) is/are for. Should match the type specified in the relevant CU-DMTM file.CU_VERSION_PROP ("cu.version")- The version of the control unit interface that this plugin's action is compatible with.CU_MEMBER_ID_PROP ("cu.member.id")- The string ID of the action handled by the plugin. Should match the action ID specified in the CU-DMTM file.
Action Mapping Plugin Example
This section offers an example implementation of an action mapping plugin. It is based on the custom users node defined in the state variable mapping plugin. The next example plugin provides a constructor action for creating new roles in the DMT.
CU-DMTM File and Control Unit Metadata XML
Following is the extension to the CU-DMTM file mprm.osgi-meg.device_Users.xml, introduced in the example of a state variable plugin, defining an external constructor action with ID $create.user.
The code snippet bellow demonstrates mapping DMT nodes to control units and actions.
<control-unit-dmtm><device-type>mprm.osgi-meg.device</device-type><control-unit> <dmt-node> <path-pattern try-struct="true">{$multi:$}/User/{roleID}</path-pattern> </dmt-node> <cu-type>my.user.role</cu-type> <cu-id> <id-format>{roleID}</id-format> </cu-id>. . . <action> <action-id>$create.user</action-id> <external/> </action>. . . </control-unit> </control-unit-dmtm>The next example shows the CU metadata section corresponding to the $create.user mapping. The action takes as input argument the new role name.
The following code snippet demonstrates defining the CU action metadata for the relevant mapping.
<?xml version="1.0" encoding="UTF-8"?><metatype-provider> <objectclass load="true"> <locale>en</locale> <name>User</name> <id>my.user.role</id> <description>User MO to CU</description> . . . <!--Action part--> <objectclass load="true"> <name>Create a User</name> <id>$create.user</id> <description>Adds a new user node to the DMT.</description> <attribute modifier="in"> <name>User Name</name> <id>user.in</id> <description/> <type>&string;</type> <cardinality>0</cardinality> </attribute> </objectclass> </objectclass></metatype-provider>Action Implementation and Service Registration
The code snippet bellow contains the action mapping plugin for the "$create.user" constructor action of the example user control units. The plugin implements the Action interface and registers itself as a service in the management server OSGi framework for control unit type "my.user.role" and action "$create.user". The plugin adds a new node to <path_to_osgi>/User by using the Dmt object for an OMA DM device.
import java.util.Hashtable;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceRegistration;import com.prosyst.mprm.backend.ms.cu.spi.component.ComponentSystemContext;import com.prosyst.mprm.impl.syncml.dm.manager.cu.ComponentCu;import com.prosyst.mprm.impl.syncml.dm.manager.cu.DeviceCu;import com.prosyst.syncml.common.elements.Add;import com.prosyst.syncml.common.elements.Item;import com.prosyst.syncml.common.elements.Meta;import com.prosyst.syncml.common.elements.Target;import com.prosyst.syncml.dm.manager.dmt.Dmt;import com.prosyst.syncml.dm.manager.dmt.DmtListener;import com.prosyst.syncml.dm.manager.dmt.DmtResult;import com.prosyst.syncml.dm.manager.map.Action;import com.prosyst.syncml.dm.manager.map.ActionSignature;import com.prosyst.syncml.dm.manager.map.AsyncOpListener;import com.prosyst.syncml.dm.manager.map.Member;import com.prosyst.syncml.dm.manager.map.Namespace;public class MyActionPlugin implements Action, BundleActivator { private static final String CREATE_USER_ACTION = "$create.user"; private ServiceRegistration reg; private ActionSignature sign; public void execute(DeviceCu device, ComponentCu cu, String cmdId, String opId, Dmt dmt, Namespace ns, final AsyncOpListener listener) { // Get arguments to constructor final String userName = (String) ns.getBinding(sign.getArgumentNames()[0]); // Build OMA DM command Target uri = new Target("./OSGi/User/" + userName); Meta meta = new Meta(); meta.setFormat("node"); Item item = new Item(uri, null, meta, null , false); Add cmd = new Add("user.add", new Item[]{item}); dmt.execute(cmd, new DmtListener(){ public void operationCompleated(DmtResult result) { listener.setResult(userName); } public void operationFailed(Exception exc) { listener.setError(exc); } }); } public void init(ComponentSystemContext ctx, ActionSignature sign) { if (sign == null)return; this.sign = sign;} public String getId() { return CREATE_USER_ACTION; } public void start(BundleContext bc) throws Exception { Hashtable props = new Hashtable(2); props.put(Member.CU_MEMBER_ID_PROP,CREATE_USER_ACTION); props.put(Member.CU_TYPE_PROP,"my.user.role"); reg = bc.registerService(Action.class.getName(), this, props); } public void stop(BundleContext bc) throws Exception { if (reg != null) { reg.unregister(); } }}