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.thrift;
019
020import static org.apache.hadoop.hbase.util.Bytes.getBytes;
021
022import java.nio.ByteBuffer;
023import java.util.ArrayList;
024import java.util.HashSet;
025import java.util.List;
026import java.util.Locale;
027import java.util.Set;
028import java.util.TreeMap;
029import org.apache.hadoop.hbase.Cell;
030import org.apache.hadoop.hbase.CellUtil;
031import org.apache.hadoop.hbase.KeyValue;
032import org.apache.hadoop.hbase.client.Append;
033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
034import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
035import org.apache.hadoop.hbase.client.Increment;
036import org.apache.hadoop.hbase.client.Result;
037import org.apache.hadoop.hbase.io.compress.Compression;
038import org.apache.hadoop.hbase.regionserver.BloomType;
039import org.apache.hadoop.hbase.security.access.Permission;
040import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
041import org.apache.hadoop.hbase.thrift.generated.IllegalArgument;
042import org.apache.hadoop.hbase.thrift.generated.TAppend;
043import org.apache.hadoop.hbase.thrift.generated.TCell;
044import org.apache.hadoop.hbase.thrift.generated.TColumn;
045import org.apache.hadoop.hbase.thrift.generated.TIncrement;
046import org.apache.hadoop.hbase.thrift.generated.TRowResult;
047import org.apache.hadoop.hbase.util.Bytes;
048import org.apache.yetus.audience.InterfaceAudience;
049
050@InterfaceAudience.Private
051public final class ThriftUtilities {
052  private ThriftUtilities() {
053  }
054
055  /**
056   * This utility method creates a new Hbase HColumnDescriptor object based on a Thrift
057   * ColumnDescriptor "struct".
058   * @param in Thrift ColumnDescriptor object
059   * @throws IllegalArgument if the column name is empty
060   */
061  public static ColumnFamilyDescriptor colDescFromThrift(ColumnDescriptor in)
062    throws IllegalArgument {
063    Compression.Algorithm comp =
064      Compression.getCompressionAlgorithmByName(in.compression.toLowerCase(Locale.ROOT));
065    BloomType bt = BloomType.valueOf(in.bloomFilterType);
066
067    if (in.name == null || !in.name.hasRemaining()) {
068      throw new IllegalArgument("column name is empty");
069    }
070    byte[] parsedName = CellUtil.parseColumn(Bytes.getBytes(in.name))[0];
071    return ColumnFamilyDescriptorBuilder.newBuilder(parsedName).setMaxVersions(in.maxVersions)
072      .setCompressionType(comp).setInMemory(in.inMemory).setBlockCacheEnabled(in.blockCacheEnabled)
073      .setTimeToLive(in.timeToLive > 0 ? in.timeToLive : Integer.MAX_VALUE).setBloomFilterType(bt)
074      .build();
075  }
076
077  /**
078   * This utility method creates a new Thrift ColumnDescriptor "struct" based on an Hbase
079   * HColumnDescriptor object. Hbase HColumnDescriptor object
080   * @return Thrift ColumnDescriptor
081   */
082  public static ColumnDescriptor colDescFromHbase(ColumnFamilyDescriptor in) {
083    ColumnDescriptor col = new ColumnDescriptor();
084    col.name = ByteBuffer.wrap(Bytes.add(in.getName(), KeyValue.COLUMN_FAMILY_DELIM_ARRAY));
085    col.maxVersions = in.getMaxVersions();
086    col.compression = in.getCompressionType().toString();
087    col.inMemory = in.isInMemory();
088    col.blockCacheEnabled = in.isBlockCacheEnabled();
089    col.bloomFilterType = in.getBloomFilterType().toString();
090    col.timeToLive = in.getTimeToLive();
091    return col;
092  }
093
094  /**
095   * This utility method creates a list of Thrift TCell "struct" based on an Hbase Cell object. The
096   * empty list is returned if the input is null. Hbase Cell object
097   * @return Thrift TCell array
098   */
099  public static List<TCell> cellFromHBase(Cell in) {
100    List<TCell> list = new ArrayList<>(1);
101    if (in != null) {
102      list.add(new TCell(ByteBuffer.wrap(CellUtil.cloneValue(in)), in.getTimestamp()));
103    }
104    return list;
105  }
106
107  /**
108   * This utility method creates a list of Thrift TCell "struct" based on an Hbase Cell array. The
109   * empty list is returned if the input is null.
110   * @param in Hbase Cell array
111   * @return Thrift TCell array
112   */
113  public static List<TCell> cellFromHBase(Cell[] in) {
114    List<TCell> list = null;
115    if (in != null) {
116      list = new ArrayList<>(in.length);
117      for (int i = 0; i < in.length; i++) {
118        list.add(new TCell(ByteBuffer.wrap(CellUtil.cloneValue(in[i])), in[i].getTimestamp()));
119      }
120    } else {
121      list = new ArrayList<>(0);
122    }
123    return list;
124  }
125
126  /**
127   * This utility method creates a list of Thrift TRowResult "struct" based on an Hbase RowResult
128   * object. The empty list is returned if the input is null. Hbase RowResult object This boolean
129   * dictates if row data is returned in a sorted order sortColumns = True will set TRowResult's
130   * sortedColumns member which is an ArrayList of TColumn struct sortColumns = False will set
131   * TRowResult's columns member which is a map of columnName and TCell struct
132   * @return Thrift TRowResult array
133   */
134  public static List<TRowResult> rowResultFromHBase(Result[] in, boolean sortColumns) {
135    List<TRowResult> results = new ArrayList<>(in.length);
136    for (Result result_ : in) {
137      if (result_ == null || result_.isEmpty()) {
138        continue;
139      }
140
141      TRowResult result = new TRowResult();
142      result.row = ByteBuffer.wrap(result_.getRow());
143
144      if (sortColumns) {
145        result.sortedColumns = new ArrayList<>();
146        for (Cell kv : result_.rawCells()) {
147          result.sortedColumns.add(new TColumn(
148            ByteBuffer
149              .wrap(CellUtil.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))),
150            new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp())));
151        }
152      } else {
153        result.columns = new TreeMap<>();
154        for (Cell kv : result_.rawCells()) {
155          result.columns.put(
156            ByteBuffer
157              .wrap(CellUtil.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))),
158            new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp()));
159        }
160      }
161
162      results.add(result);
163    }
164
165    return results;
166  }
167
168  /**
169   * This utility method creates a list of Thrift TRowResult "struct" based on an array of Hbase
170   * RowResult objects. The empty list is returned if the input is null. Array of Hbase RowResult
171   * objects
172   * @return Thrift TRowResult array
173   */
174  public static List<TRowResult> rowResultFromHBase(Result[] in) {
175    return rowResultFromHBase(in, false);
176  }
177
178  public static List<TRowResult> rowResultFromHBase(Result in) {
179    Result[] result = { in };
180    return rowResultFromHBase(result);
181  }
182
183  /**
184   * From a {@link TIncrement} create an {@link Increment}.
185   * @param tincrement the Thrift version of an increment
186   * @return an increment that the {@link TIncrement} represented.
187   */
188  public static Increment incrementFromThrift(TIncrement tincrement) {
189    Increment inc = new Increment(tincrement.getRow());
190    byte[][] famAndQf = CellUtil.parseColumn(tincrement.getColumn());
191
192    if (famAndQf.length != 2) {
193      return null;
194    }
195
196    inc.addColumn(famAndQf[0], famAndQf[1], tincrement.getAmmount());
197    return inc;
198  }
199
200  /**
201   * From a {@link TAppend} create an {@link Append}.
202   * @param tappend the Thrift version of an append.
203   * @return an increment that the {@link TAppend} represented.
204   */
205  public static Append appendFromThrift(TAppend tappend) {
206    Append append = new Append(tappend.getRow());
207    List<ByteBuffer> columns = tappend.getColumns();
208    List<ByteBuffer> values = tappend.getValues();
209
210    if (columns.size() != values.size()) {
211      throw new IllegalArgumentException(
212        "Sizes of columns and values in tappend object are not matching");
213    }
214
215    int length = columns.size();
216
217    for (int i = 0; i < length; i++) {
218      byte[][] famAndQf = CellUtil.parseColumn(getBytes(columns.get(i)));
219      append.addColumn(famAndQf[0], famAndQf[1], getBytes(values.get(i)));
220    }
221    return append;
222  }
223
224  public static Permission.Action[] permissionActionsFromString(String permission_actions) {
225    Set<Permission.Action> actions = new HashSet<>();
226    for (char c : permission_actions.toCharArray()) {
227      switch (c) {
228        case 'R':
229          actions.add(Permission.Action.READ);
230          break;
231        case 'W':
232          actions.add(Permission.Action.WRITE);
233          break;
234        case 'C':
235          actions.add(Permission.Action.CREATE);
236          break;
237        case 'X':
238          actions.add(Permission.Action.EXEC);
239          break;
240        case 'A':
241          actions.add(Permission.Action.ADMIN);
242          break;
243        default:
244          break;
245      }
246    }
247    return actions.toArray(new Permission.Action[0]);
248  }
249}