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.Base64; 022import java.util.Base64.Decoder; 023import org.apache.hadoop.hbase.Cell; 024import org.apache.hadoop.hbase.CellUtil; 025import org.apache.hadoop.hbase.filter.Filter; 026import org.apache.hadoop.hbase.filter.ParseFilter; 027import org.apache.hadoop.hbase.rest.model.CellModel; 028import org.apache.hadoop.hbase.rest.model.CellSetModel; 029import org.apache.hadoop.hbase.rest.model.RowModel; 030import org.apache.hadoop.hbase.util.Bytes; 031import org.apache.yetus.audience.InterfaceAudience; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035import org.apache.hbase.thirdparty.javax.ws.rs.Encoded; 036import org.apache.hbase.thirdparty.javax.ws.rs.GET; 037import org.apache.hbase.thirdparty.javax.ws.rs.HeaderParam; 038import org.apache.hbase.thirdparty.javax.ws.rs.Produces; 039import org.apache.hbase.thirdparty.javax.ws.rs.QueryParam; 040import org.apache.hbase.thirdparty.javax.ws.rs.core.Context; 041import org.apache.hbase.thirdparty.javax.ws.rs.core.MultivaluedMap; 042import org.apache.hbase.thirdparty.javax.ws.rs.core.Response; 043import org.apache.hbase.thirdparty.javax.ws.rs.core.UriInfo; 044 045@InterfaceAudience.Private 046public class MultiRowResource extends ResourceBase implements Constants { 047 private static final Logger LOG = LoggerFactory.getLogger(MultiRowResource.class); 048 049 private static final Decoder base64Urldecoder = Base64.getUrlDecoder(); 050 051 TableResource tableResource; 052 Integer versions = null; 053 String[] columns = null; 054 055 /** 056 * Constructor 057 */ 058 public MultiRowResource(TableResource tableResource, String versions, String columnsStr) 059 throws IOException { 060 super(); 061 this.tableResource = tableResource; 062 063 if (columnsStr != null && !columnsStr.equals("")) { 064 this.columns = columnsStr.split(","); 065 } 066 067 if (versions != null) { 068 this.versions = Integer.valueOf(versions); 069 070 } 071 } 072 073 @GET 074 @Produces({ MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, MIMETYPE_PROTOBUF_IETF }) 075 public Response get(final @Context UriInfo uriInfo, 076 final @HeaderParam("Encoding") String keyEncodingHeader, 077 @QueryParam(Constants.FILTER_B64) @Encoded String paramFilterB64, 078 @QueryParam(Constants.FILTER) String paramFilter) { 079 MultivaluedMap<String, String> params = uriInfo.getQueryParameters(); 080 String keyEncoding = (keyEncodingHeader != null) 081 ? keyEncodingHeader 082 : params.getFirst(KEY_ENCODING_QUERY_PARAM_NAME); 083 084 servlet.getMetrics().incrementRequests(1); 085 086 byte[] filterBytes = null; 087 if (paramFilterB64 != null) { 088 filterBytes = base64Urldecoder.decode(paramFilterB64); 089 } else if (paramFilter != null) { 090 // Not binary clean 091 filterBytes = paramFilter.getBytes(); 092 } 093 094 try { 095 Filter parsedParamFilter = null; 096 if (filterBytes != null) { 097 // Note that this is a completely different representation of the filters 098 // than the JSON one used in the /table/scanner endpoint 099 ParseFilter pf = new ParseFilter(); 100 parsedParamFilter = pf.parseFilterString(filterBytes); 101 } 102 CellSetModel model = new CellSetModel(); 103 // TODO map this to a Table.get(List<Get> gets) call instead of multiple get calls 104 for (String rk : params.get(ROW_KEYS_PARAM_NAME)) { 105 RowSpec rowSpec = new RowSpec(rk, keyEncoding); 106 107 if (this.versions != null) { 108 rowSpec.setMaxVersions(this.versions); 109 } 110 111 if (this.columns != null) { 112 for (int i = 0; i < this.columns.length; i++) { 113 rowSpec.addColumn(Bytes.toBytes(this.columns[i])); 114 } 115 } 116 117 ResultGenerator generator = ResultGenerator.fromRowSpec(this.tableResource.getName(), 118 rowSpec, parsedParamFilter, !params.containsKey(NOCACHE_PARAM_NAME)); 119 Cell value = null; 120 RowModel rowModel = new RowModel(rowSpec.getRow()); 121 if (generator.hasNext()) { 122 while ((value = generator.next()) != null) { 123 rowModel.addCell(new CellModel(CellUtil.cloneFamily(value), 124 CellUtil.cloneQualifier(value), value.getTimestamp(), CellUtil.cloneValue(value))); 125 } 126 model.addRow(rowModel); 127 } else { 128 if (LOG.isTraceEnabled()) { 129 LOG.trace("The row : " + rk + " not found in the table."); 130 } 131 } 132 } 133 134 if (model.getRows().isEmpty()) { 135 // If no rows found. 136 servlet.getMetrics().incrementFailedGetRequests(1); 137 return Response.status(Response.Status.NOT_FOUND).type(MIMETYPE_TEXT) 138 .entity("No rows found." + CRLF).build(); 139 } else { 140 servlet.getMetrics().incrementSucessfulGetRequests(1); 141 return Response.ok(model).build(); 142 } 143 } catch (IOException e) { 144 servlet.getMetrics().incrementFailedGetRequests(1); 145 return processException(e); 146 } 147 } 148}