View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.rest;
21  
22  import java.io.IOException;
23  
24  import javax.ws.rs.DELETE;
25  import javax.ws.rs.GET;
26  import javax.ws.rs.Produces;
27  import javax.ws.rs.QueryParam;
28  import javax.ws.rs.core.CacheControl;
29  import javax.ws.rs.core.Context;
30  import javax.ws.rs.core.Response;
31  import javax.ws.rs.core.Response.ResponseBuilder;
32  import javax.ws.rs.core.UriInfo;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  import org.apache.hadoop.hbase.classification.InterfaceAudience;
38  import org.apache.hadoop.hbase.Cell;
39  import org.apache.hadoop.hbase.CellUtil;
40  import org.apache.hadoop.hbase.KeyValue;
41  import org.apache.hadoop.hbase.rest.model.CellModel;
42  import org.apache.hadoop.hbase.rest.model.CellSetModel;
43  import org.apache.hadoop.hbase.rest.model.RowModel;
44  import org.apache.hadoop.hbase.util.Base64;
45  import org.apache.hadoop.hbase.util.Bytes;
46  
47  @InterfaceAudience.Private
48  public class ScannerInstanceResource extends ResourceBase {
49    private static final Log LOG =
50      LogFactory.getLog(ScannerInstanceResource.class);
51  
52    static CacheControl cacheControl;
53    static {
54      cacheControl = new CacheControl();
55      cacheControl.setNoCache(true);
56      cacheControl.setNoTransform(false);
57    }
58  
59    ResultGenerator generator = null;
60    String id = null;
61    int batch = 1;
62  
63    public ScannerInstanceResource() throws IOException { }
64  
65    public ScannerInstanceResource(String table, String id,
66        ResultGenerator generator, int batch) throws IOException {
67      this.id = id;
68      this.generator = generator;
69      this.batch = batch;
70    }
71  
72    @GET
73    @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
74      MIMETYPE_PROTOBUF_IETF})
75    public Response get(final @Context UriInfo uriInfo,
76        @QueryParam("n") int maxRows, final @QueryParam("c") int maxValues) {
77      if (LOG.isTraceEnabled()) {
78        LOG.trace("GET " + uriInfo.getAbsolutePath());
79      }
80      servlet.getMetrics().incrementRequests(1);
81      if (generator == null) {
82        servlet.getMetrics().incrementFailedGetRequests(1);
83        return Response.status(Response.Status.NOT_FOUND)
84          .type(MIMETYPE_TEXT).entity("Not found" + CRLF)
85          .build();
86      }
87      CellSetModel model = new CellSetModel();
88      RowModel rowModel = null;
89      byte[] rowKey = null;
90      int limit = batch;
91      if (maxValues > 0) {
92        limit = maxValues;
93      }
94      int count = limit;
95      do {
96        Cell value = null;
97        try {
98          value = generator.next();
99        } catch (IllegalStateException e) {
100         if (ScannerResource.delete(id)) {
101           servlet.getMetrics().incrementSucessfulDeleteRequests(1);
102         } else {
103           servlet.getMetrics().incrementFailedDeleteRequests(1);
104         }
105         servlet.getMetrics().incrementFailedGetRequests(1);
106         return Response.status(Response.Status.GONE)
107           .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
108           .build();
109       }
110       if (value == null) {
111         if (LOG.isTraceEnabled()) {
112           LOG.trace("generator exhausted");
113         }
114         // respond with 204 (No Content) if an empty cell set would be
115         // returned
116         if (count == limit) {
117           return Response.noContent().build();
118         }
119         break;
120       }
121       if (rowKey == null) {
122         rowKey = CellUtil.cloneRow(value);
123         rowModel = new RowModel(rowKey);
124       }
125       if (!Bytes.equals(CellUtil.cloneRow(value), rowKey)) {
126         // if maxRows was given as a query param, stop if we would exceed the
127         // specified number of rows
128         if (maxRows > 0) {
129           if (--maxRows == 0) {
130             generator.putBack(value);
131             break;
132           }
133         }
134         model.addRow(rowModel);
135         rowKey = CellUtil.cloneRow(value);
136         rowModel = new RowModel(rowKey);
137       }
138       rowModel.addCell(
139         new CellModel(CellUtil.cloneFamily(value), CellUtil.cloneQualifier(value),
140           value.getTimestamp(), CellUtil.cloneValue(value)));
141     } while (--count > 0);
142     model.addRow(rowModel);
143     ResponseBuilder response = Response.ok(model);
144     response.cacheControl(cacheControl);
145     servlet.getMetrics().incrementSucessfulGetRequests(1);
146     return response.build();
147   }
148 
149   @GET
150   @Produces(MIMETYPE_BINARY)
151   public Response getBinary(final @Context UriInfo uriInfo) {
152     if (LOG.isTraceEnabled()) {
153       LOG.trace("GET " + uriInfo.getAbsolutePath() + " as " +
154         MIMETYPE_BINARY);
155     }
156     servlet.getMetrics().incrementRequests(1);
157     try {
158       Cell value = generator.next();
159       if (value == null) {
160         if (LOG.isTraceEnabled()) {
161           LOG.trace("generator exhausted");
162         }
163         return Response.noContent().build();
164       }
165       ResponseBuilder response = Response.ok(CellUtil.cloneValue(value));
166       response.cacheControl(cacheControl);
167       response.header("X-Row", Base64.encodeBytes(CellUtil.cloneRow(value)));
168       response.header("X-Column",
169         Base64.encodeBytes(
170           KeyValue.makeColumn(CellUtil.cloneFamily(value), CellUtil.cloneQualifier(value))));
171       response.header("X-Timestamp", value.getTimestamp());
172       servlet.getMetrics().incrementSucessfulGetRequests(1);
173       return response.build();
174     } catch (IllegalStateException e) {
175       if (ScannerResource.delete(id)) {
176         servlet.getMetrics().incrementSucessfulDeleteRequests(1);
177       } else {
178         servlet.getMetrics().incrementFailedDeleteRequests(1);
179       }
180       servlet.getMetrics().incrementFailedGetRequests(1);
181       return Response.status(Response.Status.GONE)
182         .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
183         .build();
184     }
185   }
186 
187   @DELETE
188   public Response delete(final @Context UriInfo uriInfo) {
189     if (LOG.isTraceEnabled()) {
190       LOG.trace("DELETE " + uriInfo.getAbsolutePath());
191     }
192     servlet.getMetrics().incrementRequests(1);
193     if (servlet.isReadOnly()) {
194       return Response.status(Response.Status.FORBIDDEN)
195         .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
196         .build();
197     }
198     if (ScannerResource.delete(id)) {
199       servlet.getMetrics().incrementSucessfulDeleteRequests(1);
200     } else {
201       servlet.getMetrics().incrementFailedDeleteRequests(1);
202     }
203     return Response.ok().build();
204   }
205 }