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
.xml
.namespace
.QName
;
23 import org
.apache
.hadoop
.hbase
.TableExistsException
;
24 import org
.apache
.hadoop
.hbase
.TableName
;
25 import org
.apache
.hadoop
.hbase
.TableNotEnabledException
;
26 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
27 import org
.apache
.hadoop
.hbase
.client
.Admin
;
28 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptor
;
29 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptorBuilder
;
30 import org
.apache
.hadoop
.hbase
.client
.Table
;
31 import org
.apache
.hadoop
.hbase
.client
.TableDescriptor
;
32 import org
.apache
.hadoop
.hbase
.client
.TableDescriptorBuilder
;
33 import org
.apache
.hadoop
.hbase
.rest
.model
.ColumnSchemaModel
;
34 import org
.apache
.hadoop
.hbase
.rest
.model
.TableSchemaModel
;
35 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
36 import org
.apache
.yetus
.audience
.InterfaceAudience
;
37 import org
.slf4j
.Logger
;
38 import org
.slf4j
.LoggerFactory
;
40 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.Consumes
;
41 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.DELETE
;
42 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.GET
;
43 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.POST
;
44 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.PUT
;
45 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.Produces
;
46 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.WebApplicationException
;
47 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.core
.CacheControl
;
48 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.core
.Context
;
49 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.core
.Response
;
50 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.core
.Response
.ResponseBuilder
;
51 import org
.apache
.hbase
.thirdparty
.javax
.ws
.rs
.core
.UriInfo
;
53 @InterfaceAudience.Private
54 public class SchemaResource
extends ResourceBase
{
55 private static final Logger LOG
= LoggerFactory
.getLogger(SchemaResource
.class);
57 static CacheControl cacheControl
;
59 cacheControl
= new CacheControl();
60 cacheControl
.setNoCache(true);
61 cacheControl
.setNoTransform(false);
64 TableResource tableResource
;
69 public SchemaResource(TableResource tableResource
) throws IOException
{
71 this.tableResource
= tableResource
;
74 private TableDescriptor
getTableSchema() throws IOException
, TableNotFoundException
{
75 try (Table table
= servlet
.getTable(tableResource
.getName())) {
76 return table
.getDescriptor();
81 @Produces({MIMETYPE_TEXT
, MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
82 MIMETYPE_PROTOBUF_IETF
})
83 public Response
get(final @Context UriInfo uriInfo
) {
84 if (LOG
.isTraceEnabled()) {
85 LOG
.trace("GET " + uriInfo
.getAbsolutePath());
87 servlet
.getMetrics().incrementRequests(1);
89 ResponseBuilder response
=
90 Response
.ok(new TableSchemaModel(getTableSchema()));
91 response
.cacheControl(cacheControl
);
92 servlet
.getMetrics().incrementSucessfulGetRequests(1);
93 return response
.build();
94 } catch (Exception e
) {
95 servlet
.getMetrics().incrementFailedGetRequests(1);
96 return processException(e
);
100 private Response
replace(final TableName name
, final TableSchemaModel model
,
101 final UriInfo uriInfo
, final Admin admin
) {
102 if (servlet
.isReadOnly()) {
103 return Response
.status(Response
.Status
.FORBIDDEN
)
104 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
108 TableDescriptorBuilder tableDescriptorBuilder
=
109 TableDescriptorBuilder
.newBuilder(name
);
110 for (Map
.Entry
<QName
, Object
> e
: model
.getAny().entrySet()) {
111 tableDescriptorBuilder
.setValue(e
.getKey().getLocalPart(), e
.getValue().toString());
113 for (ColumnSchemaModel family
: model
.getColumns()) {
114 ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder
=
115 ColumnFamilyDescriptorBuilder
.newBuilder(Bytes
.toBytes(family
.getName()));
116 for (Map
.Entry
<QName
, Object
> e
: family
.getAny().entrySet()) {
117 columnFamilyDescriptorBuilder
.setValue(e
.getKey().getLocalPart(),
118 e
.getValue().toString());
120 tableDescriptorBuilder
.setColumnFamily(columnFamilyDescriptorBuilder
.build());
122 TableDescriptor tableDescriptor
= tableDescriptorBuilder
.build();
123 if (admin
.tableExists(name
)) {
124 admin
.disableTable(name
);
125 admin
.modifyTable(tableDescriptor
);
126 admin
.enableTable(name
);
127 servlet
.getMetrics().incrementSucessfulPutRequests(1);
130 admin
.createTable(tableDescriptor
);
131 servlet
.getMetrics().incrementSucessfulPutRequests(1);
132 } catch (TableExistsException e
) {
133 // race, someone else created a table with the same name
134 return Response
.status(Response
.Status
.NOT_MODIFIED
)
135 .type(MIMETYPE_TEXT
).entity("Not modified" + CRLF
)
139 return Response
.created(uriInfo
.getAbsolutePath()).build();
140 } catch (Exception e
) {
141 LOG
.info("Caught exception", e
);
142 servlet
.getMetrics().incrementFailedPutRequests(1);
143 return processException(e
);
147 private Response
update(final TableName name
, final TableSchemaModel model
,
148 final UriInfo uriInfo
, final Admin admin
) {
149 if (servlet
.isReadOnly()) {
150 return Response
.status(Response
.Status
.FORBIDDEN
)
151 .type(MIMETYPE_TEXT
).entity("Forbidden" + CRLF
)
155 TableDescriptorBuilder tableDescriptorBuilder
=
156 TableDescriptorBuilder
.newBuilder(admin
.getDescriptor(name
));
157 admin
.disableTable(name
);
159 for (ColumnSchemaModel family
: model
.getColumns()) {
160 ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder
=
161 ColumnFamilyDescriptorBuilder
.newBuilder(Bytes
.toBytes(family
.getName()));
162 for (Map
.Entry
<QName
, Object
> e
: family
.getAny().entrySet()) {
163 columnFamilyDescriptorBuilder
.setValue(e
.getKey().getLocalPart(),
164 e
.getValue().toString());
166 TableDescriptor tableDescriptor
= tableDescriptorBuilder
.build();
167 ColumnFamilyDescriptor columnFamilyDescriptor
= columnFamilyDescriptorBuilder
.build();
168 if (tableDescriptor
.hasColumnFamily(columnFamilyDescriptor
.getName())) {
169 admin
.modifyColumnFamily(name
, columnFamilyDescriptor
);
171 admin
.addColumnFamily(name
, columnFamilyDescriptor
);
174 } catch (IOException e
) {
175 return Response
.status(Response
.Status
.SERVICE_UNAVAILABLE
)
176 .type(MIMETYPE_TEXT
).entity("Unavailable" + CRLF
)
179 admin
.enableTable(TableName
.valueOf(tableResource
.getName()));
181 servlet
.getMetrics().incrementSucessfulPutRequests(1);
182 return Response
.ok().build();
183 } catch (Exception e
) {
184 servlet
.getMetrics().incrementFailedPutRequests(1);
185 return processException(e
);
189 private Response
update(final TableSchemaModel model
, final boolean replace
,
190 final UriInfo uriInfo
) {
192 TableName name
= TableName
.valueOf(tableResource
.getName());
193 Admin admin
= servlet
.getAdmin();
194 if (replace
|| !admin
.tableExists(name
)) {
195 return replace(name
, model
, uriInfo
, admin
);
197 return update(name
, model
, uriInfo
, admin
);
199 } catch (Exception e
) {
200 servlet
.getMetrics().incrementFailedPutRequests(1);
201 // Avoid re-unwrapping the exception
202 if (e
instanceof WebApplicationException
) {
203 throw (WebApplicationException
) e
;
205 return processException(e
);
210 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
211 MIMETYPE_PROTOBUF_IETF
})
212 public Response
put(final TableSchemaModel model
,
213 final @Context UriInfo uriInfo
) {
214 if (LOG
.isTraceEnabled()) {
215 LOG
.trace("PUT " + uriInfo
.getAbsolutePath());
217 servlet
.getMetrics().incrementRequests(1);
218 return update(model
, true, uriInfo
);
222 @Consumes({MIMETYPE_XML
, MIMETYPE_JSON
, MIMETYPE_PROTOBUF
,
223 MIMETYPE_PROTOBUF_IETF
})
224 public Response
post(final TableSchemaModel model
,
225 final @Context UriInfo uriInfo
) {
226 if (LOG
.isTraceEnabled()) {
227 LOG
.trace("PUT " + uriInfo
.getAbsolutePath());
229 servlet
.getMetrics().incrementRequests(1);
230 return update(model
, false, uriInfo
);
233 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(value
="DE_MIGHT_IGNORE",
234 justification
="Expected")
236 public Response
delete(final @Context UriInfo uriInfo
) {
237 if (LOG
.isTraceEnabled()) {
238 LOG
.trace("DELETE " + uriInfo
.getAbsolutePath());
240 servlet
.getMetrics().incrementRequests(1);
241 if (servlet
.isReadOnly()) {
242 return Response
.status(Response
.Status
.FORBIDDEN
).type(MIMETYPE_TEXT
)
243 .entity("Forbidden" + CRLF
).build();
246 Admin admin
= servlet
.getAdmin();
248 admin
.disableTable(TableName
.valueOf(tableResource
.getName()));
249 } catch (TableNotEnabledException e
) { /* this is what we want anyway */ }
250 admin
.deleteTable(TableName
.valueOf(tableResource
.getName()));
251 servlet
.getMetrics().incrementSucessfulDeleteRequests(1);
252 return Response
.ok().build();
253 } catch (Exception e
) {
254 servlet
.getMetrics().incrementFailedDeleteRequests(1);
255 return processException(e
);