diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityCondition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityCondition.java index 6da187e0e..d4eb3c903 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityCondition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityCondition.java @@ -16,8 +16,11 @@ */ package org.hawkular.alerts.api.model.condition; +import static org.hawkular.alerts.api.model.trigger.Trigger.Mode.FIRE; + import org.hawkular.alerts.api.log.MsgLogger; import org.hawkular.alerts.api.model.data.Availability.AvailabilityType; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * An availability condition definition. @@ -43,8 +46,13 @@ public AvailabilityCondition() { } public AvailabilityCondition(String triggerId, int conditionSetSize, int conditionSetIndex, - String dataId, Operator operator) { - super(triggerId, conditionSetSize, conditionSetIndex); + String dataId, Operator operator) { + this(triggerId, FIRE, conditionSetSize, conditionSetIndex, dataId, operator); + } + + public AvailabilityCondition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex, + String dataId, Operator operator) { + super(triggerId, triggerMode, conditionSetSize, conditionSetIndex); this.dataId = dataId; this.operator = operator; } @@ -85,14 +93,19 @@ public boolean match(AvailabilityType value) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; AvailabilityCondition that = (AvailabilityCondition) o; - if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) return false; - if (operator != that.operator) return false; + if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) + return false; + if (operator != that.operator) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityConditionEval.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityConditionEval.java index 4818f7b37..4d5b89a1a 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityConditionEval.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/AvailabilityConditionEval.java @@ -75,19 +75,24 @@ public int getConditionSetIndex() { @Override public String getLog() { - return condition.getLog(value); + return condition.getLog(value) + ", evalTimestamp=" + evalTimestamp + ", dataTimestamp=" + dataTimestamp; } @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; AvailabilityConditionEval that = (AvailabilityConditionEval) o; - if (condition != null ? !condition.equals(that.condition) : that.condition != null) return false; - if (value != that.value) return false; + if (condition != null ? !condition.equals(that.condition) : that.condition != null) + return false; + if (value != that.value) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareCondition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareCondition.java index f7d822a40..484ced6ab 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareCondition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareCondition.java @@ -16,7 +16,10 @@ */ package org.hawkular.alerts.api.model.condition; +import static org.hawkular.alerts.api.model.trigger.Trigger.Mode.FIRE; + import org.hawkular.alerts.api.log.MsgLogger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * A numeric comparison condition. @@ -45,8 +48,13 @@ public CompareCondition() { } public CompareCondition(String triggerId, int conditionSetSize, int conditionSetIndex, - String data1Id, Operator operator, Double data2Multiplier, String data2Id) { - super(triggerId, conditionSetSize, conditionSetIndex); + String data1Id, Operator operator, Double data2Multiplier, String data2Id) { + this(triggerId, FIRE, conditionSetSize, conditionSetIndex, data1Id, operator, data2Multiplier, data2Id); + } + + public CompareCondition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex, + String data1Id, Operator operator, Double data2Multiplier, String data2Id) { + super(triggerId, triggerMode, conditionSetSize, conditionSetIndex); this.data1Id = data1Id; this.operator = operator; this.data2Id = data2Id; @@ -110,17 +118,23 @@ public boolean match(double data1Value, double data2Value) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; CompareCondition that = (CompareCondition) o; - if (data1Id != null ? !data1Id.equals(that.data1Id) : that.data1Id != null) return false; - if (data2Id != null ? !data2Id.equals(that.data2Id) : that.data2Id != null) return false; + if (data1Id != null ? !data1Id.equals(that.data1Id) : that.data1Id != null) + return false; + if (data2Id != null ? !data2Id.equals(that.data2Id) : that.data2Id != null) + return false; if (data2Multiplier != null ? !data2Multiplier.equals(that.data2Multiplier) : that.data2Multiplier != null) return false; - if (operator != that.operator) return false; + if (operator != that.operator) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareConditionEval.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareConditionEval.java index 6521a6034..9f2d8fe7c 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareConditionEval.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/CompareConditionEval.java @@ -86,7 +86,8 @@ public int getConditionSetIndex() { @Override public String getLog() { - return condition.getLog(value1, value2); + return condition.getLog(value1, value2) + ", evalTimestamp=" + evalTimestamp + ", dataTimestamp=" + + dataTimestamp; } @Override diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/Condition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/Condition.java index 1d451ee17..cec6a848f 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/Condition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/Condition.java @@ -16,6 +16,8 @@ */ package org.hawkular.alerts.api.model.condition; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; + /** * A base class for condition definition. * @@ -29,6 +31,11 @@ public abstract class Condition { */ protected String triggerId; + /** + * The owning trigger's mode when this condition is active + */ + protected Mode triggerMode; + /** * Number of conditions associated with a particular trigger. * i.e. 2 [ conditions ] @@ -42,15 +49,16 @@ public abstract class Condition { protected int conditionSetIndex; /** - * A composed key for conditionId + * A composed key for the condition */ - protected String conditionId; + protected String id; - public Condition(String triggerId, int conditionSetSize, int conditionSetIndex) { + public Condition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex) { this.triggerId = triggerId; + this.triggerMode = triggerMode; this.conditionSetSize = conditionSetSize; this.conditionSetIndex = conditionSetIndex; - this.conditionId = triggerId + "-" + conditionSetSize + "-" + conditionSetIndex; + updateId(); } public int getConditionSetIndex() { @@ -59,6 +67,7 @@ public int getConditionSetIndex() { public void setConditionSetIndex(int conditionSetIndex) { this.conditionSetIndex = conditionSetIndex; + updateId(); } public int getConditionSetSize() { @@ -67,6 +76,7 @@ public int getConditionSetSize() { public void setConditionSetSize(int conditionSetSize) { this.conditionSetSize = conditionSetSize; + updateId(); } public String getTriggerId() { @@ -75,43 +85,59 @@ public String getTriggerId() { public void setTriggerId(String triggerId) { this.triggerId = triggerId; + updateId(); } - public String getConditionId() { - conditionId = triggerId + "-" + conditionSetSize + "-" + conditionSetIndex; - return conditionId; + public Mode getTriggerMode() { + return triggerMode; } - public void setConditionId(String conditionId) { - this.conditionId = conditionId; + public void setTriggerMode(Mode triggerMode) { + this.triggerMode = triggerMode; + updateId(); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Condition condition = (Condition) o; - - if (conditionSetIndex != condition.conditionSetIndex) return false; - if (conditionSetSize != condition.conditionSetSize) return false; - if (triggerId != null ? !triggerId.equals(condition.triggerId) : condition.triggerId != null) return false; + public String getConditionId() { + return id; + } - return true; + private void updateId() { + StringBuilder sb = new StringBuilder(triggerId); + sb.append("-").append(triggerMode.ordinal()); + sb.append("-").append(conditionSetSize); + sb.append("-").append(conditionSetIndex); + this.id = sb.toString(); } @Override public int hashCode() { - int result = triggerId != null ? triggerId.hashCode() : 0; - result = 31 * result + conditionSetSize; - result = 31 * result + conditionSetIndex; + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Condition other = (Condition) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + @Override public String toString() { - return "Condition [triggerId=" + triggerId + ", conditionSetSize=" + conditionSetSize + ", conditionSetIndex=" - + conditionSetIndex + ", conditionId=" + conditionId + "]"; + return "Condition [triggerId=" + triggerId + ", triggerMode=" + triggerMode + ", conditionSetSize=" + + conditionSetSize + ", conditionSetIndex=" + conditionSetIndex + "]"; } } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringCondition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringCondition.java index 49db68a32..a0a1de09e 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringCondition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringCondition.java @@ -17,6 +17,7 @@ package org.hawkular.alerts.api.model.condition; import org.hawkular.alerts.api.log.MsgLogger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * A string comparison condition. @@ -44,8 +45,13 @@ public StringCondition() { } public StringCondition(String triggerId, int conditionSetSize, int conditionSetIndex, - String dataId, Operator operator, String pattern, boolean ignoreCase) { - super(triggerId, conditionSetSize, conditionSetIndex); + String dataId, Operator operator, String pattern, boolean ignoreCase) { + this(triggerId, Mode.FIRE, conditionSetSize, conditionSetIndex, dataId, operator, pattern, ignoreCase); + } + + public StringCondition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex, + String dataId, Operator operator, String pattern, boolean ignoreCase) { + super(triggerId, triggerMode, conditionSetSize, conditionSetIndex); this.dataId = dataId; this.operator = operator; this.pattern = pattern; @@ -116,16 +122,23 @@ public boolean match(String value) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; StringCondition that = (StringCondition) o; - if (ignoreCase != that.ignoreCase) return false; - if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) return false; - if (operator != that.operator) return false; - if (pattern != null ? !pattern.equals(that.pattern) : that.pattern != null) return false; + if (ignoreCase != that.ignoreCase) + return false; + if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) + return false; + if (operator != that.operator) + return false; + if (pattern != null ? !pattern.equals(that.pattern) : that.pattern != null) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringConditionEval.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringConditionEval.java index fe4a4beb0..33f89b0f8 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringConditionEval.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/StringConditionEval.java @@ -74,7 +74,7 @@ public int getConditionSetIndex() { @Override public String getLog() { - return condition.getLog(value); + return condition.getLog(value) + ", evalTimestamp=" + evalTimestamp + ", dataTimestamp=" + dataTimestamp; } @Override diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdCondition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdCondition.java index c3076b326..4a602c743 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdCondition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdCondition.java @@ -17,6 +17,7 @@ package org.hawkular.alerts.api.model.condition; import org.hawkular.alerts.api.log.MsgLogger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * A numeric threshold condition. @@ -43,8 +44,14 @@ public ThresholdCondition() { } public ThresholdCondition(String triggerId, int conditionSetSize, int conditionSetIndex, - String dataId, Operator operator, Double threshold) { - super(triggerId, conditionSetSize, conditionSetIndex); + String dataId, Operator operator, Double threshold) { + + this(triggerId, Mode.FIRE, conditionSetSize, conditionSetIndex, dataId, operator, threshold); + } + + public ThresholdCondition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex, + String dataId, Operator operator, Double threshold) { + super(triggerId, triggerMode, conditionSetSize, conditionSetIndex); this.dataId = dataId; this.operator = operator; this.threshold = threshold; @@ -96,15 +103,21 @@ public boolean match(double value) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; ThresholdCondition that = (ThresholdCondition) o; - if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) return false; - if (operator != that.operator) return false; - if (threshold != null ? !threshold.equals(that.threshold) : that.threshold != null) return false; + if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) + return false; + if (operator != that.operator) + return false; + if (threshold != null ? !threshold.equals(that.threshold) : that.threshold != null) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdConditionEval.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdConditionEval.java index bf3dffdac..e2c120681 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdConditionEval.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdConditionEval.java @@ -74,7 +74,7 @@ public int getConditionSetIndex() { @Override public String getLog() { - return condition.getLog(value); + return condition.getLog(value) + ", evalTimestamp=" + evalTimestamp + ", dataTimestamp=" + dataTimestamp; } @Override diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeCondition.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeCondition.java index 3572dd017..aa1094c9d 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeCondition.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeCondition.java @@ -17,6 +17,7 @@ package org.hawkular.alerts.api.model.condition; import org.hawkular.alerts.api.log.MsgLogger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * A numeric threshold range condition. @@ -61,9 +62,17 @@ public ThresholdRangeCondition() { } public ThresholdRangeCondition(String triggerId, int conditionSetSize, int conditionSetIndex, - String dataId, Operator operatorLow, Operator operatorHigh, - Double thresholdLow, Double thresholdHigh, boolean inRange) { - super(triggerId, conditionSetSize, conditionSetIndex); + String dataId, Operator operatorLow, Operator operatorHigh, + Double thresholdLow, Double thresholdHigh, boolean inRange) { + + this(triggerId, Mode.FIRE, conditionSetSize, conditionSetIndex, dataId, operatorLow, operatorHigh, + thresholdLow, thresholdHigh, inRange); + } + + public ThresholdRangeCondition(String triggerId, Mode triggerMode, int conditionSetSize, int conditionSetIndex, + String dataId, Operator operatorLow, Operator operatorHigh, + Double thresholdLow, Double thresholdHigh, boolean inRange) { + super(triggerId, triggerMode, conditionSetSize, conditionSetIndex); this.dataId = dataId; this.operatorLow = operatorLow; this.operatorHigh = operatorHigh; @@ -162,19 +171,27 @@ public boolean match(double value) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; ThresholdRangeCondition that = (ThresholdRangeCondition) o; - if (inRange != that.inRange) return false; - if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) return false; - if (operatorHigh != that.operatorHigh) return false; - if (operatorLow != that.operatorLow) return false; + if (inRange != that.inRange) + return false; + if (dataId != null ? !dataId.equals(that.dataId) : that.dataId != null) + return false; + if (operatorHigh != that.operatorHigh) + return false; + if (operatorLow != that.operatorLow) + return false; if (thresholdHigh != null ? !thresholdHigh.equals(that.thresholdHigh) : that.thresholdHigh != null) return false; - if (thresholdLow != null ? !thresholdLow.equals(that.thresholdLow) : that.thresholdLow != null) return false; + if (thresholdLow != null ? !thresholdLow.equals(that.thresholdLow) : that.thresholdLow != null) + return false; return true; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeConditionEval.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeConditionEval.java index 54c47dbdb..4e6e44161 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeConditionEval.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/condition/ThresholdRangeConditionEval.java @@ -74,7 +74,7 @@ public int getConditionSetIndex() { @Override public String getLog() { - return condition.getLog(value); + return condition.getLog(value) + ", evalTimestamp=" + evalTimestamp + ", dataTimestamp=" + dataTimestamp; } @Override diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/dampening/Dampening.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/dampening/Dampening.java index 0f4768ca1..ac07e34ec 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/dampening/Dampening.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/dampening/Dampening.java @@ -23,6 +23,7 @@ import java.util.Set; import org.hawkular.alerts.api.model.condition.ConditionEval; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; /** * A representation of dampening status. @@ -36,6 +37,7 @@ public enum Type { }; private String triggerId; + private Mode triggerMode; private Type type; private int evalTrueSetting; private int evalTotalSetting; @@ -48,30 +50,32 @@ public enum Type { private List> satisfyingEvals = new ArrayList>(); public Dampening() { - this("Default", Type.RELAXED_COUNT, 0, 0, 0); + this("Default", Mode.FIRE, Type.STRICT, 1, 1, 0); } /** * Fire if we have numTrueEvals consecutive true evaluations of the condition set. There is * no time limit for the evaluations. * @param triggerId + * @param triggerMode the trigger mode for when this dampening is active * @param numConsecutiveTrueEvals * @return */ - public static Dampening forStrict(String triggerId, int numConsecutiveTrueEvals) { - return new Dampening(triggerId, Type.STRICT, numConsecutiveTrueEvals, numConsecutiveTrueEvals, 0); + public static Dampening forStrict(String triggerId, Mode triggerMode, int numConsecutiveTrueEvals) { + return new Dampening(triggerId, triggerMode, Type.STRICT, numConsecutiveTrueEvals, numConsecutiveTrueEvals, 0); } /** * Fire if we have numTrueEvals of the condition set out of numTotalEvals. There is * no time limit for the evaluations. * @param triggerId + * @param triggerMode the trigger mode for when this dampening is active * @param numTrueEvals * @param numTotalEvals * @return */ - public static Dampening forRelaxedCount(String triggerId, int numTrueEvals, int numTotalEvals) { - return new Dampening(triggerId, Type.RELAXED_COUNT, numTrueEvals, numTotalEvals, 0); + public static Dampening forRelaxedCount(String triggerId, Mode triggerMode, int numTrueEvals, int numTotalEvals) { + return new Dampening(triggerId, triggerMode, Type.RELAXED_COUNT, numTrueEvals, numTotalEvals, 0); } /** @@ -79,13 +83,14 @@ public static Dampening forRelaxedCount(String triggerId, int numTrueEvals, int * fire if the condition set is evaluated the required number of times in the given evalPeriod, so * the requisite data must be supplied in a timely manner. * @param triggerId + * @param triggerMode the trigger mode for when this dampening is active * @param numTrueEvals * @param evalPeriod Elapsed real time, in milliseconds. In other words, this is not measured against * collectionTimes (i.e. the timestamp on the data) but rather the evaluation times. * @return */ - public static Dampening forRelaxedTime(String triggerId, int numTrueEvals, long evalPeriod) { - return new Dampening(triggerId, Type.RELAXED_TIME, numTrueEvals, 0, evalPeriod); + public static Dampening forRelaxedTime(String triggerId, Mode triggerMode, int numTrueEvals, long evalPeriod) { + return new Dampening(triggerId, triggerMode, Type.RELAXED_TIME, numTrueEvals, 0, evalPeriod); } /** @@ -93,21 +98,24 @@ public static Dampening forRelaxedTime(String triggerId, int numTrueEvals, long * words, fire the Trigger after N consecutive true condition set evaluations, such that N >= 2 * and delta(evalTime-1,evalTime-N) >= evalPeriod. Any false evaluation resets the dampening. * @param triggerId + * @param triggerMode the trigger mode for when this dampening is active * @param evalPeriod Elapsed real time, in milliseconds. In other words, this is not measured against * collectionTimes (i.e. the timestamp on the data) but rather the evaluation times. * @return */ - public static Dampening forStrictTime(String triggerId, long evalPeriod) { - return new Dampening(triggerId, Type.STRICT_TIME, 0, 0, evalPeriod); + public static Dampening forStrictTime(String triggerId, Mode triggerMode, long evalPeriod) { + return new Dampening(triggerId, triggerMode, Type.STRICT_TIME, 0, 0, evalPeriod); } - public Dampening(String triggerId, Type type, int evalTrueSetting, int evalTotalSetting, long evalTimeSetting) { + public Dampening(String triggerId, Mode triggerMode, Type type, int evalTrueSetting, int evalTotalSetting, + long evalTimeSetting) { super(); this.triggerId = triggerId; this.type = type; this.evalTrueSetting = evalTrueSetting; this.evalTotalSetting = evalTotalSetting; this.evalTimeSetting = evalTimeSetting; + this.triggerMode = triggerMode; reset(); } @@ -184,6 +192,14 @@ public long getEvalTimeSetting() { return evalTimeSetting; } + public Mode getTriggerMode() { + return triggerMode; + } + + public void setTriggerMode(Mode triggerMode) { + this.triggerMode = triggerMode; + } + public boolean isSatisfied() { return satisfied; } @@ -299,11 +315,51 @@ public String log() { return sb.toString(); } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (evalTimeSetting ^ (evalTimeSetting >>> 32)); + result = prime * result + evalTotalSetting; + result = prime * result + evalTrueSetting; + result = prime * result + ((triggerId == null) ? 0 : triggerId.hashCode()); + result = prime * result + ((triggerMode == null) ? 0 : triggerMode.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Dampening other = (Dampening) obj; + if (evalTimeSetting != other.evalTimeSetting) + return false; + if (evalTotalSetting != other.evalTotalSetting) + return false; + if (evalTrueSetting != other.evalTrueSetting) + return false; + if (triggerId == null) { + if (other.triggerId != null) + return false; + } else if (!triggerId.equals(other.triggerId)) + return false; + if (triggerMode != other.triggerMode) + return false; + if (type != other.type) + return false; + return true; + } + @Override public String toString() { - return "Dampening [triggerId=" + triggerId + ", type=" + type + ", evalTrueSetting=" + evalTrueSetting - + ", evalTotalSetting=" + evalTotalSetting + ", evalTimeSetting=" + evalTimeSetting - + ", numTrueEvals=" + return "Dampening [triggerId=" + triggerId + ", triggerMode=" + triggerMode + ", type=" + type + + ", evalTrueSetting=" + evalTrueSetting + ", evalTotalSetting=" + evalTotalSetting + + ", evalTimeSetting=" + evalTimeSetting + ", numTrueEvals=" + numTrueEvals + ", numEvals=" + numEvals + ", trueEvalsStartTime=" + trueEvalsStartTime + ", satisfied=" + satisfied + ", satisfyingEvals=" + satisfyingEvals + "]"; } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/Trigger.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/Trigger.java index f1556b7cd..47449d20d 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/Trigger.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/Trigger.java @@ -25,11 +25,12 @@ public class Trigger extends TriggerTemplate { public enum Mode { - FIRING, SAFETY + FIRE, SAFETY }; private String id; private boolean enabled; + private boolean safetyEnabled; private Mode mode; public Trigger() { @@ -48,7 +49,8 @@ public Trigger(String id, String name) { this.id = id; this.enabled = false; - this.mode = Mode.FIRING; + this.safetyEnabled = false; + this.mode = Mode.FIRE; } public boolean isEnabled() { @@ -67,31 +69,68 @@ public void setId(String id) { this.id = id; } + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + /** + * This tells you whether the Trigger defines safety conditions and whether safety mode is enabled. + * This does NOT return the current mode of the Trigger. + * @return true if this Trigger supports safety mode and is it enabled. + * @see {@link #getMode()} to see the current mode. + */ + public boolean isSafetyEnabled() { + return safetyEnabled; + } + + /** + * Set true if safety conditions and dampening are fully defined and should be activated on a Trigger firing. Set + * false otherwise. + * @param safetyEnabled + */ + public void setSafetyEnabled(boolean safetyEnabled) { + this.safetyEnabled = safetyEnabled; + } + + public Match getMatch() { + return this.mode == Mode.FIRE ? getFiringMatch() : getSafetyMatch(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (enabled ? 1231 : 1237); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + @Override - public boolean equals(Object o) { - if (this == o) + public boolean equals(Object obj) { + if (this == obj) return true; - if (o == null || getClass() != o.getClass()) + if (!super.equals(obj)) return false; - if (!super.equals(o)) + if (getClass() != obj.getClass()) return false; - - Trigger trigger = (Trigger) o; - - if (enabled != trigger.enabled) + Trigger other = (Trigger) obj; + if (enabled != other.enabled) return false; - if (id != null ? !id.equals(trigger.id) : trigger.id != null) + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) return false; - return true; } @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (id != null ? id.hashCode() : 0); - result = 31 * result + (enabled ? 1 : 0); - return result; + public String toString() { + return "Trigger [id=" + id + ", enabled=" + enabled + ", mode=" + mode + ", match=" + getMatch() + "]"; } } diff --git a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/TriggerTemplate.java b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/TriggerTemplate.java index a89b832c7..4ef411c99 100644 --- a/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/TriggerTemplate.java +++ b/hawkular-alerts-api/src/main/java/org/hawkular/alerts/api/model/trigger/TriggerTemplate.java @@ -16,8 +16,6 @@ */ package org.hawkular.alerts.api.model.trigger; -import org.hawkular.alerts.api.model.condition.Condition; - import java.util.HashSet; import java.util.Set; @@ -35,18 +33,15 @@ public enum Match { private String name; private String description; - private Match match; - private Set conditions; - - /** - * A group of notifier's ids. - */ + private Match firingMatch; + private Match safetyMatch; + /** A group of notifier's ids. */ private Set notifiers; public TriggerTemplate(String name) { this.name = name; - this.match = Match.ALL; - this.conditions = new HashSet(); + this.firingMatch = Match.ALL; + this.safetyMatch = Match.ALL; this.notifiers = new HashSet(); } @@ -69,41 +64,20 @@ public void setDescription(String description) { this.description = description; } - public Match getMatch() { - return match; - } - - public void setMatch(Match match) { - this.match = match; - } - - public Set getConditions() { - return conditions; + public Match getFiringMatch() { + return firingMatch; } - public void setConditions(Set conditions) { - this.conditions = conditions; + public void setFiringMatch(Match firingMatch) { + this.firingMatch = firingMatch; } - public void addCondition(Condition condition) { - if (condition == null) { - return; - } - conditions.add(condition); - } - - public void addConditions(Set conditions) { - if (conditions == null) { - return; - } - this.conditions.addAll(conditions); + public Match getSafetyMatch() { + return safetyMatch; } - public void removeCondition(Condition condition) { - if (condition == null) { - return; - } - conditions.remove(condition); + public void setSafetyMatch(Match safetyMatch) { + this.safetyMatch = safetyMatch; } public Set getNotifiers() { @@ -136,39 +110,46 @@ public void removeNotifier(String id) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TriggerTemplate)) return false; - - TriggerTemplate that = (TriggerTemplate) o; - - if (conditions != null ? !conditions.equals(that.conditions) : that.conditions != null) return false; - if (description != null ? !description.equals(that.description) : that.description != null) return false; - if (match != that.match) return false; - if (name != null ? !name.equals(that.name) : that.name != null) return false; - if (notifiers != null ? !notifiers.equals(that.notifiers) : that.notifiers != null) return false; - - return true; + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((firingMatch == null) ? 0 : firingMatch.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((safetyMatch == null) ? 0 : safetyMatch.hashCode()); + return result; } @Override - public int hashCode() { - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (description != null ? description.hashCode() : 0); - result = 31 * result + (match != null ? match.hashCode() : 0); - result = 31 * result + (conditions != null ? conditions.hashCode() : 0); - result = 31 * result + (notifiers != null ? notifiers.hashCode() : 0); - return result; + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TriggerTemplate other = (TriggerTemplate) obj; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (firingMatch != other.firingMatch) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (safetyMatch != other.safetyMatch) + return false; + return true; } @Override public String toString() { - return "TriggerTemplate{" + - "name='" + name + '\'' + - ", description='" + description + '\'' + - ", match=" + match + - ", conditions=" + conditions + - ", notifiers=" + notifiers + - '}'; + return "TriggerTemplate [name=" + name + ", description=" + description + ", firingMatch=" + firingMatch + + ", safetyMatch=" + safetyMatch + "]"; } + } diff --git a/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/DbDefinitionsServiceImpl.java b/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/DbDefinitionsServiceImpl.java index e1ab448a8..1adf1d58f 100644 --- a/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/DbDefinitionsServiceImpl.java +++ b/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/DbDefinitionsServiceImpl.java @@ -50,6 +50,7 @@ import org.hawkular.alerts.api.model.condition.ThresholdRangeCondition; import org.hawkular.alerts.api.model.dampening.Dampening; import org.hawkular.alerts.api.model.trigger.Trigger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; import org.hawkular.alerts.api.model.trigger.TriggerTemplate; import org.hawkular.alerts.api.services.DefinitionsService; import org.hawkular.alerts.engine.log.MsgLogger; @@ -196,7 +197,7 @@ private void initFiles(String folder) { initNotifiers(initFolder); } } catch (Exception e) { - msgLog.errorDatabaseException("Error initializing files. Msg: " + e.getMessage()); + msgLog.errorDatabaseException("Error initializing files. Msg: " + e); } } @@ -219,18 +220,22 @@ private void initTriggers(File initFolder) throws Exception { continue; } String[] fields = line.split(","); - if (fields.length == 6) { + if (fields.length == 8) { String triggerId = fields[0]; boolean enabled = new Boolean(fields[1]).booleanValue(); - String name = fields[2]; - String description = fields[3]; - TriggerTemplate.Match match = TriggerTemplate.Match.valueOf(fields[4]); - String[] notifiers = fields[5].split("\\|"); + boolean safetyEnabled = new Boolean(fields[2]).booleanValue(); + String name = fields[3]; + String description = fields[4]; + TriggerTemplate.Match firingMatch = TriggerTemplate.Match.valueOf(fields[5]); + TriggerTemplate.Match safetyMatch = TriggerTemplate.Match.valueOf(fields[6]); + String[] notifiers = fields[7].split("\\|"); Trigger trigger = new Trigger(triggerId, name); trigger.setEnabled(enabled); + trigger.setSafetyEnabled(safetyEnabled); trigger.setDescription(description); - trigger.setMatch(match); + trigger.setFiringMatch(firingMatch); + trigger.setSafetyMatch(safetyMatch); for (String notifier : notifiers) { trigger.addNotifier(notifier); } @@ -263,18 +268,20 @@ private void initConditions(File initFolder) throws Exception { continue; } String[] fields = line.split(","); - if (fields.length > 3) { + if (fields.length > 4) { String triggerId = fields[0]; - int conditionSetSize = new Integer(fields[1]).intValue(); - int conditionSetIndex = new Integer(fields[2]).intValue(); - String type = fields[3]; - if (type != null && !type.isEmpty() && type.equals("threshold") && fields.length == 7) { - String dataId = fields[4]; - String operator = fields[5]; - Double threshold = new Double(fields[6]).doubleValue(); + Mode triggerMode = Mode.valueOf(fields[1]); + int conditionSetSize = new Integer(fields[2]).intValue(); + int conditionSetIndex = new Integer(fields[3]).intValue(); + String type = fields[4]; + if (type != null && !type.isEmpty() && type.equals("threshold") && fields.length == 8) { + String dataId = fields[5]; + String operator = fields[6]; + Double threshold = new Double(fields[7]).doubleValue(); ThresholdCondition newCondition = new ThresholdCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -284,16 +291,17 @@ private void initConditions(File initFolder) throws Exception { addCondition(newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("range") && fields.length == 10) { - String dataId = fields[4]; - String operatorLow = fields[5]; - String operatorHigh = fields[6]; - Double thresholdLow = new Double(fields[7]).doubleValue(); - Double thresholdHigh = new Double(fields[8]).doubleValue(); - boolean inRange = new Boolean(fields[9]).booleanValue(); + if (type != null && !type.isEmpty() && type.equals("range") && fields.length == 11) { + String dataId = fields[5]; + String operatorLow = fields[6]; + String operatorHigh = fields[7]; + Double thresholdLow = new Double(fields[8]).doubleValue(); + Double thresholdHigh = new Double(fields[9]).doubleValue(); + boolean inRange = new Boolean(fields[10]).booleanValue(); ThresholdRangeCondition newCondition = new ThresholdRangeCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -306,14 +314,15 @@ private void initConditions(File initFolder) throws Exception { addCondition(newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("compare") && fields.length == 8) { - String data1Id = fields[4]; - String operator = fields[5]; - Double data2Multiplier = new Double(fields[6]).doubleValue(); - String data2Id = fields[7]; + if (type != null && !type.isEmpty() && type.equals("compare") && fields.length == 9) { + String data1Id = fields[5]; + String operator = fields[6]; + Double data2Multiplier = new Double(fields[7]).doubleValue(); + String data2Id = fields[8]; CompareCondition newCondition = new CompareCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setData1Id(data1Id); @@ -324,14 +333,15 @@ private void initConditions(File initFolder) throws Exception { addCondition(newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("string") && fields.length == 8) { - String dataId = fields[4]; - String operator = fields[5]; - String pattern = fields[6]; - boolean ignoreCase = new Boolean(fields[7]).booleanValue(); + if (type != null && !type.isEmpty() && type.equals("string") && fields.length == 9) { + String dataId = fields[5]; + String operator = fields[6]; + String pattern = fields[7]; + boolean ignoreCase = new Boolean(fields[8]).booleanValue(); StringCondition newCondition = new StringCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -342,12 +352,13 @@ private void initConditions(File initFolder) throws Exception { addCondition(newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("availability") && fields.length == 6) { - String dataId = fields[4]; - String operator = fields[5]; + if (type != null && !type.isEmpty() && type.equals("availability") && fields.length == 7) { + String dataId = fields[5]; + String operator = fields[6]; AvailabilityCondition newCondition = new AvailabilityCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -382,14 +393,15 @@ private void initDampening(File initFolder) throws Exception { continue; } String[] fields = line.split(","); - if (fields.length == 5) { + if (fields.length == 6) { String triggerId = fields[0]; - String type = fields[1]; - int evalTrueSetting = new Integer(fields[2]); - int evalTotalSetting = new Integer(fields[3]); - int evalTimeSetting = new Integer(fields[4]); + Mode triggerMode = Mode.valueOf(fields[1]); + String type = fields[2]; + int evalTrueSetting = new Integer(fields[3]); + int evalTotalSetting = new Integer(fields[4]); + int evalTimeSetting = new Integer(fields[5]); - Dampening newDampening = new Dampening(triggerId, Dampening.Type.valueOf(type), + Dampening newDampening = new Dampening(triggerId, triggerMode, Dampening.Type.valueOf(type), evalTrueSetting, evalTotalSetting, evalTimeSetting); addDampening(newDampening); diff --git a/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/MemDefinitionsServiceImpl.java b/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/MemDefinitionsServiceImpl.java index eb9a4aef8..2648c9337 100644 --- a/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/MemDefinitionsServiceImpl.java +++ b/hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/MemDefinitionsServiceImpl.java @@ -41,6 +41,7 @@ import org.hawkular.alerts.api.model.condition.ThresholdRangeCondition; import org.hawkular.alerts.api.model.dampening.Dampening; import org.hawkular.alerts.api.model.trigger.Trigger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; import org.hawkular.alerts.api.model.trigger.TriggerTemplate; import org.hawkular.alerts.api.services.DefinitionsService; import org.hawkular.alerts.api.services.NotificationsService; @@ -123,18 +124,22 @@ private void initFiles(String folder) { continue; } String[] fields = line.split(","); - if (fields.length == 6) { + if (fields.length == 8) { String triggerId = fields[0]; boolean enabled = new Boolean(fields[1]).booleanValue(); - String name = fields[2]; - String description = fields[3]; - TriggerTemplate.Match match = TriggerTemplate.Match.valueOf(fields[4]); - String[] notifiers = fields[5].split("\\|"); + boolean safetyEnabled = new Boolean(fields[2]).booleanValue(); + String name = fields[3]; + String description = fields[4]; + TriggerTemplate.Match firingMatch = TriggerTemplate.Match.valueOf(fields[5]); + TriggerTemplate.Match safetyMatch = TriggerTemplate.Match.valueOf(fields[6]); + String[] notifiers = fields[7].split("\\|"); Trigger trigger = new Trigger(triggerId, name); trigger.setEnabled(enabled); + trigger.setSafetyEnabled(safetyEnabled); trigger.setDescription(description); - trigger.setMatch(match); + trigger.setFiringMatch(firingMatch); + trigger.setSafetyMatch(safetyMatch); for (String notifier : notifiers) { trigger.addNotifier(notifier); } @@ -165,18 +170,20 @@ private void initFiles(String folder) { continue; } String[] fields = line.split(","); - if (fields.length > 3) { + if (fields.length > 4) { String triggerId = fields[0]; - int conditionSetSize = new Integer(fields[1]).intValue(); - int conditionSetIndex = new Integer(fields[2]).intValue(); - String type = fields[3]; - if (type != null && !type.isEmpty() && type.equals("threshold") && fields.length == 7) { - String dataId = fields[4]; - String operator = fields[5]; - Double threshold = new Double(fields[6]).doubleValue(); + Mode triggerMode = Mode.valueOf(fields[1]); + int conditionSetSize = new Integer(fields[2]).intValue(); + int conditionSetIndex = new Integer(fields[3]).intValue(); + String type = fields[4]; + if (type != null && !type.isEmpty() && type.equals("threshold") && fields.length == 8) { + String dataId = fields[5]; + String operator = fields[6]; + Double threshold = new Double(fields[7]).doubleValue(); ThresholdCondition newCondition = new ThresholdCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -186,16 +193,17 @@ private void initFiles(String folder) { this.conditions.put(newCondition.getConditionId(), newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("range") && fields.length == 10) { - String dataId = fields[4]; - String operatorLow = fields[5]; - String operatorHigh = fields[6]; - Double thresholdLow = new Double(fields[7]).doubleValue(); - Double thresholdHigh = new Double(fields[8]).doubleValue(); - boolean inRange = new Boolean(fields[9]).booleanValue(); + if (type != null && !type.isEmpty() && type.equals("range") && fields.length == 11) { + String dataId = fields[5]; + String operatorLow = fields[6]; + String operatorHigh = fields[7]; + Double thresholdLow = new Double(fields[8]).doubleValue(); + Double thresholdHigh = new Double(fields[9]).doubleValue(); + boolean inRange = new Boolean(fields[10]).booleanValue(); ThresholdRangeCondition newCondition = new ThresholdRangeCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -208,14 +216,15 @@ private void initFiles(String folder) { this.conditions.put(newCondition.getConditionId(), newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("compare") && fields.length == 8) { - String data1Id = fields[4]; - String operator = fields[5]; - Double data2Multiplier = new Double(fields[6]).doubleValue(); - String data2Id = fields[7]; + if (type != null && !type.isEmpty() && type.equals("compare") && fields.length == 9) { + String data1Id = fields[5]; + String operator = fields[6]; + Double data2Multiplier = new Double(fields[7]).doubleValue(); + String data2Id = fields[8]; CompareCondition newCondition = new CompareCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setData1Id(data1Id); @@ -226,15 +235,16 @@ private void initFiles(String folder) { this.conditions.put(newCondition.getConditionId(), newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("string") && fields.length == 8) { - String dataId = fields[4]; - String operator = fields[5]; - String pattern = fields[6]; - boolean ignoreCase = new Boolean(fields[7]).booleanValue(); + if (type != null && !type.isEmpty() && type.equals("string") && fields.length == 9) { + String dataId = fields[5]; + String operator = fields[6]; + String pattern = fields[7]; + boolean ignoreCase = new Boolean(fields[8]).booleanValue(); StringCondition newCondition = new StringCondition(); newCondition.setTriggerId(triggerId); newCondition.setConditionSetSize(conditionSetSize); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); newCondition.setOperator(StringCondition.Operator.valueOf(operator)); @@ -244,12 +254,13 @@ private void initFiles(String folder) { this.conditions.put(newCondition.getConditionId(), newCondition); log.debugf("Init file - Inserting [%s]", newCondition); } - if (type != null && !type.isEmpty() && type.equals("availability") && fields.length == 6) { - String dataId = fields[4]; - String operator = fields[5]; + if (type != null && !type.isEmpty() && type.equals("availability") && fields.length == 7) { + String dataId = fields[5]; + String operator = fields[6]; AvailabilityCondition newCondition = new AvailabilityCondition(); newCondition.setTriggerId(triggerId); + newCondition.setTriggerMode(triggerMode); newCondition.setConditionSetSize(conditionSetSize); newCondition.setConditionSetIndex(conditionSetIndex); newCondition.setDataId(dataId); @@ -282,14 +293,15 @@ private void initFiles(String folder) { continue; } String[] fields = line.split(","); - if (fields.length == 5) { + if (fields.length == 6) { String triggerId = fields[0]; - String type = fields[1]; - int evalTrueSetting = new Integer(fields[2]); - int evalTotalSetting = new Integer(fields[3]); - int evalTimeSetting = new Integer(fields[4]); + Mode triggerMode = Mode.valueOf(fields[1]); + String type = fields[2]; + int evalTrueSetting = new Integer(fields[3]); + int evalTotalSetting = new Integer(fields[4]); + int evalTimeSetting = new Integer(fields[5]); - Dampening newDampening = new Dampening(triggerId, Dampening.Type.valueOf(type), + Dampening newDampening = new Dampening(triggerId, triggerMode, Dampening.Type.valueOf(type), evalTrueSetting, evalTotalSetting, evalTimeSetting); this.dampenings.put(triggerId, newDampening); diff --git a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/conditions.data b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/conditions.data index ec6e74f26..b95e5ba4f 100644 --- a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/conditions.data +++ b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/conditions.data @@ -1,29 +1,29 @@ -# triggerId,conditionSetSize,conditionSetIndex, +# ,,,, # == threshold # ..., dataId,operator,value # -trigger-1,1,1,threshold,NumericData-01,LT,10.0 -trigger-2,2,1,threshold,NumericData-01,GTE,15.0 -trigger-2,2,2,threshold,NumericData-02,GTE,15.0 +trigger-1,FIRE,1,1,threshold,NumericData-01,LT,10.0 +trigger-2,FIRE,2,1,threshold,NumericData-01,GTE,15.0 +trigger-2,FIRE,2,2,threshold,NumericData-02,GTE,15.0 # # == range # ...,dataId,operatorLow,operatorHigh,thresholdLow,thresholdHigh,inRange # -trigger-3,1,1,range,NumericData-03,INCLUSIVE,INCLUSIVE,10.0,15.0,true +trigger-3,FIRE,1,1,range,NumericData-03,INCLUSIVE,INCLUSIVE,10.0,15.0,true # # == compare # ...,data1Id,operator,data2Multiplier,data2Id # -trigger-4,1,1,compare,NumericData-01,LT,0.5,NumericData-02 +trigger-4,FIRE,1,1,compare,NumericData-01,LT,0.5,NumericData-02 # # == string # ...,dataId,operator,pattern,ignoreCase # -trigger-5,1,1,string,StringData-01,STARTS_WITH,Fred,false +trigger-5,FIRE,1,1,string,StringData-01,STARTS_WITH,Fred,false # # == availability # ...,dataId,operator # -trigger-6,1,1,availability,Availability-01,NOT_UP +trigger-6,FIRE,1,1,availability,Availability-01,NOT_UP diff --git a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/dampening.data b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/dampening.data index 8d41010b2..846247220 100644 --- a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/dampening.data +++ b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/dampening.data @@ -1,2 +1,2 @@ -# triggerId,type,evalTrueSetting,evalTotalSetting,evalTimeSetting -trigger-1,STRICT,2,2,0 \ No newline at end of file +# ,,,,, +trigger-1,FIRE,STRICT,2,2,0 \ No newline at end of file diff --git a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/triggers.data b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/triggers.data index 9dfe2288e..c2d984a8a 100644 --- a/hawkular-alerts-engine/src/main/resources/hawkular-alerts/triggers.data +++ b/hawkular-alerts-engine/src/main/resources/hawkular-alerts/triggers.data @@ -1,7 +1,7 @@ -# ,,,,,|||... -trigger-1,true,NumericData-01-low,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com -trigger-2,true,NumericData-01-02-high,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com -trigger-3,true,NumericData-03-range,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com -trigger-4,true,CompareData-01-d1-lthalf-d2,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com -trigger-5,true,StringData-01-starts,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com -trigger-6,true,Availability-01-NOT-UP,description,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com \ No newline at end of file +# ,,,,,,,|||... +trigger-1,true,false,NumericData-01-low,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com +trigger-2,true,false,NumericData-01-02-high,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com +trigger-3,true,false,NumericData-03-range,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com +trigger-4,true,false,CompareData-01-d1-lthalf-d2,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com +trigger-5,true,false,StringData-01-starts,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com +trigger-6,true,false,Availability-01-NOT-UP,description,ALL,ALL,SNMP-Trap-1|SNMP-Trap-2|admin@email.com \ No newline at end of file diff --git a/hawkular-alerts-engine/src/main/resources/org/hawkular/alerts/engine/rules/ConditionMatch.drl b/hawkular-alerts-engine/src/main/resources/org/hawkular/alerts/engine/rules/ConditionMatch.drl index 2d54bb88c..fe984ef18 100644 --- a/hawkular-alerts-engine/src/main/resources/org/hawkular/alerts/engine/rules/ConditionMatch.drl +++ b/hawkular-alerts-engine/src/main/resources/org/hawkular/alerts/engine/rules/ConditionMatch.drl @@ -35,6 +35,7 @@ import org.hawkular.alerts.api.model.data.NumericData; import org.hawkular.alerts.api.model.data.StringData; import org.hawkular.alerts.api.model.notification.Notification; import org.hawkular.alerts.api.model.trigger.Trigger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; import org.hawkular.alerts.api.model.trigger.TriggerTemplate.Match; import org.hawkular.alerts.api.services.NotificationsService; @@ -58,13 +59,15 @@ global List alerts; // // Data facts will be applied to all relevant Condition evals, and then will be retracted (using rule complexity // to fire the retract rule after the condition evals). +// +// It is a precondition that all Triggers in working memory are enabled (i.e. enabled == true ). // ConditionEval rules rule Threshold when - $t : Trigger( $tid : id ) - $c : ThresholdCondition ( triggerId == $tid, $did : dataId ) + $t : Trigger( $tid : id, $tmode : mode ) + $c : ThresholdCondition ( triggerId == $tid, triggerMode == $tmode, $did : dataId ) $d : NumericData( $did == id ) then ThresholdConditionEval ce = new ThresholdConditionEval($c, $d); @@ -76,8 +79,8 @@ end rule ThresholdRange when - $t : Trigger( $tid : id ) - $c : ThresholdRangeCondition ( triggerId == $tid, $did : dataId ) + $t : Trigger( $tid : id, $tmode : mode ) + $c : ThresholdRangeCondition ( triggerId == $tid, triggerMode == $tmode, $did : dataId ) $d : NumericData( $did == id ) then ThresholdRangeConditionEval ce = new ThresholdRangeConditionEval($c, $d); @@ -97,8 +100,8 @@ end // data when it arrives at different times. rule Compare when - $t : Trigger( $tid : id ) - $c : CompareCondition ( triggerId == $tid, $d1id : data1Id, $d2id : data2Id ) + $t : Trigger( $tid : id, $tmode : mode ) + $c : CompareCondition ( triggerId == $tid, triggerMode == $tmode, $d1id : data1Id, $d2id : data2Id ) $d1 : NumericData( $d1id == id ) $d2 : NumericData( $d2id == id ) then @@ -111,8 +114,8 @@ end rule Availability when - $t : Trigger( $tid : id ) - $c : AvailabilityCondition ( triggerId == $tid, $did : dataId ) + $t : Trigger( $tid : id, $tmode : mode ) + $c : AvailabilityCondition ( triggerId == $tid, triggerMode == $tmode, $did : dataId ) $d : Availability( $did == id ) then AvailabilityConditionEval ce = new AvailabilityConditionEval($c, $d); @@ -124,8 +127,8 @@ end rule String when - $t : Trigger( $tid : id ) - $c : StringCondition ( triggerId == $tid, $did : dataId ) + $t : Trigger( $tid : id, $tmode : mode ) + $c : StringCondition ( triggerId == $tid, triggerMode == $tmode, $did : dataId ) $d : StringData( $did == id ) then StringConditionEval ce = new StringConditionEval($c, $d); @@ -239,20 +242,20 @@ end rule ProvideDefaultDampening when - $t : Trigger( $tid : id ) - not Dampening( triggerId == $tid ) + $t : Trigger( $tid : id, $tmode : mode ) + not Dampening( triggerId == $tid, triggerMode == $tmode ) then if (log != null && log.isDebugEnabled()) { - log.debug("Adding default dampening for trigger! " + $t.getId()); + log.debug("Adding default " + $tmode + " dampening for trigger! " + $t.getId()); } - Dampening d = new Dampening( $tid, Dampening.Type.STRICT, 1, 1, 0L ); + Dampening d = new Dampening( $tid, $tmode, Dampening.Type.STRICT, 1, 1, 0L ); insert( d ); end rule DampenTriggerAny when - $t : Trigger( match == Match.ANY, $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == false ) + $t : Trigger( match == Match.ANY, $tid : id, $tmode : mode ) + $d : Dampening( triggerId == $tid, triggerMode == $tmode, satisfied == false ) $ce : ConditionEval ( triggerId == $tid ) then if (log != null && log.isDebugEnabled()) { @@ -268,8 +271,8 @@ end rule DampenOneConditionTrigger when - $t : Trigger( match == Match.ALL, $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == false ) + $t : Trigger( match == Match.ALL, $tid : id, $tmode : mode ) + $d : Dampening( triggerId == $tid, triggerMode == $tmode, satisfied == false ) $ce : ConditionEval ( triggerId == $tid, conditionSetSize == 1, conditionSetIndex == 1 ) then if (log != null && log.isDebugEnabled()) { @@ -285,8 +288,8 @@ end rule DampenTwoConditionTrigger when - $t : Trigger( match == Match.ALL, $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == false ) + $t : Trigger( match == Match.ALL, $tid : id, $tmode : mode ) + $d : Dampening( triggerId == $tid, triggerMode == $tmode, satisfied == false ) $ce1 : ConditionEval ( triggerId == $tid, conditionSetSize == 2, conditionSetIndex == 1 ) $ce2 : ConditionEval ( triggerId == $tid, conditionSetSize == 2, conditionSetIndex == 2 ) exists ConditionEval ( triggerId == $tid, used == false ) @@ -306,8 +309,8 @@ end rule DampenThreeConditionTrigger when - $t : Trigger( match == Match.ALL, $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == false ) + $t : Trigger( match == Match.ALL, $tid : id, $tmode : mode ) + $d : Dampening( triggerId == $tid, triggerMode == $tmode, satisfied == false ) $ce1 : ConditionEval ( triggerId == $tid, conditionSetSize == 3, conditionSetIndex == 1 ) $ce2 : ConditionEval ( triggerId == $tid, conditionSetSize == 3, conditionSetIndex == 2 ) $ce3 : ConditionEval ( triggerId == $tid, conditionSetSize == 3, conditionSetIndex == 3 ) @@ -328,8 +331,8 @@ end rule DampenFourConditionTrigger when - $t : Trigger( match == Match.ALL, $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == false ) + $t : Trigger( match == Match.ALL, $tid : id, $tmode : mode ) + $d : Dampening( triggerId == $tid, triggerMode == $tmode, satisfied == false ) $ce1 : ConditionEval ( triggerId == $tid, conditionSetSize == 4, conditionSetIndex == 1 ) $ce2 : ConditionEval ( triggerId == $tid, conditionSetSize == 4, conditionSetIndex == 2 ) $ce3 : ConditionEval ( triggerId == $tid, conditionSetSize == 4, conditionSetIndex == 3 ) @@ -351,23 +354,21 @@ end -////// ALERT GENERATION -// -// This is pretty straightforward. If a Trigger's Dampening is satisfied, then the Trigger fires and generates an -// Alert. The Trigger's Dampening fact is then reset and updated in working memory, ready to again track evals -// for the Trigger. -// -// TODO: We have yet to introduce something like RHQ's recovery alerting. So, for now, Trigger's stay active after -// firing. +////// ALERT GENERATION / TRIGGER MODE HANDLING +// If a Trigger's FIRE mode Dampening is satisfied, then the Trigger fires and generates an Alert. The Trigger's +// FIRE mode Dampening fact is then reset and updated in working memory, ready to again track evals for the Trigger. +// If the Trigger has safety mode enabled then we toggle the Trigger to SAFETY mode and it can not fire again +// until the safety mode Dampening is satisfied and the Trigger returns to FIRE mode. rule AlertOnSatisfiedDampening when - $t : Trigger( $tid : id ) - $d : Dampening( triggerId == $tid, satisfied == true ) + $t : Trigger( mode == Mode.FIRE, $tid : id ) + $d : Dampening( triggerMode == Mode.FIRE, triggerId == $tid, satisfied == true ) then if (log != null && log.isDebugEnabled()) { log.debug("AlertOnSatisfiedDampening! " + $d.log()); } + Alert newAlert = new Alert( $tid, $d.getSatisfyingEvals() ); alerts.add(newAlert); if (notifications != null) { @@ -378,7 +379,37 @@ rule AlertOnSatisfiedDampening notifications.send(notification); } } - insert( newAlert ); + + //insert( newAlert ); + $d.reset(); update( $d ) + + if ($t.isSafetyEnabled()) { + if (log != null && log.isDebugEnabled()) { + log.debug("Setting Trigger to Safety Mode! " + $t); + } + $t.setMode(Mode.SAFETY); + update( $t ) + + } else if (log != null && log.isDebugEnabled()) { + log.debug("Trigger remains in Fire mode, Safety Mode not enabled. " + $t); + } +end + + +rule SetFiringModeOnSatisfiedDampening + when + $t : Trigger( mode == Mode.SAFETY, $tid : id ) + $d : Dampening( triggerMode == Mode.SAFETY, triggerId == $tid, satisfied == true ) + then + if (log != null && log.isDebugEnabled()) { + log.debug("SetFiringModeOnSatisfiedDampening! " + $d.log()); + } + + $d.reset(); + update( $d ) + + $t.setMode(Mode.FIRE); + update( $t ) end diff --git a/hawkular-alerts-engine/src/test/java/org/hawkular/alerts/engine/RulesEngineTest.java b/hawkular-alerts-engine/src/test/java/org/hawkular/alerts/engine/RulesEngineTest.java index 030d7628d..7c85f2997 100644 --- a/hawkular-alerts-engine/src/test/java/org/hawkular/alerts/engine/RulesEngineTest.java +++ b/hawkular-alerts-engine/src/test/java/org/hawkular/alerts/engine/RulesEngineTest.java @@ -42,6 +42,7 @@ import org.hawkular.alerts.api.model.data.NumericData; import org.hawkular.alerts.api.model.data.StringData; import org.hawkular.alerts.api.model.trigger.Trigger; +import org.hawkular.alerts.api.model.trigger.Trigger.Mode; import org.hawkular.alerts.engine.impl.DroolsRulesEngineImpl; import org.hawkular.alerts.engine.rules.RulesEngine; import org.junit.After; @@ -105,6 +106,11 @@ public void thresholdTest() { // default dampening + t1.setEnabled(true); + t2.setEnabled(true); + t3.setEnabled(true); + t4.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t2); @@ -245,6 +251,10 @@ public void thresholdRangeTest() { // default dampening + t1.setEnabled(true); + t2.setEnabled(true); + t3.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t2); @@ -326,6 +336,11 @@ public void compareTest() { // default dampening + t1.setEnabled(true); + t2.setEnabled(true); + t3.setEnabled(true); + t4.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t2); @@ -534,6 +549,13 @@ public void StringTest() { // default dampening + t1.setEnabled(true); + t2.setEnabled(true); + t3.setEnabled(true); + t4.setEnabled(true); + t5.setEnabled(true); + t6.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t2); @@ -703,6 +725,13 @@ public void StringTestIgnoreCase() { // default dampening + t1.setEnabled(true); + t2.setEnabled(true); + t3.setEnabled(true); + t4.setEnabled(true); + t5.setEnabled(true); + t6.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t2); @@ -842,6 +871,8 @@ public void AvailabilityTest() { // default dampening + t1.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); @@ -888,7 +919,7 @@ public void DampeningStrictTest() { AvailabilityCondition t1c1 = new AvailabilityCondition("trigger-1", 1, 1, "AvailData-01", AvailabilityCondition.Operator.DOWN); - Dampening t1d = Dampening.forStrict("trigger-1", 3); + Dampening t1d = Dampening.forStrict("trigger-1", Mode.FIRE, 3); datums.add(new Availability("AvailData-01", 1, AvailabilityType.DOWN)); datums.add(new Availability("AvailData-01", 2, AvailabilityType.UNAVAILABLE)); @@ -898,6 +929,8 @@ public void DampeningStrictTest() { datums.add(new Availability("AvailData-01", 6, AvailabilityType.DOWN)); datums.add(new Availability("AvailData-01", 7, AvailabilityType.UP)); + t1.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t1d); @@ -933,7 +966,7 @@ public void DampeningRelaxedCountTest() { AvailabilityCondition t1c1 = new AvailabilityCondition("trigger-1", 1, 1, "AvailData-01", AvailabilityCondition.Operator.DOWN); - Dampening t1d = Dampening.forRelaxedCount("trigger-1", 3, 5); + Dampening t1d = Dampening.forRelaxedCount("trigger-1", Mode.FIRE, 3, 5); datums.add(new Availability("AvailData-01", 1, AvailabilityType.DOWN)); datums.add(new Availability("AvailData-01", 2, AvailabilityType.UNAVAILABLE)); @@ -943,6 +976,8 @@ public void DampeningRelaxedCountTest() { datums.add(new Availability("AvailData-01", 6, AvailabilityType.DOWN)); datums.add(new Availability("AvailData-01", 7, AvailabilityType.UP)); + t1.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t1d); @@ -979,7 +1014,9 @@ public void DampeningRelaxedTimeTest() { AvailabilityCondition t1c1 = new AvailabilityCondition("trigger-1", 1, 1, "AvailData-01", AvailabilityCondition.Operator.DOWN); - Dampening t1d = Dampening.forRelaxedTime("trigger-1", 2, 500L); + Dampening t1d = Dampening.forRelaxedTime("trigger-1", Mode.FIRE, 2, 500L); + + t1.setEnabled(true); rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); @@ -1034,7 +1071,9 @@ public void DampeningStrictTimeTest() { AvailabilityCondition t1c1 = new AvailabilityCondition("trigger-1", 1, 1, "AvailData-01", AvailabilityCondition.Operator.DOWN); - Dampening t1d = Dampening.forStrictTime("trigger-1", 250L); + Dampening t1d = Dampening.forStrictTime("trigger-1", Mode.FIRE, 250L); + + t1.setEnabled(true); rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); @@ -1078,6 +1117,8 @@ public void multiConditionTest() { // default dampening + t1.setEnabled(true); + rulesEngine.addFact(t1); rulesEngine.addFact(t1c1); rulesEngine.addFact(t1c2); @@ -1145,4 +1186,77 @@ public void multiConditionTest() { assert e2.getCondition().getDataId().equals("NumericData-02") : e2.getCondition(); } + @Test + public void SafetyModeTest() { + // The single trigger has definitions for both FIRE and SAFETY modes + Trigger t1 = new Trigger("trigger-1", "Avail-DOWN"); + // Fire Mode + AvailabilityCondition fmt1c1 = new AvailabilityCondition("trigger-1", Mode.FIRE, 1, 1, + "AvailData-01", AvailabilityCondition.Operator.DOWN); + Dampening fmt1d = Dampening.forStrict("trigger-1", Mode.FIRE, 2); + + // Safety Mode + AvailabilityCondition smt1c1 = new AvailabilityCondition("trigger-1", Mode.SAFETY, 1, 1, + "AvailData-01", AvailabilityCondition.Operator.UP); + Dampening smt1d = Dampening.forStrict("trigger-1", Mode.SAFETY, 2); + + + datums.add(new Availability("AvailData-01", 1, AvailabilityType.DOWN)); + datums.add(new Availability("AvailData-01", 2, AvailabilityType.UNAVAILABLE)); + datums.add(new Availability("AvailData-01", 3, AvailabilityType.UP)); + datums.add(new Availability("AvailData-01", 4, AvailabilityType.DOWN)); + datums.add(new Availability("AvailData-01", 5, AvailabilityType.DOWN)); + datums.add(new Availability("AvailData-01", 6, AvailabilityType.DOWN)); + datums.add(new Availability("AvailData-01", 7, AvailabilityType.DOWN)); + datums.add(new Availability("AvailData-01", 8, AvailabilityType.UP)); + + t1.setEnabled(true); + t1.setSafetyEnabled(true); + + rulesEngine.addFact(t1); + rulesEngine.addFact(fmt1c1); + rulesEngine.addFact(fmt1d); + rulesEngine.addFact(smt1c1); + rulesEngine.addFact(smt1d); + + // The Trigger should fire on the consecutive DOWN datums at T4,T5. It should then switch to + // safety mode and not fire again at the next two consecutive down datums at T6,T7. T8 should be the + // first match for the safety dampening but it should not yet be satisfied until T9 (see below). + rulesEngine.addData(datums); + rulesEngine.fire(); + + assert alerts.size() == 1 : alerts; + + Alert a = alerts.get(0); + assert a.getTriggerId().equals("trigger-1") : a.getTriggerId(); + assert a.getEvalSets().size() == 2 : a.getEvalSets(); + long expectedTimestamp = 4; + for (Set evalSet : a.getEvalSets()) { + assert evalSet.size() == 1 : evalSet; + AvailabilityConditionEval e = (AvailabilityConditionEval) evalSet.iterator().next(); + assert e.getConditionSetIndex() == 1 : e; + assert e.getConditionSetSize() == 1 : e; + assert e.getTriggerId().equals("trigger-1"); + assert e.isMatch(); + assert e.getDataTimestamp() == expectedTimestamp++; + AvailabilityType v = e.getValue(); + assert v == AvailabilityType.DOWN : e; + assert e.getCondition().getDataId().equals("AvailData-01") : e + .getCondition(); + } + + assert t1.getMode() == Mode.SAFETY : t1; + + alerts.clear(); + datums.clear(); + datums.add(new Availability("AvailData-01", 9, AvailabilityType.UP)); + + rulesEngine.addData(datums); + rulesEngine.fire(); + + // The second consecutive UP should satisfy the safety requirements and return the Trigger to FIRE mode. + assert alerts.size() == 0 : alerts; + assert t1.getMode() == Mode.FIRE : t1; + } + }