001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.rest;
019
020import static org.junit.Assert.assertEquals;
021
022import com.fasterxml.jackson.databind.ObjectMapper;
023import java.io.ByteArrayInputStream;
024import java.io.IOException;
025import java.io.StringWriter;
026import java.util.HashMap;
027import java.util.Map;
028import javax.xml.bind.JAXBContext;
029import javax.xml.bind.JAXBException;
030import javax.xml.bind.Marshaller;
031import javax.xml.bind.Unmarshaller;
032import org.apache.hadoop.conf.Configuration;
033import org.apache.hadoop.hbase.HBaseTestingUtility;
034import org.apache.hadoop.hbase.HColumnDescriptor;
035import org.apache.hadoop.hbase.HTableDescriptor;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.client.Admin;
038import org.apache.hadoop.hbase.rest.client.Client;
039import org.apache.hadoop.hbase.rest.client.Cluster;
040import org.apache.hadoop.hbase.rest.client.Response;
041import org.apache.hadoop.hbase.rest.model.CellModel;
042import org.apache.hadoop.hbase.rest.model.CellSetModel;
043import org.apache.hadoop.hbase.rest.model.RowModel;
044import org.apache.hadoop.hbase.util.Bytes;
045import org.junit.After;
046import org.junit.AfterClass;
047import org.junit.Before;
048import org.junit.BeforeClass;
049
050import org.apache.hbase.thirdparty.com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
051import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
052
053public class RowResourceBase {
054  protected static final String TABLE = "TestRowResource";
055
056  protected static final TableName TABLE_NAME = TableName.valueOf(TABLE);
057
058  protected static final String CFA = "a";
059  protected static final String CFB = "b";
060  protected static final String COLUMN_1 = CFA + ":1";
061  protected static final String COLUMN_2 = CFB + ":2";
062  protected static final String COLUMN_3 = CFA + ":";
063  protected static final String ROW_1 = "testrow1";
064  protected static final String VALUE_1 = "testvalue1";
065  protected static final String ROW_2 = "testrow2";
066  protected static final String VALUE_2 = "testvalue2";
067  protected static final String ROW_3 = "testrow3";
068  protected static final String VALUE_3 = "testvalue3";
069  protected static final String ROW_4 = "testrow4";
070  protected static final String VALUE_4 = "testvalue4";
071  protected static final String VALUE_5 = "5";
072  protected static final String VALUE_6 = "6";
073
074  protected static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
075  protected static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility();
076  protected static Client client;
077  protected static JAXBContext context;
078  protected static Marshaller xmlMarshaller;
079  protected static Unmarshaller xmlUnmarshaller;
080  protected static Configuration conf;
081  protected static ObjectMapper jsonMapper;
082
083  @BeforeClass
084  public static void setUpBeforeClass() throws Exception {
085    conf = TEST_UTIL.getConfiguration();
086    TEST_UTIL.startMiniCluster(3);
087    REST_TEST_UTIL.startServletContainer(conf);
088    context = JAXBContext.newInstance(CellModel.class, CellSetModel.class, RowModel.class);
089    xmlMarshaller = context.createMarshaller();
090    xmlUnmarshaller = context.createUnmarshaller();
091    jsonMapper = new JacksonJaxbJsonProvider().locateMapper(CellSetModel.class,
092      MediaType.APPLICATION_JSON_TYPE);
093    client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()));
094  }
095
096  @AfterClass
097  public static void tearDownAfterClass() throws Exception {
098    REST_TEST_UTIL.shutdownServletContainer();
099    TEST_UTIL.shutdownMiniCluster();
100  }
101
102  @Before
103  public void beforeMethod() throws Exception {
104    Admin admin = TEST_UTIL.getAdmin();
105    if (admin.tableExists(TABLE_NAME)) {
106      TEST_UTIL.deleteTable(TABLE_NAME);
107    }
108    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(TABLE));
109    htd.addFamily(new HColumnDescriptor(CFA));
110    htd.addFamily(new HColumnDescriptor(CFB));
111    admin.createTable(htd);
112  }
113
114  @After
115  public void afterMethod() throws Exception {
116    Admin admin = TEST_UTIL.getAdmin();
117    if (admin.tableExists(TABLE_NAME)) {
118      TEST_UTIL.deleteTable(TABLE_NAME);
119    }
120  }
121
122  static Response putValuePB(String table, String row, String column, String value)
123    throws IOException {
124    StringBuilder path = new StringBuilder();
125    path.append('/');
126    path.append(table);
127    path.append('/');
128    path.append(row);
129    path.append('/');
130    path.append(column);
131    return putValuePB(path.toString(), table, row, column, value);
132  }
133
134  static Response putValuePB(String url, String table, String row, String column, String value)
135    throws IOException {
136    RowModel rowModel = new RowModel(row);
137    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(value)));
138    CellSetModel cellSetModel = new CellSetModel();
139    cellSetModel.addRow(rowModel);
140    Response response =
141      client.put(url, Constants.MIMETYPE_PROTOBUF, cellSetModel.createProtobufOutput());
142    Thread.yield();
143    return response;
144  }
145
146  protected static void checkValueXML(String url, String table, String row, String column,
147    String value) throws IOException, JAXBException {
148    Response response = getValueXML(url);
149    assertEquals(200, response.getCode());
150    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
151    CellSetModel cellSet =
152      (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
153    RowModel rowModel = cellSet.getRows().get(0);
154    CellModel cell = rowModel.getCells().get(0);
155    assertEquals(Bytes.toString(cell.getColumn()), column);
156    assertEquals(Bytes.toString(cell.getValue()), value);
157  }
158
159  protected static void checkValueXML(String table, String row, String column, String value)
160    throws IOException, JAXBException {
161    Response response = getValueXML(table, row, column);
162    assertEquals(200, response.getCode());
163    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
164    CellSetModel cellSet =
165      (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
166    RowModel rowModel = cellSet.getRows().get(0);
167    CellModel cell = rowModel.getCells().get(0);
168    assertEquals(Bytes.toString(cell.getColumn()), column);
169    assertEquals(Bytes.toString(cell.getValue()), value);
170  }
171
172  protected static void checkIncrementValueXML(String table, String row, String column, long value)
173    throws IOException, JAXBException {
174    Response response1 = getValueXML(table, row, column);
175    assertEquals(200, response1.getCode());
176    assertEquals(Constants.MIMETYPE_XML, response1.getHeader("content-type"));
177    CellSetModel cellSet =
178      (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response1.getBody()));
179    RowModel rowModel = cellSet.getRows().get(0);
180    CellModel cell = rowModel.getCells().get(0);
181    assertEquals(Bytes.toString(cell.getColumn()), column);
182    assertEquals(Bytes.toLong(cell.getValue()), value);
183  }
184
185  protected static Response getValuePB(String url) throws IOException {
186    Response response = client.get(url, Constants.MIMETYPE_PROTOBUF);
187    return response;
188  }
189
190  protected static Response putValueXML(String table, String row, String column, String value)
191    throws IOException, JAXBException {
192    StringBuilder path = new StringBuilder();
193    path.append('/');
194    path.append(table);
195    path.append('/');
196    path.append(row);
197    path.append('/');
198    path.append(column);
199    return putValueXML(path.toString(), table, row, column, value);
200  }
201
202  protected static Response putValueXML(String url, String table, String row, String column,
203    String value) throws IOException, JAXBException {
204    RowModel rowModel = new RowModel(row);
205    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(value)));
206    CellSetModel cellSetModel = new CellSetModel();
207    cellSetModel.addRow(rowModel);
208    StringWriter writer = new StringWriter();
209    xmlMarshaller.marshal(cellSetModel, writer);
210    Response response = client.put(url, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
211    Thread.yield();
212    return response;
213  }
214
215  protected static Response getValuePB(String table, String row, String column) throws IOException {
216    StringBuilder path = new StringBuilder();
217    path.append('/');
218    path.append(table);
219    path.append('/');
220    path.append(row);
221    path.append('/');
222    path.append(column);
223    return getValuePB(path.toString());
224  }
225
226  protected static void checkValuePB(String table, String row, String column, String value)
227    throws IOException {
228    Response response = getValuePB(table, row, column);
229    assertEquals(200, response.getCode());
230    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
231    CellSetModel cellSet = new CellSetModel();
232    cellSet.getObjectFromMessage(response.getBody());
233    RowModel rowModel = cellSet.getRows().get(0);
234    CellModel cell = rowModel.getCells().get(0);
235    assertEquals(Bytes.toString(cell.getColumn()), column);
236    assertEquals(Bytes.toString(cell.getValue()), value);
237  }
238
239  protected static void checkIncrementValuePB(String table, String row, String column, long value)
240    throws IOException {
241    Response response = getValuePB(table, row, column);
242    assertEquals(200, response.getCode());
243    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
244    CellSetModel cellSet = new CellSetModel();
245    cellSet.getObjectFromMessage(response.getBody());
246    RowModel rowModel = cellSet.getRows().get(0);
247    CellModel cell = rowModel.getCells().get(0);
248    assertEquals(Bytes.toString(cell.getColumn()), column);
249    assertEquals(Bytes.toLong(cell.getValue()), value);
250  }
251
252  protected static Response checkAndPutValuePB(String url, String table, String row, String column,
253    String valueToCheck, String valueToPut, HashMap<String, String> otherCells) throws IOException {
254    RowModel rowModel = new RowModel(row);
255    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToPut)));
256
257    if (otherCells != null) {
258      for (Map.Entry<String, String> entry : otherCells.entrySet()) {
259        rowModel
260          .addCell(new CellModel(Bytes.toBytes(entry.getKey()), Bytes.toBytes(entry.getValue())));
261      }
262    }
263
264    // This Cell need to be added as last cell.
265    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToCheck)));
266
267    CellSetModel cellSetModel = new CellSetModel();
268    cellSetModel.addRow(rowModel);
269    Response response =
270      client.put(url, Constants.MIMETYPE_PROTOBUF, cellSetModel.createProtobufOutput());
271    Thread.yield();
272    return response;
273  }
274
275  protected static Response checkAndPutValuePB(String table, String row, String column,
276    String valueToCheck, String valueToPut) throws IOException {
277    return checkAndPutValuePB(table, row, column, valueToCheck, valueToPut, null);
278  }
279
280  protected static Response checkAndPutValuePB(String table, String row, String column,
281    String valueToCheck, String valueToPut, HashMap<String, String> otherCells) throws IOException {
282    StringBuilder path = new StringBuilder();
283    path.append('/');
284    path.append(table);
285    path.append('/');
286    path.append(row);
287    path.append("?check=put");
288    return checkAndPutValuePB(path.toString(), table, row, column, valueToCheck, valueToPut,
289      otherCells);
290  }
291
292  protected static Response checkAndPutValueXML(String url, String table, String row, String column,
293    String valueToCheck, String valueToPut, HashMap<String, String> otherCells)
294    throws IOException, JAXBException {
295    RowModel rowModel = new RowModel(row);
296    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToPut)));
297
298    if (otherCells != null) {
299      for (Map.Entry<String, String> entry : otherCells.entrySet()) {
300        rowModel
301          .addCell(new CellModel(Bytes.toBytes(entry.getKey()), Bytes.toBytes(entry.getValue())));
302      }
303    }
304
305    // This Cell need to be added as last cell.
306    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToCheck)));
307    CellSetModel cellSetModel = new CellSetModel();
308    cellSetModel.addRow(rowModel);
309    StringWriter writer = new StringWriter();
310    xmlMarshaller.marshal(cellSetModel, writer);
311    Response response = client.put(url, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
312    Thread.yield();
313    return response;
314  }
315
316  protected static Response checkAndPutValueXML(String table, String row, String column,
317    String valueToCheck, String valueToPut) throws IOException, JAXBException {
318    return checkAndPutValueXML(table, row, column, valueToCheck, valueToPut, null);
319  }
320
321  protected static Response checkAndPutValueXML(String table, String row, String column,
322    String valueToCheck, String valueToPut, HashMap<String, String> otherCells)
323    throws IOException, JAXBException {
324    StringBuilder path = new StringBuilder();
325    path.append('/');
326    path.append(table);
327    path.append('/');
328    path.append(row);
329    path.append("?check=put");
330    return checkAndPutValueXML(path.toString(), table, row, column, valueToCheck, valueToPut,
331      otherCells);
332  }
333
334  protected static Response checkAndDeleteXML(String url, String table, String row, String column,
335    String valueToCheck, HashMap<String, String> cellsToDelete) throws IOException, JAXBException {
336    RowModel rowModel = new RowModel(row);
337
338    if (cellsToDelete != null) {
339      for (Map.Entry<String, String> entry : cellsToDelete.entrySet()) {
340        rowModel
341          .addCell(new CellModel(Bytes.toBytes(entry.getKey()), Bytes.toBytes(entry.getValue())));
342      }
343    }
344    // Add this at the end
345    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToCheck)));
346    CellSetModel cellSetModel = new CellSetModel();
347    cellSetModel.addRow(rowModel);
348    StringWriter writer = new StringWriter();
349    xmlMarshaller.marshal(cellSetModel, writer);
350    Response response = client.put(url, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
351    Thread.yield();
352    return response;
353  }
354
355  protected static Response checkAndDeleteXML(String table, String row, String column,
356    String valueToCheck) throws IOException, JAXBException {
357    return checkAndDeleteXML(table, row, column, valueToCheck, null);
358  }
359
360  protected static Response checkAndDeleteXML(String table, String row, String column,
361    String valueToCheck, HashMap<String, String> cellsToDelete) throws IOException, JAXBException {
362    StringBuilder path = new StringBuilder();
363    path.append('/');
364    path.append(table);
365    path.append('/');
366    path.append(row);
367    path.append("?check=delete");
368    return checkAndDeleteXML(path.toString(), table, row, column, valueToCheck, cellsToDelete);
369  }
370
371  protected static Response checkAndDeleteJson(String table, String row, String column,
372    String valueToCheck) throws IOException {
373    return checkAndDeleteJson(table, row, column, valueToCheck, null);
374  }
375
376  protected static Response checkAndDeleteJson(String table, String row, String column,
377    String valueToCheck, HashMap<String, String> cellsToDelete) throws IOException {
378    StringBuilder path = new StringBuilder();
379    path.append('/');
380    path.append(table);
381    path.append('/');
382    path.append(row);
383    path.append("?check=delete");
384    return checkAndDeleteJson(path.toString(), table, row, column, valueToCheck, cellsToDelete);
385  }
386
387  protected static Response checkAndDeleteJson(String url, String table, String row, String column,
388    String valueToCheck, HashMap<String, String> cellsToDelete) throws IOException {
389    RowModel rowModel = new RowModel(row);
390
391    if (cellsToDelete != null) {
392      for (Map.Entry<String, String> entry : cellsToDelete.entrySet()) {
393        rowModel
394          .addCell(new CellModel(Bytes.toBytes(entry.getKey()), Bytes.toBytes(entry.getValue())));
395      }
396    }
397    // Add this at the end
398    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToCheck)));
399    CellSetModel cellSetModel = new CellSetModel();
400    cellSetModel.addRow(rowModel);
401    String jsonString = jsonMapper.writeValueAsString(cellSetModel);
402    Response response = client.put(url, Constants.MIMETYPE_JSON, Bytes.toBytes(jsonString));
403    Thread.yield();
404    return response;
405  }
406
407  protected static Response checkAndDeletePB(String table, String row, String column, String value)
408    throws IOException {
409    return checkAndDeletePB(table, row, column, value, null);
410  }
411
412  protected static Response checkAndDeletePB(String table, String row, String column, String value,
413    HashMap<String, String> cellsToDelete) throws IOException {
414    StringBuilder path = new StringBuilder();
415    path.append('/');
416    path.append(table);
417    path.append('/');
418    path.append(row);
419    path.append("?check=delete");
420    return checkAndDeleteValuePB(path.toString(), table, row, column, value, cellsToDelete);
421  }
422
423  protected static Response checkAndDeleteValuePB(String url, String table, String row,
424    String column, String valueToCheck, HashMap<String, String> cellsToDelete) throws IOException {
425    RowModel rowModel = new RowModel(row);
426
427    if (cellsToDelete != null) {
428      for (Map.Entry<String, String> entry : cellsToDelete.entrySet()) {
429        rowModel
430          .addCell(new CellModel(Bytes.toBytes(entry.getKey()), Bytes.toBytes(entry.getValue())));
431      }
432    }
433    // Add this at the end
434    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(valueToCheck)));
435    CellSetModel cellSetModel = new CellSetModel();
436    cellSetModel.addRow(rowModel);
437    Response response =
438      client.put(url, Constants.MIMETYPE_PROTOBUF, cellSetModel.createProtobufOutput());
439    Thread.yield();
440    return response;
441  }
442
443  protected static Response getValueXML(String table, String startRow, String endRow, String column)
444    throws IOException {
445    StringBuilder path = new StringBuilder();
446    path.append('/');
447    path.append(table);
448    path.append('/');
449    path.append(startRow);
450    path.append(",");
451    path.append(endRow);
452    path.append('/');
453    path.append(column);
454    return getValueXML(path.toString());
455  }
456
457  protected static Response getValueXML(String url) throws IOException {
458    Response response = client.get(url, Constants.MIMETYPE_XML);
459    return response;
460  }
461
462  protected static Response getValueJson(String url) throws IOException {
463    Response response = client.get(url, Constants.MIMETYPE_JSON);
464    return response;
465  }
466
467  protected static Response deleteValue(String table, String row, String column)
468    throws IOException {
469    StringBuilder path = new StringBuilder();
470    path.append('/');
471    path.append(table);
472    path.append('/');
473    path.append(row);
474    path.append('/');
475    path.append(column);
476    Response response = client.delete(path.toString());
477    Thread.yield();
478    return response;
479  }
480
481  protected static Response getValueXML(String table, String row, String column)
482    throws IOException {
483    StringBuilder path = new StringBuilder();
484    path.append('/');
485    path.append(table);
486    path.append('/');
487    path.append(row);
488    path.append('/');
489    path.append(column);
490    return getValueXML(path.toString());
491  }
492
493  protected static Response deleteRow(String table, String row) throws IOException {
494    StringBuilder path = new StringBuilder();
495    path.append('/');
496    path.append(table);
497    path.append('/');
498    path.append(row);
499    Response response = client.delete(path.toString());
500    Thread.yield();
501    return response;
502  }
503
504  protected static Response getValueJson(String table, String row, String column)
505    throws IOException {
506    StringBuilder path = new StringBuilder();
507    path.append('/');
508    path.append(table);
509    path.append('/');
510    path.append(row);
511    path.append('/');
512    path.append(column);
513    return getValueJson(path.toString());
514  }
515
516  protected static void checkValueJSON(String table, String row, String column, String value)
517    throws IOException {
518    Response response = getValueJson(table, row, column);
519    assertEquals(200, response.getCode());
520    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
521    ObjectMapper mapper = new JacksonJaxbJsonProvider().locateMapper(CellSetModel.class,
522      MediaType.APPLICATION_JSON_TYPE);
523    CellSetModel cellSet = mapper.readValue(response.getBody(), CellSetModel.class);
524    RowModel rowModel = cellSet.getRows().get(0);
525    CellModel cell = rowModel.getCells().get(0);
526    assertEquals(Bytes.toString(cell.getColumn()), column);
527    assertEquals(Bytes.toString(cell.getValue()), value);
528  }
529
530  protected static void checkIncrementValueJSON(String table, String row, String column, long value)
531    throws IOException {
532    Response response = getValueJson(table, row, column);
533    assertEquals(200, response.getCode());
534    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
535    ObjectMapper mapper = new JacksonJaxbJsonProvider().locateMapper(CellSetModel.class,
536      MediaType.APPLICATION_JSON_TYPE);
537    CellSetModel cellSet = mapper.readValue(response.getBody(), CellSetModel.class);
538    RowModel rowModel = cellSet.getRows().get(0);
539    CellModel cell = rowModel.getCells().get(0);
540    assertEquals(Bytes.toString(cell.getColumn()), column);
541    assertEquals(Bytes.toLong(cell.getValue()), value);
542  }
543
544  protected static Response putValueJson(String table, String row, String column, String value)
545    throws IOException {
546    StringBuilder path = new StringBuilder();
547    path.append('/');
548    path.append(table);
549    path.append('/');
550    path.append(row);
551    path.append('/');
552    path.append(column);
553    return putValueJson(path.toString(), table, row, column, value);
554  }
555
556  protected static Response putValueJson(String url, String table, String row, String column,
557    String value) throws IOException {
558    RowModel rowModel = new RowModel(row);
559    rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(value)));
560    CellSetModel cellSetModel = new CellSetModel();
561    cellSetModel.addRow(rowModel);
562    String jsonString = jsonMapper.writeValueAsString(cellSetModel);
563    Response response = client.put(url, Constants.MIMETYPE_JSON, Bytes.toBytes(jsonString));
564    Thread.yield();
565    return response;
566  }
567
568  protected static Response appendValueXML(String table, String row, String column, String value)
569    throws IOException, JAXBException {
570    StringBuilder path = new StringBuilder();
571    path.append('/');
572    path.append(table);
573    path.append('/');
574    path.append(row);
575    path.append("?check=append");
576    return putValueXML(path.toString(), table, row, column, value);
577  }
578
579  protected static Response appendValuePB(String table, String row, String column, String value)
580    throws IOException {
581    StringBuilder path = new StringBuilder();
582    path.append('/');
583    path.append(table);
584    path.append('/');
585    path.append(row);
586    path.append("?check=append");
587    return putValuePB(path.toString(), table, row, column, value);
588  }
589
590  protected static Response appendValueJson(String table, String row, String column, String value)
591    throws IOException, JAXBException {
592    StringBuilder path = new StringBuilder();
593    path.append('/');
594    path.append(table);
595    path.append('/');
596    path.append(row);
597    path.append("?check=append");
598    return putValueJson(path.toString(), table, row, column, value);
599  }
600
601  protected static Response incrementValueXML(String table, String row, String column, String value)
602    throws IOException, JAXBException {
603    StringBuilder path = new StringBuilder();
604    path.append('/');
605    path.append(table);
606    path.append('/');
607    path.append(row);
608    path.append("?check=increment");
609    return putValueXML(path.toString(), table, row, column, value);
610  }
611
612  protected static Response incrementValuePB(String table, String row, String column, String value)
613    throws IOException {
614    StringBuilder path = new StringBuilder();
615    path.append('/');
616    path.append(table);
617    path.append('/');
618    path.append(row);
619    path.append("?check=increment");
620    return putValuePB(path.toString(), table, row, column, value);
621  }
622
623  protected static Response incrementValueJson(String table, String row, String column,
624    String value) throws IOException, JAXBException {
625    StringBuilder path = new StringBuilder();
626    path.append('/');
627    path.append(table);
628    path.append('/');
629    path.append(row);
630    path.append("?check=increment");
631    return putValueJson(path.toString(), table, row, column, value);
632  }
633}