Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
decodes.tsdb.algo.ExpressionParserAlgorithm Maven / Gradle / Ivy
Go to download
A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.
package decodes.tsdb.algo;
import decodes.tsdb.DbCompException;
import decodes.tsdb.ParmRef;
import decodes.tsdb.TimeSeriesIdentifier;
import decodes.tsdb.VarFlags;
import decodes.tsdb.algo.jep.JepContext;
import ilex.util.StringPair;
import ilex.var.IFlags;
import ilex.var.NamedVariable;
import org.nfunk.jep.SymbolTable;
import org.opendcs.annotations.algorithm.Algorithm;
import org.opendcs.annotations.algorithm.Input;
import org.opendcs.annotations.algorithm.Output;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Properties;
@Algorithm(description = "Allow up to 5 inputs labeled in1...in5 and two outputs labeled out1 and out2.\n" +
"Properties can include:\n" +
"- Time slice expressions labeled ex_, where is any string.\n" +
"- Pre-time slice expressions labeled pre_\n" +
"- Post-time slice expressions labeled post_\n" +
"\n" +
"Expressions are executed in sort order.")
public class ExpressionParserAlgorithm
extends decodes.tsdb.algo.AW_AlgorithmBase
{
@Input
public double in1;
@Input
public double in2;
@Input
public double in3;
@Input
public double in4;
@Input
public double in5;
JepContext jepContext = null;
public ExpressionParserAlgorithm()
{
}
// Enter any local class variables needed by the algorithm.
ArrayList preScript = new ArrayList();
ArrayList timeSliceScript = new ArrayList();
ArrayList postScript = new ArrayList();
private void addSubBase(SymbolTable symTab, String name, String part, String id)
{
int hyphen = id.indexOf('-');
if (hyphen > 0)
{
symTab.addVariable(name + ".sub" + part, id.substring(hyphen + 1));
symTab.addVariable(name + ".base" + part, id.substring(0, hyphen));
}
else // id is the base part by itself
symTab.addVariable(name + ".base" + part, id);
}
@Output
public NamedVariable out1 = new NamedVariable("out1", 0);
@Output
public NamedVariable out2 = new NamedVariable("out2", 0);
@org.opendcs.annotations.PropertySpec(value="")
public String pre_1 = "";
@org.opendcs.annotations.PropertySpec(value="")
public String ex_1 = "";
@org.opendcs.annotations.PropertySpec(value="")
public String post_1 = "";
private void executeScript(ArrayList script)
{
// Remove outputs from the symbol table so that I can detect assignments after execution.
for(String nm: getOutputNames())
jepContext.getParser().getSymbolTable().remove(nm);
int idx = 0;
jepContext.setOnErrorLabel(null);
// jepContext.setAllowAssignment(true);
// jepContext.setAllowUndeclared(true);
while(idx >= 0 && idx < script.size())
{
StringPair label_expr = script.get(idx);
String expr = label_expr.second;
debug2("Executing expression[" + idx + "]: " + expr);
jepContext.reset();
jepContext.getParser().parseExpression(expr);
Object value = jepContext.getParser().getValueAsObject();
if (jepContext.getParser().hasError() || value == null)
{
debug2("Expression '" + expr + "' resulted in error: " + jepContext.getParser().getErrorInfo());
String lab = jepContext.getOnErrorLabel();
if (lab != null)
idx = findLabel(script, lab);
else
idx = -1;
}
else if (jepContext.getGotoLabel() != null)
idx = findLabel(script, jepContext.getGotoLabel());
else if (jepContext.isExitCalled())
idx = -1;
else
idx++;
}
}
private int findLabel(ArrayList script, String label)
{
for(int ret = 0; ret < script.size(); ret++)
if (script.get(ret).first.equalsIgnoreCase(label))
return ret;
return -1;
}
/**
* Algorithm-specific initialization provided by the subclass.
*/
protected void initAWAlgorithm( )
throws DbCompException
{
_awAlgoType = AWAlgoType.TIME_SLICE;
// Code here will be run once, after the algorithm object is created.
jepContext = new JepContext(tsdb, this);
// Extract the three scripts (pre, time-slice, and post) from the properties.
Properties props = comp.getProperties();
for(Object key : props.keySet())
{
String propName = key.toString();
String value = props.getProperty(propName);
if (propName.toLowerCase().startsWith("pre_"))
preScript.add(new StringPair(propName, value));
else if (propName.toLowerCase().startsWith("ex_"))
timeSliceScript.add(new StringPair(propName, value));
else if (propName.toLowerCase().startsWith("post_"))
postScript.add(new StringPair(propName, value));
}
if (preScript.size() == 0 && timeSliceScript.size() == 0 && postScript.size() == 0)
throw new DbCompException("ExpressionParser.init: No expressions found in properties.");
// Sort all the scripts by label (i.e. prop name)
Comparator spcomp =
new Comparator()
{
@Override
public int compare(StringPair sp1, StringPair sp2)
{
return sp1.first.compareTo(sp2.first);
}
};
Collections.sort(preScript, spcomp);
Collections.sort(timeSliceScript, spcomp);
Collections.sort(postScript, spcomp);
}
/**
* This method is called once before iterating all time slices.
*/
protected void beforeTimeSlices()
throws DbCompException
{
// This code will be executed once before each group of time slices.
// For TimeSlice algorithms this is done once before all slices.
// For Aggregating algorithms, this is done before each aggregate
// period.
// Prepopulate the symbol table with the info about the parameters.
SymbolTable symTab = jepContext.getParser().getSymbolTable();
symTab.clear();
for(String inputName : getInputNames())
{
ParmRef pr = getParmRef(inputName);
if (pr != null && pr.compParm != null && pr.timeSeries != null
&& pr.timeSeries.getTimeSeriesIdentifier() != null)
{
TimeSeriesIdentifier tsid = pr.timeSeries.getTimeSeriesIdentifier();
for(String part : tsid.getParts())
{
part = part.toLowerCase();
symTab.addVariable(inputName + "." + part, tsid.getPart(part));
}
if (tsdb.isCwms())
{
// For CWMS, add sub/base for location, param, and version
addSubBase(symTab, inputName, "loc", tsid.getSiteName());
addSubBase(symTab, inputName, "param", tsid.getDataType().getCode());
addSubBase(symTab, inputName, "version", tsid.getPart("version"));
}
}
}
ParmRef parmRef = getParmRef("out1");
if (parmRef != null && parmRef.timeSeries != null
&& parmRef.timeSeries.getTimeSeriesIdentifier() != null)
{
TimeSeriesIdentifier tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
for(String part : tsid.getParts())
{
part = part.toLowerCase();
symTab.addVariable("out1." + part, tsid.getPart(part));
}
addSubBase(symTab, "out1", "loc", tsid.getSiteName());
addSubBase(symTab, "out1", "param", tsid.getDataType().getCode());
addSubBase(symTab, "out1", "version", tsid.getPart("version"));
}
parmRef = getParmRef("out2");
if (parmRef != null && parmRef.timeSeries != null
&& parmRef.timeSeries.getTimeSeriesIdentifier() != null)
{
TimeSeriesIdentifier tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
for(String part : tsid.getParts())
{
part = part.toLowerCase();
symTab.addVariable("out2." + part, tsid.getPart(part));
}
addSubBase(symTab, "out2", "loc", tsid.getSiteName());
addSubBase(symTab, "out2", "param", tsid.getDataType().getCode());
addSubBase(symTab, "out2", "version", tsid.getPart("version"));
}
jepContext.setTimeSliceBaseTime(null);
// The pre Script can't make any assignments. The user can use it to set
// defaults, lookup meta data and set variables in the symbol table, etc.
if (preScript.size() > 0)
executeScript(preScript);
}
/**
* Do the algorithm for a single time slice.
* AW will fill in user-supplied code here.
* Base class will set inputs prior to calling this method.
* User code should call one of the setOutput methods for a time-slice
* output variable.
*
* @throws DbCompException (or subclass thereof) if execution of this
* algorithm is to be aborted.
*/
protected void doAWTimeSlice()
throws DbCompException
{
// Enter code to be executed at each time-slice.
jepContext.setTimeSliceBaseTime(_timeSliceBaseTime);
// Add the inputs to the symbol table for this time slice.
SymbolTable symTab = jepContext.getParser().getSymbolTable();
for(String inputName : getInputNames())
{
double inputVal =
inputName.equals("in1") ? in1 :
inputName.equals("in2") ? in2 :
inputName.equals("in3") ? in3 :
inputName.equals("in4") ? in4 :
inputName.equals("in5") ? in5 : Double.NEGATIVE_INFINITY;
symTab.remove(inputName);
String flagName = inputName + ".flags";
symTab.remove(flagName);
if (!isMissing(inputVal))
{
symTab.addVariable(inputName, Double.valueOf(inputVal));
int f = getInputFlagBits(inputName);
symTab.addVariable(flagName, Double.valueOf(f));
debug1("" + debugSdf.format(_timeSliceBaseTime) + " " + inputName + "=" + inputVal
+ ", " + flagName + "=0x" + Integer.toHexString(f));
}
}
// Remove the outputs from the symbol table so we can detect assignments.
// Any user-defined temporary vars stay in the table. The user can use these
// for accumulating, counting, etc., across all time slices.
symTab.remove("out1");
symTab.remove("out1.flags");
symTab.remove("out2");
symTab.remove("out2.flags");
// Execute the script should at some point set an output or input flags.
executeScript(timeSliceScript);
// Check to see if assignments were made to the output variables.
Object out1value = jepContext.getParser().getSymbolTable().getValue("out1");
Object out1Flags = jepContext.getParser().getSymbolTable().getValue("out1.flags");
if (out1value != null)
{
debug3("out1 was set to " + out1value);
if (out1value instanceof Double)
setOutput(out1, (Double)out1value);
else if (out1value instanceof String)
setOutput(out1, (String)out1value);
if (out1Flags != null)
{
int f = (out1Flags instanceof Double) ? (int)(double)(Double)out1Flags
: (out1Flags instanceof Long) ? (int)(long)(Long)out1Flags
: 0;
debug3("out1.flags was set to 0x" + Integer.toHexString(f));
clearNonReservedFlags(out1);
setFlagBits(out1, f);
}
else debug3("out1.flags not assigned.");
}
else
{
debug3("out1 was not assigned.");
if (out1Flags != null)
warning("Cannot set out1.flags without also ssetting out1 value. Ignored.");
}
Object out2value = jepContext.getParser().getSymbolTable().getValue("out2");
Object out2Flags = jepContext.getParser().getSymbolTable().getValue("out2.flags");
if (out2value != null)
{
debug3("out2 was set to " + out2value);
if (out2value instanceof Double)
setOutput(out2, (Double)out2value);
else if (out2value instanceof String)
setOutput(out2, (String)out2value);
if (out2Flags != null)
{
int f = (out2Flags instanceof Double) ? (int)(double)(Double)out2Flags
: (out2Flags instanceof Long) ? (int)(long)(Long)out2Flags
: 0;
clearNonReservedFlags(out2);
setFlagBits(out2, f);
}
}
else
{
debug3("out2 was not assigned.");
if (out2Flags != null)
warning("Cannot set out2.flags without also ssetting out2 value. Ignored.");
}
// Check the input '.flags' values in the symbol table to see if any values were
// changed. If so, set the new flags and cause them to be written to the database.
for(String inputName : getInputNames())
{
String flagName = inputName + ".flags";
debug3("Checking for " + flagName);
org.nfunk.jep.Variable v = symTab.getVar(flagName);
if (v != null)
{
debug3("...found");
Object vv = v.getValue();
if (vv instanceof Number)
{
int newFlags = ((Number)vv).intValue();
int origFlags = this.getInputFlagBits(inputName);
debug3("origFlags=0x" + Integer.toHexString(origFlags) + ", newFlags=0x" + Integer.toHexString(newFlags));
if (newFlags != origFlags)
{
debug1("" + debugSdf.format(_timeSliceBaseTime) + " " + flagName +
" changed from 0x" + Integer.toHexString(origFlags)
+ " to 0x" + Integer.toHexString(newFlags));
// Clear all application-level bits and set to the new values.
setInputFlagBits(inputName, newFlags,
~(VarFlags.RESERVED_4_COMP|IFlags.RESERVED_MASK));
}
}
}
else debug3("...not found");
}
}
/**
* This method is called once after iterating all time slices.
*/
protected void afterTimeSlices()
throws DbCompException
{
// This code will be executed once after each group of time slices.
// For TimeSlice algorithms this is done once after all slices.
// For Aggregating algorithms, this is done after each aggregate
// period.
// Leave the base time alone. It should be set to the last base time seen
// in the time slices.
executeScript(postScript);
Object out1value = jepContext.getParser().getSymbolTable().getValue("out1");
if (out1value != null)
{
if (out1value instanceof Double)
setOutput(out1, (Double)out1value);
else if (out1value instanceof String)
setOutput(out1, (String)out1value);
}
Object out2value = jepContext.getParser().getSymbolTable().getValue("out2");
if (out2value != null)
{
if (out2value instanceof Double)
setOutput(out2, (Double)out2value);
else if (out2value instanceof String)
setOutput(out2, (String)out2value);
}
}
}