1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.rest.client;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.TreeMap;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.hbase.classification.InterfaceAudience;
34 import org.apache.hadoop.hbase.classification.InterfaceStability;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.hbase.Cell;
37 import org.apache.hadoop.hbase.HBaseConfiguration;
38 import org.apache.hadoop.hbase.HConstants;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.KeyValue;
41 import org.apache.hadoop.hbase.KeyValueUtil;
42 import org.apache.hadoop.hbase.TableName;
43 import org.apache.hadoop.hbase.client.Append;
44 import org.apache.hadoop.hbase.client.Delete;
45 import org.apache.hadoop.hbase.client.Durability;
46 import org.apache.hadoop.hbase.client.Get;
47 import org.apache.hadoop.hbase.client.HTableInterface;
48 import org.apache.hadoop.hbase.client.Increment;
49 import org.apache.hadoop.hbase.client.Put;
50 import org.apache.hadoop.hbase.client.Result;
51 import org.apache.hadoop.hbase.client.ResultScanner;
52 import org.apache.hadoop.hbase.client.Row;
53 import org.apache.hadoop.hbase.client.RowMutations;
54 import org.apache.hadoop.hbase.client.Scan;
55 import org.apache.hadoop.hbase.client.coprocessor.Batch;
56 import org.apache.hadoop.hbase.client.coprocessor.Batch.Callback;
57 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
58 import org.apache.hadoop.hbase.io.TimeRange;
59 import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
60 import org.apache.hadoop.hbase.rest.Constants;
61 import org.apache.hadoop.hbase.rest.model.CellModel;
62 import org.apache.hadoop.hbase.rest.model.CellSetModel;
63 import org.apache.hadoop.hbase.rest.model.RowModel;
64 import org.apache.hadoop.hbase.rest.model.ScannerModel;
65 import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
66 import org.apache.hadoop.hbase.util.Bytes;
67 import org.apache.hadoop.util.StringUtils;
68
69 import com.google.protobuf.Descriptors;
70 import com.google.protobuf.Message;
71 import com.google.protobuf.Service;
72 import com.google.protobuf.ServiceException;
73
74
75
76
77 @InterfaceAudience.Public
78 @InterfaceStability.Stable
79 public class RemoteHTable implements HTableInterface {
80
81 private static final Log LOG = LogFactory.getLog(RemoteHTable.class);
82
83 final Client client;
84 final Configuration conf;
85 final byte[] name;
86 final int maxRetries;
87 final long sleepTime;
88
89 @SuppressWarnings("rawtypes")
90 protected String buildRowSpec(final byte[] row, final Map familyMap,
91 final long startTime, final long endTime, final int maxVersions) {
92 StringBuffer sb = new StringBuffer();
93 sb.append('/');
94 sb.append(Bytes.toStringBinary(name));
95 sb.append('/');
96 sb.append(Bytes.toStringBinary(row));
97 Set families = familyMap.entrySet();
98 if (families != null) {
99 Iterator i = familyMap.entrySet().iterator();
100 sb.append('/');
101 while (i.hasNext()) {
102 Map.Entry e = (Map.Entry)i.next();
103 Collection quals = (Collection)e.getValue();
104 if (quals == null || quals.isEmpty()) {
105
106 sb.append(Bytes.toStringBinary((byte[])e.getKey()));
107 } else {
108 Iterator ii = quals.iterator();
109 while (ii.hasNext()) {
110 sb.append(Bytes.toStringBinary((byte[])e.getKey()));
111 sb.append(':');
112 Object o = ii.next();
113
114 if (o instanceof byte[]) {
115 sb.append(Bytes.toStringBinary((byte[])o));
116 } else if (o instanceof KeyValue) {
117 sb.append(Bytes.toStringBinary(((KeyValue)o).getQualifier()));
118 } else {
119 throw new RuntimeException("object type not handled");
120 }
121 if (ii.hasNext()) {
122 sb.append(',');
123 }
124 }
125 }
126 if (i.hasNext()) {
127 sb.append(',');
128 }
129 }
130 }
131 if (startTime >= 0 && endTime != Long.MAX_VALUE) {
132 sb.append('/');
133 sb.append(startTime);
134 if (startTime != endTime) {
135 sb.append(',');
136 sb.append(endTime);
137 }
138 } else if (endTime != Long.MAX_VALUE) {
139 sb.append('/');
140 sb.append(endTime);
141 }
142 if (maxVersions > 1) {
143 sb.append("?v=");
144 sb.append(maxVersions);
145 }
146 return sb.toString();
147 }
148
149 protected String buildMultiRowSpec(final byte[][] rows, int maxVersions) {
150 StringBuilder sb = new StringBuilder();
151 sb.append('/');
152 sb.append(Bytes.toStringBinary(name));
153 sb.append("/multiget/");
154 if (rows == null || rows.length == 0) {
155 return sb.toString();
156 }
157 sb.append("?");
158 for(int i=0; i<rows.length; i++) {
159 byte[] rk = rows[i];
160 if (i != 0) {
161 sb.append('&');
162 }
163 sb.append("row=");
164 sb.append(Bytes.toStringBinary(rk));
165 }
166 sb.append("&v=");
167 sb.append(maxVersions);
168
169 return sb.toString();
170 }
171
172 protected Result[] buildResultFromModel(final CellSetModel model) {
173 List<Result> results = new ArrayList<Result>();
174 for (RowModel row: model.getRows()) {
175 List<Cell> kvs = new ArrayList<Cell>();
176 for (CellModel cell: row.getCells()) {
177 byte[][] split = KeyValue.parseColumn(cell.getColumn());
178 byte[] column = split[0];
179 byte[] qualifier = null;
180 if (split.length == 1) {
181 qualifier = HConstants.EMPTY_BYTE_ARRAY;
182 } else if (split.length == 2) {
183 qualifier = split[1];
184 } else {
185 throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
186 }
187 kvs.add(new KeyValue(row.getKey(), column, qualifier,
188 cell.getTimestamp(), cell.getValue()));
189 }
190 results.add(Result.create(kvs));
191 }
192 return results.toArray(new Result[results.size()]);
193 }
194
195 protected CellSetModel buildModelFromPut(Put put) {
196 RowModel row = new RowModel(put.getRow());
197 long ts = put.getTimeStamp();
198 for (List<Cell> cells: put.getFamilyCellMap().values()) {
199 for (Cell cell: cells) {
200 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
201 row.addCell(new CellModel(kv.getFamily(), kv.getQualifier(),
202 ts != HConstants.LATEST_TIMESTAMP ? ts : kv.getTimestamp(),
203 kv.getValue()));
204 }
205 }
206 CellSetModel model = new CellSetModel();
207 model.addRow(row);
208 return model;
209 }
210
211
212
213
214
215
216 public RemoteHTable(Client client, String name) {
217 this(client, HBaseConfiguration.create(), Bytes.toBytes(name));
218 }
219
220
221
222
223
224
225
226 public RemoteHTable(Client client, Configuration conf, String name) {
227 this(client, conf, Bytes.toBytes(name));
228 }
229
230
231
232
233
234
235
236 public RemoteHTable(Client client, Configuration conf, byte[] name) {
237 this.client = client;
238 this.conf = conf;
239 this.name = name;
240 this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10);
241 this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000);
242 }
243
244 public byte[] getTableName() {
245 return name.clone();
246 }
247
248 @Override
249 public TableName getName() {
250 return TableName.valueOf(name);
251 }
252
253 public Configuration getConfiguration() {
254 return conf;
255 }
256
257 public HTableDescriptor getTableDescriptor() throws IOException {
258 StringBuilder sb = new StringBuilder();
259 sb.append('/');
260 sb.append(Bytes.toStringBinary(name));
261 sb.append('/');
262 sb.append("schema");
263 for (int i = 0; i < maxRetries; i++) {
264 Response response = client.get(sb.toString(), Constants.MIMETYPE_PROTOBUF);
265 int code = response.getCode();
266 switch (code) {
267 case 200:
268 TableSchemaModel schema = new TableSchemaModel();
269 schema.getObjectFromMessage(response.getBody());
270 return schema.getTableDescriptor();
271 case 509:
272 try {
273 Thread.sleep(sleepTime);
274 } catch (InterruptedException e) { }
275 break;
276 default:
277 throw new IOException("schema request returned " + code);
278 }
279 }
280 throw new IOException("schema request timed out");
281 }
282
283 public void close() throws IOException {
284 client.shutdown();
285 }
286
287 public Result get(Get get) throws IOException {
288 TimeRange range = get.getTimeRange();
289 String spec = buildRowSpec(get.getRow(), get.getFamilyMap(),
290 range.getMin(), range.getMax(), get.getMaxVersions());
291 if (get.getFilter() != null) {
292 LOG.warn("filters not supported on gets");
293 }
294 Result[] results = getResults(spec);
295 if (results.length > 0) {
296 if (results.length > 1) {
297 LOG.warn("too many results for get (" + results.length + ")");
298 }
299 return results[0];
300 } else {
301 return new Result();
302 }
303 }
304
305 public Result[] get(List<Get> gets) throws IOException {
306 byte[][] rows = new byte[gets.size()][];
307 int maxVersions = 1;
308 int count = 0;
309
310 for(Get g:gets) {
311
312 if ( count == 0 ) {
313 maxVersions = g.getMaxVersions();
314 } else if (g.getMaxVersions() != maxVersions) {
315 LOG.warn("MaxVersions on Gets do not match, using the first in the list ("+maxVersions+")");
316 }
317
318 if (g.getFilter() != null) {
319 LOG.warn("filters not supported on gets");
320 }
321
322 rows[count] = g.getRow();
323 count ++;
324 }
325
326 String spec = buildMultiRowSpec(rows, maxVersions);
327
328 return getResults(spec);
329 }
330
331 private Result[] getResults(String spec) throws IOException {
332 for (int i = 0; i < maxRetries; i++) {
333 Response response = client.get(spec, Constants.MIMETYPE_PROTOBUF);
334 int code = response.getCode();
335 switch (code) {
336 case 200:
337 CellSetModel model = new CellSetModel();
338 model.getObjectFromMessage(response.getBody());
339 Result[] results = buildResultFromModel(model);
340 if ( results.length > 0) {
341 return results;
342 }
343
344 case 404:
345 return new Result[0];
346
347 case 509:
348 try {
349 Thread.sleep(sleepTime);
350 } catch (InterruptedException e) { }
351 break;
352 default:
353 throw new IOException("get request returned " + code);
354 }
355 }
356 throw new IOException("get request timed out");
357 }
358
359 public boolean exists(Get get) throws IOException {
360 LOG.warn("exists() is really get(), just use get()");
361 Result result = get(get);
362 return (result != null && !(result.isEmpty()));
363 }
364
365
366
367
368
369 public Boolean[] exists(List<Get> gets) throws IOException {
370 LOG.warn("exists(List<Get>) is really list of get() calls, just use get()");
371 Boolean[] results = new Boolean[gets.size()];
372 for (int i = 0; i < results.length; i++) {
373 results[i] = exists(gets.get(i));
374 }
375 return results;
376 }
377
378 public void put(Put put) throws IOException {
379 CellSetModel model = buildModelFromPut(put);
380 StringBuilder sb = new StringBuilder();
381 sb.append('/');
382 sb.append(Bytes.toStringBinary(name));
383 sb.append('/');
384 sb.append(Bytes.toStringBinary(put.getRow()));
385 for (int i = 0; i < maxRetries; i++) {
386 Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
387 model.createProtobufOutput());
388 int code = response.getCode();
389 switch (code) {
390 case 200:
391 return;
392 case 509:
393 try {
394 Thread.sleep(sleepTime);
395 } catch (InterruptedException e) { }
396 break;
397 default:
398 throw new IOException("put request failed with " + code);
399 }
400 }
401 throw new IOException("put request timed out");
402 }
403
404 public void put(List<Put> puts) throws IOException {
405
406
407
408
409 TreeMap<byte[],List<Cell>> map =
410 new TreeMap<byte[],List<Cell>>(Bytes.BYTES_COMPARATOR);
411 for (Put put: puts) {
412 byte[] row = put.getRow();
413 List<Cell> cells = map.get(row);
414 if (cells == null) {
415 cells = new ArrayList<Cell>();
416 map.put(row, cells);
417 }
418 for (List<Cell> l: put.getFamilyCellMap().values()) {
419 cells.addAll(l);
420 }
421 }
422
423
424 CellSetModel model = new CellSetModel();
425 for (Map.Entry<byte[], List<Cell>> e: map.entrySet()) {
426 RowModel row = new RowModel(e.getKey());
427 for (Cell cell: e.getValue()) {
428 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
429 row.addCell(new CellModel(kv));
430 }
431 model.addRow(row);
432 }
433
434
435 StringBuilder sb = new StringBuilder();
436 sb.append('/');
437 sb.append(Bytes.toStringBinary(name));
438 sb.append("/$multiput");
439 for (int i = 0; i < maxRetries; i++) {
440 Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
441 model.createProtobufOutput());
442 int code = response.getCode();
443 switch (code) {
444 case 200:
445 return;
446 case 509:
447 try {
448 Thread.sleep(sleepTime);
449 } catch (InterruptedException e) { }
450 break;
451 default:
452 throw new IOException("multiput request failed with " + code);
453 }
454 }
455 throw new IOException("multiput request timed out");
456 }
457
458 public void delete(Delete delete) throws IOException {
459 String spec = buildRowSpec(delete.getRow(), delete.getFamilyCellMap(),
460 delete.getTimeStamp(), delete.getTimeStamp(), 1);
461 for (int i = 0; i < maxRetries; i++) {
462 Response response = client.delete(spec);
463 int code = response.getCode();
464 switch (code) {
465 case 200:
466 return;
467 case 509:
468 try {
469 Thread.sleep(sleepTime);
470 } catch (InterruptedException e) { }
471 break;
472 default:
473 throw new IOException("delete request failed with " + code);
474 }
475 }
476 throw new IOException("delete request timed out");
477 }
478
479 public void delete(List<Delete> deletes) throws IOException {
480 for (Delete delete: deletes) {
481 delete(delete);
482 }
483 }
484
485 public void flushCommits() throws IOException {
486
487 }
488
489 class Scanner implements ResultScanner {
490
491 String uri;
492
493 public Scanner(Scan scan) throws IOException {
494 ScannerModel model;
495 try {
496 model = ScannerModel.fromScan(scan);
497 } catch (Exception e) {
498 throw new IOException(e);
499 }
500 StringBuffer sb = new StringBuffer();
501 sb.append('/');
502 sb.append(Bytes.toStringBinary(name));
503 sb.append('/');
504 sb.append("scanner");
505 for (int i = 0; i < maxRetries; i++) {
506 Response response = client.post(sb.toString(),
507 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
508 int code = response.getCode();
509 switch (code) {
510 case 201:
511 uri = response.getLocation();
512 return;
513 case 509:
514 try {
515 Thread.sleep(sleepTime);
516 } catch (InterruptedException e) { }
517 break;
518 default:
519 throw new IOException("scan request failed with " + code);
520 }
521 }
522 throw new IOException("scan request timed out");
523 }
524
525 @Override
526 public Result[] next(int nbRows) throws IOException {
527 StringBuilder sb = new StringBuilder(uri);
528 sb.append("?n=");
529 sb.append(nbRows);
530 for (int i = 0; i < maxRetries; i++) {
531 Response response = client.get(sb.toString(),
532 Constants.MIMETYPE_PROTOBUF);
533 int code = response.getCode();
534 switch (code) {
535 case 200:
536 CellSetModel model = new CellSetModel();
537 model.getObjectFromMessage(response.getBody());
538 return buildResultFromModel(model);
539 case 204:
540 case 206:
541 return null;
542 case 509:
543 try {
544 Thread.sleep(sleepTime);
545 } catch (InterruptedException e) { }
546 break;
547 default:
548 throw new IOException("scanner.next request failed with " + code);
549 }
550 }
551 throw new IOException("scanner.next request timed out");
552 }
553
554 @Override
555 public Result next() throws IOException {
556 Result[] results = next(1);
557 if (results == null || results.length < 1) {
558 return null;
559 }
560 return results[0];
561 }
562
563 class Iter implements Iterator<Result> {
564
565 Result cache;
566
567 public Iter() {
568 try {
569 cache = Scanner.this.next();
570 } catch (IOException e) {
571 LOG.warn(StringUtils.stringifyException(e));
572 }
573 }
574
575 @Override
576 public boolean hasNext() {
577 return cache != null;
578 }
579
580 @Override
581 public Result next() {
582 Result result = cache;
583 try {
584 cache = Scanner.this.next();
585 } catch (IOException e) {
586 LOG.warn(StringUtils.stringifyException(e));
587 cache = null;
588 }
589 return result;
590 }
591
592 @Override
593 public void remove() {
594 throw new RuntimeException("remove() not supported");
595 }
596
597 }
598
599 @Override
600 public Iterator<Result> iterator() {
601 return new Iter();
602 }
603
604 @Override
605 public void close() {
606 try {
607 client.delete(uri);
608 } catch (IOException e) {
609 LOG.warn(StringUtils.stringifyException(e));
610 }
611 }
612
613 }
614
615 public ResultScanner getScanner(Scan scan) throws IOException {
616 return new Scanner(scan);
617 }
618
619 public ResultScanner getScanner(byte[] family) throws IOException {
620 Scan scan = new Scan();
621 scan.addFamily(family);
622 return new Scanner(scan);
623 }
624
625 public ResultScanner getScanner(byte[] family, byte[] qualifier)
626 throws IOException {
627 Scan scan = new Scan();
628 scan.addColumn(family, qualifier);
629 return new Scanner(scan);
630 }
631
632 public boolean isAutoFlush() {
633 return true;
634 }
635
636 public Result getRowOrBefore(byte[] row, byte[] family) throws IOException {
637 throw new IOException("getRowOrBefore not supported");
638 }
639
640 public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
641 byte[] value, Put put) throws IOException {
642
643 put.add(new KeyValue(row, family, qualifier, value));
644
645 CellSetModel model = buildModelFromPut(put);
646 StringBuilder sb = new StringBuilder();
647 sb.append('/');
648 sb.append(Bytes.toStringBinary(name));
649 sb.append('/');
650 sb.append(Bytes.toStringBinary(put.getRow()));
651 sb.append("?check=put");
652
653 for (int i = 0; i < maxRetries; i++) {
654 Response response = client.put(sb.toString(),
655 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
656 int code = response.getCode();
657 switch (code) {
658 case 200:
659 return true;
660 case 304:
661 return false;
662 case 509:
663 try {
664 Thread.sleep(sleepTime);
665 } catch (final InterruptedException e) {
666 }
667 break;
668 default:
669 throw new IOException("checkAndPut request failed with " + code);
670 }
671 }
672 throw new IOException("checkAndPut request timed out");
673 }
674
675 public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
676 byte[] value, Delete delete) throws IOException {
677 Put put = new Put(row);
678
679 put.add(new KeyValue(row, family, qualifier, value));
680 CellSetModel model = buildModelFromPut(put);
681 StringBuilder sb = new StringBuilder();
682 sb.append('/');
683 sb.append(Bytes.toStringBinary(name));
684 sb.append('/');
685 sb.append(Bytes.toStringBinary(row));
686 sb.append("?check=delete");
687
688 for (int i = 0; i < maxRetries; i++) {
689 Response response = client.put(sb.toString(),
690 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
691 int code = response.getCode();
692 switch (code) {
693 case 200:
694 return true;
695 case 304:
696 return false;
697 case 509:
698 try {
699 Thread.sleep(sleepTime);
700 } catch (final InterruptedException e) {
701 }
702 break;
703 default:
704 throw new IOException("checkAndDelete request failed with " + code);
705 }
706 }
707 throw new IOException("checkAndDelete request timed out");
708 }
709
710 public Result increment(Increment increment) throws IOException {
711 throw new IOException("Increment not supported");
712 }
713
714 public Result append(Append append) throws IOException {
715 throw new IOException("Append not supported");
716 }
717
718 public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
719 long amount) throws IOException {
720 throw new IOException("incrementColumnValue not supported");
721 }
722
723 public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
724 long amount, Durability durability) throws IOException {
725 throw new IOException("incrementColumnValue not supported");
726 }
727
728 @Override
729 public void batch(List<? extends Row> actions, Object[] results) throws IOException {
730 throw new IOException("batch not supported");
731 }
732
733 @Override
734 public Object[] batch(List<? extends Row> actions) throws IOException {
735 throw new IOException("batch not supported");
736 }
737
738 @Override
739 public <R> void batchCallback(List<? extends Row> actions, Object[] results,
740 Batch.Callback<R> callback) throws IOException, InterruptedException {
741 throw new IOException("batchCallback not supported");
742 }
743
744 @Override
745 public <R> Object[] batchCallback(List<? extends Row> actions, Batch.Callback<R> callback)
746 throws IOException, InterruptedException {
747 throw new IOException("batchCallback not supported");
748 }
749
750 @Override
751 public CoprocessorRpcChannel coprocessorService(byte[] row) {
752 throw new UnsupportedOperationException("coprocessorService not implemented");
753 }
754
755 @Override
756 public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service,
757 byte[] startKey, byte[] endKey, Batch.Call<T, R> callable)
758 throws ServiceException, Throwable {
759 throw new UnsupportedOperationException("coprocessorService not implemented");
760 }
761
762 @Override
763 public <T extends Service, R> void coprocessorService(Class<T> service,
764 byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Batch.Callback<R> callback)
765 throws ServiceException, Throwable {
766 throw new UnsupportedOperationException("coprocessorService not implemented");
767 }
768
769 @Override
770 public void mutateRow(RowMutations rm) throws IOException {
771 throw new IOException("atomicMutation not supported");
772 }
773
774 @Override
775 public void setAutoFlush(boolean autoFlush) {
776 throw new UnsupportedOperationException("setAutoFlush not implemented");
777 }
778
779 @Override
780 public void setAutoFlush(boolean autoFlush, boolean clearBufferOnFail) {
781 throw new UnsupportedOperationException("setAutoFlush not implemented");
782 }
783
784 @Override
785 public void setAutoFlushTo(boolean autoFlush) {
786 throw new UnsupportedOperationException("setAutoFlushTo not implemented");
787 }
788
789 @Override
790 public long getWriteBufferSize() {
791 throw new UnsupportedOperationException("getWriteBufferSize not implemented");
792 }
793
794 @Override
795 public void setWriteBufferSize(long writeBufferSize) throws IOException {
796 throw new IOException("setWriteBufferSize not supported");
797 }
798
799 @Override
800 public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
801 long amount, boolean writeToWAL) throws IOException {
802 throw new IOException("incrementColumnValue not supported");
803 }
804
805 @Override
806 public <R extends Message> Map<byte[], R> batchCoprocessorService(
807 Descriptors.MethodDescriptor method, Message request,
808 byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable {
809 throw new UnsupportedOperationException("batchCoprocessorService not implemented");
810 }
811
812 @Override
813 public <R extends Message> void batchCoprocessorService(
814 Descriptors.MethodDescriptor method, Message request,
815 byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback)
816 throws ServiceException, Throwable {
817 throw new UnsupportedOperationException("batchCoprocessorService not implemented");
818 }
819
820 @Override
821 public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp,
822 byte[] value, RowMutations mutation) throws IOException {
823 throw new UnsupportedOperationException("checkAndMutate not implemented");
824 }
825 }