/*
* 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-2008], 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.util;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.appdef.shared.AppdefEntityConstants;
import org.hyperic.hq.appdef.shared.AppdefEntityID;
import org.hyperic.hq.appdef.shared.AppdefResourceTypeValue;
import org.hyperic.hq.appdef.shared.AppdefResourceValue;
import org.hyperic.hq.appdef.shared.ServerTypeValue;
import org.hyperic.hq.appdef.shared.ServerValue;
import org.hyperic.hq.appdef.shared.ServiceTypeValue;
import org.hyperic.hq.bizapp.shared.uibeans.MetricDisplaySummary;
import org.hyperic.hq.bizapp.shared.uibeans.ResourceTypeDisplaySummary;
import org.hyperic.hq.measurement.MeasurementConstants;
import org.hyperic.hq.measurement.UnitsConvert;
import org.hyperic.hq.ui.Constants;
import org.hyperic.hq.ui.util.minitab.SubMiniTab;
import org.hyperic.util.units.DateFormatter.DateSpecifics;
import org.hyperic.util.units.FormattedNumber;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
public class MonitorUtilsNG {
private static Log log = LogFactory.getLog(MonitorUtilsNG.class.getName());
public static final String RO = "ro";
public static final String LASTN = "lastN";
public static final String UNIT = "unit";
public static final String BEGIN = "begin";
public static final String END = "end";
public static final int DEFAULT_CURRENTHEALTH_LASTN = 8;
public static final Boolean DEFAULT_VALUE_RANGE_RO = Boolean.FALSE;
public static final Integer DEFAULT_VALUE_RANGE_LASTN = new Integer(8);
public static final Integer DEFAULT_VALUE_RANGE_UNIT = new Integer(3);
public static final int UNIT_COLLECTION_POINTS = 1;
public static final int UNIT_MINUTES = 2;
public static final int UNIT_HOURS = 3;
public static final int UNIT_DAYS = 4;
public static final int THRESHOLD_BASELINE_VALUE = 1;
public static final String THRESHOLD_BASELINE_LABEL = "Baseline";
public static final int THRESHOLD_HIGH_RANGE_VALUE = 2;
public static final String THRESHOLD_HIGH_RANGE_LABEL = "HighRange";
public static final int THRESHOLD_LOW_RANGE_VALUE = 3;
public static final String THRESHOLD_LOW_RANGE_LABEL = "LowRange";
public static final int THRESHOLD_UNDER_VALUE = 1;
public static final int THRESHOLD_OVER_VALUE = 2;
/**
* Method calculateTimeFrame
*
* Returns a two element<code>List</code> of <code>Long</code> objects
* representing the begin and end times (in milliseconds since the epoch) of
* the timeframe. Returns null instead if the time unit is indicated as
* <code>UNIT_COLLECTION_POINTS</code>.
*
* @param lastN
* the number of time units in the time frame
* @param unit
* the unit of time (as defined by <code>UNIT_*</code> constants
* @return List
*/
public static List<Long> calculateTimeFrame(int lastN, int unit) {
List<Long> l = new ArrayList<Long>(0);
if (unit == UNIT_COLLECTION_POINTS) {
return null;
}
long now = System.currentTimeMillis();
long retrospective = lastN;
switch (unit) {
case UNIT_MINUTES:
retrospective *= Constants.MINUTES;
break;
case UNIT_HOURS:
retrospective *= Constants.HOURS;
break;
case UNIT_DAYS:
retrospective *= Constants.DAYS;
break;
default:
retrospective = -1;
break;
}
l.add(new Long(now - retrospective));
l.add(new Long(now));
return l;
}
/**
* Method getSubMiniTabs
*
* Returns a list of <code>SubMiniTab</code> objects to be displayed below
* the Monitor mini tabs. The properties of each <code>SubMiniTab</code>
* will be set by examining the corresponding
* <code>AppdefResourceTypeValue</code>:
*
* <ul>
* <li>id: resource type id
* <li>name: resource type name
* <li>count: number of resources of this type (defaults to 0)
* <li>selected: if this type is the one identified by the selectedId (if
* any)
* </ul>
*
* @param resourceTypes
* a <code>List</code> of <code>AppdefResourceTypeValue</code>
* objects
* @param resourceCounts
* a <code>Map</code> of resource counts keyed by resource type
* name
* @param selectedId
* a <code>Integer</code> identifying the particular resource
* type that is being currently viewed 8 @return List
*/
public static List<SubMiniTab> getSubMiniTabs(
List<AppdefResourceTypeValue> resourceTypes,
Map<String, Object> resourceCounts, Integer selectedId) {
List<SubMiniTab> subtabs = new ArrayList<SubMiniTab>();
if (resourceTypes != null & resourceCounts != null) {
for (Iterator i = resourceTypes.iterator(); i.hasNext();) {
AppdefResourceTypeValue type = (AppdefResourceTypeValue) i
.next();
SubMiniTab subtab = new SubMiniTab();
subtab.setName(type.getName());
Integer typeId = type.getId();
subtab.setId(AppdefEntityConstants.APPDEF_TYPE_SERVICE + ":"
+ typeId.toString());
subtab.setSelected(isSubMiniTabSelected(typeId, selectedId));
Object count = resourceCounts.get(type.getName());
if (count == null) {
count = new Integer(0);
}
subtab.setCount(count.toString());
subtabs.add(subtab);
}
}
return subtabs;
}
private static Boolean isSubMiniTabSelected(Integer tabId,
Integer selectedId) {
return new Boolean(selectedId != null
&& selectedId.intValue() == tabId.intValue());
}
/**
* Method findDefaultChildResourceId
*
* Return the id of the first child resource type (according to whatever
* order in which the BizApp lists them) for which the parent resource has
* one or more defined child resources.
*
* @param resourceTypes
* a <code>List</code> of <code>AppdefResourceTypeValue</code>
* objects
* @param resourceCounts
* a <code>Map</code> of resource counts keyed by resource type
* name
* @return Integer
*/
public static Integer findDefaultChildResourceId(List resourceTypes,
Map resourceCounts) {
if (resourceTypes != null && resourceCounts != null) {
Iterator i = resourceTypes.iterator();
while (i.hasNext()) {
AppdefResourceTypeValue type = (AppdefResourceTypeValue) i
.next();
Integer count = (Integer) resourceCounts.get(type.getName());
if (count != null && count.intValue() > 0) {
return type.getId();
}
}
}
return null;
}
/**
* Method findServiceTypes.
*
* Given a List of services associated with an application or server, filter
* through them for the service types so we can link to showing selections
* by type. The returned List has the ServiceTypeValue as elements.
*
* This should eventually get pushed into the bizapp
*
* @param services
* @return List
*/
public static List<ServiceTypeValue> findServiceTypes(List services,
Boolean internal) {
TreeMap<String, ServiceTypeValue> serviceTypeSet = new TreeMap<String, ServiceTypeValue>();
for (Iterator i = services.iterator(); i.hasNext();) {
AppdefResourceValue svcCandidate = (AppdefResourceValue) i.next();
final AppdefEntityID aeid = svcCandidate.getEntityId();
if (aeid.isService() || aeid.isGroup()) {
AppdefResourceValue service = (AppdefResourceValue) svcCandidate;
if (service != null
&& service.getAppdefResourceTypeValue() != null) {
// if we don't have a group that is a compat group of
// services, then this
// better throw a ClassCastException
ServiceTypeValue svcType = (ServiceTypeValue) service
.getAppdefResourceTypeValue();
if (internal == null) {
// if we're not discriminating between internal and
// deployed, we'll just
// return them all
serviceTypeSet.put(svcType.getName(), svcType);
} else if (internal != null
&& new Boolean(svcType.getIsInternal())
.equals(internal)) {
serviceTypeSet.put(svcType.getName(), svcType);
}
}
} else {
throw new IllegalStateException("Did not get a valid service: "
+ svcCandidate);
}
}
return new ArrayList(serviceTypeSet.values());
}
public static List findServerTypes(List servers) {
TreeMap serverTypeSet = new TreeMap();
for (Iterator i = servers.iterator(); i.hasNext();) {
ServerValue thisAppSvc = (ServerValue) i.next();
if (thisAppSvc != null && thisAppSvc.getServerType() != null) {
ServerTypeValue svcType = thisAppSvc.getServerType();
serverTypeSet.put(svcType.getName(), svcType);
}
}
return new ArrayList(serverTypeSet.values());
}
/**
* Sometimes, it's useful to just get a dump of all of the metrics returned
* by the backend.
*
* @param log
* @param metrics
* a Map keyed on the category (String), values are List's of
* MetricDisplaySummary beans
*/
public static void traceMetricDisplaySummaryMap(Log logger, Map metrics) {
logger.trace("Dumping metric map (from "
+ MonitorUtilsNG.class.getName() + "):");
for (Iterator categoryIter = metrics.keySet().iterator(); categoryIter
.hasNext();) {
String categoryName = (String) categoryIter.next();
logger.trace("Category: " + categoryName);
int i = 0;
Collection metricList = (Collection) metrics.get(categoryName);
for (Iterator iter = metricList.iterator(); iter.hasNext();) {
MetricDisplaySummary summaryBean = (MetricDisplaySummary) iter
.next();
++i;
logger.trace("\t " + i + ": " + summaryBean);
}
}
}
public static void traceResourceTypeDisplaySummaryList(Log logger,
List healths) {
logger.trace("Dumping list of ResourceTypeDisplaySummary's (from "
+ MonitorUtilsNG.class.getName() + "):");
if (healths == null) {
logger.trace("'healths' list was null!");
return;
}
if (healths.size() < 1) {
logger.trace("'healths' list was empty!");
return;
}
int i = 0;
for (Iterator iter = healths.iterator(); iter.hasNext();) {
ResourceTypeDisplaySummary summaryBean = (ResourceTypeDisplaySummary) iter
.next();
++i;
logger.trace("\t" + i + ":" + summaryBean);
}
}
public static Integer formatMetrics(Map metrics, Locale userLocale) {
Integer resourceCount = null;
try {
for (Iterator iter = metrics.values().iterator(); iter.hasNext();) {
Collection metricList = (Collection) iter.next();
for (Iterator m = metricList.iterator(); m.hasNext();) {
MetricDisplaySummary mds = (MetricDisplaySummary) m.next();
if (resourceCount == null)
resourceCount = mds.getAvailUp();
// the formatting subsystem doesn't interpret
// units set to empty strings as "no units" so
// we'll explicity set it so
if (mds.getUnits().length() < 1) {
mds.setUnits(MeasurementConstants.UNITS_NONE);
}
FormattedNumber[] fs = new FormattedNumber[0];
String fmtString = LocalizedTextUtil.findDefaultText(
Constants.UNIT_FORMAT_PREFIX_KEY + mds.getUnits(),
userLocale);
if (fmtString != null) {
// this means that there's a whole song and dance for
// formatting this type of thing
// a certain way (hopefully in a way that some decendent
// of java.test.Format will
// help with)
if (mds.getUnits().equals(
MeasurementConstants.UNITS_EPOCH_MILLIS)) {
DateSpecifics specs = new DateSpecifics();
specs.setDateFormat(new SimpleDateFormat(fmtString,
userLocale));
fs = UnitsConvert.convertSame(
mds.getMetricValueDoubles(),
mds.getUnits(), userLocale, specs);
} else {
fs = UnitsConvert.convertSame(
mds.getMetricValueDoubles(),
mds.getUnits(), userLocale);
}
} else {
fs = UnitsConvert.convertSame(
mds.getMetricValueDoubles(), mds.getUnits(),
userLocale);
}
String[] keys = mds.getMetricKeys();
if (keys.length != fs.length)
throw new IllegalStateException(
"Formatting metrics failed");
for (int i = 0; i < keys.length; i++) {
mds.getMetric(keys[i]).setValueFmt(fs[i]);
}
}
}
} catch (IllegalArgumentException e) { // catch and rethrow for
// debug/logging only
if (log.isDebugEnabled())
log.debug(
"formatting metrics failed due to IllegalArgumentException: ",
e);
throw e;
}
return resourceCount;
}
public static Map<String, String> getThresholdMenu() {
Map<String, String> items = new HashMap<String, String>();
String label = null, value = null;
label = MonitorUtilsNG.THRESHOLD_BASELINE_LABEL;
value = String.valueOf(MonitorUtilsNG.THRESHOLD_BASELINE_VALUE);
items.put(label, value);
label = MonitorUtilsNG.THRESHOLD_HIGH_RANGE_LABEL;
value = String.valueOf(MonitorUtilsNG.THRESHOLD_HIGH_RANGE_VALUE);
items.put(label, value);
label = MonitorUtilsNG.THRESHOLD_LOW_RANGE_LABEL;
value = String.valueOf(MonitorUtilsNG.THRESHOLD_LOW_RANGE_VALUE);
items.put(label, value);
return items;
}
}