package rocks.inspectit.shared.cs.ci;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import rocks.inspectit.shared.all.util.EMailUtils;
/**
* XML element which represents a threshold used for alerting purpose.
*
* @author Marius Oehler
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "alerting-definition")
public class AlertingDefinition extends AbstractCiData {
/**
* Threshold types.
*
* @author Marius Oehler
*
*/
public enum ThresholdType {
/**
* The specified threshold is an upper threshold. Alert is issued if the threshold is
* exceeded.
*/
UPPER_THRESHOLD("Upper Threshold"),
/**
* The specified threshold is an lower threshold. Alert is issued if the threshold is
* undercut.
*/
LOWER_THRESHOLD("Lower Threshold");
/**
* The name of the threshold type.
*/
private String name;
/**
* Constructor.
*
* @param name
* the name of the threshold type
*/
ThresholdType(String name) {
this.name = name;
}
/**
* Gets {@link #name}.
*
* @return {@link #name}
*/
public String getName() {
return this.name;
}
}
/**
* The threshold.
*/
@XmlAttribute(name = "threshold")
private Double threshold;
/**
* The field to check against the threshold.
*/
@XmlAttribute(name = "field")
private String field;
/**
* The type of the specified threshold.
*/
@XmlAttribute(name = "threshold-type")
private ThresholdType thresholdType = ThresholdType.UPPER_THRESHOLD;
/**
* The measurement to monitor.
*/
@XmlAttribute(name = "measurement")
private String measurement;
/**
* The tags used to select the monitored data.
*/
@XmlElementWrapper(name = "tags")
private Map<String, String> tags = new HashMap<>(0);
/**
* The duration between consecutive checks in minutes.
*/
@XmlAttribute(name = "timerange")
private Long timeRange;
/**
* List of e-mails which receives a notification when the threshold is violated.
*/
@XmlElementWrapper(name = "notification-email-addresses")
@XmlElement(name = "notification-email-address")
private List<String> notificationEmailAddresses = new ArrayList<>(0);
/**
* Default constructor.
*/
public AlertingDefinition() {
}
/**
* Clone constructor.
*
* @param template
* template for the new instance
*/
public AlertingDefinition(AlertingDefinition template) {
super(template);
if (template != null) {
this.threshold = template.threshold;
this.field = template.field;
this.thresholdType = template.thresholdType;
this.measurement = template.measurement;
this.timeRange = template.timeRange;
if (notificationEmailAddresses != null) {
this.notificationEmailAddresses = new ArrayList<>(template.notificationEmailAddresses);
}
if (tags != null) {
this.tags = new HashMap<>(template.tags);
}
}
}
/**
* Adds a email address to the alerting definition.
*
* @param email
* the email address to add
* @return result of the adding (as specified by {@link Collection#add(Object)})
*/
public boolean addNotificationEmailAddress(String email) {
if (email == null) {
throw new IllegalArgumentException("Adding email adress 'null'.");
} else if (email.isEmpty()) {
throw new IllegalArgumentException("Adding empty email address.");
} else if (!EMailUtils.isValidEmailAddress(email)) {
throw new IllegalArgumentException("Adding invalid email address '" + email + "'.");
} else if (notificationEmailAddresses.contains(email)) {
throw new IllegalArgumentException("Adding email address '" + email + "'.");
} else {
return notificationEmailAddresses.add(email);
}
}
/**
* Gets {@link #field}.
*
* @return {@link #field}
*/
public String getField() {
return field;
}
/**
* Gets {@link #measurement}.
*
* @return {@link #measurement}
*/
public String getMeasurement() {
return measurement;
}
/**
* Gets {@link #notificationEmailAddresses}.
*
* @return {@link #notificationEmailAddresses}
*/
public List<String> getNotificationEmailAddresses() {
return Collections.unmodifiableList(notificationEmailAddresses);
}
/**
* Gets {@link #tags}.
*
* @return {@link #tags}
*/
public Map<String, String> getTags() {
return Collections.unmodifiableMap(tags);
}
/**
* Gets {@link #threshold}.
*
* @return {@link #threshold}
*/
public double getThreshold() {
return threshold.doubleValue();
}
/**
* Gets {@link #thresholdType}.
*
* @return {@link #thresholdType}
*/
public ThresholdType getThresholdType() {
return thresholdType;
}
/**
* Gets {@link #timeRange}.
*
* @param unit
* the time unit of the returned value
* @return {@link #timeRange}
*/
public long getTimeRange(TimeUnit unit) {
return unit.convert(timeRange, TimeUnit.MINUTES);
}
/**
* Puts a tag represented by the given key-value to the alerting definition. A previously added
* tag containing the same key will be overridden.
*
* @param tagKey
* the tag key
* @param tagValue
* the tag value
* @return returns the previous value related to the given key (as specified by
* {@link Map#put(Object, Object)}
*/
public String putTag(String tagKey, String tagValue) {
if (tagKey == null) {
throw new IllegalArgumentException("Putting tag with key 'null'.");
} else if (tagValue == null) {
throw new IllegalArgumentException("Putting tag with value 'null'.");
} else if (tagKey.isEmpty()) {
throw new IllegalArgumentException("Putting tag with empty key.");
} else if (tagValue.isEmpty()) {
throw new IllegalArgumentException("Putting tag with empty value.");
} else {
return tags.put(tagKey, tagValue);
}
}
/**
* Removes the given email address from the alerting definition.
*
* @param email
* the email address to remove
* @return result of the removing (as specified by {@link Collection#remove(Object)}
*/
public boolean removeNotificationEmailAddress(String email) {
if (email == null) {
throw new IllegalArgumentException("Adding email adress 'null'.");
} else if (email.isEmpty()) {
throw new IllegalArgumentException("Adding empty email address.");
} else {
return notificationEmailAddresses.remove(email);
}
}
/**
* Removes the tag with the given key from the alerting definition.
*
* @param tagKey
* the key of the tag to remove
*/
public void removeTag(String tagKey) {
if (tagKey == null) {
throw new IllegalArgumentException("Removing tag with key 'null'.");
} else if (tagKey.isEmpty()) {
throw new IllegalArgumentException("Removing tag with empty key.");
} else if (!tags.containsKey(tagKey)) {
throw new IllegalArgumentException("Removing tag with key '" + tagKey + "'.");
} else {
tags.remove(tagKey);
}
}
/**
* Replaces the current notification email addresses with the ones of the given list.
*
* @param newNotificationEmailAddresses
* new email addresses
*/
public void replaceNotificationEmailAddresses(List<String> newNotificationEmailAddresses) {
if (newNotificationEmailAddresses == null) {
throw new IllegalArgumentException("Replacing notification email list with 'null'.");
}
notificationEmailAddresses.clear();
for (String emailAddress : newNotificationEmailAddresses) {
addNotificationEmailAddress(emailAddress);
}
}
/**
* Replacing the current tags with the tags contained on the given map.
*
* @param newTags
* map contains the new tags
*/
public void replaceTags(Map<String, String> newTags) {
if (newTags == null) {
throw new IllegalArgumentException("Replacing the current tags with a null map.");
}
tags.clear();
for (Entry<String, String> tag : newTags.entrySet()) {
putTag(tag.getKey(), tag.getValue());
}
}
/**
* Sets {@link #field}.
*
* @param field
* New value for {@link #field}
*/
public void setField(String field) {
this.field = field;
}
/**
* Sets {@link #measurement}.
*
* @param measurement
* New value for {@link #measurement}
*/
public void setMeasurement(String measurement) {
this.measurement = measurement;
}
/**
* Sets {@link #threshold}.
*
* @param threshold
* New value for {@link #threshold}
*/
public void setThreshold(double threshold) {
this.threshold = threshold;
}
/**
* Sets {@link #thresholdType}.
*
* @param thresholdType
* New value for {@link #thresholdType}
*/
public void setThresholdType(ThresholdType thresholdType) {
this.thresholdType = thresholdType;
}
/**
* Sets {@link #timeRange}.
*
* @param timeRange
* New value for {@link #timeRange}
* @param unit
* the time unit of the given time range
*/
public void setTimeRange(Long timeRange, TimeUnit unit) {
this.timeRange = TimeUnit.MINUTES.convert(timeRange, unit);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = (prime * result) + ((field == null) ? 0 : field.hashCode());
result = (prime * result) + ((measurement == null) ? 0 : measurement.hashCode());
result = (prime * result) + ((notificationEmailAddresses == null) ? 0 : notificationEmailAddresses.hashCode());
result = (prime * result) + ((tags == null) ? 0 : tags.hashCode());
result = (prime * result) + ((threshold == null) ? 0 : threshold.hashCode());
result = (prime * result) + ((thresholdType == null) ? 0 : thresholdType.hashCode());
result = (prime * result) + ((timeRange == null) ? 0 : timeRange.hashCode());
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AlertingDefinition other = (AlertingDefinition) obj;
if (field == null) {
if (other.field != null) {
return false;
}
} else if (!field.equals(other.field)) {
return false;
}
if (measurement == null) {
if (other.measurement != null) {
return false;
}
} else if (!measurement.equals(other.measurement)) {
return false;
}
if (notificationEmailAddresses == null) {
if (other.notificationEmailAddresses != null) {
return false;
}
} else if (!notificationEmailAddresses.equals(other.notificationEmailAddresses)) {
return false;
}
if (tags == null) {
if (other.tags != null) {
return false;
}
} else if (!tags.equals(other.tags)) {
return false;
}
if (threshold == null) {
if (other.threshold != null) {
return false;
}
} else if (!threshold.equals(other.threshold)) {
return false;
}
if (thresholdType != other.thresholdType) {
return false;
}
if (timeRange == null) {
if (other.timeRange != null) {
return false;
}
} else if (!timeRange.equals(other.timeRange)) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
String thresholdString = threshold == null ? "" : " threshold=" + getThreshold();
String timeRangeString = timeRange == null ? "" : ", timerange=" + getTimeRange(TimeUnit.MINUTES);
return getName() + thresholdString + ", type=" + getThresholdType() + timeRangeString;
}
}