diff --git a/Core/src/com/serotonin/m2m2/rt/event/detectors/AbstractEventDetectorRT.java b/Core/src/com/serotonin/m2m2/rt/event/detectors/AbstractEventDetectorRT.java index 7c55978aa4..f23015d29b 100644 --- a/Core/src/com/serotonin/m2m2/rt/event/detectors/AbstractEventDetectorRT.java +++ b/Core/src/com/serotonin/m2m2/rt/event/detectors/AbstractEventDetectorRT.java @@ -4,7 +4,18 @@ */ package com.serotonin.m2m2.rt.event.detectors; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.serotonin.m2m2.Common; +import com.serotonin.m2m2.i18n.TranslatableMessage; +import com.serotonin.m2m2.rt.event.type.EventType; +import com.serotonin.m2m2.util.timeout.TimeoutClient; +import com.serotonin.m2m2.util.timeout.TimeoutTask; import com.serotonin.m2m2.vo.event.detector.AbstractEventDetectorVO; +import com.serotonin.timer.OneTimeTrigger; +import com.serotonin.timer.Task; /** * @@ -15,12 +26,88 @@ public abstract class AbstractEventDetectorRT> { protected T vo; + private TimeoutClient quiescentClient; + private Task quiescentTask; + private final long quiescentMillis; + private boolean quiescentState; + private Map quiescentContext; public AbstractEventDetectorRT(T vo){ this.vo = vo; + quiescentMillis = Common.getMillis(vo.getQuiescentPeriodType(), vo.getQuiescentPeriods()); + quiescentClient = new TimeoutClient() { + + @Override + public void scheduleTimeout(long fireTime) { + wakeup(); + } + + @Override + public String getTaskId() { + //XIDs unique as of 3.3 + return "EDQ-" + vo.getXid(); + } + + @Override + public String getThreadName() { + return vo.getXid() + " Quiescence"; + } + }; } public T getVO(){ return vo; } + + protected void raiseEvent(long time, Map context) { + if(quiescentMillis != 0 && quiescentTask != null) { + synchronized(this) { //get the lock and check + if(quiescentTask != null) { + quiescentState = true; + quiescentContext = context; + return; + } + } + } + + TranslatableMessage msg; + if (!StringUtils.isBlank(vo.getName())) + msg = new TranslatableMessage("common.default", vo.getName()); + else + msg = getMessage(); + + Common.eventManager.raiseEvent(getEventType(), time, vo.isRtnApplicable(), vo.getAlarmLevel(), msg, context); + } + + protected void returnToNormal(long time) { + quiescentState = false; + Common.eventManager.returnToNormal(getEventType(), time, vo.getAlarmLevel()); + if(quiescentMillis != 0) { + synchronized(this) { + if(quiescentTask != null) + quiescentTask.cancel(); + quiescentTask = new TimeoutTask(new OneTimeTrigger(quiescentMillis), quiescentClient); + } + } + } + + private void wakeup() { + boolean state; + Map context; + synchronized(this) { + state = quiescentState; + context = quiescentContext; + quiescentState = false; + quiescentContext = null; + quiescentTask = null; + } + + if(state) { + raiseEvent(Common.timer.currentTimeMillis(), context); + } + } + + protected abstract EventType getEventType(); + + abstract protected TranslatableMessage getMessage(); } diff --git a/Core/src/com/serotonin/m2m2/rt/event/detectors/PointEventDetectorRT.java b/Core/src/com/serotonin/m2m2/rt/event/detectors/PointEventDetectorRT.java index bc46eac001..be920a3596 100644 --- a/Core/src/com/serotonin/m2m2/rt/event/detectors/PointEventDetectorRT.java +++ b/Core/src/com/serotonin/m2m2/rt/event/detectors/PointEventDetectorRT.java @@ -7,11 +7,7 @@ import java.util.HashMap; import java.util.Map; -import org.apache.commons.lang3.StringUtils; - -import com.serotonin.m2m2.Common; import com.serotonin.m2m2.db.dao.DataPointTagsDao; -import com.serotonin.m2m2.i18n.TranslatableMessage; import com.serotonin.m2m2.rt.dataImage.DataPointListener; import com.serotonin.m2m2.rt.dataImage.PointValueTime; import com.serotonin.m2m2.rt.event.type.DataPointEventType; @@ -28,7 +24,6 @@ public PointEventDetectorRT(T vo) { super(vo); } - protected EventType getEventType() { DataPointEventType et = new DataPointEventType(vo.njbGetDataPoint().getId(), vo.getId()); if (!vo.isRtnApplicable()) @@ -36,20 +31,6 @@ protected EventType getEventType() { return et; } - protected void raiseEvent(long time, Map context) { - TranslatableMessage msg; - if (!StringUtils.isBlank(vo.getName())) - msg = new TranslatableMessage("common.default", vo.getName()); - else - msg = getMessage(); - - Common.eventManager.raiseEvent(getEventType(), time, vo.isRtnApplicable(), vo.getAlarmLevel(), msg, context); - } - - protected void returnToNormal(long time) { - Common.eventManager.returnToNormal(getEventType(), time, vo.getAlarmLevel()); - } - protected Map createEventContext() { Map context = new HashMap(); context.put("pointEventDetector", vo); @@ -61,9 +42,6 @@ protected Map createEventContext() { return context; } - - abstract protected TranslatableMessage getMessage(); - public abstract boolean isEventActive(); @Override diff --git a/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractEventDetectorVO.java b/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractEventDetectorVO.java index 8d3009e5b3..6e00275203 100644 --- a/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractEventDetectorVO.java +++ b/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractEventDetectorVO.java @@ -14,6 +14,7 @@ import com.serotonin.json.JsonReader; import com.serotonin.json.ObjectWriter; import com.serotonin.json.type.JsonObject; +import com.serotonin.m2m2.Common; import com.serotonin.m2m2.db.dao.AbstractDao; import com.serotonin.m2m2.db.dao.EventDetectorDao; import com.serotonin.m2m2.db.dao.EventHandlerDao; @@ -39,6 +40,10 @@ public abstract class AbstractEventDetectorVO eventHandler) { if(addedEventHandlers == null) addedEventHandlers = new ArrayList<>(); @@ -182,6 +205,12 @@ else if (!isXidUnique(xid, id)) if(EventHandlerDao.getInstance().getXidById(eh.getId()) == null) response.addMessage("handlers", new TranslatableMessage("emport.eventHandler.missing", eh.getXid())); } + + if(quiescentPeriods < 0) + response.addMessage("quiescentPeriods", new TranslatableMessage("validate.cannotBeNegative")); + + if(!Common.TIME_PERIOD_CODES.isValidId(quiescentPeriodType)) + response.addMessage("quiescentPeriodType", new TranslatableMessage("validate.invalidValueWithAcceptable", Common.TIME_PERIOD_CODES.getCodeList())); } @Override @@ -190,6 +219,8 @@ public void jsonWrite(ObjectWriter writer) throws IOException, JsonException { writer.writeEntry("sourceType", this.definition.getSourceTypeName()); writer.writeEntry("xid", xid); writer.writeEntry("name", name); + writer.writeEntry("quiescentPeriods", quiescentPeriods); + writer.writeEntry("quiescentPeriodType", quiescentPeriodType); /* Event handler references are not exported here because there would be a circular dependency * with the eventTypes array in the handler, and since there are other event types that was deemed @@ -209,5 +240,13 @@ public void jsonRead(JsonReader reader, JsonObject jsonObject) throws JsonExcept if(text != null) name = text; } + + if(jsonObject.containsKey("quiescentPeriods")) + quiescentPeriods = jsonObject.getInt("quiescentPeriods"); + + text = jsonObject.getString("quiescentPeriodType"); + if(text != null) { + quiescentPeriodType = Common.TIME_PERIOD_CODES.getId(text); + } } } diff --git a/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractPointEventDetectorVO.java b/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractPointEventDetectorVO.java index 731cfe0130..b7aed04623 100644 --- a/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractPointEventDetectorVO.java +++ b/Core/src/com/serotonin/m2m2/vo/event/detector/AbstractPointEventDetectorVO.java @@ -12,7 +12,6 @@ import com.serotonin.json.JsonReader; import com.serotonin.json.ObjectWriter; import com.serotonin.json.type.JsonObject; -import com.serotonin.json.type.JsonValue; import com.serotonin.m2m2.db.dao.DataPointDao; import com.serotonin.m2m2.i18n.ProcessResult; import com.serotonin.m2m2.i18n.TranslatableJsonException; @@ -32,8 +31,6 @@ public abstract class AbstractPointEventDetectorVO