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.core.CacheControl; 032import javax.ws.rs.core.Context; 033import javax.ws.rs.core.Response; 034import javax.ws.rs.core.Response.ResponseBuilder; 035import javax.ws.rs.core.UriInfo; 036import javax.xml.namespace.QName; 037 038import org.apache.hadoop.hbase.HColumnDescriptor; 039import org.apache.hadoop.hbase.HTableDescriptor; 040import org.apache.hadoop.hbase.TableExistsException; 041import org.apache.hadoop.hbase.TableName; 042import org.apache.hadoop.hbase.TableNotEnabledException; 043import org.apache.hadoop.hbase.TableNotFoundException; 044import org.apache.yetus.audience.InterfaceAudience; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047import org.apache.hadoop.hbase.client.Admin; 048import org.apache.hadoop.hbase.client.Table; 049import org.apache.hadoop.hbase.rest.model.ColumnSchemaModel; 050import org.apache.hadoop.hbase.rest.model.TableSchemaModel; 051 052@InterfaceAudience.Private 053public class SchemaResource extends ResourceBase { 054 private static final Logger LOG = LoggerFactory.getLogger(SchemaResource.class); 055 056 static CacheControl cacheControl; 057 static { 058 cacheControl = new CacheControl(); 059 cacheControl.setNoCache(true); 060 cacheControl.setNoTransform(false); 061 } 062 063 TableResource tableResource; 064 065 /** 066 * Constructor 067 * @param tableResource 068 * @throws IOException 069 */ 070 public SchemaResource(TableResource tableResource) throws IOException { 071 super(); 072 this.tableResource = tableResource; 073 } 074 075 private HTableDescriptor getTableSchema() throws IOException, 076 TableNotFoundException { 077 Table table = servlet.getTable(tableResource.getName()); 078 try { 079 return table.getTableDescriptor(); 080 } finally { 081 table.close(); 082 } 083 } 084 085 @GET 086 @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 087 MIMETYPE_PROTOBUF_IETF}) 088 public Response get(final @Context UriInfo uriInfo) { 089 if (LOG.isTraceEnabled()) { 090 LOG.trace("GET " + uriInfo.getAbsolutePath()); 091 } 092 servlet.getMetrics().incrementRequests(1); 093 try { 094 ResponseBuilder response = 095 Response.ok(new TableSchemaModel(getTableSchema())); 096 response.cacheControl(cacheControl); 097 servlet.getMetrics().incrementSucessfulGetRequests(1); 098 return response.build(); 099 } catch (Exception e) { 100 servlet.getMetrics().incrementFailedGetRequests(1); 101 return processException(e); 102 } 103 } 104 105 private Response replace(final TableName name, final TableSchemaModel model, 106 final UriInfo uriInfo, final Admin admin) { 107 if (servlet.isReadOnly()) { 108 return Response.status(Response.Status.FORBIDDEN) 109 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF) 110 .build(); 111 } 112 try { 113 HTableDescriptor htd = new HTableDescriptor(name); 114 for (Map.Entry<QName,Object> e: model.getAny().entrySet()) { 115 htd.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 116 } 117 for (ColumnSchemaModel family: model.getColumns()) { 118 HColumnDescriptor hcd = new HColumnDescriptor(family.getName()); 119 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) { 120 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 121 } 122 htd.addFamily(hcd); 123 } 124 if (admin.tableExists(name)) { 125 admin.disableTable(name); 126 admin.modifyTable(name, htd); 127 admin.enableTable(name); 128 servlet.getMetrics().incrementSucessfulPutRequests(1); 129 } else try { 130 admin.createTable(htd); 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) 136 .build(); 137 } 138 return Response.created(uriInfo.getAbsolutePath()).build(); 139 } catch (Exception e) { 140 servlet.getMetrics().incrementFailedPutRequests(1); 141 return processException(e); 142 } 143 } 144 145 private Response update(final TableName name, final TableSchemaModel model, 146 final UriInfo uriInfo, final Admin admin) { 147 if (servlet.isReadOnly()) { 148 return Response.status(Response.Status.FORBIDDEN) 149 .type(MIMETYPE_TEXT).entity("Forbidden" + CRLF) 150 .build(); 151 } 152 try { 153 HTableDescriptor htd = admin.getTableDescriptor(name); 154 admin.disableTable(name); 155 try { 156 for (ColumnSchemaModel family: model.getColumns()) { 157 HColumnDescriptor hcd = new HColumnDescriptor(family.getName()); 158 for (Map.Entry<QName,Object> e: family.getAny().entrySet()) { 159 hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 160 } 161 if (htd.hasFamily(hcd.getName())) { 162 admin.modifyColumnFamily(name, hcd); 163 } else { 164 admin.addColumnFamily(name, hcd); 165 } 166 } 167 } catch (IOException e) { 168 return Response.status(Response.Status.SERVICE_UNAVAILABLE) 169 .type(MIMETYPE_TEXT).entity("Unavailable" + CRLF) 170 .build(); 171 } finally { 172 admin.enableTable(TableName.valueOf(tableResource.getName())); 173 } 174 servlet.getMetrics().incrementSucessfulPutRequests(1); 175 return Response.ok().build(); 176 } catch (Exception e) { 177 servlet.getMetrics().incrementFailedPutRequests(1); 178 return processException(e); 179 } 180 } 181 182 private Response update(final TableSchemaModel model, final boolean replace, 183 final UriInfo uriInfo) { 184 try { 185 TableName name = TableName.valueOf(tableResource.getName()); 186 Admin admin = servlet.getAdmin(); 187 if (replace || !admin.tableExists(name)) { 188 return replace(name, model, uriInfo, admin); 189 } else { 190 return update(name, model, uriInfo, admin); 191 } 192 } catch (Exception e) { 193 servlet.getMetrics().incrementFailedPutRequests(1); 194 return processException(e); 195 } 196 } 197 198 @PUT 199 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 200 MIMETYPE_PROTOBUF_IETF}) 201 public Response put(final TableSchemaModel model, 202 final @Context UriInfo uriInfo) { 203 if (LOG.isTraceEnabled()) { 204 LOG.trace("PUT " + uriInfo.getAbsolutePath()); 205 } 206 servlet.getMetrics().incrementRequests(1); 207 return update(model, true, uriInfo); 208 } 209 210 @POST 211 @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, 212 MIMETYPE_PROTOBUF_IETF}) 213 public Response post(final TableSchemaModel model, 214 final @Context UriInfo uriInfo) { 215 if (LOG.isTraceEnabled()) { 216 LOG.trace("PUT " + uriInfo.getAbsolutePath()); 217 } 218 servlet.getMetrics().incrementRequests(1); 219 return update(model, false, uriInfo); 220 } 221 222 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DE_MIGHT_IGNORE", 223 justification="Expected") 224 @DELETE 225 public Response delete(final @Context UriInfo uriInfo) { 226 if (LOG.isTraceEnabled()) { 227 LOG.trace("DELETE " + uriInfo.getAbsolutePath()); 228 } 229 servlet.getMetrics().incrementRequests(1); 230 if (servlet.isReadOnly()) { 231 return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT) 232 .entity("Forbidden" + CRLF).build(); 233 } 234 try { 235 Admin admin = servlet.getAdmin(); 236 try { 237 admin.disableTable(TableName.valueOf(tableResource.getName())); 238 } catch (TableNotEnabledException e) { /* this is what we want anyway */ } 239 admin.deleteTable(TableName.valueOf(tableResource.getName())); 240 servlet.getMetrics().incrementSucessfulDeleteRequests(1); 241 return Response.ok().build(); 242 } catch (Exception e) { 243 servlet.getMetrics().incrementFailedDeleteRequests(1); 244 return processException(e); 245 } 246 } 247}