001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.apache.hadoop.hbase.rest; 021 022import java.io.IOException; 023import java.util.Map; 024 025import javax.ws.rs.Consumes; 026import javax.ws.rs.DELETE; 027import javax.ws.rs.GET; 028import javax.ws.rs.POST; 029import javax.ws.rs.PUT; 030import javax.ws.rs.Produces; 031import javax.ws.rs.WebApplicationException; 032import javax.ws.rs.core.CacheControl; 033import javax.ws.rs.core.Context; 034import javax.ws.rs.core.Response; 035import javax.ws.rs.core.Response.ResponseBuilder; 036import javax.ws.rs.core.UriInfo; 037import javax.xml.namespace.QName; 038 039import org.apache.hadoop.hbase.HColumnDescriptor; 040import org.apache.hadoop.hbase.HTableDescriptor; 041import org.apache.hadoop.hbase.TableExistsException; 042import org.apache.hadoop.hbase.TableName; 043import org.apache.hadoop.hbase.TableNotEnabledException; 044import org.apache.hadoop.hbase.TableNotFoundException; 045import org.apache.yetus.audience.InterfaceAudience; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048import org.apache.hadoop.hbase.client.Admin; 049import org.apache.hadoop.hbase.client.Table; 050import org.apache.hadoop.hbase.rest.model.ColumnSchemaModel; 051import org.apache.hadoop.hbase.rest.model.TableSchemaModel; 052 053@InterfaceAudience.Private 054public class SchemaResource extends ResourceBase { 055 private static final Logger LOG = LoggerFactory.getLogger(SchemaResource.class); 056 057 static CacheControl cacheControl; 058 static { 059 cacheControl = new CacheControl(); 060 cacheControl.setNoCache(true); 061 cacheControl.setNoTransform(false); 062 } 063 064 TableResource tableResource; 065 066 /** 067 * Constructor 068 * @param tableResource 069 * @throws IOException 070 */ 071 public SchemaResource(TableResource tableResource) throws IOException { 072 super(); 073 this.tableResource = tableResource; 074 } 075 076 private HTableDescriptor getTableSchema() throws IOException, 077 TableNotFoundException { 078 Table table = servlet.getTable(tableResource.getName()); 079 try { 080 return table.getTableDescriptor(); 081 } finally { 082 table.close(); 083 } 084 } 085 086 @GET 087 @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 088 MIMETYPE_PROTOBUF_IETF}) 089 public Response get(final @Context UriInfo uriInfo) { 090 if (LOG.isTraceEnabled()) { 091 LOG.trace("GET " + uriInfo.getAbsolutePath()); 092 } 093 servlet.getMetrics().incrementRequests(1); 094 try { 095 ResponseBuilder response = 096 Response.ok(new TableSchemaModel(getTableSchema())); 097 response.cacheControl(cacheControl); 098 servlet.getMetrics().incrementSucessfulGetRequests(1); 099 return response.build(); 100 } catch (Exception e) { 101 servlet.getMetrics().incrementFailedGetRequests(1); 102 return processException(e); 103 } 104 } 105 106 private Response replace(final TableName name, final TableSchemaModel model, 107 final UriInfo uriInfo, final Admin 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(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 // race, someone else created a table with the same name 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 LOG.info("Caught exception", e); 142 servlet.getMetrics().incrementFailedPutRequests(1); 143 return processException(e); 144 } 145 } 146 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) 152 .build(); 153 } 154 try { 155 HTableDescriptor htd = admin.getTableDescriptor(name); 156 admin.disableTable(name); 157 try { 158 for (ColumnSchemaModel family: model.getColumns()) { 159 HColumnDescriptor hcd = new HColumnDescriptor(family.getName()); 160 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) { 161 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 162 } 163 if (htd.hasFamily(hcd.getName())) { 164 admin.modifyColumnFamily(name, hcd); 165 } else { 166 admin.addColumnFamily(name, hcd); 167 } 168 } 169 } catch (IOException e) { 170 return Response.status(Response.Status.SERVICE_UNAVAILABLE) 171 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF) 172 .build(); 173 } finally { 174 admin.enableTable(TableName.valueOf(tableResource.getName())); 175 } 176 servlet.getMetrics().incrementSucessfulPutRequests(1); 177 return Response.ok().build(); 178 } catch (Exception e) { 179 servlet.getMetrics().incrementFailedPutRequests(1); 180 return processException(e); 181 } 182 } 183 184 private Response update(final TableSchemaModel model, final boolean replace, 185 final UriInfo uriInfo) { 186 try { 187 TableName name = TableName.valueOf(tableResource.getName()); 188 Admin admin = servlet.getAdmin(); 189 if (replace || !admin.tableExists(name)) { 190 return replace(name, model, uriInfo, admin); 191 } else { 192 return update(name, model, uriInfo, admin); 193 } 194 } catch (Exception e) { 195 servlet.getMetrics().incrementFailedPutRequests(1); 196 // Avoid re-unwrapping the exception 197 if (e instanceof WebApplicationException) { 198 throw (WebApplicationException) e; 199 } 200 return processException(e); 201 } 202 } 203 204 @PUT 205 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 206 MIMETYPE_PROTOBUF_IETF}) 207 public Response put(final TableSchemaModel model, 208 final @Context UriInfo uriInfo) { 209 if (LOG.isTraceEnabled()) { 210 LOG.trace("PUT " + uriInfo.getAbsolutePath()); 211 } 212 servlet.getMetrics().incrementRequests(1); 213 return update(model, true, uriInfo); 214 } 215 216 @POST 217 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 218 MIMETYPE_PROTOBUF_IETF}) 219 public Response post(final TableSchemaModel model, 220 final @Context UriInfo uriInfo) { 221 if (LOG.isTraceEnabled()) { 222 LOG.trace("PUT " + uriInfo.getAbsolutePath()); 223 } 224 servlet.getMetrics().incrementRequests(1); 225 return update(model, false, uriInfo); 226 } 227 228 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DE_MIGHT_IGNORE", 229 justification="Expected") 230 @DELETE 231 public Response delete(final @Context UriInfo uriInfo) { 232 if (LOG.isTraceEnabled()) { 233 LOG.trace("DELETE " + uriInfo.getAbsolutePath()); 234 } 235 servlet.getMetrics().incrementRequests(1); 236 if (servlet.isReadOnly()) { 237 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT) 238 .entity("Forbidden" + CRLF).build(); 239 } 240 try { 241 Admin admin = servlet.getAdmin(); 242 try { 243 admin.disableTable(TableName.valueOf(tableResource.getName())); 244 } catch (TableNotEnabledException e) { /* this is what we want anyway */ } 245 admin.deleteTable(TableName.valueOf(tableResource.getName())); 246 servlet.getMetrics().incrementSucessfulDeleteRequests(1); 247 return Response.ok().build(); 248 } catch (Exception e) { 249 servlet.getMetrics().incrementFailedDeleteRequests(1); 250 return processException(e); 251 } 252 } 253}