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.rest;
019
020import java.io.IOException;
021import java.util.Iterator;
022import java.util.NoSuchElementException;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.CellUtil;
025import org.apache.hadoop.hbase.DoNotRetryIOException;
026import org.apache.hadoop.hbase.client.Get;
027import org.apache.hadoop.hbase.client.Result;
028import org.apache.hadoop.hbase.client.Table;
029import org.apache.hadoop.hbase.filter.Filter;
030import org.apache.hadoop.hbase.security.AccessDeniedException;
031import org.apache.hadoop.util.StringUtils;
032import org.apache.yetus.audience.InterfaceAudience;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036@InterfaceAudience.Private
037public class RowResultGenerator extends ResultGenerator {
038  private static final Logger LOG = LoggerFactory.getLogger(RowResultGenerator.class);
039
040  private Iterator<Cell> valuesI;
041  private Cell cache;
042
043  public RowResultGenerator(final String tableName, final RowSpec rowspec, final Filter filter,
044    final boolean cacheBlocks) throws IllegalArgumentException, IOException {
045    try (Table table = RESTServlet.getInstance().getTable(tableName)) {
046      Get get = new Get(rowspec.getRow());
047      if (rowspec.hasColumns()) {
048        for (byte[] col : rowspec.getColumns()) {
049          byte[][] split = CellUtil.parseColumn(col);
050          if (split.length == 1) {
051            get.addFamily(split[0]);
052          } else if (split.length == 2) {
053            get.addColumn(split[0], split[1]);
054          } else {
055            throw new IllegalArgumentException("Invalid column specifier.");
056          }
057        }
058      }
059      get.setTimeRange(rowspec.getStartTime(), rowspec.getEndTime());
060      get.readVersions(rowspec.getMaxVersions());
061      if (filter != null) {
062        get.setFilter(filter);
063      }
064      get.setCacheBlocks(cacheBlocks);
065      Result result = table.get(get);
066      if (result != null && !result.isEmpty()) {
067        valuesI = result.listCells().iterator();
068      }
069    } catch (DoNotRetryIOException e) {
070      // Warn here because Stargate will return 404 in the case if multiple
071      // column families were specified but one did not exist -- currently
072      // HBase will fail the whole Get.
073      // Specifying multiple columns in a URI should be uncommon usage but
074      // help to avoid confusion by leaving a record of what happened here in
075      // the log.
076      LOG.warn(StringUtils.stringifyException(e));
077      // Lets get the exception rethrown to get a more meaningful error message than 404
078      if (e instanceof AccessDeniedException) {
079        throw e;
080      }
081    }
082  }
083
084  @Override
085  public void close() {
086  }
087
088  @Override
089  public boolean hasNext() {
090    if (cache != null) {
091      return true;
092    }
093    if (valuesI == null) {
094      return false;
095    }
096    return valuesI.hasNext();
097  }
098
099  @Override
100  public Cell next() {
101    if (cache != null) {
102      Cell kv = cache;
103      cache = null;
104      return kv;
105    }
106    if (valuesI == null) {
107      return null;
108    }
109    try {
110      return valuesI.next();
111    } catch (NoSuchElementException e) {
112      return null;
113    }
114  }
115
116  @Override
117  public void putBack(Cell kv) {
118    this.cache = kv;
119  }
120
121  @Override
122  public void remove() {
123    throw new UnsupportedOperationException("remove not supported");
124  }
125}