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