/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.controller.client.helpers; import org.jboss.as.controller.client.logging.ControllerClientLogger; /** * Metric data values can be in one of the following known units of measurement. These enum values should correspond to * the "units" attribute enumerated type values as defined in the plugin descriptor's <metric> element. * * @author Joseph Marques * @author Brian Stansberry (c) 2011 Red Hat Inc. */ public enum MeasurementUnit { // Simple Metric Types - Absolute and Relative NONE("", Family.ABSOLUTE, Scale.ONE), // PERCENTAGE("%", Family.RELATIVE, Scale.HECTO), // // Absolute Sizes in Bytes (utilization) BYTES("B", Family.BYTES, Scale.ONE), // KILOBYTES("KB", Family.BYTES, Scale.KILO), // MEGABYTES("MB", Family.BYTES, Scale.MEGA), // GIGABYTES("GB", Family.BYTES, Scale.GIGA), // TERABYTES("TB", Family.BYTES, Scale.TERA), // PETABYTES("PB", Family.BYTES, Scale.PETA), // // Absolute Sizes in Bits (throughput) BITS("b", Family.BITS, Scale.ONE), // KILOBITS("Kb", Family.BITS, Scale.KILO), // MEGABITS("Mb", Family.BITS, Scale.MEGA), // GIGABITS("Gb", Family.BITS, Scale.GIGA), // TERABITS("Tb", Family.BITS, Scale.TERA), // PETABITS("Pb", Family.BITS, Scale.PETA), // // Absolute Time - no display, only hints to the UI how to display EPOCH_MILLISECONDS("", Family.DURATION, Scale.MILLI), // EPOCH_SECONDS("", Family.DURATION, Scale.SEC), // // Relative Time JIFFYS("j", Family.TIME, Scale.JIFFY), // NANOSECONDS("ns", Family.TIME, Scale.NANO), // MICROSECONDS("us", Family.TIME, Scale.MICRO), // MILLISECONDS("ms", Family.TIME, Scale.MILLI), // SECONDS("s", Family.TIME, Scale.SEC), // MINUTES("m", Family.TIME, Scale.MIN), // HOURS("h", Family.TIME, Scale.HOUR), // DAYS("d", Family.TIME, Scale.DAY), // // Rate PER_JIFFY("/j", Family.RATE, Scale.PER_JIFFY), // PER_NANOSECOND("/ns", Family.RATE, Scale.PER_NANO), // PER_MICROSECOND("/us", Family.RATE, Scale.PER_MICRO), // PER_MILLISECOND("/ms", Family.RATE, Scale.PER_MILLI), // PER_SECOND("/s", Family.RATE, Scale.PER_SEC), // PER_MINUTE("/m", Family.RATE, Scale.PER_MIN), // PER_HOUR("/h", Family.RATE, Scale.PER_HOUR), // PER_DAY(" /d", Family.RATE, Scale.PER_DAY), // // Temperature CELSIUS("C", Family.TEMPERATURE, Scale.ONE), // KELVIN("K", Family.TEMPERATURE, Scale.ONE), // FAHRENHEIGHT("F", Family.TEMPERATURE, Scale.ONE); private String displayUnits; private Family family; private Scale scale; private MeasurementUnit(String displayUnits, Family family, Scale scale) { if (displayUnits.length() > 5) { throw ControllerClientLogger.ROOT_LOGGER.maxDisplayUnitLength(); } this.displayUnits = displayUnits; this.family = family; this.scale = scale; } public static MeasurementUnit getUsingDisplayUnits(String displayUnits, MeasurementUnit.Family family) { for (MeasurementUnit units : values()) { if ((units.getFamily() == family) && units.toString().equalsIgnoreCase(displayUnits)) { return units; } } return null; } public MeasurementUnit getBaseUnits() { if (family == Family.BYTES) { return BYTES; } else if (family == Family.BITS) { return BITS; } else if (family == Family.TIME) { return SECONDS; } else if (family == Family.RATE) { return PER_SECOND; } else if (family == Family.TEMPERATURE) { return CELSIUS; } else if ((family == Family.ABSOLUTE) || (family == Family.DURATION) || (family == Family.RELATIVE)) { /* * Members of these families are their own base units */ return this; } return null; } public boolean isComparableTo(MeasurementUnit other) { return family == other.family; } public static Double calculateOffset(MeasurementUnit first, MeasurementUnit second) throws MeasurementConversionException { if (first.isComparableTo(second) == false) { throw new MeasurementConversionException(ControllerClientLogger.ROOT_LOGGER.cannotConvert(first.name(), second.name())); } return Scale.calculateOffset(first.scale, second.scale); } public Family getFamily() { return family; } /** * A Java bean style getter to allow us to access the enum name from JSPs (e.g. ${measureUnits.name}). * * @return the enum name */ public String getName() { return name(); } @Override public String toString() { return this.displayUnits; } public enum Family { ABSOLUTE, BITS, BYTES, DURATION, RELATIVE, RATE, TIME, TEMPERATURE; } private enum Scale { // Binary based scaling factors CENTI(Type.SIZE), // ONE(Type.SIZE, CENTI, 100), // HECTO(Type.SIZE, ONE, 100), // KILO(Type.SIZE, ONE, 1024), // MEGA(Type.SIZE, KILO, 1024), // GIGA(Type.SIZE, MEGA, 1024), // TERA(Type.SIZE, GIGA, 1024), // PETA(Type.SIZE, TERA, 1024), // // Time based scaling factors JIFFY(Type.TIME), // NANO(Type.TIME, JIFFY, 1000), // MICRO(Type.TIME, NANO, 1000), // MILLI(Type.TIME, MICRO, 1000), // SEC(Type.TIME, MILLI, 1000), // MIN(Type.TIME, SEC, 60), // HOUR(Type.TIME, MIN, 60), // DAY(Type.TIME, HOUR, 24), // WEEK(Type.TIME, DAY, 7), // YEAR(Type.TIME, WEEK, 52), // Rate based scaling factors PER_JIFFY(Type.RATE), // PER_NANO(Type.RATE, PER_JIFFY, .001d), // PER_MICRO(Type.RATE, PER_NANO, .001d), // PER_MILLI(Type.RATE, PER_MICRO, .001d), // PER_SEC(Type.RATE, PER_MILLI, .001d), // PER_MIN(Type.RATE, PER_SEC, 1d/60d), // PER_HOUR(Type.RATE, PER_MIN, 1d/60d), // PER_DAY(Type.RATE, PER_HOUR, 1d/24d), // PER_WEEK(Type.RATE, PER_DAY, 1d/7d), // PER_YEAR(Type.RATE, PER_WEEK, 1d/52d); enum Type { NONE, SIZE, TIME, RATE; } private Type type; private Scale comparisonScale; private double offset; private Scale(Type type) { this.type = type; } private Scale(Type type, Scale comparisonScale, double offset) { this(type); this.comparisonScale = comparisonScale; this.offset = offset; } // don't expose this, force callers through MeasurementUnit.applyScale() /** * @param value * @param scale * * @return value scaled by the supplied Scale offset. 0.0 if scale is null. */ static Double scaleUp(Double value, Scale scale) { if (null == scale) { return 0.0; } return value * scale.offset; } // don't expose this, force callers through MeasurementUnit.applyScale() /** * @param value * @param scale * * @return value scaled by the supplied Scale offset. 0.0 if scale is null. */ static Double scaleDown(Double value, Scale scale) { if (null == scale) { return 0.0; } return value / scale.offset; } // don't expose this, force callers through MeasurementUnit.getScaleOffset() static Double calculateOffset(Scale first, Scale second) { if (first.type != second.type) { /* * special return value meaning invalid comparison, though it was designed that this method would only * be calling by the outer enumeration, which wouldn't do the necessary checks in advance. so this code * path will rarely, if ever, be followed. */ return null; } if ((first.comparisonScale == null) && (second.comparisonScale == null)) { return 1.0; } Scale higher; Scale lower; if (first.comparisonScale == null) { higher = second; lower = first; } else if (second.comparisonScale == null) { higher = first; lower = second; } else { if (first.comparisonScale.ordinal() > second.comparisonScale.ordinal()) { higher = first; lower = second; } else if (first.comparisonScale.ordinal() < second.comparisonScale.ordinal()) { higher = second; lower = first; } else { return 1.0; } } double results = 1.0; Scale movingScale = higher; while ((movingScale != lower) && (movingScale.comparisonScale != null)) { results *= movingScale.offset; movingScale = movingScale.comparisonScale; } if (first == lower) { return 1 / results; // return inverse } return results; } } public static class MeasurementConversionException extends RuntimeException { public MeasurementConversionException(String message) { super(message); } } }