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