You are not logged in. Click here to log in.

Application Lifecycle Management

Search In Project

Search inClear

Tags:  not added yet

OMS Execution API


This document describes the OMS runtime and execution API that allows the programmatic execution of OMS models within other applications. It is a part of OMS version 2.1.

API (org.oms.model.runtime.*)

The package org.oms.model.runtime.* contains all the classes that are required for programmatic model execution control. The class Execution allows for full control of OMS model execution. The interface ExecutionStateListener and the enum State help managing feedback during execution.

ExecutionStateListener.java

The ExecutionStateListener can be added to a Execution Object and receives notifications if a model state changes during execution and a component gets invoked.

package org.oms.model.runtime;

import java.util.EventListener;

/** Model state execution listener.
 *
 * @author Olaf David
 */
public interface ExecutionStateListener extends EventListener {

    /** Fired, if the model changes stated during execution
     * @param state the new State
     */
    void stateChanged(State state);

    /** Fired, if a component was invoked.
     *
     * @param name the name of the component that got invoked.
     */
    void componentInvoked(String name);
}

Listing 1: Interface ExecutionStateListener

State.java

The enum State decribes different model states during execution. A current state gets passed in as an argument into the stateChanged method in Listing 1 and gets returned from the execute() call in Execution.

 /** Different model states that can be reported in a state event
 *
 * @author Olaf David
 */
public enum State {
    /** Model reloaded */
    RELOADED,

    /** Model execution started */
    STARTED,

    /** Model execution done and succeeded */
    SUCCEEDED,

    /** Unknown state */
    UNKNOWN,

    /** Model Execution failed. Call Exception.getExecption() to find out
     * what the problem is. */
    FAILED;
}

Listing 2: enum State

Execution.java

The class Execution is being used to interact with the OMS runtime system for model execution.

/** Model Runtime Execution API.
 *
 * @author Olaf David
 */
public abstract class Execution {

    /**
     * Create an Execution instance for a given model.
     * It loads the model.
     *
     * @param modelFile the model to load
     * @throws java.io.Exception if there is a loading problem
     * @return Execution instance
     */
    public static Execution create(File modelFile) throws Exception;


    /** Set the parameter sets.
     * @param parameterFile the files to apply
     * @throws java.io.IOException
     */
    public abstract void setParameterSet(File ... parameterFile) throws IOException;


    /** Set parameter directely via properties.
     * @param props the additional properties to set.
     */
    public abstract void setParameterProperties(Properties props);


    /** Set the input directory.
     * @param input the input directory to use
     * @throws java.io.IOException
     */
    public abstract void setInputDir(File input) throws IOException;


    /** Set the ouput directory.
     * @param output the output directory to use
     * @throws java.io.IOException
     */
    public abstract void setOutputDir(File output) throws IOException;


    /** Execute the model synchronously.
     * @return the State at the end of execution (FAILED or SUCCEEDED)
     */
    public abstract State execute();

   
    /** Add a state listener to the model runtime
     * @param l the listener to add
     */
    public abstract void addExecutionListener(ExecutionStateListener l);


    /** Remove a ExecutionStateListener
     * @param l the listener to remove
     */
    public abstract void removeExecutionListener(ExecutionStateListener l);


    /** Get the name of all components, that are
     * part of the model
     */
    public abstract String[] getComponents();


    /** Get the names of block components.
     * @return array of block component names
     */
    public abstract String[] getBlockComponents();

    /** Get all the Attribute names in a block
     * @param block the block name
     * @return array of declared attributes in a block
     */
    public abstract Attribute[] getAttributes(String block);

    /** If model execution failed, this returns the exection
     * that caused the failure
     * @return the exception being thrown that stopped the model
     */
    public abstract Throwable getException();

    /** Reloads a model
     */
    public void reload() throws Exception;
}
Listing 3: class execution.

Compile and Runtime Dependencies

To successfully compile an application that should use the Execution API, you need to put the jar org-omscentral-modules-omsapi.jar into your compiler classpath. This jar file contains the classes, interfaces, and enum that is listed above.

To run an application that is using the API you need to put the following jar files into your application's classpath:

  • org-omscentral-modules-omsapi.jar
  • org-omscentral-modules-omscore.jar
  • org-omscentral-modules-tableapi.jar
  • org-omscentral-modules-tableio.jar
  • qdox-1.6.jar
  • units.jar

