/*
* NOTE: This copyright does *not* cover user programs that use Hyperic
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004-2010], VMware, Inc.
* This file is part of Hyperic.
*
* Hyperic is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.hq.events.server.session;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hibernate.PageInfo;
import org.hyperic.hq.appdef.server.session.AppdefResourceType;
import org.hyperic.hq.appdef.shared.AppdefEntityID;
import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException;
import org.hyperic.hq.appdef.shared.AppdefEntityTypeID;
import org.hyperic.hq.appdef.shared.AppdefEntityValue;
import org.hyperic.hq.authz.server.session.AuthzSubject;
import org.hyperic.hq.authz.server.session.Resource;
import org.hyperic.hq.authz.server.session.ResourceDeleteRequestedEvent;
import org.hyperic.hq.authz.server.session.ResourceType;
import org.hyperic.hq.authz.shared.AuthzConstants;
import org.hyperic.hq.authz.shared.AuthzSubjectManager;
import org.hyperic.hq.authz.shared.PermissionException;
import org.hyperic.hq.authz.shared.PermissionManagerFactory;
import org.hyperic.hq.authz.shared.ResourceManager;
import org.hyperic.hq.bizapp.shared.action.EnableAlertDefActionConfig;
import org.hyperic.hq.common.SystemException;
import org.hyperic.hq.escalation.server.session.Escalation;
import org.hyperic.hq.escalation.shared.EscalationManager;
import org.hyperic.hq.events.ActionCreateException;
import org.hyperic.hq.events.ActionInterface;
import org.hyperic.hq.events.AlertConditionCreateException;
import org.hyperic.hq.events.AlertDefinitionCreateException;
import org.hyperic.hq.events.AlertPermissionManager;
import org.hyperic.hq.events.AlertSeverity;
import org.hyperic.hq.events.EventConstants;
import org.hyperic.hq.events.shared.ActionValue;
import org.hyperic.hq.events.shared.AlertConditionValue;
import org.hyperic.hq.events.shared.AlertDefinitionManager;
import org.hyperic.hq.events.shared.AlertDefinitionValue;
import org.hyperic.hq.events.shared.RegisteredTriggerManager;
import org.hyperic.hq.events.shared.RegisteredTriggerValue;
import org.hyperic.hq.measurement.MeasurementNotFoundException;
import org.hyperic.hq.measurement.action.MetricAlertAction;
import org.hyperic.hq.measurement.server.session.Measurement;
import org.hyperic.hq.measurement.server.session.MetricsEnabledEvent;
import org.hyperic.hq.measurement.shared.MeasurementManager;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.EncodingException;
import org.hyperic.util.config.InvalidOptionException;
import org.hyperic.util.config.InvalidOptionValueException;
import org.hyperic.util.pager.PageControl;
import org.hyperic.util.pager.PageList;
import org.hyperic.util.pager.Pager;
import org.hyperic.util.pager.SortAttribute;
import org.hyperic.util.timer.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
* Stores Events to and deletes Events from storage
*
* </p>
*
*/
@Service
@Transactional
public class AlertDefinitionManagerImpl implements AlertDefinitionManager,
ApplicationListener<ApplicationEvent> {
private final Log log = LogFactory.getLog(AlertDefinitionManagerImpl.class);
private final AlertPermissionManager alertPermissionManager;
private final String VALUE_PROCESSOR = PagerProcessor_events.class.getName();
private Pager _valuePager = null;
private AlertDefinitionDAO alertDefDao;
private ActionDAO actionDao;
private AlertConditionDAO alertConditionDAO;
private AlertDAO alertDAO;
private final MeasurementManager measurementManager;
private final RegisteredTriggerManager registeredTriggerManager;
private final ResourceManager resourceManager;
private final EscalationManager escalationManager;
private final AuthzSubjectManager authzSubjectManager;
private final AlertAuditFactory alertAuditFactory;
private final AvailabilityDownAlertDefinitionCache availabilityDownAlertDefinitionCache;
@Autowired
public AlertDefinitionManagerImpl(AlertPermissionManager alertPermissionManager, AlertDefinitionDAO alertDefDao,
ActionDAO actionDao, AlertConditionDAO alertConditionDAO,
MeasurementManager measurementManager, RegisteredTriggerManager registeredTriggerManager,
ResourceManager resourceManager, EscalationManager escalationManager,
AlertAuditFactory alertAuditFactory, AlertDAO alertDAO,
AuthzSubjectManager authzSubjectManager,
AvailabilityDownAlertDefinitionCache availabilityDownAlertDefinitionCache) {
this.alertPermissionManager = alertPermissionManager;
this.alertDefDao = alertDefDao;
this.actionDao = actionDao;
this.alertConditionDAO = alertConditionDAO;
this.measurementManager = measurementManager;
this.registeredTriggerManager = registeredTriggerManager;
this.resourceManager = resourceManager;
this.escalationManager = escalationManager;
this.authzSubjectManager = authzSubjectManager;
this.alertAuditFactory = alertAuditFactory;
this.alertDAO = alertDAO;
this.availabilityDownAlertDefinitionCache = availabilityDownAlertDefinitionCache;
}
@PostConstruct
public void afterPropertiesSet() throws Exception {
_valuePager = Pager.getPager(VALUE_PROCESSOR);
}
@PreDestroy
public final void destroy() {
this.alertDefDao = null ;
this.actionDao = null ;
this.alertConditionDAO = null ;
this.alertDAO = null ;
}//EOM
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ResourceDeleteRequestedEvent) {
disassociateResource(((ResourceDeleteRequestedEvent) event).getResource());
} else if (event instanceof MetricsEnabledEvent) {
metricsEnabled(((MetricsEnabledEvent) event).getEntityId());
}
}
private boolean deleteAlertDefinitionStuff(AuthzSubject subj, AlertDefinition alertdef, EscalationManager escMan) {
StopWatch watch = new StopWatch();
// Delete escalation state
watch.markTimeBegin("endEscalation");
if (alertdef.getEscalation() != null && !alertdef.isResourceTypeDefinition()) {
escMan.endEscalation(alertdef);
}
watch.markTimeEnd("endEscalation");
availabilityDownAlertDefinitionCache.removeFromCache(alertdef);
if (log.isDebugEnabled()) {
log.debug("deleteAlertDefinitionStuff: " + watch);
}
return true;
}
/**
* Remove alert definitions. It is assumed that the subject has permission
* to remove this alert definition and any of its' child alert definitions.
*/
private boolean deleteAlertDefinition(AuthzSubject subj, AlertDefinition alertdef, boolean force)
throws PermissionException {
final boolean debug = log.isDebugEnabled();
StopWatch watch = new StopWatch();
if (force) { // Used when resources are being deleted
// Disassociate from Resource so that the Resource can be deleted
alertdef.setResource(null);
} else {
// If there are any children, delete them, too
if(debug){
watch.markTimeBegin("delete children");
}
List<AlertDefinition> childBag = new ArrayList<AlertDefinition>(alertdef.getChildrenBag());
for (AlertDefinition child : childBag) {
deleteAlertDefinitionStuff(subj, child, escalationManager);
registeredTriggerManager.deleteTriggers(child);
}
if (debug) watch.markTimeBegin("deleteByAlertDefinition");
alertDefDao.deleteByAlertDefinition(alertdef);
if(debug) {
watch.markTimeEnd("deleteByAlertDefinition");
watch.markTimeEnd("delete children");
}
}
deleteAlertDefinitionStuff(subj, alertdef, escalationManager);
if (debug) watch.markTimeBegin("deleteTriggers");
registeredTriggerManager.deleteTriggers(alertdef);
if(debug) watch.markTimeBegin("deleteTriggers");
if(debug) watch.markTimeBegin("markActionsDeleted");
actionDao.deleteAlertDefinition(alertdef);
if(debug) watch.markTimeBegin("markActionsDeleted");
if(debug) watch.markTimeBegin("mark deleted");
// Disassociated from escalations
alertdef.setEscalation(null);
alertdef.setDeleted(true);
alertdef.setActiveStatus(false);
// Disassociate from parent
// This must be at the very end since we use the parent to determine
// whether or not this is a resource type alert definition.
alertdef.setParent(null);
if (debug) {
watch.markTimeEnd("mark deleted");
log.debug("deleteAlertDefinition: " + watch);
}
return true;
}
/**
* Get the MetricAlertAction ActionValue from an AlertDefinitionValue. If
* none exists, return null.
*/
private ActionValue getMetricAlertAction(AlertDefinitionValue adv) {
ActionValue[] actions = adv.getActions();
for (int i = 0; i < actions.length; ++i) {
String actionClass = actions[i].getClassname();
if (MetricAlertAction.class.getName().equals(actionClass)) {
return actions[i];
}
}
return null;
}
private void setMetricAlertAction(AlertDefinitionValue adval) {
AlertConditionValue[] conds = adval.getConditions();
for (int i = 0; i < conds.length; i++) {
if (conds[i].getType() == EventConstants.TYPE_THRESHOLD ||
conds[i].getType() == EventConstants.TYPE_BASELINE ||
conds[i].getType() == EventConstants.TYPE_CHANGE) {
ActionValue action = getMetricAlertAction(adval);
// if MetricAlertAction doesn't exist, add one
if (action == null) {
action = new ActionValue();
action.setClassname(MetricAlertAction.class.getName());
ConfigResponse config = new ConfigResponse();
try {
action.setConfig(config.encode());
} catch (EncodingException e) {
// This should never happen
log.error("Empty ConfigResponse threw an encoding error", e);
}
adval.addAction(action);
}
break;
}
}
}
/**
* Create a new alert definition
*/
public AlertDefinitionValue createAlertDefinition(AuthzSubject subj, AlertDefinitionValue a)
throws AlertDefinitionCreateException, PermissionException {
if (EventConstants.TYPE_ALERT_DEF_ID.equals(a.getParentId())) {
// ...check that user has access to resource type alert definitions alert definition's resource...
alertPermissionManager.canCreateResourceTypeAlertDefinitionTemplate(subj);
// Subject permissions should have already been checked when
// creating
// the parent (resource type) alert definition.
} else if (!a.parentIdHasBeenSet()) {
// ...check that user has create permission on alert definition's resource...
alertPermissionManager.canCreateAlertDefinition(subj, new AppdefEntityID(a.getAppdefType(),
a.getAppdefId()));
}
return createAlertDefinition(a);
}
/**
* Create a new alert definition
*/
public AlertDefinitionValue createAlertDefinition(AlertDefinitionValue a)
throws AlertDefinitionCreateException {
// Create a measurement AlertLogAction if necessary
setMetricAlertAction(a);
// HHQ-1054: since the alert definition mtime is managed explicitly,
// let's initialize it
a.initializeMTimeToNow();
AlertDefinition res = new AlertDefinition();
// The following is duplicated out of what the Impl did. Makes sense
a.cleanAction();
a.cleanCondition();
a.cleanTrigger();
alertDefDao.setAlertDefinitionValue(res, a);
// Create new conditions
AlertConditionValue[] conds = a.getConditions();
for (AlertConditionValue condition : conds) {
RegisteredTrigger trigger = condition.getTriggerId() != null ? registeredTriggerManager.findById(condition
.getTriggerId()) : null;
AlertCondition cond = res.createCondition(condition, trigger);
if (res.getName() == null || res.getName().trim().length() == 0) {
Measurement dm = measurementManager.findMeasurementById(new Integer(cond.getMeasurementId()));
if (dm == null) {
throw new AlertDefinitionCreateException(
"Could not automatically name the alert definition "
+ "because the AlertCondition (id=" + cond.getId()
+ ") has an associated Measurement (id="
+ cond.getMeasurementId() + ") that does not exist.");
}
String predefinedAlertDefName = cond.describe(dm);
if (predefinedAlertDefName == null
|| predefinedAlertDefName.trim().length() == 0) {
throw new AlertDefinitionCreateException(
"Could not automatically name the alert definition "
+ "based on the alert condition.");
}
res.setName(predefinedAlertDefName);
}
if (cond.getType() == EventConstants.TYPE_ALERT) {
setEnableAlertDefAction(a, cond.getMeasurementId());
}
alertConditionDAO.save(cond);
}
// Create actions
ActionValue[] actions = a.getActions();
for (ActionValue action : actions) {
Action parent = null;
if (action.getParentId() != null)
parent = actionDao.findById(action.getParentId());
Action act = res.createAction(action.getClassname(), action.getConfig(), parent);
actionDao.save(act);
}
// Set triggers
for (RegisteredTriggerValue trigger : a.getTriggers()) {
RegisteredTrigger trig;
// Triggers were already created by bizapp, so we only need
// to add them to our list
trig = registeredTriggerManager.findById(trigger.getId());
trig.setAlertDefinition(res);
}
Integer esclId = a.getEscalationId();
if (esclId != null) {
Escalation escalation = escalationManager.findById(esclId);
res.setEscalation(escalation);
}
// Alert definitions are the root of the cascade relationship, so
// we must explicitly save them
alertDefDao.save(res);
availabilityDownAlertDefinitionCache.removeFromCache(res);
return res.getAlertDefinitionValue();
}
/**
* Update just the basics
* @throws PermissionException
*
*/
public void updateAlertDefinitionBasic(AuthzSubject subj, Integer id, String name, String desc, int priority,
boolean activate) throws PermissionException {
final boolean debug = log.isDebugEnabled();
StopWatch watch = new StopWatch();
AlertDefinition def = alertDefDao.findById(id);
// ...check that user has modify permission on alert definition's resource...
alertPermissionManager.canModifyAlertDefinition(subj, def.getAppdefEntityId());
int initCapacity = def.getChildren().size() + 1;
List<AlertDefinition> alertdefs = new ArrayList<AlertDefinition>(initCapacity);
List<Integer> defIds = new ArrayList<Integer>(initCapacity);
alertdefs.add(def);
if (debug) watch.markTimeBegin("getChildren");
// If there are any children, add them, too
alertdefs.addAll(def.getChildren());
if (debug) {
watch.markTimeEnd("getChildren");
watch.markTimeBegin("updateBasic");
}
for (AlertDefinition child : alertdefs) {
child.setName(name);
child.setDescription(desc);
child.setPriority(priority);
if (child.isActive() != activate || child.isEnabled() != activate) {
child.setActiveStatus(activate);
alertAuditFactory.enableAlert(child, subj);
defIds.add(def.getId());
}
child.setMtime(System.currentTimeMillis());
availabilityDownAlertDefinitionCache.removeFromCache(child);
}
if (debug) {
watch.markTimeEnd("updateBasic");
watch.markTimeBegin("setAlertDefinitionTriggersEnabled");
}
registeredTriggerManager.setAlertDefinitionTriggersEnabled(defIds, activate);
if (debug) {
watch.markTimeEnd("setAlertDefinitionTriggersEnabled");
log.debug("updateAlertDefinitionBasic[" + initCapacity + "]: " + watch);
}
}
/**
* Get the EnableAlertDefAction ActionValue from an AlertDefinitionValue. If
* none exists, return null.
*/
private ActionValue getEnableAlertDefAction(AlertDefinitionValue adv) {
EnableAlertDefActionConfig cfg = new EnableAlertDefActionConfig();
for (ActionValue action : adv.getActions()) {
String actionClass = action.getClassname();
if (cfg.getImplementor().equals(actionClass))
return action;
}
return null;
}
private void setEnableAlertDefAction(AlertDefinitionValue adval, int recoverId) {
EnableAlertDefActionConfig action =
new EnableAlertDefActionConfig();
// Find recovery actions first
ActionValue recoverAction = getEnableAlertDefAction(adval);
if (recoverAction != null) {
try {
ConfigResponse configResponse =
ConfigResponse.decode(recoverAction.getConfig());
action.init(configResponse);
if (action.getAlertDefId() != recoverId) {
action.setAlertDefId(recoverId);
recoverAction.setConfig(action
.getConfigResponse()
.encode());
adval.updateAction(recoverAction);
}
} catch (Exception e) {
adval.removeAction(recoverAction);
recoverAction = null;
}
}
// Add action if doesn't exist
if (recoverAction == null) {
recoverAction = new ActionValue();
action.setAlertDefId(recoverId);
recoverAction.setClassname(action.getImplementor());
try {
recoverAction
.setConfig(action.getConfigResponse().encode());
} catch (EncodingException e) {
log.debug("Error encoding EnableAlertDefAction", e);
} catch (InvalidOptionException e) {
log.debug("Error encoding EnableAlertDefAction", e);
} catch (InvalidOptionValueException e) {
log.debug("Error encoding EnableAlertDefAction", e);
}
adval.addAction(recoverAction);
}
}
/**
* Update an alert definition
*/
public AlertDefinitionValue updateAlertDefinition(AlertDefinitionValue adval) throws AlertConditionCreateException,
ActionCreateException {
AlertDefinition aldef = alertDefDao.findById(adval.getId());
// Create a measurement AlertLogAction if necessary
setMetricAlertAction(adval);
// Find recovery actions first
int recoverId = -1;
// See if the conditions changed
if (adval.getAddedConditions().size() > 0 || adval.getUpdatedConditions().size() > 0 ||
adval.getRemovedConditions().size() > 0) {
// We need to keep old conditions around for the logs. So
// we'll create new conditions and update the alert
// definition, but we won't remove the old conditions.
AlertConditionValue[] conds = adval.getConditions();
aldef.clearConditions();
for (AlertConditionValue condition : conds) {
RegisteredTrigger trigger = null;
// Trigger ID is null for resource type alerts
if (condition.getTriggerId() != null)
trigger = registeredTriggerManager.findById(condition.getTriggerId());
if (condition.getType() == EventConstants.TYPE_ALERT) {
recoverId = condition.getMeasurementId();
}
aldef.createCondition(condition, trigger);
}
}
if (recoverId > 0) {
setEnableAlertDefAction(adval, recoverId);
} else {
// Remove recover action if exists
ActionValue recoverAction = getEnableAlertDefAction(adval);
if (recoverAction != null) {
adval.removeAction(recoverAction);
}
}
// See if the actions changed
if (adval.getAddedActions().size() > 0 || adval.getUpdatedActions().size() > 0 ||
adval.getRemovedActions().size() > 0 || adval.getActions().length != aldef.getActions().size()) {
// We need to keep old actions around for the logs. So
// we'll create new actions and update the alert
// definition, but we won't remove the old actions.
ActionValue[] actions = adval.getActions();
aldef.clearActions();
for (ActionValue action : actions) {
Action parent = null;
if (action.getParentId() != null)
parent = actionDao.findById(action.getParentId());
actionDao.save(aldef.createAction(action.getClassname(), action.getConfig(), parent));
}
}
// Find out the last trigger ID (bizapp should have created them)
RegisteredTriggerValue[] triggers = adval.getTriggers();
for (int i = 0; i < triggers.length; i++) {
RegisteredTrigger t = registeredTriggerManager.findById(triggers[i].getId());
t.setAlertDefinition(aldef);
}
// Lastly, the modification time
adval.setMtime(System.currentTimeMillis());
// Now set the alertdef
alertDefDao.setAlertDefinitionValueNoRels(aldef, adval);
if (adval.isEscalationIdHasBeenSet()) {
Integer esclId = adval.getEscalationId();
Escalation escl = escalationManager.findById(esclId);
aldef.setEscalation(escl);
}
// Alert definitions are the root of the cascade relationship, so
// we must explicitly save them
alertDefDao.save(aldef);
availabilityDownAlertDefinitionCache.removeFromCache(aldef);
return aldef.getAlertDefinitionValue();
}
/**
* Activate/deactivate an alert definitions.
*
*/
public void updateAlertDefinitionsActiveStatus(AuthzSubject subj, Integer[] ids, boolean activate)
throws PermissionException {
List<AlertDefinition> alertdefs = new ArrayList<AlertDefinition>();
for (int i = 0; i < ids.length; i++) {
alertdefs.add((alertDefDao.get(ids[i])));
}
for (AlertDefinition alertDef : alertdefs) {
updateAlertDefinitionActiveStatus(subj, alertDef, activate);
}
}
/**
* Activate/deactivate an alert definition.
*/
public void updateAlertDefinitionActiveStatus(AuthzSubject subj, AlertDefinition def, boolean activate)
throws PermissionException {
final boolean debug = log.isDebugEnabled();
StopWatch watch = new StopWatch();
// ...check that user has modify permission on alert definition's resource...
alertPermissionManager.canModifyAlertDefinition(subj, def.getAppdefEntityId());
if (def.isActive() != activate || def.isEnabled() != activate) {
def.setActiveStatus(activate);
def.setMtime(System.currentTimeMillis());
alertAuditFactory.enableAlert(def, subj);
// process the children
if (debug) watch.markTimeBegin("getChildren");
Collection<AlertDefinition> children = def.getChildren();
if (debug) watch.markTimeEnd("getChildren");
List<Integer> defIds = new ArrayList<Integer>(children.size()+1);
defIds.add(def.getId());
for (AlertDefinition childDef : children) {
defIds.add(childDef.getId());
}
if (debug) watch.markTimeBegin("setAlertDefinitionTriggersEnabled");
registeredTriggerManager.setAlertDefinitionTriggersEnabled(defIds, activate);
if (debug) watch.markTimeEnd("setAlertDefinitionTriggersEnabled");
}
alertDefDao.setChildrenActive(def, activate);
availabilityDownAlertDefinitionCache.removeFromCache(def);
}
/**
* Enable/Disable an alert definition. For internal use only where the mtime
* does not need to be reset on each update.
*
* @return <code>true</code> if the enable/disable succeeded.
*/
public boolean updateAlertDefinitionInternalEnable(AuthzSubject subj, AlertDefinition def, boolean enable)
throws PermissionException {
boolean succeeded = false;
if (def.isEnabled() != enable) {
// ...check that user has modify permission on alert definition's resource...
alertPermissionManager.canModifyAlertDefinition(subj, def.getAppdefEntityId());
def.setEnabledStatus(enable);
registeredTriggerManager.setAlertDefinitionTriggersEnabled(def.getId(), enable);
succeeded = true;
}
return succeeded;
}
/**
* Enable/Disable an alert definition. For internal use only where the mtime
* does not need to be reset on each update.
*
* @return <code>true</code> if the enable/disable succeeded.
*/
public boolean updateAlertDefinitionInternalEnable(AuthzSubject subj, Integer defId, boolean enable)
throws PermissionException {
return updateAlertDefinitionInternalEnable(subj, Collections.singletonList(defId), enable);
}
/**
* Enable/Disable an alert definition. For internal use only where the mtime
* does not need to be reset on each update.
*
* @return <code>true</code> if the enable/disable succeeded.
*/
public boolean updateAlertDefinitionInternalEnable(AuthzSubject subj,
List<Integer> ids,
boolean enable)
throws PermissionException {
List<Integer> triggerDefIds = new ArrayList<Integer>(ids.size());
for (Integer alertDefId : ids ) {
AlertDefinition def = alertDefDao.get(alertDefId);
if (def != null && def.isEnabled() != enable) {
// ...check that user has modify permission on alert definition's resource...
alertPermissionManager.canModifyAlertDefinition(subj, def.getAppdefEntityId());
def.setEnabledStatus(enable);
triggerDefIds.add(def.getId());
}
}
if (!triggerDefIds.isEmpty()) {
// HQ-1799: enable the triggers in batch to improve performance
registeredTriggerManager.setAlertDefinitionTriggersEnabled(triggerDefIds, enable);
return true;
} else {
return false;
}
}
/**
* Set the escalation on the alert definition
*
*/
public void setEscalation(AuthzSubject subj, Integer defId, Integer escId) throws PermissionException {
AlertDefinition def = alertDefDao.findById(defId);
// ...check that user has modify permission on alert definition's resource...
alertPermissionManager.canModifyAlertDefinition(subj, def.getAppdefEntityId());
Escalation esc = escalationManager.findById(escId);
// End any escalation we were previously doing.
escalationManager.endEscalation(def);
def.setEscalation(esc);
def.setMtime(System.currentTimeMillis());
// End all children's escalation
for (AlertDefinition child : def.getChildren()) {
escalationManager.endEscalation(child);
}
alertDefDao.setChildrenEscalation(def, esc);
}
/**
* Returns the {@link AlertDefinition}s using the passed escalation.
*/
@Transactional(readOnly=true)
public Collection<AlertDefinition> getUsing(Escalation e) {
return alertDefDao.getUsing(e);
}
/**
* Remove alert definitions
*/
public void deleteAlertDefinitions(AuthzSubject subj, Integer[] ids) throws PermissionException {
for (int i = 0; i < ids.length; i++) {
AlertDefinition alertdef = alertDefDao.findById(ids[i]);
// Don't delete child alert definitions
if (alertdef.getParent() != null && !EventConstants.TYPE_ALERT_DEF_ID.equals(alertdef.getParent().getId())) {
continue;
}
// ...check that user has delete permission on alert definitions...
alertPermissionManager.canDeleteAlertDefinition(subj, alertdef.getAppdefEntityId());
alertAuditFactory.deleteAlert(alertdef, subj);
deleteAlertDefinition(subj, alertdef, false);
}
}
/**
* Set Resource to null on entity's alert definitions
*/
private void disassociateResource(Resource r) {
ResourceType resourceType = r.getResourceType();
if ((null != resourceType) && AuthzConstants.authzPolicy.equals(resourceType.getId())) {
// bug HQ-4644
return;
}
List<AlertDefinition> adefs = alertDefDao.findAllByResource(r);
for (AlertDefinition alertdef : adefs) {
alertdef.setResource(null);
alertdef.setDeleted(true);
}
alertDefDao.getSession().flush();
}
private void metricsEnabled(AppdefEntityID ent) {
try {
if(log.isDebugEnabled()) {
log.debug("Inheriting type-based alert defs for " + ent);
}
AuthzSubject hqadmin = authzSubjectManager.getSubjectById(AuthzConstants.rootSubjectId);
inheritResourceTypeAlertDefinition(hqadmin, ent);
} catch (Exception e) {
throw new SystemException(e);
}
}
private void inheritResourceTypeAlertDefinition(AuthzSubject subject, AppdefEntityID id)
throws AppdefEntityNotFoundException, PermissionException, InvalidOptionException,
InvalidOptionValueException, AlertDefinitionCreateException {
AppdefEntityValue rv = new AppdefEntityValue(id, subject);
AppdefResourceType type = rv.getAppdefResourceType();
// Find the alert definitions for the type
AppdefEntityTypeID aetid = new AppdefEntityTypeID(type.getAppdefType(), type.getId());
// The alert definitions should be returned sorted by creation time.
// This should minimize the possibility of creating a recovery alert
// before the recover from alert.
PageControl pc = new PageControl(0, PageControl.SIZE_UNLIMITED, PageControl.SORT_ASC,
SortAttribute.CTIME);
List<AlertDefinitionValue> defs = findAlertDefinitions(subject,
aetid, pc);
ArrayList<RegisteredTriggerValue> triggers = new ArrayList<RegisteredTriggerValue>();
for (AlertDefinitionValue adval : defs) {
// Only create if definition does not already exist
if (isAlertDefined(id, adval.getId())) {
continue;
}
// Set the parent ID
adval.setParentId(adval.getId());
// Reset the value object with this entity ID
adval.setAppdefId(id.getId());
try {
boolean succeeded = cloneParentConditions(subject, id, adval,
adval.getConditions(), true, false);
if (!succeeded) {
continue;
}
} catch (MeasurementNotFoundException e) {
throw new AlertDefinitionCreateException(
"Expected parent condition cloning to fail silently", e);
}
// Create the triggers
registeredTriggerManager.createTriggers(subject, adval);
triggers.addAll(Arrays.asList(adval.getTriggers()));
// Recreate the actions
cloneParentActions(id, adval, adval.getActions());
// Now create the alert definition
createAlertDefinition(subject, adval);
}
}
/**
* Clone the parent actions into the alert definition.
*/
public void cloneParentActions(AppdefEntityID parentId, AlertDefinitionValue child,
ActionValue[] actions) {
child.removeAllActions();
for (int i = 0; i < actions.length; i++) {
ActionValue childAct;
try {
ActionInterface actInst = (ActionInterface) Class
.forName(actions[i].getClassname()).newInstance();
ConfigResponse config = ConfigResponse.decode(actions[i].getConfig());
actInst.setParentActionConfig(parentId, config);
childAct = new ActionValue(null, actInst.getImplementor(), actInst
.getConfigResponse().encode(), actions[i].getId());
} catch (Exception e) {
// Not a valid action, skip it then
log.debug("Invalid action to clone: " + actions[i].getClassname(), e);
continue;
}
child.addAction(childAct);
}
}
/**
* Clone the parent conditions into the alert definition.
*
* @param subject The subject.
* @param id The entity to which the alert definition is assigned.
* @param adval The alert definition where the cloned conditions are set.
* @param conds The parent conditions to clone.
* @param failSilently <code>true</code> fail silently if cloning fails
* because no measurement is found corresponding to the measurement
* template specified in a parent condition; <code>false</code> to
* throw a {@link MeasurementNotFoundException} when this occurs.
* @param allowStale True if we don't need to perform a flush to query for measurements
* (this will be the case if we are not in the same transaction that measurements are created in)
* @return <code>true</code> if cloning succeeded; <code>false</code> if
* cloning failed.
*/
public boolean cloneParentConditions(AuthzSubject subject, AppdefEntityID id,
AlertDefinitionValue adval, AlertConditionValue[] conds,
boolean failSilently, boolean allowStale)
throws MeasurementNotFoundException {
// scrub and copy the parent's conditions
adval.removeAllConditions();
for (int i = 0; i < conds.length; i++) {
AlertConditionValue clone = new AlertConditionValue(conds[i]);
switch (clone.getType()) {
case EventConstants.TYPE_THRESHOLD:
case EventConstants.TYPE_BASELINE:
case EventConstants.TYPE_CHANGE:
Integer tid = new Integer(clone.getMeasurementId());
// If allowStale is true, don't need to synch the Measurement with the db
// since changes to the Measurement aren't cascaded
// on saving the AlertCondition.
try {
Measurement dmv = measurementManager.findMeasurement(subject, tid, id
.getId(), allowStale);
clone.setMeasurementId(dmv.getId().intValue());
} catch (MeasurementNotFoundException e) {
log.error("No measurement found for entity " + id +
" associated with template id=" + tid +
". Alert definition name [" + adval.getName() + "]");
log.debug("Root cause", e);
if (failSilently) {
log.info("Alert condition creation failed. " +
"The alert definition for entity " + id + " with name [" +
adval.getName() + "] should not be created.");
// Just set to 0, it'll never fire
clone.setMeasurementId(0);
return false;
} else {
throw e;
}
}
break;
case EventConstants.TYPE_ALERT:
// Don't need to synch the child alert definition Id lookup.
Integer recoverId = findChildAlertDefinitionId(id,
new Integer(clone.getMeasurementId()), true);
if (recoverId == null) {
// recoverId should never be null, but if it is and
// assertions
// are disabled, just move on.
assert false : "recover Id should not be null.";
log.error("A recovery alert has no associated recover "
+ "from alert. Setting alert condition "
+ "measurement Id to 0.");
clone.setMeasurementId(0);
} else {
clone.setMeasurementId(recoverId.intValue());
}
break;
}
// Now add it to the alert definition
adval.addCondition(clone);
}
return true;
}
@Transactional(readOnly=true)
public List<Integer> getAllDeletedAlertDefs() {
return alertDefDao.findAndPrefetchAllDeletedAlertDefs();
}
/**
* Clean up alert definitions and alerts for removed resources
*
*/
public void cleanupAlertDefs(List<Integer> alertDefIds) {
if (alertDefIds.size() <= 0) {
return;
}
StopWatch watch = new StopWatch();
final boolean debug = log.isDebugEnabled();
int i=0;
try {
final List<AlertDefinition> alertDefs = new ArrayList<AlertDefinition>(alertDefIds.size());
for (Integer alertdefId : alertDefIds) {
if (debug) watch.markTimeBegin("findById");
final AlertDefinition alertdef = alertDefDao.findById(alertdefId);
if (debug) watch.markTimeEnd("findById");
alertDefs.add(alertdef);
}
if (debug) watch.markTimeBegin("deleteByAlertDefinition");
alertDAO.deleteByAlertDefinitions(alertDefs);
if(debug) watch.markTimeEnd("deleteByAlertDefinition");
if (debug) watch.markTimeBegin("loop");
for (AlertDefinition alertdef : alertDefs) {
// Remove the conditions
if(debug) watch.markTimeBegin("remove conditions and triggers");
alertdef.clearConditions();
alertdef.getTriggersBag().clear();
if(debug) watch.markTimeEnd("remove conditions and triggers");
// Remove the actions
if (debug) watch.markTimeBegin("removeActions");
actionDao.removeActions(alertdef);
if(debug) watch.markTimeEnd("removeActions");
if(debug) watch.markTimeBegin("remove from parent");
if (alertdef.getParent() != null) {
alertdef.getParent().getChildrenBag().remove(alertdef);
}
if(debug) watch.markTimeBegin("remove from parent");
// Actually remove the definition
if(debug) watch.markTimeBegin("remove");
alertDefDao.remove(alertdef);
if(debug) watch.markTimeBegin("remove");
i++;
}
if (debug) watch.markTimeEnd("loop");
} finally {
if (debug) log.debug("deleted " + i + " alertDefs: " + watch);
}
}
/**
* Find an alert definition and return a value object
* @throws PermissionException if user does not have permission to manage
* alerts
*/
@Transactional(readOnly=true)
public AlertDefinitionValue getById(AuthzSubject subj, Integer id) throws PermissionException {
AlertDefinitionValue adv = null;
AlertDefinition ad = getByIdAndCheck(subj, id);
if (ad != null) {
adv = ad.getAlertDefinitionValue();
}
return adv;
}
/**
* Find an alert definition
* @throws PermissionException if user does not have permission to manage
* alerts
*/
@Transactional(readOnly=true)
public AlertDefinition getByIdAndCheck(AuthzSubject subj, Integer id) throws PermissionException {
AlertDefinition ad = alertDefDao.get(id);
if (ad != null) {
if (ad.isDeleted()) {
ad = null;
} else {
Resource r = ad.getResource();
if (r == null || r.isInAsyncDeleteState()) {
ad = null;
}
}
if (ad != null) {
// ...check that user has view permission on alert definitions...
alertPermissionManager.canViewAlertDefinition(subj, ad.getAppdefEntityId());
}
}
return ad;
}
/**
* Find an alert definition and return a basic value. This is called by the
* abstract trigger, so it does no permission checking.
*
* @param id The alert def Id.
*/
@Transactional(readOnly=true)
public AlertDefinition getByIdNoCheck(Integer id) {
return alertDefDao.get(id);
}
/**
* Check if an alert definition is a resource type alert definition.
*
* @param id The alert def Id.
* @return <code>true</code> if the alert definition is a resource type
* alert definition.
*
*/
@Transactional(readOnly=true)
public boolean isResourceTypeAlertDefinition(Integer id) {
AlertDefinition ad = alertDefDao.get(id);
return ad.isResourceTypeDefinition();
}
/**
*
*/
@Transactional(readOnly=true)
public AlertDefinition findAlertDefinitionById(Integer id) {
return alertDefDao.findById(id);
}
/**
* Get an alert definition's name
*
*/
@Transactional(readOnly=true)
public String getNameById(Integer id) {
return alertDefDao.get(id).getName();
}
/**
* Get an alert definition's conditions
*
*/
@Transactional(readOnly=true)
public AlertConditionValue[] getConditionsById(Integer id) {
AlertDefinition def = alertDefDao.get(id);
Collection<AlertCondition> conds = def.getConditions();
AlertConditionValue[] condVals = new AlertConditionValue[conds.size()];
int i = 0;
for (AlertCondition cond : conds) {
condVals[i] = cond.getAlertConditionValue();
i++;
}
return condVals;
}
/**
* Get list of alert conditions for a resource or resource type
*
*/
@Transactional(readOnly=true)
public boolean isAlertDefined(AppdefEntityID id, Integer parentId) {
Resource res = resourceManager.findResource(id);
return alertDefDao.findChildAlertDef(res, parentId) != null;
}
/**
* Get list of all alert conditions
*
* @return a PageList of {@link AlertDefinitionValue} objects
*
*/
@Transactional(readOnly=true)
public PageList<AlertDefinitionValue> findAllAlertDefinitions(AuthzSubject subj) {
List<AlertDefinitionValue> vals = new ArrayList<AlertDefinitionValue>();
for (AlertDefinition a : alertDefDao.findAll()) {
try {
// Only return the alert definitions that user can see
// ...check that user has view permission on alert definitions...
alertPermissionManager.canViewAlertDefinition(subj, a.getAppdefEntityId());
} catch (PermissionException e) {
continue;
}
vals.add(a.getAlertDefinitionValue());
}
return new PageList<AlertDefinitionValue>(vals, vals.size());
}
/**
* Get the resource-specific alert definition ID by parent ID, allowing for
* the query to return a stale copy of the alert definition (for efficiency
* reasons).
*
* @param aeid The resource.
* @param pid The ID of the resource type alert definition (parent ID).
* @param allowStale <code>true</code> to allow stale copies of an alert
* definition in the query results; <code>false</code> to never allow
* stale copies, potentially always forcing a sync with the database.
* @return The alert definition ID or <code>null</code> if no alert
* definition is found for the resource.
*
*/
@Transactional(readOnly=true)
public Integer findChildAlertDefinitionId(AppdefEntityID aeid, Integer pid, boolean allowStale) {
Resource res = resourceManager.findResource(aeid);
AlertDefinition def = alertDefDao.findChildAlertDef(res, pid, true);
return def == null ? null : def.getId();
}
/**
* Find alert definitions passing the criteria.
*
* @param minSeverity Specifies the minimum severity that the defs should be
* set for
* @param enabled If non-null, specifies the nature of the returned
* definitions (i.e. only return enabled or disabled defs)
* @param excludeTypeBased If true, exclude any alert definitions associated
* with a type-based def.
* @param pInfo Paging information. The sort field must be a value from
* {@link AlertDefSortField}
*
*
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findAlertDefinitions(AuthzSubject subj, AlertSeverity minSeverity, Boolean enabled,
boolean excludeTypeBased, PageInfo pInfo) {
return alertDefDao.findDefinitions(subj, minSeverity, enabled, excludeTypeBased, pInfo);
}
/**
* Get the list of type-based alert definitions.
*
* @param enabled If non-null, specifies the nature of the returned defs.
* @param pInfo Paging information. The sort field must be a value from
* {@link AlertDefSortField}
*
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findTypeBasedDefinitions(AuthzSubject subj, Boolean enabled, PageInfo pInfo)
throws PermissionException {
if (!PermissionManagerFactory.getInstance().hasAdminPermission(subj.getId())) {
throw new PermissionException("Only administrators can do this");
}
return alertDefDao.findTypeBased(enabled, pInfo);
}
/**
* Get list of alert definition POJOs for a resource
* @throws PermissionException if user cannot manage alerts for resource
*
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findAlertDefinitions(AuthzSubject subject, AppdefEntityID id)
throws PermissionException {
// ...check that user has view permission on alert definitions...
alertPermissionManager.canViewAlertDefinition(subject, id);
return alertDefDao.findByResource(resourceManager.findResource(id));
}
/**
*
*/
@Transactional(readOnly=true)
public PageList<AlertDefinitionValue> findAlertDefinitions(AuthzSubject subj, AppdefEntityID id, PageControl pc)
throws PermissionException {
// ...check that user has view permission on alert definitions...
alertPermissionManager.canViewAlertDefinition(subj, id);
Resource res = resourceManager.findResource(id);
List<AlertDefinition> adefs;
if (pc.getSortattribute() == SortAttribute.CTIME) {
adefs = alertDefDao.findByResourceSortByCtime(res, !pc.isDescending());
} else {
adefs = alertDefDao.findByResource(res, !pc.isDescending());
}
// TODO:G
return _valuePager.seek(adefs, pc.getPagenum(), pc.getPagesize());
}
/**
* Get list of alert definitions for a resource type.
*
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findAlertDefinitions(AuthzSubject subject, Resource prototype)
throws PermissionException {
// TODO: Check admin permission?
return alertDefDao.findByResource(prototype);
}
/**
* Get list of alert conditions for a resource or resource type
*
*/
@Transactional(readOnly=true)
public PageList<AlertDefinitionValue> findAlertDefinitions(AuthzSubject subj, AppdefEntityTypeID aetid,
PageControl pc) throws PermissionException {
Resource res = resourceManager.findResourcePrototype(aetid);
Collection<AlertDefinition> adefs;
if (pc.getSortattribute() == SortAttribute.CTIME) {
adefs = alertDefDao.findByResourceSortByCtime(res, pc.isAscending());
} else {
adefs = alertDefDao.findByResource(res, pc.isAscending());
}
// TODO:G
return _valuePager.seek(adefs, pc.getPagenum(), pc.getPagesize());
}
/**
* Get a list of all alert definitions for the resource and its descendents
* @param subj the caller
* @param res the root resource
* @return a list of alert definitions
*
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findRelatedAlertDefinitions(AuthzSubject subj, Resource res) {
return alertDefDao.findByRootResource(subj, res);
}
/**
* Get a list of all alert definitions with an availability metric condition
* @param subj the caller
* @return a list of alert definitions
*/
@Transactional(readOnly=true)
public List<AlertDefinition> findAvailAlertDefinitions(AuthzSubject subj)
throws PermissionException {
if (!PermissionManagerFactory.getInstance()
.hasAdminPermission(subj.getId())) {
throw new PermissionException("Only administrators can do this");
}
return alertDefDao.findAvailAlertDefs();
}
/**
* Get list of children alert definition for a parent alert definition
*
*/
@Transactional(readOnly=true)
public PageList<AlertDefinitionValue> findAlertDefinitionChildren(Integer id) {
AlertDefinition def = alertDefDao.findById(id);
PageControl pc = PageControl.PAGE_ALL;
// TODO:G
return _valuePager.seek(def.getChildren(), pc.getPagenum(), pc.getPagesize());
}
/**
* Get list of alert definition names for a resource
*
*/
@Transactional(readOnly=true)
public SortedMap<String, Integer> findAlertDefinitionNames(AuthzSubject subj, AppdefEntityID id, Integer parentId)
throws PermissionException {
if (parentId == null) {
// ...check that user has view permission on alert definitions...
alertPermissionManager.canViewAlertDefinition(subj, id);
}
return findAlertDefinitionNames(id, parentId);
}
/**
* Get list of alert definition names for a resource
*
*/
@Transactional(readOnly=true)
public SortedMap<String, Integer> findAlertDefinitionNames(AppdefEntityID id, Integer parentId) {
AlertDefinitionDAO aDao = alertDefDao;
TreeMap<String, Integer> ret = new TreeMap<String, Integer>();
Collection<AlertDefinition> adefs;
if (parentId != null) {
if (EventConstants.TYPE_ALERT_DEF_ID.equals(parentId)) {
AppdefEntityTypeID aetid = new AppdefEntityTypeID(id.getType(), id.getId());
Resource res = resourceManager.findResourcePrototype(aetid);
adefs = aDao.findByResource(res);
} else {
AlertDefinition def = alertDefDao.findById(parentId);
adefs = def.getChildren();
}
} else {
Resource res = resourceManager.findResource(id);
adefs = aDao.findByResource(res);
}
// Use name as key so that map is sorted
for (AlertDefinition adLocal : adefs) {
ret.put(adLocal.getName(), adLocal.getId());
}
return ret;
}
/**
* Return array of two values: enabled and act on trigger ID
*
*/
@Transactional(readOnly=true)
public boolean isEnabled(Integer id) {
return alertDefDao.isEnabled(id);
}
/**
*
*/
@Transactional(readOnly=true)
public int getActiveCount() {
return alertDefDao.getNumActiveDefs();
}
}