1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.rest;
21
22 import java.io.IOException;
23 import java.util.Map;
24
25 import javax.ws.rs.Consumes;
26 import javax.ws.rs.DELETE;
27 import javax.ws.rs.GET;
28 import javax.ws.rs.POST;
29 import javax.ws.rs.PUT;
30 import javax.ws.rs.Produces;
31 import javax.ws.rs.core.CacheControl;
32 import javax.ws.rs.core.Context;
33 import javax.ws.rs.core.Response;
34 import javax.ws.rs.core.UriInfo;
35 import javax.ws.rs.core.Response.ResponseBuilder;
36
37 import javax.xml.namespace.QName;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42 import org.apache.hadoop.classification.InterfaceAudience;
43 import org.apache.hadoop.hbase.HColumnDescriptor;
44 import org.apache.hadoop.hbase.HTableDescriptor;
45 import org.apache.hadoop.hbase.TableName;
46 import org.apache.hadoop.hbase.TableExistsException;
47 import org.apache.hadoop.hbase.TableNotFoundException;
48 import org.apache.hadoop.hbase.client.HBaseAdmin;
49 import org.apache.hadoop.hbase.client.HTableInterface;
50 import org.apache.hadoop.hbase.client.HTablePool;
51 import org.apache.hadoop.hbase.rest.model.ColumnSchemaModel;
52 import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
53 import org.apache.hadoop.hbase.util.Bytes;
54
55 @InterfaceAudience.Private
56 public class SchemaResource extends ResourceBase {
57 private static final Log LOG = LogFactory.getLog(SchemaResource.class);
58
59 static CacheControl cacheControl;
60 static {
61 cacheControl = new CacheControl();
62 cacheControl.setNoCache(true);
63 cacheControl.setNoTransform(false);
64 }
65
66 TableResource tableResource;
67
68
69
70
71
72
73 public SchemaResource(TableResource tableResource) throws IOException {
74 super();
75 this.tableResource = tableResource;
76 }
77
78 private HTableDescriptor getTableSchema() throws IOException,
79 TableNotFoundException {
80 HTablePool pool = servlet.getTablePool();
81 HTableInterface table = pool.getTable(tableResource.getName());
82 try {
83 return table.getTableDescriptor();
84 } finally {
85 table.close();
86 }
87 }
88
89 @GET
90 @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
91 MIMETYPE_PROTOBUF_IETF})
92 public Response get(final @Context UriInfo uriInfo) {
93 if (LOG.isDebugEnabled()) {
94 LOG.debug("GET " + uriInfo.getAbsolutePath());
95 }
96 servlet.getMetrics().incrementRequests(1);
97 try {
98 ResponseBuilder response =
99 Response.ok(new TableSchemaModel(getTableSchema()));
100 response.cacheControl(cacheControl);
101 servlet.getMetrics().incrementSucessfulGetRequests(1);
102 return response.build();
103 } catch (TableNotFoundException e) {
104 servlet.getMetrics().incrementFailedGetRequests(1);
105 return Response.status(Response.Status.NOT_FOUND)
106 .type(MIMETYPE_TEXT).entity("Not found" + CRLF)
107 .build();
108 } catch (IOException e) {
109 servlet.getMetrics().incrementFailedGetRequests(1);
110 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
111 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
112 .build();
113 }
114 }
115
116 private Response replace(final byte[] name, final TableSchemaModel model,
117 final UriInfo uriInfo, final HBaseAdmin admin) {
118 if (servlet.isReadOnly()) {
119 return Response.status(Response.Status.FORBIDDEN)
120 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
121 .build();
122 }
123 try {
124 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name));
125 for (Map.Entry<QName,Object> e: model.getAny().entrySet()) {
126 htd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
127 }
128 for (ColumnSchemaModel family: model.getColumns()) {
129 HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
130 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
131 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
132 }
133 htd.addFamily(hcd);
134 }
135 if (admin.tableExists(name)) {
136 admin.disableTable(name);
137 admin.modifyTable(name, htd);
138 admin.enableTable(name);
139 servlet.getMetrics().incrementSucessfulPutRequests(1);
140 } else try {
141 admin.createTable(htd);
142 servlet.getMetrics().incrementSucessfulPutRequests(1);
143 } catch (TableExistsException e) {
144
145 return Response.status(Response.Status.NOT_MODIFIED)
146 .type(MIMETYPE_TEXT).entity("Not modified" + CRLF)
147 .build();
148 }
149 return Response.created(uriInfo.getAbsolutePath()).build();
150 } catch (IOException e) {
151 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
152 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
153 .build();
154 }
155 }
156
157 private Response update(final byte[] name, final TableSchemaModel model,
158 final UriInfo uriInfo, final HBaseAdmin admin) {
159 if (servlet.isReadOnly()) {
160 return Response.status(Response.Status.FORBIDDEN)
161 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
162 .build();
163 }
164 try {
165 HTableDescriptor htd = admin.getTableDescriptor(name);
166 admin.disableTable(name);
167 try {
168 for (ColumnSchemaModel family: model.getColumns()) {
169 HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
170 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
171 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
172 }
173 if (htd.hasFamily(hcd.getName())) {
174 admin.modifyColumn(name, hcd);
175 } else {
176 admin.addColumn(name, hcd);
177 }
178 }
179 } catch (IOException e) {
180 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
181 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
182 .build();
183 } finally {
184 admin.enableTable(tableResource.getName());
185 }
186 servlet.getMetrics().incrementSucessfulPutRequests(1);
187 return Response.ok().build();
188 } catch (IOException e) {
189 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
190 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
191 .build();
192 }
193 }
194
195 private Response update(final TableSchemaModel model, final boolean replace,
196 final UriInfo uriInfo) {
197 try {
198 byte[] name = Bytes.toBytes(tableResource.getName());
199 HBaseAdmin admin = servlet.getAdmin();
200 if (replace || !admin.tableExists(name)) {
201 return replace(name, model, uriInfo, admin);
202 } else {
203 return update(name, model, uriInfo, admin);
204 }
205 } catch (IOException e) {
206 servlet.getMetrics().incrementFailedPutRequests(1);
207 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
208 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
209 .build();
210 }
211 }
212
213 @PUT
214 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
215 MIMETYPE_PROTOBUF_IETF})
216 public Response put(final TableSchemaModel model,
217 final @Context UriInfo uriInfo) {
218 if (LOG.isDebugEnabled()) {
219 LOG.debug("PUT " + uriInfo.getAbsolutePath());
220 }
221 servlet.getMetrics().incrementRequests(1);
222 return update(model, true, uriInfo);
223 }
224
225 @POST
226 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
227 MIMETYPE_PROTOBUF_IETF})
228 public Response post(final TableSchemaModel model,
229 final @Context UriInfo uriInfo) {
230 if (LOG.isDebugEnabled()) {
231 LOG.debug("PUT " + uriInfo.getAbsolutePath());
232 }
233 servlet.getMetrics().incrementRequests(1);
234 return update(model, false, uriInfo);
235 }
236
237 @DELETE
238 public Response delete(final @Context UriInfo uriInfo) {
239 if (LOG.isDebugEnabled()) {
240 LOG.debug("DELETE " + uriInfo.getAbsolutePath());
241 }
242 servlet.getMetrics().incrementRequests(1);
243 try {
244 HBaseAdmin admin = servlet.getAdmin();
245 boolean success = false;
246 for (int i = 0; i < 10; i++) try {
247 admin.disableTable(tableResource.getName());
248 success = true;
249 break;
250 } catch (IOException e) {
251 }
252 if (!success) {
253 throw new IOException("could not disable table");
254 }
255 admin.deleteTable(tableResource.getName());
256 servlet.getMetrics().incrementSucessfulDeleteRequests(1);
257 return Response.ok().build();
258 } catch (TableNotFoundException e) {
259 servlet.getMetrics().incrementFailedDeleteRequests(1);
260 return Response.status(Response.Status.NOT_FOUND)
261 .type(MIMETYPE_TEXT).entity("Not found" + CRLF)
262 .build();
263 } catch (IOException e) {
264 servlet.getMetrics().incrementFailedDeleteRequests(1);
265 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
266 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
267 .build();
268 }
269 }
270 }