001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.monitoring.counters;
019
020 import java.util.ArrayList;
021 import java.util.Collections;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Set;
025 import java.util.concurrent.ConcurrentHashMap;
026 import java.util.concurrent.CopyOnWriteArraySet;
027
028 /**
029 * Units allow monitored data to have get typed. A primary unit is the
030 * finest unit for a data type. A primary unit can have derived units,
031 * that represent the same data type, but with a scale factor.
032 * A primary Unit is created with the {@link Unit#Unit(String)} constructor.
033 * A derived Unit is created with the {@link Unit#Unit(String, Unit, long)} constructor.
034 * <p/>
035 * A primary Unit maintains a Map of it's derived units. {@see Unit#getDerived()} can be
036 * used to retrieve the complete list, and {@see Unit#getDerived(String)} to retrieve a
037 * derived unit by it's name.
038 *
039 * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
040 */
041 public class Unit implements Comparable<Unit> {
042 private static final Map<String, Unit> UNITS = new ConcurrentHashMap<String, Unit>();
043
044 /**
045 * Time based units
046 */
047 public static class Time extends Unit {
048 public static final Unit NANOSECOND = new Unit("ns");
049 public static final Unit MICROSECOND = new Unit("µs", NANOSECOND, 1000);
050 public static final Unit MILLISECOND = new Unit("ms", MICROSECOND, 1000);
051 public static final Unit SECOND = new Unit("s", MILLISECOND, 1000);
052 public static final Unit MINUTE = new Unit("min", SECOND, 60);
053 public static final Unit HOUR = new Unit("h", MINUTE, 60);
054 public static final Unit DAY = new Unit("day", HOUR, 24);
055
056 public Time(String name) {
057 super(name);
058 }
059
060 public Time(String name, Unit derived, long scale) {
061 super(name, derived, scale);
062 }
063
064 }
065
066 /**
067 * Binary data units
068 */
069 public static class Binary
070 extends Unit {
071
072 public static final Unit BYTE = new Unit("b");
073
074 public static final Unit KBYTE = new Unit("Kb", BYTE, 1024);
075
076 public static final Unit MBYTE = new Unit("Mb", KBYTE, 1024);
077
078 public static final Unit GBYTE = new Unit("Gb", MBYTE, 1024);
079
080 public Binary(String name) {
081 super(name);
082 }
083
084 public Binary(String name, Unit derived, long scale) {
085 super(name, derived, scale);
086 }
087
088
089 }
090
091 /**
092 * unit for basic item counters & gauges
093 */
094 // "BILLION" does not have same signification depending on country (10^12 or 10^9).
095 // We use International system of unit names to avoid confusion
096 // @see http://en.wikipedia.org/wiki/SI
097 public static final Unit UNARY = new Unit("u");
098 public static final Unit DECA = new Unit("*10", UNARY, 10);
099 public static final Unit HECTO = new Unit("*100", DECA, 10);
100 public static final Unit KILO = new Unit("*1000", HECTO, 10);
101 public static final Unit MEGA = new Unit("*10^6", KILO, 1000);
102 public static final Unit GIGA = new Unit("*10^9", MEGA, 1000);
103 public static final Unit TERA = new Unit("*10^12", GIGA, 1000);
104
105 private final String name;
106
107 private final long scale;
108
109 private Unit primary;
110
111 private List<Unit> derived;
112
113 public Set<Unit> primaryUnits = new CopyOnWriteArraySet<Unit>();
114
115
116 public static Unit get(String name) {
117 return UNITS.get(name);
118 }
119
120 /**
121 * Constructor for a primary unit
122 *
123 * @param name
124 */
125 public Unit(String name) {
126 this.name = name;
127 this.primary = this;
128 this.scale = 1;
129 this.derived = new ArrayList<Unit>();
130 this.derived.add(this);
131 primaryUnits.add(this);
132 UNITS.put(name, this);
133 }
134
135 /**
136 * Constructor for a derived unit
137 *
138 * @param name
139 * @param derived the unit this unit is derived from
140 * @param scale the scale factor to convert to derived unit
141 */
142 public Unit(String name, Unit derived, long scale) {
143 this.name = name;
144 this.primary = derived.isPrimary() ? derived : derived.getPrimary();
145 this.scale = scale * derived.getScale();
146 primary.derived.add(this);
147 Collections.sort(primary.derived);
148 UNITS.put(name, this);
149 }
150
151 public Unit getDerived(String name) {
152 for (Unit unit : derived) {
153 if (unit.name.equals(name)) {
154 return unit;
155 }
156 }
157 return null;
158 }
159
160 public List<Unit> getDerived() {
161 return Collections.unmodifiableList(derived);
162 }
163
164
165 public String getName() {
166 return name;
167 }
168
169 public long getScale() {
170 return scale;
171 }
172
173 /**
174 * Convert value from unit to this unit (if conpatible)
175 *
176 * @param value value to convert
177 * @param unit unit of value
178 * @return value converted to this unit
179 */
180 public double convert(final double value, final Unit unit) {
181 if (unit == this) {
182 return value;
183 }
184 if (!isCompatible(unit)) {
185 throw new IllegalArgumentException("unit " + name + " is incompatible with unit " + unit.name);
186 }
187 return value * unit.getScale() / scale;
188 }
189
190 public boolean isPrimary() {
191 return primary == this;
192 }
193
194 public boolean isCompatible(Unit unit) {
195 return primary == unit.getPrimary();
196 }
197
198 public Unit getPrimary() {
199 return this.primary;
200 }
201
202 public int compareTo(Unit o) {
203 return scale < o.scale ? -1 : 1;
204 }
205
206 public String toString() {
207 return name;
208 }
209
210 /**
211 * @see java.lang.Object#hashCode()
212 */
213 @Override
214 public int hashCode() {
215 final int prime = 31;
216 int result = 1;
217 result = prime * result + ((name == null) ? 0 : name.hashCode());
218 return result;
219 }
220
221 /**
222 * @see java.lang.Object#equals(java.lang.Object)
223 */
224 @Override
225 public boolean equals(Object obj) {
226 if (this == obj)
227 return true;
228 if (obj == null)
229 return false;
230 if (getClass() != obj.getClass())
231 return false;
232 final Unit other = (Unit) obj;
233 if (name == null) {
234 if (other.name != null)
235 return false;
236 } else if (!name.equals(other.name))
237 return false;
238 return true;
239 }
240
241 }