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