You find all these jar files in the OMS installation folder.

Example Application

The example below shows a very simple java class that executes the Thornthwaite example model

package runtimeexample;

import java.io.File;
import java.util.Arrays;

import org.oms.model.data.Attribute;                                                         (1)
import org.oms.model.runtime.Execution;
import org.oms.model.runtime.ExecutionStateListener;
import org.oms.model.runtime.State;

/**
 *
 * @author Olaf David
 */
public class Main {

    public static void main(String[] args) throws Exception {
 
        // Set the workspace folder
        File workspace = new File("D:/oms21/thornthwaite/");
 
        // Create an Execution Object                                                         (2)
        Execution e = Execution.create(new File(workspace, "models/thornthwaite.jma"));
 

        // Lookup some Attributes                                                             (3)
        Attribute a[] = e.getAttributes("TimeLoop");        
        final Attribute.Calendar currentTime = (Attribute.Calendar) find(a, "currentTime");
        final Attribute.Double runoff = (Attribute.Double) find(a, "runoff");

 
        // Set up some folders                                                                (4)
        e.setParameterSet(new File(workspace, "data/thornthwaite.pps"));
        e.setInputDir(new File(workspace, "data"));
        e.setOutputDir(new File(workspace, "output"));
 
        // Add an execution listener                                                          (5)
        e.addExecutionListener(new ExecutionStateListener() {
            public void componentInvoked(String name) {
                if (name.equals("Output")) {
                    System.out.println(currentTime.getMonth() + ": " + runoff.getValue());
                }
            }
            public void stateChanged(State state) {
                System.out.println("State " + state);
            }
        });
 
        // Explore the model content.                                                          (6)
        System.out.println("Components " + Arrays.asList(e.getComponents()));
        System.out.println("Block Components " + Arrays.asList(e.getBlockComponents()));
        System.out.println("TimeLoop Attributes " + Arrays.asList(a));
 
        // execute the model.                                                                  (7)
        State result = e.execute();
        System.out.println("Finished with exit status: " + result);
    }

    // helper method
    static private Attribute find(Attribute[] attrs, String name) {
        for (Attribute a : attrs)
            if (a.getName().equals(name))
                return a;
        return null;
    }
}

The rest of this document describes the sections as pointed out in the example above.

(1) Import required API classes
Import all required classes/interfaces/enums that let you interact with the runtime system and Attributes. You have to add at least the classes and interfaces from org.oms.model.runtime
(2) Obtain an Execution object
Obtain the execution instance using the Execution.create() method. This call results in an instance that is not shared and thread safe.
(3) Lookup some Attributes
Use the API to find attributes in the model. Attribute Lookup is context specific to the a block.
(4) Set the Model environment
Set the model IO folder, load parameter sets
(5) Add execution listener
Add custom execution listener to the executor. I the example above it is being used to print out the current month and the runoff every time the Output Component gets executed ( A graph component could be used here instead. )
(6) Explore the content
There are more API methods available that show the content of the model
(7) Execution
The model gets executed synchronously and returns an execution result.

The output of the application above is shown below:

Components [gov.usgs.thornthwaite.Climate, gov.usgs.thornthwaite.Daylen,
ov.usgs.thornthwaite.HamonET, gov.usgs.thornthwaite.SoilMoisture, gov.usgs.thornthwaite.Snow,
gov.usgs.thornthwaite.Runoff, gov.usgs.thornthwaite.Output]
Block Components [Thornthwaite, TimeLoop]
TimeLoop Attributes [generic:0.0, pmpe:0.0, condition:false,
soilMoistStor:0.0, outFile, currentTime, snowStorage:0.0, precip:0.0, actET:0.0,
climateInput, dff:0.0, runoff:0.0, temp:0.0, potET:0.0, daylength:0.0, snowMelt:0.0, surfaceRunoff:0.0]

State STARTED
1: 75.0
2: 47.9275233444456
3: 26.1201468779645
4: 13.06007343898225
5: 22.004395133246266
6: 11.002197566623133
7: 5.5010987833115665
....

10: 2.33398146011457
11: 1.166990730057285
12: 0.5834953650286425
12: 0.29174768251432126
State SUCCEEDED
Finished with exit status: SUCCEEDED