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.classification.InterfaceAudience;
38  import org.apache.hadoop.hbase.KeyValue;
39  import org.apache.hadoop.hbase.rest.model.CellModel;
40  import org.apache.hadoop.hbase.rest.model.CellSetModel;
41  import org.apache.hadoop.hbase.rest.model.RowModel;
42  import org.apache.hadoop.hbase.util.Base64;
43  import org.apache.hadoop.hbase.util.Bytes;
44  
45  @InterfaceAudience.Private
46  public class ScannerInstanceResource extends ResourceBase {
47    private static final Log LOG =
48      LogFactory.getLog(ScannerInstanceResource.class);
49  
50    static CacheControl cacheControl;
51    static {
52      cacheControl = new CacheControl();
53      cacheControl.setNoCache(true);
54      cacheControl.setNoTransform(false);
55    }
56  
57    ResultGenerator generator = null;
58    String id = null;
59    int batch = 1;
60  
61    public ScannerInstanceResource() throws IOException { }
62  
63    public ScannerInstanceResource(String table, String id, 
64        ResultGenerator generator, int batch) throws IOException {
65      this.id = id;
66      this.generator = generator;
67      this.batch = batch;
68    }
69  
70    @GET
71    @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
72      MIMETYPE_PROTOBUF_IETF})
73    public Response get(final @Context UriInfo uriInfo, 
74        @QueryParam("n") int maxRows, final @QueryParam("c") int maxValues) {
75      if (LOG.isDebugEnabled()) {
76        LOG.debug("GET " + uriInfo.getAbsolutePath());
77      }
78      servlet.getMetrics().incrementRequests(1);
79      if (generator == null) {
80        servlet.getMetrics().incrementFailedGetRequests(1);
81        return Response.status(Response.Status.NOT_FOUND)
82          .type(MIMETYPE_TEXT).entity("Not found" + CRLF)
83          .build();
84      }
85      CellSetModel model = new CellSetModel();
86      RowModel rowModel = null;
87      byte[] rowKey = null;
88      int limit = batch;
89      if (maxValues > 0) {
90        limit = maxValues;
91      }
92      int count = limit;
93      do {
94        KeyValue value = null;
95        try {
96          value = generator.next();
97        } catch (IllegalStateException e) {
98          if (ScannerResource.delete(id)) {
99            servlet.getMetrics().incrementSucessfulDeleteRequests(1);
100         } else {
101           servlet.getMetrics().incrementFailedDeleteRequests(1);
102         }
103         servlet.getMetrics().incrementFailedGetRequests(1);
104         return Response.status(Response.Status.GONE)
105           .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
106           .build();
107       }
108       if (value == null) {
109         LOG.info("generator exhausted");
110         // respond with 204 (No Content) if an empty cell set would be
111         // returned
112         if (count == limit) {
113           return Response.noContent().build();
114         }
115         break;
116       }
117       if (rowKey == null) {
118         rowKey = value.getRow();
119         rowModel = new RowModel(rowKey);
120       }
121       if (!Bytes.equals(value.getRow(), rowKey)) {
122         // if maxRows was given as a query param, stop if we would exceed the
123         // specified number of rows
124         if (maxRows > 0) { 
125           if (--maxRows == 0) {
126             generator.putBack(value);
127             break;
128           }
129         }
130         model.addRow(rowModel);
131         rowKey = value.getRow();
132         rowModel = new RowModel(rowKey);
133       }
134       rowModel.addCell(
135         new CellModel(value.getFamily(), value.getQualifier(), 
136           value.getTimestamp(), value.getValue()));
137     } while (--count > 0);
138     model.addRow(rowModel);
139     ResponseBuilder response = Response.ok(model);
140     response.cacheControl(cacheControl);
141     servlet.getMetrics().incrementSucessfulGetRequests(1);
142     return response.build();
143   }
144 
145   @GET
146   @Produces(MIMETYPE_BINARY)
147   public Response getBinary(final @Context UriInfo uriInfo) {
148     if (LOG.isDebugEnabled()) {
149       LOG.debug("GET " + uriInfo.getAbsolutePath() + " as " +
150         MIMETYPE_BINARY);
151     }
152     servlet.getMetrics().incrementRequests(1);
153     try {
154       KeyValue value = generator.next();
155       if (value == null) {
156         LOG.info("generator exhausted");
157         return Response.noContent().build();
158       }
159       ResponseBuilder response = Response.ok(value.getValue());
160       response.cacheControl(cacheControl);
161       response.header("X-Row", Base64.encodeBytes(value.getRow()));      
162       response.header("X-Column", 
163         Base64.encodeBytes(
164           KeyValue.makeColumn(value.getFamily(), value.getQualifier())));
165       response.header("X-Timestamp", value.getTimestamp());
166       servlet.getMetrics().incrementSucessfulGetRequests(1);
167       return response.build();
168     } catch (IllegalStateException e) {
169       if (ScannerResource.delete(id)) {
170         servlet.getMetrics().incrementSucessfulDeleteRequests(1);
171       } else {
172         servlet.getMetrics().incrementFailedDeleteRequests(1);
173       }
174       servlet.getMetrics().incrementFailedGetRequests(1);
175       return Response.status(Response.Status.GONE)
176         .type(MIMETYPE_TEXT).entity("Gone" + CRLF)
177         .build();
178     }
179   }
180 
181   @DELETE
182   public Response delete(final @Context UriInfo uriInfo) {
183     if (LOG.isDebugEnabled()) {
184       LOG.debug("DELETE " + uriInfo.getAbsolutePath());
185     }
186     servlet.getMetrics().incrementRequests(1);
187     if (servlet.isReadOnly()) {
188       return Response.status(Response.Status.FORBIDDEN)
189         .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
190         .build();
191     }
192     if (ScannerResource.delete(id)) {
193       servlet.getMetrics().incrementSucessfulDeleteRequests(1);
194     } else {
195       servlet.getMetrics().incrementFailedDeleteRequests(1);
196     }
197     return Response.ok().build();
198   }
199 }