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.client; 021 022import com.google.protobuf.Descriptors; 023import com.google.protobuf.Message; 024import com.google.protobuf.Service; 025import com.google.protobuf.ServiceException; 026 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.Cell; 029import org.apache.hadoop.hbase.CellUtil; 030import org.apache.hadoop.hbase.CompareOperator; 031import org.apache.hadoop.hbase.HBaseConfiguration; 032import org.apache.hadoop.hbase.HConstants; 033import org.apache.hadoop.hbase.HTableDescriptor; 034import org.apache.hadoop.hbase.KeyValue; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.yetus.audience.InterfaceAudience; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039import org.apache.hadoop.hbase.client.Append; 040import org.apache.hadoop.hbase.client.Delete; 041import org.apache.hadoop.hbase.client.Durability; 042import org.apache.hadoop.hbase.client.Get; 043import org.apache.hadoop.hbase.client.Increment; 044import org.apache.hadoop.hbase.client.Put; 045import org.apache.hadoop.hbase.client.Result; 046import org.apache.hadoop.hbase.client.ResultScanner; 047import org.apache.hadoop.hbase.client.Row; 048import org.apache.hadoop.hbase.client.RowMutations; 049import org.apache.hadoop.hbase.client.Scan; 050import org.apache.hadoop.hbase.client.Table; 051import org.apache.hadoop.hbase.client.TableDescriptor; 052import org.apache.hadoop.hbase.client.coprocessor.Batch; 053import org.apache.hadoop.hbase.client.coprocessor.Batch.Callback; 054import org.apache.hadoop.hbase.client.metrics.ScanMetrics; 055import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; 056import org.apache.hadoop.hbase.io.TimeRange; 057import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel; 058import org.apache.hadoop.hbase.rest.Constants; 059import org.apache.hadoop.hbase.rest.model.CellModel; 060import org.apache.hadoop.hbase.rest.model.CellSetModel; 061import org.apache.hadoop.hbase.rest.model.RowModel; 062import org.apache.hadoop.hbase.rest.model.ScannerModel; 063import org.apache.hadoop.hbase.rest.model.TableSchemaModel; 064import org.apache.hadoop.hbase.util.Bytes; 065import org.apache.hadoop.util.StringUtils; 066 067import java.io.IOException; 068import java.io.InterruptedIOException; 069import java.io.UnsupportedEncodingException; 070import java.net.URLEncoder; 071import java.util.ArrayList; 072import java.util.Collection; 073import java.util.Iterator; 074import java.util.List; 075import java.util.Map; 076import java.util.Set; 077import java.util.TreeMap; 078import java.util.concurrent.TimeUnit; 079 080import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 081 082/** 083 * HTable interface to remote tables accessed via REST gateway 084 */ 085@InterfaceAudience.Public 086public class RemoteHTable implements Table { 087 088 private static final Logger LOG = LoggerFactory.getLogger(RemoteHTable.class); 089 090 final Client client; 091 final Configuration conf; 092 final byte[] name; 093 final int maxRetries; 094 final long sleepTime; 095 096 @SuppressWarnings("rawtypes") 097 protected String buildRowSpec(final byte[] row, final Map familyMap, 098 final long startTime, final long endTime, final int maxVersions) { 099 StringBuffer sb = new StringBuffer(); 100 sb.append('/'); 101 sb.append(Bytes.toString(name)); 102 sb.append('/'); 103 sb.append(toURLEncodedBytes(row)); 104 Set families = familyMap.entrySet(); 105 if (families != null) { 106 Iterator i = familyMap.entrySet().iterator(); 107 sb.append('/'); 108 while (i.hasNext()) { 109 Map.Entry e = (Map.Entry)i.next(); 110 Collection quals = (Collection)e.getValue(); 111 if (quals == null || quals.isEmpty()) { 112 // this is an unqualified family. append the family name and NO ':' 113 sb.append(toURLEncodedBytes((byte[])e.getKey())); 114 } else { 115 Iterator ii = quals.iterator(); 116 while (ii.hasNext()) { 117 sb.append(toURLEncodedBytes((byte[])e.getKey())); 118 Object o = ii.next(); 119 // Puts use byte[] but Deletes use KeyValue 120 if (o instanceof byte[]) { 121 sb.append(':'); 122 sb.append(toURLEncodedBytes((byte[]) o)); 123 } else if (o instanceof KeyValue) { 124 if (((KeyValue) o).getQualifierLength() != 0) { 125 sb.append(':'); 126 sb.append(toURLEncodedBytes(CellUtil.cloneQualifier((KeyValue) o))); 127 } 128 } else { 129 throw new RuntimeException("object type not handled"); 130 } 131 if (ii.hasNext()) { 132 sb.append(','); 133 } 134 } 135 } 136 if (i.hasNext()) { 137 sb.append(','); 138 } 139 } 140 } 141 if (startTime >= 0 && endTime != Long.MAX_VALUE) { 142 sb.append('/'); 143 sb.append(startTime); 144 if (startTime != endTime) { 145 sb.append(','); 146 sb.append(endTime); 147 } 148 } else if (endTime != Long.MAX_VALUE) { 149 sb.append('/'); 150 sb.append(endTime); 151 } 152 if (maxVersions > 1) { 153 sb.append("?v="); 154 sb.append(maxVersions); 155 } 156 return sb.toString(); 157 } 158 159 protected String buildMultiRowSpec(final byte[][] rows, int maxVersions) { 160 StringBuilder sb = new StringBuilder(); 161 sb.append('/'); 162 sb.append(Bytes.toString(name)); 163 sb.append("/multiget/"); 164 if (rows == null || rows.length == 0) { 165 return sb.toString(); 166 } 167 sb.append("?"); 168 for(int i=0; i<rows.length; i++) { 169 byte[] rk = rows[i]; 170 if (i != 0) { 171 sb.append('&'); 172 } 173 sb.append("row="); 174 sb.append(toURLEncodedBytes(rk)); 175 } 176 sb.append("&v="); 177 sb.append(maxVersions); 178 179 return sb.toString(); 180 } 181 182 protected Result[] buildResultFromModel(final CellSetModel model) { 183 List<Result> results = new ArrayList<>(); 184 for (RowModel row: model.getRows()) { 185 List<Cell> kvs = new ArrayList<>(row.getCells().size()); 186 for (CellModel cell: row.getCells()) { 187 byte[][] split = CellUtil.parseColumn(cell.getColumn()); 188 byte[] column = split[0]; 189 byte[] qualifier = null; 190 if (split.length == 1) { 191 qualifier = HConstants.EMPTY_BYTE_ARRAY; 192 } else if (split.length == 2) { 193 qualifier = split[1]; 194 } else { 195 throw new IllegalArgumentException("Invalid familyAndQualifier provided."); 196 } 197 kvs.add(new KeyValue(row.getKey(), column, qualifier, 198 cell.getTimestamp(), cell.getValue())); 199 } 200 results.add(Result.create(kvs)); 201 } 202 return results.toArray(new Result[results.size()]); 203 } 204 205 protected CellSetModel buildModelFromPut(Put put) { 206 RowModel row = new RowModel(put.getRow()); 207 long ts = put.getTimestamp(); 208 for (List<Cell> cells: put.getFamilyCellMap().values()) { 209 for (Cell cell: cells) { 210 row.addCell(new CellModel(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell), 211 ts != HConstants.LATEST_TIMESTAMP ? ts : cell.getTimestamp(), 212 CellUtil.cloneValue(cell))); 213 } 214 } 215 CellSetModel model = new CellSetModel(); 216 model.addRow(row); 217 return model; 218 } 219 220 /** 221 * Constructor 222 */ 223 public RemoteHTable(Client client, String name) { 224 this(client, HBaseConfiguration.create(), Bytes.toBytes(name)); 225 } 226 227 /** 228 * Constructor 229 */ 230 public RemoteHTable(Client client, Configuration conf, String name) { 231 this(client, conf, Bytes.toBytes(name)); 232 } 233 234 /** 235 * Constructor 236 */ 237 public RemoteHTable(Client client, Configuration conf, byte[] name) { 238 this.client = client; 239 this.conf = conf; 240 this.name = name; 241 this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10); 242 this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000); 243 } 244 245 public byte[] getTableName() { 246 return name.clone(); 247 } 248 249 @Override 250 public TableName getName() { 251 return TableName.valueOf(name); 252 } 253 254 @Override 255 public Configuration getConfiguration() { 256 return conf; 257 } 258 259 @Override 260 @Deprecated 261 public HTableDescriptor getTableDescriptor() throws IOException { 262 StringBuilder sb = new StringBuilder(); 263 sb.append('/'); 264 sb.append(Bytes.toString(name)); 265 sb.append('/'); 266 sb.append("schema"); 267 for (int i = 0; i < maxRetries; i++) { 268 Response response = client.get(sb.toString(), Constants.MIMETYPE_PROTOBUF); 269 int code = response.getCode(); 270 switch (code) { 271 case 200: 272 TableSchemaModel schema = new TableSchemaModel(); 273 schema.getObjectFromMessage(response.getBody()); 274 return schema.getTableDescriptor(); 275 case 509: 276 try { 277 Thread.sleep(sleepTime); 278 } catch (InterruptedException e) { 279 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 280 } 281 break; 282 default: 283 throw new IOException("schema request returned " + code); 284 } 285 } 286 throw new IOException("schema request timed out"); 287 } 288 289 @Override 290 public void close() throws IOException { 291 client.shutdown(); 292 } 293 294 @Override 295 public Result get(Get get) throws IOException { 296 TimeRange range = get.getTimeRange(); 297 String spec = buildRowSpec(get.getRow(), get.getFamilyMap(), 298 range.getMin(), range.getMax(), get.getMaxVersions()); 299 if (get.getFilter() != null) { 300 LOG.warn("filters not supported on gets"); 301 } 302 Result[] results = getResults(spec); 303 if (results.length > 0) { 304 if (results.length > 1) { 305 LOG.warn("too many results for get (" + results.length + ")"); 306 } 307 return results[0]; 308 } else { 309 return new Result(); 310 } 311 } 312 313 @Override 314 public Result[] get(List<Get> gets) throws IOException { 315 byte[][] rows = new byte[gets.size()][]; 316 int maxVersions = 1; 317 int count = 0; 318 319 for(Get g:gets) { 320 321 if ( count == 0 ) { 322 maxVersions = g.getMaxVersions(); 323 } else if (g.getMaxVersions() != maxVersions) { 324 LOG.warn("MaxVersions on Gets do not match, using the first in the list ("+maxVersions+")"); 325 } 326 327 if (g.getFilter() != null) { 328 LOG.warn("filters not supported on gets"); 329 } 330 331 rows[count] = g.getRow(); 332 count ++; 333 } 334 335 String spec = buildMultiRowSpec(rows, maxVersions); 336 337 return getResults(spec); 338 } 339 340 private Result[] getResults(String spec) throws IOException { 341 for (int i = 0; i < maxRetries; i++) { 342 Response response = client.get(spec, Constants.MIMETYPE_PROTOBUF); 343 int code = response.getCode(); 344 switch (code) { 345 case 200: 346 CellSetModel model = new CellSetModel(); 347 model.getObjectFromMessage(response.getBody()); 348 Result[] results = buildResultFromModel(model); 349 if ( results.length > 0) { 350 return results; 351 } 352 // fall through 353 case 404: 354 return new Result[0]; 355 356 case 509: 357 try { 358 Thread.sleep(sleepTime); 359 } catch (InterruptedException e) { 360 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 361 } 362 break; 363 default: 364 throw new IOException("get request returned " + code); 365 } 366 } 367 throw new IOException("get request timed out"); 368 } 369 370 @Override 371 public boolean exists(Get get) throws IOException { 372 LOG.warn("exists() is really get(), just use get()"); 373 Result result = get(get); 374 return (result != null && !(result.isEmpty())); 375 } 376 377 @Override 378 public boolean[] exists(List<Get> gets) throws IOException { 379 LOG.warn("exists(List<Get>) is really list of get() calls, just use get()"); 380 boolean[] results = new boolean[gets.size()]; 381 for (int i = 0; i < results.length; i++) { 382 results[i] = exists(gets.get(i)); 383 } 384 return results; 385 } 386 387 @Override 388 public void put(Put put) throws IOException { 389 CellSetModel model = buildModelFromPut(put); 390 StringBuilder sb = new StringBuilder(); 391 sb.append('/'); 392 sb.append(Bytes.toString(name)); 393 sb.append('/'); 394 sb.append(toURLEncodedBytes(put.getRow())); 395 for (int i = 0; i < maxRetries; i++) { 396 Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF, 397 model.createProtobufOutput()); 398 int code = response.getCode(); 399 switch (code) { 400 case 200: 401 return; 402 case 509: 403 try { 404 Thread.sleep(sleepTime); 405 } catch (InterruptedException e) { 406 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 407 } 408 break; 409 default: 410 throw new IOException("put request failed with " + code); 411 } 412 } 413 throw new IOException("put request timed out"); 414 } 415 416 @Override 417 public void put(List<Put> puts) throws IOException { 418 // this is a trick: The gateway accepts multiple rows in a cell set and 419 // ignores the row specification in the URI 420 421 // separate puts by row 422 TreeMap<byte[],List<Cell>> map = new TreeMap<>(Bytes.BYTES_COMPARATOR); 423 for (Put put: puts) { 424 byte[] row = put.getRow(); 425 List<Cell> cells = map.get(row); 426 if (cells == null) { 427 cells = new ArrayList<>(); 428 map.put(row, cells); 429 } 430 for (List<Cell> l: put.getFamilyCellMap().values()) { 431 cells.addAll(l); 432 } 433 } 434 435 // build the cell set 436 CellSetModel model = new CellSetModel(); 437 for (Map.Entry<byte[], List<Cell>> e: map.entrySet()) { 438 RowModel row = new RowModel(e.getKey()); 439 for (Cell cell: e.getValue()) { 440 row.addCell(new CellModel(cell)); 441 } 442 model.addRow(row); 443 } 444 445 // build path for multiput 446 StringBuilder sb = new StringBuilder(); 447 sb.append('/'); 448 sb.append(Bytes.toString(name)); 449 sb.append("/$multiput"); // can be any nonexistent row 450 for (int i = 0; i < maxRetries; i++) { 451 Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF, 452 model.createProtobufOutput()); 453 int code = response.getCode(); 454 switch (code) { 455 case 200: 456 return; 457 case 509: 458 try { 459 Thread.sleep(sleepTime); 460 } catch (InterruptedException e) { 461 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 462 } 463 break; 464 default: 465 throw new IOException("multiput request failed with " + code); 466 } 467 } 468 throw new IOException("multiput request timed out"); 469 } 470 471 @Override 472 public void delete(Delete delete) throws IOException { 473 String spec = buildRowSpec(delete.getRow(), delete.getFamilyCellMap(), 474 delete.getTimestamp(), delete.getTimestamp(), 1); 475 for (int i = 0; i < maxRetries; i++) { 476 Response response = client.delete(spec); 477 int code = response.getCode(); 478 switch (code) { 479 case 200: 480 return; 481 case 509: 482 try { 483 Thread.sleep(sleepTime); 484 } catch (InterruptedException e) { 485 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 486 } 487 break; 488 default: 489 throw new IOException("delete request failed with " + code); 490 } 491 } 492 throw new IOException("delete request timed out"); 493 } 494 495 @Override 496 public void delete(List<Delete> deletes) throws IOException { 497 for (Delete delete: deletes) { 498 delete(delete); 499 } 500 } 501 502 public void flushCommits() throws IOException { 503 // no-op 504 } 505 506 @Override 507 public TableDescriptor getDescriptor() throws IOException { 508 return getTableDescriptor(); 509 } 510 511 class Scanner implements ResultScanner { 512 513 String uri; 514 515 public Scanner(Scan scan) throws IOException { 516 ScannerModel model; 517 try { 518 model = ScannerModel.fromScan(scan); 519 } catch (Exception e) { 520 throw new IOException(e); 521 } 522 StringBuffer sb = new StringBuffer(); 523 sb.append('/'); 524 sb.append(Bytes.toString(name)); 525 sb.append('/'); 526 sb.append("scanner"); 527 for (int i = 0; i < maxRetries; i++) { 528 Response response = client.post(sb.toString(), 529 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput()); 530 int code = response.getCode(); 531 switch (code) { 532 case 201: 533 uri = response.getLocation(); 534 return; 535 case 509: 536 try { 537 Thread.sleep(sleepTime); 538 } catch (InterruptedException e) { 539 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 540 } 541 break; 542 default: 543 throw new IOException("scan request failed with " + code); 544 } 545 } 546 throw new IOException("scan request timed out"); 547 } 548 549 @Override 550 public Result[] next(int nbRows) throws IOException { 551 StringBuilder sb = new StringBuilder(uri); 552 sb.append("?n="); 553 sb.append(nbRows); 554 for (int i = 0; i < maxRetries; i++) { 555 Response response = client.get(sb.toString(), 556 Constants.MIMETYPE_PROTOBUF); 557 int code = response.getCode(); 558 switch (code) { 559 case 200: 560 CellSetModel model = new CellSetModel(); 561 model.getObjectFromMessage(response.getBody()); 562 return buildResultFromModel(model); 563 case 204: 564 case 206: 565 return null; 566 case 509: 567 try { 568 Thread.sleep(sleepTime); 569 } catch (InterruptedException e) { 570 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 571 } 572 break; 573 default: 574 throw new IOException("scanner.next request failed with " + code); 575 } 576 } 577 throw new IOException("scanner.next request timed out"); 578 } 579 580 @Override 581 public Result next() throws IOException { 582 Result[] results = next(1); 583 if (results == null || results.length < 1) { 584 return null; 585 } 586 return results[0]; 587 } 588 589 class Iter implements Iterator<Result> { 590 591 Result cache; 592 593 public Iter() { 594 try { 595 cache = Scanner.this.next(); 596 } catch (IOException e) { 597 LOG.warn(StringUtils.stringifyException(e)); 598 } 599 } 600 601 @Override 602 public boolean hasNext() { 603 return cache != null; 604 } 605 606 @Override 607 public Result next() { 608 Result result = cache; 609 try { 610 cache = Scanner.this.next(); 611 } catch (IOException e) { 612 LOG.warn(StringUtils.stringifyException(e)); 613 cache = null; 614 } 615 return result; 616 } 617 618 @Override 619 public void remove() { 620 throw new RuntimeException("remove() not supported"); 621 } 622 623 } 624 625 @Override 626 public Iterator<Result> iterator() { 627 return new Iter(); 628 } 629 630 @Override 631 public void close() { 632 try { 633 client.delete(uri); 634 } catch (IOException e) { 635 LOG.warn(StringUtils.stringifyException(e)); 636 } 637 } 638 639 @Override 640 public boolean renewLease() { 641 throw new RuntimeException("renewLease() not supported"); 642 } 643 644 @Override 645 public ScanMetrics getScanMetrics() { 646 throw new RuntimeException("getScanMetrics() not supported"); 647 } 648 } 649 650 @Override 651 public ResultScanner getScanner(Scan scan) throws IOException { 652 return new Scanner(scan); 653 } 654 655 @Override 656 public ResultScanner getScanner(byte[] family) throws IOException { 657 Scan scan = new Scan(); 658 scan.addFamily(family); 659 return new Scanner(scan); 660 } 661 662 @Override 663 public ResultScanner getScanner(byte[] family, byte[] qualifier) 664 throws IOException { 665 Scan scan = new Scan(); 666 scan.addColumn(family, qualifier); 667 return new Scanner(scan); 668 } 669 670 public boolean isAutoFlush() { 671 return true; 672 } 673 674 @Override 675 @Deprecated 676 public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier, 677 byte[] value, Put put) throws IOException { 678 return doCheckAndPut(row, family, qualifier, value, put); 679 } 680 681 private boolean doCheckAndPut(byte[] row, byte[] family, byte[] qualifier, 682 byte[] value, Put put) throws IOException { 683 // column to check-the-value 684 put.add(new KeyValue(row, family, qualifier, value)); 685 686 CellSetModel model = buildModelFromPut(put); 687 StringBuilder sb = new StringBuilder(); 688 sb.append('/'); 689 sb.append(Bytes.toString(name)); 690 sb.append('/'); 691 sb.append(toURLEncodedBytes(put.getRow())); 692 sb.append("?check=put"); 693 694 for (int i = 0; i < maxRetries; i++) { 695 Response response = client.put(sb.toString(), 696 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput()); 697 int code = response.getCode(); 698 switch (code) { 699 case 200: 700 return true; 701 case 304: // NOT-MODIFIED 702 return false; 703 case 509: 704 try { 705 Thread.sleep(sleepTime); 706 } catch (final InterruptedException e) { 707 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 708 } 709 break; 710 default: 711 throw new IOException("checkAndPut request failed with " + code); 712 } 713 } 714 throw new IOException("checkAndPut request timed out"); 715 } 716 717 @Override 718 @Deprecated 719 public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier, 720 CompareOp compareOp, byte[] value, Put put) throws IOException { 721 throw new IOException("checkAndPut for non-equal comparison not implemented"); 722 } 723 724 @Override 725 @Deprecated 726 public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier, 727 CompareOperator compareOp, byte[] value, Put put) throws IOException { 728 throw new IOException("checkAndPut for non-equal comparison not implemented"); 729 } 730 731 @Override 732 public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier, 733 byte[] value, Delete delete) throws IOException { 734 return doCheckAndDelete(row, family, qualifier, value, delete); 735 } 736 737 private boolean doCheckAndDelete(byte[] row, byte[] family, byte[] qualifier, 738 byte[] value, Delete delete) throws IOException { 739 Put put = new Put(row); 740 put.setFamilyCellMap(delete.getFamilyCellMap()); 741 // column to check-the-value 742 put.add(new KeyValue(row, family, qualifier, value)); 743 CellSetModel model = buildModelFromPut(put); 744 StringBuilder sb = new StringBuilder(); 745 sb.append('/'); 746 sb.append(Bytes.toString(name)); 747 sb.append('/'); 748 sb.append(toURLEncodedBytes(row)); 749 sb.append("?check=delete"); 750 751 for (int i = 0; i < maxRetries; i++) { 752 Response response = client.put(sb.toString(), 753 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput()); 754 int code = response.getCode(); 755 switch (code) { 756 case 200: 757 return true; 758 case 304: // NOT-MODIFIED 759 return false; 760 case 509: 761 try { 762 Thread.sleep(sleepTime); 763 } catch (final InterruptedException e) { 764 throw (InterruptedIOException)new InterruptedIOException().initCause(e); 765 } 766 break; 767 default: 768 throw new IOException("checkAndDelete request failed with " + code); 769 } 770 } 771 throw new IOException("checkAndDelete request timed out"); 772 } 773 774 @Override 775 @Deprecated 776 public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier, 777 CompareOp compareOp, byte[] value, Delete delete) throws IOException { 778 throw new IOException("checkAndDelete for non-equal comparison not implemented"); 779 } 780 781 @Override 782 @Deprecated 783 public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier, 784 CompareOperator compareOp, byte[] value, Delete delete) throws IOException { 785 throw new IOException("checkAndDelete for non-equal comparison not implemented"); 786 } 787 788 @Override 789 public CheckAndMutateBuilder checkAndMutate(byte[] row, byte[] family) { 790 return new CheckAndMutateBuilderImpl(row, family); 791 } 792 793 @Override 794 @Deprecated 795 public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, 796 CompareOp compareOp, byte[] value, RowMutations rm) throws IOException { 797 throw new UnsupportedOperationException("checkAndMutate not implemented"); 798 } 799 800 @Override 801 @Deprecated 802 public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, 803 CompareOperator compareOp, byte[] value, RowMutations rm) throws IOException { 804 throw new UnsupportedOperationException("checkAndMutate not implemented"); 805 } 806 807 @Override 808 public Result increment(Increment increment) throws IOException { 809 throw new IOException("Increment not supported"); 810 } 811 812 @Override 813 public Result append(Append append) throws IOException { 814 throw new IOException("Append not supported"); 815 } 816 817 @Override 818 public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier, 819 long amount) throws IOException { 820 throw new IOException("incrementColumnValue not supported"); 821 } 822 823 @Override 824 public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier, 825 long amount, Durability durability) throws IOException { 826 throw new IOException("incrementColumnValue not supported"); 827 } 828 829 @Override 830 public void batch(List<? extends Row> actions, Object[] results) throws IOException { 831 throw new IOException("batch not supported"); 832 } 833 834 @Override 835 public <R> void batchCallback(List<? extends Row> actions, Object[] results, 836 Batch.Callback<R> callback) throws IOException, InterruptedException { 837 throw new IOException("batchCallback not supported"); 838 } 839 840 @Override 841 public CoprocessorRpcChannel coprocessorService(byte[] row) { 842 throw new UnsupportedOperationException("coprocessorService not implemented"); 843 } 844 845 @Override 846 public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service, 847 byte[] startKey, byte[] endKey, Batch.Call<T, R> callable) 848 throws ServiceException, Throwable { 849 throw new UnsupportedOperationException("coprocessorService not implemented"); 850 } 851 852 @Override 853 public <T extends Service, R> void coprocessorService(Class<T> service, 854 byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Batch.Callback<R> callback) 855 throws ServiceException, Throwable { 856 throw new UnsupportedOperationException("coprocessorService not implemented"); 857 } 858 859 @Override 860 public void mutateRow(RowMutations rm) throws IOException { 861 throw new IOException("atomicMutation not supported"); 862 } 863 864 @Override 865 public <R extends Message> Map<byte[], R> batchCoprocessorService( 866 Descriptors.MethodDescriptor method, Message request, 867 byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable { 868 throw new UnsupportedOperationException("batchCoprocessorService not implemented"); 869 } 870 871 @Override 872 public <R extends Message> void batchCoprocessorService( 873 Descriptors.MethodDescriptor method, Message request, 874 byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback) 875 throws ServiceException, Throwable { 876 throw new UnsupportedOperationException("batchCoprocessorService not implemented"); 877 } 878 879 @Override 880 @Deprecated 881 public void setOperationTimeout(int operationTimeout) { 882 throw new UnsupportedOperationException(); 883 } 884 885 @Override 886 @Deprecated 887 public int getOperationTimeout() { 888 throw new UnsupportedOperationException(); 889 } 890 891 @Override 892 @Deprecated 893 public void setRpcTimeout(int rpcTimeout) { 894 throw new UnsupportedOperationException(); 895 } 896 897 @Override 898 public long getReadRpcTimeout(TimeUnit unit) { 899 throw new UnsupportedOperationException(); 900 } 901 902 @Override 903 @Deprecated 904 public int getRpcTimeout() { 905 throw new UnsupportedOperationException(); 906 } 907 908 @Override 909 public long getRpcTimeout(TimeUnit unit) { 910 throw new UnsupportedOperationException(); 911 } 912 913 @Override 914 @Deprecated 915 public int getReadRpcTimeout() { 916 throw new UnsupportedOperationException(); 917 } 918 919 @Override 920 @Deprecated 921 public void setReadRpcTimeout(int readRpcTimeout) { 922 throw new UnsupportedOperationException(); 923 } 924 925 @Override 926 public long getWriteRpcTimeout(TimeUnit unit) { 927 throw new UnsupportedOperationException(); 928 } 929 930 @Override 931 @Deprecated 932 public int getWriteRpcTimeout() { 933 throw new UnsupportedOperationException(); 934 } 935 936 @Override 937 @Deprecated 938 public void setWriteRpcTimeout(int writeRpcTimeout) { 939 throw new UnsupportedOperationException(); 940 } 941 942 @Override 943 public long getOperationTimeout(TimeUnit unit) { 944 throw new UnsupportedOperationException(); 945 } 946 947 /* 948 * Only a small subset of characters are valid in URLs. 949 * 950 * Row keys, column families, and qualifiers cannot be appended to URLs without first URL 951 * escaping. Table names are ok because they can only contain alphanumeric, ".","_", and "-" 952 * which are valid characters in URLs. 953 */ 954 private static String toURLEncodedBytes(byte[] row) { 955 try { 956 return URLEncoder.encode(new String(row, "UTF-8"), "UTF-8"); 957 } catch (UnsupportedEncodingException e) { 958 throw new IllegalStateException("URLEncoder doesn't support UTF-8", e); 959 } 960 } 961 962 private class CheckAndMutateBuilderImpl implements CheckAndMutateBuilder { 963 964 private final byte[] row; 965 private final byte[] family; 966 private byte[] qualifier; 967 private byte[] value; 968 969 CheckAndMutateBuilderImpl(byte[] row, byte[] family) { 970 this.row = Preconditions.checkNotNull(row, "row is null"); 971 this.family = Preconditions.checkNotNull(family, "family is null"); 972 } 973 974 @Override 975 public CheckAndMutateBuilder qualifier(byte[] qualifier) { 976 this.qualifier = Preconditions.checkNotNull(qualifier, "qualifier is null. Consider using" + 977 " an empty byte array, or just do not call this method if you want a null qualifier"); 978 return this; 979 } 980 981 @Override 982 public CheckAndMutateBuilder timeRange(TimeRange timeRange) { 983 throw new UnsupportedOperationException("timeRange not implemented"); 984 } 985 986 @Override 987 public CheckAndMutateBuilder ifNotExists() { 988 throw new UnsupportedOperationException("CheckAndMutate for non-equal comparison " 989 + "not implemented"); 990 } 991 992 @Override 993 public CheckAndMutateBuilder ifMatches(CompareOperator compareOp, byte[] value) { 994 if (compareOp == CompareOperator.EQUAL) { 995 this.value = Preconditions.checkNotNull(value, "value is null"); 996 return this; 997 } else { 998 throw new UnsupportedOperationException("CheckAndMutate for non-equal comparison " + 999 "not implemented"); 1000 } 1001 } 1002 1003 @Override 1004 public CheckAndMutateBuilder ifEquals(byte[] value) { 1005 this.value = Preconditions.checkNotNull(value, "value is null"); 1006 return this; 1007 } 1008 1009 @Override 1010 public boolean thenPut(Put put) throws IOException { 1011 return doCheckAndPut(row, family, qualifier, value, put); 1012 } 1013 1014 @Override 1015 public boolean thenDelete(Delete delete) throws IOException { 1016 return doCheckAndDelete(row, family, qualifier, value, delete); 1017 } 1018 1019 @Override 1020 public boolean thenMutate(RowMutations mutation) throws IOException { 1021 throw new UnsupportedOperationException("thenMutate not implemented"); 1022 } 1023 } 1024}