diff --git a/src/main/java/org/apache/hadoop/hbase/rest/MultiRowResource.java b/src/main/java/org/apache/hadoop/hbase/rest/MultiRowResource.java new file mode 100644 index 0000000..7dc63eb --- /dev/null +++ b/src/main/java/org/apache/hadoop/hbase/rest/MultiRowResource.java @@ -0,0 +1,82 @@ +package org.apache.hadoop.hbase.rest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.rest.ResourceBase; +import org.apache.hadoop.hbase.rest.RowSpec; +import org.apache.hadoop.hbase.rest.TableResource; +import org.apache.hadoop.hbase.rest.model.CellModel; +import org.apache.hadoop.hbase.rest.model.CellSetModel; +import org.apache.hadoop.hbase.rest.model.RowModel; +import org.apache.hadoop.hbase.rest.transform.Transform; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.io.IOException; +import java.util.ArrayList; + +public class MultiRowResource extends ResourceBase { + private static final Log LOG = LogFactory.getLog(MultiRowResource.class); + public static final String ROW_KEYS_PARAM_NAME = "rows"; + + TableResource tableResource; + RowSpec rowspec; + + /** + * Constructor + * + * @param tableResource + * @param versions + * @throws java.io.IOException + */ + public MultiRowResource(TableResource tableResource, String versions) throws IOException { + super(); + this.tableResource = tableResource; + if (versions != null) { + this.rowspec.setMaxVersions(Integer.valueOf(versions)); + } + } + + @GET + @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF}) + public Response get(final @Context UriInfo uriInfo) { + MultivaluedMap params = uriInfo.getQueryParameters(); + + servlet.getMetrics().incrementRequests(1); + try { + CellSetModel model = new CellSetModel(); + for (String rk : params.get(ROW_KEYS_PARAM_NAME)) { + RowSpec rowSpec = new RowSpec(rk); + + ResultGenerator generator = ResultGenerator.fromRowSpec(this.tableResource.getName(), rowSpec, null); + if (!generator.hasNext()) { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + KeyValue value = null; + RowModel rowModel = new RowModel(rk); + + + while ((value = generator.next()) != null) { + byte[] family = value.getFamily(); + byte[] qualifier = value.getQualifier(); + byte[] data = tableResource.transform(family, qualifier, value.getValue(), Transform.Direction.OUT); + rowModel.addCell(new CellModel(family, qualifier, value.getTimestamp(), data)); + } + + model.addRow(rowModel); + } + return Response.ok(model).build(); + } catch (IOException e) { + throw new WebApplicationException(e, + Response.Status.SERVICE_UNAVAILABLE); + } + + } +} diff --git a/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java b/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java index e19893d..cc719bc 100644 --- a/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java +++ b/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java @@ -269,6 +269,12 @@ public class TableResource extends ResourceBase { return new SchemaResource(this); } + @Path("multiget") + public MultiRowResource getMultipleRowResource( + final @QueryParam("v") String versions) throws IOException { + return new MultiRowResource(this, versions); + } + @Path("{rowspec: .+}") public RowResource getRowResource( // We need the @Encoded decorator so Jersey won't urldecode before diff --git a/src/test/java/org/apache/hadoop/hbase/rest/TestMultiRowResource.java b/src/test/java/org/apache/hadoop/hbase/rest/TestMultiRowResource.java new file mode 100644 index 0000000..a01cfad --- /dev/null +++ b/src/test/java/org/apache/hadoop/hbase/rest/TestMultiRowResource.java @@ -0,0 +1,151 @@ +package org.apache.hadoop.hbase.rest; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.rest.client.Client; +import org.apache.hadoop.hbase.rest.client.Cluster; +import org.apache.hadoop.hbase.rest.client.Response; +import org.apache.hadoop.hbase.rest.model.CellModel; +import org.apache.hadoop.hbase.rest.model.CellSetModel; +import org.apache.hadoop.hbase.rest.model.RowModel; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + + +public class TestMultiRowResource { + + private static final String TABLE = "TestRowResource"; + private static final String CFA = "a"; + private static final String CFB = "b"; + private static final String COLUMN_1 = CFA + ":1"; + private static final String COLUMN_2 = CFB + ":2"; + private static final String ROW_1 = "testrow5"; + private static final String VALUE_1 = "testvalue5"; + private static final String ROW_2 = "testrow6"; + private static final String VALUE_2 = "testvalue6"; + + + private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility(); + + private static Client client; + private static JAXBContext context; + private static Marshaller marshaller; + private static Unmarshaller unmarshaller; + private static Configuration conf; + + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + conf = TEST_UTIL.getConfiguration(); + TEST_UTIL.startMiniCluster(3); + REST_TEST_UTIL.startServletContainer(conf); + context = JAXBContext.newInstance( + CellModel.class, + CellSetModel.class, + RowModel.class); + marshaller = context.createMarshaller(); + unmarshaller = context.createUnmarshaller(); + client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())); + HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + if (admin.tableExists(TABLE)) { + return; + } + HTableDescriptor htd = new HTableDescriptor(TABLE); + htd.addFamily(new HColumnDescriptor(CFA)); + htd.addFamily(new HColumnDescriptor(CFB)); + admin.createTable(htd); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + REST_TEST_UTIL.shutdownServletContainer(); + TEST_UTIL.shutdownMiniCluster(); + } + + + @Test + public void testMultiCellGetJSON() throws IOException, JAXBException { + String row_5_url = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1; + String row_6_url = "/" + TABLE + "/" + ROW_2 + "/" + COLUMN_2; + + + StringBuilder path = new StringBuilder(); + path.append("/"); + path.append(TABLE); + path.append("/multiget/?rows="); + path.append(ROW_1); + path.append("&rows="); + path.append(ROW_2); + + client.post(row_5_url, Constants.MIMETYPE_BINARY, Bytes.toBytes(VALUE_1)); + client.post(row_6_url, Constants.MIMETYPE_BINARY, Bytes.toBytes(VALUE_2)); + + + Response response = client.get(path.toString(), Constants.MIMETYPE_JSON); + assertEquals(response.getCode(), 200); + + client.delete(row_5_url); + client.delete(row_6_url); + + } + + @Test + public void testMultiCellGetXML() throws IOException, JAXBException { + String row_5_url = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1; + String row_6_url = "/" + TABLE + "/" + ROW_2 + "/" + COLUMN_2; + + + StringBuilder path = new StringBuilder(); + path.append("/"); + path.append(TABLE); + path.append("/multiget/?rows="); + path.append(ROW_1); + path.append("&rows="); + path.append(ROW_2); + + client.post(row_5_url, Constants.MIMETYPE_BINARY, Bytes.toBytes(VALUE_1)); + client.post(row_6_url, Constants.MIMETYPE_BINARY, Bytes.toBytes(VALUE_2)); + + + Response response = client.get(path.toString(), Constants.MIMETYPE_XML); + assertEquals(response.getCode(), 200); + + client.delete(row_5_url); + client.delete(row_6_url); + + } + + @Test + public void testMultiCellGetJSONNotFound() throws IOException { + String row_5_url = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1; + + StringBuilder path = new StringBuilder(); + path.append("/"); + path.append(TABLE); + path.append("/multiget/?rows="); + path.append(ROW_1); + path.append("&rows="); + path.append(ROW_2); + + client.post(row_5_url, Constants.MIMETYPE_BINARY, Bytes.toBytes(VALUE_1)); + + Response response = client.get(path.toString(), Constants.MIMETYPE_JSON); + + assertEquals(response.getCode(), 404); + + } +}