org.hyperic.hq.ui.action.portlet.metricviewer.ViewAction.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.ui.action.portlet.metricviewer.ViewAction.java

Source

/*
 * 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.ui.action.portlet.metricviewer;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionRedirect;
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.BaseAction;
import org.hyperic.hq.ui.exception.ParameterNotFoundException;
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.beans.factory.annotation.Autowired;

/**
 * This action class is used by the Metric Viewer portlet. It's main use is to
 * generate the JSON objects required for display into the UI.
 */
public class ViewAction extends BaseAction {

    private final Log log = LogFactory.getLog(ViewAction.class);

    private AuthzBoss authzBoss;
    private MeasurementBoss measurementBoss;
    private AppdefBoss appdefBoss;
    private DashboardManager dashboardManager;

    @Autowired
    public ViewAction(AuthzBoss authzBoss, MeasurementBoss measurementBoss, AppdefBoss appdefBoss,
            DashboardManager dashboardManager) {
        super();
        this.authzBoss = authzBoss;
        this.measurementBoss = measurementBoss;
        this.appdefBoss = appdefBoss;
        this.dashboardManager = dashboardManager;
    }

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        HttpSession session = request.getSession();
        WebUser user = SessionUtils.getWebUser(session);
        DashboardConfig dashConfig = dashboardManager
                .findDashboard((Integer) session.getAttribute(Constants.SELECTED_DASHBOARD_ID), user, authzBoss);

        if (dashConfig == null) {
            return new ActionRedirect("/Dashboard.do");
        }

        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 = PropertiesForm.NUM_TO_SHOW;
        String resKey = PropertiesForm.RESOURCES;
        String resTypeKey = PropertiesForm.RES_TYPE;
        String metricKey = PropertiesForm.METRIC;
        String descendingKey = PropertiesForm.DECSENDING;
        String titleKey = PropertiesForm.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());
            response.getWriter().write(res.toString());
            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);
        CacheData[] data = new CacheData[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<MetricSummary> sortedSet = new TreeSet<MetricSummary>(new MetricSummaryComparator(isDescending));
        for (int i = 0; i < data.length; i++) {
            // Only show resources with data
            if (vals[i] != null) {
                MetricSummary summary = new MetricSummary(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<MetricSummary> i = sortedSet.iterator(); i.hasNext() && count-- > 0;) {
            MetricSummary 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);

        response.getWriter().write(res.toString());

        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);
        }

        return null;
    }

    private class MetricSummary {
        private AppdefResourceValue _resource;
        private MeasurementTemplate _template;
        private MetricValue _val;

        public MetricSummary(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 MetricSummaryComparator implements Comparator<MetricSummary> {

        private boolean _decending;

        public MetricSummaryComparator(boolean decending) {
            _decending = decending;
        }

        public int compare(MetricSummary s1, MetricSummary 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 CacheData loadData(int sessionId, AppdefEntityID id, MeasurementTemplate template)
            throws AppdefEntityNotFoundException {
        Cache cache = CacheManager.getInstance().getCache("MetricViewer");
        CacheKey key = new CacheKey(sessionId, id, template);
        Element e = cache.get(key);

        if (e != null) {
            return (CacheData) e.getObjectValue();
        }

        // Otherwise, load from the backend

        try {
            AppdefResourceValue val = appdefBoss.findById(sessionId, id);
            Measurement m = measurementBoss.findMeasurement(sessionId, template.getId(), id);
            CacheData data = new CacheData(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

    public class CacheKey {
        private int _sessionId;
        private AppdefEntityID _id;
        private MeasurementTemplate _template;

        public CacheKey(int sessionId, AppdefEntityID id, MeasurementTemplate template) {
            _sessionId = sessionId;
            _id = id;
            _template = template;
        }

        public boolean equals(Object o) {
            return (o instanceof CacheKey) && ((CacheKey) o)._id.equals(_id)
                    && ((CacheKey) o)._template.equals(_template) && ((CacheKey) o)._sessionId == _sessionId;
        }

        public int hashCode() {
            return _id.hashCode() + _template.hashCode() + _sessionId;
        }
    }

    public class CacheData {
        private AppdefResourceValue _resource;
        private Measurement _m;

        public CacheData(AppdefResourceValue resource, Measurement m) {
            _resource = resource;
            _m = m;
        }

        public AppdefResourceValue getResource() {
            return _resource;
        }

        public Measurement getMeasurement() {
            return _m;
        }
    }
}