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 import java.util.ArrayList;
25 import java.util.List;
26
27 import javax.ws.rs.Consumes;
28 import javax.ws.rs.DELETE;
29 import javax.ws.rs.GET;
30 import javax.ws.rs.POST;
31 import javax.ws.rs.PUT;
32 import javax.ws.rs.Produces;
33 import javax.ws.rs.WebApplicationException;
34 import javax.ws.rs.core.Context;
35 import javax.ws.rs.core.HttpHeaders;
36 import javax.ws.rs.core.Response;
37 import javax.ws.rs.core.UriInfo;
38 import javax.ws.rs.core.Response.ResponseBuilder;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42 import org.apache.hadoop.hbase.HConstants;
43 import org.apache.hadoop.hbase.KeyValue;
44 import org.apache.hadoop.hbase.client.Delete;
45 import org.apache.hadoop.hbase.client.HTableInterface;
46 import org.apache.hadoop.hbase.client.HTablePool;
47 import org.apache.hadoop.hbase.client.HTable;
48 import org.apache.hadoop.hbase.client.Put;
49 import org.apache.hadoop.hbase.rest.model.CellModel;
50 import org.apache.hadoop.hbase.rest.model.CellSetModel;
51 import org.apache.hadoop.hbase.rest.model.RowModel;
52 import org.apache.hadoop.hbase.rest.transform.Transform;
53 import org.apache.hadoop.hbase.util.Bytes;
54
55 public class RowResource extends ResourceBase {
56 private static final Log LOG = LogFactory.getLog(RowResource.class);
57
58 TableResource tableResource;
59 RowSpec rowspec;
60
61
62
63
64
65
66
67
68 public RowResource(TableResource tableResource, String rowspec,
69 String versions) throws IOException {
70 super();
71 this.tableResource = tableResource;
72 this.rowspec = new RowSpec(rowspec);
73 if (versions != null) {
74 this.rowspec.setMaxVersions(Integer.valueOf(versions));
75 }
76 }
77
78 @GET
79 @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
80 public Response get(final @Context UriInfo uriInfo) {
81 if (LOG.isDebugEnabled()) {
82 LOG.debug("GET " + uriInfo.getAbsolutePath());
83 }
84 servlet.getMetrics().incrementRequests(1);
85 try {
86 ResultGenerator generator =
87 ResultGenerator.fromRowSpec(tableResource.getName(), rowspec, null);
88 if (!generator.hasNext()) {
89 throw new WebApplicationException(Response.Status.NOT_FOUND);
90 }
91 int count = 0;
92 CellSetModel model = new CellSetModel();
93 KeyValue value = generator.next();
94 byte[] rowKey = value.getRow();
95 RowModel rowModel = new RowModel(rowKey);
96 do {
97 if (!Bytes.equals(value.getRow(), rowKey)) {
98 model.addRow(rowModel);
99 rowKey = value.getRow();
100 rowModel = new RowModel(rowKey);
101 }
102 byte[] family = value.getFamily();
103 byte[] qualifier = value.getQualifier();
104 byte[] data = tableResource.transform(family, qualifier,
105 value.getValue(), Transform.Direction.OUT);
106 rowModel.addCell(new CellModel(family, qualifier,
107 value.getTimestamp(), data));
108 if (++count > rowspec.getMaxValues()) {
109 break;
110 }
111 value = generator.next();
112 } while (value != null);
113 model.addRow(rowModel);
114 return Response.ok(model).build();
115 } catch (IOException e) {
116 throw new WebApplicationException(e,
117 Response.Status.SERVICE_UNAVAILABLE);
118 }
119 }
120
121 @GET
122 @Produces(MIMETYPE_BINARY)
123 public Response getBinary(final @Context UriInfo uriInfo) {
124 if (LOG.isDebugEnabled()) {
125 LOG.debug("GET " + uriInfo.getAbsolutePath() + " as "+ MIMETYPE_BINARY);
126 }
127 servlet.getMetrics().incrementRequests(1);
128
129
130 if (!rowspec.hasColumns() || rowspec.getColumns().length > 1) {
131 throw new WebApplicationException(Response.Status.BAD_REQUEST);
132 }
133 try {
134 ResultGenerator generator =
135 ResultGenerator.fromRowSpec(tableResource.getName(), rowspec, null);
136 if (!generator.hasNext()) {
137 throw new WebApplicationException(Response.Status.NOT_FOUND);
138 }
139 KeyValue value = generator.next();
140 byte[] family = value.getFamily();
141 byte[] qualifier = value.getQualifier();
142 byte[] data = tableResource.transform(family, qualifier,
143 value.getValue(), Transform.Direction.OUT);
144 ResponseBuilder response = Response.ok(data);
145 response.header("X-Timestamp", value.getTimestamp());
146 return response.build();
147 } catch (IOException e) {
148 throw new WebApplicationException(e,
149 Response.Status.SERVICE_UNAVAILABLE);
150 }
151 }
152
153 Response update(final CellSetModel model, final boolean replace) {
154 servlet.getMetrics().incrementRequests(1);
155 if (servlet.isReadOnly()) {
156 throw new WebApplicationException(Response.Status.FORBIDDEN);
157 }
158 HTablePool pool = servlet.getTablePool();
159 HTableInterface table = null;
160 try {
161 List<RowModel> rows = model.getRows();
162 List<Put> puts = new ArrayList<Put>();
163 for (RowModel row: rows) {
164 byte[] key = row.getKey();
165 if (key == null) {
166 key = rowspec.getRow();
167 }
168 if (key == null) {
169 throw new WebApplicationException(Response.Status.BAD_REQUEST);
170 }
171 Put put = new Put(key);
172 int i = 0;
173 for (CellModel cell: row.getCells()) {
174 byte[] col = cell.getColumn();
175 if (col == null) try {
176 col = rowspec.getColumns()[i++];
177 } catch (ArrayIndexOutOfBoundsException e) {
178 col = null;
179 }
180 if (col == null) {
181 throw new WebApplicationException(Response.Status.BAD_REQUEST);
182 }
183 byte [][] parts = KeyValue.parseColumn(col);
184 if (parts.length == 2 && parts[1].length > 0) {
185 put.add(parts[0], parts[1], cell.getTimestamp(),
186 tableResource.transform(parts[0], parts[1], cell.getValue(),
187 Transform.Direction.IN));
188 } else {
189 put.add(parts[0], null, cell.getTimestamp(),
190 tableResource.transform(parts[0], null, cell.getValue(),
191 Transform.Direction.IN));
192 }
193 }
194 puts.add(put);
195 if (LOG.isDebugEnabled()) {
196 LOG.debug("PUT " + put.toString());
197 }
198 }
199 table = pool.getTable(tableResource.getName());
200 table.put(puts);
201 table.flushCommits();
202 ResponseBuilder response = Response.ok();
203 return response.build();
204 } catch (IOException e) {
205 throw new WebApplicationException(e,
206 Response.Status.SERVICE_UNAVAILABLE);
207 } finally {
208 if (table != null) {
209 try {
210 pool.putTable(table);
211 } catch (IOException ioe) {
212 throw new WebApplicationException(ioe,
213 Response.Status.SERVICE_UNAVAILABLE);
214 }
215 }
216 }
217 }
218
219
220 Response updateBinary(final byte[] message, final HttpHeaders headers,
221 final boolean replace) {
222 servlet.getMetrics().incrementRequests(1);
223 if (servlet.isReadOnly()) {
224 throw new WebApplicationException(Response.Status.FORBIDDEN);
225 }
226 HTablePool pool = servlet.getTablePool();
227 HTableInterface table = null;
228 try {
229 byte[] row = rowspec.getRow();
230 byte[][] columns = rowspec.getColumns();
231 byte[] column = null;
232 if (columns != null) {
233 column = columns[0];
234 }
235 long timestamp = HConstants.LATEST_TIMESTAMP;
236 List<String> vals = headers.getRequestHeader("X-Row");
237 if (vals != null && !vals.isEmpty()) {
238 row = Bytes.toBytes(vals.get(0));
239 }
240 vals = headers.getRequestHeader("X-Column");
241 if (vals != null && !vals.isEmpty()) {
242 column = Bytes.toBytes(vals.get(0));
243 }
244 vals = headers.getRequestHeader("X-Timestamp");
245 if (vals != null && !vals.isEmpty()) {
246 timestamp = Long.valueOf(vals.get(0));
247 }
248 if (column == null) {
249 throw new WebApplicationException(Response.Status.BAD_REQUEST);
250 }
251 Put put = new Put(row);
252 byte parts[][] = KeyValue.parseColumn(column);
253 if (parts.length == 2 && parts[1].length > 0) {
254 put.add(parts[0], parts[1], timestamp,
255 tableResource.transform(parts[0], parts[1], message,
256 Transform.Direction.IN));
257 } else {
258 put.add(parts[0], null, timestamp,
259 tableResource.transform(parts[0], null, message,
260 Transform.Direction.IN));
261 }
262 table = pool.getTable(tableResource.getName());
263 table.put(put);
264 if (LOG.isDebugEnabled()) {
265 LOG.debug("PUT " + put.toString());
266 }
267 return Response.ok().build();
268 } catch (IOException e) {
269 throw new WebApplicationException(e,
270 Response.Status.SERVICE_UNAVAILABLE);
271 } finally {
272 if (table != null) {
273 try {
274 pool.putTable(table);
275 } catch (IOException ioe) {
276 throw new WebApplicationException(ioe,
277 Response.Status.SERVICE_UNAVAILABLE);
278 }
279 }
280 }
281 }
282
283 @PUT
284 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
285 public Response put(final CellSetModel model,
286 final @Context UriInfo uriInfo) {
287 if (LOG.isDebugEnabled()) {
288 LOG.debug("PUT " + uriInfo.getAbsolutePath());
289 }
290 return update(model, true);
291 }
292
293 @PUT
294 @Consumes(MIMETYPE_BINARY)
295 public Response putBinary(final byte[] message,
296 final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
297 if (LOG.isDebugEnabled()) {
298 LOG.debug("PUT " + uriInfo.getAbsolutePath() + " as "+ MIMETYPE_BINARY);
299 }
300 return updateBinary(message, headers, true);
301 }
302
303 @POST
304 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
305 public Response post(final CellSetModel model,
306 final @Context UriInfo uriInfo) {
307 if (LOG.isDebugEnabled()) {
308 LOG.debug("POST " + uriInfo.getAbsolutePath());
309 }
310 return update(model, false);
311 }
312
313 @POST
314 @Consumes(MIMETYPE_BINARY)
315 public Response postBinary(final byte[] message,
316 final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
317 if (LOG.isDebugEnabled()) {
318 LOG.debug("POST " + uriInfo.getAbsolutePath() + " as "+MIMETYPE_BINARY);
319 }
320 return updateBinary(message, headers, false);
321 }
322
323 @DELETE
324 public Response delete(final @Context UriInfo uriInfo) {
325 if (LOG.isDebugEnabled()) {
326 LOG.debug("DELETE " + uriInfo.getAbsolutePath());
327 }
328 servlet.getMetrics().incrementRequests(1);
329 if (servlet.isReadOnly()) {
330 throw new WebApplicationException(Response.Status.FORBIDDEN);
331 }
332 Delete delete = null;
333 if (rowspec.hasTimestamp())
334 delete = new Delete(rowspec.getRow(), rowspec.getTimestamp(), null);
335 else
336 delete = new Delete(rowspec.getRow());
337
338 for (byte[] column: rowspec.getColumns()) {
339 byte[][] split = KeyValue.parseColumn(column);
340 if (rowspec.hasTimestamp()) {
341 if (split.length == 2 && split[1].length != 0) {
342 delete.deleteColumns(split[0], split[1], rowspec.getTimestamp());
343 } else {
344 delete.deleteFamily(split[0], rowspec.getTimestamp());
345 }
346 } else {
347 if (split.length == 2 && split[1].length != 0) {
348 delete.deleteColumns(split[0], split[1]);
349 } else {
350 delete.deleteFamily(split[0]);
351 }
352 }
353 }
354 HTablePool pool = servlet.getTablePool();
355 HTableInterface table = null;
356 try {
357 table = pool.getTable(tableResource.getName());
358 table.delete(delete);
359 if (LOG.isDebugEnabled()) {
360 LOG.debug("DELETE " + delete.toString());
361 }
362 } catch (IOException e) {
363 throw new WebApplicationException(e,
364 Response.Status.SERVICE_UNAVAILABLE);
365 } finally {
366 if (table != null) {
367 try {
368 pool.putTable(table);
369 } catch (IOException ioe) {
370 throw new WebApplicationException(ioe,
371 Response.Status.SERVICE_UNAVAILABLE);
372 }
373 }
374 }
375 return Response.ok().build();
376 }
377 }