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