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 com.google.protobuf.Descriptors;
23  import com.google.protobuf.Message;
24  import com.google.protobuf.Service;
25  import com.google.protobuf.ServiceException;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.classification.InterfaceAudience;
29  import org.apache.hadoop.hbase.classification.InterfaceStability;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.Cell;
32  import org.apache.hadoop.hbase.CellUtil;
33  import org.apache.hadoop.hbase.HBaseConfiguration;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.HTableDescriptor;
36  import org.apache.hadoop.hbase.KeyValue;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.client.Append;
39  import org.apache.hadoop.hbase.client.Delete;
40  import org.apache.hadoop.hbase.client.Durability;
41  import org.apache.hadoop.hbase.client.Get;
42  import org.apache.hadoop.hbase.client.HTableInterface;
43  import org.apache.hadoop.hbase.client.Increment;
44  import org.apache.hadoop.hbase.client.Put;
45  import org.apache.hadoop.hbase.client.Result;
46  import org.apache.hadoop.hbase.client.ResultScanner;
47  import org.apache.hadoop.hbase.client.Row;
48  import org.apache.hadoop.hbase.client.RowMutations;
49  import org.apache.hadoop.hbase.client.Scan;
50  import org.apache.hadoop.hbase.client.coprocessor.Batch;
51  import org.apache.hadoop.hbase.client.coprocessor.Batch.Callback;
52  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
53  import org.apache.hadoop.hbase.io.TimeRange;
54  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
55  import org.apache.hadoop.hbase.rest.Constants;
56  import org.apache.hadoop.hbase.rest.model.CellModel;
57  import org.apache.hadoop.hbase.rest.model.CellSetModel;
58  import org.apache.hadoop.hbase.rest.model.RowModel;
59  import org.apache.hadoop.hbase.rest.model.ScannerModel;
60  import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
61  import org.apache.hadoop.hbase.util.Bytes;
62  import org.apache.hadoop.util.StringUtils;
63  
64  import java.io.IOException;
65  import java.io.InterruptedIOException;
66  import java.util.ArrayList;
67  import java.util.Collection;
68  import java.util.Iterator;
69  import java.util.List;
70  import java.util.Map;
71  import java.util.Set;
72  import java.util.TreeMap;
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         row.addCell(new CellModel(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell),
201           ts != HConstants.LATEST_TIMESTAMP ? ts : cell.getTimestamp(),
202           CellUtil.cloneValue(cell)));
203       }
204     }
205     CellSetModel model = new CellSetModel();
206     model.addRow(row);
207     return model;
208   }
209 
210   /**
211    * Constructor
212    * @param client
213    * @param name
214    */
215   public RemoteHTable(Client client, String name) {
216     this(client, HBaseConfiguration.create(), Bytes.toBytes(name));
217   }
218 
219   /**
220    * Constructor
221    * @param client
222    * @param conf
223    * @param name
224    */
225   public RemoteHTable(Client client, Configuration conf, String name) {
226     this(client, conf, Bytes.toBytes(name));
227   }
228 
229   /**
230    * Constructor
231    * @param client
232    * @param conf
233    * @param name
234    */
235   public RemoteHTable(Client client, Configuration conf, byte[] name) {
236     this.client = client;
237     this.conf = conf;
238     this.name = name;
239     this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10);
240     this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000);
241   }
242 
243   public byte[] getTableName() {
244     return name.clone();
245   }
246 
247   @Override
248   public TableName getName() {
249     return TableName.valueOf(name);
250   }
251 
252   public Configuration getConfiguration() {
253     return conf;
254   }
255 
256   public HTableDescriptor getTableDescriptor() throws IOException {
257     StringBuilder sb = new StringBuilder();
258     sb.append('/');
259     sb.append(Bytes.toStringBinary(name));
260     sb.append('/');
261     sb.append("schema");
262     for (int i = 0; i < maxRetries; i++) {
263       Response response = client.get(sb.toString(), Constants.MIMETYPE_PROTOBUF);
264       int code = response.getCode();
265       switch (code) {
266       case 200:
267         TableSchemaModel schema = new TableSchemaModel();
268         schema.getObjectFromMessage(response.getBody());
269         return schema.getTableDescriptor();
270       case 509:
271         try {
272           Thread.sleep(sleepTime);
273         } catch (InterruptedException e) {
274           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
275         }
276         break;
277       default:
278         throw new IOException("schema request returned " + code);
279       }
280     }
281     throw new IOException("schema request timed out");
282   }
283 
284   public void close() throws IOException {
285     client.shutdown();
286   }
287 
288   public Result get(Get get) throws IOException {
289     TimeRange range = get.getTimeRange();
290     String spec = buildRowSpec(get.getRow(), get.getFamilyMap(),
291       range.getMin(), range.getMax(), get.getMaxVersions());
292     if (get.getFilter() != null) {
293       LOG.warn("filters not supported on gets");
294     }
295     Result[] results = getResults(spec);
296     if (results.length > 0) {
297       if (results.length > 1) {
298         LOG.warn("too many results for get (" + results.length + ")");
299       }
300       return results[0];
301     } else {
302       return new Result();
303     }
304   }
305 
306   public Result[] get(List<Get> gets) throws IOException {
307     byte[][] rows = new byte[gets.size()][];
308     int maxVersions = 1;
309     int count = 0;
310 
311     for(Get g:gets) {
312 
313       if ( count == 0 ) {
314         maxVersions = g.getMaxVersions();
315       } else if (g.getMaxVersions() != maxVersions) {
316         LOG.warn("MaxVersions on Gets do not match, using the first in the list ("+maxVersions+")");
317       }
318 
319       if (g.getFilter() != null) {
320         LOG.warn("filters not supported on gets");
321       }
322 
323       rows[count] = g.getRow();
324       count ++;
325     }
326 
327     String spec = buildMultiRowSpec(rows, maxVersions);
328 
329     return getResults(spec);
330   }
331 
332   private Result[] getResults(String spec) throws IOException {
333     for (int i = 0; i < maxRetries; i++) {
334       Response response = client.get(spec, Constants.MIMETYPE_PROTOBUF);
335       int code = response.getCode();
336       switch (code) {
337         case 200:
338           CellSetModel model = new CellSetModel();
339           model.getObjectFromMessage(response.getBody());
340           Result[] results = buildResultFromModel(model);
341           if ( results.length > 0) {
342             return results;
343           }
344           // fall through
345         case 404:
346           return new Result[0];
347 
348         case 509:
349           try {
350             Thread.sleep(sleepTime);
351           } catch (InterruptedException e) {
352             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
353           }
354           break;
355         default:
356           throw new IOException("get request returned " + code);
357       }
358     }
359     throw new IOException("get request timed out");
360   }
361 
362   public boolean exists(Get get) throws IOException {
363     LOG.warn("exists() is really get(), just use get()");
364     Result result = get(get);
365     return (result != null && !(result.isEmpty()));
366   }
367 
368   /**
369    * exists(List) is really a list of get() calls. Just use get().
370    * @param gets list of Get to test for the existence
371    */
372   public boolean[] existsAll(List<Get> gets) throws IOException {
373     LOG.warn("exists(List<Get>) is really list of get() calls, just use get()");
374     boolean[] results = new boolean[gets.size()];
375     for (int i = 0; i < results.length; i++) {
376       results[i] = exists(gets.get(i));
377     }
378     return results;
379   }
380 
381   @Deprecated
382   public Boolean[] exists(List<Get> gets) throws IOException {
383     boolean[] results = existsAll(gets);
384     Boolean[] objectResults = new Boolean[results.length];
385     for (int i = 0; i < results.length; ++i) {
386       objectResults[i] = results[i];
387     }
388     return objectResults;
389   }
390 
391   public void put(Put put) throws IOException {
392     CellSetModel model = buildModelFromPut(put);
393     StringBuilder sb = new StringBuilder();
394     sb.append('/');
395     sb.append(Bytes.toStringBinary(name));
396     sb.append('/');
397     sb.append(Bytes.toStringBinary(put.getRow()));
398     for (int i = 0; i < maxRetries; i++) {
399       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
400         model.createProtobufOutput());
401       int code = response.getCode();
402       switch (code) {
403       case 200:
404         return;
405       case 509:
406         try {
407           Thread.sleep(sleepTime);
408         } catch (InterruptedException e) {
409           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
410         }
411         break;
412       default:
413         throw new IOException("put request failed with " + code);
414       }
415     }
416     throw new IOException("put request timed out");
417   }
418 
419   public void put(List<Put> puts) throws IOException {
420     // this is a trick: The gateway accepts multiple rows in a cell set and
421     // ignores the row specification in the URI
422 
423     // separate puts by row
424     TreeMap<byte[],List<Cell>> map =
425       new TreeMap<byte[],List<Cell>>(Bytes.BYTES_COMPARATOR);
426     for (Put put: puts) {
427       byte[] row = put.getRow();
428       List<Cell> cells = map.get(row);
429       if (cells == null) {
430         cells = new ArrayList<Cell>();
431         map.put(row, cells);
432       }
433       for (List<Cell> l: put.getFamilyCellMap().values()) {
434         cells.addAll(l);
435       }
436     }
437 
438     // build the cell set
439     CellSetModel model = new CellSetModel();
440     for (Map.Entry<byte[], List<Cell>> e: map.entrySet()) {
441       RowModel row = new RowModel(e.getKey());
442       for (Cell cell: e.getValue()) {
443         row.addCell(new CellModel(cell));
444       }
445       model.addRow(row);
446     }
447 
448     // build path for multiput
449     StringBuilder sb = new StringBuilder();
450     sb.append('/');
451     sb.append(Bytes.toStringBinary(name));
452     sb.append("/$multiput"); // can be any nonexistent row
453     for (int i = 0; i < maxRetries; i++) {
454       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
455         model.createProtobufOutput());
456       int code = response.getCode();
457       switch (code) {
458       case 200:
459         return;
460       case 509:
461         try {
462           Thread.sleep(sleepTime);
463         } catch (InterruptedException e) {
464           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
465         }
466         break;
467       default:
468         throw new IOException("multiput request failed with " + code);
469       }
470     }
471     throw new IOException("multiput request timed out");
472   }
473 
474   public void delete(Delete delete) throws IOException {
475     String spec = buildRowSpec(delete.getRow(), delete.getFamilyCellMap(),
476       delete.getTimeStamp(), delete.getTimeStamp(), 1);
477     for (int i = 0; i < maxRetries; i++) {
478       Response response = client.delete(spec);
479       int code = response.getCode();
480       switch (code) {
481       case 200:
482         return;
483       case 509:
484         try {
485           Thread.sleep(sleepTime);
486         } catch (InterruptedException e) {
487           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
488         }
489         break;
490       default:
491         throw new IOException("delete request failed with " + code);
492       }
493     }
494     throw new IOException("delete request timed out");
495   }
496 
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   class Scanner implements ResultScanner {
508 
509     String uri;
510 
511     public Scanner(Scan scan) throws IOException {
512       ScannerModel model;
513       try {
514         model = ScannerModel.fromScan(scan);
515       } catch (Exception e) {
516         throw new IOException(e);
517       }
518       StringBuffer sb = new StringBuffer();
519       sb.append('/');
520       sb.append(Bytes.toStringBinary(name));
521       sb.append('/');
522       sb.append("scanner");
523       for (int i = 0; i < maxRetries; i++) {
524         Response response = client.post(sb.toString(),
525           Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
526         int code = response.getCode();
527         switch (code) {
528         case 201:
529           uri = response.getLocation();
530           return;
531         case 509:
532           try {
533             Thread.sleep(sleepTime);
534           } catch (InterruptedException e) {
535             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
536           }
537           break;
538         default:
539           throw new IOException("scan request failed with " + code);
540         }
541       }
542       throw new IOException("scan request timed out");
543     }
544 
545     @Override
546     public Result[] next(int nbRows) throws IOException {
547       StringBuilder sb = new StringBuilder(uri);
548       sb.append("?n=");
549       sb.append(nbRows);
550       for (int i = 0; i < maxRetries; i++) {
551         Response response = client.get(sb.toString(),
552           Constants.MIMETYPE_PROTOBUF);
553         int code = response.getCode();
554         switch (code) {
555         case 200:
556           CellSetModel model = new CellSetModel();
557           model.getObjectFromMessage(response.getBody());
558           return buildResultFromModel(model);
559         case 204:
560         case 206:
561           return null;
562         case 509:
563           try {
564             Thread.sleep(sleepTime);
565           } catch (InterruptedException e) {
566             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
567           }
568           break;
569         default:
570           throw new IOException("scanner.next request failed with " + code);
571         }
572       }
573       throw new IOException("scanner.next request timed out");
574     }
575 
576     @Override
577     public Result next() throws IOException {
578       Result[] results = next(1);
579       if (results == null || results.length < 1) {
580         return null;
581       }
582       return results[0];
583     }
584 
585     class Iter implements Iterator<Result> {
586 
587       Result cache;
588 
589       public Iter() {
590         try {
591           cache = Scanner.this.next();
592         } catch (IOException e) {
593           LOG.warn(StringUtils.stringifyException(e));
594         }
595       }
596 
597       @Override
598       public boolean hasNext() {
599         return cache != null;
600       }
601 
602       @Override
603       public Result next() {
604         Result result = cache;
605         try {
606           cache = Scanner.this.next();
607         } catch (IOException e) {
608           LOG.warn(StringUtils.stringifyException(e));
609           cache = null;
610         }
611         return result;
612       }
613 
614       @Override
615       public void remove() {
616         throw new RuntimeException("remove() not supported");
617       }
618 
619     }
620 
621     @Override
622     public Iterator<Result> iterator() {
623       return new Iter();
624     }
625 
626     @Override
627     public void close() {
628       try {
629         client.delete(uri);
630       } catch (IOException e) {
631         LOG.warn(StringUtils.stringifyException(e));
632       }
633     }
634 
635   }
636 
637   public ResultScanner getScanner(Scan scan) throws IOException {
638     return new Scanner(scan);
639   }
640 
641   public ResultScanner getScanner(byte[] family) throws IOException {
642     Scan scan = new Scan();
643     scan.addFamily(family);
644     return new Scanner(scan);
645   }
646 
647   public ResultScanner getScanner(byte[] family, byte[] qualifier)
648       throws IOException {
649     Scan scan = new Scan();
650     scan.addColumn(family, qualifier);
651     return new Scanner(scan);
652   }
653 
654   public boolean isAutoFlush() {
655     return true;
656   }
657 
658   public Result getRowOrBefore(byte[] row, byte[] family) throws IOException {
659     throw new IOException("getRowOrBefore not supported");
660   }
661 
662   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
663       byte[] value, Put put) throws IOException {
664     // column to check-the-value
665     put.add(new KeyValue(row, family, qualifier, value));
666 
667     CellSetModel model = buildModelFromPut(put);
668     StringBuilder sb = new StringBuilder();
669     sb.append('/');
670     sb.append(Bytes.toStringBinary(name));
671     sb.append('/');
672     sb.append(Bytes.toStringBinary(put.getRow()));
673     sb.append("?check=put");
674 
675     for (int i = 0; i < maxRetries; i++) {
676       Response response = client.put(sb.toString(),
677         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
678       int code = response.getCode();
679       switch (code) {
680       case 200:
681         return true;
682       case 304: // NOT-MODIFIED
683         return false;
684       case 509:
685         try {
686           Thread.sleep(sleepTime);
687         } catch (final InterruptedException e) {
688           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
689         }
690         break;
691       default:
692         throw new IOException("checkAndPut request failed with " + code);
693       }
694     }
695     throw new IOException("checkAndPut request timed out");
696   }
697 
698   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
699       CompareOp compareOp, byte[] value, Put put) throws IOException {
700     throw new IOException("checkAndPut for non-equal comparison not implemented");
701   }
702 
703   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
704       byte[] value, Delete delete) throws IOException {
705     Put put = new Put(row);
706     // column to check-the-value
707     put.add(new KeyValue(row, family, qualifier, value));
708     CellSetModel model = buildModelFromPut(put);
709     StringBuilder sb = new StringBuilder();
710     sb.append('/');
711     sb.append(Bytes.toStringBinary(name));
712     sb.append('/');
713     sb.append(Bytes.toStringBinary(row));
714     sb.append("?check=delete");
715 
716     for (int i = 0; i < maxRetries; i++) {
717       Response response = client.put(sb.toString(),
718         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
719       int code = response.getCode();
720       switch (code) {
721       case 200:
722         return true;
723       case 304: // NOT-MODIFIED
724         return false;
725       case 509:
726         try {
727           Thread.sleep(sleepTime);
728         } catch (final InterruptedException e) {
729           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
730         }
731         break;
732       default:
733         throw new IOException("checkAndDelete request failed with " + code);
734       }
735     }
736     throw new IOException("checkAndDelete request timed out");
737   }
738 
739   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
740       CompareOp compareOp, byte[] value, Delete delete) throws IOException {
741     throw new IOException("checkAndDelete for non-equal comparison not implemented");
742   }
743 
744   public Result increment(Increment increment) throws IOException {
745     throw new IOException("Increment not supported");
746   }
747 
748   public Result append(Append append) throws IOException {
749     throw new IOException("Append not supported");
750   }
751 
752   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
753       long amount) throws IOException {
754     throw new IOException("incrementColumnValue not supported");
755   }
756 
757   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
758       long amount, Durability durability) throws IOException {
759     throw new IOException("incrementColumnValue not supported");
760   }
761 
762   @Override
763   public void batch(List<? extends Row> actions, Object[] results) throws IOException {
764     throw new IOException("batch not supported");
765   }
766 
767   @Override
768   public Object[] batch(List<? extends Row> actions) throws IOException {
769     throw new IOException("batch not supported");
770   }
771 
772   @Override
773   public <R> void batchCallback(List<? extends Row> actions, Object[] results,
774       Batch.Callback<R> callback) throws IOException, InterruptedException {
775     throw new IOException("batchCallback not supported");
776   }
777 
778   @Override
779   public <R> Object[] batchCallback(List<? extends Row> actions, Batch.Callback<R> callback)
780    throws IOException, InterruptedException {
781     throw new IOException("batchCallback not supported");
782   }
783 
784   @Override
785   public CoprocessorRpcChannel coprocessorService(byte[] row) {
786     throw new UnsupportedOperationException("coprocessorService not implemented");
787   }
788 
789   @Override
790   public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service,
791       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable)
792       throws ServiceException, Throwable {
793     throw new UnsupportedOperationException("coprocessorService not implemented");
794   }
795 
796   @Override
797   public <T extends Service, R> void coprocessorService(Class<T> service,
798       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Batch.Callback<R> callback)
799       throws ServiceException, Throwable {
800     throw new UnsupportedOperationException("coprocessorService not implemented");
801   }
802 
803   @Override
804   public void mutateRow(RowMutations rm) throws IOException {
805     throw new IOException("atomicMutation not supported");
806   }
807 
808   @Override
809   public void setAutoFlush(boolean autoFlush) {
810     throw new UnsupportedOperationException("setAutoFlush not implemented");
811   }
812 
813   @Override
814   public void setAutoFlush(boolean autoFlush, boolean clearBufferOnFail) {
815     throw new UnsupportedOperationException("setAutoFlush not implemented");
816   }
817 
818   @Override
819   public void setAutoFlushTo(boolean autoFlush) {
820     throw new UnsupportedOperationException("setAutoFlushTo not implemented");
821   }
822 
823   @Override
824   public long getWriteBufferSize() {
825     throw new UnsupportedOperationException("getWriteBufferSize not implemented");
826   }
827 
828   @Override
829   public void setWriteBufferSize(long writeBufferSize) throws IOException {
830     throw new IOException("setWriteBufferSize not supported");
831   }
832 
833   @Override
834   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
835       long amount, boolean writeToWAL) throws IOException {
836     throw new IOException("incrementColumnValue not supported");
837   }
838 
839   @Override
840   public <R extends Message> Map<byte[], R> batchCoprocessorService(
841       Descriptors.MethodDescriptor method, Message request,
842       byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable {
843     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
844   }
845 
846   @Override
847   public <R extends Message> void batchCoprocessorService(
848       Descriptors.MethodDescriptor method, Message request,
849       byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback)
850       throws ServiceException, Throwable {
851     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
852   }
853 
854   @Override public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier,
855       CompareOp compareOp, byte[] value, RowMutations rm) throws IOException {
856     throw new UnsupportedOperationException("checkAndMutate not implemented");
857   }
858 }