/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* This program 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.core.domain.alert;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlTransient;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.operation.OperationRequestStatus;
/**
* An alert condition (e.g. ActiveThreads > 100) as configured in an alert definition.
*
* @author Joseph Marques
*/
@Entity
@NamedQueries({
@NamedQuery(name = "AlertCondition.findByTriggerId", query = "SELECT a FROM AlertCondition AS a WHERE a.triggerId = :tid"),
@NamedQuery(name = "AlertCondition.findAll", query = "SELECT a FROM AlertCondition AS a"),
@NamedQuery(name = AlertCondition.QUERY_DELETE_BY_RESOURCES, query = "DELETE FROM AlertCondition ac WHERE ac.alertDefinition IN ( SELECT ad FROM AlertDefinition ad WHERE ad.resource.id IN ( :resourceIds ) )"),
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_BASELINE, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionBaselineCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ms.id, " //
+ " mb.id, " //
+ " mb.baselineMin, " //
+ " mb.baselineMean, " //
+ " mb.baselineMax, " //
+ " md.dataType " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms JOIN ms.baseline mb " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND mb IS NOT NULL " //
+ " AND ac.category = 'BASELINE' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_COUNT_BASELINE, query = "" //
+ " SELECT count(ac.id) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms JOIN ms.baseline mb " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND mb IS NOT NULL " //
+ " AND ac.category = 'BASELINE' "), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_CHANGE, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionChangesCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ms.id, " //
+ " md.dataType " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND ac.category = 'CHANGE' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_TRAIT, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionTraitCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ms.id, " //
+ " (" //
+ " SELECT md.value " //
+ " FROM MeasurementDataTrait md " //
+ " WHERE md.schedule = ms " //
+ " AND md.id.timestamp = " //
+ " ( " //
+ " SELECT max(imd.id.timestamp) " //
+ " FROM MeasurementDataTrait imd " //
+ " WHERE ms.id = imd.schedule.id " //
+ " ) " //
+ " ) " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND ac.category = 'TRAIT' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_AVAILABILITY, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionAvailabilityCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ad.id, " // needed for avail duration
+ " res.id, " //
+ " (" //
+ " SELECT max(a.availabilityType) " //
+ " FROM Availability a " //
+ " JOIN a.resource ar " //
+ " WHERE ar = res " //
+ " AND a.endTime IS NULL " //
+ " ) " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = :category " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_CONTROL, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionControlCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " res.id, " //
+ " (" //
+ " SELECT op.id " //
+ " FROM OperationDefinition op " //
+ " WHERE op.resourceType = type " //
+ " AND op.name = ac.name " //
+ " ) " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN res.resourceType type " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = 'CONTROL' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_THRESHOLD, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionScheduleCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ms.id, " //
+ " md.dataType " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND ac.category = 'THRESHOLD' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_EVENT, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionEventCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " res.id " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = 'EVENT' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_RESOURCE_CONFIG, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionResourceConfigurationCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " res.id, " //
+ " resConfig " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " LEFT JOIN res.resourceConfiguration resConfig " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = 'RESOURCE_CONFIG' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_DRIFT, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionDriftCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " res.id " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = 'DRIFT' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_RANGE, query = "" //
+ " SELECT new org.rhq.core.domain.alert.composite.AlertConditionRangeCategoryComposite " //
+ " ( " //
+ AlertCondition.COMP_COLS
+ " ms.id, " //
+ " md.dataType " //
+ " ) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " JOIN ac.measurementDefinition md, MeasurementSchedule ms " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ms.definition = md " //
+ " AND ms.resource = res " //
+ " AND ac.category = 'RANGE' " //
+ "ORDER BY ac.id"), //
@NamedQuery(name = AlertCondition.QUERY_BY_CATEGORY_COUNT_PARAMETERIZED, query = "" //
+ " SELECT count(ac.id) " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " WHERE " + AlertCondition.RECOVERY_CONDITIONAL_EXPRESSION //
+ " AND ( res.agent.id = :agentId OR :agentId IS NULL ) " //
+ " AND ad.enabled = TRUE " //
+ " AND ad.deleted = FALSE " //
+ " AND ac.category = :category "),
@NamedQuery(name = AlertCondition.QUERY_FIND_RESOURCE_STATUS_BY_CONDITION_ID, query = "" //
+ " SELECT res.inventoryStatus " //
+ " FROM AlertCondition AS ac " //
+ " JOIN ac.alertDefinition ad " //
+ " JOIN ad.resource res " //
+ " WHERE ac.id = :alertConditionId "),
@NamedQuery(name = AlertCondition.QUERY_DELETE_ORPHANED, query = "" //
+ " DELETE FROM AlertCondition ac " //
+ " WHERE ac.alertDefinition IS NULL " //
+ " AND NOT EXISTS ( SELECT acl FROM AlertConditionLog acl WHERE acl.condition.id = ac.id ) ") })
@SequenceGenerator(allocationSize = org.rhq.core.domain.util.Constants.ALLOCATION_SIZE, name = "RHQ_ALERT_CONDITION_ID_SEQ", sequenceName = "RHQ_ALERT_CONDITION_ID_SEQ")
@Table(name = "RHQ_ALERT_CONDITION")
@XmlAccessorType(XmlAccessType.FIELD)
public class AlertCondition implements Serializable {
private static final long serialVersionUID = 1L;
/**
* When you select an entity into a composite, Hibernate creates an unloaded
* entity. This causes N+1 selects when the cache is created. Hence the select
* for every entity column, minus the alert definition ID.
*/
static final String COMP_COLS =
"ac.id, ac.category, ac.name, ac.comparator, ac.threshold, ac.option, ac.triggerId,";
public static final String QUERY_DELETE_BY_RESOURCES = "AlertCondition.deleteByResources";
public static final String QUERY_BY_CATEGORY_BASELINE = "AlertCondition.byCategoryBaseline";
public static final String QUERY_BY_CATEGORY_CHANGE = "AlertCondition.byCategoryChange";
public static final String QUERY_BY_CATEGORY_TRAIT = "AlertCondition.byCategoryTrait";
public static final String QUERY_BY_CATEGORY_AVAILABILITY = "AlertCondition.byCategoryAvailability";
public static final String QUERY_BY_CATEGORY_CONTROL = "AlertCondition.byCategoryControl";
public static final String QUERY_BY_CATEGORY_THRESHOLD = "AlertCondition.byCategoryThreshold";
public static final String QUERY_BY_CATEGORY_EVENT = "AlertCondition.byCategoryEvent";
public static final String QUERY_BY_CATEGORY_RESOURCE_CONFIG = "AlertCondition.byCategoryResourceConfig";
public static final String QUERY_BY_CATEGORY_DRIFT = "AlertCondition.byCategoryDrift";
public static final String QUERY_BY_CATEGORY_RANGE = "AlertCondition.byCategoryRange";
public static final String QUERY_BY_CATEGORY_COUNT_BASELINE = "AlertCondition.byCategoryCountBaseline";
public static final String QUERY_BY_CATEGORY_COUNT_PARAMETERIZED = "AlertCondition.byCategoryCountParameterized";
public static final String QUERY_FIND_RESOURCE_STATUS_BY_CONDITION_ID = "AlertCondition.findResourceStatus";
public static final String QUERY_DELETE_ORPHANED = "AlertCondition.deleteOrphaned";
public static final String RECOVERY_CONDITIONAL_EXPRESSION = "" //
+ " ( ad.recoveryId = 0 " //
+ " OR ( ad.recoveryId <> 0 " //
+ " AND EXISTS ( SELECT iad FROM AlertDefinition iad " //
+ " WHERE iad.id = ad.recoveryId " //
+ " AND iad.deleted = FALSE " //
+ " AND iad.enabled = FALSE " //
+ " ) " //
+ " ) " //
+ " ) ";
public static final String ADHOC_SEPARATOR = "@@@";
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "RHQ_ALERT_CONDITION_ID_SEQ")
@Id
private int id;
@Column(name = "TYPE", nullable = false)
@Enumerated(EnumType.STRING)
private AlertConditionCategory category;
@JoinColumn(name = "MEASUREMENT_DEFINITION_ID", referencedColumnName = "ID", nullable = true)
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@XmlTransient
private MeasurementDefinition measurementDefinition;
@Column(name = "NAME")
private String name;
@Column(name = "COMPARATOR")
private String comparator;
@Column(name = "THRESHOLD")
private Double threshold;
@Column(name = "OPTION_STATUS")
private String option;
@Column(name = "TRIGGER_ID")
private Integer triggerId;
@JoinColumn(name = "ALERT_DEFINITION_ID", referencedColumnName = "ID", nullable = true)
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@XmlTransient
private AlertDefinition alertDefinition;
@OneToMany(mappedBy = "condition", cascade = CascadeType.ALL)
@OrderBy
// primary key
private Set<AlertConditionLog> conditionLogs = new LinkedHashSet<AlertConditionLog>();
/**
* Creates a new alert condition.
*/
public AlertCondition() {
}
public AlertCondition(AlertDefinition alertDef, AlertConditionCategory type) {
this.alertDefinition = alertDef;
this.category = type;
}
/**
* Creates a skeletal copy of the specified alert condition.
*
* @param cond the alert condition to be copied
*/
public AlertCondition(AlertCondition cond) {
this.category = cond.category;
this.measurementDefinition = cond.measurementDefinition;
this.name = cond.name;
this.comparator = cond.comparator;
this.threshold = cond.threshold;
this.option = cond.option;
this.triggerId = cond.triggerId;
// Don't copy the condition logs.
}
/**
* Construct with some fields.
*/
public AlertCondition(int id, AlertConditionCategory category, String name,
String comparator, Double threshold, String option,
Integer triggerId)
{
this.id = id;
this.category = category;
this.name = name;
this.comparator = comparator;
this.threshold = threshold;
this.option = option;
this.triggerId = triggerId;
}
public int getId() {
return this.id;
}
public AlertConditionCategory getCategory() {
return this.category;
}
public void setCategory(AlertConditionCategory category) {
this.category = category;
}
/**
* Identifies the measurement definition of the metric that is to be compared when determining
* if the condition is true. This is null if the condition category is not a metric-related one
* (metric related categories are THRESHOLD, TRAIT, BASELINE and CHANGE; others are not).
*
* @return measurement definition or null
*/
public MeasurementDefinition getMeasurementDefinition() {
return this.measurementDefinition;
}
public void setMeasurementDefinition(MeasurementDefinition measurementDefinition) {
this.measurementDefinition = measurementDefinition;
}
/**
* The name of the condition whose semantics are different based on this condition's category:
*
* AVAILABILITY: The relevant Avail AlertConditionOperator name
* THRESHOLD: the name of the metric (TODO: today its the display name, very bad for i18n purposes)
* BASELINE: the name of the metric (TODO: today its the display name, very bad for i18n purposes)
* CHANGE: the name of the metric (TODO: today its the display name, very bad for i18n purposes)
* OR (for calltime alert conditions only) this will be the optional regular expression condition
* (which may be null)
* TRAIT: the name of the trait (TODO: today its the display name, very bad for i18n purposes)
* CONTROL: the name of the operation (not its display name)
* EVENT: the level of event to compare with (DEBUG, INFO, WARN, ERROR, FATAL)
* RESOURCE_CONFIG: n/a (null)
* DRIFT: the name of the drift definition that triggered the drift detection. This is actually a
* regex that allows the user to match more than one drift definition if they so choose.
* (this value may be null, in which case it doesn't matter which drift definition were the ones
* in which the drift was detected)
* RANGE: the name of the metric (TODO: today its the display name, very bad for i18n purposes)
*
* @return additional information about the condition
*/
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
/**
* THRESHOLD and BASELINE: one of these comparators: "<", ">" or "="
* For calltime alert conditions (i.e. category CHANGE for calltime metric definitions),
* comparator will be one of these comparators: "HI", "LO", "CH" (where "CH" means "change").
* RANGE: one of these comparators "<", ">" (meaning inside and outside the range respectively)
* or one of these "<=", ">=" (meaning inside and outside inclusive respectively)
*
* Other types of conditions will return <code>null</code> (i.e. this will be
* null if the condition does not compare values).
*
* @return comparator string
*/
public String getComparator() {
return this.comparator;
}
public void setComparator(String comparator) {
this.comparator = comparator;
}
/**
* Returns the threshold to compare a measurement value to see if the condition is true.
* This is only valid for conditions of category THRESHOLD, BASELINE, RANGE and CHANGE (but
* only where CHANGE is for a calltime metric alert condition). All other
* condition types will return <code>null</code>.
*
* Note: If RANGE condition, this threshold is always the LOW end of the range.
* The high end of the range is in {@link #getOption()}.
*
* @return threshold value or null
*/
public Double getThreshold() {
return this.threshold;
}
public void setThreshold(Double threshold) {
this.threshold = threshold;
}
/**
* The option string is optional and its semantics differ based on the category of this condition:
* AVAILABILITY: n/a
* AVAIL_DURATION: the duration, in minutes
* THRESHOLD: for calltime metric conditions, one of "MIN, "MAX", "AVG" - all others are n/a
* BASELINE: one of "min", "max" or "mean" - indicates what the threshold is compared to (min/max/avg baseline value)
* CHANGE: for calltime metric conditions, one of "MIN, "MAX", "AVG" - all others are n/a
* TRAIT: n/a
* CONTROL: the {@link OperationRequestStatus} name (SUCCESS, FAILURE, etc).
* EVENT: the regular expression of the message to match (which may be empty string if not specified)
* RESOURCE_CONFIG: n/a
* DRIFT: a regular expression to match files whose content drifted (may be empty string or null if not specified)
* RANGE: the string form of a double value that is the HIGH end of the range (low end is {@link #getThreshold()})
*
* @return additional information about the condition
*/
public String getOption() {
return this.option;
}
public void setOption(String option) {
this.option = option;
}
public Integer getTriggerId() {
return this.triggerId;
}
public void setTriggerId(Integer triggerId) {
this.triggerId = triggerId;
}
public AlertDefinition getAlertDefinition() {
return this.alertDefinition;
}
public void setAlertDefinition(AlertDefinition alertDef) {
this.alertDefinition = alertDef;
}
public Set<AlertConditionLog> getConditionLogs() {
return this.conditionLogs;
}
public void addConditionLog(AlertConditionLog condLog) {
this.conditionLogs.add(condLog);
condLog.setCondition(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AlertCondition)) {
return false;
}
final AlertCondition other = (AlertCondition) obj;
if (category == null) {
if (other.category != null) {
return false;
}
} else if (!category.equals(other.category)) {
return false;
}
if (comparator == null) {
if (other.comparator != null) {
return false;
}
} else if (!comparator.equals(other.comparator)) {
return false;
}
if (id != other.id) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (option == null) {
if (other.option != null) {
return false;
}
} else if (!option.equals(other.option)) {
return false;
}
if (threshold == null) {
if (other.threshold != null) {
return false;
}
} else if (!threshold.equals(other.threshold)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((category == null) ? 0 : category.hashCode());
result = (prime * result) + ((comparator == null) ? 0 : comparator.hashCode());
result = (prime * result) + id;
result = (prime * result) + ((name == null) ? 0 : name.hashCode());
result = (prime * result) + ((option == null) ? 0 : option.hashCode());
result = (prime * result) + ((threshold == null) ? 0 : threshold.hashCode());
return result;
}
@Override
public String toString() {
return "org.rhq.core.domain.alert.AlertCondition" + "[ " + "id=" + id + ", " + "category=" + category + ", "
+ "name=" + name + ", " + "comparator='" + comparator + "', " + "threshold=" + threshold + ", " + "option="
+ option + " ]";
}
}