2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.rest
;
20 import java
.io
.IOException
;
22 import javax
.ws
.rs
.Consumes
;
23 import javax
.ws
.rs
.DELETE
;
24 import javax
.ws
.rs
.GET
;
25 import javax
.ws
.rs
.POST
;
26 import javax
.ws
.rs
.PUT
;
27 import javax
.ws
.rs
.Produces
;
28 import javax
.ws
.rs
.WebApplicationException
;
29 import javax
.ws
.rs
.core
.CacheControl
;
30 import javax
.ws
.rs
.core
.Context
;
31 import javax
.ws
.rs
.core
.Response
;
32 import javax
.ws
.rs
.core
.Response
.ResponseBuilder
;
33 import javax
.ws
.rs
.core
.UriInfo
;
34 import javax
.xml
.namespace
.QName
;
35 import org
.apache
.hadoop
.hbase
.TableExistsException
;
36 import org
.apache
.hadoop
.hbase
.TableName
;
37 import org
.apache
.hadoop
.hbase
.TableNotEnabledException
;
38 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
39 import org
.apache
.hadoop
.hbase
.client
.Admin
;
40 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptor
;
41 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptorBuilder
;
42 import org
.apache
.hadoop
.hbase
.client
.Table
;
43 import org
.apache
.hadoop
.hbase
.client
.TableDescriptor
;
44 import org
.apache
.hadoop
.hbase
.client
.TableDescriptorBuilder
;
45 import org
.apache
.hadoop
.hbase
.rest
.model
.ColumnSchemaModel
;
46 import org
.apache
.hadoop
.hbase
.rest
.model
.TableSchemaModel
;
47 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
48 import org
.apache
.yetus
.audience
.InterfaceAudience
;
49 import org
.slf4j
.Logger
;
50 import org
.slf4j
.LoggerFactory
;
52 @InterfaceAudience.Private
53 public class SchemaResource
extends ResourceBase
{
54 private static final Logger LOG
= LoggerFactory
.getLogger(SchemaResource
.class);
56 static CacheControl cacheControl
;
58 cacheControl
= new CacheControl();
59 cacheControl
.setNoCache(true);
60 cacheControl
.setNoTransform(false);
63 TableResource tableResource
;
68 public SchemaResource(TableResource tableResource
) throws IOException
{
70 this.tableResource
= tableResource
;
73 private TableDescriptor
getTableSchema() throws IOException
, TableNotFoundException
{
74 try (Table table
= servlet
.getTable(tableResource
.getName())) {
75 return table
.getDescriptor();
80 @Produces({MIMETYPE_TEXT
, MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
81 MIMETYPE_PROTOBUF_IETF
})
82 public Response
get(final @Context UriInfo uriInfo
) {
83 if (LOG
.isTraceEnabled()) {
84 LOG
.trace("GET " + uriInfo
.getAbsolutePath());
86 servlet
.getMetrics().incrementRequests(1);
88 ResponseBuilder response
=
89 Response
.ok(new TableSchemaModel(getTableSchema()));
90 response
.cacheControl(cacheControl
);
91 servlet
.getMetrics().incrementSucessfulGetRequests(1);
92 return response
.build();
93 } catch (Exception e
) {
94 servlet
.getMetrics().incrementFailedGetRequests(1);
95 return processException(e
);
99 private Response
replace(final TableName name
, final TableSchemaModel model
,
100 final UriInfo uriInfo
, final Admin admin
) {
101 if (servlet
.isReadOnly()) {
102 return Response
.status(Response
.Status
.FORBIDDEN
)
103 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
107 TableDescriptorBuilder tableDescriptorBuilder
=
108 TableDescriptorBuilder
.newBuilder(name
);
109 for (Map
.Entry
<QName
, Object
> e
: model
.getAny().entrySet()) {
110 tableDescriptorBuilder
.setValue(e
.getKey().getLocalPart(), e
.getValue().toString());
112 for (ColumnSchemaModel family
: model
.getColumns()) {
113 ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder
=
114 ColumnFamilyDescriptorBuilder
.newBuilder(Bytes
.toBytes(family
.getName()));
115 for (Map
.Entry
<QName
, Object
> e
: family
.getAny().entrySet()) {
116 columnFamilyDescriptorBuilder
.setValue(e
.getKey().getLocalPart(),
117 e
.getValue().toString());
119 tableDescriptorBuilder
.setColumnFamily(columnFamilyDescriptorBuilder
.build());
121 TableDescriptor tableDescriptor
= tableDescriptorBuilder
.build();
122 if (admin
.tableExists(name
)) {
123 admin
.disableTable(name
);
124 admin
.modifyTable(tableDescriptor
);
125 admin
.enableTable(name
);
126 servlet
.getMetrics().incrementSucessfulPutRequests(1);
129 admin
.createTable(tableDescriptor
);
130 servlet
.getMetrics().incrementSucessfulPutRequests(1);
131 } catch (TableExistsException e
) {
132 // race, someone else created a table with the same name
133 return Response
.status(Response
.Status
.NOT_MODIFIED
)
134 .type(MIMETYPE_TEXT
).entity("Not modified" + CRLF
)
138 return Response
.created(uriInfo
.getAbsolutePath()).build();
139 } catch (Exception e
) {
140 LOG
.info("Caught exception", e
);
141 servlet
.getMetrics().incrementFailedPutRequests(1);
142 return processException(e
);
146 private Response
update(final TableName name
, final TableSchemaModel model
,
147 final UriInfo uriInfo
, final Admin admin
) {
148 if (servlet
.isReadOnly()) {
149 return Response
.status(Response
.Status
.FORBIDDEN
)
150 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
154 TableDescriptorBuilder tableDescriptorBuilder
=
155 TableDescriptorBuilder
.newBuilder(admin
.getDescriptor(name
));
156 admin
.disableTable(name
);
158 for (ColumnSchemaModel family
: model
.getColumns()) {
159 ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder
=
160 ColumnFamilyDescriptorBuilder
.newBuilder(Bytes
.toBytes(family
.getName()));
161 for (Map
.Entry
<QName
, Object
> e
: family
.getAny().entrySet()) {
162 columnFamilyDescriptorBuilder
.setValue(e
.getKey().getLocalPart(),
163 e
.getValue().toString());
165 TableDescriptor tableDescriptor
= tableDescriptorBuilder
.build();
166 ColumnFamilyDescriptor columnFamilyDescriptor
= columnFamilyDescriptorBuilder
.build();
167 if (tableDescriptor
.hasColumnFamily(columnFamilyDescriptor
.getName())) {
168 admin
.modifyColumnFamily(name
, columnFamilyDescriptor
);
170 admin
.addColumnFamily(name
, columnFamilyDescriptor
);
173 } catch (IOException e
) {
174 return Response
.status(Response
.Status
.SERVICE_UNAVAILABLE
)
175 .type(MIMETYPE_TEXT
).entity("Unavailable" + CRLF
)
178 admin
.enableTable(TableName
.valueOf(tableResource
.getName()));
180 servlet
.getMetrics().incrementSucessfulPutRequests(1);
181 return Response
.ok().build();
182 } catch (Exception e
) {
183 servlet
.getMetrics().incrementFailedPutRequests(1);
184 return processException(e
);
188 private Response
update(final TableSchemaModel model
, final boolean replace
,
189 final UriInfo uriInfo
) {
191 TableName name
= TableName
.valueOf(tableResource
.getName());
192 Admin admin
= servlet
.getAdmin();
193 if (replace
|| !admin
.tableExists(name
)) {
194 return replace(name
, model
, uriInfo
, admin
);
196 return update(name
, model
, uriInfo
, admin
);
198 } catch (Exception e
) {
199 servlet
.getMetrics().incrementFailedPutRequests(1);
200 // Avoid re-unwrapping the exception
201 if (e
instanceof WebApplicationException
) {
202 throw (WebApplicationException
) e
;
204 return processException(e
);
209 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
210 MIMETYPE_PROTOBUF_IETF
})
211 public Response
put(final TableSchemaModel model
,
212 final @Context UriInfo uriInfo
) {
213 if (LOG
.isTraceEnabled()) {
214 LOG
.trace("PUT " + uriInfo
.getAbsolutePath());
216 servlet
.getMetrics().incrementRequests(1);
217 return update(model
, true, uriInfo
);
221 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
222 MIMETYPE_PROTOBUF_IETF
})
223 public Response
post(final TableSchemaModel model
,
224 final @Context UriInfo uriInfo
) {
225 if (LOG
.isTraceEnabled()) {
226 LOG
.trace("PUT " + uriInfo
.getAbsolutePath());
228 servlet
.getMetrics().incrementRequests(1);
229 return update(model
, false, uriInfo
);
232 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(value
="DE_MIGHT_IGNORE",
233 justification
="Expected")
235 public Response
delete(final @Context UriInfo uriInfo
) {
236 if (LOG
.isTraceEnabled()) {
237 LOG
.trace("DELETE " + uriInfo
.getAbsolutePath());
239 servlet
.getMetrics().incrementRequests(1);
240 if (servlet
.isReadOnly()) {
241 return Response
.status(Response
.Status
.FORBIDDEN
).type(MIMETYPE_TEXT
)
242 .entity("Forbidden" + CRLF
).build();
245 Admin admin
= servlet
.getAdmin();
247 admin
.disableTable(TableName
.valueOf(tableResource
.getName()));
248 } catch (TableNotEnabledException e
) { /* this is what we want anyway */ }
249 admin
.deleteTable(TableName
.valueOf(tableResource
.getName()));
250 servlet
.getMetrics().incrementSucessfulDeleteRequests(1);
251 return Response
.ok().build();
252 } catch (Exception e
) {
253 servlet
.getMetrics().incrementFailedDeleteRequests(1);
254 return processException(e
);