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