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.client; 019 020import org.apache.hadoop.hbase.CompareOperator; 021import org.apache.hadoop.hbase.filter.Filter; 022import org.apache.hadoop.hbase.io.TimeRange; 023import org.apache.hadoop.hbase.util.Bytes; 024import org.apache.yetus.audience.InterfaceAudience; 025import org.apache.yetus.audience.InterfaceStability; 026import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 027 028/** 029 * Used to perform CheckAndMutate operations. 030 * <p> 031 * Use the builder class to instantiate a CheckAndMutate object. 032 * This builder class is fluent style APIs, the code are like: 033 * <pre> 034 * <code> 035 * // A CheckAndMutate operation where do the specified action if the column (specified by the 036 * // family and the qualifier) of the row equals to the specified value 037 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 038 * .ifEquals(family, qualifier, value) 039 * .build(put); 040 * 041 * // A CheckAndMutate operation where do the specified action if the column (specified by the 042 * // family and the qualifier) of the row doesn't exist 043 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 044 * .ifNotExists(family, qualifier) 045 * .build(put); 046 * 047 * // A CheckAndMutate operation where do the specified action if the row matches the filter 048 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 049 * .ifMatches(filter) 050 * .build(delete); 051 * </code> 052 * </pre> 053 */ 054@InterfaceAudience.Public 055@InterfaceStability.Evolving 056public final class CheckAndMutate implements Row { 057 058 /** 059 * A builder class for building a CheckAndMutate object. 060 */ 061 @InterfaceAudience.Public 062 @InterfaceStability.Evolving 063 public static final class Builder { 064 private final byte[] row; 065 private byte[] family; 066 private byte[] qualifier; 067 private CompareOperator op; 068 private byte[] value; 069 private Filter filter; 070 private TimeRange timeRange; 071 072 private Builder(byte[] row) { 073 this.row = Preconditions.checkNotNull(row, "row is null"); 074 } 075 076 /** 077 * Check for lack of column 078 * 079 * @param family family to check 080 * @param qualifier qualifier to check 081 * @return the CheckAndMutate object 082 */ 083 public Builder ifNotExists(byte[] family, byte[] qualifier) { 084 return ifEquals(family, qualifier, null); 085 } 086 087 /** 088 * Check for equality 089 * 090 * @param family family to check 091 * @param qualifier qualifier to check 092 * @param value the expected value 093 * @return the CheckAndMutate object 094 */ 095 public Builder ifEquals(byte[] family, byte[] qualifier, byte[] value) { 096 return ifMatches(family, qualifier, CompareOperator.EQUAL, value); 097 } 098 099 /** 100 * @param family family to check 101 * @param qualifier qualifier to check 102 * @param compareOp comparison operator to use 103 * @param value the expected value 104 * @return the CheckAndMutate object 105 */ 106 public Builder ifMatches(byte[] family, byte[] qualifier, CompareOperator compareOp, 107 byte[] value) { 108 this.family = Preconditions.checkNotNull(family, "family is null"); 109 this.qualifier = qualifier; 110 this.op = Preconditions.checkNotNull(compareOp, "compareOp is null"); 111 this.value = value; 112 return this; 113 } 114 115 /** 116 * @param filter filter to check 117 * @return the CheckAndMutate object 118 */ 119 public Builder ifMatches(Filter filter) { 120 this.filter = Preconditions.checkNotNull(filter, "filter is null"); 121 return this; 122 } 123 124 /** 125 * @param timeRange time range to check 126 * @return the CheckAndMutate object 127 */ 128 public Builder timeRange(TimeRange timeRange) { 129 this.timeRange = timeRange; 130 return this; 131 } 132 133 private void preCheck(Row action) { 134 Preconditions.checkNotNull(action, "action is null"); 135 if (!Bytes.equals(row, action.getRow())) { 136 throw new IllegalArgumentException("The row of the action <" + 137 Bytes.toStringBinary(action.getRow()) + "> doesn't match the original one <" + 138 Bytes.toStringBinary(this.row) + ">"); 139 } 140 Preconditions.checkState(op != null || filter != null, "condition is null. You need to" 141 + " specify the condition by calling ifNotExists/ifEquals/ifMatches before building a" 142 + " CheckAndMutate object"); 143 } 144 145 /** 146 * @param put data to put if check succeeds 147 * @return a CheckAndMutate object 148 */ 149 public CheckAndMutate build(Put put) { 150 preCheck(put); 151 if (filter != null) { 152 return new CheckAndMutate(row, filter, timeRange, put); 153 } else { 154 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, put); 155 } 156 } 157 158 /** 159 * @param delete data to delete if check succeeds 160 * @return a CheckAndMutate object 161 */ 162 public CheckAndMutate build(Delete delete) { 163 preCheck(delete); 164 if (filter != null) { 165 return new CheckAndMutate(row, filter, timeRange, delete); 166 } else { 167 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, delete); 168 } 169 } 170 171 /** 172 * @param increment data to increment if check succeeds 173 * @return a CheckAndMutate object 174 */ 175 public CheckAndMutate build(Increment increment) { 176 preCheck(increment); 177 if (filter != null) { 178 return new CheckAndMutate(row, filter, timeRange, increment); 179 } else { 180 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, increment); 181 } 182 } 183 184 /** 185 * @param append data to append if check succeeds 186 * @return a CheckAndMutate object 187 */ 188 public CheckAndMutate build(Append append) { 189 preCheck(append); 190 if (filter != null) { 191 return new CheckAndMutate(row, filter, timeRange, append); 192 } else { 193 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, append); 194 } 195 } 196 197 /** 198 * @param mutations mutations to perform if check succeeds 199 * @return a CheckAndMutate object 200 */ 201 public CheckAndMutate build(RowMutations mutations) { 202 preCheck(mutations); 203 if (filter != null) { 204 return new CheckAndMutate(row, filter, timeRange, mutations); 205 } else { 206 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, mutations); 207 } 208 } 209 } 210 211 /** 212 * returns a builder object to build a CheckAndMutate object 213 * 214 * @param row row 215 * @return a builder object 216 */ 217 public static Builder newBuilder(byte[] row) { 218 return new Builder(row); 219 } 220 221 private final byte[] row; 222 private final byte[] family; 223 private final byte[] qualifier; 224 private final CompareOperator op; 225 private final byte[] value; 226 private final Filter filter; 227 private final TimeRange timeRange; 228 private final Row action; 229 230 private CheckAndMutate(byte[] row, byte[] family, byte[] qualifier,final CompareOperator op, 231 byte[] value, TimeRange timeRange, Row action) { 232 this.row = row; 233 this.family = family; 234 this.qualifier = qualifier; 235 this.op = op; 236 this.value = value; 237 this.filter = null; 238 this.timeRange = timeRange != null ? timeRange : TimeRange.allTime(); 239 this.action = action; 240 } 241 242 private CheckAndMutate(byte[] row, Filter filter, TimeRange timeRange, Row action) { 243 this.row = row; 244 this.family = null; 245 this.qualifier = null; 246 this.op = null; 247 this.value = null; 248 this.filter = filter; 249 this.timeRange = timeRange != null ? timeRange : TimeRange.allTime(); 250 this.action = action; 251 } 252 253 /** 254 * @return the row 255 */ 256 @Override 257 public byte[] getRow() { 258 return row; 259 } 260 261 /** 262 * @return the family to check 263 */ 264 public byte[] getFamily() { 265 return family; 266 } 267 268 /** 269 * @return the qualifier to check 270 */ 271 public byte[] getQualifier() { 272 return qualifier; 273 } 274 275 /** 276 * @return the comparison operator 277 */ 278 public CompareOperator getCompareOp() { 279 return op; 280 } 281 282 /** 283 * @return the expected value 284 */ 285 public byte[] getValue() { 286 return value; 287 } 288 289 /** 290 * @return the filter to check 291 */ 292 public Filter getFilter() { 293 return filter; 294 } 295 296 /** 297 * @return whether this has a filter or not 298 */ 299 public boolean hasFilter() { 300 return filter != null; 301 } 302 303 /** 304 * @return the time range to check 305 */ 306 public TimeRange getTimeRange() { 307 return timeRange; 308 } 309 310 /** 311 * @return the action done if check succeeds 312 */ 313 public Row getAction() { 314 return action; 315 } 316}