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      case SIZE:
179        return value.toString();
180
181      case PERCENT:
182        return String.format("%.2f", (Float) value) + "%";
183
184      default:
185        throw new AssertionError();
186    }
187  }
188
189  @Override
190  public int compareTo(@NonNull FieldValue o) {
191    if (type != o.type) {
192      throw new IllegalArgumentException("invalid type");
193    }
194
195    switch (type) {
196      case STRING:
197        return ((String) value).compareTo((String) o.value);
198
199      case INTEGER:
200        return ((Integer) value).compareTo((Integer) o.value);
201
202      case LONG:
203        return ((Long) value).compareTo((Long) o.value);
204
205      case FLOAT:
206      case PERCENT:
207        return ((Float) value).compareTo((Float) o.value);
208
209      case SIZE:
210        return ((Size) value).compareTo((Size) o.value);
211
212      default:
213        throw new AssertionError();
214    }
215  }
216
217  @Override
218  public boolean equals(Object o) {
219    if (this == o) {
220      return true;
221    }
222    if (!(o instanceof FieldValue)) {
223      return false;
224    }
225    FieldValue that = (FieldValue) o;
226    return value.equals(that.value) && type == that.type;
227  }
228
229  @Override
230  public int hashCode() {
231    return Objects.hash(value, type);
232  }
233
234  public FieldValue plus(FieldValue o) {
235    if (type != o.type) {
236      throw new IllegalArgumentException("invalid type");
237    }
238
239    switch (type) {
240      case STRING:
241        return new FieldValue(((String) value).concat((String) o.value), type);
242
243      case INTEGER:
244        return new FieldValue(((Integer) value) + ((Integer) o.value), type);
245
246      case LONG:
247        return new FieldValue(((Long) value) + ((Long) o.value), type);
248
249      case FLOAT:
250      case PERCENT:
251        return new FieldValue(((Float) value) + ((Float) o.value), type);
252
253      case SIZE:
254        Size size = (Size) value;
255        Size oSize = (Size) o.value;
256        Size.Unit unit = size.getUnit();
257        return new FieldValue(new Size(size.get(unit) + oSize.get(unit), unit), type);
258
259      default:
260        throw new AssertionError();
261    }
262  }
263
264  public int compareToIgnoreCase(FieldValue o) {
265    if (type != o.type) {
266      throw new IllegalArgumentException("invalid type");
267    }
268
269    switch (type) {
270      case STRING:
271        return ((String) value).compareToIgnoreCase((String) o.value);
272
273      case INTEGER:
274      case LONG:
275      case FLOAT:
276      case SIZE:
277      case PERCENT:
278        return compareTo(o);
279
280      default:
281        throw new AssertionError();
282    }
283  }
284}