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