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