001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.hbtop.field;
019
020import edu.umd.cs.findbugs.annotations.NonNull;
021import java.util.Objects;
022import org.apache.hadoop.hbase.Size;
023import org.apache.yetus.audience.InterfaceAudience;
024
025
026/**
027 * Represents a value of a field.
028 *
029 * The type of a value is defined by {@link FieldValue}.
030 */
031@InterfaceAudience.Private
032public final class FieldValue implements Comparable<FieldValue> {
033
034  private final Object value;
035  private final FieldValueType type;
036
037  FieldValue(Object value, FieldValueType type) {
038    Objects.requireNonNull(value);
039    this.type = Objects.requireNonNull(type);
040
041    switch (type) {
042      case STRING:
043        if (value instanceof String) {
044          this.value = value;
045          break;
046        }
047        throw new IllegalArgumentException("invalid type");
048
049      case INTEGER:
050        if (value instanceof Integer) {
051          this.value = value;
052          break;
053        } else if (value instanceof String) {
054          this.value = Integer.valueOf((String) value);
055          break;
056        }
057        throw new IllegalArgumentException("invalid type");
058
059      case LONG:
060        if (value instanceof Long) {
061          this.value = value;
062          break;
063        } else if (value instanceof String) {
064          this.value = Long.valueOf((String) value);
065          break;
066        }
067        throw new IllegalArgumentException("invalid type");
068
069      case FLOAT:
070        if (value instanceof Float) {
071          this.value = value;
072          break;
073        } else if (value instanceof String) {
074          this.value = Float.valueOf((String) value);
075          break;
076        }
077        throw new IllegalArgumentException("invalid type");
078
079      case SIZE:
080        if (value instanceof Size) {
081          this.value = optimizeSize((Size) value);
082          break;
083        } else if (value instanceof String) {
084          this.value = optimizeSize(parseSizeString((String) value));
085          break;
086        }
087        throw new IllegalArgumentException("invalid type");
088
089      case PERCENT:
090        if (value instanceof Float) {
091          this.value = value;
092          break;
093        } else if (value instanceof String) {
094          this.value = parsePercentString((String) value);
095          break;
096        }
097        throw new IllegalArgumentException("invalid type");
098
099      default:
100        throw new AssertionError();
101    }
102  }
103
104  private Size optimizeSize(Size size) {
105    if (size.get(Size.Unit.BYTE) < 1024d) {
106      return size.getUnit() == Size.Unit.BYTE ?
107        size : new Size(size.get(Size.Unit.BYTE), Size.Unit.BYTE);
108    } else if (size.get(Size.Unit.KILOBYTE) < 1024d) {
109      return size.getUnit() == Size.Unit.KILOBYTE ?
110        size : new Size(size.get(Size.Unit.KILOBYTE), Size.Unit.KILOBYTE);
111    } else if (size.get(Size.Unit.MEGABYTE) < 1024d) {
112      return size.getUnit() == Size.Unit.MEGABYTE ?
113        size : new Size(size.get(Size.Unit.MEGABYTE), Size.Unit.MEGABYTE);
114    } else if (size.get(Size.Unit.GIGABYTE) < 1024d) {
115      return size.getUnit() == Size.Unit.GIGABYTE ?
116        size : new Size(size.get(Size.Unit.GIGABYTE), Size.Unit.GIGABYTE);
117    } else if (size.get(Size.Unit.TERABYTE) < 1024d) {
118      return size.getUnit() == Size.Unit.TERABYTE ?
119        size : new Size(size.get(Size.Unit.TERABYTE), Size.Unit.TERABYTE);
120    }
121    return size.getUnit() == Size.Unit.PETABYTE ?
122      size : new Size(size.get(Size.Unit.PETABYTE), Size.Unit.PETABYTE);
123  }
124
125  private Size parseSizeString(String sizeString) {
126    if (sizeString.length() < 3) {
127      throw new IllegalArgumentException("invalid size");
128    }
129
130    String valueString = sizeString.substring(0, sizeString.length() - 2);
131    String unitSimpleName = sizeString.substring(sizeString.length() - 2);
132    return new Size(Double.parseDouble(valueString), convertToUnit(unitSimpleName));
133  }
134
135  private Size.Unit convertToUnit(String unitSimpleName) {
136    for (Size.Unit unit: Size.Unit.values()) {
137      if (unitSimpleName.equals(unit.getSimpleName())) {
138        return unit;
139      }
140    }
141    throw new IllegalArgumentException("invalid size");
142  }
143
144  private Float parsePercentString(String percentString) {
145    if (percentString.endsWith("%")) {
146      percentString = percentString.substring(0, percentString.length() - 1);
147    }
148    return Float.valueOf(percentString);
149  }
150
151  public String asString() {
152    return toString();
153  }
154
155  public int asInt() {
156    return (Integer) value;
157  }
158
159  public long asLong() {
160    return (Long) value;
161  }
162
163  public float asFloat() {
164    return (Float) value;
165  }
166
167  public Size asSize() {
168    return (Size) value;
169  }
170
171  @Override
172  public String toString() {
173    switch (type) {
174      case STRING:
175      case INTEGER:
176      case LONG:
177      case FLOAT:
178        return value.toString();
179
180      case SIZE:
181        Size size = (Size) value;
182        return String.format("%.1f", size.get()) + size.getUnit().getSimpleName();
183
184      case PERCENT:
185        return String.format("%.2f", (Float) value) + "%";
186
187      default:
188        throw new AssertionError();
189    }
190  }
191
192  @Override
193  public int compareTo(@NonNull FieldValue o) {
194    if (type != o.type) {
195      throw new IllegalArgumentException("invalid type");
196    }
197
198    switch (type) {
199      case STRING:
200        return ((String) value).compareTo((String) o.value);
201
202      case INTEGER:
203        return ((Integer) value).compareTo((Integer) o.value);
204
205      case LONG:
206        return ((Long) value).compareTo((Long) o.value);
207
208      case FLOAT:
209      case PERCENT:
210        return ((Float) value).compareTo((Float) o.value);
211
212      case SIZE:
213        return ((Size) value).compareTo((Size) o.value);
214
215      default:
216        throw new AssertionError();
217    }
218  }
219
220  @Override
221  public boolean equals(Object o) {
222    if (this == o) {
223      return true;
224    }
225    if (!(o instanceof FieldValue)) {
226      return false;
227    }
228    FieldValue that = (FieldValue) o;
229    return value.equals(that.value) && type == that.type;
230  }
231
232  @Override
233  public int hashCode() {
234    return Objects.hash(value, type);
235  }
236
237  public FieldValue plus(FieldValue o) {
238    if (type != o.type) {
239      throw new IllegalArgumentException("invalid type");
240    }
241
242    switch (type) {
243      case STRING:
244        return new FieldValue(((String) value).concat((String) o.value), type);
245
246      case INTEGER:
247        return new FieldValue(((Integer) value) + ((Integer) o.value), type);
248
249      case LONG:
250        return new FieldValue(((Long) value) + ((Long) o.value), type);
251
252      case FLOAT:
253      case PERCENT:
254        return new FieldValue(((Float) value) + ((Float) o.value), type);
255
256      case SIZE:
257        Size size = (Size) value;
258        Size oSize = (Size) o.value;
259        Size.Unit unit = size.getUnit();
260        return new FieldValue(new Size(size.get(unit) + oSize.get(unit), unit), type);
261
262      default:
263        throw new AssertionError();
264    }
265  }
266
267  public int compareToIgnoreCase(FieldValue o) {
268    if (type != o.type) {
269      throw new IllegalArgumentException("invalid type");
270    }
271
272    switch (type) {
273      case STRING:
274        return ((String) value).compareToIgnoreCase((String) o.value);
275
276      case INTEGER:
277      case LONG:
278      case FLOAT:
279      case SIZE:
280      case PERCENT:
281        return compareTo(o);
282
283      default:
284        throw new AssertionError();
285    }
286  }
287}