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