/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2007-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.threshd;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.xml.event.Event;
import org.springframework.util.Assert;
/**
* <p>ThresholdEvaluatorHighLow class.</p>
*
* @author ranger
* @version $Id: $
*/
public class ThresholdEvaluatorHighLow implements ThresholdEvaluator {
/**
* <p>Constructor for ThresholdEvaluatorHighLow.</p>
*/
public ThresholdEvaluatorHighLow() {
}
/** {@inheritDoc} */
public boolean supportsType(String type) {
return "low".equals(type) || "high".equals(type);
}
/** {@inheritDoc} */
public ThresholdEvaluatorState getThresholdEvaluatorState(BaseThresholdDefConfigWrapper threshold) {
return new ThresholdEvaluatorStateHighLow(threshold);
}
public static class ThresholdEvaluatorStateHighLow extends AbstractThresholdEvaluatorState {
/**
* Castor Threshold object containing threshold configuration data.
*/
private BaseThresholdDefConfigWrapper m_thresholdConfig;
/**
* Threshold exceeded count
*/
private int m_exceededCount;
/**
* Threshold armed flag
*
* This flag must be true before evaluate() will return true (indicating
* that the threshold has been triggered). This flag is initialized to true
* by the constructor and is set to false each time the threshold is
* triggered. It can only be reset by the current value of the datasource
* falling below (for high threshold) or rising above (for low threshold)
* the rearm value.
*/
private boolean m_armed;
private CollectionResourceWrapper m_lastCollectionResourceUsed;
public ThresholdEvaluatorStateHighLow(BaseThresholdDefConfigWrapper threshold) {
Assert.notNull(threshold, "threshold argument cannot be null");
setThresholdConfig(threshold);
setExceededCount(0);
setArmed(true);
}
public boolean isArmed() {
return m_armed;
}
public void setArmed(boolean armed) {
m_armed = armed;
}
public int getExceededCount() {
return m_exceededCount;
}
public void setExceededCount(int exceededCount) {
m_exceededCount = exceededCount;
}
public BaseThresholdDefConfigWrapper getThresholdConfig() {
return m_thresholdConfig;
}
public void setThresholdConfig(BaseThresholdDefConfigWrapper thresholdConfig) {
Assert.notNull(thresholdConfig.getType(), "threshold must have a 'type' value set");
Assert.notNull(thresholdConfig.getDatasourceExpression(), "threshold must have a 'ds-name' value set");
Assert.notNull(thresholdConfig.getDsType(), "threshold must have a 'ds-type' value set");
Assert.isTrue(thresholdConfig.hasValue(), "threshold must have a 'value' value set");
Assert.isTrue(thresholdConfig.hasRearm(), "threshold must have a 'rearm' value set");
Assert.isTrue(thresholdConfig.hasTrigger(), "threshold must have a 'trigger' value set");
m_thresholdConfig = thresholdConfig;
}
public String getType() {
return getThresholdConfig().getType().toString();
}
public Status evaluate(double dsValue) {
if (isThresholdExceeded(dsValue)) {
if (isArmed()) {
setExceededCount(getExceededCount() + 1);
if (log().isDebugEnabled()) {
log().debug("evaluate: " + getType() + " threshold exceeded, count=" + getExceededCount());
}
if (isTriggerCountExceeded()) {
log().debug("evaluate: " + getType() + " threshold triggered");
setExceededCount(1);
setArmed(false);
return Status.TRIGGERED;
}
}
} else if (isRearmExceeded(dsValue)) {
if (!isArmed()) {
log().debug("evaluate: " + getType() + " threshold rearmed");
setArmed(true);
setExceededCount(0);
return Status.RE_ARMED;
}
if (getExceededCount() > 0) {
log().debug("evaluate: resetting " + getType() + " threshold count to 0, because the current value indicates that the in-progress threshold has been rearmed, but it doesn't triggered yet.");
setExceededCount(0);
}
} else {
log().debug("evaluate: resetting " + getType() + " threshold count to 0");
setExceededCount(0);
}
return Status.NO_CHANGE;
}
protected boolean isThresholdExceeded(double dsValue) {
if ("high".equals(getThresholdConfig().getType())) {
return dsValue >= getThresholdConfig().getValue();
} else if ("low".equals(getThresholdConfig().getType())) {
return dsValue <= getThresholdConfig().getValue();
} else {
throw new IllegalStateException("This thresholding strategy can only be used for thresholding types of 'high' and 'low'.");
}
}
protected boolean isRearmExceeded(double dsValue) {
if ("high".equals(getThresholdConfig().getType())) {
return dsValue <= getThresholdConfig().getRearm();
} else if ("low".equals(getThresholdConfig().getType())) {
return dsValue >= getThresholdConfig().getRearm();
} else {
throw new IllegalStateException("This thresholding strategy can only be used for thresholding types of 'high' and 'low'.");
}
}
protected boolean isTriggerCountExceeded() {
return getExceededCount() >= getThresholdConfig().getTrigger();
}
public Event getEventForState(Status status, Date date, double dsValue, CollectionResourceWrapper resource) {
/*
* If resource is null, we will use m_lastCollectionResourceUsed; else we will use provided resource.
* For future calls we will preserve the latest not null resource on m_lastCollectionResourceUsed.
* See ThresholdEntity.merge
*/
if (resource == null) {
resource = m_lastCollectionResourceUsed;
}
m_lastCollectionResourceUsed = resource;
String uei;
switch (status) {
case TRIGGERED:
uei=getThresholdConfig().getTriggeredUEI();
if ("low".equals(getThresholdConfig().getType())) {
if(uei==null || "".equals(uei)) {
uei=EventConstants.LOW_THRESHOLD_EVENT_UEI;
}
return createBasicEvent(uei, date, dsValue, resource);
} else if ("high".equals(getThresholdConfig().getType())) {
if(uei==null || "".equals(uei)) {
uei=EventConstants.HIGH_THRESHOLD_EVENT_UEI;
}
return createBasicEvent(uei, date, dsValue, resource);
} else {
throw new IllegalArgumentException("Threshold type " + getThresholdConfig().getType().toString() + " is not supported");
}
case RE_ARMED:
uei=getThresholdConfig().getRearmedUEI();
if ("low".equals(getThresholdConfig().getType())) {
if(uei==null || "".equals(uei)) {
uei=EventConstants.LOW_THRESHOLD_REARM_EVENT_UEI;
}
return createBasicEvent(uei, date, dsValue, resource);
} else if ("high".equals(getThresholdConfig().getType())) {
if(uei==null || "".equals(uei)) {
uei=EventConstants.HIGH_THRESHOLD_REARM_EVENT_UEI;
}
return createBasicEvent(uei, date, dsValue, resource);
} else {
throw new IllegalArgumentException("Threshold type " + getThresholdConfig().getType().toString() + " is not supported");
}
case NO_CHANGE:
return null;
default:
throw new IllegalArgumentException("Status " + status + " is not supported for converting to an event.");
}
}
private Event createBasicEvent(String uei, Date date, double dsValue, CollectionResourceWrapper resource) {
Map<String,String> params = new HashMap<String,String>();
params.put("threshold", Double.toString(getThresholdConfig().getValue()));
params.put("trigger", Integer.toString(getThresholdConfig().getTrigger()));
params.put("rearm", Double.toString(getThresholdConfig().getRearm()));
return createBasicEvent(uei, date, dsValue, resource, params);
}
public ThresholdEvaluatorState getCleanClone() {
return new ThresholdEvaluatorStateHighLow(m_thresholdConfig);
}
public boolean isTriggered() {
return !isArmed();
}
public void clearState() {
setArmed(true);
setExceededCount(0);
}
}
}