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.thrift2;
019
020import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_READONLY_ENABLED;
021import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_READONLY_ENABLED_DEFAULT;
022import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.appendFromThrift;
023import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.columnFamilyDescriptorFromThrift;
024import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.compareOpFromThrift;
025import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deleteFromThrift;
026import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deletesFromThrift;
027import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getFromThrift;
028import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getsFromThrift;
029import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.incrementFromThrift;
030import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorFromHBase;
031import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorFromThrift;
032import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorsFromHBase;
033import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putFromThrift;
034import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putsFromThrift;
035import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.resultFromHBase;
036import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.resultsFromHBase;
037import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.rowMutationsFromThrift;
038import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.scanFromThrift;
039import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.splitKeyFromThrift;
040import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorFromHBase;
041import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorFromThrift;
042import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorsFromHBase;
043import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableNameFromThrift;
044import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableNamesFromHBase;
045import static org.apache.thrift.TBaseHelper.byteBufferToByteArray;
046
047import java.io.IOException;
048import java.nio.ByteBuffer;
049import java.util.ArrayList;
050import java.util.Collections;
051import java.util.List;
052import java.util.Set;
053import java.util.regex.Pattern;
054import org.apache.hadoop.conf.Configuration;
055import org.apache.hadoop.hbase.DoNotRetryIOException;
056import org.apache.hadoop.hbase.HRegionLocation;
057import org.apache.hadoop.hbase.NamespaceDescriptor;
058import org.apache.hadoop.hbase.ServerName;
059import org.apache.hadoop.hbase.TableName;
060import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
061import org.apache.hadoop.hbase.client.LogQueryFilter;
062import org.apache.hadoop.hbase.client.OnlineLogRecord;
063import org.apache.hadoop.hbase.client.RegionLocator;
064import org.apache.hadoop.hbase.client.ResultScanner;
065import org.apache.hadoop.hbase.client.Table;
066import org.apache.hadoop.hbase.client.TableDescriptor;
067import org.apache.hadoop.hbase.security.UserProvider;
068import org.apache.hadoop.hbase.security.access.AccessControlClient;
069import org.apache.hadoop.hbase.security.access.Permission;
070import org.apache.hadoop.hbase.thrift.HBaseServiceHandler;
071import org.apache.hadoop.hbase.thrift2.generated.TAccessControlEntity;
072import org.apache.hadoop.hbase.thrift2.generated.TAppend;
073import org.apache.hadoop.hbase.thrift2.generated.TColumnFamilyDescriptor;
074import org.apache.hadoop.hbase.thrift2.generated.TCompareOperator;
075import org.apache.hadoop.hbase.thrift2.generated.TDelete;
076import org.apache.hadoop.hbase.thrift2.generated.TGet;
077import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
078import org.apache.hadoop.hbase.thrift2.generated.THRegionLocation;
079import org.apache.hadoop.hbase.thrift2.generated.TIOError;
080import org.apache.hadoop.hbase.thrift2.generated.TIllegalArgument;
081import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
082import org.apache.hadoop.hbase.thrift2.generated.TLogQueryFilter;
083import org.apache.hadoop.hbase.thrift2.generated.TNamespaceDescriptor;
084import org.apache.hadoop.hbase.thrift2.generated.TOnlineLogRecord;
085import org.apache.hadoop.hbase.thrift2.generated.TPermissionScope;
086import org.apache.hadoop.hbase.thrift2.generated.TPut;
087import org.apache.hadoop.hbase.thrift2.generated.TResult;
088import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
089import org.apache.hadoop.hbase.thrift2.generated.TScan;
090import org.apache.hadoop.hbase.thrift2.generated.TServerName;
091import org.apache.hadoop.hbase.thrift2.generated.TTableDescriptor;
092import org.apache.hadoop.hbase.thrift2.generated.TTableName;
093import org.apache.hadoop.hbase.thrift2.generated.TThriftServerType;
094import org.apache.hadoop.hbase.util.Bytes;
095import org.apache.thrift.TException;
096import org.apache.yetus.audience.InterfaceAudience;
097import org.slf4j.Logger;
098import org.slf4j.LoggerFactory;
099
100/**
101 * This class is a glue object that connects Thrift RPC calls to the HBase client API primarily
102 * defined in the Table interface.
103 */
104@InterfaceAudience.Private
105@SuppressWarnings("deprecation")
106public class ThriftHBaseServiceHandler extends HBaseServiceHandler implements THBaseService.Iface {
107
108  // TODO: Size of pool configuraple
109  private static final Logger LOG = LoggerFactory.getLogger(ThriftHBaseServiceHandler.class);
110
111  private static final IOException ioe =
112    new DoNotRetryIOException("Thrift Server is in Read-only mode.");
113  private boolean isReadOnly;
114
115  private static class TIOErrorWithCause extends TIOError {
116    private Throwable cause;
117
118    public TIOErrorWithCause(Throwable cause) {
119      super();
120      this.cause = cause;
121    }
122
123    @Override
124    public synchronized Throwable getCause() {
125      return cause;
126    }
127
128    @Override
129    public boolean equals(Object other) {
130      if (super.equals(other) && other instanceof TIOErrorWithCause) {
131        Throwable otherCause = ((TIOErrorWithCause) other).getCause();
132        if (this.getCause() != null) {
133          return otherCause != null && this.getCause().equals(otherCause);
134        } else {
135          return otherCause == null;
136        }
137      }
138      return false;
139    }
140
141    @Override
142    public int hashCode() {
143      int result = super.hashCode();
144      result = 31 * result + (cause != null ? cause.hashCode() : 0);
145      return result;
146    }
147  }
148
149  public ThriftHBaseServiceHandler(final Configuration conf, final UserProvider userProvider)
150    throws IOException {
151    super(conf, userProvider);
152    isReadOnly = conf.getBoolean(THRIFT_READONLY_ENABLED, THRIFT_READONLY_ENABLED_DEFAULT);
153  }
154
155  @Override
156  protected Table getTable(ByteBuffer tableName) {
157    try {
158      return connectionCache.getTable(Bytes.toString(byteBufferToByteArray(tableName)));
159    } catch (IOException ie) {
160      throw new RuntimeException(ie);
161    }
162  }
163
164  private RegionLocator getLocator(ByteBuffer tableName) {
165    try {
166      return connectionCache.getRegionLocator(byteBufferToByteArray(tableName));
167    } catch (IOException ie) {
168      throw new RuntimeException(ie);
169    }
170  }
171
172  private void closeTable(Table table) throws TIOError {
173    try {
174      table.close();
175    } catch (IOException e) {
176      throw getTIOError(e);
177    }
178  }
179
180  private TIOError getTIOError(IOException e) {
181    TIOError err = new TIOErrorWithCause(e);
182    err.setCanRetry(!(e instanceof DoNotRetryIOException));
183    err.setMessage(e.getMessage());
184    return err;
185  }
186
187  @Override
188  public boolean exists(ByteBuffer table, TGet get) throws TIOError, TException {
189    Table htable = getTable(table);
190    try {
191      return htable.exists(getFromThrift(get));
192    } catch (IOException e) {
193      throw getTIOError(e);
194    } finally {
195      closeTable(htable);
196    }
197  }
198
199  @Override
200  public List<Boolean> existsAll(ByteBuffer table, List<TGet> gets) throws TIOError, TException {
201    Table htable = getTable(table);
202    try {
203      boolean[] exists = htable.exists(getsFromThrift(gets));
204      List<Boolean> result = new ArrayList<>(exists.length);
205      for (boolean exist : exists) {
206        result.add(exist);
207      }
208      return result;
209    } catch (IOException e) {
210      throw getTIOError(e);
211    } finally {
212      closeTable(htable);
213    }
214  }
215
216  @Override
217  public TResult get(ByteBuffer table, TGet get) throws TIOError, TException {
218    Table htable = getTable(table);
219    try {
220      return resultFromHBase(htable.get(getFromThrift(get)));
221    } catch (IOException e) {
222      throw getTIOError(e);
223    } finally {
224      closeTable(htable);
225    }
226  }
227
228  @Override
229  public List<TResult> getMultiple(ByteBuffer table, List<TGet> gets) throws TIOError, TException {
230    Table htable = getTable(table);
231    try {
232      return resultsFromHBase(htable.get(getsFromThrift(gets)));
233    } catch (IOException e) {
234      throw getTIOError(e);
235    } finally {
236      closeTable(htable);
237    }
238  }
239
240  @Override
241  public void put(ByteBuffer table, TPut put) throws TIOError, TException {
242    checkReadOnlyMode();
243    Table htable = getTable(table);
244    try {
245      htable.put(putFromThrift(put));
246    } catch (IOException e) {
247      throw getTIOError(e);
248    } finally {
249      closeTable(htable);
250    }
251  }
252
253  @Override
254  public boolean checkAndPut(ByteBuffer table, ByteBuffer row, ByteBuffer family,
255    ByteBuffer qualifier, ByteBuffer value, TPut put) throws TIOError, TException {
256    checkReadOnlyMode();
257    Table htable = getTable(table);
258    try {
259      Table.CheckAndMutateBuilder builder =
260        htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
261          .qualifier(byteBufferToByteArray(qualifier));
262      if (value == null) {
263        return builder.ifNotExists().thenPut(putFromThrift(put));
264      } else {
265        return builder.ifEquals(byteBufferToByteArray(value)).thenPut(putFromThrift(put));
266      }
267    } catch (IOException e) {
268      throw getTIOError(e);
269    } finally {
270      closeTable(htable);
271    }
272  }
273
274  @Override
275  public void putMultiple(ByteBuffer table, List<TPut> puts) throws TIOError, TException {
276    checkReadOnlyMode();
277    Table htable = getTable(table);
278    try {
279      htable.put(putsFromThrift(puts));
280    } catch (IOException e) {
281      throw getTIOError(e);
282    } finally {
283      closeTable(htable);
284    }
285  }
286
287  @Override
288  public void deleteSingle(ByteBuffer table, TDelete deleteSingle) throws TIOError, TException {
289    checkReadOnlyMode();
290    Table htable = getTable(table);
291    try {
292      htable.delete(deleteFromThrift(deleteSingle));
293    } catch (IOException e) {
294      throw getTIOError(e);
295    } finally {
296      closeTable(htable);
297    }
298  }
299
300  @Override
301  public List<TDelete> deleteMultiple(ByteBuffer table, List<TDelete> deletes)
302    throws TIOError, TException {
303    checkReadOnlyMode();
304    Table htable = getTable(table);
305    try {
306      htable.delete(deletesFromThrift(deletes));
307    } catch (IOException e) {
308      throw getTIOError(e);
309    } finally {
310      closeTable(htable);
311    }
312    return Collections.emptyList();
313  }
314
315  @Override
316  public boolean checkAndMutate(ByteBuffer table, ByteBuffer row, ByteBuffer family,
317    ByteBuffer qualifier, TCompareOperator compareOp, ByteBuffer value, TRowMutations rowMutations)
318    throws TIOError, TException {
319    checkReadOnlyMode();
320    try (final Table htable = getTable(table)) {
321      return htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
322        .qualifier(byteBufferToByteArray(qualifier))
323        .ifMatches(compareOpFromThrift(compareOp), byteBufferToByteArray(value))
324        .thenMutate(rowMutationsFromThrift(rowMutations));
325    } catch (IOException e) {
326      throw getTIOError(e);
327    }
328  }
329
330  @Override
331  public boolean checkAndDelete(ByteBuffer table, ByteBuffer row, ByteBuffer family,
332    ByteBuffer qualifier, ByteBuffer value, TDelete deleteSingle) throws TIOError, TException {
333    checkReadOnlyMode();
334    Table htable = getTable(table);
335    try {
336      Table.CheckAndMutateBuilder mutateBuilder =
337        htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
338          .qualifier(byteBufferToByteArray(qualifier));
339      if (value == null) {
340        return mutateBuilder.ifNotExists().thenDelete(deleteFromThrift(deleteSingle));
341      } else {
342        return mutateBuilder.ifEquals(byteBufferToByteArray(value))
343          .thenDelete(deleteFromThrift(deleteSingle));
344      }
345    } catch (IOException e) {
346      throw getTIOError(e);
347    } finally {
348      closeTable(htable);
349    }
350  }
351
352  @Override
353  public TResult increment(ByteBuffer table, TIncrement increment) throws TIOError, TException {
354    checkReadOnlyMode();
355    Table htable = getTable(table);
356    try {
357      return resultFromHBase(htable.increment(incrementFromThrift(increment)));
358    } catch (IOException e) {
359      throw getTIOError(e);
360    } finally {
361      closeTable(htable);
362    }
363  }
364
365  @Override
366  public TResult append(ByteBuffer table, TAppend append) throws TIOError, TException {
367    checkReadOnlyMode();
368    Table htable = getTable(table);
369    try {
370      return resultFromHBase(htable.append(appendFromThrift(append)));
371    } catch (IOException e) {
372      throw getTIOError(e);
373    } finally {
374      closeTable(htable);
375    }
376  }
377
378  @Override
379  public int openScanner(ByteBuffer table, TScan scan) throws TIOError, TException {
380    Table htable = getTable(table);
381    ResultScanner resultScanner = null;
382    try {
383      resultScanner = htable.getScanner(scanFromThrift(scan));
384    } catch (IOException e) {
385      throw getTIOError(e);
386    } finally {
387      closeTable(htable);
388    }
389    return addScanner(resultScanner, false);
390  }
391
392  @Override
393  public List<TResult> getScannerRows(int scannerId, int numRows)
394    throws TIOError, TIllegalArgument, TException {
395    ResultScannerWrapper wrapper;
396    try {
397      wrapper = removeScanner(scannerId);
398    } catch (IOException e) {
399      throw getTIOError(e);
400    }
401    if (wrapper == null) {
402      TIllegalArgument ex = new TIllegalArgument();
403      ex.setMessage("Invalid scanner Id");
404      throw ex;
405    }
406    try {
407      connectionCache.updateConnectionAccessTime();
408      return resultsFromHBase(wrapper.scanner.next(numRows));
409    } catch (IOException e) {
410      throw getTIOError(e);
411    } finally {
412      addScannerBack(scannerId, wrapper);
413    }
414  }
415
416  @Override
417  public List<TResult> getScannerResults(ByteBuffer table, TScan scan, int numRows)
418    throws TIOError, TException {
419    Table htable = getTable(table);
420    List<TResult> results = null;
421    ResultScanner scanner = null;
422    try {
423      scanner = htable.getScanner(scanFromThrift(scan));
424      results = resultsFromHBase(scanner.next(numRows));
425    } catch (IOException e) {
426      throw getTIOError(e);
427    } finally {
428      if (scanner != null) {
429        scanner.close();
430      }
431      closeTable(htable);
432    }
433    return results;
434  }
435
436  @Override
437  public void closeScanner(int scannerId) throws TIOError, TIllegalArgument, TException {
438    LOG.debug("scannerClose: id=" + scannerId);
439    ResultScannerWrapper wrapper;
440    try {
441      wrapper = removeScanner(scannerId);
442    } catch (IOException e) {
443      throw getTIOError(e);
444    }
445    if (wrapper == null) {
446      LOG.warn("scanner ID: " + scannerId + "is invalid");
447      // While the scanner could be already expired,
448      // we should not throw exception here. Just log and return.
449      return;
450    }
451    wrapper.scanner.close();
452  }
453
454  @Override
455  public void mutateRow(ByteBuffer table, TRowMutations rowMutations) throws TIOError, TException {
456    checkReadOnlyMode();
457    Table htable = getTable(table);
458    try {
459      htable.mutateRow(rowMutationsFromThrift(rowMutations));
460    } catch (IOException e) {
461      throw getTIOError(e);
462    } finally {
463      closeTable(htable);
464    }
465  }
466
467  @Override
468  public List<THRegionLocation> getAllRegionLocations(ByteBuffer table)
469    throws TIOError, TException {
470    RegionLocator locator = null;
471    try {
472      locator = getLocator(table);
473      return ThriftUtilities.regionLocationsFromHBase(locator.getAllRegionLocations());
474
475    } catch (IOException e) {
476      throw getTIOError(e);
477    } finally {
478      if (locator != null) {
479        try {
480          locator.close();
481        } catch (IOException e) {
482          LOG.warn("Couldn't close the locator.", e);
483        }
484      }
485    }
486  }
487
488  @Override
489  public THRegionLocation getRegionLocation(ByteBuffer table, ByteBuffer row, boolean reload)
490    throws TIOError, TException {
491
492    RegionLocator locator = null;
493    try {
494      locator = getLocator(table);
495      byte[] rowBytes = byteBufferToByteArray(row);
496      HRegionLocation hrl = locator.getRegionLocation(rowBytes, reload);
497      return ThriftUtilities.regionLocationFromHBase(hrl);
498
499    } catch (IOException e) {
500      throw getTIOError(e);
501    } finally {
502      if (locator != null) {
503        try {
504          locator.close();
505        } catch (IOException e) {
506          LOG.warn("Couldn't close the locator.", e);
507        }
508      }
509    }
510  }
511
512  private void checkReadOnlyMode() throws TIOError {
513    if (isReadOnly()) {
514      throw getTIOError(ioe);
515    }
516  }
517
518  private boolean isReadOnly() {
519    return isReadOnly;
520  }
521
522  @Override
523  public TTableDescriptor getTableDescriptor(TTableName table) throws TIOError, TException {
524    try {
525      TableName tableName = ThriftUtilities.tableNameFromThrift(table);
526      TableDescriptor tableDescriptor = connectionCache.getAdmin().getDescriptor(tableName);
527      return tableDescriptorFromHBase(tableDescriptor);
528    } catch (IOException e) {
529      throw getTIOError(e);
530    }
531  }
532
533  @Override
534  public List<TTableDescriptor> getTableDescriptors(List<TTableName> tables)
535    throws TIOError, TException {
536    try {
537      List<TableName> tableNames = ThriftUtilities.tableNamesFromThrift(tables);
538      List<TableDescriptor> tableDescriptors =
539        connectionCache.getAdmin().listTableDescriptors(tableNames);
540      return tableDescriptorsFromHBase(tableDescriptors);
541    } catch (IOException e) {
542      throw getTIOError(e);
543    }
544  }
545
546  @Override
547  public boolean tableExists(TTableName tTableName) throws TIOError, TException {
548    try {
549      TableName tableName = tableNameFromThrift(tTableName);
550      return connectionCache.getAdmin().tableExists(tableName);
551    } catch (IOException e) {
552      throw getTIOError(e);
553    }
554  }
555
556  @Override
557  public List<TTableDescriptor> getTableDescriptorsByPattern(String regex, boolean includeSysTables)
558    throws TIOError, TException {
559    try {
560      Pattern pattern = (regex == null ? null : Pattern.compile(regex));
561      List<TableDescriptor> tableDescriptors =
562        connectionCache.getAdmin().listTableDescriptors(pattern, includeSysTables);
563      return tableDescriptorsFromHBase(tableDescriptors);
564    } catch (IOException e) {
565      throw getTIOError(e);
566    }
567  }
568
569  @Override
570  public List<TTableDescriptor> getTableDescriptorsByNamespace(String name)
571    throws TIOError, TException {
572    try {
573      List<TableDescriptor> descriptors =
574        connectionCache.getAdmin().listTableDescriptorsByNamespace(Bytes.toBytes(name));
575      return tableDescriptorsFromHBase(descriptors);
576    } catch (IOException e) {
577      throw getTIOError(e);
578    }
579  }
580
581  @Override
582  public List<TTableName> getTableNamesByPattern(String regex, boolean includeSysTables)
583    throws TIOError, TException {
584    try {
585      Pattern pattern = (regex == null ? null : Pattern.compile(regex));
586      TableName[] tableNames = connectionCache.getAdmin().listTableNames(pattern, includeSysTables);
587      return tableNamesFromHBase(tableNames);
588    } catch (IOException e) {
589      throw getTIOError(e);
590    }
591  }
592
593  @Override
594  public List<TTableName> getTableNamesByNamespace(String name) throws TIOError, TException {
595    try {
596      TableName[] tableNames = connectionCache.getAdmin().listTableNamesByNamespace(name);
597      return tableNamesFromHBase(tableNames);
598    } catch (IOException e) {
599      throw getTIOError(e);
600    }
601  }
602
603  @Override
604  public void createTable(TTableDescriptor desc, List<ByteBuffer> splitKeys)
605    throws TIOError, TException {
606    try {
607      TableDescriptor descriptor = tableDescriptorFromThrift(desc);
608      byte[][] split = splitKeyFromThrift(splitKeys);
609      if (split != null) {
610        connectionCache.getAdmin().createTable(descriptor, split);
611      } else {
612        connectionCache.getAdmin().createTable(descriptor);
613      }
614    } catch (IOException e) {
615      throw getTIOError(e);
616    }
617  }
618
619  @Override
620  public void deleteTable(TTableName tableName) throws TIOError, TException {
621    try {
622      TableName table = tableNameFromThrift(tableName);
623      connectionCache.getAdmin().deleteTable(table);
624    } catch (IOException e) {
625      throw getTIOError(e);
626    }
627  }
628
629  @Override
630  public void truncateTable(TTableName tableName, boolean preserveSplits)
631    throws TIOError, TException {
632    try {
633      TableName table = tableNameFromThrift(tableName);
634      connectionCache.getAdmin().truncateTable(table, preserveSplits);
635    } catch (IOException e) {
636      throw getTIOError(e);
637    }
638  }
639
640  @Override
641  public void enableTable(TTableName tableName) throws TIOError, TException {
642    try {
643      TableName table = tableNameFromThrift(tableName);
644      connectionCache.getAdmin().enableTable(table);
645    } catch (IOException e) {
646      throw getTIOError(e);
647    }
648  }
649
650  @Override
651  public void disableTable(TTableName tableName) throws TIOError, TException {
652    try {
653      TableName table = tableNameFromThrift(tableName);
654      connectionCache.getAdmin().disableTable(table);
655    } catch (IOException e) {
656      throw getTIOError(e);
657    }
658  }
659
660  @Override
661  public boolean isTableEnabled(TTableName tableName) throws TIOError, TException {
662    try {
663      TableName table = tableNameFromThrift(tableName);
664      return connectionCache.getAdmin().isTableEnabled(table);
665    } catch (IOException e) {
666      throw getTIOError(e);
667    }
668  }
669
670  @Override
671  public boolean isTableDisabled(TTableName tableName) throws TIOError, TException {
672    try {
673      TableName table = tableNameFromThrift(tableName);
674      return connectionCache.getAdmin().isTableDisabled(table);
675    } catch (IOException e) {
676      throw getTIOError(e);
677    }
678  }
679
680  @Override
681  public boolean isTableAvailable(TTableName tableName) throws TIOError, TException {
682    try {
683      TableName table = tableNameFromThrift(tableName);
684      return connectionCache.getAdmin().isTableAvailable(table);
685    } catch (IOException e) {
686      throw getTIOError(e);
687    }
688  }
689
690  @Override
691  public void addColumnFamily(TTableName tableName, TColumnFamilyDescriptor column)
692    throws TIOError, TException {
693    try {
694      TableName table = tableNameFromThrift(tableName);
695      ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorFromThrift(column);
696      connectionCache.getAdmin().addColumnFamily(table, columnFamilyDescriptor);
697    } catch (IOException e) {
698      throw getTIOError(e);
699    }
700  }
701
702  @Override
703  public void deleteColumnFamily(TTableName tableName, ByteBuffer column)
704    throws TIOError, TException {
705    try {
706      TableName table = tableNameFromThrift(tableName);
707      connectionCache.getAdmin().deleteColumnFamily(table, column.array());
708    } catch (IOException e) {
709      throw getTIOError(e);
710    }
711  }
712
713  @Override
714  public void modifyColumnFamily(TTableName tableName, TColumnFamilyDescriptor column)
715    throws TIOError, TException {
716    try {
717      TableName table = tableNameFromThrift(tableName);
718      ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorFromThrift(column);
719      connectionCache.getAdmin().modifyColumnFamily(table, columnFamilyDescriptor);
720    } catch (IOException e) {
721      throw getTIOError(e);
722    }
723  }
724
725  @Override
726  public void modifyTable(TTableDescriptor desc) throws TIOError, TException {
727    try {
728      TableDescriptor descriptor = tableDescriptorFromThrift(desc);
729      connectionCache.getAdmin().modifyTable(descriptor);
730    } catch (IOException e) {
731      throw getTIOError(e);
732    }
733  }
734
735  @Override
736  public void createNamespace(TNamespaceDescriptor namespaceDesc) throws TIOError, TException {
737    try {
738      NamespaceDescriptor descriptor = namespaceDescriptorFromThrift(namespaceDesc);
739      connectionCache.getAdmin().createNamespace(descriptor);
740    } catch (IOException e) {
741      throw getTIOError(e);
742    }
743  }
744
745  @Override
746  public void modifyNamespace(TNamespaceDescriptor namespaceDesc) throws TIOError, TException {
747    try {
748      NamespaceDescriptor descriptor = namespaceDescriptorFromThrift(namespaceDesc);
749      connectionCache.getAdmin().modifyNamespace(descriptor);
750    } catch (IOException e) {
751      throw getTIOError(e);
752    }
753  }
754
755  @Override
756  public void deleteNamespace(String name) throws TIOError, TException {
757    try {
758      connectionCache.getAdmin().deleteNamespace(name);
759    } catch (IOException e) {
760      throw getTIOError(e);
761    }
762  }
763
764  @Override
765  public TNamespaceDescriptor getNamespaceDescriptor(String name) throws TIOError, TException {
766    try {
767      NamespaceDescriptor descriptor = connectionCache.getAdmin().getNamespaceDescriptor(name);
768      return namespaceDescriptorFromHBase(descriptor);
769    } catch (IOException e) {
770      throw getTIOError(e);
771    }
772  }
773
774  @Override
775  public List<String> listNamespaces() throws TIOError, TException {
776    try {
777      String[] namespaces = connectionCache.getAdmin().listNamespaces();
778      List<String> result = new ArrayList<>(namespaces.length);
779      for (String ns : namespaces) {
780        result.add(ns);
781      }
782      return result;
783    } catch (IOException e) {
784      throw getTIOError(e);
785    }
786  }
787
788  @Override
789  public TThriftServerType getThriftServerType() {
790    return TThriftServerType.TWO;
791  }
792
793  @Override
794  public String getClusterId() throws TException {
795    return connectionCache.getClusterId();
796  }
797
798  @Override
799  public List<TOnlineLogRecord> getSlowLogResponses(Set<TServerName> tServerNames,
800    TLogQueryFilter tLogQueryFilter) throws TIOError, TException {
801    try {
802      Set<ServerName> serverNames = ThriftUtilities.getServerNamesFromThrift(tServerNames);
803      LogQueryFilter logQueryFilter = ThriftUtilities.getSlowLogQueryFromThrift(tLogQueryFilter);
804      List<OnlineLogRecord> onlineLogRecords =
805        connectionCache.getAdmin().getSlowLogResponses(serverNames, logQueryFilter);
806      return ThriftUtilities.getSlowLogRecordsFromHBase(onlineLogRecords);
807    } catch (IOException e) {
808      throw getTIOError(e);
809    }
810  }
811
812  @Override
813  public List<Boolean> clearSlowLogResponses(Set<TServerName> tServerNames)
814    throws TIOError, TException {
815    Set<ServerName> serverNames = ThriftUtilities.getServerNamesFromThrift(tServerNames);
816    try {
817      return connectionCache.getAdmin().clearSlowLogResponses(serverNames);
818    } catch (IOException e) {
819      throw getTIOError(e);
820    }
821  }
822
823  @Override
824  public boolean grant(TAccessControlEntity info) throws TIOError, TException {
825    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
826    try {
827      if (info.scope == TPermissionScope.NAMESPACE) {
828        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), info.getNsName(),
829          info.getUsername(), actions);
830      } else if (info.scope == TPermissionScope.TABLE) {
831        TableName tableName = TableName.valueOf(info.getTableName());
832        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), tableName,
833          info.getUsername(), null, null, actions);
834      }
835    } catch (Throwable t) {
836      if (t instanceof IOException) {
837        throw getTIOError((IOException) t);
838      } else {
839        throw getTIOError(new DoNotRetryIOException(t.getMessage()));
840      }
841    }
842    return true;
843  }
844
845  @Override
846  public boolean revoke(TAccessControlEntity info) throws TIOError, TException {
847    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
848    try {
849      if (info.scope == TPermissionScope.NAMESPACE) {
850        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), info.getNsName(),
851          info.getUsername(), actions);
852      } else if (info.scope == TPermissionScope.TABLE) {
853        TableName tableName = TableName.valueOf(info.getTableName());
854        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), tableName,
855          info.getUsername(), null, null, actions);
856      }
857    } catch (Throwable t) {
858      if (t instanceof IOException) {
859        throw getTIOError((IOException) t);
860      } else {
861        throw getTIOError(new DoNotRetryIOException(t.getMessage()));
862      }
863    }
864    return true;
865  }
866
867  @Override
868  public List<TNamespaceDescriptor> listNamespaceDescriptors() throws TIOError, TException {
869    try {
870      NamespaceDescriptor[] descriptors = connectionCache.getAdmin().listNamespaceDescriptors();
871      return namespaceDescriptorsFromHBase(descriptors);
872    } catch (IOException e) {
873      throw getTIOError(e);
874    }
875  }
876}