View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.rest;
19  
20  import static org.junit.Assert.assertEquals;
21  
22  import com.fasterxml.jackson.databind.ObjectMapper;
23  import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.IOException;
27  import java.io.StringWriter;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  import javax.ws.rs.core.MediaType;
32  import javax.xml.bind.JAXBContext;
33  import javax.xml.bind.JAXBException;
34  import javax.xml.bind.Marshaller;
35  import javax.xml.bind.Unmarshaller;
36  
37  import org.apache.hadoop.conf.Configuration;
38  import org.apache.hadoop.hbase.HBaseTestingUtility;
39  import org.apache.hadoop.hbase.HColumnDescriptor;
40  import org.apache.hadoop.hbase.HTableDescriptor;
41  import org.apache.hadoop.hbase.TableName;
42  import org.apache.hadoop.hbase.client.Admin;
43  import org.apache.hadoop.hbase.rest.client.Client;
44  import org.apache.hadoop.hbase.rest.client.Cluster;
45  import org.apache.hadoop.hbase.rest.client.Response;
46  import org.apache.hadoop.hbase.rest.model.CellModel;
47  import org.apache.hadoop.hbase.rest.model.CellSetModel;
48  import org.apache.hadoop.hbase.rest.model.RowModel;
49  import org.apache.hadoop.hbase.rest.provider.JacksonProvider;
50  import org.apache.hadoop.hbase.util.Bytes;
51  import org.junit.After;
52  import org.junit.AfterClass;
53  import org.junit.Before;
54  import org.junit.BeforeClass;
55  
56  public class RowResourceBase {
57    protected static final String TABLE = "TestRowResource";
58    protected static final String CFA = "a";
59    protected static final String CFB = "b";
60    protected static final String COLUMN_1 = CFA + ":1";
61    protected static final String COLUMN_2 = CFB + ":2";
62    protected static final String COLUMN_3 = CFA + ":";
63    protected static final String ROW_1 = "testrow1";
64    protected static final String VALUE_1 = "testvalue1";
65    protected static final String ROW_2 = "testrow2";
66    protected static final String VALUE_2 = "testvalue2";
67    protected static final String ROW_3 = "testrow3";
68    protected static final String VALUE_3 = "testvalue3";
69    protected static final String ROW_4 = "testrow4";
70    protected static final String VALUE_4 = "testvalue4";
71    protected static final String VALUE_5 = "5";
72    protected static final String VALUE_6 = "6";
73  
74    protected static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
75    protected static final HBaseRESTTestingUtility REST_TEST_UTIL =
76      new HBaseRESTTestingUtility();
77    protected static Client client;
78    protected static JAXBContext context;
79    protected static Marshaller xmlMarshaller;
80    protected static Unmarshaller xmlUnmarshaller;
81    protected static Configuration conf;
82    protected static ObjectMapper jsonMapper;
83  
84    @BeforeClass
85    public static void setUpBeforeClass() throws Exception {
86      conf = TEST_UTIL.getConfiguration();
87      TEST_UTIL.startMiniCluster(3);
88      REST_TEST_UTIL.startServletContainer(conf);
89      context = JAXBContext.newInstance(
90          CellModel.class,
91          CellSetModel.class,
92          RowModel.class);
93      xmlMarshaller = context.createMarshaller();
94      xmlUnmarshaller = context.createUnmarshaller();
95      jsonMapper = new JacksonProvider()
96      .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
97      client = new Client(new Cluster().add("localhost",
98        REST_TEST_UTIL.getServletPort()));
99    }
100 
101   @AfterClass
102   public static void tearDownAfterClass() throws Exception {
103     REST_TEST_UTIL.shutdownServletContainer();
104     TEST_UTIL.shutdownMiniCluster();
105   }
106 
107   @Before
108   public void beforeMethod() throws Exception {
109     Admin admin = TEST_UTIL.getHBaseAdmin();
110     if (admin.tableExists(TableName.valueOf(TABLE))) {
111       TEST_UTIL.deleteTable(Bytes.toBytes(TABLE));
112     }
113     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(TABLE));
114     htd.addFamily(new HColumnDescriptor(CFA));
115     htd.addFamily(new HColumnDescriptor(CFB));
116     admin.createTable(htd);
117   }
118 
119   @After
120   public void afterMethod() throws Exception {
121     Admin admin = TEST_UTIL.getHBaseAdmin();
122     if (admin.tableExists(TableName.valueOf(TABLE))) {
123       TEST_UTIL.deleteTable(Bytes.toBytes(TABLE));
124     }
125   }
126 
127   static Response putValuePB(String table, String row, String column,
128       String value) throws IOException {
129     StringBuilder path = new StringBuilder();
130     path.append('/');
131     path.append(table);
132     path.append('/');
133     path.append(row);
134     path.append('/');
135     path.append(column);
136     return putValuePB(path.toString(), table, row, column, value);
137   }
138 
139   static Response putValuePB(String url, String table, String row,
140       String column, String value) throws IOException {
141     RowModel rowModel = new RowModel(row);
142     rowModel.addCell(new CellModel(Bytes.toBytes(column),
143       Bytes.toBytes(value)));
144     CellSetModel cellSetModel = new CellSetModel();
145     cellSetModel.addRow(rowModel);
146     Response response = client.put(url, Constants.MIMETYPE_PROTOBUF,
147       cellSetModel.createProtobufOutput());
148     Thread.yield();
149     return response;
150   }
151 
152   protected static void checkValueXML(String url, String table, String row,
153       String column, String value) throws IOException, JAXBException {
154     Response response = getValueXML(url);
155     assertEquals(200, response.getCode());
156     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
157     CellSetModel cellSet = (CellSetModel)
158       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
159     RowModel rowModel = cellSet.getRows().get(0);
160     CellModel cell = rowModel.getCells().get(0);
161     assertEquals(Bytes.toString(cell.getColumn()), column);
162     assertEquals(Bytes.toString(cell.getValue()), value);
163   }
164 
165   protected static void checkValueXML(String table, String row, String column,
166       String value) throws IOException, JAXBException {
167     Response response = getValueXML(table, row, column);
168     assertEquals(200, response.getCode());
169     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
170     CellSetModel cellSet = (CellSetModel)
171       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
172     RowModel rowModel = cellSet.getRows().get(0);
173     CellModel cell = rowModel.getCells().get(0);
174     assertEquals(Bytes.toString(cell.getColumn()), column);
175     assertEquals(Bytes.toString(cell.getValue()), value);
176   }
177 
178   protected static void checkIncrementValueXML(String table, String row, String column, long value)
179       throws IOException, JAXBException {
180     Response response = getValueXML(table, row, column);
181     assertEquals(200, response.getCode());
182     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
183     CellSetModel cellSet = (CellSetModel)
184             xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
185     RowModel rowModel = cellSet.getRows().get(0);
186     CellModel cell = rowModel.getCells().get(0);
187     assertEquals(Bytes.toString(cell.getColumn()), column);
188     assertEquals(Bytes.toLong(cell.getValue()), value);
189   }
190 
191   protected static Response getValuePB(String url) throws IOException {
192     Response response = client.get(url, Constants.MIMETYPE_PROTOBUF); 
193     return response;
194   }
195 
196   protected static Response putValueXML(String table, String row, String column,
197       String value) throws IOException, JAXBException {
198     StringBuilder path = new StringBuilder();
199     path.append('/');
200     path.append(table);
201     path.append('/');
202     path.append(row);
203     path.append('/');
204     path.append(column);
205     return putValueXML(path.toString(), table, row, column, value);
206   }
207 
208   protected static Response putValueXML(String url, String table, String row,
209       String column, String value) throws IOException, JAXBException {
210     RowModel rowModel = new RowModel(row);
211     rowModel.addCell(new CellModel(Bytes.toBytes(column),
212       Bytes.toBytes(value)));
213     CellSetModel cellSetModel = new CellSetModel();
214     cellSetModel.addRow(rowModel);
215     StringWriter writer = new StringWriter();
216     xmlMarshaller.marshal(cellSetModel, writer);
217     Response response = client.put(url, Constants.MIMETYPE_XML,
218       Bytes.toBytes(writer.toString()));
219     Thread.yield();
220     return response;
221   }
222 
223   protected static Response getValuePB(String table, String row, String column)
224       throws IOException {
225     StringBuilder path = new StringBuilder();
226     path.append('/');
227     path.append(table);
228     path.append('/');
229     path.append(row);
230     path.append('/');
231     path.append(column);
232     return getValuePB(path.toString());
233   }
234 
235   protected static void checkValuePB(String table, String row, String column,
236       String value) throws IOException {
237     Response response = getValuePB(table, row, column);
238     assertEquals(200, response.getCode());
239     assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
240     CellSetModel cellSet = new CellSetModel();
241     cellSet.getObjectFromMessage(response.getBody());
242     RowModel rowModel = cellSet.getRows().get(0);
243     CellModel cell = rowModel.getCells().get(0);
244     assertEquals(Bytes.toString(cell.getColumn()), column);
245     assertEquals(Bytes.toString(cell.getValue()), value);
246   }
247 
248   protected static void checkIncrementValuePB(String table, String row, String column,
249       long value) throws IOException {
250     Response response = getValuePB(table, row, column);
251     assertEquals(200, response.getCode());
252     assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
253     CellSetModel cellSet = new CellSetModel();
254     cellSet.getObjectFromMessage(response.getBody());
255     RowModel rowModel = cellSet.getRows().get(0);
256     CellModel cell = rowModel.getCells().get(0);
257     assertEquals(Bytes.toString(cell.getColumn()), column);
258     assertEquals(Bytes.toLong(cell.getValue()), value);
259   }
260 
261   protected static Response checkAndPutValuePB(String url, String table, String row, String column,
262       String valueToCheck, String valueToPut, HashMap<String,String> otherCells)
263       throws IOException {
264     RowModel rowModel = new RowModel(row);
265     rowModel.addCell(new CellModel(Bytes.toBytes(column),
266       Bytes.toBytes(valueToPut)));
267 
268     if (otherCells != null) {
269       for (Map.Entry<String,String> entry : otherCells.entrySet()) {
270         rowModel.addCell(new CellModel(Bytes.toBytes(entry.getKey()),
271           Bytes.toBytes(entry.getValue())));
272       }
273     }
274 
275     // This Cell need to be added as last cell.
276     rowModel.addCell(new CellModel(Bytes.toBytes(column),
277       Bytes.toBytes(valueToCheck)));
278 
279     CellSetModel cellSetModel = new CellSetModel();
280     cellSetModel.addRow(rowModel);
281     Response response = client.put(url, Constants.MIMETYPE_PROTOBUF,
282       cellSetModel.createProtobufOutput());
283     Thread.yield();
284     return response;
285   }
286 
287   protected static Response checkAndPutValuePB(String table, String row,
288       String column, String valueToCheck, String valueToPut) throws IOException {
289     return checkAndPutValuePB(table,row,column,valueToCheck,valueToPut,null);
290   }
291 
292   protected static Response checkAndPutValuePB(String table, String row, String column,
293       String valueToCheck, String valueToPut, HashMap<String,String> otherCells)
294       throws IOException {
295     StringBuilder path = new StringBuilder();
296     path.append('/');
297     path.append(table);
298     path.append('/');
299     path.append(row);
300     path.append("?check=put");
301     return checkAndPutValuePB(path.toString(), table, row, column,
302       valueToCheck, valueToPut, otherCells);
303   }
304 
305   protected static Response checkAndPutValueXML(String url, String table, String row, String column,
306       String valueToCheck, String valueToPut, HashMap<String,String> otherCells)
307       throws IOException, JAXBException {
308     RowModel rowModel = new RowModel(row);
309     rowModel.addCell(new CellModel(Bytes.toBytes(column),
310       Bytes.toBytes(valueToPut)));
311 
312     if (otherCells != null) {
313       for (Map.Entry<String,String> entry : otherCells.entrySet()) {
314         rowModel.addCell(new CellModel(Bytes.toBytes(entry.getKey()),
315           Bytes.toBytes(entry.getValue())));
316       }
317     }
318 
319     // This Cell need to be added as last cell.
320     rowModel.addCell(new CellModel(Bytes.toBytes(column),
321       Bytes.toBytes(valueToCheck)));
322     CellSetModel cellSetModel = new CellSetModel();
323     cellSetModel.addRow(rowModel);
324     StringWriter writer = new StringWriter();
325     xmlMarshaller.marshal(cellSetModel, writer);
326     Response response = client.put(url, Constants.MIMETYPE_XML,
327       Bytes.toBytes(writer.toString()));
328     Thread.yield();
329     return response;
330   }
331 
332   protected static Response checkAndPutValueXML(String table, String row, String column,
333       String valueToCheck, String valueToPut) throws IOException, JAXBException {
334     return checkAndPutValueXML(table,row,column,valueToCheck,valueToPut, null);
335   }
336 
337   protected static Response checkAndPutValueXML(String table, String row,
338       String column, String valueToCheck, String valueToPut, HashMap<String,String> otherCells)
339         throws IOException, JAXBException {
340     StringBuilder path = new StringBuilder();
341     path.append('/');
342     path.append(table);
343     path.append('/');
344     path.append(row);
345     path.append("?check=put");
346     return checkAndPutValueXML(path.toString(), table, row, column,
347       valueToCheck, valueToPut, otherCells);
348   }
349 
350   protected static Response checkAndDeleteXML(String url, String table,
351       String row, String column, String valueToCheck, HashMap<String,String> cellsToDelete)
352         throws IOException, JAXBException {
353     RowModel rowModel = new RowModel(row);
354 
355     if (cellsToDelete != null) {
356       for (Map.Entry<String,String> entry : cellsToDelete.entrySet()) {
357         rowModel.addCell(new CellModel(Bytes.toBytes(entry.getKey()),
358           Bytes.toBytes(entry.getValue())));
359       }
360     }
361     // Add this at the end
362     rowModel.addCell(new CellModel(Bytes.toBytes(column),
363       Bytes.toBytes(valueToCheck)));
364     CellSetModel cellSetModel = new CellSetModel();
365     cellSetModel.addRow(rowModel);
366     StringWriter writer = new StringWriter();
367     xmlMarshaller.marshal(cellSetModel, writer);
368     Response response = client.put(url, Constants.MIMETYPE_XML,
369       Bytes.toBytes(writer.toString()));
370     Thread.yield();
371     return response;
372   }
373 
374   protected static Response checkAndDeleteXML(String table, String row,
375       String column, String valueToCheck) throws IOException, JAXBException {
376     return checkAndDeleteXML(table, row, column, valueToCheck, null);
377   }
378 
379   protected static Response checkAndDeleteXML(String table, String row,
380       String column, String valueToCheck, HashMap<String,String> cellsToDelete)
381       throws IOException, JAXBException {
382     StringBuilder path = new StringBuilder();
383     path.append('/');
384     path.append(table);
385     path.append('/');
386     path.append(row);
387     path.append("?check=delete");
388     return checkAndDeleteXML(path.toString(), table, row, column, valueToCheck, cellsToDelete);
389   }
390 
391   protected static Response checkAndDeleteJson(String table, String row,
392       String column, String valueToCheck) throws IOException {
393     return checkAndDeleteJson(table, row, column, valueToCheck, null);
394   }
395 
396   protected static Response checkAndDeleteJson(String table, String row,
397       String column, String valueToCheck, HashMap<String,String> cellsToDelete)
398       throws IOException {
399     StringBuilder path = new StringBuilder();
400     path.append('/');
401     path.append(table);
402     path.append('/');
403     path.append(row);
404     path.append("?check=delete");
405     return checkAndDeleteJson(path.toString(), table, row, column, valueToCheck, cellsToDelete);
406   }
407 
408   protected static Response checkAndDeleteJson(String url, String table,
409       String row, String column, String valueToCheck, HashMap<String,String> cellsToDelete)
410       throws IOException {
411     RowModel rowModel = new RowModel(row);
412 
413     if (cellsToDelete != null) {
414       for (Map.Entry<String,String> entry : cellsToDelete.entrySet()) {
415         rowModel.addCell(new CellModel(Bytes.toBytes(entry.getKey()),
416           Bytes.toBytes(entry.getValue())));
417       }
418     }
419     // Add this at the end
420     rowModel.addCell(new CellModel(Bytes.toBytes(column),
421       Bytes.toBytes(valueToCheck)));
422     CellSetModel cellSetModel = new CellSetModel();
423     cellSetModel.addRow(rowModel);
424     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
425     Response response = client.put(url, Constants.MIMETYPE_JSON,
426       Bytes.toBytes(jsonString));
427     Thread.yield();
428     return response;
429   }
430 
431   protected static Response checkAndDeletePB(String table, String row, String column, String value)
432       throws IOException {
433     return checkAndDeletePB(table, row, column, value, null);
434   }
435 
436   protected static Response checkAndDeletePB(String table, String row,
437       String column, String value, HashMap<String,String> cellsToDelete) throws IOException {
438     StringBuilder path = new StringBuilder();
439     path.append('/');
440     path.append(table);
441     path.append('/');
442     path.append(row);
443     path.append("?check=delete");
444     return checkAndDeleteValuePB(path.toString(), table, row, column, value, cellsToDelete);
445   }
446   protected static Response checkAndDeleteValuePB(String url, String table,
447       String row, String column, String valueToCheck, HashMap<String,String> cellsToDelete)
448       throws IOException {
449     RowModel rowModel = new RowModel(row);
450 
451     if (cellsToDelete != null) {
452       for (Map.Entry<String,String> entry : cellsToDelete.entrySet()) {
453         rowModel.addCell(new CellModel(Bytes.toBytes(entry.getKey()),
454           Bytes.toBytes(entry.getValue())));
455       }
456     }
457     // Add this at the end
458     rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes
459         .toBytes(valueToCheck)));
460     CellSetModel cellSetModel = new CellSetModel();
461     cellSetModel.addRow(rowModel);
462     Response response = client.put(url, Constants.MIMETYPE_PROTOBUF,
463         cellSetModel.createProtobufOutput());
464     Thread.yield();
465     return response;
466   }
467 
468   protected static Response getValueXML(String table, String startRow,
469       String endRow, String column) throws IOException {
470     StringBuilder path = new StringBuilder();
471     path.append('/');
472     path.append(table);
473     path.append('/');
474     path.append(startRow);
475     path.append(",");
476     path.append(endRow);
477     path.append('/');
478     path.append(column);
479     return getValueXML(path.toString());
480   }
481 
482   protected static Response getValueXML(String url) throws IOException {
483     Response response = client.get(url, Constants.MIMETYPE_XML);
484     return response;
485   }
486 
487   protected static Response getValueJson(String url) throws IOException {
488     Response response = client.get(url, Constants.MIMETYPE_JSON);
489     return response;
490   }
491 
492   protected static Response deleteValue(String table, String row, String column)
493       throws IOException {
494     StringBuilder path = new StringBuilder();
495     path.append('/');
496     path.append(table);
497     path.append('/');
498     path.append(row);
499     path.append('/');
500     path.append(column);
501     Response response = client.delete(path.toString());
502     Thread.yield();
503     return response;
504   }
505 
506   protected static Response getValueXML(String table, String row, String column)
507       throws IOException {
508     StringBuilder path = new StringBuilder();
509     path.append('/');
510     path.append(table);
511     path.append('/');
512     path.append(row);
513     path.append('/');
514     path.append(column);
515     return getValueXML(path.toString());
516   }
517 
518   protected static Response deleteRow(String table, String row)
519       throws IOException {
520     StringBuilder path = new StringBuilder();
521     path.append('/');
522     path.append(table);
523     path.append('/');
524     path.append(row);
525     Response response = client.delete(path.toString());
526     Thread.yield();
527     return response;
528   }
529 
530   protected static Response getValueJson(String table, String row,
531       String column) throws IOException {
532     StringBuilder path = new StringBuilder();
533     path.append('/');
534     path.append(table);
535     path.append('/');
536     path.append(row);
537     path.append('/');
538     path.append(column);
539     return getValueJson(path.toString());
540   }
541 
542   protected static void checkValueJSON(String table, String row, String column,
543       String value) throws IOException {
544     Response response = getValueJson(table, row, column);
545     assertEquals(200, response.getCode());
546     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
547     ObjectMapper mapper = new JacksonProvider().locateMapper(CellSetModel.class,
548       MediaType.APPLICATION_JSON_TYPE);
549     CellSetModel cellSet = mapper.readValue(response.getBody(), CellSetModel.class);
550     RowModel rowModel = cellSet.getRows().get(0);
551     CellModel cell = rowModel.getCells().get(0);
552     assertEquals(Bytes.toString(cell.getColumn()), column);
553     assertEquals(Bytes.toString(cell.getValue()), value);
554   }
555 
556   protected static void checkIncrementValueJSON(String table, String row, String column,
557       long value) throws IOException {
558     Response response = getValueJson(table, row, column);
559     assertEquals(200, response.getCode());
560     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
561     ObjectMapper mapper = new JacksonJaxbJsonProvider()
562             .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
563     CellSetModel cellSet = mapper.readValue(response.getBody(), CellSetModel.class);
564     RowModel rowModel = cellSet.getRows().get(0);
565     CellModel cell = rowModel.getCells().get(0);
566     assertEquals(Bytes.toString(cell.getColumn()), column);
567     assertEquals(Bytes.toLong(cell.getValue()), value);
568   }
569 
570   protected static Response putValueJson(String table, String row, String column,
571       String value) throws IOException {
572     StringBuilder path = new StringBuilder();
573     path.append('/');
574     path.append(table);
575     path.append('/');
576     path.append(row);
577     path.append('/');
578     path.append(column);
579     return putValueJson(path.toString(), table, row, column, value);
580   }
581 
582   protected static Response putValueJson(String url, String table, String row, String column,
583       String value) throws IOException {
584     RowModel rowModel = new RowModel(row);
585     rowModel.addCell(new CellModel(Bytes.toBytes(column),
586       Bytes.toBytes(value)));
587     CellSetModel cellSetModel = new CellSetModel();
588     cellSetModel.addRow(rowModel);
589     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
590     Response response = client.put(url, Constants.MIMETYPE_JSON,
591       Bytes.toBytes(jsonString));
592     Thread.yield();
593     return response;
594   }
595 
596   protected static Response appendValueXML(String table, String row, String column,
597       String value) throws IOException, JAXBException {
598     StringBuilder path = new StringBuilder();
599     path.append('/');
600     path.append(table);
601     path.append('/');
602     path.append(row);
603     path.append("?check=append");
604     return putValueXML(path.toString(), table, row, column, value);
605   }
606 
607   protected static Response appendValuePB(String table, String row, String column,
608       String value) throws IOException {
609     StringBuilder path = new StringBuilder();
610     path.append('/');
611     path.append(table);
612     path.append('/');
613     path.append(row);
614     path.append("?check=append");
615     return putValuePB(path.toString(), table, row, column, value);
616   }
617 
618   protected static Response appendValueJson(String table, String row, String column,
619       String value) throws IOException, JAXBException {
620     StringBuilder path = new StringBuilder();
621     path.append('/');
622     path.append(table);
623     path.append('/');
624     path.append(row);
625     path.append("?check=append");
626     return putValueJson(path.toString(), table, row, column, value);
627   }
628 
629   protected static Response incrementValueXML(String table, String row, String column,
630       String value) throws IOException, JAXBException {
631     StringBuilder path = new StringBuilder();
632     path.append('/');
633     path.append(table);
634     path.append('/');
635     path.append(row);
636     path.append("?check=increment");
637     return putValueXML(path.toString(), table, row, column, value);
638   }
639 
640   protected static Response incrementValuePB(String table, String row, String column,
641       String value) throws IOException {
642     StringBuilder path = new StringBuilder();
643     path.append('/');
644     path.append(table);
645     path.append('/');
646     path.append(row);
647     path.append("?check=increment");
648     return putValuePB(path.toString(), table, row, column, value);
649   }
650 
651   protected static Response incrementValueJson(String table, String row, String column,
652       String value) throws IOException, JAXBException {
653     StringBuilder path = new StringBuilder();
654     path.append('/');
655     path.append(table);
656     path.append('/');
657     path.append(row);
658     path.append("?check=increment");
659     return putValueJson(path.toString(), table, row, column, value);
660   }
661 }