private void intervalSave(PointValueTime pvt) { synchronized (intervalLoggingLock) { if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.MAXIMUM) { if (intervalValue == null) intervalValue = pvt; else if (pvt != null) { if (intervalValue.getDoubleValue() < pvt.getDoubleValue()) intervalValue = pvt; } } else if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.MINIMUM) { if (intervalValue == null) intervalValue = pvt; else if (pvt != null) { if (intervalValue.getDoubleValue() > pvt.getDoubleValue()) intervalValue = pvt; } } else if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.AVERAGE) { // Using the averaging values, ensure we keep the most recent values and pop off the old // ones if (vo.isOverrideIntervalLoggingSamples()) { while (averagingValues.size() >= vo.getIntervalLoggingSampleWindowSize()) { averagingValues.remove(0); // Size -1 for the next item we are going to add } } averagingValues.add(pvt); } } }
// // // Single value // @Override public PointValueTime getPointValueBefore(long time) { for (PointValueTime pvt : valueCache.getCacheContents()) { if (pvt.getTime() < time) return pvt; } return Common.databaseProxy.newPointValueDao().getPointValueBefore(vo.getId(), time); }
@Override public PointValueTime getPointValueAfter(long time) { List<PointValueTime> pvts = valueCache.getCacheContents(); for (int i = pvts.size() - 1; i >= 0; i--) { PointValueTime pvt = pvts.get(i); if (pvt.getTime() >= time) return pvt; } return Common.databaseProxy.newPointValueDao().getPointValueAfter(vo.getId(), time); }
@Override public List<PointValueTime> getPointValuesBetween(long from, long to) { List<PointValueTime> result = Common.databaseProxy.newPointValueDao().getPointValuesBetween(vo.getId(), from, to); for (PointValueTime pvt : valueCache.getCacheContents()) { if (pvt.getTime() >= from && pvt.getTime() < to) { int index = Collections.binarySearch(result, pvt, pvtTimeComparator); if (index < 0) result.add(-index - 1, pvt); } } return result; }
@Override public void scheduleTimeout(long fireTime) { synchronized (intervalLoggingLock) { DataValue value; if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.INSTANT) value = PointValueTime.getValue(pointValue); else if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.MAXIMUM || vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.MINIMUM) { value = PointValueTime.getValue(intervalValue); intervalValue = pointValue; } else if (vo.getIntervalLoggingType() == DataPointVO.IntervalLoggingTypes.AVERAGE) { // We won't allow logging values until we have a full average window // If we don't have enough averaging values then we will bail and wait for more if (vo.isOverrideIntervalLoggingSamples() && (averagingValues.size() != vo.getIntervalLoggingSampleWindowSize())) return; IValueTime endValue = intervalValue; if (!averagingValues.isEmpty()) endValue = averagingValues.get(averagingValues.size() - 1); AnalogStatistics stats = new AnalogStatistics( intervalStartTime, fireTime, intervalValue, averagingValues, endValue); if (stats.getAverage() == null) value = null; else value = new NumericValue(stats.getAverage()); // Compute the center point of our average data, starting by finding where our period // started long sampleWindowStartTime; if (vo.isOverrideIntervalLoggingSamples()) sampleWindowStartTime = averagingValues.get(0).getTime(); else sampleWindowStartTime = intervalStartTime; intervalStartTime = fireTime; fireTime = sampleWindowStartTime + (fireTime - sampleWindowStartTime) / 2L; // Fix to simulate center tapped filter (un-shift the average) intervalValue = pointValue; if (!vo.isOverrideIntervalLoggingSamples()) averagingValues.clear(); } else throw new ShouldNeverHappenException( "Unknown interval logging type: " + vo.getIntervalLoggingType()); if (value != null) valueCache.logPointValueAsync(new PointValueTime(value, fireTime), null); } }
// // // Lifecycle // @Override public void initialize() { // Get the latest value for the point from the database. pointValue = valueCache.getLatestPointValue(); // Set the tolerance origin if this is a numeric if (pointValue != null && pointValue.getValue() instanceof NumericValue) toleranceOrigin = pointValue.getDoubleValue(); // Add point event listeners for (PointEventDetectorVO ped : vo.getEventDetectors()) { if (detectors == null) detectors = new ArrayList<PointEventDetectorRT>(); PointEventDetectorRT pedRT = ped.createRuntime(); detectors.add(pedRT); pedRT.initialize(); Common.runtimeManager.addDataPointListener(vo.getId(), pedRT); } initializeIntervalLogging(); }
@Override public void execute() { if (backdate) listener.pointBackdated(newValue); else { // Always fire this. listener.pointUpdated(newValue); // Fire if the point has changed. if (!PointValueTime.equalValues(oldValue, newValue)) listener.pointChanged(oldValue, newValue); // Fire if the point was set. if (set) listener.pointSet(oldValue, newValue); } }
private void savePointValue( PointValueTime newValue, SetPointSource source, boolean async, boolean saveToDatabase) { // Null values are not very nice, and since they don't have a specific meaning they are hereby // ignored. if (newValue == null) return; // Check the data type of the value against that of the locator, just for fun. int valueDataType = DataTypes.getDataType(newValue.getValue()); if (valueDataType != DataTypes.UNKNOWN && valueDataType != vo.getPointLocator().getDataTypeId()) // This should never happen, but if it does it can have serious downstream consequences. Also, // we need // to know how it happened, and the stack trace here provides the best information. throw new ShouldNeverHappenException( "Data type mismatch between new value and point locator: newValue=" + DataTypes.getDataType(newValue.getValue()) + ", locator=" + vo.getPointLocator().getDataTypeId()); // Check if this value qualifies for discardation. if (vo.isDiscardExtremeValues() && DataTypes.getDataType(newValue.getValue()) == DataTypes.NUMERIC) { double newd = newValue.getDoubleValue(); if (newd < vo.getDiscardLowLimit() || newd > vo.getDiscardHighLimit()) // Discard the value return; } if (newValue.getTime() > System.currentTimeMillis() + SystemSettingsDao.getFutureDateLimit()) { // Too far future dated. Toss it. But log a message first. LOG.warn( "Future dated value detected: pointId=" + vo.getId() + ", value=" + newValue.getStringValue() + ", type=" + vo.getPointLocator().getDataTypeId() + ", ts=" + newValue.getTime(), new Exception()); return; } boolean backdated = pointValue != null && newValue.getTime() < pointValue.getTime(); // Determine whether the new value qualifies for logging. boolean logValue; // ... or even saving in the cache. boolean saveValue = true; switch (vo.getLoggingType()) { case DataPointVO.LoggingTypes.ON_CHANGE: if (pointValue == null) logValue = true; else if (backdated) // Backdated. Ignore it logValue = false; else { if (newValue.getValue() instanceof NumericValue) { // Get the new double double newd = newValue.getDoubleValue(); // See if the new value is outside of the tolerance. double diff = toleranceOrigin - newd; if (diff < 0) diff = -diff; if (diff > vo.getTolerance()) { toleranceOrigin = newd; logValue = true; } else logValue = false; } else logValue = !ObjectUtils.equals(newValue.getValue(), pointValue.getValue()); } saveValue = logValue; break; case DataPointVO.LoggingTypes.ALL: logValue = true; break; case DataPointVO.LoggingTypes.ON_TS_CHANGE: if (pointValue == null) logValue = true; else if (backdated) // Backdated. Ignore it logValue = false; else logValue = newValue.getTime() != pointValue.getTime(); saveValue = logValue; break; case DataPointVO.LoggingTypes.INTERVAL: if (!backdated) intervalSave(newValue); default: logValue = false; } if (!saveToDatabase) logValue = false; if (saveValue) valueCache.savePointValue(newValue, source, logValue, async); // add annotation to newValue before firing events so event detectors can // fetch the annotation if (source != null) { newValue = new AnnotatedPointValueTime( newValue.getValue(), newValue.getTime(), source.getSetPointSourceMessage()); } // Ignore historical values. if (pointValue == null || newValue.getTime() >= pointValue.getTime()) { PointValueTime oldValue = pointValue; pointValue = newValue; fireEvents(oldValue, newValue, source != null, false); } else fireEvents(null, newValue, false, true); }
public static DataValue getValue(PointValueTime pvt) { if (pvt == null) return null; return pvt.getValue(); }
public static boolean equalValues(PointValueTime pvt1, PointValueTime pvt2) { if (pvt1 == null && pvt2 == null) return true; if (pvt1 == null || pvt2 == null) return false; return ObjectUtils.equals(pvt1.getValue(), pvt2.getValue()); }