3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 package org
.apache
.hadoop
.hbase
.rest
;
22 import java
.io
.IOException
;
23 import java
.util
.ArrayList
;
24 import java
.util
.List
;
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
.core
.Context
;
33 import javax
.ws
.rs
.core
.HttpHeaders
;
34 import javax
.ws
.rs
.core
.MultivaluedMap
;
35 import javax
.ws
.rs
.core
.Response
;
36 import javax
.ws
.rs
.core
.Response
.ResponseBuilder
;
37 import javax
.ws
.rs
.core
.UriInfo
;
39 import org
.apache
.commons
.lang3
.StringUtils
;
40 import org
.apache
.hadoop
.hbase
.Cell
;
41 import org
.apache
.hadoop
.hbase
.Cell
.Type
;
42 import org
.apache
.hadoop
.hbase
.CellBuilderFactory
;
43 import org
.apache
.hadoop
.hbase
.CellBuilderType
;
44 import org
.apache
.hadoop
.hbase
.CellUtil
;
45 import org
.apache
.hadoop
.hbase
.HConstants
;
46 import org
.apache
.hadoop
.hbase
.client
.Append
;
47 import org
.apache
.hadoop
.hbase
.client
.Delete
;
48 import org
.apache
.hadoop
.hbase
.client
.Increment
;
49 import org
.apache
.hadoop
.hbase
.client
.Put
;
50 import org
.apache
.hadoop
.hbase
.client
.Result
;
51 import org
.apache
.hadoop
.hbase
.client
.Table
;
52 import org
.apache
.hadoop
.hbase
.rest
.model
.CellModel
;
53 import org
.apache
.hadoop
.hbase
.rest
.model
.CellSetModel
;
54 import org
.apache
.hadoop
.hbase
.rest
.model
.RowModel
;
55 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
56 import org
.apache
.yetus
.audience
.InterfaceAudience
;
57 import org
.slf4j
.Logger
;
58 import org
.slf4j
.LoggerFactory
;
60 @InterfaceAudience.Private
61 public class RowResource
extends ResourceBase
{
62 private static final Logger LOG
= LoggerFactory
.getLogger(RowResource
.class);
64 private static final String CHECK_PUT
= "put";
65 private static final String CHECK_DELETE
= "delete";
66 private static final String CHECK_APPEND
= "append";
67 private static final String CHECK_INCREMENT
= "increment";
69 private TableResource tableResource
;
70 private RowSpec rowspec
;
71 private String check
= null;
72 private boolean returnResult
= false;
76 * @param tableResource
83 public RowResource(TableResource tableResource
, String rowspec
,
84 String versions
, String check
, String returnResult
) throws IOException
{
86 this.tableResource
= tableResource
;
87 this.rowspec
= new RowSpec(rowspec
);
88 if (versions
!= null) {
89 this.rowspec
.setMaxVersions(Integer
.parseInt(versions
));
92 if (returnResult
!= null) {
93 this.returnResult
= Boolean
.valueOf(returnResult
);
98 @Produces({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
99 MIMETYPE_PROTOBUF_IETF
})
100 public Response
get(final @Context UriInfo uriInfo
) {
101 if (LOG
.isTraceEnabled()) {
102 LOG
.trace("GET " + uriInfo
.getAbsolutePath());
104 servlet
.getMetrics().incrementRequests(1);
105 MultivaluedMap
<String
, String
> params
= uriInfo
.getQueryParameters();
107 ResultGenerator generator
=
108 ResultGenerator
.fromRowSpec(tableResource
.getName(), rowspec
, null,
109 !params
.containsKey(NOCACHE_PARAM_NAME
));
110 if (!generator
.hasNext()) {
111 servlet
.getMetrics().incrementFailedGetRequests(1);
112 return Response
.status(Response
.Status
.NOT_FOUND
)
113 .type(MIMETYPE_TEXT
).entity("Not found" + CRLF
)
117 CellSetModel model
= new CellSetModel();
118 Cell value
= generator
.next();
119 byte[] rowKey
= CellUtil
.cloneRow(value
);
120 RowModel rowModel
= new RowModel(rowKey
);
122 if (!Bytes
.equals(CellUtil
.cloneRow(value
), rowKey
)) {
123 model
.addRow(rowModel
);
124 rowKey
= CellUtil
.cloneRow(value
);
125 rowModel
= new RowModel(rowKey
);
127 rowModel
.addCell(new CellModel(CellUtil
.cloneFamily(value
), CellUtil
.cloneQualifier(value
),
128 value
.getTimestamp(), CellUtil
.cloneValue(value
)));
129 if (++count
> rowspec
.getMaxValues()) {
132 value
= generator
.next();
133 } while (value
!= null);
134 model
.addRow(rowModel
);
135 servlet
.getMetrics().incrementSucessfulGetRequests(1);
136 return Response
.ok(model
).build();
137 } catch (Exception e
) {
138 servlet
.getMetrics().incrementFailedPutRequests(1);
139 return processException(e
);
144 @Produces(MIMETYPE_BINARY
)
145 public Response
getBinary(final @Context UriInfo uriInfo
) {
146 if (LOG
.isTraceEnabled()) {
147 LOG
.trace("GET " + uriInfo
.getAbsolutePath() + " as "+ MIMETYPE_BINARY
);
149 servlet
.getMetrics().incrementRequests(1);
150 // doesn't make sense to use a non specific coordinate as this can only
151 // return a single cell
152 if (!rowspec
.hasColumns() || rowspec
.getColumns().length
> 1) {
153 servlet
.getMetrics().incrementFailedGetRequests(1);
154 return Response
.status(Response
.Status
.BAD_REQUEST
).type(MIMETYPE_TEXT
)
155 .entity("Bad request: Default 'GET' method only works if there is exactly 1 column " +
156 "in the row. Using the 'Accept' header with one of these formats lets you " +
157 "retrieve the entire row if it has multiple columns: " +
158 // Same as the @Produces list for the get method.
159 MIMETYPE_XML
+ ", " + MIMETYPE_JSON
+ ", " +
160 MIMETYPE_PROTOBUF
+ ", " + MIMETYPE_PROTOBUF_IETF
+
163 MultivaluedMap
<String
, String
> params
= uriInfo
.getQueryParameters();
165 ResultGenerator generator
=
166 ResultGenerator
.fromRowSpec(tableResource
.getName(), rowspec
, null,
167 !params
.containsKey(NOCACHE_PARAM_NAME
));
168 if (!generator
.hasNext()) {
169 servlet
.getMetrics().incrementFailedGetRequests(1);
170 return Response
.status(Response
.Status
.NOT_FOUND
)
171 .type(MIMETYPE_TEXT
).entity("Not found" + CRLF
)
174 Cell value
= generator
.next();
175 ResponseBuilder response
= Response
.ok(CellUtil
.cloneValue(value
));
176 response
.header("X-Timestamp", value
.getTimestamp());
177 servlet
.getMetrics().incrementSucessfulGetRequests(1);
178 return response
.build();
179 } catch (Exception e
) {
180 servlet
.getMetrics().incrementFailedGetRequests(1);
181 return processException(e
);
185 Response
update(final CellSetModel model
, final boolean replace
) {
186 servlet
.getMetrics().incrementRequests(1);
187 if (servlet
.isReadOnly()) {
188 servlet
.getMetrics().incrementFailedPutRequests(1);
189 return Response
.status(Response
.Status
.FORBIDDEN
)
190 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
194 if (CHECK_PUT
.equalsIgnoreCase(check
)) {
195 return checkAndPut(model
);
196 } else if (CHECK_DELETE
.equalsIgnoreCase(check
)) {
197 return checkAndDelete(model
);
198 } else if (CHECK_APPEND
.equalsIgnoreCase(check
)) {
199 return append(model
);
200 } else if (CHECK_INCREMENT
.equalsIgnoreCase(check
)) {
201 return increment(model
);
202 } else if (check
!= null && check
.length() > 0) {
203 return Response
.status(Response
.Status
.BAD_REQUEST
)
204 .type(MIMETYPE_TEXT
).entity("Invalid check value '" + check
+ "'" + CRLF
)
210 List
<RowModel
> rows
= model
.getRows();
211 List
<Put
> puts
= new ArrayList
<>();
212 for (RowModel row
: rows
) {
213 byte[] key
= row
.getKey();
215 key
= rowspec
.getRow();
218 servlet
.getMetrics().incrementFailedPutRequests(1);
219 return Response
.status(Response
.Status
.BAD_REQUEST
)
220 .type(MIMETYPE_TEXT
).entity("Bad request: Row key not specified." + CRLF
)
223 Put put
= new Put(key
);
225 for (CellModel cell
: row
.getCells()) {
226 byte[] col
= cell
.getColumn();
227 if (col
== null) try {
228 col
= rowspec
.getColumns()[i
++];
229 } catch (ArrayIndexOutOfBoundsException e
) {
233 servlet
.getMetrics().incrementFailedPutRequests(1);
234 return Response
.status(Response
.Status
.BAD_REQUEST
)
235 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
238 byte [][] parts
= CellUtil
.parseColumn(col
);
239 if (parts
.length
!= 2) {
240 return Response
.status(Response
.Status
.BAD_REQUEST
)
241 .type(MIMETYPE_TEXT
).entity("Bad request" + CRLF
)
244 put
.add(CellBuilderFactory
.create(CellBuilderType
.SHALLOW_COPY
)
245 .setRow(put
.getRow())
247 .setQualifier(parts
[1])
248 .setTimestamp(cell
.getTimestamp())
250 .setValue(cell
.getValue())
254 if (LOG
.isTraceEnabled()) {
255 LOG
.trace("PUT " + put
.toString());
258 table
= servlet
.getTable(tableResource
.getName());
260 ResponseBuilder response
= Response
.ok();
261 servlet
.getMetrics().incrementSucessfulPutRequests(1);
262 return response
.build();
263 } catch (Exception e
) {
264 servlet
.getMetrics().incrementFailedPutRequests(1);
265 return processException(e
);
267 if (table
!= null) try {
269 } catch (IOException ioe
) {
270 LOG
.debug("Exception received while closing the table", ioe
);
275 // This currently supports only update of one row at a time.
276 Response
updateBinary(final byte[] message
, final HttpHeaders headers
,
277 final boolean replace
) {
278 servlet
.getMetrics().incrementRequests(1);
279 if (servlet
.isReadOnly()) {
280 servlet
.getMetrics().incrementFailedPutRequests(1);
281 return Response
.status(Response
.Status
.FORBIDDEN
)
282 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
287 byte[] row
= rowspec
.getRow();
288 byte[][] columns
= rowspec
.getColumns();
289 byte[] column
= null;
290 if (columns
!= null) {
293 long timestamp
= HConstants
.LATEST_TIMESTAMP
;
294 List
<String
> vals
= headers
.getRequestHeader("X-Row");
295 if (vals
!= null && !vals
.isEmpty()) {
296 row
= Bytes
.toBytes(vals
.get(0));
298 vals
= headers
.getRequestHeader("X-Column");
299 if (vals
!= null && !vals
.isEmpty()) {
300 column
= Bytes
.toBytes(vals
.get(0));
302 vals
= headers
.getRequestHeader("X-Timestamp");
303 if (vals
!= null && !vals
.isEmpty()) {
304 timestamp
= Long
.parseLong(vals
.get(0));
306 if (column
== null) {
307 servlet
.getMetrics().incrementFailedPutRequests(1);
308 return Response
.status(Response
.Status
.BAD_REQUEST
)
309 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
312 Put put
= new Put(row
);
313 byte parts
[][] = CellUtil
.parseColumn(column
);
314 if (parts
.length
!= 2) {
315 return Response
.status(Response
.Status
.BAD_REQUEST
)
316 .type(MIMETYPE_TEXT
).entity("Bad request" + CRLF
)
319 put
.add(CellBuilderFactory
.create(CellBuilderType
.SHALLOW_COPY
)
320 .setRow(put
.getRow())
322 .setQualifier(parts
[1])
323 .setTimestamp(timestamp
)
327 table
= servlet
.getTable(tableResource
.getName());
329 if (LOG
.isTraceEnabled()) {
330 LOG
.trace("PUT " + put
.toString());
332 servlet
.getMetrics().incrementSucessfulPutRequests(1);
333 return Response
.ok().build();
334 } catch (Exception e
) {
335 servlet
.getMetrics().incrementFailedPutRequests(1);
336 return processException(e
);
338 if (table
!= null) try {
340 } catch (IOException ioe
) {
341 LOG
.debug("Exception received while closing the table", ioe
);
347 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
348 MIMETYPE_PROTOBUF_IETF
})
349 public Response
put(final CellSetModel model
,
350 final @Context UriInfo uriInfo
) {
351 if (LOG
.isTraceEnabled()) {
352 LOG
.trace("PUT " + uriInfo
.getAbsolutePath()
353 + " " + uriInfo
.getQueryParameters());
355 return update(model
, true);
359 @Consumes(MIMETYPE_BINARY
)
360 public Response
putBinary(final byte[] message
,
361 final @Context UriInfo uriInfo
, final @Context HttpHeaders headers
) {
362 if (LOG
.isTraceEnabled()) {
363 LOG
.trace("PUT " + uriInfo
.getAbsolutePath() + " as "+ MIMETYPE_BINARY
);
365 return updateBinary(message
, headers
, true);
369 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
370 MIMETYPE_PROTOBUF_IETF
})
371 public Response
post(final CellSetModel model
,
372 final @Context UriInfo uriInfo
) {
373 if (LOG
.isTraceEnabled()) {
374 LOG
.trace("POST " + uriInfo
.getAbsolutePath()
375 + " " + uriInfo
.getQueryParameters());
377 return update(model
, false);
381 @Consumes(MIMETYPE_BINARY
)
382 public Response
postBinary(final byte[] message
,
383 final @Context UriInfo uriInfo
, final @Context HttpHeaders headers
) {
384 if (LOG
.isTraceEnabled()) {
385 LOG
.trace("POST " + uriInfo
.getAbsolutePath() + " as "+MIMETYPE_BINARY
);
387 return updateBinary(message
, headers
, false);
391 public Response
delete(final @Context UriInfo uriInfo
) {
392 if (LOG
.isTraceEnabled()) {
393 LOG
.trace("DELETE " + uriInfo
.getAbsolutePath());
395 servlet
.getMetrics().incrementRequests(1);
396 if (servlet
.isReadOnly()) {
397 servlet
.getMetrics().incrementFailedDeleteRequests(1);
398 return Response
.status(Response
.Status
.FORBIDDEN
)
399 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
402 Delete delete
= null;
403 if (rowspec
.hasTimestamp())
404 delete
= new Delete(rowspec
.getRow(), rowspec
.getTimestamp());
406 delete
= new Delete(rowspec
.getRow());
408 for (byte[] column
: rowspec
.getColumns()) {
409 byte[][] split
= CellUtil
.parseColumn(column
);
410 if (rowspec
.hasTimestamp()) {
411 if (split
.length
== 1) {
412 delete
.addFamily(split
[0], rowspec
.getTimestamp());
413 } else if (split
.length
== 2) {
414 delete
.addColumns(split
[0], split
[1], rowspec
.getTimestamp());
416 return Response
.status(Response
.Status
.BAD_REQUEST
)
417 .type(MIMETYPE_TEXT
).entity("Bad request" + CRLF
)
421 if (split
.length
== 1) {
422 delete
.addFamily(split
[0]);
423 } else if (split
.length
== 2) {
424 delete
.addColumns(split
[0], split
[1]);
426 return Response
.status(Response
.Status
.BAD_REQUEST
)
427 .type(MIMETYPE_TEXT
).entity("Bad request" + CRLF
)
434 table
= servlet
.getTable(tableResource
.getName());
435 table
.delete(delete
);
436 servlet
.getMetrics().incrementSucessfulDeleteRequests(1);
437 if (LOG
.isTraceEnabled()) {
438 LOG
.trace("DELETE " + delete
.toString());
440 } catch (Exception e
) {
441 servlet
.getMetrics().incrementFailedDeleteRequests(1);
442 return processException(e
);
444 if (table
!= null) try {
446 } catch (IOException ioe
) {
447 LOG
.debug("Exception received while closing the table", ioe
);
450 return Response
.ok().build();
454 * Validates the input request parameters, parses columns from CellSetModel,
455 * and invokes checkAndPut on HTable.
457 * @param model instance of CellSetModel
458 * @return Response 200 OK, 304 Not modified, 400 Bad request
460 Response
checkAndPut(final CellSetModel model
) {
463 table
= servlet
.getTable(tableResource
.getName());
464 if (model
.getRows().size() != 1) {
465 servlet
.getMetrics().incrementFailedPutRequests(1);
466 return Response
.status(Response
.Status
.BAD_REQUEST
).type(MIMETYPE_TEXT
)
467 .entity("Bad request: Number of rows specified is not 1." + CRLF
).build();
470 RowModel rowModel
= model
.getRows().get(0);
471 byte[] key
= rowModel
.getKey();
473 key
= rowspec
.getRow();
476 List
<CellModel
> cellModels
= rowModel
.getCells();
477 int cellModelCount
= cellModels
.size();
478 if (key
== null || cellModelCount
<= 1) {
479 servlet
.getMetrics().incrementFailedPutRequests(1);
481 .status(Response
.Status
.BAD_REQUEST
)
484 "Bad request: Either row key is null or no data found for columns specified." + CRLF
)
488 Put put
= new Put(key
);
490 CellModel valueToCheckCell
= cellModels
.get(cellModelCount
- 1);
491 byte[] valueToCheckColumn
= valueToCheckCell
.getColumn();
492 byte[][] valueToPutParts
= CellUtil
.parseColumn(valueToCheckColumn
);
493 if (valueToPutParts
.length
== 2 && valueToPutParts
[1].length
> 0) {
494 CellModel valueToPutCell
= null;
496 // Copy all the cells to the Put request
497 // and track if the check cell's latest value is also sent
498 for (int i
= 0, n
= cellModelCount
- 1; i
< n
; i
++) {
499 CellModel cell
= cellModels
.get(i
);
500 byte[] col
= cell
.getColumn();
503 servlet
.getMetrics().incrementFailedPutRequests(1);
504 return Response
.status(Response
.Status
.BAD_REQUEST
)
505 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
509 byte [][] parts
= CellUtil
.parseColumn(col
);
511 if (parts
.length
!= 2) {
512 return Response
.status(Response
.Status
.BAD_REQUEST
)
513 .type(MIMETYPE_TEXT
).entity("Bad request" + CRLF
)
516 put
.add(CellBuilderFactory
.create(CellBuilderType
.SHALLOW_COPY
)
517 .setRow(put
.getRow())
519 .setQualifier(parts
[1])
520 .setTimestamp(cell
.getTimestamp())
522 .setValue(cell
.getValue())
525 valueToCheckCell
.getColumn())) {
526 valueToPutCell
= cell
;
530 if (valueToPutCell
== null) {
531 servlet
.getMetrics().incrementFailedPutRequests(1);
532 return Response
.status(Response
.Status
.BAD_REQUEST
).type(MIMETYPE_TEXT
)
533 .entity("Bad request: The column to put and check do not match." + CRLF
).build();
535 retValue
= table
.checkAndMutate(key
, valueToPutParts
[0]).qualifier(valueToPutParts
[1])
536 .ifEquals(valueToCheckCell
.getValue()).thenPut(put
);
539 servlet
.getMetrics().incrementFailedPutRequests(1);
540 return Response
.status(Response
.Status
.BAD_REQUEST
)
541 .type(MIMETYPE_TEXT
).entity("Bad request: Column incorrectly specified." + CRLF
)
545 if (LOG
.isTraceEnabled()) {
546 LOG
.trace("CHECK-AND-PUT " + put
.toString() + ", returns " + retValue
);
549 servlet
.getMetrics().incrementFailedPutRequests(1);
550 return Response
.status(Response
.Status
.NOT_MODIFIED
)
551 .type(MIMETYPE_TEXT
).entity("Value not Modified" + CRLF
)
554 ResponseBuilder response
= Response
.ok();
555 servlet
.getMetrics().incrementSucessfulPutRequests(1);
556 return response
.build();
557 } catch (Exception e
) {
558 servlet
.getMetrics().incrementFailedPutRequests(1);
559 return processException(e
);
561 if (table
!= null) try {
563 } catch (IOException ioe
) {
564 LOG
.debug("Exception received while closing the table", ioe
);
570 * Validates the input request parameters, parses columns from CellSetModel,
571 * and invokes checkAndDelete on HTable.
573 * @param model instance of CellSetModel
574 * @return Response 200 OK, 304 Not modified, 400 Bad request
576 Response
checkAndDelete(final CellSetModel model
) {
578 Delete delete
= null;
580 table
= servlet
.getTable(tableResource
.getName());
581 if (model
.getRows().size() != 1) {
582 servlet
.getMetrics().incrementFailedDeleteRequests(1);
583 return Response
.status(Response
.Status
.BAD_REQUEST
)
584 .type(MIMETYPE_TEXT
).entity("Bad request: Number of rows specified is not 1." + CRLF
)
587 RowModel rowModel
= model
.getRows().get(0);
588 byte[] key
= rowModel
.getKey();
590 key
= rowspec
.getRow();
593 servlet
.getMetrics().incrementFailedDeleteRequests(1);
594 return Response
.status(Response
.Status
.BAD_REQUEST
)
595 .type(MIMETYPE_TEXT
).entity("Bad request: Row key found to be null." + CRLF
)
599 List
<CellModel
> cellModels
= rowModel
.getCells();
600 int cellModelCount
= cellModels
.size();
602 delete
= new Delete(key
);
604 CellModel valueToDeleteCell
= rowModel
.getCells().get(cellModelCount
-1);
605 byte[] valueToDeleteColumn
= valueToDeleteCell
.getColumn();
606 if (valueToDeleteColumn
== null) {
608 valueToDeleteColumn
= rowspec
.getColumns()[0];
609 } catch (final ArrayIndexOutOfBoundsException e
) {
610 servlet
.getMetrics().incrementFailedDeleteRequests(1);
611 return Response
.status(Response
.Status
.BAD_REQUEST
)
612 .type(MIMETYPE_TEXT
).entity("Bad request: Column not specified for check." + CRLF
)
618 // Copy all the cells to the Delete request if extra cells are sent
619 if(cellModelCount
> 1) {
620 for (int i
= 0, n
= cellModelCount
- 1; i
< n
; i
++) {
621 CellModel cell
= cellModels
.get(i
);
622 byte[] col
= cell
.getColumn();
625 servlet
.getMetrics().incrementFailedPutRequests(1);
626 return Response
.status(Response
.Status
.BAD_REQUEST
)
627 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
631 parts
= CellUtil
.parseColumn(col
);
633 if (parts
.length
== 1) {
634 // Only Column Family is specified
635 delete
.addFamily(parts
[0], cell
.getTimestamp());
636 } else if (parts
.length
== 2) {
637 delete
.addColumn(parts
[0], parts
[1], cell
.getTimestamp());
639 servlet
.getMetrics().incrementFailedDeleteRequests(1);
640 return Response
.status(Response
.Status
.BAD_REQUEST
)
642 .entity("Bad request: Column to delete incorrectly specified." + CRLF
)
648 parts
= CellUtil
.parseColumn(valueToDeleteColumn
);
649 if (parts
.length
== 2) {
650 if (parts
[1].length
!= 0) {
651 // To support backcompat of deleting a cell
652 // if that is the only cell passed to the rest api
653 if(cellModelCount
== 1) {
654 delete
.addColumns(parts
[0], parts
[1]);
656 retValue
= table
.checkAndMutate(key
, parts
[0]).qualifier(parts
[1])
657 .ifEquals(valueToDeleteCell
.getValue()).thenDelete(delete
);
659 // The case of empty qualifier.
660 if(cellModelCount
== 1) {
661 delete
.addColumns(parts
[0], Bytes
.toBytes(StringUtils
.EMPTY
));
663 retValue
= table
.checkAndMutate(key
, parts
[0])
664 .ifEquals(valueToDeleteCell
.getValue()).thenDelete(delete
);
667 servlet
.getMetrics().incrementFailedDeleteRequests(1);
668 return Response
.status(Response
.Status
.BAD_REQUEST
)
669 .type(MIMETYPE_TEXT
).entity("Bad request: Column to check incorrectly specified." + CRLF
)
673 if (LOG
.isTraceEnabled()) {
674 LOG
.trace("CHECK-AND-DELETE " + delete
.toString() + ", returns "
679 servlet
.getMetrics().incrementFailedDeleteRequests(1);
680 return Response
.status(Response
.Status
.NOT_MODIFIED
)
681 .type(MIMETYPE_TEXT
).entity(" Delete check failed." + CRLF
)
684 ResponseBuilder response
= Response
.ok();
685 servlet
.getMetrics().incrementSucessfulDeleteRequests(1);
686 return response
.build();
687 } catch (Exception e
) {
688 servlet
.getMetrics().incrementFailedDeleteRequests(1);
689 return processException(e
);
691 if (table
!= null) try {
693 } catch (IOException ioe
) {
694 LOG
.debug("Exception received while closing the table", ioe
);
700 * Validates the input request parameters, parses columns from CellSetModel,
701 * and invokes Append on HTable.
703 * @param model instance of CellSetModel
704 * @return Response 200 OK, 304 Not modified, 400 Bad request
706 Response
append(final CellSetModel model
) {
708 Append append
= null;
710 table
= servlet
.getTable(tableResource
.getName());
711 if (model
.getRows().size() != 1) {
712 servlet
.getMetrics().incrementFailedAppendRequests(1);
713 return Response
.status(Response
.Status
.BAD_REQUEST
)
714 .type(MIMETYPE_TEXT
).entity("Bad request: Number of rows specified is not 1." + CRLF
)
717 RowModel rowModel
= model
.getRows().get(0);
718 byte[] key
= rowModel
.getKey();
720 key
= rowspec
.getRow();
723 servlet
.getMetrics().incrementFailedAppendRequests(1);
724 return Response
.status(Response
.Status
.BAD_REQUEST
)
725 .type(MIMETYPE_TEXT
).entity("Bad request: Row key found to be null." + CRLF
)
729 append
= new Append(key
);
730 append
.setReturnResults(returnResult
);
732 for (CellModel cell
: rowModel
.getCells()) {
733 byte[] col
= cell
.getColumn();
736 col
= rowspec
.getColumns()[i
++];
737 } catch (ArrayIndexOutOfBoundsException e
) {
742 servlet
.getMetrics().incrementFailedAppendRequests(1);
743 return Response
.status(Response
.Status
.BAD_REQUEST
)
744 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
747 byte [][] parts
= CellUtil
.parseColumn(col
);
748 if (parts
.length
!= 2) {
749 servlet
.getMetrics().incrementFailedAppendRequests(1);
750 return Response
.status(Response
.Status
.BAD_REQUEST
)
751 .type(MIMETYPE_TEXT
).entity("Bad request: Column incorrectly specified." + CRLF
)
754 append
.addColumn(parts
[0], parts
[1], cell
.getValue());
757 if (LOG
.isDebugEnabled()) {
758 LOG
.debug("APPEND " + append
.toString());
760 Result result
= table
.append(append
);
762 if (result
.isEmpty()) {
763 servlet
.getMetrics().incrementFailedAppendRequests(1);
764 return Response
.status(Response
.Status
.NOT_MODIFIED
)
765 .type(MIMETYPE_TEXT
).entity("Append return empty." + CRLF
)
769 CellSetModel rModel
= new CellSetModel();
770 RowModel rRowModel
= new RowModel(result
.getRow());
771 for (Cell cell
: result
.listCells()) {
772 rRowModel
.addCell(new CellModel(CellUtil
.cloneFamily(cell
), CellUtil
.cloneQualifier(cell
),
773 cell
.getTimestamp(), CellUtil
.cloneValue(cell
)));
775 rModel
.addRow(rRowModel
);
776 servlet
.getMetrics().incrementSucessfulAppendRequests(1);
777 return Response
.ok(rModel
).build();
779 servlet
.getMetrics().incrementSucessfulAppendRequests(1);
780 return Response
.ok().build();
781 } catch (Exception e
) {
782 servlet
.getMetrics().incrementFailedAppendRequests(1);
783 return processException(e
);
785 if (table
!= null) try {
787 } catch (IOException ioe
) {
788 LOG
.debug("Exception received while closing the table" + table
.getName(), ioe
);
794 * Validates the input request parameters, parses columns from CellSetModel,
795 * and invokes Increment on HTable.
797 * @param model instance of CellSetModel
798 * @return Response 200 OK, 304 Not modified, 400 Bad request
800 Response
increment(final CellSetModel model
) {
802 Increment increment
= null;
804 table
= servlet
.getTable(tableResource
.getName());
805 if (model
.getRows().size() != 1) {
806 servlet
.getMetrics().incrementFailedIncrementRequests(1);
807 return Response
.status(Response
.Status
.BAD_REQUEST
)
808 .type(MIMETYPE_TEXT
).entity("Bad request: Number of rows specified is not 1." + CRLF
)
811 RowModel rowModel
= model
.getRows().get(0);
812 byte[] key
= rowModel
.getKey();
814 key
= rowspec
.getRow();
817 servlet
.getMetrics().incrementFailedIncrementRequests(1);
818 return Response
.status(Response
.Status
.BAD_REQUEST
)
819 .type(MIMETYPE_TEXT
).entity("Bad request: Row key found to be null." + CRLF
)
823 increment
= new Increment(key
);
824 increment
.setReturnResults(returnResult
);
826 for (CellModel cell
: rowModel
.getCells()) {
827 byte[] col
= cell
.getColumn();
830 col
= rowspec
.getColumns()[i
++];
831 } catch (ArrayIndexOutOfBoundsException e
) {
836 servlet
.getMetrics().incrementFailedIncrementRequests(1);
837 return Response
.status(Response
.Status
.BAD_REQUEST
)
838 .type(MIMETYPE_TEXT
).entity("Bad request: Column found to be null." + CRLF
)
841 byte [][] parts
= CellUtil
.parseColumn(col
);
842 if (parts
.length
!= 2) {
843 servlet
.getMetrics().incrementFailedIncrementRequests(1);
844 return Response
.status(Response
.Status
.BAD_REQUEST
)
845 .type(MIMETYPE_TEXT
).entity("Bad request: Column incorrectly specified." + CRLF
)
848 increment
.addColumn(parts
[0], parts
[1], Long
.parseLong(Bytes
.toStringBinary(cell
.getValue())));
851 if (LOG
.isDebugEnabled()) {
852 LOG
.debug("INCREMENT " + increment
.toString());
854 Result result
= table
.increment(increment
);
857 if (result
.isEmpty()) {
858 servlet
.getMetrics().incrementFailedIncrementRequests(1);
859 return Response
.status(Response
.Status
.NOT_MODIFIED
)
860 .type(MIMETYPE_TEXT
).entity("Increment return empty." + CRLF
)
864 CellSetModel rModel
= new CellSetModel();
865 RowModel rRowModel
= new RowModel(result
.getRow());
866 for (Cell cell
: result
.listCells()) {
867 rRowModel
.addCell(new CellModel(CellUtil
.cloneFamily(cell
), CellUtil
.cloneQualifier(cell
),
868 cell
.getTimestamp(), CellUtil
.cloneValue(cell
)));
870 rModel
.addRow(rowModel
);
871 servlet
.getMetrics().incrementSucessfulIncrementRequests(1);
872 return Response
.ok(rModel
).build();
875 ResponseBuilder response
= Response
.ok();
876 servlet
.getMetrics().incrementSucessfulIncrementRequests(1);
877 return response
.build();
878 } catch (Exception e
) {
879 servlet
.getMetrics().incrementFailedIncrementRequests(1);
880 return processException(e
);
882 if (table
!= null) try {
884 } catch (IOException ioe
) {
885 LOG
.debug("Exception received while closing the table " + table
.getName(), ioe
);