001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.rest.model; 019 020import com.fasterxml.jackson.annotation.JsonAnyGetter; 021import com.fasterxml.jackson.annotation.JsonAnySetter; 022import com.fasterxml.jackson.annotation.JsonIgnore; 023import java.io.IOException; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Iterator; 027import java.util.LinkedHashMap; 028import java.util.List; 029import java.util.Map; 030import javax.xml.bind.annotation.XmlAnyAttribute; 031import javax.xml.bind.annotation.XmlAttribute; 032import javax.xml.bind.annotation.XmlElement; 033import javax.xml.bind.annotation.XmlRootElement; 034import javax.xml.namespace.QName; 035import org.apache.hadoop.hbase.HConstants; 036import org.apache.hadoop.hbase.TableName; 037import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 038import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 039import org.apache.hadoop.hbase.client.TableDescriptor; 040import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 041import org.apache.hadoop.hbase.rest.ProtobufMessageHandler; 042import org.apache.hadoop.hbase.rest.RestUtil; 043import org.apache.hadoop.hbase.rest.protobuf.generated.ColumnSchemaMessage.ColumnSchema; 044import org.apache.hadoop.hbase.rest.protobuf.generated.TableSchemaMessage.TableSchema; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.apache.yetus.audience.InterfaceAudience; 047 048import org.apache.hbase.thirdparty.com.google.protobuf.CodedInputStream; 049import org.apache.hbase.thirdparty.com.google.protobuf.Message; 050 051/** 052 * A representation of HBase table descriptors. 053 * 054 * <pre> 055 * <complexType name="TableSchema"> 056 * <sequence> 057 * <element name="column" type="tns:ColumnSchema" 058 * maxOccurs="unbounded" minOccurs="1"></element> 059 * </sequence> 060 * <attribute name="name" type="string"></attribute> 061 * <anyAttribute></anyAttribute> 062 * </complexType> 063 * </pre> 064 */ 065@XmlRootElement(name = "TableSchema") 066@InterfaceAudience.Private 067public class TableSchemaModel implements Serializable, ProtobufMessageHandler { 068 private static final long serialVersionUID = 1L; 069 private static final QName IS_META = new QName(TableDescriptorBuilder.IS_META); 070 private static final QName IS_ROOT = new QName("IS_ROOT"); 071 private static final QName READONLY = new QName(TableDescriptorBuilder.READONLY); 072 private static final QName TTL = new QName(ColumnFamilyDescriptorBuilder.TTL); 073 private static final QName VERSIONS = new QName(HConstants.VERSIONS); 074 private static final QName COMPRESSION = new QName(ColumnFamilyDescriptorBuilder.COMPRESSION); 075 076 private String name; 077 private Map<QName, Object> attrs = new LinkedHashMap<>(); 078 private List<ColumnSchemaModel> columns = new ArrayList<>(); 079 080 /** 081 * Default constructor. 082 */ 083 public TableSchemaModel() { 084 } 085 086 /** 087 * Constructor 088 * @param tableDescriptor the table descriptor 089 */ 090 public TableSchemaModel(TableDescriptor tableDescriptor) { 091 setName(tableDescriptor.getTableName().getNameAsString()); 092 for (Map.Entry<Bytes, Bytes> e : tableDescriptor.getValues().entrySet()) { 093 addAttribute(Bytes.toString(e.getKey().get()), Bytes.toString(e.getValue().get())); 094 } 095 for (ColumnFamilyDescriptor hcd : tableDescriptor.getColumnFamilies()) { 096 ColumnSchemaModel columnModel = new ColumnSchemaModel(); 097 columnModel.setName(hcd.getNameAsString()); 098 for (Map.Entry<Bytes, Bytes> e : hcd.getValues().entrySet()) { 099 columnModel.addAttribute(Bytes.toString(e.getKey().get()), 100 Bytes.toString(e.getValue().get())); 101 } 102 addColumnFamily(columnModel); 103 } 104 } 105 106 /** 107 * Add an attribute to the table descriptor 108 * @param name attribute name 109 * @param value attribute value 110 */ 111 @JsonAnySetter 112 public void addAttribute(String name, Object value) { 113 attrs.put(new QName(name), value); 114 } 115 116 /** 117 * Return a table descriptor value as a string. Calls toString() on the object stored in the 118 * descriptor value map. 119 * @param name the attribute name 120 * @return the attribute value 121 */ 122 public String getAttribute(String name) { 123 Object o = attrs.get(new QName(name)); 124 return o != null ? o.toString() : null; 125 } 126 127 /** 128 * Add a column family to the table descriptor 129 * @param family the column family model 130 */ 131 public void addColumnFamily(ColumnSchemaModel family) { 132 columns.add(family); 133 } 134 135 /** 136 * Retrieve the column family at the given index from the table descriptor 137 * @param index the index 138 * @return the column family model 139 */ 140 public ColumnSchemaModel getColumnFamily(int index) { 141 return columns.get(index); 142 } 143 144 /** Returns the table name */ 145 @XmlAttribute 146 public String getName() { 147 return name; 148 } 149 150 /** Returns the map for holding unspecified (user) attributes */ 151 @XmlAnyAttribute 152 @JsonAnyGetter 153 public Map<QName, Object> getAny() { 154 return attrs; 155 } 156 157 /** Returns the columns */ 158 @XmlElement(name = "ColumnSchema") 159 public List<ColumnSchemaModel> getColumns() { 160 return columns; 161 } 162 163 /** 164 * @param name the table name 165 */ 166 public void setName(String name) { 167 this.name = name; 168 } 169 170 /** 171 * @param columns the columns to set 172 */ 173 public void setColumns(List<ColumnSchemaModel> columns) { 174 this.columns = columns; 175 } 176 177 /* 178 * (non-Javadoc) 179 * @see java.lang.Object#toString() 180 */ 181 @Override 182 public String toString() { 183 StringBuilder sb = new StringBuilder(); 184 sb.append("{ NAME=> '"); 185 sb.append(name); 186 sb.append('\''); 187 for (Map.Entry<QName, Object> e : attrs.entrySet()) { 188 sb.append(", "); 189 sb.append(e.getKey().getLocalPart()); 190 sb.append(" => '"); 191 sb.append(e.getValue().toString()); 192 sb.append('\''); 193 } 194 sb.append(", COLUMNS => [ "); 195 Iterator<ColumnSchemaModel> i = columns.iterator(); 196 while (i.hasNext()) { 197 ColumnSchemaModel family = i.next(); 198 sb.append(family.toString()); 199 if (i.hasNext()) { 200 sb.append(','); 201 } 202 sb.append(' '); 203 } 204 sb.append("] }"); 205 return sb.toString(); 206 } 207 208 // getters and setters for common schema attributes 209 210 // cannot be standard bean type getters and setters, otherwise this would 211 // confuse JAXB 212 213 /** Returns true if IS_META attribute exists and is truel */ 214 public boolean __getIsMeta() { 215 Object o = attrs.get(IS_META); 216 return o != null && Boolean.parseBoolean(o.toString()); 217 } 218 219 /** Returns true if IS_ROOT attribute exists and is truel */ 220 public boolean __getIsRoot() { 221 Object o = attrs.get(IS_ROOT); 222 return o != null && Boolean.parseBoolean(o.toString()); 223 } 224 225 /** Returns true if READONLY attribute exists and is truel */ 226 public boolean __getReadOnly() { 227 Object o = attrs.get(READONLY); 228 return o != null ? Boolean.parseBoolean(o.toString()) : TableDescriptorBuilder.DEFAULT_READONLY; 229 } 230 231 /** 232 * @param value desired value of IS_META attribute 233 */ 234 public void __setIsMeta(boolean value) { 235 attrs.put(IS_META, Boolean.toString(value)); 236 } 237 238 /** 239 * @param value desired value of IS_ROOT attribute 240 */ 241 public void __setIsRoot(boolean value) { 242 attrs.put(IS_ROOT, Boolean.toString(value)); 243 } 244 245 /** 246 * @param value desired value of READONLY attribute 247 */ 248 public void __setReadOnly(boolean value) { 249 attrs.put(READONLY, Boolean.toString(value)); 250 } 251 252 @Override 253 public Message messageFromObject() { 254 TableSchema.Builder builder = TableSchema.newBuilder(); 255 builder.setName(name); 256 for (Map.Entry<QName, Object> e : attrs.entrySet()) { 257 TableSchema.Attribute.Builder attrBuilder = TableSchema.Attribute.newBuilder(); 258 attrBuilder.setName(e.getKey().getLocalPart()); 259 attrBuilder.setValue(e.getValue().toString()); 260 builder.addAttrs(attrBuilder); 261 } 262 for (ColumnSchemaModel family : columns) { 263 Map<QName, Object> familyAttrs = family.getAny(); 264 ColumnSchema.Builder familyBuilder = ColumnSchema.newBuilder(); 265 familyBuilder.setName(family.getName()); 266 for (Map.Entry<QName, Object> e : familyAttrs.entrySet()) { 267 ColumnSchema.Attribute.Builder attrBuilder = ColumnSchema.Attribute.newBuilder(); 268 attrBuilder.setName(e.getKey().getLocalPart()); 269 attrBuilder.setValue(e.getValue().toString()); 270 familyBuilder.addAttrs(attrBuilder); 271 } 272 if (familyAttrs.containsKey(TTL)) { 273 familyBuilder.setTtl(Integer.parseInt(familyAttrs.get(TTL).toString())); 274 } 275 if (familyAttrs.containsKey(VERSIONS)) { 276 familyBuilder.setMaxVersions(Integer.parseInt(familyAttrs.get(VERSIONS).toString())); 277 } 278 if (familyAttrs.containsKey(COMPRESSION)) { 279 familyBuilder.setCompression(familyAttrs.get(COMPRESSION).toString()); 280 } 281 builder.addColumns(familyBuilder); 282 } 283 if (attrs.containsKey(READONLY)) { 284 builder.setReadOnly(Boolean.parseBoolean(attrs.get(READONLY).toString())); 285 } 286 return builder.build(); 287 } 288 289 @Override 290 public ProtobufMessageHandler getObjectFromMessage(CodedInputStream cis) throws IOException { 291 TableSchema.Builder builder = TableSchema.newBuilder(); 292 RestUtil.mergeFrom(builder, cis); 293 this.setName(builder.getName()); 294 for (TableSchema.Attribute attr : builder.getAttrsList()) { 295 this.addAttribute(attr.getName(), attr.getValue()); 296 } 297 if (builder.hasReadOnly()) { 298 this.addAttribute(TableDescriptorBuilder.READONLY, builder.getReadOnly()); 299 } 300 for (ColumnSchema family : builder.getColumnsList()) { 301 ColumnSchemaModel familyModel = new ColumnSchemaModel(); 302 familyModel.setName(family.getName()); 303 for (ColumnSchema.Attribute attr : family.getAttrsList()) { 304 familyModel.addAttribute(attr.getName(), attr.getValue()); 305 } 306 if (family.hasTtl()) { 307 familyModel.addAttribute(ColumnFamilyDescriptorBuilder.TTL, family.getTtl()); 308 } 309 if (family.hasMaxVersions()) { 310 familyModel.addAttribute(HConstants.VERSIONS, family.getMaxVersions()); 311 } 312 if (family.hasCompression()) { 313 familyModel.addAttribute(ColumnFamilyDescriptorBuilder.COMPRESSION, 314 family.getCompression()); 315 } 316 this.addColumnFamily(familyModel); 317 } 318 return this; 319 } 320 321 /** Returns a table descriptor */ 322 @JsonIgnore 323 public TableDescriptor getTableDescriptor() { 324 TableDescriptorBuilder tableDescriptorBuilder = 325 TableDescriptorBuilder.newBuilder(TableName.valueOf(getName())); 326 for (Map.Entry<QName, Object> e : getAny().entrySet()) { 327 tableDescriptorBuilder.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 328 } 329 for (ColumnSchemaModel column : getColumns()) { 330 ColumnFamilyDescriptorBuilder cfdb = 331 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column.getName())); 332 for (Map.Entry<QName, Object> e : column.getAny().entrySet()) { 333 cfdb.setValue(e.getKey().getLocalPart(), e.getValue().toString()); 334 } 335 tableDescriptorBuilder.setColumnFamily(cfdb.build()); 336 } 337 return tableDescriptorBuilder.build(); 338 } 339}