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 com.fasterxml.jackson.annotation.JsonIgnore; 021import com.fasterxml.jackson.annotation.JsonProperty; 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.Iterator; 025import java.util.List; 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlElement; 029import javax.xml.bind.annotation.XmlRootElement; 030import org.apache.hadoop.hbase.Cell; 031import org.apache.hadoop.hbase.CellUtil; 032import org.apache.hadoop.hbase.client.Result; 033import org.apache.hadoop.hbase.client.ResultScanner; 034import org.apache.hadoop.hbase.rest.model.CellModel; 035import org.apache.hadoop.hbase.rest.model.RowModel; 036import org.apache.yetus.audience.InterfaceAudience; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import org.apache.hbase.thirdparty.javax.ws.rs.GET; 041import org.apache.hbase.thirdparty.javax.ws.rs.HeaderParam; 042import org.apache.hbase.thirdparty.javax.ws.rs.Produces; 043import org.apache.hbase.thirdparty.javax.ws.rs.core.Context; 044import org.apache.hbase.thirdparty.javax.ws.rs.core.Response; 045import org.apache.hbase.thirdparty.javax.ws.rs.core.Response.ResponseBuilder; 046import org.apache.hbase.thirdparty.javax.ws.rs.core.StreamingOutput; 047import org.apache.hbase.thirdparty.javax.ws.rs.core.UriInfo; 048 049@InterfaceAudience.Private 050public class TableScanResource extends ResourceBase { 051 private static final Logger LOG = LoggerFactory.getLogger(TableScanResource.class); 052 053 TableResource tableResource; 054 ResultScanner results; 055 int userRequestedLimit; 056 057 public TableScanResource(ResultScanner scanner, int userRequestedLimit) throws IOException { 058 super(); 059 this.results = scanner; 060 this.userRequestedLimit = userRequestedLimit; 061 } 062 063 @GET 064 @Produces({ Constants.MIMETYPE_XML, Constants.MIMETYPE_JSON }) 065 public CellSetModelStream get(final @Context UriInfo uriInfo) { 066 if (LOG.isTraceEnabled()) { 067 LOG.trace("GET " + uriInfo.getAbsolutePath()); 068 } 069 servlet.getMetrics().incrementRequests(1); 070 final int rowsToSend = userRequestedLimit; 071 servlet.getMetrics().incrementSucessfulScanRequests(1); 072 final Iterator<Result> itr = results.iterator(); 073 return new CellSetModelStream(new ArrayList<RowModel>() { 074 @Override 075 public Iterator<RowModel> iterator() { 076 return new Iterator<RowModel>() { 077 int count = rowsToSend; 078 079 @Override 080 public boolean hasNext() { 081 return count > 0 && itr.hasNext(); 082 } 083 084 @Override 085 public RowModel next() { 086 Result rs = itr.next(); 087 if ((rs == null) || (count <= 0)) { 088 return null; 089 } 090 byte[] rowKey = rs.getRow(); 091 RowModel rModel = new RowModel(rowKey); 092 List<Cell> kvs = rs.listCells(); 093 for (Cell kv : kvs) { 094 rModel.addCell(new CellModel(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv), 095 kv.getTimestamp(), CellUtil.cloneValue(kv))); 096 } 097 count--; 098 if (count == 0) { 099 results.close(); 100 } 101 return rModel; 102 } 103 }; 104 } 105 }); 106 } 107 108 @GET 109 @Produces({ Constants.MIMETYPE_PROTOBUF, Constants.MIMETYPE_PROTOBUF_IETF }) 110 public Response getProtobuf(final @Context UriInfo uriInfo, 111 final @HeaderParam("Accept") String contentType) { 112 if (LOG.isTraceEnabled()) { 113 LOG.trace("GET " + uriInfo.getAbsolutePath() + " as " + MIMETYPE_BINARY); 114 } 115 servlet.getMetrics().incrementRequests(1); 116 try { 117 int fetchSize = this.servlet.getConfiguration().getInt(Constants.SCAN_FETCH_SIZE, 10); 118 StreamingOutput stream = 119 new ProtobufStreamingOutput(this.results, contentType, userRequestedLimit, fetchSize); 120 servlet.getMetrics().incrementSucessfulScanRequests(1); 121 ResponseBuilder response = Response.ok(stream); 122 response.header("content-type", contentType); 123 return response.build(); 124 } catch (Exception exp) { 125 servlet.getMetrics().incrementFailedScanRequests(1); 126 processException(exp); 127 LOG.warn(exp.toString(), exp); 128 return null; 129 } 130 } 131 132 @XmlRootElement(name = "CellSet") 133 @XmlAccessorType(XmlAccessType.FIELD) 134 public static class CellSetModelStream { 135 // JAXB needs an arraylist for streaming 136 @XmlElement(name = "Row") 137 @JsonIgnore 138 private ArrayList<RowModel> Row; 139 140 public CellSetModelStream() { 141 } 142 143 public CellSetModelStream(final ArrayList<RowModel> rowList) { 144 this.Row = rowList; 145 } 146 147 // jackson needs an iterator for streaming 148 @JsonProperty("Row") 149 public Iterator<RowModel> getIterator() { 150 return Row.iterator(); 151 } 152 } 153}