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  import org.apache.hadoop.hbase.Cell;
37  import org.apache.hadoop.hbase.CellUtil;
38  import org.apache.hadoop.hbase.KeyValue;
39  import org.apache.hadoop.hbase.TableNotFoundException;
40  import org.apache.hadoop.hbase.classification.InterfaceAudience;
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      } else {
87        // Updated the connection access time for each client next() call
88        RESTServlet.getInstance().getConnectionCache().updateConnectionAccessTime();
89      }
90      CellSetModel model = new CellSetModel();
91      RowModel rowModel = null;
92      byte[] rowKey = null;
93      int limit = batch;
94      if (maxValues > 0) {
95        limit = maxValues;
96      }
97      int count = limit;
98      do {
99        Cell value = null;
100       try {
101         value = generator.next();
102       } catch (IllegalStateException e) {
103         if (ScannerResource.delete(id)) {
104           servlet.getMetrics().incrementSucessfulDeleteRequests(1);
105         } else {
106           servlet.getMetrics().incrementFailedDeleteRequests(1);
107         }
108         servlet.getMetrics().incrementFailedGetRequests(1);
109         return Response.status(Response.Status.GONE)
110           .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
111           .build();
112       } catch (IllegalArgumentException e) {
113         Throwable t = e.getCause();
114         if (t instanceof TableNotFoundException) {
115           return Response.status(Response.Status.NOT_FOUND)
116               .type(MIMETYPE_TEXT).entity("Not found" + CRLF)
117               .build();
118         }
119         throw e;
120       }
121       if (value == null) {
122         if (LOG.isTraceEnabled()) {
123           LOG.trace("generator exhausted");
124         }
125         // respond with 204 (No Content) if an empty cell set would be
126         // returned
127         if (count == limit) {
128           return Response.noContent().build();
129         }
130         break;
131       }
132       if (rowKey == null) {
133         rowKey = CellUtil.cloneRow(value);
134         rowModel = new RowModel(rowKey);
135       }
136       if (!Bytes.equals(CellUtil.cloneRow(value), rowKey)) {
137         // if maxRows was given as a query param, stop if we would exceed the
138         // specified number of rows
139         if (maxRows > 0) {
140           if (--maxRows == 0) {
141             generator.putBack(value);
142             break;
143           }
144         }
145         model.addRow(rowModel);
146         rowKey = CellUtil.cloneRow(value);
147         rowModel = new RowModel(rowKey);
148       }
149       rowModel.addCell(
150         new CellModel(CellUtil.cloneFamily(value), CellUtil.cloneQualifier(value),
151           value.getTimestamp(), CellUtil.cloneValue(value)));
152     } while (--count > 0);
153     model.addRow(rowModel);
154     ResponseBuilder response = Response.ok(model);
155     response.cacheControl(cacheControl);
156     servlet.getMetrics().incrementSucessfulGetRequests(1);
157     return response.build();
158   }
159 
160   @GET
161   @Produces(MIMETYPE_BINARY)
162   public Response getBinary(final @Context UriInfo uriInfo) {
163     if (LOG.isTraceEnabled()) {
164       LOG.trace("GET " + uriInfo.getAbsolutePath() + " as " +
165         MIMETYPE_BINARY);
166     }
167     servlet.getMetrics().incrementRequests(1);
168     try {
169       Cell value = generator.next();
170       if (value == null) {
171         if (LOG.isTraceEnabled()) {
172           LOG.trace("generator exhausted");
173         }
174         return Response.noContent().build();
175       }
176       ResponseBuilder response = Response.ok(CellUtil.cloneValue(value));
177       response.cacheControl(cacheControl);
178       response.header("X-Row", Base64.encodeBytes(CellUtil.cloneRow(value)));
179       response.header("X-Column",
180         Base64.encodeBytes(
181           KeyValue.makeColumn(CellUtil.cloneFamily(value), CellUtil.cloneQualifier(value))));
182       response.header("X-Timestamp", value.getTimestamp());
183       servlet.getMetrics().incrementSucessfulGetRequests(1);
184       return response.build();
185     } catch (IllegalStateException e) {
186       if (ScannerResource.delete(id)) {
187         servlet.getMetrics().incrementSucessfulDeleteRequests(1);
188       } else {
189         servlet.getMetrics().incrementFailedDeleteRequests(1);
190       }
191       servlet.getMetrics().incrementFailedGetRequests(1);
192       return Response.status(Response.Status.GONE)
193         .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
194         .build();
195     }
196   }
197 
198   @DELETE
199   public Response delete(final @Context UriInfo uriInfo) {
200     if (LOG.isTraceEnabled()) {
201       LOG.trace("DELETE " + uriInfo.getAbsolutePath());
202     }
203     servlet.getMetrics().incrementRequests(1);
204     if (servlet.isReadOnly()) {
205       return Response.status(Response.Status.FORBIDDEN)
206         .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
207         .build();
208     }
209     if (ScannerResource.delete(id)) {
210       servlet.getMetrics().incrementSucessfulDeleteRequests(1);
211     } else {
212       servlet.getMetrics().incrementFailedDeleteRequests(1);
213     }
214     return Response.ok().build();
215   }
216 }