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