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 */
019
020package org.apache.hadoop.hbase.rest;
021
022import java.io.IOException;
023import java.util.List;
024import javax.ws.rs.DefaultValue;
025import javax.ws.rs.Encoded;
026import javax.ws.rs.Path;
027import javax.ws.rs.PathParam;
028import javax.ws.rs.QueryParam;
029import org.apache.commons.lang3.StringUtils;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.yetus.audience.InterfaceAudience;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034import org.apache.hadoop.hbase.client.Scan;
035import org.apache.hadoop.hbase.client.Table;
036import org.apache.hadoop.hbase.filter.Filter;
037import org.apache.hadoop.hbase.filter.FilterList;
038import org.apache.hadoop.hbase.filter.ParseFilter;
039import org.apache.hadoop.hbase.filter.PrefixFilter;
040import org.apache.hadoop.hbase.util.Bytes;
041
042@InterfaceAudience.Private
043public class TableResource extends ResourceBase {
044
045  String table;
046  private static final Logger LOG = LoggerFactory.getLogger(TableResource.class);
047
048  /**
049   * Constructor
050   * @param table
051   * @throws IOException
052   */
053  public TableResource(String table) throws IOException {
054    super();
055    this.table = table;
056  }
057
058  /** @return the table name */
059  String getName() {
060    return table;
061  }
062
063  /**
064   * @return true if the table exists
065   * @throws IOException
066   */
067  boolean exists() throws IOException {
068    return servlet.getAdmin().tableExists(TableName.valueOf(table));
069  }
070
071  @Path("exists")
072  public ExistsResource getExistsResource() throws IOException {
073    return new ExistsResource(this);
074  }
075
076  @Path("regions")
077  public RegionsResource getRegionsResource() throws IOException {
078    return new RegionsResource(this);
079  }
080
081  @Path("scanner")
082  public ScannerResource getScannerResource() throws IOException {
083    return new ScannerResource(this);
084  }
085
086  @Path("schema")
087  public SchemaResource getSchemaResource() throws IOException {
088    return new SchemaResource(this);
089  }
090
091  @Path("{multiget: multiget.*}")
092  public MultiRowResource getMultipleRowResource(final @QueryParam("v") String versions,
093      @PathParam("multiget") String path) throws IOException {
094    return new MultiRowResource(this, versions, path.replace("multiget", "").replace("/", ""));
095  }
096
097  @Path("{rowspec: [^*]+}")
098  public RowResource getRowResource(
099      // We need the @Encoded decorator so Jersey won't urldecode before
100      // the RowSpec constructor has a chance to parse
101      final @PathParam("rowspec") @Encoded String rowspec,
102      final @QueryParam("v") String versions,
103      final @QueryParam("check") String check,
104      final @QueryParam("rr") String returnResult) throws IOException {
105    return new RowResource(this, rowspec, versions, check, returnResult);
106  }
107
108  @Path("{suffixglobbingspec: .*\\*/.+}")
109  public RowResource getRowResourceWithSuffixGlobbing(
110      // We need the @Encoded decorator so Jersey won't urldecode before
111      // the RowSpec constructor has a chance to parse
112      final @PathParam("suffixglobbingspec") @Encoded String suffixglobbingspec,
113      final @QueryParam("v") String versions,
114      final @QueryParam("check") String check,
115      final @QueryParam("rr") String returnResult) throws IOException {
116    return new RowResource(this, suffixglobbingspec, versions, check, returnResult);
117  }
118
119  @Path("{scanspec: .*[*]$}")
120  public TableScanResource  getScanResource(
121      final @PathParam("scanspec") String scanSpec,
122      @DefaultValue(Integer.MAX_VALUE + "")
123      @QueryParam(Constants.SCAN_LIMIT) int userRequestedLimit,
124      @DefaultValue("") @QueryParam(Constants.SCAN_START_ROW) String startRow,
125      @DefaultValue("") @QueryParam(Constants.SCAN_END_ROW) String endRow,
126      @DefaultValue("") @QueryParam(Constants.SCAN_COLUMN) List<String> column,
127      @DefaultValue("1") @QueryParam(Constants.SCAN_MAX_VERSIONS) int maxVersions,
128      @DefaultValue("-1") @QueryParam(Constants.SCAN_BATCH_SIZE) int batchSize,
129      @DefaultValue("0") @QueryParam(Constants.SCAN_START_TIME) long startTime,
130      @DefaultValue(Long.MAX_VALUE + "") @QueryParam(Constants.SCAN_END_TIME) long endTime,
131      @DefaultValue("true") @QueryParam(Constants.SCAN_CACHE_BLOCKS) boolean cacheBlocks,
132      @DefaultValue("false") @QueryParam(Constants.SCAN_REVERSED) boolean reversed,
133      @DefaultValue("") @QueryParam(Constants.SCAN_FILTER) String paramFilter) {
134    try {
135      Filter prefixFilter = null;
136      Scan tableScan = new Scan();
137      if (scanSpec.indexOf('*') > 0) {
138        String prefix = scanSpec.substring(0, scanSpec.indexOf('*'));
139        byte[] prefixBytes = Bytes.toBytes(prefix);
140        prefixFilter = new PrefixFilter(Bytes.toBytes(prefix));
141        if (startRow.isEmpty()) {
142          tableScan.setStartRow(prefixBytes);
143        }
144      }
145      if (LOG.isTraceEnabled()) {
146        LOG.trace("Query parameters  : Table Name = > " + this.table + " Start Row => " + startRow
147            + " End Row => " + endRow + " Columns => " + column + " Start Time => " + startTime
148            + " End Time => " + endTime + " Cache Blocks => " + cacheBlocks + " Max Versions => "
149            + maxVersions + " Batch Size => " + batchSize);
150      }
151      Table hTable = RESTServlet.getInstance().getTable(this.table);
152      tableScan.setBatch(batchSize);
153      tableScan.setMaxVersions(maxVersions);
154      tableScan.setTimeRange(startTime, endTime);
155      if (!startRow.isEmpty()) {
156        tableScan.setStartRow(Bytes.toBytes(startRow));
157      }
158      tableScan.setStopRow(Bytes.toBytes(endRow));
159      for (String csplit : column) {
160        String[] familysplit = csplit.trim().split(":");
161        if (familysplit.length == 2) {
162          if (familysplit[1].length() > 0) {
163            if (LOG.isTraceEnabled()) {
164              LOG.trace("Scan family and column : " + familysplit[0] + "  " + familysplit[1]);
165            }
166            tableScan.addColumn(Bytes.toBytes(familysplit[0]), Bytes.toBytes(familysplit[1]));
167          } else {
168            tableScan.addFamily(Bytes.toBytes(familysplit[0]));
169            if (LOG.isTraceEnabled()) {
170              LOG.trace("Scan family : " + familysplit[0] + " and empty qualifier.");
171            }
172            tableScan.addColumn(Bytes.toBytes(familysplit[0]), null);
173          }
174        } else if (StringUtils.isNotEmpty(familysplit[0])) {
175          if (LOG.isTraceEnabled()) {
176            LOG.trace("Scan family : " + familysplit[0]);
177          }
178          tableScan.addFamily(Bytes.toBytes(familysplit[0]));
179        }
180      }
181      FilterList filterList = new FilterList();
182      if (StringUtils.isNotEmpty(paramFilter)) {
183        ParseFilter pf = new ParseFilter();
184        Filter parsedParamFilter = pf.parseFilterString(paramFilter);
185        if (parsedParamFilter != null) {
186          filterList.addFilter(parsedParamFilter);
187        }
188        if (prefixFilter != null) {
189          filterList.addFilter(prefixFilter);
190        }
191      }
192      if (filterList.size() > 0) {
193        tableScan.setFilter(filterList);
194      }
195
196      int fetchSize = this.servlet.getConfiguration().getInt(Constants.SCAN_FETCH_SIZE, 10);
197      tableScan.setCaching(fetchSize);
198      tableScan.setReversed(reversed);
199      tableScan.setCacheBlocks(cacheBlocks);
200      return new TableScanResource(hTable.getScanner(tableScan), userRequestedLimit);
201    } catch (IOException exp) {
202      servlet.getMetrics().incrementFailedScanRequests(1);
203      processException(exp);
204      LOG.warn(exp.toString(), exp);
205      return null;
206    }
207  }
208}