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