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