This document describes the writing of Rule Engine script service from scratch. By script services, dedicated APIs can be added to the RM functionality and can be accessed by Groovy scripts. Scripting can be used to appoint various management actions upon devices managed by the RM, as well as to operate the backend RM system itself.
It is obligatory for every script service to extend the com.prosyst.mprm.backend.rules.spi.ScriptService interface and to be registered as an OSGi service with a registration of ScriptService.SCRIPT_ALIAS property.
For the purpose of demonstration the script services writing we will create a service that manages simulated cameras attached to OSGi devices. The service will be able to change the camera settings and to provide information about the value of a certain camera feature (settings). It will also be notified when the settings of a camera have been changed on the camera itself. The script service will have a method for getting a camera object by camera ID. It also has to be able to communicate with the camera devices, that's why it will extend the MessageHandler interface which is part of the Messaging API, used for OSGi Device communication.
package com.prosyst.mprm.demos.rules;import com.prosyst.mprm.backend.rules.spi.ScriptService;// every script service must extend/implement the ScriptService interfacepublic interface CameraManager extends ScriptService { public Camera getCamera(String cameraId);}All script service classes must have a default constructor. It is used when creating a proxy via the CGLib Java library.
The CameraManager implementation:
package com.prosyst.mprm.demos.rules.impl;...import com.prosyst.mprm.backend.rules.spi.ScriptService;import com.prosyst.mprm.demos.rules.CameraManager;publicclass Activator implements BundleActivator {...publicvoid start(BundleContext bc)throws Exception { ... // instantiate and register the script service within the start method of the // bundle activatorCameraManager cameraManager =new CameraManagerImpl();registerScript(cameraManager);}privatevoid registerScript(CameraManager scriptSrv){Dictionary<String, Object> props =new Hashtable<String, Object>(1);// setting the mandatory script alias service registration propertyprops.put(ScriptService.SCRIPT_ALIAS, CameraManagerImpl.ALIAS);// making the service registrationscriptSrvReg = bc.registerService(CameraManager.class.getName(), scriptSrv, props);} ...}And its registration in the bundle activator:
package com.prosyst.mprm.demos.rules.impl;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.backend.rules.spi.ScriptService;import com.prosyst.mprm.demos.rules.CameraManager;public class Activator implements BundleActivator { private BundleContext bc = null; private ServiceRegistration scriptSrvReg = null; public void start(BundleContext bc) throws Exception { this.bc = bc; CameraManager cameraManager = new CameraManagerImpl(); registerScript(cameraManager); } public void stop(BundleContext context) throws Exception { scriptSrvReg = unregisterService(scriptSrvReg); } private void registerScript(CameraManager scriptSrv) { Dictionary<String, Object> props = new Hashtable<String, Object>(1); props.put(ScriptService.SCRIPT_ALIAS, CameraManagerImpl.ALIAS); scriptSrvReg = bc.registerService(CameraManager.class.getName(), scriptSrv, props); } private ServiceRegistration unregisterService(ServiceRegistration srvReg) { if (srvReg != null) { srvReg.unregister(); } return null; }}The OSGi bundle, where the script service is defined, must have a Maven dependency to gdm.rules.be.api. The bundle has to export the package where the script service interface will be placed and import dynamically all packages.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.prosyst.mprm.poms</groupId> <artifactId>be</artifactId> <version>SNAPSHOT</version> </parent> <groupId>com.prosyst.mprm.demos</groupId> <artifactId>rules.demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Camera Manager</name> <description /> <properties> <Bundle-Category>demos</Bundle-Category> <Bundle-Activator>com.prosyst.mprm.demos.rules.impl.Activator</Bundle-Activator> <Export-Package> com.prosyst.mprm.demos.rules; version="1.0.0" </Export-Package> <DynamicImport-Package>*</DynamicImport-Package> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.7</version> <executions> <execution> <id>compile</id> <phase>process-resources</phase> <configuration> <target> <property name="compile_classpath" refid="maven.compile.classpath" /> <property name="runtime_classpath" refid="maven.runtime.classpath" /> <property name="test_classpath" refid="maven.test.classpath" /> <property name="plugin_classpath" refid="maven.plugin.classpath" /> <echo message="compile classpath: ${compile_classpath}" /> <echo message="runtime classpath: ${runtime_classpath}" /> <echo message="test classpath: ${test_classpath}" /> <echo message="plugin classpath: ${plugin_classpath}" /> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.prosyst.mprm.gdm</groupId> <artifactId>gdm.rules.be.api</artifactId> <version>1.0.1-SNAPSHOT</version> </dependency> </dependencies></project>Now the CameraManager service is bound under the aliases 'cm' and 'cameraManager'. We can call its getCamera() method by typing either
cm.getCamera('camera1');or
cameraManager.getCamera('camera1');