001/*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.rest;
020
021import java.io.IOException;
022import java.util.Iterator;
023import java.util.NoSuchElementException;
024
025import org.apache.hadoop.hbase.Cell;
026import org.apache.hadoop.hbase.CellUtil;
027import org.apache.hadoop.hbase.DoNotRetryIOException;
028import org.apache.hadoop.hbase.client.Get;
029import org.apache.hadoop.hbase.client.Result;
030import org.apache.hadoop.hbase.client.Table;
031import org.apache.hadoop.hbase.filter.Filter;
032import org.apache.hadoop.hbase.security.AccessDeniedException;
033
034import org.apache.hadoop.util.StringUtils;
035
036import org.apache.yetus.audience.InterfaceAudience;
037
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041@InterfaceAudience.Private
042public class RowResultGenerator extends ResultGenerator {
043  private static final Logger LOG = LoggerFactory.getLogger(RowResultGenerator.class);
044
045  private Iterator<Cell> valuesI;
046  private Cell cache;
047
048  public RowResultGenerator(final String tableName, final RowSpec rowspec,
049      final Filter filter, final boolean cacheBlocks)
050      throws IllegalArgumentException, IOException {
051    try (Table table = RESTServlet.getInstance().getTable(tableName)) {
052      Get get = new Get(rowspec.getRow());
053      if (rowspec.hasColumns()) {
054        for (byte[] col : rowspec.getColumns()) {
055          byte[][] split = CellUtil.parseColumn(col);
056          if (split.length == 1) {
057            get.addFamily(split[0]);
058          } else if (split.length == 2) {
059            get.addColumn(split[0], split[1]);
060          } else {
061            throw new IllegalArgumentException("Invalid column specifier.");
062          }
063        }
064      }
065      get.setTimeRange(rowspec.getStartTime(), rowspec.getEndTime());
066      get.readVersions(rowspec.getMaxVersions());
067      if (filter != null) {
068        get.setFilter(filter);
069      }
070      get.setCacheBlocks(cacheBlocks);
071      Result result = table.get(get);
072      if (result != null && !result.isEmpty()) {
073        valuesI = result.listCells().iterator();
074      }
075    } catch (DoNotRetryIOException e) {
076      // Warn here because Stargate will return 404 in the case if multiple
077      // column families were specified but one did not exist -- currently
078      // HBase will fail the whole Get.
079      // Specifying multiple columns in a URI should be uncommon usage but
080      // help to avoid confusion by leaving a record of what happened here in
081      // the log.
082      LOG.warn(StringUtils.stringifyException(e));
083      // Lets get the exception rethrown to get a more meaningful error message than 404
084      if (e instanceof AccessDeniedException) {
085        throw e;
086      }
087    }
088  }
089
090  @Override
091  public void close() {
092  }
093
094  @Override
095  public boolean hasNext() {
096    if (cache != null) {
097      return true;
098    }
099    if (valuesI == null) {
100      return false;
101    }
102    return valuesI.hasNext();
103  }
104
105  @Override
106  public Cell next() {
107    if (cache != null) {
108      Cell kv = cache;
109      cache = null;
110      return kv;
111    }
112    if (valuesI == null) {
113      return null;
114    }
115    try {
116      return valuesI.next();
117    } catch (NoSuchElementException e) {
118      return null;
119    }
120  }
121
122  @Override
123  public void putBack(Cell kv) {
124    this.cache = kv;
125  }
126
127  @Override
128  public void remove() {
129    throw new UnsupportedOperationException("remove not supported");
130  }
131}