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