/* * 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, 2005, 2006, 2007], 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.ui.action.portlet.metricviewer; import java.io.InputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import javax.annotation.Resource; import javax.servlet.http.HttpSession; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.AppdefResourceTypeValue; import org.hyperic.hq.appdef.shared.AppdefResourceValue; import org.hyperic.hq.bizapp.shared.AppdefBoss; import org.hyperic.hq.bizapp.shared.AuthzBoss; import org.hyperic.hq.bizapp.shared.MeasurementBoss; import org.hyperic.hq.measurement.MeasurementNotFoundException; import org.hyperic.hq.measurement.UnitsConvert; import org.hyperic.hq.measurement.server.session.Measurement; import org.hyperic.hq.measurement.server.session.MeasurementTemplate; import org.hyperic.hq.product.MetricValue; import org.hyperic.hq.ui.Constants; import org.hyperic.hq.ui.WebUser; import org.hyperic.hq.ui.action.BaseActionNG; import org.hyperic.hq.ui.exception.ParameterNotFoundException; import org.hyperic.hq.ui.json.JSONResult; import org.hyperic.hq.ui.json.action.JsonActionContextNG; import org.hyperic.hq.ui.server.session.DashboardConfig; import org.hyperic.hq.ui.shared.DashboardManager; import org.hyperic.hq.ui.util.DashboardUtils; import org.hyperic.hq.ui.util.RequestUtils; import org.hyperic.hq.ui.util.SessionUtils; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.pager.PageControl; import org.hyperic.util.units.FormattedNumber; import org.json.JSONObject; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component(value = "jsonLoadMetricViewerNG") @Scope("prototype") public class JsonLoadMetricViewerNG extends BaseActionNG { private final Log log = LogFactory.getLog(JsonLoadMetricViewerNG.class); @Resource private AuthzBoss authzBoss; @Resource private MeasurementBoss measurementBoss; @Resource private AppdefBoss appdefBoss; @Resource private DashboardManager dashboardManager; private InputStream inputStream; public InputStream getInputStream() { return inputStream; } public String execute() throws Exception { try { JsonActionContextNG ctx = this.setJSONContext(); HttpSession session = request.getSession(); WebUser user = SessionUtils.getWebUser(session); DashboardConfig dashConfig = dashboardManager.findDashboard((Integer) session .getAttribute(Constants.SELECTED_DASHBOARD_ID), user, authzBoss); ConfigResponse dashPrefs = dashConfig.getConfig(); int sessionId = user.getSessionId().intValue(); long ts = System.currentTimeMillis(); String token; try { token = RequestUtils.getStringParameter(request, "token"); } catch (ParameterNotFoundException e) { token = null; } // For multi-portlet configuration String numKey = PropertiesFormNG.NUM_TO_SHOW; String resKey = PropertiesFormNG.RESOURCES; String resTypeKey = PropertiesFormNG.RES_TYPE; String metricKey = PropertiesFormNG.METRIC; String descendingKey = PropertiesFormNG.DECSENDING; String titleKey = PropertiesFormNG.TITLE; if (token != null) { numKey += token; resKey += token; resTypeKey += token; metricKey += token; descendingKey += token; titleKey += token; } JSONObject res = new JSONObject(); if (token != null) { res.put("token", token); } else { res.put("token", JSONObject.NULL); } res.put("title", dashPrefs.getValue(titleKey, "")); // Load resources List<AppdefEntityID> entityIds = DashboardUtils.preferencesAsEntityIds(resKey, dashPrefs); AppdefEntityID[] arrayIds = entityIds.toArray(new AppdefEntityID[entityIds.size()]); int count = Integer.parseInt(dashPrefs.getValue(numKey, "10")); String metric = dashPrefs.getValue(metricKey, ""); boolean isDescending = Boolean.valueOf(dashPrefs.getValue(descendingKey, "true")).booleanValue(); // Validate if (arrayIds.length == 0 || count == 0 || metric.length() == 0) { res.put("metricValues", new JSONObject()); JSONResult jsonRes = new JSONResult(res); ctx.setJSONResult(jsonRes); inputStream = this.streamJSONResult(ctx); return null; } Integer[] tids = new Integer[] { new Integer(metric) }; List<MeasurementTemplate> metricTemplates = measurementBoss.findMeasurementTemplates(sessionId, tids, PageControl.PAGE_ALL); MeasurementTemplate template = (MeasurementTemplate) metricTemplates.get(0); String resource = dashPrefs.getValue(resTypeKey); AppdefEntityTypeID typeId = new AppdefEntityTypeID(resource); AppdefResourceTypeValue typeVal = appdefBoss.findResourceTypeById(sessionId, typeId); CacheDataNG[] data = new CacheDataNG[arrayIds.length]; List<Integer> measurements = new ArrayList<Integer>(arrayIds.length); long interval = 0; ArrayList<String> toRemove = new ArrayList<String>(); for (int i = 0; i < arrayIds.length; i++) { AppdefEntityID id = arrayIds[i]; try { data[i] = loadData(sessionId, id, template); } catch (AppdefEntityNotFoundException e) { toRemove.add(id.getAppdefKey()); } if (data[i] != null && data[i].getMeasurement() != null) { measurements.add(i, data[i].getMeasurement().getId()); if (data[i].getMeasurement().getInterval() > interval) { interval = data[i].getMeasurement().getInterval(); } } else { measurements.add(i, null); } } MetricValue[] vals = measurementBoss.getLastMetricValue(sessionId, measurements, interval); TreeSet<MetricSummaryNG> sortedSet = new TreeSet<MetricSummaryNG>(new MetricSummaryComparatorNG(isDescending)); for (int i = 0; i < data.length; i++) { // Only show resources with data if (vals[i] != null) { MetricSummaryNG summary = new MetricSummaryNG(data[i].getResource(), template, vals[i]); sortedSet.add(summary); } } JSONObject metricValues = new JSONObject(); metricValues.put("resourceTypeName", typeVal.getName()); metricValues.put("metricName", template.getName()); ArrayList<JSONObject> values = new ArrayList<JSONObject>(); for (Iterator<MetricSummaryNG> i = sortedSet.iterator(); i.hasNext() && count-- > 0;) { MetricSummaryNG s = i.next(); JSONObject val = new JSONObject(); val.put("value", s.getFormattedValue()); val.put("resourceId", s.getAppdefResourceValue().getId()); val.put("resourceTypeId", s.getAppdefResourceValue().getEntityId().getType()); val.put("resourceName", StringEscapeUtils.escapeHtml(s.getAppdefResourceValue().getName())); values.add(val); } metricValues.put("values", values); res.put("metricValues", metricValues); log.debug("Metric viewer loaded in " + (System.currentTimeMillis() - ts) + " ms."); if (toRemove.size() > 0) { log.debug("Removing " + toRemove.size() + " missing resources."); DashboardUtils.removeResources((String[]) toRemove.toArray(new String[toRemove.size()]), resKey, dashPrefs); } JSONResult jsonRes = new JSONResult(res); ctx.setJSONResult(jsonRes); inputStream = this.streamJSONResult(ctx); request.setAttribute("titleDescription", dashPrefs.getValue(titleKey, "")); } catch (Exception ex) { log.error("dashConfig for key " + Constants.SELECTED_DASHBOARD_ID); log.error(ex,ex); } return null; } private class MetricSummaryNG { private AppdefResourceValue _resource; private MeasurementTemplate _template; private MetricValue _val; public MetricSummaryNG(AppdefResourceValue resource, MeasurementTemplate template, MetricValue val) { _resource = resource; _template = template; _val = val; } public AppdefResourceValue getAppdefResourceValue() { return _resource; } public MetricValue getMetricValue() { return _val; } public String getFormattedValue() { FormattedNumber fn = UnitsConvert.convert(_val.getValue(), _template.getUnits()); return fn.toString(); } public String toString() { return "[" + _resource.getEntityId() + "]=" + _val.getValue(); } } private class MetricSummaryComparatorNG implements Comparator<MetricSummaryNG> { private boolean _decending; public MetricSummaryComparatorNG(boolean decending) { _decending = decending; } public int compare(MetricSummaryNG s1, MetricSummaryNG s2) { MetricValue m1 = s1.getMetricValue(); MetricValue m2 = s2.getMetricValue(); if (m1.getValue() == m2.getValue()) { String n1 = s1.getAppdefResourceValue().getName(); String n2 = s2.getAppdefResourceValue().getName(); return n1.compareTo(n2); } else if (m1.getValue() < m2.getValue()) { if (_decending) { return 1; } else { return -1; } } else { if (_decending) { return -1; } else { return 1; } } } } private CacheDataNG loadData(int sessionId, AppdefEntityID id, MeasurementTemplate template) throws AppdefEntityNotFoundException { Cache cache = CacheManager.getInstance().getCache("MetricViewer"); CacheKeyNG key = new CacheKeyNG(sessionId, id, template); Element e = cache.get(key); if (e != null) { return (CacheDataNG) e.getObjectValue(); } // Otherwise, load from the backend try { AppdefResourceValue val = appdefBoss.findById(sessionId, id); Measurement m = measurementBoss.findMeasurement(sessionId, template.getId(), id); CacheDataNG data = new CacheDataNG(val, m); cache.put(new Element(key, data)); return data; } catch (AppdefEntityNotFoundException ex) { throw ex; } catch (MeasurementNotFoundException ex) { return null; // No metric scheduled. } catch (Exception ex) { log.debug("Caught exception loading data: " + ex, ex); return null; } } // Classes for caching dashboard data private class CacheKeyNG { private int _sessionId; private AppdefEntityID _id; private MeasurementTemplate _template; public CacheKeyNG(int sessionId, AppdefEntityID id, MeasurementTemplate template) { _sessionId = sessionId; _id = id; _template = template; } public boolean equals(Object o) { return (o instanceof CacheKeyNG) && ((CacheKeyNG) o)._id.equals(_id) && ((CacheKeyNG) o)._template.equals(_template) && ((CacheKeyNG) o)._sessionId == _sessionId; } public int hashCode() { return _id.hashCode() + _template.hashCode() + _sessionId; } } private class CacheDataNG { private AppdefResourceValue _resource; private Measurement _m; public CacheDataNG(AppdefResourceValue resource, Measurement m) { _resource = resource; _m = m; } public AppdefResourceValue getResource() { return _resource; } public Measurement getMeasurement() { return _m; } } }