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