3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 package org
.apache
.hadoop
.hbase
.rest
;
22 import java
.io
.IOException
;
23 import java
.util
.List
;
24 import org
.apache
.commons
.lang3
.StringUtils
;
25 import org
.apache
.hadoop
.hbase
.CellUtil
;
26 import org
.apache
.hadoop
.hbase
.TableName
;
27 import org
.apache
.hadoop
.hbase
.client
.Scan
;
28 import org
.apache
.hadoop
.hbase
.client
.Table
;
29 import org
.apache
.hadoop
.hbase
.filter
.Filter
;
30 import org
.apache
.hadoop
.hbase
.filter
.FilterList
;
31 import org
.apache
.hadoop
.hbase
.filter
.ParseFilter
;
32 import org
.apache
.hadoop
.hbase
.filter
.PrefixFilter
;
33 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
34 import org
.apache
.yetus
.audience
.InterfaceAudience
;
35 import org
.slf4j
.Logger
;
36 import org
.slf4j
.LoggerFactory
;
38 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.DefaultValue
;
39 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.Encoded
;
40 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.Path
;
41 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.PathParam
;
42 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.QueryParam
;
44 @InterfaceAudience.Private
45 public class TableResource
extends ResourceBase
{
48 private static final Logger LOG
= LoggerFactory
.getLogger(TableResource
.class);
55 public TableResource(String table
) throws IOException
{
60 /** @return the table name */
66 * @return true if the table exists
69 boolean exists() throws IOException
{
70 return servlet
.getAdmin().tableExists(TableName
.valueOf(table
));
74 public ExistsResource
getExistsResource() throws IOException
{
75 return new ExistsResource(this);
79 public RegionsResource
getRegionsResource() throws IOException
{
80 return new RegionsResource(this);
84 public ScannerResource
getScannerResource() throws IOException
{
85 return new ScannerResource(this);
89 public SchemaResource
getSchemaResource() throws IOException
{
90 return new SchemaResource(this);
93 @Path("{multiget: multiget.*}")
94 public MultiRowResource
getMultipleRowResource(final @QueryParam("v") String versions
,
95 @PathParam("multiget") String path
) throws IOException
{
96 return new MultiRowResource(this, versions
, path
.replace("multiget", "").replace("/", ""));
99 @Path("{rowspec: [^*]+}")
100 public RowResource
getRowResource(
101 // We need the @Encoded decorator so Jersey won't urldecode before
102 // the RowSpec constructor has a chance to parse
103 final @PathParam("rowspec") @Encoded String rowspec
,
104 final @QueryParam("v") String versions
,
105 final @QueryParam("check") String check
,
106 final @QueryParam("rr") String returnResult
) throws IOException
{
107 return new RowResource(this, rowspec
, versions
, check
, returnResult
);
110 @Path("{suffixglobbingspec: .*\\*/.+}")
111 public RowResource
getRowResourceWithSuffixGlobbing(
112 // We need the @Encoded decorator so Jersey won't urldecode before
113 // the RowSpec constructor has a chance to parse
114 final @PathParam("suffixglobbingspec") @Encoded String suffixglobbingspec
,
115 final @QueryParam("v") String versions
,
116 final @QueryParam("check") String check
,
117 final @QueryParam("rr") String returnResult
) throws IOException
{
118 return new RowResource(this, suffixglobbingspec
, versions
, check
, returnResult
);
121 @Path("{scanspec: .*[*]$}")
122 public TableScanResource
getScanResource(
123 final @PathParam("scanspec") String scanSpec
,
124 @DefaultValue(Integer
.MAX_VALUE
+ "")
125 @QueryParam(Constants
.SCAN_LIMIT
) int userRequestedLimit
,
126 @DefaultValue("") @QueryParam(Constants
.SCAN_START_ROW
) String startRow
,
127 @DefaultValue("") @QueryParam(Constants
.SCAN_END_ROW
) String endRow
,
128 @QueryParam(Constants
.SCAN_COLUMN
) List
<String
> column
,
129 @DefaultValue("1") @QueryParam(Constants
.SCAN_MAX_VERSIONS
) int maxVersions
,
130 @DefaultValue("-1") @QueryParam(Constants
.SCAN_BATCH_SIZE
) int batchSize
,
131 @DefaultValue("0") @QueryParam(Constants
.SCAN_START_TIME
) long startTime
,
132 @DefaultValue(Long
.MAX_VALUE
+ "") @QueryParam(Constants
.SCAN_END_TIME
) long endTime
,
133 @DefaultValue("true") @QueryParam(Constants
.SCAN_CACHE_BLOCKS
) boolean cacheBlocks
,
134 @DefaultValue("false") @QueryParam(Constants
.SCAN_REVERSED
) boolean reversed
,
135 @DefaultValue("") @QueryParam(Constants
.SCAN_FILTER
) String paramFilter
) {
137 Filter prefixFilter
= null;
138 Scan tableScan
= new Scan();
139 if (scanSpec
.indexOf('*') > 0) {
140 String prefix
= scanSpec
.substring(0, scanSpec
.indexOf('*'));
141 byte[] prefixBytes
= Bytes
.toBytes(prefix
);
142 prefixFilter
= new PrefixFilter(Bytes
.toBytes(prefix
));
143 if (startRow
.isEmpty()) {
144 tableScan
.withStartRow(prefixBytes
);
147 if (LOG
.isTraceEnabled()) {
148 LOG
.trace("Query parameters : Table Name = > " + this.table
+ " Start Row => " + startRow
149 + " End Row => " + endRow
+ " Columns => " + column
+ " Start Time => " + startTime
150 + " End Time => " + endTime
+ " Cache Blocks => " + cacheBlocks
+ " Max Versions => "
151 + maxVersions
+ " Batch Size => " + batchSize
);
153 Table hTable
= RESTServlet
.getInstance().getTable(this.table
);
154 tableScan
.setBatch(batchSize
);
155 tableScan
.readVersions(maxVersions
);
156 tableScan
.setTimeRange(startTime
, endTime
);
157 if (!startRow
.isEmpty()) {
158 tableScan
.withStartRow(Bytes
.toBytes(startRow
));
160 tableScan
.withStopRow(Bytes
.toBytes(endRow
));
161 for (String col
: column
) {
162 byte [][] parts
= CellUtil
.parseColumn(Bytes
.toBytes(col
.trim()));
163 if (parts
.length
== 1) {
164 if (LOG
.isTraceEnabled()) {
165 LOG
.trace("Scan family : " + Bytes
.toStringBinary(parts
[0]));
167 tableScan
.addFamily(parts
[0]);
168 } else if (parts
.length
== 2) {
169 if (LOG
.isTraceEnabled()) {
170 LOG
.trace("Scan family and column : " + Bytes
.toStringBinary(parts
[0])
171 + " " + Bytes
.toStringBinary(parts
[1]));
173 tableScan
.addColumn(parts
[0], parts
[1]);
175 throw new IllegalArgumentException("Invalid column specifier.");
178 FilterList filterList
= new FilterList();
179 if (StringUtils
.isNotEmpty(paramFilter
)) {
180 ParseFilter pf
= new ParseFilter();
181 Filter parsedParamFilter
= pf
.parseFilterString(paramFilter
);
182 if (parsedParamFilter
!= null) {
183 filterList
.addFilter(parsedParamFilter
);
185 if (prefixFilter
!= null) {
186 filterList
.addFilter(prefixFilter
);
189 if (filterList
.size() > 0) {
190 tableScan
.setFilter(filterList
);
193 int fetchSize
= this.servlet
.getConfiguration().getInt(Constants
.SCAN_FETCH_SIZE
, 10);
194 tableScan
.setCaching(fetchSize
);
195 tableScan
.setReversed(reversed
);
196 tableScan
.setCacheBlocks(cacheBlocks
);
197 return new TableScanResource(hTable
.getScanner(tableScan
), userRequestedLimit
);
198 } catch (IOException exp
) {
199 servlet
.getMetrics().incrementFailedScanRequests(1);
200 processException(exp
);
201 LOG
.warn(exp
.toString(), exp
);