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.rest.model; 019 020import com.fasterxml.jackson.annotation.JsonInclude; 021import java.io.IOException; 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.Base64; 025import java.util.List; 026import java.util.Map; 027import java.util.NavigableSet; 028import javax.xml.bind.annotation.XmlAttribute; 029import javax.xml.bind.annotation.XmlElement; 030import javax.xml.bind.annotation.XmlRootElement; 031import org.apache.hadoop.hbase.CompareOperator; 032import org.apache.hadoop.hbase.HConstants; 033import org.apache.hadoop.hbase.client.Scan; 034import org.apache.hadoop.hbase.filter.BinaryComparator; 035import org.apache.hadoop.hbase.filter.BinaryPrefixComparator; 036import org.apache.hadoop.hbase.filter.BitComparator; 037import org.apache.hadoop.hbase.filter.ByteArrayComparable; 038import org.apache.hadoop.hbase.filter.ColumnCountGetFilter; 039import org.apache.hadoop.hbase.filter.ColumnPaginationFilter; 040import org.apache.hadoop.hbase.filter.ColumnPrefixFilter; 041import org.apache.hadoop.hbase.filter.ColumnRangeFilter; 042import org.apache.hadoop.hbase.filter.CompareFilter; 043import org.apache.hadoop.hbase.filter.DependentColumnFilter; 044import org.apache.hadoop.hbase.filter.FamilyFilter; 045import org.apache.hadoop.hbase.filter.Filter; 046import org.apache.hadoop.hbase.filter.FilterList; 047import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter; 048import org.apache.hadoop.hbase.filter.InclusiveStopFilter; 049import org.apache.hadoop.hbase.filter.KeyOnlyFilter; 050import org.apache.hadoop.hbase.filter.MultiRowRangeFilter; 051import org.apache.hadoop.hbase.filter.MultiRowRangeFilter.RowRange; 052import org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter; 053import org.apache.hadoop.hbase.filter.NullComparator; 054import org.apache.hadoop.hbase.filter.PageFilter; 055import org.apache.hadoop.hbase.filter.PrefixFilter; 056import org.apache.hadoop.hbase.filter.QualifierFilter; 057import org.apache.hadoop.hbase.filter.RandomRowFilter; 058import org.apache.hadoop.hbase.filter.RegexStringComparator; 059import org.apache.hadoop.hbase.filter.RowFilter; 060import org.apache.hadoop.hbase.filter.SingleColumnValueExcludeFilter; 061import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; 062import org.apache.hadoop.hbase.filter.SkipFilter; 063import org.apache.hadoop.hbase.filter.SubstringComparator; 064import org.apache.hadoop.hbase.filter.TimestampsFilter; 065import org.apache.hadoop.hbase.filter.ValueFilter; 066import org.apache.hadoop.hbase.filter.WhileMatchFilter; 067import org.apache.hadoop.hbase.rest.ProtobufMessageHandler; 068import org.apache.hadoop.hbase.security.visibility.Authorizations; 069import org.apache.hadoop.hbase.util.Bytes; 070import org.apache.yetus.audience.InterfaceAudience; 071 072import org.apache.hbase.thirdparty.com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; 073import org.apache.hbase.thirdparty.com.google.protobuf.ByteString; 074import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 075import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType; 076 077import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 078import org.apache.hadoop.hbase.shaded.rest.protobuf.generated.ScannerMessage.Scanner; 079 080/** 081 * A representation of Scanner parameters. 082 * 083 * <pre> 084 * <complexType name="Scanner"> 085 * <sequence> 086 * <element name="column" type="base64Binary" minOccurs="0" maxOccurs="unbounded"/> 087 * <element name="filter" type="string" minOccurs="0" maxOccurs="1"></element> 088 * </sequence> 089 * <attribute name="startRow" type="base64Binary"></attribute> 090 * <attribute name="endRow" type="base64Binary"></attribute> 091 * <attribute name="batch" type="int"></attribute> 092 * <attribute name="caching" type="int"></attribute> 093 * <attribute name="startTime" type="int"></attribute> 094 * <attribute name="endTime" type="int"></attribute> 095 * <attribute name="maxVersions" type="int"></attribute> 096 * </complexType> 097 * </pre> 098 */ 099@XmlRootElement(name = "Scanner") 100@JsonInclude(JsonInclude.Include.NON_NULL) 101@InterfaceAudience.Private 102public class ScannerModel implements ProtobufMessageHandler, Serializable { 103 104 private static final long serialVersionUID = 1L; 105 106 private byte[] startRow = HConstants.EMPTY_START_ROW; 107 private byte[] endRow = HConstants.EMPTY_END_ROW; 108 private List<byte[]> columns = new ArrayList<>(); 109 private int batch = Integer.MAX_VALUE; 110 private long startTime = 0; 111 private long endTime = Long.MAX_VALUE; 112 private String filter = null; 113 private int maxVersions = Integer.MAX_VALUE; 114 private int caching = -1; 115 private List<String> labels = new ArrayList<>(); 116 private boolean cacheBlocks = true; 117 private int limit = -1; 118 119 /** 120 * Implement lazily-instantiated singleton as per recipe here: 121 * http://literatejava.com/jvm/fastest-threadsafe-singleton-jvm/ 122 */ 123 private static class JaxbJsonProviderHolder { 124 static final JacksonJaxbJsonProvider INSTANCE = new JacksonJaxbJsonProvider(); 125 } 126 127 @XmlRootElement 128 static class FilterModel { 129 130 @XmlRootElement 131 static class ByteArrayComparableModel { 132 @XmlAttribute 133 public String type; 134 @XmlAttribute 135 public String value; 136 @XmlAttribute 137 public String op; 138 139 static enum ComparatorType { 140 BinaryComparator, 141 BinaryPrefixComparator, 142 BitComparator, 143 NullComparator, 144 RegexStringComparator, 145 SubstringComparator 146 } 147 148 public ByteArrayComparableModel() { 149 } 150 151 public ByteArrayComparableModel(ByteArrayComparable comparator) { 152 String typeName = comparator.getClass().getSimpleName(); 153 ComparatorType type = ComparatorType.valueOf(typeName); 154 this.type = typeName; 155 switch (type) { 156 case BinaryComparator: 157 case BinaryPrefixComparator: 158 this.value = Bytes.toString(Base64.getEncoder().encode(comparator.getValue())); 159 break; 160 case BitComparator: 161 this.value = Bytes.toString(Base64.getEncoder().encode(comparator.getValue())); 162 this.op = ((BitComparator) comparator).getOperator().toString(); 163 break; 164 case NullComparator: 165 break; 166 case RegexStringComparator: 167 case SubstringComparator: 168 this.value = Bytes.toString(comparator.getValue()); 169 break; 170 default: 171 throw new RuntimeException("unhandled filter type: " + type); 172 } 173 } 174 175 public ByteArrayComparable build() { 176 ByteArrayComparable comparator; 177 switch (ComparatorType.valueOf(type)) { 178 case BinaryComparator: 179 comparator = new BinaryComparator(Base64.getDecoder().decode(value)); 180 break; 181 case BinaryPrefixComparator: 182 comparator = new BinaryPrefixComparator(Base64.getDecoder().decode(value)); 183 break; 184 case BitComparator: 185 comparator = new BitComparator(Base64.getDecoder().decode(value), 186 BitComparator.BitwiseOp.valueOf(op)); 187 break; 188 case NullComparator: 189 comparator = new NullComparator(); 190 break; 191 case RegexStringComparator: 192 comparator = new RegexStringComparator(value); 193 break; 194 case SubstringComparator: 195 comparator = new SubstringComparator(value); 196 break; 197 default: 198 throw new RuntimeException("unhandled comparator type: " + type); 199 } 200 return comparator; 201 } 202 203 } 204 205 // A grab bag of fields, would have been a union if this were C. 206 // These are null by default and will only be serialized if set (non null). 207 @XmlAttribute 208 public String type; 209 @XmlAttribute 210 public String op; 211 @XmlElement 212 ByteArrayComparableModel comparator; 213 @XmlAttribute 214 public String value; 215 @XmlElement 216 public List<FilterModel> filters; 217 @XmlAttribute 218 public Integer limit; 219 @XmlAttribute 220 public Integer offset; 221 @XmlAttribute 222 public String family; 223 @XmlAttribute 224 public String qualifier; 225 @XmlAttribute 226 public Boolean ifMissing; 227 @XmlAttribute 228 public Boolean latestVersion; 229 @XmlAttribute 230 public String minColumn; 231 @XmlAttribute 232 public Boolean minColumnInclusive; 233 @XmlAttribute 234 public String maxColumn; 235 @XmlAttribute 236 public Boolean maxColumnInclusive; 237 @XmlAttribute 238 public Boolean dropDependentColumn; 239 @XmlAttribute 240 public Float chance; 241 @XmlElement 242 public List<String> prefixes; 243 @XmlElement 244 private List<RowRange> ranges; 245 @XmlElement 246 public List<Long> timestamps; 247 248 static enum FilterType { 249 ColumnCountGetFilter, 250 ColumnPaginationFilter, 251 ColumnPrefixFilter, 252 ColumnRangeFilter, 253 DependentColumnFilter, 254 FamilyFilter, 255 FilterList, 256 FirstKeyOnlyFilter, 257 InclusiveStopFilter, 258 KeyOnlyFilter, 259 MultipleColumnPrefixFilter, 260 MultiRowRangeFilter, 261 PageFilter, 262 PrefixFilter, 263 QualifierFilter, 264 RandomRowFilter, 265 RowFilter, 266 SingleColumnValueExcludeFilter, 267 SingleColumnValueFilter, 268 SkipFilter, 269 TimestampsFilter, 270 ValueFilter, 271 WhileMatchFilter 272 } 273 274 public FilterModel() { 275 } 276 277 public FilterModel(Filter filter) { 278 String typeName = filter.getClass().getSimpleName(); 279 FilterType type = FilterType.valueOf(typeName); 280 this.type = typeName; 281 switch (type) { 282 case ColumnCountGetFilter: 283 this.limit = ((ColumnCountGetFilter) filter).getLimit(); 284 break; 285 case ColumnPaginationFilter: 286 this.limit = ((ColumnPaginationFilter) filter).getLimit(); 287 this.offset = ((ColumnPaginationFilter) filter).getOffset(); 288 break; 289 case ColumnPrefixFilter: 290 byte[] src = ((ColumnPrefixFilter) filter).getPrefix(); 291 this.value = Bytes.toString(Base64.getEncoder().encode(src)); 292 break; 293 case ColumnRangeFilter: 294 ColumnRangeFilter crf = (ColumnRangeFilter) filter; 295 this.minColumn = Bytes.toString(Base64.getEncoder().encode(crf.getMinColumn())); 296 this.minColumnInclusive = crf.getMinColumnInclusive(); 297 this.maxColumn = Bytes.toString(Base64.getEncoder().encode(crf.getMaxColumn())); 298 this.maxColumnInclusive = crf.getMaxColumnInclusive(); 299 break; 300 case DependentColumnFilter: { 301 DependentColumnFilter dcf = (DependentColumnFilter) filter; 302 this.family = Bytes.toString(Base64.getEncoder().encode(dcf.getFamily())); 303 byte[] qualifier = dcf.getQualifier(); 304 if (qualifier != null) { 305 this.qualifier = Bytes.toString(Base64.getEncoder().encode(qualifier)); 306 } 307 this.op = dcf.getCompareOperator().toString(); 308 this.comparator = new ByteArrayComparableModel(dcf.getComparator()); 309 this.dropDependentColumn = dcf.dropDependentColumn(); 310 } 311 break; 312 case FilterList: 313 this.op = ((FilterList) filter).getOperator().toString(); 314 this.filters = new ArrayList<>(); 315 for (Filter child : ((FilterList) filter).getFilters()) { 316 this.filters.add(new FilterModel(child)); 317 } 318 break; 319 case FirstKeyOnlyFilter: 320 case KeyOnlyFilter: 321 break; 322 case InclusiveStopFilter: 323 this.value = Bytes 324 .toString(Base64.getEncoder().encode(((InclusiveStopFilter) filter).getStopRowKey())); 325 break; 326 case MultipleColumnPrefixFilter: 327 this.prefixes = new ArrayList<>(); 328 for (byte[] prefix : ((MultipleColumnPrefixFilter) filter).getPrefix()) { 329 this.prefixes.add(Bytes.toString(Base64.getEncoder().encode(prefix))); 330 } 331 break; 332 case MultiRowRangeFilter: 333 this.ranges = new ArrayList<>(); 334 for (RowRange range : ((MultiRowRangeFilter) filter).getRowRanges()) { 335 this.ranges.add(new RowRange(range.getStartRow(), range.isStartRowInclusive(), 336 range.getStopRow(), range.isStopRowInclusive())); 337 } 338 break; 339 case PageFilter: 340 this.value = Long.toString(((PageFilter) filter).getPageSize()); 341 break; 342 case PrefixFilter: 343 this.value = 344 Bytes.toString(Base64.getEncoder().encode(((PrefixFilter) filter).getPrefix())); 345 break; 346 case FamilyFilter: 347 case QualifierFilter: 348 case RowFilter: 349 case ValueFilter: 350 this.op = ((CompareFilter) filter).getCompareOperator().toString(); 351 this.comparator = new ByteArrayComparableModel(((CompareFilter) filter).getComparator()); 352 break; 353 case RandomRowFilter: 354 this.chance = ((RandomRowFilter) filter).getChance(); 355 break; 356 case SingleColumnValueExcludeFilter: 357 case SingleColumnValueFilter: { 358 SingleColumnValueFilter scvf = (SingleColumnValueFilter) filter; 359 this.family = Bytes.toString(Base64.getEncoder().encode(scvf.getFamily())); 360 byte[] qualifier = scvf.getQualifier(); 361 if (qualifier != null) { 362 this.qualifier = Bytes.toString(Base64.getEncoder().encode(qualifier)); 363 } 364 this.op = scvf.getCompareOperator().toString(); 365 this.comparator = new ByteArrayComparableModel(scvf.getComparator()); 366 if (scvf.getFilterIfMissing()) { 367 this.ifMissing = true; 368 } 369 if (scvf.getLatestVersionOnly()) { 370 this.latestVersion = true; 371 } 372 } 373 break; 374 case SkipFilter: 375 this.filters = new ArrayList<>(); 376 this.filters.add(new FilterModel(((SkipFilter) filter).getFilter())); 377 break; 378 case TimestampsFilter: 379 this.timestamps = ((TimestampsFilter) filter).getTimestamps(); 380 break; 381 case WhileMatchFilter: 382 this.filters = new ArrayList<>(); 383 this.filters.add(new FilterModel(((WhileMatchFilter) filter).getFilter())); 384 break; 385 default: 386 throw new RuntimeException("unhandled filter type " + type); 387 } 388 } 389 390 public Filter build() { 391 Filter filter; 392 switch (FilterType.valueOf(type)) { 393 case ColumnCountGetFilter: 394 filter = new ColumnCountGetFilter(limit); 395 break; 396 case ColumnPaginationFilter: 397 filter = new ColumnPaginationFilter(limit, offset); 398 break; 399 case ColumnPrefixFilter: 400 filter = new ColumnPrefixFilter(Base64.getDecoder().decode(value)); 401 break; 402 case ColumnRangeFilter: 403 filter = new ColumnRangeFilter(Base64.getDecoder().decode(minColumn), minColumnInclusive, 404 Base64.getDecoder().decode(maxColumn), maxColumnInclusive); 405 break; 406 case DependentColumnFilter: 407 filter = new DependentColumnFilter(Base64.getDecoder().decode(family), 408 qualifier != null ? Base64.getDecoder().decode(qualifier) : null, dropDependentColumn, 409 CompareOperator.valueOf(op), comparator.build()); 410 break; 411 case FamilyFilter: 412 filter = new FamilyFilter(CompareOperator.valueOf(op), comparator.build()); 413 break; 414 case FilterList: { 415 List<Filter> list = new ArrayList<>(filters.size()); 416 for (FilterModel model : filters) { 417 list.add(model.build()); 418 } 419 filter = new FilterList(FilterList.Operator.valueOf(op), list); 420 } 421 break; 422 case FirstKeyOnlyFilter: 423 filter = new FirstKeyOnlyFilter(); 424 break; 425 case InclusiveStopFilter: 426 filter = new InclusiveStopFilter(Base64.getDecoder().decode(value)); 427 break; 428 case KeyOnlyFilter: 429 filter = new KeyOnlyFilter(); 430 break; 431 case MultipleColumnPrefixFilter: { 432 byte[][] values = new byte[prefixes.size()][]; 433 for (int i = 0; i < prefixes.size(); i++) { 434 values[i] = Base64.getDecoder().decode(prefixes.get(i)); 435 } 436 filter = new MultipleColumnPrefixFilter(values); 437 } 438 break; 439 case MultiRowRangeFilter: { 440 filter = new MultiRowRangeFilter(ranges); 441 } 442 break; 443 case PageFilter: 444 filter = new PageFilter(Long.parseLong(value)); 445 break; 446 case PrefixFilter: 447 filter = new PrefixFilter(Base64.getDecoder().decode(value)); 448 break; 449 case QualifierFilter: 450 filter = new QualifierFilter(CompareOperator.valueOf(op), comparator.build()); 451 break; 452 case RandomRowFilter: 453 filter = new RandomRowFilter(chance); 454 break; 455 case RowFilter: 456 filter = new RowFilter(CompareOperator.valueOf(op), comparator.build()); 457 break; 458 case SingleColumnValueFilter: 459 filter = new SingleColumnValueFilter(Base64.getDecoder().decode(family), 460 qualifier != null ? Base64.getDecoder().decode(qualifier) : null, 461 CompareOperator.valueOf(op), comparator.build()); 462 if (ifMissing != null) { 463 ((SingleColumnValueFilter) filter).setFilterIfMissing(ifMissing); 464 } 465 if (latestVersion != null) { 466 ((SingleColumnValueFilter) filter).setLatestVersionOnly(latestVersion); 467 } 468 break; 469 case SingleColumnValueExcludeFilter: 470 filter = new SingleColumnValueExcludeFilter(Base64.getDecoder().decode(family), 471 qualifier != null ? Base64.getDecoder().decode(qualifier) : null, 472 CompareOperator.valueOf(op), comparator.build()); 473 if (ifMissing != null) { 474 ((SingleColumnValueExcludeFilter) filter).setFilterIfMissing(ifMissing); 475 } 476 if (latestVersion != null) { 477 ((SingleColumnValueExcludeFilter) filter).setLatestVersionOnly(latestVersion); 478 } 479 break; 480 case SkipFilter: 481 filter = new SkipFilter(filters.get(0).build()); 482 break; 483 case TimestampsFilter: 484 filter = new TimestampsFilter(timestamps); 485 break; 486 case ValueFilter: 487 filter = new ValueFilter(CompareOperator.valueOf(op), comparator.build()); 488 break; 489 case WhileMatchFilter: 490 filter = new WhileMatchFilter(filters.get(0).build()); 491 break; 492 default: 493 throw new RuntimeException("unhandled filter type: " + type); 494 } 495 return filter; 496 } 497 498 } 499 500 /** 501 * Get the <code>JacksonJaxbJsonProvider</code> instance; 502 * @return A <code>JacksonJaxbJsonProvider</code>. 503 */ 504 private static JacksonJaxbJsonProvider getJasonProvider() { 505 return JaxbJsonProviderHolder.INSTANCE; 506 } 507 508 /** 509 * @param s the JSON representation of the filter 510 * @return the filter 511 */ 512 public static Filter buildFilter(String s) throws Exception { 513 FilterModel model = 514 getJasonProvider().locateMapper(FilterModel.class, MediaType.APPLICATION_JSON_TYPE) 515 .readValue(s, FilterModel.class); 516 return model.build(); 517 } 518 519 /** 520 * @param filter the filter 521 * @return the JSON representation of the filter 522 */ 523 public static String stringifyFilter(final Filter filter) throws Exception { 524 return getJasonProvider().locateMapper(FilterModel.class, MediaType.APPLICATION_JSON_TYPE) 525 .writeValueAsString(new FilterModel(filter)); 526 } 527 528 private static final byte[] COLUMN_DIVIDER = Bytes.toBytes(":"); 529 530 /** 531 * @param scan the scan specification 532 */ 533 public static ScannerModel fromScan(Scan scan) throws Exception { 534 ScannerModel model = new ScannerModel(); 535 model.setStartRow(scan.getStartRow()); 536 model.setEndRow(scan.getStopRow()); 537 Map<byte[], NavigableSet<byte[]>> families = scan.getFamilyMap(); 538 if (families != null) { 539 for (Map.Entry<byte[], NavigableSet<byte[]>> entry : families.entrySet()) { 540 if (entry.getValue() != null) { 541 for (byte[] qualifier : entry.getValue()) { 542 model.addColumn(Bytes.add(entry.getKey(), COLUMN_DIVIDER, qualifier)); 543 } 544 } else { 545 model.addColumn(entry.getKey()); 546 } 547 } 548 } 549 model.setStartTime(scan.getTimeRange().getMin()); 550 model.setEndTime(scan.getTimeRange().getMax()); 551 int caching = scan.getCaching(); 552 if (caching > 0) { 553 model.setCaching(caching); 554 } 555 int batch = scan.getBatch(); 556 if (batch > 0) { 557 model.setBatch(batch); 558 } 559 int maxVersions = scan.getMaxVersions(); 560 if (maxVersions > 0) { 561 model.setMaxVersions(maxVersions); 562 } 563 if (scan.getLimit() > 0) { 564 model.setLimit(scan.getLimit()); 565 } 566 Filter filter = scan.getFilter(); 567 if (filter != null) { 568 model.setFilter(stringifyFilter(filter)); 569 } 570 // Add the visbility labels if found in the attributes 571 Authorizations authorizations = scan.getAuthorizations(); 572 if (authorizations != null) { 573 List<String> labels = authorizations.getLabels(); 574 for (String label : labels) { 575 model.addLabel(label); 576 } 577 } 578 return model; 579 } 580 581 /** 582 * Default constructor 583 */ 584 public ScannerModel() { 585 } 586 587 /** 588 * Constructor 589 * @param startRow the start key of the row-range 590 * @param endRow the end key of the row-range 591 * @param columns the columns to scan 592 * @param batch the number of values to return in batch 593 * @param caching the number of rows that the scanner will fetch at once 594 * @param endTime the upper bound on timestamps of values of interest 595 * @param maxVersions the maximum number of versions to return 596 * @param filter a filter specification (values with timestamps later than this are excluded) 597 */ 598 public ScannerModel(byte[] startRow, byte[] endRow, List<byte[]> columns, int batch, int caching, 599 long endTime, int maxVersions, String filter) { 600 super(); 601 this.startRow = startRow; 602 this.endRow = endRow; 603 this.columns = columns; 604 this.batch = batch; 605 this.caching = caching; 606 this.endTime = endTime; 607 this.maxVersions = maxVersions; 608 this.filter = filter; 609 } 610 611 /** 612 * Constructor 613 * @param startRow the start key of the row-range 614 * @param endRow the end key of the row-range 615 * @param columns the columns to scan 616 * @param batch the number of values to return in batch 617 * @param caching the number of rows that the scanner will fetch at once 618 * @param startTime the lower bound on timestamps of values of interest (values with timestamps 619 * earlier than this are excluded) 620 * @param endTime the upper bound on timestamps of values of interest (values with timestamps 621 * later than this are excluded) 622 * @param filter a filter specification 623 */ 624 public ScannerModel(byte[] startRow, byte[] endRow, List<byte[]> columns, int batch, int caching, 625 long startTime, long endTime, String filter) { 626 super(); 627 this.startRow = startRow; 628 this.endRow = endRow; 629 this.columns = columns; 630 this.batch = batch; 631 this.caching = caching; 632 this.startTime = startTime; 633 this.endTime = endTime; 634 this.filter = filter; 635 } 636 637 /** 638 * Add a column to the column set 639 * @param column the column name, as <column>(:<qualifier>)? 640 */ 641 public void addColumn(byte[] column) { 642 columns.add(column); 643 } 644 645 /** 646 * Add a visibility label to the scan 647 */ 648 public void addLabel(String label) { 649 labels.add(label); 650 } 651 652 /** Returns true if a start row was specified */ 653 public boolean hasStartRow() { 654 return !Bytes.equals(startRow, HConstants.EMPTY_START_ROW); 655 } 656 657 /** Returns start row */ 658 @XmlAttribute 659 public byte[] getStartRow() { 660 return startRow; 661 } 662 663 /** Returns true if an end row was specified */ 664 public boolean hasEndRow() { 665 return !Bytes.equals(endRow, HConstants.EMPTY_END_ROW); 666 } 667 668 /** Returns end row */ 669 @XmlAttribute 670 public byte[] getEndRow() { 671 return endRow; 672 } 673 674 /** Returns list of columns of interest in column:qualifier format, or empty for all */ 675 @XmlElement(name = "column") 676 public List<byte[]> getColumns() { 677 return columns; 678 } 679 680 @XmlElement(name = "labels") 681 public List<String> getLabels() { 682 return labels; 683 } 684 685 /** Returns the number of cells to return in batch */ 686 @XmlAttribute 687 public int getBatch() { 688 return batch; 689 } 690 691 /** Returns the number of rows that the scanner to fetch at once */ 692 @XmlAttribute 693 public int getCaching() { 694 return caching; 695 } 696 697 /** Returns the limit specification */ 698 @XmlAttribute 699 public int getLimit() { 700 return limit; 701 } 702 703 /** Returns true if HFile blocks should be cached on the servers for this scan, false otherwise */ 704 @XmlAttribute 705 public boolean getCacheBlocks() { 706 return cacheBlocks; 707 } 708 709 /** Returns the lower bound on timestamps of items of interest */ 710 @XmlAttribute 711 public long getStartTime() { 712 return startTime; 713 } 714 715 /** Returns the upper bound on timestamps of items of interest */ 716 @XmlAttribute 717 public long getEndTime() { 718 return endTime; 719 } 720 721 /** Returns maximum number of versions to return */ 722 @XmlAttribute 723 public int getMaxVersions() { 724 return maxVersions; 725 } 726 727 /** Returns the filter specification */ 728 @XmlElement 729 public String getFilter() { 730 return filter; 731 } 732 733 /** 734 * @param startRow start row 735 */ 736 public void setStartRow(byte[] startRow) { 737 this.startRow = startRow; 738 } 739 740 /** 741 * @param endRow end row 742 */ 743 public void setEndRow(byte[] endRow) { 744 this.endRow = endRow; 745 } 746 747 /** 748 * @param columns list of columns of interest in column:qualifier format, or empty for all 749 */ 750 public void setColumns(List<byte[]> columns) { 751 this.columns = columns; 752 } 753 754 /** 755 * @param batch the number of cells to return in batch 756 */ 757 public void setBatch(int batch) { 758 this.batch = batch; 759 } 760 761 /** 762 * @param caching the number of rows to fetch at once 763 */ 764 public void setCaching(int caching) { 765 this.caching = caching; 766 } 767 768 /** 769 * @param value true if HFile blocks should be cached on the servers for this scan, false 770 * otherwise 771 */ 772 public void setCacheBlocks(boolean value) { 773 this.cacheBlocks = value; 774 } 775 776 /** 777 * @param limit the number of rows can fetch of each scanner at lifetime 778 */ 779 public void setLimit(int limit) { 780 this.limit = limit; 781 } 782 783 /** 784 * @param maxVersions maximum number of versions to return 785 */ 786 public void setMaxVersions(int maxVersions) { 787 this.maxVersions = maxVersions; 788 } 789 790 /** 791 * @param startTime the lower bound on timestamps of values of interest 792 */ 793 public void setStartTime(long startTime) { 794 this.startTime = startTime; 795 } 796 797 /** 798 * @param endTime the upper bound on timestamps of values of interest 799 */ 800 public void setEndTime(long endTime) { 801 this.endTime = endTime; 802 } 803 804 /** 805 * @param filter the filter specification 806 */ 807 public void setFilter(String filter) { 808 this.filter = filter; 809 } 810 811 @Override 812 public byte[] createProtobufOutput() { 813 Scanner.Builder builder = Scanner.newBuilder(); 814 if (!Bytes.equals(startRow, HConstants.EMPTY_START_ROW)) { 815 builder.setStartRow(UnsafeByteOperations.unsafeWrap(startRow)); 816 } 817 if (!Bytes.equals(endRow, HConstants.EMPTY_START_ROW)) { 818 builder.setEndRow(UnsafeByteOperations.unsafeWrap(endRow)); 819 } 820 for (byte[] column : columns) { 821 builder.addColumns(UnsafeByteOperations.unsafeWrap(column)); 822 } 823 if (startTime != 0) { 824 builder.setStartTime(startTime); 825 } 826 if (endTime != 0) { 827 builder.setEndTime(endTime); 828 } 829 builder.setBatch(getBatch()); 830 if (caching > 0) { 831 builder.setCaching(caching); 832 } 833 if (limit > 0) { 834 builder.setLimit(limit); 835 } 836 builder.setMaxVersions(maxVersions); 837 if (filter != null) { 838 builder.setFilter(filter); 839 } 840 if (labels != null && labels.size() > 0) { 841 for (String label : labels) 842 builder.addLabels(label); 843 } 844 builder.setCacheBlocks(cacheBlocks); 845 return builder.build().toByteArray(); 846 } 847 848 @Override 849 public ProtobufMessageHandler getObjectFromMessage(byte[] message) throws IOException { 850 Scanner.Builder builder = Scanner.newBuilder(); 851 ProtobufUtil.mergeFrom(builder, message); 852 if (builder.hasStartRow()) { 853 startRow = builder.getStartRow().toByteArray(); 854 } 855 if (builder.hasEndRow()) { 856 endRow = builder.getEndRow().toByteArray(); 857 } 858 for (ByteString column : builder.getColumnsList()) { 859 addColumn(column.toByteArray()); 860 } 861 if (builder.hasBatch()) { 862 batch = builder.getBatch(); 863 } 864 if (builder.hasCaching()) { 865 caching = builder.getCaching(); 866 } 867 if (builder.hasLimit()) { 868 limit = builder.getLimit(); 869 } 870 if (builder.hasStartTime()) { 871 startTime = builder.getStartTime(); 872 } 873 if (builder.hasEndTime()) { 874 endTime = builder.getEndTime(); 875 } 876 if (builder.hasMaxVersions()) { 877 maxVersions = builder.getMaxVersions(); 878 } 879 if (builder.hasFilter()) { 880 filter = builder.getFilter(); 881 } 882 if (builder.getLabelsList() != null) { 883 List<String> labels = builder.getLabelsList(); 884 for (String label : labels) { 885 addLabel(label); 886 } 887 } 888 if (builder.hasCacheBlocks()) { 889 this.cacheBlocks = builder.getCacheBlocks(); 890 } 891 return this; 892 } 893 894}