HBASE-26921 Rewrite the counting cells part in TestMultiVersions (#4316)
[hbase.git] / hbase-rest / src / main / java / org / apache / hadoop / hbase / rest / NamespacesInstanceResource.java
blob6156b8aaf97984ba32945d094a7c4b74d85b2cbd
1 /*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org.apache.hadoop.hbase.rest;
21 import java.io.IOException;
22 import java.util.List;
23 import javax.servlet.ServletContext;
24 import org.apache.hadoop.hbase.NamespaceDescriptor;
25 import org.apache.hadoop.hbase.client.Admin;
26 import org.apache.hadoop.hbase.client.TableDescriptor;
27 import org.apache.hadoop.hbase.rest.model.NamespacesInstanceModel;
28 import org.apache.hadoop.hbase.rest.model.TableListModel;
29 import org.apache.hadoop.hbase.rest.model.TableModel;
30 import org.apache.hadoop.hbase.util.Bytes;
31 import org.apache.yetus.audience.InterfaceAudience;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 import org.apache.hbase.thirdparty.javax.ws.rs.Consumes;
36 import org.apache.hbase.thirdparty.javax.ws.rs.DELETE;
37 import org.apache.hbase.thirdparty.javax.ws.rs.GET;
38 import org.apache.hbase.thirdparty.javax.ws.rs.POST;
39 import org.apache.hbase.thirdparty.javax.ws.rs.PUT;
40 import org.apache.hbase.thirdparty.javax.ws.rs.Path;
41 import org.apache.hbase.thirdparty.javax.ws.rs.PathParam;
42 import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
43 import org.apache.hbase.thirdparty.javax.ws.rs.core.Context;
44 import org.apache.hbase.thirdparty.javax.ws.rs.core.HttpHeaders;
45 import org.apache.hbase.thirdparty.javax.ws.rs.core.Response;
46 import org.apache.hbase.thirdparty.javax.ws.rs.core.UriInfo;
48 /**
49 * Implements the following REST end points:
50 * <p>
51 * <tt>/namespaces/{namespace} GET: get namespace properties.</tt>
52 * <tt>/namespaces/{namespace} POST: create namespace.</tt>
53 * <tt>/namespaces/{namespace} PUT: alter namespace.</tt>
54 * <tt>/namespaces/{namespace} DELETE: drop namespace.</tt>
55 * <tt>/namespaces/{namespace}/tables GET: list namespace's tables.</tt>
56 * <p>
58 @InterfaceAudience.Private
59 public class NamespacesInstanceResource extends ResourceBase {
61 private static final Logger LOG = LoggerFactory.getLogger(NamespacesInstanceResource.class);
62 String namespace;
63 boolean queryTables = false;
65 /**
66 * Constructor for standard NamespaceInstanceResource.
67 * @throws IOException
69 public NamespacesInstanceResource(String namespace) throws IOException {
70 this(namespace, false);
73 /**
74 * Constructor for querying namespace table list via NamespaceInstanceResource.
75 * @throws IOException
77 public NamespacesInstanceResource(String namespace, boolean queryTables) throws IOException {
78 super();
79 this.namespace = namespace;
80 this.queryTables = queryTables;
83 /**
84 * Build a response for GET namespace description or GET list of namespace tables.
85 * @param context servlet context
86 * @param uriInfo (JAX-RS context variable) request URL
87 * @return A response containing NamespacesInstanceModel for a namespace descriptions and
88 * TableListModel for a list of namespace tables.
90 @GET
91 @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
92 MIMETYPE_PROTOBUF_IETF})
93 public Response get(final @Context ServletContext context,
94 final @Context UriInfo uriInfo) {
95 if (LOG.isTraceEnabled()) {
96 LOG.trace("GET " + uriInfo.getAbsolutePath());
98 servlet.getMetrics().incrementRequests(1);
100 // Respond to list of namespace tables requests.
101 if(queryTables){
102 TableListModel tableModel = new TableListModel();
103 try{
104 List<TableDescriptor> tables =
105 servlet.getAdmin().listTableDescriptorsByNamespace(Bytes.toBytes(namespace));
106 for (TableDescriptor table : tables) {
107 tableModel.add(new TableModel(table.getTableName().getQualifierAsString()));
110 servlet.getMetrics().incrementSucessfulGetRequests(1);
111 return Response.ok(tableModel).build();
112 }catch(IOException e) {
113 servlet.getMetrics().incrementFailedGetRequests(1);
114 throw new RuntimeException("Cannot retrieve table list for '" + namespace + "'.");
118 // Respond to namespace description requests.
119 try {
120 NamespacesInstanceModel rowModel =
121 new NamespacesInstanceModel(servlet.getAdmin(), namespace);
122 servlet.getMetrics().incrementSucessfulGetRequests(1);
123 return Response.ok(rowModel).build();
124 } catch (IOException e) {
125 servlet.getMetrics().incrementFailedGetRequests(1);
126 throw new RuntimeException("Cannot retrieve info for '" + namespace + "'.");
131 * Build a response for PUT alter namespace with properties specified.
132 * @param model properties used for alter.
133 * @param uriInfo (JAX-RS context variable) request URL
134 * @return response code.
136 @PUT
137 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
138 MIMETYPE_PROTOBUF_IETF})
139 public Response put(final NamespacesInstanceModel model, final @Context UriInfo uriInfo) {
140 return processUpdate(model, true, uriInfo);
144 * Build a response for POST create namespace with properties specified.
145 * @param model properties used for create.
146 * @param uriInfo (JAX-RS context variable) request URL
147 * @return response code.
149 @POST
150 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
151 MIMETYPE_PROTOBUF_IETF})
152 public Response post(final NamespacesInstanceModel model,
153 final @Context UriInfo uriInfo) {
154 return processUpdate(model, false, uriInfo);
158 // Check that POST or PUT is valid and then update namespace.
159 private Response processUpdate(NamespacesInstanceModel model, final boolean updateExisting,
160 final UriInfo uriInfo) {
161 if (LOG.isTraceEnabled()) {
162 LOG.trace((updateExisting ? "PUT " : "POST ") + uriInfo.getAbsolutePath());
164 if (model == null) {
165 try {
166 model = new NamespacesInstanceModel(namespace);
167 } catch(IOException ioe) {
168 servlet.getMetrics().incrementFailedPutRequests(1);
169 throw new RuntimeException("Cannot retrieve info for '" + namespace + "'.");
172 servlet.getMetrics().incrementRequests(1);
174 if (servlet.isReadOnly()) {
175 servlet.getMetrics().incrementFailedPutRequests(1);
176 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT)
177 .entity("Forbidden" + CRLF).build();
180 Admin admin = null;
181 boolean namespaceExists = false;
182 try {
183 admin = servlet.getAdmin();
184 namespaceExists = doesNamespaceExist(admin, namespace);
185 }catch (IOException e) {
186 servlet.getMetrics().incrementFailedPutRequests(1);
187 return processException(e);
190 // Do not allow creation if namespace already exists.
191 if(!updateExisting && namespaceExists){
192 servlet.getMetrics().incrementFailedPutRequests(1);
193 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT).
194 entity("Namespace '" + namespace + "' already exists. Use REST PUT " +
195 "to alter the existing namespace.").build();
198 // Do not allow altering if namespace does not exist.
199 if (updateExisting && !namespaceExists){
200 servlet.getMetrics().incrementFailedPutRequests(1);
201 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT).
202 entity("Namespace '" + namespace + "' does not exist. Use " +
203 "REST POST to create the namespace.").build();
206 return createOrUpdate(model, uriInfo, admin, updateExisting);
209 // Do the actual namespace create or alter.
210 private Response createOrUpdate(final NamespacesInstanceModel model, final UriInfo uriInfo,
211 final Admin admin, final boolean updateExisting) {
212 NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);
213 builder.addConfiguration(model.getProperties());
214 if(model.getProperties().size() > 0){
215 builder.addConfiguration(model.getProperties());
217 NamespaceDescriptor nsd = builder.build();
219 try{
220 if(updateExisting){
221 admin.modifyNamespace(nsd);
222 }else{
223 admin.createNamespace(nsd);
225 }catch (IOException e) {
226 servlet.getMetrics().incrementFailedPutRequests(1);
227 return processException(e);
230 servlet.getMetrics().incrementSucessfulPutRequests(1);
232 return updateExisting ? Response.ok(uriInfo.getAbsolutePath()).build() :
233 Response.created(uriInfo.getAbsolutePath()).build();
236 private boolean doesNamespaceExist(Admin admin, String namespaceName) throws IOException{
237 NamespaceDescriptor[] nd = admin.listNamespaceDescriptors();
238 for(int i = 0; i < nd.length; i++){
239 if(nd[i].getName().equals(namespaceName)){
240 return true;
243 return false;
247 * Build a response for DELETE delete namespace.
248 * @param message value not used.
249 * @param headers value not used.
250 * @return response code.
252 @DELETE
253 public Response deleteNoBody(final byte[] message,
254 final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
255 if (LOG.isTraceEnabled()) {
256 LOG.trace("DELETE " + uriInfo.getAbsolutePath());
258 if (servlet.isReadOnly()) {
259 servlet.getMetrics().incrementFailedDeleteRequests(1);
260 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT)
261 .entity("Forbidden" + CRLF).build();
264 try{
265 Admin admin = servlet.getAdmin();
266 if (!doesNamespaceExist(admin, namespace)){
267 return Response.status(Response.Status.NOT_FOUND).type(MIMETYPE_TEXT).
268 entity("Namespace '" + namespace + "' does not exists. Cannot " +
269 "drop namespace.").build();
272 admin.deleteNamespace(namespace);
273 servlet.getMetrics().incrementSucessfulDeleteRequests(1);
274 return Response.ok().build();
276 } catch (IOException e) {
277 servlet.getMetrics().incrementFailedDeleteRequests(1);
278 return processException(e);
283 * Dispatch to NamespaceInstanceResource for getting list of tables.
285 @Path("tables")
286 public NamespacesInstanceResource getNamespaceInstanceResource(
287 final @PathParam("tables") String namespace) throws IOException {
288 return new NamespacesInstanceResource(this.namespace, true);