View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.hbtop;
19  
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.Objects;
23  
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.hbase.hbtop.field.Field;
26  import org.apache.hadoop.hbase.hbtop.field.FieldValue;
27  
28  /**
29   * Represents a filter that's filtering the metric {@link Record}s.
30   */
31  @InterfaceAudience.Private
32  public final class RecordFilter {
33  
34    private enum Operator {
35      EQUAL("="),
36      DOUBLE_EQUALS("=="),
37      GREATER(">"),
38      GREATER_OR_EQUAL(">="),
39      LESS("<"),
40      LESS_OR_EQUAL("<=");
41  
42      private final String operator;
43  
44      Operator(String operator) {
45        this.operator = operator;
46      }
47  
48      @Override
49      public String toString() {
50        return operator;
51      }
52    }
53  
54    public static RecordFilter parse(String filterString, boolean ignoreCase) {
55      return parse(filterString, Arrays.asList(Field.values()), ignoreCase);
56    }
57  
58    /*
59     * Parse a filter string and build a RecordFilter instance.
60     */
61    public static RecordFilter parse(String filterString, List<Field> fields, boolean ignoreCase) {
62      int index = 0;
63  
64      boolean not = isNot(filterString);
65      if (not) {
66        index += 1;
67      }
68  
69      StringBuilder fieldString = new StringBuilder();
70      while (filterString.length() > index && filterString.charAt(index) != '<'
71        && filterString.charAt(index) != '>' && filterString.charAt(index) != '=') {
72        fieldString.append(filterString.charAt(index++));
73      }
74  
75      if (fieldString.length() == 0 || filterString.length() == index) {
76        return null;
77      }
78  
79      Field field = getField(fields, fieldString.toString());
80      if (field == null) {
81        return null;
82      }
83  
84      StringBuilder operatorString = new StringBuilder();
85      while (filterString.length() > index && (filterString.charAt(index) == '<' ||
86        filterString.charAt(index) == '>' || filterString.charAt(index) == '=')) {
87        operatorString.append(filterString.charAt(index++));
88      }
89  
90      Operator operator = getOperator(operatorString.toString());
91      if (operator == null) {
92        return null;
93      }
94  
95      String value = filterString.substring(index);
96      FieldValue fieldValue = getFieldValue(field, value);
97      if (fieldValue == null) {
98        return null;
99      }
100 
101     return new RecordFilter(ignoreCase, not, field, operator, fieldValue);
102   }
103 
104   private static FieldValue getFieldValue(Field field, String value) {
105     try {
106       return field.newValue(value);
107     } catch (Exception e) {
108       return null;
109     }
110   }
111 
112   private static boolean isNot(String filterString) {
113     return filterString.startsWith("!");
114   }
115 
116   private static Field getField(List<Field> fields, String fieldString) {
117     for (Field f : fields) {
118       if (f.getHeader().equals(fieldString)) {
119         return f;
120       }
121     }
122     return null;
123   }
124 
125   private static Operator getOperator(String operatorString) {
126     for (Operator o : Operator.values()) {
127       if (operatorString.equals(o.toString())) {
128         return o;
129       }
130     }
131     return null;
132   }
133 
134   private final boolean ignoreCase;
135   private final boolean not;
136   private final Field field;
137   private final Operator operator;
138   private final FieldValue value;
139 
140   private RecordFilter(boolean ignoreCase, boolean not, Field field, Operator operator,
141     FieldValue value) {
142     this.ignoreCase = ignoreCase;
143     this.not = not;
144     this.field = Objects.requireNonNull(field);
145     this.operator = Objects.requireNonNull(operator);
146     this.value = Objects.requireNonNull(value);
147   }
148 
149   public boolean execute(Record record) {
150     FieldValue fieldValue = record.get(field);
151     if (fieldValue == null) {
152       return false;
153     }
154 
155     if (operator == Operator.EQUAL) {
156       boolean ret;
157       if (ignoreCase) {
158         ret = fieldValue.asString().toLowerCase().contains(value.asString().toLowerCase());
159       } else {
160         ret = fieldValue.asString().contains(value.asString());
161       }
162       return not != ret;
163     }
164 
165     int compare = ignoreCase ?
166       fieldValue.compareToIgnoreCase(value) : fieldValue.compareTo(value);
167 
168     boolean ret;
169     switch (operator) {
170       case DOUBLE_EQUALS:
171         ret = compare == 0;
172         break;
173 
174       case GREATER:
175         ret = compare > 0;
176         break;
177 
178       case GREATER_OR_EQUAL:
179         ret = compare >= 0;
180         break;
181 
182       case LESS:
183         ret = compare < 0;
184         break;
185 
186       case LESS_OR_EQUAL:
187         ret = compare <= 0;
188         break;
189 
190       default:
191         throw new AssertionError();
192     }
193     return not != ret;
194   }
195 
196   @Override
197   public String toString() {
198     return (not ? "!" : "") + field.getHeader() + operator + value.asString();
199   }
200 
201   @Override
202   public boolean equals(Object o) {
203     if (this == o) {
204       return true;
205     }
206     if (!(o instanceof RecordFilter)) {
207       return false;
208     }
209     RecordFilter filter = (RecordFilter) o;
210     return ignoreCase == filter.ignoreCase && not == filter.not && field == filter.field
211       && operator == filter.operator && value.equals(filter.value);
212   }
213 
214   @Override
215   public int hashCode() {
216     return Objects.hash(ignoreCase, not, field, operator, value);
217   }
218 
219   /*
220    * For FilterBuilder
221    */
222   public static FilterBuilder newBuilder(Field field) {
223     return new FilterBuilder(field, false);
224   }
225 
226   public static FilterBuilder newBuilder(Field field, boolean ignoreCase) {
227     return new FilterBuilder(field, ignoreCase);
228   }
229 
230   public static final class FilterBuilder {
231     private final Field field;
232     private final boolean ignoreCase;
233 
234     private FilterBuilder(Field field, boolean ignoreCase) {
235       this.field = Objects.requireNonNull(field);
236       this.ignoreCase = ignoreCase;
237     }
238 
239     public RecordFilter equal(FieldValue value) {
240       return newFilter(false, Operator.EQUAL, value);
241     }
242 
243     public RecordFilter equal(Object value) {
244       return equal(field.newValue(value));
245     }
246 
247     public RecordFilter notEqual(FieldValue value) {
248       return newFilter(true, Operator.EQUAL, value);
249     }
250 
251     public RecordFilter notEqual(Object value) {
252       return notEqual(field.newValue(value));
253     }
254 
255     public RecordFilter doubleEquals(FieldValue value) {
256       return newFilter(false, Operator.DOUBLE_EQUALS, value);
257     }
258 
259     public RecordFilter doubleEquals(Object value) {
260       return doubleEquals(field.newValue(value));
261     }
262 
263     public RecordFilter notDoubleEquals(FieldValue value) {
264       return newFilter(true, Operator.DOUBLE_EQUALS, value);
265     }
266 
267     public RecordFilter notDoubleEquals(Object value) {
268       return notDoubleEquals(field.newValue(value));
269     }
270 
271     public RecordFilter greater(FieldValue value) {
272       return newFilter(false, Operator.GREATER, value);
273     }
274 
275     public RecordFilter greater(Object value) {
276       return greater(field.newValue(value));
277     }
278 
279     public RecordFilter notGreater(FieldValue value) {
280       return newFilter(true, Operator.GREATER, value);
281     }
282 
283     public RecordFilter notGreater(Object value) {
284       return notGreater(field.newValue(value));
285     }
286 
287     public RecordFilter greaterOrEqual(FieldValue value) {
288       return newFilter(false, Operator.GREATER_OR_EQUAL, value);
289     }
290 
291     public RecordFilter greaterOrEqual(Object value) {
292       return greaterOrEqual(field.newValue(value));
293     }
294 
295     public RecordFilter notGreaterOrEqual(FieldValue value) {
296       return newFilter(true, Operator.GREATER_OR_EQUAL, value);
297     }
298 
299     public RecordFilter notGreaterOrEqual(Object value) {
300       return notGreaterOrEqual(field.newValue(value));
301     }
302 
303     public RecordFilter less(FieldValue value) {
304       return newFilter(false, Operator.LESS, value);
305     }
306 
307     public RecordFilter less(Object value) {
308       return less(field.newValue(value));
309     }
310 
311     public RecordFilter notLess(FieldValue value) {
312       return newFilter(true, Operator.LESS, value);
313     }
314 
315     public RecordFilter notLess(Object value) {
316       return notLess(field.newValue(value));
317     }
318 
319     public RecordFilter lessOrEqual(FieldValue value) {
320       return newFilter(false, Operator.LESS_OR_EQUAL, value);
321     }
322 
323     public RecordFilter lessOrEqual(Object value) {
324       return lessOrEqual(field.newValue(value));
325     }
326 
327     public RecordFilter notLessOrEqual(FieldValue value) {
328       return newFilter(true, Operator.LESS_OR_EQUAL, value);
329     }
330 
331     public RecordFilter notLessOrEqual(Object value) {
332       return notLessOrEqual(field.newValue(value));
333     }
334 
335     private RecordFilter newFilter(boolean not, Operator operator, FieldValue value) {
336       return new RecordFilter(ignoreCase, not, field, operator, value);
337     }
338   }
339 }