Skip to content

ObsSM Listener Developing Guide

Javier Fuentes edited this page May 30, 2016 · 5 revisions

Custom Listener Developing Guide

ObsSM Interpreter

First you need to know how ObsSM works!

The interpreter works using a SCXML Framework Apache commons scxml this framework is used to read and parse the SCXML Model and execute the transitions.

We developed a simple JSON parser who translate a log line message like:

2016-05-29T10:57:21.451 CONTROL/Array002 alma.Control.ObservingModes.ArrayMountControllerImpl waitForSubscanStart Not waiting as the subscan started 25.675 seconds ago. 

and the parser says if is a legal event for the state machine or not.

The ObsSM read data from ElasticSearch and for each line log search first for a keyName (See more about keyName in Models) with this keyName the ObsSM has a StateMachineManager who has a single state machine for each keyName. The StateMachineManager is waiting on each line for a initial transition to initialize the State Machine.

The StateMachineManager controls the lifecycle of every StateMachine, and on every change over the StateMachine it has a EntryListener who implements a SCXMLListener class:

public interface SCXMLListener {

    /**
     * Handle the entry into a TransitionTarget.
     *
     * @param state The TransitionTarget entered
     */
    void onEntry(TransitionTarget state);

    /**
     * Handle the exit out of a TransitionTarget.
     *
     * @param state The TransitionTarget exited
     */
    void onExit(TransitionTarget state);

    /**
     * Handle the transition.
     *
     * @param from The source TransitionTarget
     * @param to The destination TransitionTarget
     * @param transition The Transition taken
     */
    void onTransition(TransitionTarget from, TransitionTarget to,
            Transition transition);
}

In order to simplify the acquisition of vars relatives to a transitions we made another version:

public abstract class EntryListener implements SCXMLListener {

    /**
     * Parent state machine execution.
     */
    protected StateMachine stateMachine = null;

    /**
     * Global Manager instance.
     */
    protected final Manager manager;

    /**
     *
     * @param manager
     */
    public EntryListener(Manager manager) {
        this.manager = manager;
    }
    
    /**
     * This method will be executed after the parent State machine receive a keyName.
     */
    public abstract void initialize();
    
    
    @Override
    public void onTransition(TransitionTarget from, TransitionTarget to, Transition transition) {
        onTransition(from, to, transition, Parser.savedArray, Parser.savedTimeStamp, Parser.savedLogLine);
    }
    
    /**
     * this methods allow to execute what you need, on every transition.
     * 
     * @param from
     * @param to
     * @param transition
     * @param array
     * @param timeStamp
     * @param logLine
     */
    public abstract void onTransition(TransitionTarget from, TransitionTarget to, Transition transition, String array, String timeStamp, String logLine);
}

So, we can look an example: This is the default EntryListener.

public class DefaultEntryListener extends EntryListener {

    public DefaultEntryListener(Manager manager) {
        super(manager);
    }

    @Override
    public void onEntry(TransitionTarget state) {
    }

    @Override
    public void onExit(TransitionTarget state) {
    }

    @Override
    public void onTransition(TransitionTarget from, TransitionTarget to, Transition transition, String array, String timeStamp, String logline) {
        System.out.println("ARRAY: "+array+" EVENT: " + transition.getEvent() + " TO: " + to.getId() + " FROM: " + from.getId() + " TS: " + timeStamp);
    }

    @Override
    public void initialize() {
    }

}

Example

To create an example we are going to use a similiar code of above.

CustomEntryListener:

import org.alma.obssm.Manager;
import org.alma.obssm.sm.EntryListener;
import org.apache.commons.scxml.model.Transition;
import org.apache.commons.scxml.model.TransitionTarget;

public class CustomEntryListener extends EntryListener {

    public CustomEntryListener(Manager manager) {
        super(manager);
    }

    @Override
    public void onEntry(TransitionTarget state) {
    }

    @Override
    public void onExit(TransitionTarget state) {
    }

    @Override
    public void onTransition(TransitionTarget from, TransitionTarget to, Transition transition, String array, String timeStamp, String logline) {
        System.out.println("ARRAY: "+array+" EVENT: " + transition.getEvent() + " TO: " + to.getId() + " FROM: " + from.getId() + " TS: " + timeStamp);
    }

    @Override
    public void initialize() {
        System.out.println("I am the array: " + getParent().getKeyName());
    }

}

Now we have to compile it!

We suppose you're in the ObsSM folder. And you've compiled the ObsSM

Compiling process:

javac -classpath .:target/ObsSM-1.0.jar:target/dependency/commons-scxml-0.9.jar CustomEntryListener.java
jar cf CustomEntryListener.jar CustomEntryListener.class

Execution:

./obssm.sh -c --date_from="2016-05-22T21:16:22.037" --date_to="2016-05-23T21:16:22.037" --query="*" --listener="CustomEntryListener.jar:CustomEntryListener"

Now we have a custom listener. Maybe you want to interconnect data between state machines. On every StateMachine a listener is created, so you can use static vars to share data between all the instances.

Like this:

public class GraphViewer extends EntryListener{

    public static Viewer view = null;
    public GraphViewer(Manager m) {
        super(m);
        if (view == null) {
            view = new Viewer();
        }
    }
Clone this wiki locally