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