/* * NOTE: This copyright does *not* cover user programs that use HQ * 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-2009], Hyperic, Inc. * This file is part of HQ. * * HQ 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.bizapp.server.session; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hibernate.PageInfo; 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.AppdefUtil; import org.hyperic.hq.authz.server.session.AuthzSubject; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.server.session.ResourceGroup; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.authz.shared.PermissionManager; import org.hyperic.hq.authz.shared.ResourceGroupManager; import org.hyperic.hq.authz.shared.ResourceManager; import org.hyperic.hq.bizapp.shared.DashboardPortletBoss; import org.hyperic.hq.bizapp.shared.MeasurementBoss; import org.hyperic.hq.escalation.server.session.Escalation; import org.hyperic.hq.escalation.server.session.EscalationState; import org.hyperic.hq.escalation.shared.EscalationManager; import org.hyperic.hq.events.AlertPermissionManager; import org.hyperic.hq.events.server.session.Alert; import org.hyperic.hq.events.server.session.AlertDefinition; import org.hyperic.hq.events.server.session.AlertSortField; import org.hyperic.hq.events.shared.AlertDefinitionManager; import org.hyperic.hq.events.shared.AlertDefinitionValue; import org.hyperic.hq.events.shared.AlertManager; import org.hyperic.hq.galerts.server.session.GalertDef; import org.hyperic.hq.galerts.server.session.GalertLog; import org.hyperic.hq.galerts.shared.GalertManager; import org.hyperic.hq.grouping.server.session.GroupUtil; import org.hyperic.hq.grouping.shared.GroupNotCompatibleException; import org.hyperic.hq.measurement.MeasurementConstants; import org.hyperic.hq.measurement.server.session.Measurement; import org.hyperic.hq.measurement.shared.DataManager; import org.hyperic.hq.measurement.shared.HighLowMetricValue; import org.hyperic.hq.measurement.shared.MeasurementManager; import org.hyperic.util.pager.PageControl; import org.hyperic.util.timer.StopWatch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** */ @Service @Transactional public class DashboardPortletBossImpl implements DashboardPortletBoss { private static final String ALERT_CRITICAL = "red", ALERT_WARN = "yellow", ALERT_UNKNOWN = "gray", ALERT_OK = "green"; private final Log log = LogFactory.getLog(DashboardPortletBossImpl.class); private PermissionManager permissionManager; private ResourceManager resourceManager; private MeasurementManager measurementManager; private DataManager dataManager; private MeasurementBoss measurementBoss; private ResourceGroupManager resourceGroupManager; private GalertManager galertManager; private AlertManager alertManager; private AlertDefinitionManager alertDefinitionManager; private EscalationManager escalationManager; private AlertPermissionManager alertPermissionManager; @Autowired public DashboardPortletBossImpl(PermissionManager permissionManager, ResourceManager resourceManager, MeasurementManager measurementManager, DataManager dataManager, MeasurementBoss measurementBoss, ResourceGroupManager resourceGroupManager, GalertManager galertManager, AlertManager alertManager, AlertDefinitionManager alertDefinitionManager, EscalationManager escalationManager, AlertPermissionManager alertPermissionManager) { this.permissionManager = permissionManager; this.resourceManager = resourceManager; this.measurementManager = measurementManager; this.dataManager = dataManager; this.measurementBoss = measurementBoss; this.resourceGroupManager = resourceGroupManager; this.galertManager = galertManager; this.alertManager = alertManager; this.alertDefinitionManager = alertDefinitionManager; this.escalationManager = escalationManager; this.alertPermissionManager = alertPermissionManager; } @Transactional(readOnly=true) public List<Map<String, Object>> getMeasurementData(AuthzSubject subj, Integer resId, Integer mtid, AppdefEntityTypeID ctype, long begin, long end) throws PermissionException { List<Map<String, Object>> result = new ArrayList<Map<String,Object>>(); DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); long intv = (end - begin) / 60; Map<String, Object> chartData = new HashMap<String, Object>(); Resource res = resourceManager.findResourceById(resId); if (res == null || res.isInAsyncDeleteState()) { return result; } AppdefEntityID aeid = AppdefUtil.newAppdefEntityId(res); try { chartData.put("resourceName", res.getName()); AppdefEntityID[] aeids; if (aeid.isGroup()) { List<AppdefEntityID> members = GroupUtil.getCompatGroupMembers(subj, aeid, null, PageControl.PAGE_ALL); aeids = (AppdefEntityID[]) members.toArray(new AppdefEntityID[members.size()]); } else if (ctype != null) { aeids = measurementBoss.getAutoGroupMemberIDs(subj, new AppdefEntityID[] { aeid }, ctype); } else { aeids = new AppdefEntityID[] { aeid }; } List<Measurement> metrics = measurementManager.findMeasurements(subj, mtid, aeids); // Get measurement name if (!metrics.isEmpty()) { Measurement measurement = metrics.get(0); chartData.put("measurementName", measurement.getTemplate().getName()); chartData.put("measurementUnits", measurement.getTemplate().getUnits()); } List<HighLowMetricValue> data = dataManager.getHistoricalData(metrics, begin, end, intv, 0, true, PageControl.PAGE_ALL); Map<String, List<Double>> metricData = new LinkedHashMap<String, List<Double>>(); for (HighLowMetricValue pt : data) { List<Double> metricValues = new ArrayList<Double>(); double val = pt.getValue(); if (Double.isNaN(val) || Double.isInfinite(val)) { continue; } metricValues.add(val); Date date = new Date(pt.getTimestamp()); metricData.put(dateFmt.format(date), metricValues); } chartData.put("data", metricData); result.add(chartData); } catch (AppdefEntityNotFoundException e) { log.error("AppdefEntityNotFound: " + aeid); } catch (GroupNotCompatibleException e) { log.error("GroupNotCompatibleException: " + aeid); } return result; } @Transactional(readOnly=true) public Map<Integer, List<String>> getAlertCounts(AuthzSubject subj, Integer[] groupIds, PageInfo pageInfo) throws PermissionException { final long PORTLET_RANGE = MeasurementConstants.DAY * 3; final int maxRecords = pageInfo.getStartRow() + pageInfo.getPageSize(); Map<Integer, List<Alert>> resourceAlertMap = alertManager.getUnfixedByResource(subj.getId(), PORTLET_RANGE, System.currentTimeMillis()); Map<Integer, List<String>> result = new HashMap<Integer, List<String>>(); for (int x = pageInfo.getStartRow(); x < groupIds.length && (maxRecords == 0 || x <= maxRecords); x++) { ResourceGroup group = resourceGroupManager.findResourceGroupById(subj, groupIds[x]); if (group != null) { List<String> alertStatus = new ArrayList<String>(); alertStatus.add(getResourceStatus(subj, group, resourceAlertMap, PORTLET_RANGE)); alertStatus.add(getGroupStatus(subj, group, PORTLET_RANGE)); result.put(group.getId(), alertStatus); } } return result; } private String getGroupStatus(AuthzSubject subj, ResourceGroup group, long range) { boolean debug = log.isDebugEnabled(); String rtn = ALERT_OK; long now = System.currentTimeMillis(); try { long begin = now - range; List<GalertLog> galerts = galertManager.findUnfixedAlertLogsByTimeWindow(group, begin, now); if (debug) { log.debug("getGroupStatus: findUnfixedAlertLogsByTimeWindow execution time(ms)=" + (System.currentTimeMillis() - now)); } for (GalertLog galert : galerts) { try { alertPermissionManager.canViewAlertDefinition(subj, galert.getAlertDef().getAppdefID()); } catch (PermissionException pe) { // continue to next group alert continue; } // a galert always has an associated escalation which may or may // not // be acknowledged. if (galert.hasEscalationState() && galert.isAcknowledged()) { rtn = ALERT_WARN; } else { return ALERT_CRITICAL; } } // Is it that there are no alerts or that there are no alert // definitions? if (rtn.equals(ALERT_OK)) { List<GalertDef> galertDefs = galertManager.findAlertDefs(group, PageControl.PAGE_ALL); if (galertDefs.size() == 0) { return ALERT_UNKNOWN; } } return rtn; } finally { if (debug) { log.debug("getGroupStatus: groupId=" + group.getId() + ", execution time(ms)=" + (System.currentTimeMillis() - now)); } } } private String getResourceStatus(AuthzSubject subj, ResourceGroup group, Map<Integer,List<Alert>>resourceAlertMap, long range) { boolean debug = log.isDebugEnabled(); long now = System.currentTimeMillis(); StopWatch watch = new StopWatch(now); try { watch.markTimeBegin("getResourceStatus: getUnfixedCount"); Collection<Resource> resources = resourceGroupManager.getMembers(group); List<Alert> alerts = new ArrayList<Alert>(); for (Resource r : resources) { List<Alert> resourceAlerts = resourceAlertMap.get(r.getId()); if (resourceAlerts != null) { alerts.addAll(resourceAlerts); } } watch.markTimeEnd("getResourceStatus: getUnfixedCount"); // There are unfixed alerts for resources in this group. if (alerts.size() > 0) { // If all alerts are ack'ed, return WARN, otherwise CRITICAL. for (Alert alert : alerts) { if (!isAckd(subj, alert)) { return ALERT_CRITICAL; } } return ALERT_WARN; } else { // Is it that there are no alerts or that there are no alert definitions? // TODO: Should query these all at once - once complete we can // remove the query cache for AlertDefinition.findByResource. This // used to check alerting permission, but now that's already done // on the master list of alerts. List<AlertDefinition> alertDefs; for (Resource r : resources) { alertDefs = alertDefinitionManager.findAlertDefinitions(subj, r); if (alertDefs.size() > 0) { return ALERT_OK; } } } } catch (PermissionException e) { // User has no permission to see these resources } finally { if (debug) { log.debug("getResourceStatus: groupId=" + group.getId() + ", execution time =" + watch); } } return ALERT_UNKNOWN; } private boolean isAckd(AuthzSubject subj, Alert alert) { AlertDefinition alertDef = alert.getAlertDefinition(); // a resource alert may not have an associated escalation Escalation esc = alertDef.getEscalation(); if (esc == null || esc.getMaxPauseTime() == 0) { return false; } EscalationState state = escalationManager.findEscalationState(alertDef); return state != null && state.getAcknowledgedBy() != null; } }