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