View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.rest;
22  
23  import java.io.IOException;
24  
25  import javax.ws.rs.DELETE;
26  import javax.ws.rs.GET;
27  import javax.ws.rs.Produces;
28  import javax.ws.rs.QueryParam;
29  import javax.ws.rs.WebApplicationException;
30  import javax.ws.rs.core.CacheControl;
31  import javax.ws.rs.core.Context;
32  import javax.ws.rs.core.Response;
33  import javax.ws.rs.core.Response.ResponseBuilder;
34  import javax.ws.rs.core.UriInfo;
35  
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  
39  import org.apache.hadoop.hbase.KeyValue;
40  import org.apache.hadoop.hbase.rest.model.CellModel;
41  import org.apache.hadoop.hbase.rest.model.CellSetModel;
42  import org.apache.hadoop.hbase.rest.model.RowModel;
43  import org.apache.hadoop.hbase.util.Base64;
44  import org.apache.hadoop.hbase.util.Bytes;
45  
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;
58    String id;
59    int batch = 1;
60  
61    public ScannerInstanceResource(String table, String id, 
62        ResultGenerator generator, int batch) throws IOException {
63      this.id = id;
64      this.generator = generator;
65      this.batch = batch;
66    }
67  
68    @GET
69    @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
70    public Response get(final @Context UriInfo uriInfo, 
71        @QueryParam("n") int maxRows, final @QueryParam("c") int maxValues) {
72      if (LOG.isDebugEnabled()) {
73        LOG.debug("GET " + uriInfo.getAbsolutePath());
74      }
75      servlet.getMetrics().incrementRequests(1);
76      CellSetModel model = new CellSetModel();
77      RowModel rowModel = null;
78      byte[] rowKey = null;
79      int limit = batch;
80      if (maxValues > 0) {
81        limit = maxValues;
82      }
83      int count = limit;
84      do {
85        KeyValue value = null;
86        try {
87          value = generator.next();
88        } catch (IllegalStateException e) {
89          ScannerResource.delete(id);
90          throw new WebApplicationException(Response.Status.GONE);
91        }
92        if (value == null) {
93          LOG.info("generator exhausted");
94          // respond with 204 (No Content) if an empty cell set would be
95          // returned
96          if (count == limit) {
97            return Response.noContent().build();
98          }
99          break;
100       }
101       if (rowKey == null) {
102         rowKey = value.getRow();
103         rowModel = new RowModel(rowKey);
104       }
105       if (!Bytes.equals(value.getRow(), rowKey)) {
106         // if maxRows was given as a query param, stop if we would exceed the
107         // specified number of rows
108         if (maxRows > 0) { 
109           if (--maxRows == 0) {
110             generator.putBack(value);
111             break;
112           }
113         }
114         model.addRow(rowModel);
115         rowKey = value.getRow();
116         rowModel = new RowModel(rowKey);
117       }
118       rowModel.addCell(
119         new CellModel(value.getFamily(), value.getQualifier(), 
120           value.getTimestamp(), value.getValue()));
121     } while (--count > 0);
122     model.addRow(rowModel);
123     ResponseBuilder response = Response.ok(model);
124     response.cacheControl(cacheControl);
125     return response.build();
126   }
127 
128   @GET
129   @Produces(MIMETYPE_BINARY)
130   public Response getBinary(final @Context UriInfo uriInfo) {
131     if (LOG.isDebugEnabled()) {
132       LOG.debug("GET " + uriInfo.getAbsolutePath() + " as " +
133         MIMETYPE_BINARY);
134     }
135     servlet.getMetrics().incrementRequests(1);
136     try {
137       KeyValue value = generator.next();
138       if (value == null) {
139         LOG.info("generator exhausted");
140         return Response.noContent().build();
141       }
142       ResponseBuilder response = Response.ok(value.getValue());
143       response.cacheControl(cacheControl);
144       response.header("X-Row", Base64.encodeBytes(value.getRow()));      
145       response.header("X-Column", 
146         Base64.encodeBytes(
147           KeyValue.makeColumn(value.getFamily(), value.getQualifier())));
148       response.header("X-Timestamp", value.getTimestamp());
149       return response.build();
150     } catch (IllegalStateException e) {
151       ScannerResource.delete(id);
152       throw new WebApplicationException(Response.Status.GONE);
153     }
154   }
155 
156   @DELETE
157   public Response delete(final @Context UriInfo uriInfo) {
158     if (LOG.isDebugEnabled()) {
159       LOG.debug("DELETE " + uriInfo.getAbsolutePath());
160     }
161     servlet.getMetrics().incrementRequests(1);
162     if (servlet.isReadOnly()) {
163       throw new WebApplicationException(Response.Status.FORBIDDEN);
164     }
165     ScannerResource.delete(id);
166     return Response.ok().build();
167   }
168 }