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 static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIMITER; 021 022import com.fasterxml.jackson.annotation.JsonIgnore; 023import com.fasterxml.jackson.annotation.JsonProperty; 024import java.io.IOException; 025import java.io.Serializable; 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlAttribute; 029import javax.xml.bind.annotation.XmlRootElement; 030import javax.xml.bind.annotation.XmlValue; 031import org.apache.commons.lang3.builder.EqualsBuilder; 032import org.apache.commons.lang3.builder.HashCodeBuilder; 033import org.apache.commons.lang3.builder.ToStringBuilder; 034import org.apache.hadoop.hbase.CellUtil; 035import org.apache.hadoop.hbase.HConstants; 036import org.apache.hadoop.hbase.rest.ProtobufMessageHandler; 037import org.apache.hadoop.hbase.rest.RestUtil; 038import org.apache.yetus.audience.InterfaceAudience; 039 040import org.apache.hbase.thirdparty.com.google.protobuf.CodedInputStream; 041import org.apache.hbase.thirdparty.com.google.protobuf.Message; 042import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 043 044import org.apache.hadoop.hbase.shaded.rest.protobuf.generated.CellMessage.Cell; 045 046/** 047 * Representation of a cell. A cell is a single value associated a column and optional qualifier, 048 * and either the timestamp when it was stored or the user- provided timestamp if one was explicitly 049 * supplied. 050 * 051 * <pre> 052 * <complexType name="Cell"> 053 * <sequence> 054 * <element name="value" maxOccurs="1" minOccurs="1"> 055 * <simpleType> 056 * <restriction base="base64Binary"/> 057 * </simpleType> 058 * </element> 059 * </sequence> 060 * <attribute name="column" type="base64Binary" /> 061 * <attribute name="timestamp" type="int" /> 062 * </complexType> 063 * </pre> 064 */ 065@XmlRootElement(name = "Cell") 066@XmlAccessorType(XmlAccessType.NONE) 067@InterfaceAudience.Private 068public class CellModel implements ProtobufMessageHandler, Serializable { 069 private static final long serialVersionUID = 1L; 070 public static final int MAGIC_LENGTH = -1; 071 072 @JsonProperty("column") 073 @XmlAttribute 074 private byte[] column; 075 076 @JsonProperty("timestamp") 077 @XmlAttribute 078 private long timestamp = HConstants.LATEST_TIMESTAMP; 079 080 // If valueLength = -1, this represents the cell's value. 081 // If valueLength <> 1, this represents an array containing the cell's value as determined by 082 // offset and length. 083 private byte[] value; 084 085 @JsonIgnore 086 private int valueOffset; 087 088 @JsonIgnore 089 private int valueLength = MAGIC_LENGTH; 090 091 /** 092 * Default constructor 093 */ 094 public CellModel() { 095 } 096 097 /** 098 * Constructor 099 */ 100 public CellModel(byte[] column, byte[] value) { 101 this(column, HConstants.LATEST_TIMESTAMP, value); 102 } 103 104 /** 105 * Constructor 106 */ 107 public CellModel(byte[] column, byte[] qualifier, byte[] value) { 108 this(column, qualifier, HConstants.LATEST_TIMESTAMP, value); 109 } 110 111 /** 112 * Constructor from KeyValue This avoids copying the value from the cell, and tries to optimize 113 * generating the column value. 114 */ 115 public CellModel(org.apache.hadoop.hbase.Cell cell) { 116 this.column = makeColumn(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), 117 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); 118 this.timestamp = cell.getTimestamp(); 119 this.value = cell.getValueArray(); 120 this.valueOffset = cell.getValueOffset(); 121 this.valueLength = cell.getValueLength(); 122 } 123 124 /** 125 * Constructor 126 */ 127 public CellModel(byte[] column, long timestamp, byte[] value) { 128 this.column = column; 129 this.timestamp = timestamp; 130 setValue(value); 131 } 132 133 /** 134 * Constructor 135 */ 136 public CellModel(byte[] family, byte[] qualifier, long timestamp, byte[] value) { 137 this.column = CellUtil.makeColumn(family, qualifier); 138 this.timestamp = timestamp; 139 setValue(value); 140 } 141 142 /** Returns the column */ 143 public byte[] getColumn() { 144 return column; 145 } 146 147 /** 148 * @param column the column to set 149 */ 150 public void setColumn(byte[] column) { 151 this.column = column; 152 } 153 154 /** Returns true if the timestamp property has been specified by the user */ 155 public boolean hasUserTimestamp() { 156 return timestamp != HConstants.LATEST_TIMESTAMP; 157 } 158 159 /** Returns the timestamp */ 160 public long getTimestamp() { 161 return timestamp; 162 } 163 164 /** 165 * @param timestamp the timestamp to set 166 */ 167 public void setTimestamp(long timestamp) { 168 this.timestamp = timestamp; 169 } 170 171 /** Returns the value */ 172 @JsonProperty("$") 173 @XmlValue 174 public byte[] getValue() { 175 if (valueLength == MAGIC_LENGTH) { 176 return value; 177 } else { 178 byte[] retValue = new byte[valueLength]; 179 System.arraycopy(value, valueOffset, retValue, 0, valueLength); 180 return retValue; 181 } 182 } 183 184 /** Returns the backing array for value (may be the same as value) */ 185 public byte[] getValueArray() { 186 return value; 187 } 188 189 /** 190 * @param value the value to set 191 */ 192 @JsonProperty("$") 193 public void setValue(byte[] value) { 194 this.value = value; 195 this.valueLength = MAGIC_LENGTH; 196 } 197 198 public int getValueOffset() { 199 return valueOffset; 200 } 201 202 public int getValueLength() { 203 return valueLength; 204 } 205 206 @Override 207 public Message messageFromObject() { 208 Cell.Builder builder = Cell.newBuilder(); 209 builder.setColumn(UnsafeByteOperations.unsafeWrap(getColumn())); 210 if (valueLength == MAGIC_LENGTH) { 211 builder.setData(UnsafeByteOperations.unsafeWrap(getValue())); 212 } else { 213 builder.setData(UnsafeByteOperations.unsafeWrap(value, valueOffset, valueLength)); 214 } 215 if (hasUserTimestamp()) { 216 builder.setTimestamp(getTimestamp()); 217 } 218 return builder.build(); 219 } 220 221 @Override 222 public ProtobufMessageHandler getObjectFromMessage(CodedInputStream cis) throws IOException { 223 Cell.Builder builder = Cell.newBuilder(); 224 RestUtil.mergeFrom(builder, cis); 225 setColumn(builder.getColumn().toByteArray()); 226 setValue(builder.getData().toByteArray()); 227 if (builder.hasTimestamp()) { 228 setTimestamp(builder.getTimestamp()); 229 } 230 return this; 231 } 232 233 /** 234 * Makes a column in family:qualifier form from separate byte arrays with offset and length. 235 * <p> 236 * Not recommended for usage as this is old-style API. 237 * @return family:qualifier 238 */ 239 public static byte[] makeColumn(byte[] family, int familyOffset, int familyLength, 240 byte[] qualifier, int qualifierOffset, int qualifierLength) { 241 byte[] column = new byte[familyLength + qualifierLength + 1]; 242 System.arraycopy(family, familyOffset, column, 0, familyLength); 243 column[familyLength] = COLUMN_FAMILY_DELIMITER; 244 System.arraycopy(qualifier, qualifierOffset, column, familyLength + 1, qualifierLength); 245 return column; 246 } 247 248 @Override 249 public boolean equals(Object obj) { 250 if (obj == null) { 251 return false; 252 } 253 if (obj == this) { 254 return true; 255 } 256 if (obj.getClass() != getClass()) { 257 return false; 258 } 259 CellModel cellModel = (CellModel) obj; 260 return new EqualsBuilder().append(column, cellModel.column) 261 .append(timestamp, cellModel.timestamp).append(getValue(), cellModel.getValue()).isEquals(); 262 } 263 264 @Override 265 public int hashCode() { 266 return new HashCodeBuilder().append(column).append(timestamp).append(getValue()).toHashCode(); 267 } 268 269 @Override 270 public String toString() { 271 return new ToStringBuilder(this).append("column", column).append("timestamp", timestamp) 272 .append("value", getValue()).toString(); 273 } 274}