View Javadoc

1   /*
2    *
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
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
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.
18   */
19  
20  package org.apache.hadoop.hbase.rest.client;
21  
22  import java.io.ByteArrayInputStream;
23  import java.io.IOException;
24  
25  import javax.xml.bind.JAXBContext;
26  import javax.xml.bind.JAXBException;
27  import javax.xml.bind.Unmarshaller;
28  
29  import org.apache.hadoop.classification.InterfaceAudience;
30  import org.apache.hadoop.classification.InterfaceStability;
31  import org.apache.hadoop.conf.Configuration;
32  
33  import org.apache.hadoop.hbase.HTableDescriptor;
34  import org.apache.hadoop.hbase.rest.Constants;
35  import org.apache.hadoop.hbase.rest.model.StorageClusterStatusModel;
36  import org.apache.hadoop.hbase.rest.model.StorageClusterVersionModel;
37  import org.apache.hadoop.hbase.rest.model.TableListModel;
38  import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
39  import org.apache.hadoop.hbase.rest.model.VersionModel;
40  import org.apache.hadoop.hbase.util.Bytes;
41  
42  @InterfaceAudience.Public
43  @InterfaceStability.Stable
44  public class RemoteAdmin {
45  
46    final Client client;
47    final Configuration conf;
48    final String accessToken;
49    final int maxRetries;
50    final long sleepTime;
51  
52    // This unmarshaller is necessary for getting the /version/cluster resource.
53    // This resource does not support protobufs. Therefore this is necessary to
54    // request/interpret it as XML.
55    private static volatile Unmarshaller versionClusterUnmarshaller;
56  
57    /**
58     * Constructor
59     * 
60     * @param client
61     * @param conf
62     */
63    public RemoteAdmin(Client client, Configuration conf) {
64      this(client, conf, null);
65    }
66  
67    static Unmarshaller getUnmarsheller() throws JAXBException {
68  
69      if (versionClusterUnmarshaller == null) {
70  
71        RemoteAdmin.versionClusterUnmarshaller = JAXBContext.newInstance(
72            StorageClusterVersionModel.class).createUnmarshaller();
73      }
74      return RemoteAdmin.versionClusterUnmarshaller;
75    }
76  
77    /**
78     * Constructor
79     * @param client
80     * @param conf
81     * @param accessToken
82     */
83    public RemoteAdmin(Client client, Configuration conf, String accessToken) {
84      this.client = client;
85      this.conf = conf;
86      this.accessToken = accessToken;
87      this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10);
88      this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000);
89    }
90  
91    /**
92     * @param tableName name of table to check
93     * @return true if all regions of the table are available
94     * @throws IOException if a remote or network exception occurs
95     */
96    public boolean isTableAvailable(String tableName) throws IOException {
97      return isTableAvailable(Bytes.toBytes(tableName));
98    }
99  
100   /**
101    * @return string representing the rest api's version
102    * @throws IOEXception
103    *           if the endpoint does not exist, there is a timeout, or some other
104    *           general failure mode
105    */
106   public VersionModel getRestVersion() throws IOException {
107 
108     StringBuilder path = new StringBuilder();
109     path.append('/');
110     if (accessToken != null) {
111       path.append(accessToken);
112       path.append('/');
113     }
114 
115     path.append("version/rest");
116 
117     int code = 0;
118     for (int i = 0; i < maxRetries; i++) {
119       Response response = client.get(path.toString(),
120           Constants.MIMETYPE_PROTOBUF);
121       code = response.getCode();
122       switch (code) {
123       case 200:
124 
125         VersionModel v = new VersionModel();
126         return (VersionModel) v.getObjectFromMessage(response.getBody());
127       case 404:
128         throw new IOException("REST version not found");
129       case 509:
130         try {
131           Thread.sleep(sleepTime);
132         } catch (InterruptedException e) {
133         }
134         break;
135       default:
136         throw new IOException("get request to " + path.toString()
137             + " returned " + code);
138       }
139     }
140     throw new IOException("get request to " + path.toString() + " timed out");
141   }
142 
143   /**
144    * @return string representing the cluster's version
145    * @throws IOEXception if the endpoint does not exist, there is a timeout, or some other general failure mode
146    */
147   public StorageClusterStatusModel getClusterStatus() throws IOException {
148 
149       StringBuilder path = new StringBuilder();
150       path.append('/');
151       if (accessToken !=null) {
152           path.append(accessToken);
153           path.append('/');
154       }
155 
156     path.append("status/cluster");
157 
158     int code = 0;
159     for (int i = 0; i < maxRetries; i++) {
160       Response response = client.get(path.toString(),
161           Constants.MIMETYPE_PROTOBUF);
162       code = response.getCode();
163       switch (code) {
164       case 200:
165         StorageClusterStatusModel s = new StorageClusterStatusModel();
166         return (StorageClusterStatusModel) s.getObjectFromMessage(response
167             .getBody());
168       case 404:
169         throw new IOException("Cluster version not found");
170       case 509:
171         try {
172           Thread.sleep(sleepTime);
173         } catch (InterruptedException e) {
174         }
175         break;
176       default:
177         throw new IOException("get request to " + path + " returned " + code);
178       }
179     }
180     throw new IOException("get request to " + path + " timed out");
181   }
182 
183   /**
184    * @return string representing the cluster's version
185    * @throws IOEXception
186    *           if the endpoint does not exist, there is a timeout, or some other
187    *           general failure mode
188    */
189   public StorageClusterVersionModel getClusterVersion() throws IOException {
190 
191     StringBuilder path = new StringBuilder();
192     path.append('/');
193     if (accessToken != null) {
194       path.append(accessToken);
195       path.append('/');
196     }
197 
198     path.append("version/cluster");
199 
200     int code = 0;
201     for (int i = 0; i < maxRetries; i++) {
202       Response response = client.get(path.toString(), Constants.MIMETYPE_XML);
203       code = response.getCode();
204       switch (code) {
205       case 200:
206         try {
207 
208           return (StorageClusterVersionModel) getUnmarsheller().unmarshal(
209               new ByteArrayInputStream(response.getBody()));
210         } catch (JAXBException jaxbe) {
211 
212           throw new IOException(
213               "Issue parsing StorageClusterVersionModel object in XML form: "
214                   + jaxbe.getLocalizedMessage());
215         }
216       case 404:
217         throw new IOException("Cluster version not found");
218       case 509:
219         try {
220           Thread.sleep(sleepTime);
221         } catch (InterruptedException e) {
222         }
223         break;
224       default:
225         throw new IOException(path.toString() + " request returned " + code);
226       }
227     }
228     throw new IOException("get request to " + path.toString()
229         + " request timed out");
230   }
231 
232   /**
233    * @param tableName name of table to check
234    * @return true if all regions of the table are available
235    * @throws IOException if a remote or network exception occurs
236    */
237   public boolean isTableAvailable(byte[] tableName) throws IOException {
238     StringBuilder path = new StringBuilder();
239     path.append('/');
240     if (accessToken != null) {
241       path.append(accessToken);
242       path.append('/');
243     }
244     path.append(Bytes.toStringBinary(tableName));
245     path.append('/');
246     path.append("exists");
247     int code = 0;
248     for (int i = 0; i < maxRetries; i++) {
249       Response response = client.get(path.toString(), Constants.MIMETYPE_PROTOBUF);
250       code = response.getCode();
251       switch (code) {
252       case 200:
253         return true;
254       case 404:
255         return false;
256       case 509:
257         try {
258           Thread.sleep(sleepTime);
259         } catch (InterruptedException e) { }
260         break;
261       default:
262         throw new IOException("get request to " + path.toString() + " returned " + code);
263       }
264     }
265     throw new IOException("get request to " + path.toString() + " timed out");
266   }
267 
268   /**
269    * Creates a new table.
270    * @param desc table descriptor for table
271    * @throws IOException if a remote or network exception occurs
272    */
273   public void createTable(HTableDescriptor desc)
274       throws IOException {
275     TableSchemaModel model = new TableSchemaModel(desc);
276     StringBuilder path = new StringBuilder();
277     path.append('/');
278     if (accessToken != null) {
279       path.append(accessToken);
280       path.append('/');
281     }
282     path.append(desc.getTableName());
283     path.append('/');
284     path.append("schema");
285     int code = 0;
286     for (int i = 0; i < maxRetries; i++) {
287       Response response = client.put(path.toString(), Constants.MIMETYPE_PROTOBUF,
288         model.createProtobufOutput());
289       code = response.getCode();
290       switch (code) {
291       case 201:
292         return;
293       case 509:
294         try {
295           Thread.sleep(sleepTime);
296         } catch (InterruptedException e) { }
297         break;
298       default:
299         throw new IOException("create request to " + path.toString() + " returned " + code);
300       }
301     }
302     throw new IOException("create request to " + path.toString() + " timed out");
303   }
304 
305   /**
306    * Deletes a table.
307    * @param tableName name of table to delete
308    * @throws IOException if a remote or network exception occurs
309    */
310   public void deleteTable(final String tableName) throws IOException {
311     deleteTable(Bytes.toBytes(tableName));
312   }
313 
314   /**
315    * Deletes a table.
316    * @param tableName name of table to delete
317    * @throws IOException if a remote or network exception occurs
318    */
319   public void deleteTable(final byte [] tableName) throws IOException {
320     StringBuilder path = new StringBuilder();
321     path.append('/');
322     if (accessToken != null) {
323       path.append(accessToken);
324       path.append('/');
325     }
326     path.append(Bytes.toStringBinary(tableName));
327     path.append('/');
328     path.append("schema");
329     int code = 0;
330     for (int i = 0; i < maxRetries; i++) {
331       Response response = client.delete(path.toString());
332       code = response.getCode();
333       switch (code) {
334       case 200:
335         return;
336       case 509:
337         try {
338           Thread.sleep(sleepTime);
339         } catch (InterruptedException e) { }
340         break;
341       default:
342         throw new IOException("delete request to " + path.toString() + " returned " + code);
343       }
344     }
345     throw new IOException("delete request to " + path.toString() + " timed out");
346   }
347 
348   /**
349    * @return string representing the cluster's version
350    * @throws IOEXception
351    *           if the endpoint does not exist, there is a timeout, or some other
352    *           general failure mode
353    */
354   public TableListModel getTableList() throws IOException {
355 
356     StringBuilder path = new StringBuilder();
357     path.append('/');
358     if (accessToken != null) {
359       path.append(accessToken);
360       path.append('/');
361     }
362 
363     int code = 0;
364     for (int i = 0; i < maxRetries; i++) {
365       // Response response = client.get(path.toString(),
366       // Constants.MIMETYPE_XML);
367       Response response = client.get(path.toString(),
368           Constants.MIMETYPE_PROTOBUF);
369       code = response.getCode();
370       switch (code) {
371       case 200:
372         TableListModel t = new TableListModel();
373         return (TableListModel) t.getObjectFromMessage(response.getBody());
374       case 404:
375         throw new IOException("Table list not found");
376       case 509:
377         try {
378           Thread.sleep(sleepTime);
379         } catch (InterruptedException e) {
380         }
381         break;
382       default:
383         throw new IOException("get request to " + path.toString()
384             + " request returned " + code);
385       }
386     }
387     throw new IOException("get request to " + path.toString()
388         + " request timed out");
389   }
390 }