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