1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.rest;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.IOException;
25  import java.net.InetSocketAddress;
26  import java.util.Iterator;
27  import java.util.Map;
28  
29  import javax.xml.bind.JAXBContext;
30  import javax.xml.bind.JAXBException;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.hbase.HColumnDescriptor;
35  import org.apache.hadoop.hbase.HRegionInfo;
36  import org.apache.hadoop.hbase.HServerAddress;
37  import org.apache.hadoop.hbase.HTableDescriptor;
38  import org.apache.hadoop.hbase.KeyValue;
39  import org.apache.hadoop.hbase.client.HBaseAdmin;
40  import org.apache.hadoop.hbase.client.HTable;
41  import org.apache.hadoop.hbase.client.Put;
42  import org.apache.hadoop.hbase.rest.client.Client;
43  import org.apache.hadoop.hbase.rest.client.Cluster;
44  import org.apache.hadoop.hbase.rest.client.Response;
45  import org.apache.hadoop.hbase.rest.model.TableModel;
46  import org.apache.hadoop.hbase.rest.model.TableInfoModel;
47  import org.apache.hadoop.hbase.rest.model.TableListModel;
48  import org.apache.hadoop.hbase.rest.model.TableRegionModel;
49  import org.apache.hadoop.hbase.util.Bytes;
50  import org.apache.hadoop.util.StringUtils;
51  
52  public class TestTableResource extends HBaseRESTClusterTestBase {
53    static final Log LOG = LogFactory.getLog(TestTableResource.class);
54  
55    static String TABLE = "TestTableResource";
56    static String COLUMN_FAMILY = "test";
57    static String COLUMN = COLUMN_FAMILY + ":qualifier";
58    static Map<HRegionInfo,HServerAddress> regionMap;
59  
60    Client client;
61    JAXBContext context;
62    HBaseAdmin admin;
63  
64    @Override
65    protected void setUp() throws Exception {
66      super.setUp();
67      context = JAXBContext.newInstance(
68          TableModel.class,
69          TableInfoModel.class,
70          TableListModel.class,
71          TableRegionModel.class);
72      client = new Client(new Cluster().add("localhost", testServletPort));
73      admin = new HBaseAdmin(conf);
74      if (admin.tableExists(TABLE)) {
75        return;
76      }
77      HTableDescriptor htd = new HTableDescriptor(TABLE);
78      htd.addFamily(new HColumnDescriptor(COLUMN_FAMILY));
79      admin.createTable(htd);
80      HTable table = new HTable(conf, TABLE);
81      byte[] k = new byte[3];
82      byte [][] famAndQf = KeyValue.parseColumn(Bytes.toBytes(COLUMN));
83      for (byte b1 = 'a'; b1 < 'z'; b1++) {
84        for (byte b2 = 'a'; b2 < 'z'; b2++) {
85          for (byte b3 = 'a'; b3 < 'z'; b3++) {
86            k[0] = b1;
87            k[1] = b2;
88            k[2] = b3;
89            Put put = new Put(k);
90            put.add(famAndQf[0], famAndQf[1], k);
91            table.put(put);
92          }
93        }
94      }
95      table.flushCommits();
96      // get the initial layout (should just be one region)
97      Map<HRegionInfo,HServerAddress> m = table.getRegionsInfo();
98      assertEquals(m.size(), 1);
99      // tell the master to split the table
100     admin.split(TABLE);
101     // give some time for the split to happen
102     try {
103       Thread.sleep(15 * 1000);
104     } catch (InterruptedException e) {
105       LOG.warn(StringUtils.stringifyException(e));
106     }
107     // check again
108     m = table.getRegionsInfo();
109     // should have two regions now
110     assertEquals(m.size(), 2);
111     regionMap = m;
112     LOG.info("regions: " + regionMap);
113   }
114 
115   @Override
116   protected void tearDown() throws Exception {
117     client.shutdown();
118     super.tearDown();
119   }
120 
121   void checkTableList(TableListModel model) {
122     boolean found = false;
123     Iterator<TableModel> tables = model.getTables().iterator();
124     assertTrue(tables.hasNext());
125     while (tables.hasNext()) {
126       TableModel table = tables.next();
127       if (table.getName().equals(TABLE)) {
128         found = true;
129         break;
130       }
131     }
132     assertTrue(found);
133   }
134 
135   void doTestTableListText() throws IOException {
136     Response response = client.get("/", MIMETYPE_TEXT);
137     assertEquals(response.getCode(), 200);
138   }
139 
140   void doTestTableListXML() throws IOException, JAXBException {
141     Response response = client.get("/", MIMETYPE_XML);
142     assertEquals(response.getCode(), 200);
143     TableListModel model = (TableListModel)
144       context.createUnmarshaller()
145         .unmarshal(new ByteArrayInputStream(response.getBody()));
146     checkTableList(model);
147   }
148 
149   void doTestTableListJSON() throws IOException {
150     Response response = client.get("/", MIMETYPE_JSON);
151     assertEquals(response.getCode(), 200);
152   }
153 
154   void doTestTableListPB() throws IOException, JAXBException {
155     Response response = client.get("/", MIMETYPE_PROTOBUF);
156     assertEquals(response.getCode(), 200);
157     TableListModel model = new TableListModel();
158     model.getObjectFromMessage(response.getBody());
159     checkTableList(model);
160   }
161 
162   public void checkTableInfo(TableInfoModel model) {
163     assertEquals(model.getName(), TABLE);
164     Iterator<TableRegionModel> regions = model.getRegions().iterator();
165     assertTrue(regions.hasNext());
166     while (regions.hasNext()) {
167       TableRegionModel region = regions.next();
168       boolean found = false;
169       for (Map.Entry<HRegionInfo,HServerAddress> e: regionMap.entrySet()) {
170         HRegionInfo hri = e.getKey();
171         String hriRegionName = hri.getRegionNameAsString();
172         String regionName = region.getName();
173         if (hriRegionName.startsWith(regionName)) {
174           found = true;
175           byte[] startKey = hri.getStartKey();
176           byte[] endKey = hri.getEndKey();
177           InetSocketAddress sa = e.getValue().getInetSocketAddress();
178           String location = sa.getHostName() + ":" +
179             Integer.valueOf(sa.getPort());
180           assertEquals(hri.getRegionId(), region.getId());
181           assertTrue(Bytes.equals(startKey, region.getStartKey()));
182           assertTrue(Bytes.equals(endKey, region.getEndKey()));
183           assertEquals(location, region.getLocation());
184           break;
185         }
186       }
187       assertTrue(found);
188     }
189   }
190 
191   void doTestTableInfoText() throws IOException {
192     Response response = client.get("/" + TABLE + "/regions", MIMETYPE_TEXT);
193     assertEquals(response.getCode(), 200);
194   }
195 
196   void doTestTableInfoXML() throws IOException, JAXBException {
197     Response response = client.get("/" + TABLE + "/regions", MIMETYPE_XML);
198     assertEquals(response.getCode(), 200);
199     TableInfoModel model = (TableInfoModel)
200       context.createUnmarshaller()
201         .unmarshal(new ByteArrayInputStream(response.getBody()));
202     checkTableInfo(model);
203   }
204 
205   void doTestTableInfoJSON() throws IOException {
206     Response response = client.get("/" + TABLE + "/regions", MIMETYPE_JSON);
207     assertEquals(response.getCode(), 200);
208   }
209 
210   void doTestTableInfoPB() throws IOException, JAXBException {
211     Response response = 
212       client.get("/" + TABLE + "/regions", MIMETYPE_PROTOBUF);
213     assertEquals(response.getCode(), 200);
214     TableInfoModel model = new TableInfoModel();
215     model.getObjectFromMessage(response.getBody());
216     checkTableInfo(model);
217   }
218 
219   public void testTableResource() throws Exception {
220     doTestTableListText();
221     doTestTableListXML();
222     doTestTableListJSON();
223     doTestTableListPB();
224     doTestTableInfoText();
225     doTestTableInfoXML();
226     doTestTableInfoJSON();
227     doTestTableInfoPB();
228   }
229 }