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