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    String tableName;
66  
67    /**
68     * Constructor
69     * @param table
70     * @throws IOException
71     */
72    public SchemaResource(String table) throws IOException {
73      super();
74      this.tableName = table;
75    }
76  
77    private HTableDescriptor getTableSchema() throws IOException,
78        TableNotFoundException {
79      HTablePool pool = servlet.getTablePool();
80      HTableInterface table = pool.getTable(tableName);
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     try {
111       HTableDescriptor htd = new HTableDescriptor(name);
112       for (Map.Entry<QName,Object> e: model.getAny().entrySet()) {
113         htd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
114       }
115       for (ColumnSchemaModel family: model.getColumns()) {
116         HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
117         for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
118           hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
119         }
120         htd.addFamily(hcd);
121       }
122       if (admin.tableExists(name)) {
123         admin.disableTable(name);
124         admin.modifyTable(name, htd);
125         admin.enableTable(name);
126       } else try {
127         admin.createTable(htd);
128       } catch (TableExistsException e) {
129         // race, someone else created a table with the same name
130         throw new WebApplicationException(e, Response.Status.NOT_MODIFIED);
131       }
132       return Response.created(uriInfo.getAbsolutePath()).build();
133     } catch (IOException e) {
134       throw new WebApplicationException(e, 
135             Response.Status.SERVICE_UNAVAILABLE);
136     }      
137   } 
138 
139   private Response update(final byte[] name, final TableSchemaModel model,
140       final UriInfo uriInfo, final HBaseAdmin admin) {
141     try {
142       HTableDescriptor htd = admin.getTableDescriptor(name);
143       admin.disableTable(name);
144       try {
145         for (ColumnSchemaModel family: model.getColumns()) {
146           HColumnDescriptor hcd = new HColumnDescriptor(family.getName());
147           for (Map.Entry<QName,Object> e: family.getAny().entrySet()) {
148             hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
149           }
150           if (htd.hasFamily(hcd.getName())) {
151             admin.modifyColumn(name, hcd.getName(), hcd);
152           } else {
153             admin.addColumn(model.getName(), hcd);            
154           }
155         }
156       } catch (IOException e) {
157         throw new WebApplicationException(e, 
158             Response.Status.INTERNAL_SERVER_ERROR);
159       } finally {
160         admin.enableTable(tableName);
161       }
162       return Response.ok().build();
163     } catch (IOException e) {
164       throw new WebApplicationException(e,
165           Response.Status.SERVICE_UNAVAILABLE);
166     }
167   }
168 
169   private Response update(final TableSchemaModel model, final boolean replace,
170       final UriInfo uriInfo) {
171     try {
172       servlet.invalidateMaxAge(tableName);
173       byte[] name = Bytes.toBytes(tableName);
174       HBaseAdmin admin = new HBaseAdmin(servlet.getConfiguration());
175       if (replace || !admin.tableExists(name)) {
176         return replace(name, model, uriInfo, admin);
177       } else {
178         return update(name, model, uriInfo, admin);
179       }
180     } catch (IOException e) {
181       throw new WebApplicationException(e, 
182             Response.Status.SERVICE_UNAVAILABLE);
183     }
184   }
185 
186   @PUT
187   @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
188   public Response put(final TableSchemaModel model, 
189       final @Context UriInfo uriInfo) {
190     if (LOG.isDebugEnabled()) {
191       LOG.debug("PUT " + uriInfo.getAbsolutePath());
192     }
193     servlet.getMetrics().incrementRequests(1);
194     return update(model, true, uriInfo);
195   }
196 
197   @POST
198   @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF})
199   public Response post(final TableSchemaModel model, 
200       final @Context UriInfo uriInfo) {
201     if (LOG.isDebugEnabled()) {
202       LOG.debug("PUT " + uriInfo.getAbsolutePath());
203     }
204     servlet.getMetrics().incrementRequests(1);
205     return update(model, false, uriInfo);
206   }
207 
208   @DELETE
209   public Response delete(final @Context UriInfo uriInfo) {
210     if (LOG.isDebugEnabled()) {
211       LOG.debug("DELETE " + uriInfo.getAbsolutePath());
212     }
213     servlet.getMetrics().incrementRequests(1);
214     try {
215       HBaseAdmin admin = new HBaseAdmin(servlet.getConfiguration());
216       boolean success = false;
217       for (int i = 0; i < 10; i++) try {
218         admin.disableTable(tableName);
219         success = true;
220         break;
221       } catch (IOException e) {
222       }
223       if (!success) {
224         throw new IOException("could not disable table");
225       }
226       admin.deleteTable(tableName);
227       return Response.ok().build();
228     } catch (TableNotFoundException e) {
229       throw new WebApplicationException(Response.Status.NOT_FOUND);
230     } catch (IOException e) {
231       throw new WebApplicationException(e, 
232             Response.Status.SERVICE_UNAVAILABLE);
233     }
234   }
235 }