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