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.model;
21  
22  import java.io.IOException;
23  import java.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.LinkedHashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.xml.bind.annotation.XmlAnyAttribute;
31  import javax.xml.bind.annotation.XmlAttribute;
32  import javax.xml.bind.annotation.XmlElement;
33  import javax.xml.bind.annotation.XmlRootElement;
34  import javax.xml.namespace.QName;
35  
36  import org.apache.hadoop.hbase.classification.InterfaceAudience;
37  import org.apache.hadoop.hbase.HColumnDescriptor;
38  import org.apache.hadoop.hbase.HConstants;
39  import org.apache.hadoop.hbase.HTableDescriptor;
40  import org.apache.hadoop.hbase.TableName;
41  import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
42  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
43  import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
44  import org.apache.hadoop.hbase.rest.protobuf.generated.ColumnSchemaMessage.ColumnSchema;
45  import org.apache.hadoop.hbase.rest.protobuf.generated.TableSchemaMessage.TableSchema;
46  import org.apache.hadoop.hbase.util.Bytes;
47  import org.codehaus.jackson.annotate.JsonAnyGetter;
48  import org.codehaus.jackson.annotate.JsonAnySetter;
49  import org.codehaus.jackson.annotate.JsonIgnore;
50  
51  /**
52   * A representation of HBase table descriptors.
53   * 
54   * <pre>
55   * &lt;complexType name="TableSchema"&gt;
56   *   &lt;sequence&gt;
57   *     &lt;element name="column" type="tns:ColumnSchema" 
58   *       maxOccurs="unbounded" minOccurs="1"&gt;&lt;/element&gt;
59   *   &lt;/sequence&gt;
60   *   &lt;attribute name="name" type="string"&gt;&lt;/attribute&gt;
61   *   &lt;anyAttribute&gt;&lt;/anyAttribute&gt;
62   * &lt;/complexType&gt;
63   * </pre>
64   */
65  @XmlRootElement(name="TableSchema")
66  @InterfaceAudience.Private
67  public class TableSchemaModel implements Serializable, ProtobufMessageHandler {
68    private static final long serialVersionUID = 1L;
69    private static final QName IS_META = new QName(HTableDescriptor.IS_META);
70    private static final QName IS_ROOT = new QName(HTableDescriptor.IS_ROOT);
71    private static final QName READONLY = new QName(HTableDescriptor.READONLY);
72    private static final QName TTL = new QName(HColumnDescriptor.TTL);
73    private static final QName VERSIONS = new QName(HConstants.VERSIONS);
74    private static final QName COMPRESSION = 
75      new QName(HColumnDescriptor.COMPRESSION);
76  
77    private String name;
78    private Map<QName,Object> attrs = new LinkedHashMap<QName,Object>();
79    private List<ColumnSchemaModel> columns = new ArrayList<ColumnSchemaModel>();
80    
81    /**
82     * Default constructor.
83     */
84    public TableSchemaModel() {}
85  
86    /**
87     * Constructor
88     * @param htd the table descriptor
89     */
90    public TableSchemaModel(HTableDescriptor htd) {
91      setName(htd.getTableName().getNameAsString());
92      for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
93          htd.getValues().entrySet()) {
94        addAttribute(Bytes.toString(e.getKey().get()), 
95          Bytes.toString(e.getValue().get()));
96      }
97      for (HColumnDescriptor hcd: htd.getFamilies()) {
98        ColumnSchemaModel columnModel = new ColumnSchemaModel();
99        columnModel.setName(hcd.getNameAsString());
100       for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
101           hcd.getValues().entrySet()) {
102         columnModel.addAttribute(Bytes.toString(e.getKey().get()), 
103             Bytes.toString(e.getValue().get()));
104       }
105       addColumnFamily(columnModel);
106     }
107   }
108 
109   /**
110    * Add an attribute to the table descriptor
111    * @param name attribute name
112    * @param value attribute value
113    */
114   @JsonAnySetter
115   public void addAttribute(String name, Object value) {
116     attrs.put(new QName(name), value);
117   }
118 
119   /**
120    * Return a table descriptor value as a string. Calls toString() on the
121    * object stored in the descriptor value map.
122    * @param name the attribute name
123    * @return the attribute value
124    */
125   public String getAttribute(String name) {
126     Object o = attrs.get(new QName(name));
127     return o != null ? o.toString() : null;
128   }
129 
130   /**
131    * Add a column family to the table descriptor
132    * @param family the column family model
133    */
134   public void addColumnFamily(ColumnSchemaModel family) {
135     columns.add(family);
136   }
137 
138   /**
139    * Retrieve the column family at the given index from the table descriptor
140    * @param index the index
141    * @return the column family model
142    */
143   public ColumnSchemaModel getColumnFamily(int index) {
144     return columns.get(index);
145   }
146 
147   /**
148    * @return the table name
149    */
150   @XmlAttribute
151   public String getName() {
152     return name;
153   }
154 
155   /**
156    * @return the map for holding unspecified (user) attributes
157    */
158   @XmlAnyAttribute
159   @JsonAnyGetter
160   public Map<QName,Object> getAny() {
161     return attrs;
162   }
163 
164   /**
165    * @return the columns
166    */
167   @XmlElement(name="ColumnSchema")
168   public List<ColumnSchemaModel> getColumns() {
169     return columns;
170   }
171 
172   /**
173    * @param name the table name
174    */
175   public void setName(String name) {
176     this.name = name;
177   }
178 
179   /**
180    * @param columns the columns to set
181    */
182   public void setColumns(List<ColumnSchemaModel> columns) {
183     this.columns = columns;
184   }
185 
186   /* (non-Javadoc)
187    * @see java.lang.Object#toString()
188    */
189   @Override
190   public String toString() {
191     StringBuilder sb = new StringBuilder();
192     sb.append("{ NAME=> '");
193     sb.append(name);
194     sb.append('\'');
195     for (Map.Entry<QName,Object> e: attrs.entrySet()) {
196       sb.append(", ");
197       sb.append(e.getKey().getLocalPart());
198       sb.append(" => '");
199       sb.append(e.getValue().toString());
200       sb.append('\'');
201     }
202     sb.append(", COLUMNS => [ ");
203     Iterator<ColumnSchemaModel> i = columns.iterator();
204     while (i.hasNext()) {
205       ColumnSchemaModel family = i.next();
206       sb.append(family.toString());
207       if (i.hasNext()) {
208         sb.append(',');
209       }
210       sb.append(' ');
211     }
212     sb.append("] }");
213     return sb.toString();
214   }
215 
216   // getters and setters for common schema attributes
217 
218   // cannot be standard bean type getters and setters, otherwise this would
219   // confuse JAXB
220 
221   /**
222    * @return true if IS_META attribute exists and is truel
223    */
224   public boolean __getIsMeta() {
225     Object o = attrs.get(IS_META);
226     return o != null ? Boolean.valueOf(o.toString()) : false;
227   }
228 
229   /**
230    * @return true if IS_ROOT attribute exists and is truel
231    */
232   public boolean __getIsRoot() {
233     Object o = attrs.get(IS_ROOT);
234     return o != null ? Boolean.valueOf(o.toString()) : false;
235   }
236 
237   /**
238    * @return true if READONLY attribute exists and is truel
239    */
240   public boolean __getReadOnly() {
241     Object o = attrs.get(READONLY);
242     return o != null ? 
243       Boolean.valueOf(o.toString()) : HTableDescriptor.DEFAULT_READONLY;
244   }
245 
246   /**
247    * @param value desired value of IS_META attribute
248    */
249   public void __setIsMeta(boolean value) {
250     attrs.put(IS_META, Boolean.toString(value));
251   }
252 
253   /**
254    * @param value desired value of IS_ROOT attribute
255    */
256   public void __setIsRoot(boolean value) {
257     attrs.put(IS_ROOT, Boolean.toString(value));
258   }
259 
260   /**
261    * @param value desired value of READONLY attribute
262    */
263   public void __setReadOnly(boolean value) {
264     attrs.put(READONLY, Boolean.toString(value));
265   }
266 
267   @Override
268   public byte[] createProtobufOutput() {
269     TableSchema.Builder builder = TableSchema.newBuilder();
270     builder.setName(name);
271     for (Map.Entry<QName, Object> e: attrs.entrySet()) {
272       TableSchema.Attribute.Builder attrBuilder = 
273         TableSchema.Attribute.newBuilder();
274       attrBuilder.setName(e.getKey().getLocalPart());
275       attrBuilder.setValue(e.getValue().toString());
276       builder.addAttrs(attrBuilder);
277     }
278     for (ColumnSchemaModel family: columns) {
279       Map<QName, Object> familyAttrs = family.getAny();
280       ColumnSchema.Builder familyBuilder = ColumnSchema.newBuilder();
281       familyBuilder.setName(family.getName());
282       for (Map.Entry<QName, Object> e: familyAttrs.entrySet()) {
283         ColumnSchema.Attribute.Builder attrBuilder = 
284           ColumnSchema.Attribute.newBuilder();
285         attrBuilder.setName(e.getKey().getLocalPart());
286         attrBuilder.setValue(e.getValue().toString());
287         familyBuilder.addAttrs(attrBuilder);
288       }
289       if (familyAttrs.containsKey(TTL)) {
290         familyBuilder.setTtl(
291           Integer.valueOf(familyAttrs.get(TTL).toString()));
292       }
293       if (familyAttrs.containsKey(VERSIONS)) {
294         familyBuilder.setMaxVersions(
295           Integer.valueOf(familyAttrs.get(VERSIONS).toString()));
296       }
297       if (familyAttrs.containsKey(COMPRESSION)) {
298         familyBuilder.setCompression(familyAttrs.get(COMPRESSION).toString());
299       }
300       builder.addColumns(familyBuilder);
301     }
302     if (attrs.containsKey(READONLY)) {
303       builder.setReadOnly(
304         Boolean.valueOf(attrs.get(READONLY).toString()));
305     }
306     return builder.build().toByteArray();
307   }
308 
309   @Override
310   public ProtobufMessageHandler getObjectFromMessage(byte[] message) 
311       throws IOException {
312     TableSchema.Builder builder = TableSchema.newBuilder();
313     ProtobufUtil.mergeFrom(builder, message);
314     this.setName(builder.getName());
315     for (TableSchema.Attribute attr: builder.getAttrsList()) {
316       this.addAttribute(attr.getName(), attr.getValue());
317     }
318     if (builder.hasReadOnly()) {
319       this.addAttribute(HTableDescriptor.READONLY, builder.getReadOnly());
320     }
321     for (ColumnSchema family: builder.getColumnsList()) {
322       ColumnSchemaModel familyModel = new ColumnSchemaModel();
323       familyModel.setName(family.getName());
324       for (ColumnSchema.Attribute attr: family.getAttrsList()) {
325         familyModel.addAttribute(attr.getName(), attr.getValue());
326       }
327       if (family.hasTtl()) {
328         familyModel.addAttribute(HColumnDescriptor.TTL, family.getTtl());
329       }
330       if (family.hasMaxVersions()) {
331         familyModel.addAttribute(HConstants.VERSIONS,
332           family.getMaxVersions());
333       }
334       if (family.hasCompression()) {
335         familyModel.addAttribute(HColumnDescriptor.COMPRESSION,
336           family.getCompression());
337       }
338       this.addColumnFamily(familyModel);
339     }
340     return this;
341   }
342 
343   /**
344    * @return a table descriptor
345    */
346   @JsonIgnore
347   public HTableDescriptor getTableDescriptor() {
348     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(getName()));
349     for (Map.Entry<QName, Object> e: getAny().entrySet()) {
350       htd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
351     }
352     for (ColumnSchemaModel column: getColumns()) {
353       HColumnDescriptor hcd = new HColumnDescriptor(column.getName());
354       for (Map.Entry<QName, Object> e: column.getAny().entrySet()) {
355         hcd.setValue(e.getKey().getLocalPart(), e.getValue().toString());
356       }
357       htd.addFamily(hcd);
358     }
359     return htd;
360   }
361 
362 }