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 Put put = new Put(key);
166 for (CellModel cell: row.getCells()) {
167 byte [][] parts = KeyValue.parseColumn(cell.getColumn());
168 if (parts.length == 2 && parts[1].length > 0) {
169 put.add(parts[0], parts[1], cell.getTimestamp(),
170 tableResource.transform(parts[0], parts[1], cell.getValue(),
171 Transform.Direction.IN));
172 } else {
173 put.add(parts[0], null, cell.getTimestamp(),
174 tableResource.transform(parts[0], null, cell.getValue(),
175 Transform.Direction.IN));
176 }
177 }
178 table.put(put);
179 if (LOG.isDebugEnabled()) {
180 LOG.debug("PUT " + put.toString());
181 }
182 }
183 ((HTable)table).setAutoFlush(true);
184 table.flushCommits();
185 ResponseBuilder response = Response.ok();
186 return response.build();
187 } catch (IOException e) {
188 throw new WebApplicationException(e,
189 Response.Status.SERVICE_UNAVAILABLE);
190 } finally {
191 if (table != null) {
192 pool.putTable(table);
193 }
194 }
195 }
196
197
198 Response updateBinary(final byte[] message, final HttpHeaders headers,
199 final boolean replace) {
200 servlet.getMetrics().incrementRequests(1);
201 if (servlet.isReadOnly()) {
202 throw new WebApplicationException(Response.Status.FORBIDDEN);
203 }
204 HTablePool pool = servlet.getTablePool();
205 HTableInterface table = null;
206 try {
207 byte[] row = rowspec.getRow();
208 byte[][] columns = rowspec.getColumns();
209 byte[] column = null;
210 if (columns != null) {
211 column = columns[0];
212 }
213 long timestamp = HConstants.LATEST_TIMESTAMP;
214 List<String> vals = headers.getRequestHeader("X-Row");
215 if (vals != null && !vals.isEmpty()) {
216 row = Bytes.toBytes(vals.get(0));
217 }
218 vals = headers.getRequestHeader("X-Column");
219 if (vals != null && !vals.isEmpty()) {
220 column = Bytes.toBytes(vals.get(0));
221 }
222 vals = headers.getRequestHeader("X-Timestamp");
223 if (vals != null && !vals.isEmpty()) {
224 timestamp = Long.valueOf(vals.get(0));
225 }
226 if (column == null) {
227 throw new WebApplicationException(Response.Status.BAD_REQUEST);
228 }
229 Put put = new Put(row);
230 byte parts[][] = KeyValue.parseColumn(column);
231 if (parts.length == 2 && parts[1].length > 0) {
232 put.add(parts[0], parts[1], timestamp,
233 tableResource.transform(parts[0], parts[1], message,
234 Transform.Direction.IN));
235 } else {
236 put.add(parts[0], null, timestamp,
237 tableResource.transform(parts[0], null, message,
238 Transform.Direction.IN));
239 }
240 table = pool.getTable(tableResource.getName());
241 table.put(put);
242 if (LOG.isDebugEnabled()) {
243 LOG.debug("PUT " + put.toString());
244 }
245 return Response.ok().build();
246 } catch (IOException e) {
247 throw new WebApplicationException(e,
248 Response.Status.SERVICE_UNAVAILABLE);
249 } finally {
250 if (table != null) {
251 pool.putTable(table);
252 }
253 }
254 }
255
256 @PUT
257 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
258 public Response put(final CellSetModel model,
259 final @Context UriInfo uriInfo) {
260 if (LOG.isDebugEnabled()) {
261 LOG.debug("PUT " + uriInfo.getAbsolutePath());
262 }
263 return update(model, true);
264 }
265
266 @PUT
267 @Consumes(MIMETYPE_BINARY)
268 public Response putBinary(final byte[] message,
269 final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
270 if (LOG.isDebugEnabled()) {
271 LOG.debug("PUT " + uriInfo.getAbsolutePath() + " as "+ MIMETYPE_BINARY);
272 }
273 return updateBinary(message, headers, true);
274 }
275
276 @POST
277 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
278 public Response post(final CellSetModel model,
279 final @Context UriInfo uriInfo) {
280 if (LOG.isDebugEnabled()) {
281 LOG.debug("POST " + uriInfo.getAbsolutePath());
282 }
283 return update(model, false);
284 }
285
286 @POST
287 @Consumes(MIMETYPE_BINARY)
288 public Response postBinary(final byte[] message,
289 final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
290 if (LOG.isDebugEnabled()) {
291 LOG.debug("POST " + uriInfo.getAbsolutePath() + " as "+MIMETYPE_BINARY);
292 }
293 return updateBinary(message, headers, false);
294 }
295
296 @DELETE
297 public Response delete(final @Context UriInfo uriInfo) {
298 if (LOG.isDebugEnabled()) {
299 LOG.debug("DELETE " + uriInfo.getAbsolutePath());
300 }
301 servlet.getMetrics().incrementRequests(1);
302 if (servlet.isReadOnly()) {
303 throw new WebApplicationException(Response.Status.FORBIDDEN);
304 }
305 Delete delete = null;
306 if (rowspec.hasTimestamp())
307 delete = new Delete(rowspec.getRow(), rowspec.getTimestamp(), null);
308 else
309 delete = new Delete(rowspec.getRow());
310
311 for (byte[] column: rowspec.getColumns()) {
312 byte[][] split = KeyValue.parseColumn(column);
313 if (rowspec.hasTimestamp()) {
314 if (split.length == 2 && split[1].length != 0) {
315 delete.deleteColumns(split[0], split[1], rowspec.getTimestamp());
316 } else {
317 delete.deleteFamily(split[0], rowspec.getTimestamp());
318 }
319 } else {
320 if (split.length == 2 && split[1].length != 0) {
321 delete.deleteColumns(split[0], split[1]);
322 } else {
323 delete.deleteFamily(split[0]);
324 }
325 }
326 }
327 HTablePool pool = servlet.getTablePool();
328 HTableInterface table = null;
329 try {
330 table = pool.getTable(tableResource.getName());
331 table.delete(delete);
332 if (LOG.isDebugEnabled()) {
333 LOG.debug("DELETE " + delete.toString());
334 }
335 } catch (IOException e) {
336 throw new WebApplicationException(e,
337 Response.Status.SERVICE_UNAVAILABLE);
338 } finally {
339 if (table != null) {
340 pool.putTable(table);
341 }
342 }
343 return Response.ok().build();
344 }
345 }