View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
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   * HTable interface to remote tables accessed via REST gateway
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           // this is an unqualified family. append the family name and NO ':'
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             // Puts use byte[] but Deletes use KeyValue
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    * Constructor
213    * @param client
214    * @param name
215    */
216   public RemoteHTable(Client client, String name) {
217     this(client, HBaseConfiguration.create(), Bytes.toBytes(name));
218   }
219 
220   /**
221    * Constructor
222    * @param client
223    * @param conf
224    * @param name
225    */
226   public RemoteHTable(Client client, Configuration conf, String name) {
227     this(client, conf, Bytes.toBytes(name));
228   }
229 
230   /**
231    * Constructor
232    * @param client
233    * @param conf
234    * @param name
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           // fall through
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    * exists(List) is really a list of get() calls. Just use get().
367    * @param gets list of Get to test for the existence
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     // this is a trick: The gateway accepts multiple rows in a cell set and
406     // ignores the row specification in the URI
407 
408     // separate puts by row
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     // build the cell set
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     // build path for multiput
435     StringBuilder sb = new StringBuilder();
436     sb.append('/');
437     sb.append(Bytes.toStringBinary(name));
438     sb.append("/$multiput"); // can be any nonexistent row
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     // no-op
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     // column to check-the-value
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: // NOT-MODIFIED
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     // column to check-the-value
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: // NOT-MODIFIED
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 }