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