blob: f7d846b44c7a5c108f42cb9ab9ff7dd7054e3a7a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import java.util.Collections;
import java.util.List;
import java.util.NavigableMap;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellBuilder;
import org.apache.hadoop.hbase.CellBuilderType;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.io.TimeRange;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
/**
* Used to perform CheckAndMutate operations.
* <p>
* Use the builder class to instantiate a CheckAndMutate object.
* This builder class is fluent style APIs, the code are like:
* <pre>
* <code>
* // A CheckAndMutate operation where do the specified action if the column (specified by the
* // family and the qualifier) of the row equals to the specified value
* CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row)
* .ifEquals(family, qualifier, value)
* .build(put);
*
* // A CheckAndMutate operation where do the specified action if the column (specified by the
* // family and the qualifier) of the row doesn't exist
* CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row)
* .ifNotExists(family, qualifier)
* .build(put);
*
* // A CheckAndMutate operation where do the specified action if the row matches the filter
* CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row)
* .ifMatches(filter)
* .build(delete);
* </code>
* </pre>
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public final class CheckAndMutate extends Mutation {
/**
* A builder class for building a CheckAndMutate object.
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public static final class Builder {
private final byte[] row;
private byte[] family;
private byte[] qualifier;
private CompareOperator op;
private byte[] value;
private Filter filter;
private TimeRange timeRange;
private Builder(byte[] row) {
this.row = Preconditions.checkNotNull(row, "row is null");
}
/**
* Check for lack of column
*
* @param family family to check
* @param qualifier qualifier to check
* @return the CheckAndMutate object
*/
public Builder ifNotExists(byte[] family, byte[] qualifier) {
return ifEquals(family, qualifier, null);
}
/**
* Check for equality
*
* @param family family to check
* @param qualifier qualifier to check
* @param value the expected value
* @return the CheckAndMutate object
*/
public Builder ifEquals(byte[] family, byte[] qualifier, byte[] value) {
return ifMatches(family, qualifier, CompareOperator.EQUAL, value);
}
/**
* @param family family to check
* @param qualifier qualifier to check
* @param compareOp comparison operator to use
* @param value the expected value
* @return the CheckAndMutate object
*/
public Builder ifMatches(byte[] family, byte[] qualifier, CompareOperator compareOp,
byte[] value) {
this.family = Preconditions.checkNotNull(family, "family is null");
this.qualifier = qualifier;
this.op = Preconditions.checkNotNull(compareOp, "compareOp is null");
this.value = value;
return this;
}
/**
* @param filter filter to check
* @return the CheckAndMutate object
*/
public Builder ifMatches(Filter filter) {
this.filter = Preconditions.checkNotNull(filter, "filter is null");
return this;
}
/**
* @param timeRange time range to check
* @return the CheckAndMutate object
*/
public Builder timeRange(TimeRange timeRange) {
this.timeRange = timeRange;
return this;
}
private void preCheck(Row action) {
Preconditions.checkNotNull(action, "action is null");
if (!Bytes.equals(row, action.getRow())) {
throw new IllegalArgumentException("The row of the action <" +
Bytes.toStringBinary(action.getRow()) + "> doesn't match the original one <" +
Bytes.toStringBinary(this.row) + ">");
}
Preconditions.checkState(op != null || filter != null, "condition is null. You need to"
+ " specify the condition by calling ifNotExists/ifEquals/ifMatches before building a"
+ " CheckAndMutate object");
}
/**
* @param put data to put if check succeeds
* @return a CheckAndMutate object
*/
public CheckAndMutate build(Put put) {
preCheck(put);
if (filter != null) {
return new CheckAndMutate(row, filter, timeRange, put);
} else {
return new CheckAndMutate(row, family, qualifier, op, value, timeRange, put);
}
}
/**
* @param delete data to delete if check succeeds
* @return a CheckAndMutate object
*/
public CheckAndMutate build(Delete delete) {
preCheck(delete);
if (filter != null) {
return new CheckAndMutate(row, filter, timeRange, delete);
} else {
return new CheckAndMutate(row, family, qualifier, op, value, timeRange, delete);
}
}
/**
* @param increment data to increment if check succeeds
* @return a CheckAndMutate object
*/
public CheckAndMutate build(Increment increment) {
preCheck(increment);
if (filter != null) {
return new CheckAndMutate(row, filter, timeRange, increment);
} else {
return new CheckAndMutate(row, family, qualifier, op, value, timeRange, increment);
}
}
/**
* @param append data to append if check succeeds
* @return a CheckAndMutate object
*/
public CheckAndMutate build(Append append) {
preCheck(append);
if (filter != null) {
return new CheckAndMutate(row, filter, timeRange, append);
} else {
return new CheckAndMutate(row, family, qualifier, op, value, timeRange, append);
}
}
/**
* @param mutation mutations to perform if check succeeds
* @return a CheckAndMutate object
*/
public CheckAndMutate build(RowMutations mutation) {
preCheck(mutation);
if (filter != null) {
return new CheckAndMutate(row, filter, timeRange, mutation);
} else {
return new CheckAndMutate(row, family, qualifier, op, value, timeRange, mutation);
}
}
}
/**
* returns a builder object to build a CheckAndMutate object
*
* @param row row
* @return a builder object
*/
public static Builder newBuilder(byte[] row) {
return new Builder(row);
}
private final byte[] family;
private final byte[] qualifier;
private final CompareOperator op;
private final byte[] value;
private final Filter filter;
private final TimeRange timeRange;
private final Row action;
private CheckAndMutate(byte[] row, byte[] family, byte[] qualifier,final CompareOperator op,
byte[] value, TimeRange timeRange, Row action) {
super(row, HConstants.LATEST_TIMESTAMP, Collections.emptyNavigableMap());
this.family = family;
this.qualifier = qualifier;
this.op = op;
this.value = value;
this.filter = null;
this.timeRange = timeRange != null ? timeRange : TimeRange.allTime();
this.action = action;
}
private CheckAndMutate(byte[] row, Filter filter, TimeRange timeRange, Row action) {
super(row, HConstants.LATEST_TIMESTAMP, Collections.emptyNavigableMap());
this.family = null;
this.qualifier = null;
this.op = null;
this.value = null;
this.filter = filter;
this.timeRange = timeRange != null ? timeRange : TimeRange.allTime();
this.action = action;
}
/**
* @return the family to check
*/
public byte[] getFamily() {
return family;
}
/**
* @return the qualifier to check
*/
public byte[] getQualifier() {
return qualifier;
}
/**
* @return the comparison operator
*/
public CompareOperator getCompareOp() {
return op;
}
/**
* @return the expected value
*/
public byte[] getValue() {
return value;
}
/**
* @return the filter to check
*/
public Filter getFilter() {
return filter;
}
/**
* @return whether this has a filter or not
*/
public boolean hasFilter() {
return filter != null;
}
/**
* @return the time range to check
*/
public TimeRange getTimeRange() {
return timeRange;
}
/**
* @return the action done if check succeeds
*/
public Row getAction() {
return action;
}
@Override
public NavigableMap<byte[], List<Cell>> getFamilyCellMap() {
if (action instanceof Mutation) {
return ((Mutation) action).getFamilyCellMap();
}
throw new UnsupportedOperationException();
}
@Override
public CellBuilder getCellBuilder(CellBuilderType cellBuilderType) {
if (action instanceof Mutation) {
return ((Mutation) action).getCellBuilder();
}
throw new UnsupportedOperationException();
}
@Override
public long getTimestamp() {
if (action instanceof Mutation) {
return ((Mutation) action).getTimestamp();
}
throw new UnsupportedOperationException();
}
@Override
public Mutation setTimestamp(long timestamp) {
if (action instanceof Mutation) {
return ((Mutation) action).setTimestamp(timestamp);
}
throw new UnsupportedOperationException();
}
@Override
public Durability getDurability() {
if (action instanceof Mutation) {
return ((Mutation) action).getDurability();
}
throw new UnsupportedOperationException();
}
@Override
public Mutation setDurability(Durability d) {
if (action instanceof Mutation) {
return ((Mutation) action).setDurability(d);
}
throw new UnsupportedOperationException();
}
@Override
public byte[] getAttribute(String name) {
if (action instanceof Mutation) {
return ((Mutation) action).getAttribute(name);
}
throw new UnsupportedOperationException();
}
@Override
public OperationWithAttributes setAttribute(String name, byte[] value) {
if (action instanceof Mutation) {
return ((Mutation) action).setAttribute(name, value);
}
throw new UnsupportedOperationException();
}
@Override
public int getPriority() {
if (action instanceof Mutation) {
return ((Mutation) action).getPriority();
}
return ((RowMutations) action).getMaxPriority();
}
@Override
public OperationWithAttributes setPriority(int priority) {
if (action instanceof Mutation) {
return ((Mutation) action).setPriority(priority);
}
throw new UnsupportedOperationException();
}
}