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