Skip to content
Julien Eberle edited this page Jul 23, 2014 · 1 revision

Scriptlet

This Processor (processing class) executes a scriptlet upon reception of a new StreamElement and can be used to implement arbitrary complex processing class by specifying its logic directly in the virtual sensor description file. This way of implementing processing classes offer a higher level of flexibility. As the script is defined in the Virtual Sensor description file, the implementation can be quickly and easily modified with no need to edit, compile Java code nor to restart GSN. However, after each script modification, the Virtual Sensor will be automatically reloaded and will execute the last version of the script.

The current implementation supports the Groovy (http://groovy.codehaus.org) scripting language which offers an access to all the GSN java objects and libraries available in the classpath.

Data Binding

This processor automatically binds the data between the StreamElement and the variables of the scriptlet. It executes the script against each StreamElement available from the Virtual Sensor sources. Upon reception a new StreamElement, a Context containing all its variables (and their values) is created and passed to the script for execution. When the script completes, it returns the updated Context containing the updated variables as well as those created in the script. Based on the returned Context, a new StreamElement matching the output structure defined in the Virtual Sensor description file is created and may be stored.

State

In order to save the state of a variable for the next evaluation, the following code is automatically added to your script:

def isdef(var) {
    (binding.getVariables().containsKey(var))
}

It can be used for initializing or updating a variable like below:

statefulCounter = isdef("statefulCounter") ? statefulCounter + 1 : 0;

Predefined Variable

The following variable contains all the bindings (variable name, variable value) and is accessible in your scriptlet. Moreover, all the variables in the binding objects are directly accessible in your script as defined and initialized variables.

groovy.lang.Binding binding                This contains the variables binded to your scriptlet.

// If the variableName is defined, then the following holds
binding.getVariable("variableName") == variableName

Typical Usage

This processing class is especially useful for setting up flexible, complex and DBMS independent calibration functions. See the Example 2.

Parameters

  • persistant Sets whether or not a StreamElement (matching the OutputStructure) is created and stored in the DB, at the end of the scriplet execution.
  • scriptlet The actual script code which implements the processor logic.

Example 1

<class-name>gsn.processor.ScriptletProcessor</class-name>
<init-params>
    <param name="persistant">true</param>
    <param name="scriptlet">
        <![CDATA[
        //------------------------------
        // Demo scriptlet
        //------------------------------

        // Example of accessing the list of bindings
        println 'binding: ' + binding.getVariables();

        // Example of usage of a stateful variable
        //
        def isdef(var) {
            (binding.getVariables().containsKey(var))
        }
        // Initialisation
        statefulCounter = isdef('statefulCounter') ? statefulCounter + 1 : 0;
        println 'Stateful Counter: ' + statefulCounter;

        // Example of getting a logger
        def logger = org.apache.log4j.Logger.getLogger(gsn.processor.ScriptletProcessor.class);

        // Define a variable x (variables defined with the def keywords are 'local' ant then not returned in the Context)
        def x = 1000;

        // The HEAP field is automatically binded from the stream1
        logger.warn('The HEAP value before calibration: ' + HEAP);

        // The HEAP field is calibrated based on the variable x and using an external library (apache commons-math: http://commons.apache.org/math/)
        HEAP = HEAP / x + (10000 + org.apache.commons.math.util.MathUtils.factorial(8));

        println 'The HEAP value after calibration: ' + HEAP;

        // We set a random value for the PENDING_FINALIZATION_COUNT
        PENDING_FINALIZATION_COUNT += Math.random();

        // The NON_HEAP value is not modified.

        ]]>
    </param>
</init-params>
 ...

Example 2

This Virtual Sensor description file calibrates the HEAP and NON_HEAP fields from the MemoryMonitorVS virtual sensor.

<virtual-sensor name="MemoryMonitorCalibratedVS" priority="1"">
    <processing-class>
        <class-name>gsn.processor.ScriptletProcessor</class-name>
        <init-params>
            <param name="persistant">true</param>
            <param name="scriptlet">
                <![CDATA[

		def p1 = -3.171e-23;
            	def p2 = 1.868e-19;
            	def p3 = -4.779e-16;
            	def p4 = 6.957e-13;
            	def p5 = -6.337e-10;
            	def p6 = 3.735e-7;
            	def p7 = -0.0001421;
            	def p8 = 0.03357;
            	def p9 = -4.463;
            	def p10 = 258.4;
		
		def rawValue = HEAP; 

		HEAP_CAL = p1 * Math.pow(rawValue, 9) + p2 * Math.pow(rawValue, 8) + p3 * Math.pow(rawValue, 7) + p4 * Math.pow(rawValue, 6) + p5 * Math.pow(rawValue, 5) + p6 * Math.pow(rawValue, 4) + p7 * Math.pow(rawValue, 3) + p8 * Math.pow(rawValue, 2) + p9 * rawValue + p10;

		NON_HEAP_CAL = HEAP_CAL / 1000.0;

		if (NON_HEAP_CAL <= 1) {
     			NON_HEAP_CAL = -20.0 * (NON_HEAP_CAL * (1.0 + 0.018 * (NON_HEAP_CAL - 24.0)) - 0.55);
            	} else if (NON_HEAP_CAL <= 8) {
                	NON_HEAP_CAL = (-3.213 * NON_HEAP_CAL - 4.093) / (1.0 - 0.009733 * NON_HEAP_CAL - 0.01205 * NON_HEAP_CAL);
            	} else {
                	NON_HEAP_CAL = -2.246 - 5.239 * NON_HEAP_CAL * (1.0 + 0.018 * (NON_HEAP_CAL - 24.0)) - 0.06756 * Math.pow(1.0 + 0.018 * (NON_HEAP_CAL - 24.0), 2);
            	}
                
		]]>
            </param>
        </init-params>
        <output-structure>
            <field name="HEAP_CAL" type="double"/>
            <field name="NON_HEAP_CAL" type="double"/>
        </output-structure>
    </processing-class>
    <description/>
    <addressing/>
    <storage history-size="1"/>
    <streams>
        <stream name="stream1">
            <source alias="source1" storage-size="1" sampling-rate="1">
                <address wrapper="local">
                    <predicate key="name">MemoryMonitorVS</predicate>
                </address>
                <query>select * from wrapper</query>
            </source>
            <query>select * from source1</query>
        </stream>
    </streams>
</virtual-sensor>
Clone this wiki locally