1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
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 }