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.Response.ResponseBuilder;
35 import javax.ws.rs.core.UriInfo;
36 import javax.xml.namespace.QName;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.hadoop.hbase.classification.InterfaceAudience;
41 import org.apache.hadoop.hbase.HColumnDescriptor;
42 import org.apache.hadoop.hbase.HTableDescriptor;
43 import org.apache.hadoop.hbase.TableExistsException;
44 import org.apache.hadoop.hbase.TableName;
45 import org.apache.hadoop.hbase.TableNotEnabledException;
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.rest.model.ColumnSchemaModel;
50 import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
51 import org.apache.hadoop.hbase.util.Bytes;
52
53 @InterfaceAudience.Private
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 HTableInterface table = servlet.getTable(tableResource.getName());
79 try {
80 return table.getTableDescriptor();
81 } finally {
82 table.close();
83 }
84 }
85
86 @GET
87 @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
88 MIMETYPE_PROTOBUF_IETF})
89 public Response get(final @Context UriInfo uriInfo) {
90 if (LOG.isDebugEnabled()) {
91 LOG.debug("GET " + uriInfo.getAbsolutePath());
92 }
93 servlet.getMetrics().incrementRequests(1);
94 try {
95 ResponseBuilder response =
96 Response.ok(new TableSchemaModel(getTableSchema()));
97 response.cacheControl(cacheControl);
98 servlet.getMetrics().incrementSucessfulGetRequests(1);
99 return response.build();
100 } catch (Exception e) {
101 servlet.getMetrics().incrementFailedGetRequests(1);
102 return processException(e);
103 }
104 }
105
106 private Response replace(final byte[] name, final TableSchemaModel model,
107 final UriInfo uriInfo, final HBaseAdmin admin) {
108 if (servlet.isReadOnly()) {
109 return Response.status(Response.Status.FORBIDDEN)
110 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
111 .build();
112 }
113 try {
114 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name));
115 for (Map.Entry<QName,Object> e: model.getAny().entrySet()) {
116 htd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
117 }
118 for (ColumnSchemaModel family: model.getColumns()) {
119 HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
120 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
121 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
122 }
123 htd.addFamily(hcd);
124 }
125 if (admin.tableExists(name)) {
126 admin.disableTable(name);
127 admin.modifyTable(name, htd);
128 admin.enableTable(name);
129 servlet.getMetrics().incrementSucessfulPutRequests(1);
130 } else try {
131 admin.createTable(htd);
132 servlet.getMetrics().incrementSucessfulPutRequests(1);
133 } catch (TableExistsException e) {
134
135 return Response.status(Response.Status.NOT_MODIFIED)
136 .type(MIMETYPE_TEXT).entity("Not modified" + CRLF)
137 .build();
138 }
139 return Response.created(uriInfo.getAbsolutePath()).build();
140 } catch (Exception e) {
141 servlet.getMetrics().incrementFailedPutRequests(1);
142 return processException(e);
143 }
144 }
145
146 private Response update(final byte[] name, final TableSchemaModel model,
147 final UriInfo uriInfo, final HBaseAdmin admin) {
148 if (servlet.isReadOnly()) {
149 return Response.status(Response.Status.FORBIDDEN)
150 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF)
151 .build();
152 }
153 try {
154 HTableDescriptor htd = admin.getTableDescriptor(name);
155 admin.disableTable(name);
156 try {
157 for (ColumnSchemaModel family: model.getColumns()) {
158 HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
159 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
160 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
161 }
162 if (htd.hasFamily(hcd.getName())) {
163 admin.modifyColumn(name, hcd);
164 } else {
165 admin.addColumn(name, hcd);
166 }
167 }
168 } catch (IOException e) {
169 return Response.status(Response.Status.SERVICE_UNAVAILABLE)
170 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF)
171 .build();
172 } finally {
173 admin.enableTable(tableResource.getName());
174 }
175 servlet.getMetrics().incrementSucessfulPutRequests(1);
176 return Response.ok().build();
177 } catch (Exception e) {
178 servlet.getMetrics().incrementFailedPutRequests(1);
179 return processException(e);
180 }
181 }
182
183 private Response update(final TableSchemaModel model, final boolean replace,
184 final UriInfo uriInfo) {
185 try {
186 byte[] name = Bytes.toBytes(tableResource.getName());
187 HBaseAdmin admin = servlet.getAdmin();
188 if (replace || !admin.tableExists(name)) {
189 return replace(name, model, uriInfo, admin);
190 } else {
191 return update(name, model, uriInfo, admin);
192 }
193 } catch (Exception e) {
194 servlet.getMetrics().incrementFailedPutRequests(1);
195 return processException(e);
196 }
197 }
198
199 @PUT
200 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
201 MIMETYPE_PROTOBUF_IETF})
202 public Response put(final TableSchemaModel model,
203 final @Context UriInfo uriInfo) {
204 if (LOG.isDebugEnabled()) {
205 LOG.debug("PUT " + uriInfo.getAbsolutePath());
206 }
207 servlet.getMetrics().incrementRequests(1);
208 return update(model, true, uriInfo);
209 }
210
211 @POST
212 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
213 MIMETYPE_PROTOBUF_IETF})
214 public Response post(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, false, uriInfo);
221 }
222
223 @DELETE
224 public Response delete(final @Context UriInfo uriInfo) {
225 if (LOG.isDebugEnabled()) {
226 LOG.debug("DELETE " + uriInfo.getAbsolutePath());
227 }
228 servlet.getMetrics().incrementRequests(1);
229 if (servlet.isReadOnly()) {
230 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT)
231 .entity("Forbidden" + CRLF).build();
232 }
233 try {
234 HBaseAdmin admin = servlet.getAdmin();
235 try {
236 admin.disableTable(tableResource.getName());
237 } catch (TableNotEnabledException e) {
238 admin.deleteTable(tableResource.getName());
239 servlet.getMetrics().incrementSucessfulDeleteRequests(1);
240 return Response.ok().build();
241 } catch (Exception e) {
242 servlet.getMetrics().incrementFailedDeleteRequests(1);
243 return processException(e);
244 }
245 }
246 }