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