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