View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.rest;
22  
23  import java.io.IOException;
24  import java.util.Map;
25  
26  import javax.ws.rs.Consumes;
27  import javax.ws.rs.DELETE;
28  import javax.ws.rs.GET;
29  import javax.ws.rs.POST;
30  import javax.ws.rs.PUT;
31  import javax.ws.rs.Produces;
32  import javax.ws.rs.WebApplicationException;
33  import javax.ws.rs.core.CacheControl;
34  import javax.ws.rs.core.Context;
35  import javax.ws.rs.core.Response;
36  import javax.ws.rs.core.UriInfo;
37  import javax.ws.rs.core.Response.ResponseBuilder;
38  
39  import javax.xml.namespace.QName;
40  
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  
44  import org.apache.hadoop.hbase.HColumnDescriptor;
45  import org.apache.hadoop.hbase.HTableDescriptor;
46  import org.apache.hadoop.hbase.TableExistsException;
47  import org.apache.hadoop.hbase.TableNotFoundException;
48  import org.apache.hadoop.hbase.client.HBaseAdmin;
49  import org.apache.hadoop.hbase.client.HTableInterface;
50  import org.apache.hadoop.hbase.client.HTablePool;
51  import org.apache.hadoop.hbase.rest.model.ColumnSchemaModel;
52  import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
53  import org.apache.hadoop.hbase.util.Bytes;
54  
55  public class SchemaResource extends ResourceBase {
56    private static final Log LOG = LogFactory.getLog(SchemaResource.class);
57  
58    static CacheControl cacheControl;
59    static {
60      cacheControl = new CacheControl();
61      cacheControl.setNoCache(true);
62      cacheControl.setNoTransform(false);
63    }
64  
65    TableResource tableResource;
66  
67    /**
68     * Constructor
69     * @param tableResource
70     * @throws IOException
71     */
72    public SchemaResource(TableResource tableResource) throws IOException {
73      super();
74      this.tableResource = tableResource;
75    }
76  
77    private HTableDescriptor getTableSchema() throws IOException,
78        TableNotFoundException {
79      HTablePool pool = servlet.getTablePool();
80      HTableInterface table = pool.getTable(tableResource.getName());
81      try {
82        return table.getTableDescriptor();
83      } finally {
84        pool.putTable(table);
85      }
86    }
87  
88    @GET
89    @Produces({MIMETYPE_TEXT, MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
90    public Response get(final @Context UriInfo uriInfo) {
91      if (LOG.isDebugEnabled()) {
92        LOG.debug("GET " + uriInfo.getAbsolutePath());
93      }
94      servlet.getMetrics().incrementRequests(1);
95      try {
96        ResponseBuilder response =
97          Response.ok(new TableSchemaModel(getTableSchema()));
98        response.cacheControl(cacheControl);
99        return response.build();
100     } catch (TableNotFoundException e) {
101       throw new WebApplicationException(Response.Status.NOT_FOUND);
102     } catch (IOException e) {
103       throw new WebApplicationException(e,
104                   Response.Status.SERVICE_UNAVAILABLE);
105     }
106   }
107 
108   private Response replace(final byte[] name, final TableSchemaModel model,
109       final UriInfo uriInfo, final HBaseAdmin admin) {
110     if (servlet.isReadOnly()) {
111       throw new WebApplicationException(Response.Status.FORBIDDEN);
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       } else try {
130         admin.createTable(htd);
131       } catch (TableExistsException e) {
132         // race, someone else created a table with the same name
133         throw new WebApplicationException(e, Response.Status.NOT_MODIFIED);
134       }
135       return Response.created(uriInfo.getAbsolutePath()).build();
136     } catch (IOException e) {
137       throw new WebApplicationException(e,
138             Response.Status.SERVICE_UNAVAILABLE);
139     }
140   }
141 
142   private Response update(final byte[] name, final TableSchemaModel model,
143       final UriInfo uriInfo, final HBaseAdmin admin) {
144     if (servlet.isReadOnly()) {
145       throw new WebApplicationException(Response.Status.FORBIDDEN);
146     }
147     try {
148       HTableDescriptor htd = admin.getTableDescriptor(name);
149       admin.disableTable(name);
150       try {
151         for (ColumnSchemaModel family: model.getColumns()) {
152           HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
153           for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
154             hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
155           }
156           if (htd.hasFamily(hcd.getName())) {
157             admin.modifyColumn(name, hcd);
158           } else {
159             admin.addColumn(name, hcd);
160           }
161         }
162       } catch (IOException e) {
163         throw new WebApplicationException(e,
164             Response.Status.INTERNAL_SERVER_ERROR);
165       } finally {
166         admin.enableTable(tableResource.getName());
167       }
168       return Response.ok().build();
169     } catch (IOException e) {
170       throw new WebApplicationException(e,
171           Response.Status.SERVICE_UNAVAILABLE);
172     }
173   }
174 
175   private Response update(final TableSchemaModel model, final boolean replace,
176       final UriInfo uriInfo) {
177     try {
178       byte[] name = Bytes.toBytes(tableResource.getName());
179       HBaseAdmin admin = new HBaseAdmin(servlet.getConfiguration());
180       if (replace || !admin.tableExists(name)) {
181         return replace(name, model, uriInfo, admin);
182       } else {
183         return update(name, model, uriInfo, admin);
184       }
185     } catch (IOException e) {
186       throw new WebApplicationException(e, 
187             Response.Status.SERVICE_UNAVAILABLE);
188     }
189   }
190 
191   @PUT
192   @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
193   public Response put(final TableSchemaModel model, 
194       final @Context UriInfo uriInfo) {
195     if (LOG.isDebugEnabled()) {
196       LOG.debug("PUT " + uriInfo.getAbsolutePath());
197     }
198     servlet.getMetrics().incrementRequests(1);
199     return update(model, true, uriInfo);
200   }
201 
202   @POST
203   @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
204   public Response post(final TableSchemaModel model, 
205       final @Context UriInfo uriInfo) {
206     if (LOG.isDebugEnabled()) {
207       LOG.debug("PUT " + uriInfo.getAbsolutePath());
208     }
209     servlet.getMetrics().incrementRequests(1);
210     return update(model, false, uriInfo);
211   }
212 
213   @DELETE
214   public Response delete(final @Context UriInfo uriInfo) {
215     if (LOG.isDebugEnabled()) {
216       LOG.debug("DELETE " + uriInfo.getAbsolutePath());
217     }
218     servlet.getMetrics().incrementRequests(1);
219     try {
220       HBaseAdmin admin = new HBaseAdmin(servlet.getConfiguration());
221       boolean success = false;
222       for (int i = 0; i < 10; i++) try {
223         admin.disableTable(tableResource.getName());
224         success = true;
225         break;
226       } catch (IOException e) {
227       }
228       if (!success) {
229         throw new IOException("could not disable table");
230       }
231       admin.deleteTable(tableResource.getName());
232       return Response.ok().build();
233     } catch (TableNotFoundException e) {
234       throw new WebApplicationException(Response.Status.NOT_FOUND);
235     } catch (IOException e) {
236       throw new WebApplicationException(e, 
237             Response.Status.SERVICE_UNAVAILABLE);
238     }
239   }
240 }