/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.statistics;
import org.apache.geode.*;
import org.apache.geode.internal.i18n.LocalizedStrings;
/**
* Describes an individual statistic whose value is updated by an application and may be archived by
* GemFire. These descriptions are gathered together in a {@link StatisticsType}.
*
* @see Statistics
*
*
* @since GemFire 3.0
*/
public final class StatisticDescriptorImpl implements StatisticDescriptor {
/** A constant for an <code>byte</code> type */
static final byte BYTE = (byte) 3;
/** A constant for an <code>short</code> type */
static final byte SHORT = (byte) 4;
/** A constant for an <code>int</code> type */
static final byte INT = (byte) 5;
/** A constant for an <code>long</code> type */
static final byte LONG = (byte) 6;
/** A constant for an <code>float</code> type */
static final byte FLOAT = (byte) 7;
/** A constant for an <code>double</code> type */
static final byte DOUBLE = (byte) 8;
//////////////////// Instance Fields ////////////////////
/** An unitialized offset */
private int INVALID_OFFSET = -1;
/** The name of the statistic */
private final String name;
/** The type code of this statistic */
private final byte typeCode;
/** A description of the statistic */
private final String description;
/** The unit of the statistic */
private final String unit;
/** Is the statistic a counter? */
private final boolean isCounter;
/** Do larger values of the statistic indicate better performance? */
private final boolean isLargerBetter;
/**
* The physical offset used to access the data that stores the value for this statistic in an
* instance of {@link Statistics}
*/
private int id = INVALID_OFFSET;
////////////////////// Static Methods //////////////////////
/**
* Returns the name of the given type code
*
* @throws IllegalArgumentException <code>code</code> is an unknown type
*/
public final static String getTypeCodeName(int code) {
switch (code) {
case BYTE:
return "byte";
case SHORT:
return "short";
case FLOAT:
return "float";
case INT:
return "int";
case LONG:
return "long";
case DOUBLE:
return "double";
default:
throw new IllegalArgumentException(
LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0
.toLocalizedString(Integer.valueOf(code)));
}
}
/**
* Returns the number of bits needed to represent a value of the given type
*
* @throws IllegalArgumentException <code>code</code> is an unknown type
*/
public final static int getTypeCodeBits(int code) {
switch (code) {
case BYTE:
return 8;
case SHORT:
return 16;
case FLOAT:
return 32;
case INT:
return 32;
case LONG:
return 64;
case DOUBLE:
return 64;
default:
throw new IllegalArgumentException(
LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0
.toLocalizedString(Integer.valueOf(code)));
}
}
/**
* Returns the class of the given type code
*
* @throws IllegalArgumentException <code>code</code> is an unknown type
*/
public final static Class<?> getTypeCodeClass(byte code) {
switch (code) {
case BYTE:
return byte.class;
case SHORT:
return short.class;
case FLOAT:
return float.class;
case INT:
return int.class;
case LONG:
return long.class;
case DOUBLE:
return double.class;
default:
throw new IllegalArgumentException(
LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0
.toLocalizedString(Integer.valueOf(code)));
}
}
public static StatisticDescriptor createIntCounter(String name, String description, String units,
boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, INT, description, units, true, isLargerBetter);
}
public static StatisticDescriptor createLongCounter(String name, String description, String units,
boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, LONG, description, units, true, isLargerBetter);
}
public static StatisticDescriptor createDoubleCounter(String name, String description,
String units, boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, DOUBLE, description, units, true, isLargerBetter);
}
public static StatisticDescriptor createIntGauge(String name, String description, String units,
boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, INT, description, units, false, isLargerBetter);
}
public static StatisticDescriptor createLongGauge(String name, String description, String units,
boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, LONG, description, units, false, isLargerBetter);
}
public static StatisticDescriptor createDoubleGauge(String name, String description, String units,
boolean isLargerBetter) {
return new StatisticDescriptorImpl(name, DOUBLE, description, units, false, isLargerBetter);
}
/////////////////////// Constructors ///////////////////////
/**
* Creates a new description of a statistic.
*
* @param name The name of the statistic (for example, <code>"numDatabaseLookups"</code>)
* @param typeCode The type of the statistic. This must be either <code>int.class</code>,
* <code>long.class</code>, or <code>double.class</code>.
* @param description A description of the statistic (for example, <code>"The
* number of database lookups"</code>
* @param unit The units that this statistic is measure in (for example,
* <code>"milliseconds"</code>)
* @param isCounter Is this statistic a counter? That is, does its value change monotonically
* (always increases or always decreases)?
* @param isLargerBetter True if larger values indicate better performance.
*
* @throws IllegalArgumentException <code>type</code> is not one of <code>int.class</code>,
* <code>long.class</code>, or <code>double.class</code>.
*/
private StatisticDescriptorImpl(String name, byte typeCode, String description, String unit,
boolean isCounter, boolean isLargerBetter) {
this.name = name;
this.typeCode = typeCode;
if (description == null) {
this.description = "";
} else {
this.description = description;
}
if (unit == null) {
this.unit = "";
} else {
this.unit = unit;
}
this.isCounter = isCounter;
this.isLargerBetter = isLargerBetter;
}
//////////////////// StatisticDescriptor Methods ////////////////////
public final String getName() {
return this.name;
}
public final String getDescription() {
return this.description;
}
public final Class<?> getType() {
return getTypeCodeClass(this.typeCode);
}
public final int getStorageBits() {
return getTypeCodeBits(this.typeCode);
}
public final boolean isCounter() {
return this.isCounter;
}
public final boolean isLargerBetter() {
return this.isLargerBetter;
}
public final String getUnit() {
return this.unit;
}
public final int getId() {
// if (this.id == INVALID_OFFSET) {
// String s = "The id has not been initialized yet.";
// throw new IllegalStateException(s);
// }
// Assert.assertTrue(this.id >= 0);
return this.id;
}
public final Number getNumberForRawBits(long bits) {
switch (this.typeCode) {
case StatisticDescriptorImpl.INT:
return (int) bits;
case StatisticDescriptorImpl.LONG:
return bits;
case StatisticDescriptorImpl.DOUBLE:
return Double.longBitsToDouble(bits);
default:
throw new RuntimeException(
LocalizedStrings.StatisticsImpl_UNEXPECTED_STAT_DESCRIPTOR_TYPE_CODE_0
.toLocalizedString(Byte.valueOf(this.typeCode)));
}
}
//////////////////// Instance Methods ////////////////////
/**
* Returns the type code of this statistic
*/
public final byte getTypeCode() {
return this.typeCode;
}
/**
* Sets the id of this descriptor
*/
final void setId(int id) {
// Assert.assertTrue(id >= 0);
this.id = id;
}
//////////////////// Comparable Methods ////////////////////
/**
* <code>StatisticDescriptor</code>s are naturally ordered by their name.
*
* @throws IllegalArgumentException <code>o</code> is not a <code>StatisticDescriptor</code>
*
* @see #getName
*/
public int compareTo(StatisticDescriptor o) {
return this.getName().compareTo(o.getName());
}
public final int checkInt() {
if (this.typeCode != INT) {
throw new IllegalArgumentException(
LocalizedStrings.StatisticDescriptorImpl_THE_STATISTIC_0_WITH_ID_1_IS_OF_TYPE_2_AND_IT_WAS_EXPECTED_TO_BE_AN_INT
.toLocalizedString(new Object[] {getName(), Integer.valueOf(getId()),
StatisticDescriptorImpl.getTypeCodeName(getTypeCode())}));
}
return this.id;
}
public final int checkLong() {
if (this.typeCode != LONG) {
StringBuffer sb = new StringBuffer();
sb.append("The statistic " + getName() + " with id ");
sb.append(getId());
sb.append(" is of type ");
sb.append(StatisticDescriptorImpl.getTypeCodeName(getTypeCode()));
sb.append(" and it was expected to be a long");
throw new IllegalArgumentException(sb.toString());
}
return this.id;
}
public final int checkDouble() {
if (this.typeCode != DOUBLE) {
throw new IllegalArgumentException(
LocalizedStrings.StatisticDescriptorImpl_THE_STATISTIC_0_WITH_ID_1_IS_OF_TYPE_2_AND_IT_WAS_EXPECTED_TO_BE_A_DOUBLE
.toLocalizedString(new Object[] {getName(), Integer.valueOf(getId()),
StatisticDescriptorImpl.getTypeCodeName(getTypeCode())}));
}
return this.id;
}
@Override // GemStoneAddition
public int hashCode() {
return getName().hashCode();
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof StatisticDescriptorImpl)) {
return false;
}
StatisticDescriptorImpl other = (StatisticDescriptorImpl) o;
if (getId() != other.getId()) {
return false;
}
if (!getName().equals(other.getName())) {
return false;
}
if (isCounter() != other.isCounter()) {
return false;
}
if (isLargerBetter() != other.isLargerBetter()) {
return false;
}
if (!getType().equals(other.getType())) {
return false;
}
if (!getUnit().equals(other.getUnit())) {
return false;
}
if (!getDescription().equals(other.getDescription())) {
return false;
}
return true;
}
}