1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.rest.model;
22
23 import java.io.IOException;
24 import java.io.Serializable;
25 import java.io.StringReader;
26 import java.io.StringWriter;
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import javax.xml.bind.annotation.XmlAttribute;
31 import javax.xml.bind.annotation.XmlElement;
32 import javax.xml.bind.annotation.XmlRootElement;
33
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.client.Scan;
36 import org.apache.hadoop.hbase.filter.BinaryComparator;
37 import org.apache.hadoop.hbase.filter.BinaryPrefixComparator;
38 import org.apache.hadoop.hbase.filter.ColumnCountGetFilter;
39 import org.apache.hadoop.hbase.filter.CompareFilter;
40 import org.apache.hadoop.hbase.filter.Filter;
41 import org.apache.hadoop.hbase.filter.FilterList;
42 import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
43 import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
44 import org.apache.hadoop.hbase.filter.PageFilter;
45 import org.apache.hadoop.hbase.filter.PrefixFilter;
46 import org.apache.hadoop.hbase.filter.QualifierFilter;
47 import org.apache.hadoop.hbase.filter.RegexStringComparator;
48 import org.apache.hadoop.hbase.filter.RowFilter;
49 import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
50 import org.apache.hadoop.hbase.filter.SkipFilter;
51 import org.apache.hadoop.hbase.filter.SubstringComparator;
52 import org.apache.hadoop.hbase.filter.ValueFilter;
53 import org.apache.hadoop.hbase.filter.WhileMatchFilter;
54 import org.apache.hadoop.hbase.filter.WritableByteArrayComparable;
55 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
56 import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
57 import org.apache.hadoop.hbase.rest.protobuf.generated.ScannerMessage.Scanner;
58 import org.apache.hadoop.hbase.util.Base64;
59 import org.apache.hadoop.hbase.util.Bytes;
60
61 import com.google.protobuf.ByteString;
62
63 import com.sun.jersey.api.json.JSONConfiguration;
64 import com.sun.jersey.api.json.JSONJAXBContext;
65 import com.sun.jersey.api.json.JSONMarshaller;
66 import com.sun.jersey.api.json.JSONUnmarshaller;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 @XmlRootElement(name="Scanner")
87 public class ScannerModel implements ProtobufMessageHandler, Serializable {
88
89 private static final long serialVersionUID = 1L;
90
91 private byte[] startRow = HConstants.EMPTY_START_ROW;
92 private byte[] endRow = HConstants.EMPTY_END_ROW;;
93 private List<byte[]> columns = new ArrayList<byte[]>();
94 private int batch = Integer.MAX_VALUE;
95 private long startTime = 0;
96 private long endTime = Long.MAX_VALUE;
97 private String filter = null;
98 private int maxVersions = Integer.MAX_VALUE;
99
100 @XmlRootElement
101 static class FilterModel {
102
103 @XmlRootElement
104 static class WritableByteArrayComparableModel {
105 @XmlAttribute public String type;
106 @XmlAttribute public String value;
107
108 static enum ComparatorType {
109 BinaryComparator,
110 BinaryPrefixComparator,
111 RegexStringComparator,
112 SubstringComparator
113 }
114
115 public WritableByteArrayComparableModel() { }
116
117 public WritableByteArrayComparableModel(
118 WritableByteArrayComparable comparator) {
119 String typeName = comparator.getClass().getSimpleName();
120 ComparatorType type = ComparatorType.valueOf(typeName);
121 this.type = typeName;
122 switch (type) {
123 case BinaryComparator:
124 case BinaryPrefixComparator:
125 this.value = Base64.encodeBytes(comparator.getValue());
126 break;
127 case RegexStringComparator:
128 case SubstringComparator:
129 this.value = Bytes.toString(comparator.getValue());
130 break;
131 default:
132 throw new RuntimeException("unhandled filter type: " + type);
133 }
134 }
135
136 public WritableByteArrayComparable build() {
137 WritableByteArrayComparable comparator;
138 switch (ComparatorType.valueOf(type)) {
139 case BinaryComparator: {
140 comparator = new BinaryComparator(Base64.decode(value));
141 } break;
142 case BinaryPrefixComparator: {
143 comparator = new BinaryPrefixComparator(Base64.decode(value));
144 } break;
145 case RegexStringComparator: {
146 comparator = new RegexStringComparator(value);
147 } break;
148 case SubstringComparator: {
149 comparator = new SubstringComparator(value);
150 } break;
151 default: {
152 throw new RuntimeException("unhandled comparator type: " + type);
153 }
154 }
155 return comparator;
156 }
157
158 }
159
160
161 @XmlAttribute public String type = null;
162 @XmlAttribute public String op = null;
163 @XmlElement WritableByteArrayComparableModel comparator = null;
164 @XmlAttribute public String value = null;
165 @XmlElement public List<FilterModel> filters = null;
166 @XmlAttribute public Integer limit = null;
167 @XmlAttribute public String family = null;
168 @XmlAttribute public String qualifier = null;
169 @XmlAttribute public Boolean ifMissing = null;
170 @XmlAttribute public Boolean latestVersion = null;
171
172 static enum FilterType {
173 ColumnCountGetFilter,
174 FilterList,
175 FirstKeyOnlyFilter,
176 InclusiveStopFilter,
177 PageFilter,
178 PrefixFilter,
179 QualifierFilter,
180 RowFilter,
181 SingleColumnValueFilter,
182 SkipFilter,
183 ValueFilter,
184 WhileMatchFilter
185 }
186
187 public FilterModel() { }
188
189 public FilterModel(Filter filter) {
190 String typeName = filter.getClass().getSimpleName();
191 FilterType type = FilterType.valueOf(typeName);
192 this.type = typeName;
193 switch (type) {
194 case ColumnCountGetFilter:
195 this.limit = ((ColumnCountGetFilter)filter).getLimit();
196 break;
197 case FilterList:
198 this.op = ((FilterList)filter).getOperator().toString();
199 this.filters = new ArrayList<FilterModel>();
200 for (Filter child: ((FilterList)filter).getFilters()) {
201 this.filters.add(new FilterModel(child));
202 }
203 break;
204 case FirstKeyOnlyFilter:
205 break;
206 case InclusiveStopFilter:
207 this.value =
208 Base64.encodeBytes(((InclusiveStopFilter)filter).getStopRowKey());
209 break;
210 case PageFilter:
211 this.value = Long.toString(((PageFilter)filter).getPageSize());
212 break;
213 case PrefixFilter:
214 this.value = Base64.encodeBytes(((PrefixFilter)filter).getPrefix());
215 break;
216 case QualifierFilter:
217 case RowFilter:
218 case ValueFilter:
219 this.op = ((CompareFilter)filter).getOperator().toString();
220 this.comparator =
221 new WritableByteArrayComparableModel(
222 ((CompareFilter)filter).getComparator());
223 break;
224 case SingleColumnValueFilter: {
225 SingleColumnValueFilter scvf = (SingleColumnValueFilter) filter;
226 this.family = Base64.encodeBytes(scvf.getFamily());
227 byte[] qualifier = scvf.getQualifier();
228 if (qualifier != null) {
229 this.qualifier = Base64.encodeBytes(qualifier);
230 }
231 this.op = scvf.getOperator().toString();
232 this.comparator =
233 new WritableByteArrayComparableModel(scvf.getComparator());
234 if (scvf.getFilterIfMissing()) {
235 this.ifMissing = true;
236 }
237 if (scvf.getLatestVersionOnly()) {
238 this.latestVersion = true;
239 }
240 } break;
241 case SkipFilter:
242 this.filters = new ArrayList<FilterModel>();
243 this.filters.add(new FilterModel(((SkipFilter)filter).getFilter()));
244 break;
245 case WhileMatchFilter:
246 this.filters = new ArrayList<FilterModel>();
247 this.filters.add(
248 new FilterModel(((WhileMatchFilter)filter).getFilter()));
249 break;
250 default:
251 throw new RuntimeException("unhandled filter type " + type);
252 }
253 }
254
255 public Filter build() {
256 Filter filter;
257 switch (FilterType.valueOf(type)) {
258 case ColumnCountGetFilter: {
259 filter = new ColumnCountGetFilter(limit);
260 } break;
261 case FilterList: {
262 List<Filter> list = new ArrayList<Filter>();
263 for (FilterModel model: filters) {
264 list.add(model.build());
265 }
266 filter = new FilterList(FilterList.Operator.valueOf(op), list);
267 } break;
268 case FirstKeyOnlyFilter: {
269 filter = new FirstKeyOnlyFilter();
270 } break;
271 case InclusiveStopFilter: {
272 filter = new InclusiveStopFilter(Base64.decode(value));
273 } break;
274 case PageFilter: {
275 filter = new PageFilter(Long.valueOf(value));
276 } break;
277 case PrefixFilter: {
278 filter = new PrefixFilter(Base64.decode(value));
279 } break;
280 case QualifierFilter: {
281 filter = new QualifierFilter(CompareOp.valueOf(op), comparator.build());
282 } break;
283 case RowFilter: {
284 filter = new RowFilter(CompareOp.valueOf(op), comparator.build());
285 } break;
286 case SingleColumnValueFilter: {
287 filter = new SingleColumnValueFilter(Base64.decode(family),
288 qualifier != null ? Base64.decode(qualifier) : null,
289 CompareOp.valueOf(op), comparator.build());
290 if (ifMissing != null) {
291 ((SingleColumnValueFilter)filter).setFilterIfMissing(ifMissing);
292 }
293 if (latestVersion != null) {
294 ((SingleColumnValueFilter)filter).setLatestVersionOnly(latestVersion);
295 }
296 } break;
297 case SkipFilter: {
298 filter = new SkipFilter(filters.get(0).build());
299 } break;
300 case ValueFilter: {
301 filter = new ValueFilter(CompareOp.valueOf(op), comparator.build());
302 } break;
303 case WhileMatchFilter: {
304 filter = new WhileMatchFilter(filters.get(0).build());
305 } break;
306 default:
307 throw new RuntimeException("unhandled filter type: " + type);
308 }
309 return filter;
310 }
311
312 }
313
314
315
316
317
318
319 public static Filter buildFilter(String s) throws Exception {
320 JSONJAXBContext context =
321 new JSONJAXBContext(JSONConfiguration.natural().build(),
322 FilterModel.class);
323 JSONUnmarshaller unmarshaller = context.createJSONUnmarshaller();
324 FilterModel model = unmarshaller.unmarshalFromJSON(new StringReader(s),
325 FilterModel.class);
326 return model.build();
327 }
328
329
330
331
332
333
334 public static String stringifyFilter(final Filter filter) throws Exception {
335 JSONJAXBContext context =
336 new JSONJAXBContext(JSONConfiguration.natural().build(),
337 FilterModel.class);
338 JSONMarshaller marshaller = context.createJSONMarshaller();
339 StringWriter writer = new StringWriter();
340 marshaller.marshallToJSON(new FilterModel(filter), writer);
341 return writer.toString();
342 }
343
344
345
346
347
348 public static ScannerModel fromScan(Scan scan) throws Exception {
349 ScannerModel model = new ScannerModel();
350 model.setStartRow(scan.getStartRow());
351 model.setEndRow(scan.getStopRow());
352 byte[][] families = scan.getFamilies();
353 if (families != null) {
354 for (byte[] column: families) {
355 model.addColumn(column);
356 }
357 }
358 model.setStartTime(scan.getTimeRange().getMin());
359 model.setEndTime(scan.getTimeRange().getMax());
360 int caching = scan.getCaching();
361 if (caching > 0) {
362 model.setBatch(caching);
363 }
364 int maxVersions = scan.getMaxVersions();
365 if (maxVersions > 0) {
366 model.setMaxVersions(maxVersions);
367 }
368 Filter filter = scan.getFilter();
369 if (filter != null) {
370 model.setFilter(stringifyFilter(filter));
371 }
372 return model;
373 }
374
375
376
377
378 public ScannerModel() {}
379
380
381
382
383
384
385
386
387
388
389
390
391 public ScannerModel(byte[] startRow, byte[] endRow, List<byte[]> columns,
392 int batch, long endTime, int maxVersions, String filter) {
393 super();
394 this.startRow = startRow;
395 this.endRow = endRow;
396 this.columns = columns;
397 this.batch = batch;
398 this.endTime = endTime;
399 this.maxVersions = maxVersions;
400 this.filter = filter;
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415 public ScannerModel(byte[] startRow, byte[] endRow, List<byte[]> columns,
416 int batch, long startTime, long endTime, String filter) {
417 super();
418 this.startRow = startRow;
419 this.endRow = endRow;
420 this.columns = columns;
421 this.batch = batch;
422 this.startTime = startTime;
423 this.endTime = endTime;
424 this.filter = filter;
425 }
426
427
428
429
430
431 public void addColumn(byte[] column) {
432 columns.add(column);
433 }
434
435
436
437
438 public boolean hasStartRow() {
439 return !Bytes.equals(startRow, HConstants.EMPTY_START_ROW);
440 }
441
442
443
444
445 @XmlAttribute
446 public byte[] getStartRow() {
447 return startRow;
448 }
449
450
451
452
453 public boolean hasEndRow() {
454 return !Bytes.equals(endRow, HConstants.EMPTY_END_ROW);
455 }
456
457
458
459
460 @XmlAttribute
461 public byte[] getEndRow() {
462 return endRow;
463 }
464
465
466
467
468 @XmlElement(name="column")
469 public List<byte[]> getColumns() {
470 return columns;
471 }
472
473
474
475
476 @XmlAttribute
477 public int getBatch() {
478 return batch;
479 }
480
481
482
483
484 @XmlAttribute
485 public long getStartTime() {
486 return startTime;
487 }
488
489
490
491
492 @XmlAttribute
493 public long getEndTime() {
494 return endTime;
495 }
496
497
498
499
500 @XmlAttribute
501 public int getMaxVersions() {
502 return maxVersions;
503 }
504
505
506
507
508 @XmlElement
509 public String getFilter() {
510 return filter;
511 }
512
513
514
515
516 public void setStartRow(byte[] startRow) {
517 this.startRow = startRow;
518 }
519
520
521
522
523 public void setEndRow(byte[] endRow) {
524 this.endRow = endRow;
525 }
526
527
528
529
530 public void setColumns(List<byte[]> columns) {
531 this.columns = columns;
532 }
533
534
535
536
537 public void setBatch(int batch) {
538 this.batch = batch;
539 }
540
541
542
543
544 public void setMaxVersions(int maxVersions) {
545 this.maxVersions = maxVersions;
546 }
547
548
549
550
551 public void setStartTime(long startTime) {
552 this.startTime = startTime;
553 }
554
555
556
557
558 public void setEndTime(long endTime) {
559 this.endTime = endTime;
560 }
561
562
563
564
565 public void setFilter(String filter) {
566 this.filter = filter;
567 }
568
569 @Override
570 public byte[] createProtobufOutput() {
571 Scanner.Builder builder = Scanner.newBuilder();
572 if (!Bytes.equals(startRow, HConstants.EMPTY_START_ROW)) {
573 builder.setStartRow(ByteString.copyFrom(startRow));
574 }
575 if (!Bytes.equals(endRow, HConstants.EMPTY_START_ROW)) {
576 builder.setEndRow(ByteString.copyFrom(endRow));
577 }
578 for (byte[] column: columns) {
579 builder.addColumns(ByteString.copyFrom(column));
580 }
581 builder.setBatch(batch);
582 if (startTime != 0) {
583 builder.setStartTime(startTime);
584 }
585 if (endTime != 0) {
586 builder.setEndTime(endTime);
587 }
588 builder.setBatch(getBatch());
589 builder.setMaxVersions(maxVersions);
590 if (filter != null) {
591 builder.setFilter(filter);
592 }
593 return builder.build().toByteArray();
594 }
595
596 @Override
597 public ProtobufMessageHandler getObjectFromMessage(byte[] message)
598 throws IOException {
599 Scanner.Builder builder = Scanner.newBuilder();
600 builder.mergeFrom(message);
601 if (builder.hasStartRow()) {
602 startRow = builder.getStartRow().toByteArray();
603 }
604 if (builder.hasEndRow()) {
605 endRow = builder.getEndRow().toByteArray();
606 }
607 for (ByteString column: builder.getColumnsList()) {
608 addColumn(column.toByteArray());
609 }
610 if (builder.hasBatch()) {
611 batch = builder.getBatch();
612 }
613 if (builder.hasStartTime()) {
614 startTime = builder.getStartTime();
615 }
616 if (builder.hasEndTime()) {
617 endTime = builder.getEndTime();
618 }
619 if (builder.hasMaxVersions()) {
620 maxVersions = builder.getMaxVersions();
621 }
622 if (builder.hasFilter()) {
623 filter = builder.getFilter();
624 }
625 return this;
626 }
627
628 }