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 n 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 n 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 n 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 /** 653 * @return true if a start row was specified 654 */ 655 public boolean hasStartRow() { 656 return !Bytes.equals(startRow, HConstants.EMPTY_START_ROW); 657 } 658 659 /** 660 * @return start row 661 */ 662 @XmlAttribute 663 public byte[] getStartRow() { 664 return startRow; 665 } 666 667 /** 668 * @return true if an end row was specified 669 */ 670 public boolean hasEndRow() { 671 return !Bytes.equals(endRow, HConstants.EMPTY_END_ROW); 672 } 673 674 /** 675 * @return end row 676 */ 677 @XmlAttribute 678 public byte[] getEndRow() { 679 return endRow; 680 } 681 682 /** 683 * @return list of columns of interest in column:qualifier format, or empty for all 684 */ 685 @XmlElement(name = "column") 686 public List<byte[]> getColumns() { 687 return columns; 688 } 689 690 @XmlElement(name = "labels") 691 public List<String> getLabels() { 692 return labels; 693 } 694 695 /** 696 * @return the number of cells to return in batch 697 */ 698 @XmlAttribute 699 public int getBatch() { 700 return batch; 701 } 702 703 /** 704 * @return the number of rows that the scanner to fetch at once 705 */ 706 @XmlAttribute 707 public int getCaching() { 708 return caching; 709 } 710 711 /** 712 * @return the limit specification 713 */ 714 @XmlAttribute 715 public int getLimit() { 716 return limit; 717 } 718 719 /** 720 * @return true if HFile blocks should be cached on the servers for this scan, false otherwise 721 */ 722 @XmlAttribute 723 public boolean getCacheBlocks() { 724 return cacheBlocks; 725 } 726 727 /** 728 * @return the lower bound on timestamps of items of interest 729 */ 730 @XmlAttribute 731 public long getStartTime() { 732 return startTime; 733 } 734 735 /** 736 * @return the upper bound on timestamps of items of interest 737 */ 738 @XmlAttribute 739 public long getEndTime() { 740 return endTime; 741 } 742 743 /** 744 * @return maximum number of versions to return 745 */ 746 @XmlAttribute 747 public int getMaxVersions() { 748 return maxVersions; 749 } 750 751 /** 752 * @return the filter specification 753 */ 754 @XmlElement 755 public String getFilter() { 756 return filter; 757 } 758 759 /** 760 * @param startRow start row 761 */ 762 public void setStartRow(byte[] startRow) { 763 this.startRow = startRow; 764 } 765 766 /** 767 * @param endRow end row 768 */ 769 public void setEndRow(byte[] endRow) { 770 this.endRow = endRow; 771 } 772 773 /** 774 * @param columns list of columns of interest in column:qualifier format, or empty for all 775 */ 776 public void setColumns(List<byte[]> columns) { 777 this.columns = columns; 778 } 779 780 /** 781 * @param batch the number of cells to return in batch 782 */ 783 public void setBatch(int batch) { 784 this.batch = batch; 785 } 786 787 /** 788 * @param caching the number of rows to fetch at once 789 */ 790 public void setCaching(int caching) { 791 this.caching = caching; 792 } 793 794 /** 795 * @param value true if HFile blocks should be cached on the servers for this scan, false 796 * otherwise 797 */ 798 public void setCacheBlocks(boolean value) { 799 this.cacheBlocks = value; 800 } 801 802 /** 803 * @param limit the number of rows can fetch of each scanner at lifetime 804 */ 805 public void setLimit(int limit) { 806 this.limit = limit; 807 } 808 809 /** 810 * @param maxVersions maximum number of versions to return 811 */ 812 public void setMaxVersions(int maxVersions) { 813 this.maxVersions = maxVersions; 814 } 815 816 /** 817 * @param startTime the lower bound on timestamps of values of interest 818 */ 819 public void setStartTime(long startTime) { 820 this.startTime = startTime; 821 } 822 823 /** 824 * @param endTime the upper bound on timestamps of values of interest 825 */ 826 public void setEndTime(long endTime) { 827 this.endTime = endTime; 828 } 829 830 /** 831 * @param filter the filter specification 832 */ 833 public void setFilter(String filter) { 834 this.filter = filter; 835 } 836 837 @Override 838 public byte[] createProtobufOutput() { 839 Scanner.Builder builder = Scanner.newBuilder(); 840 if (!Bytes.equals(startRow, HConstants.EMPTY_START_ROW)) { 841 builder.setStartRow(UnsafeByteOperations.unsafeWrap(startRow)); 842 } 843 if (!Bytes.equals(endRow, HConstants.EMPTY_START_ROW)) { 844 builder.setEndRow(UnsafeByteOperations.unsafeWrap(endRow)); 845 } 846 for (byte[] column : columns) { 847 builder.addColumns(UnsafeByteOperations.unsafeWrap(column)); 848 } 849 if (startTime != 0) { 850 builder.setStartTime(startTime); 851 } 852 if (endTime != 0) { 853 builder.setEndTime(endTime); 854 } 855 builder.setBatch(getBatch()); 856 if (caching > 0) { 857 builder.setCaching(caching); 858 } 859 if (limit > 0) { 860 builder.setLimit(limit); 861 } 862 builder.setMaxVersions(maxVersions); 863 if (filter != null) { 864 builder.setFilter(filter); 865 } 866 if (labels != null && labels.size() > 0) { 867 for (String label : labels) 868 builder.addLabels(label); 869 } 870 builder.setCacheBlocks(cacheBlocks); 871 return builder.build().toByteArray(); 872 } 873 874 @Override 875 public ProtobufMessageHandler getObjectFromMessage(byte[] message) throws IOException { 876 Scanner.Builder builder = Scanner.newBuilder(); 877 ProtobufUtil.mergeFrom(builder, message); 878 if (builder.hasStartRow()) { 879 startRow = builder.getStartRow().toByteArray(); 880 } 881 if (builder.hasEndRow()) { 882 endRow = builder.getEndRow().toByteArray(); 883 } 884 for (ByteString column : builder.getColumnsList()) { 885 addColumn(column.toByteArray()); 886 } 887 if (builder.hasBatch()) { 888 batch = builder.getBatch(); 889 } 890 if (builder.hasCaching()) { 891 caching = builder.getCaching(); 892 } 893 if (builder.hasLimit()) { 894 limit = builder.getLimit(); 895 } 896 if (builder.hasStartTime()) { 897 startTime = builder.getStartTime(); 898 } 899 if (builder.hasEndTime()) { 900 endTime = builder.getEndTime(); 901 } 902 if (builder.hasMaxVersions()) { 903 maxVersions = builder.getMaxVersions(); 904 } 905 if (builder.hasFilter()) { 906 filter = builder.getFilter(); 907 } 908 if (builder.getLabelsList() != null) { 909 List<String> labels = builder.getLabelsList(); 910 for (String label : labels) { 911 addLabel(label); 912 } 913 } 914 if (builder.hasCacheBlocks()) { 915 this.cacheBlocks = builder.getCacheBlocks(); 916 } 917 return this; 918 } 919 920}