package org.infinispan.commands.write;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import org.infinispan.atomic.Delta;
import org.infinispan.atomic.DeltaCompositeKey;
import org.infinispan.commands.CommandInvocationId;
import org.infinispan.commands.Visitor;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.util.EnumUtil;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.DeltaAwareCacheEntry;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.FlagBitSets;
/**
* @author Vladimir Blagojevic
* @since 5.1
*/
public class ApplyDeltaCommand extends AbstractDataWriteCommand {
public static final int COMMAND_ID = 25;
private Collection<Object> keys;
private Delta delta;
public ApplyDeltaCommand() {
}
public ApplyDeltaCommand(Object deltaAwareValueKey, Delta delta, Collection<Object> keys, CommandInvocationId commandInvocationId) {
super(deltaAwareValueKey, EnumUtil.bitSetOf(Flag.DELTA_WRITE), commandInvocationId);
if (keys == null || keys.isEmpty())
throw new IllegalArgumentException("At least one key to be locked needs to be specified");
this.keys = keys;
this.delta = delta;
}
public Delta getDelta(){
return delta;
}
/**
* Performs an application of delta on a specified entry
*
* @param ctx invocation context
* @return null
*/
@Override
public Object perform(InvocationContext ctx) throws Throwable {
CacheEntry contextEntry = ctx.lookupEntry(key);
if (contextEntry instanceof DeltaAwareCacheEntry) {
DeltaAwareCacheEntry deltaAwareCacheEntry = (DeltaAwareCacheEntry) contextEntry;
deltaAwareCacheEntry.appendDelta(delta);
} else {
throw new IllegalStateException();
}
return null;
}
@Override
public byte getCommandId() {
return COMMAND_ID;
}
@Override
public String toString() {
return "ApplyDeltaCommand[" +
"key=" + key +
", delta=" + delta +
", keys=" + keys +
", commandInvocationId=" + CommandInvocationId.show(commandInvocationId) +
+ ']';
}
@Override
public void writeTo(ObjectOutput output) throws IOException {
output.writeObject(key);
output.writeObject(delta);
MarshallUtil.marshallCollection(keys, output);
output.writeLong(FlagBitSets.copyWithoutRemotableFlags(getFlagsBitSet()));
CommandInvocationId.writeTo(output, commandInvocationId);
}
@Override
public void readFrom(ObjectInput input) throws IOException, ClassNotFoundException {
key = input.readObject();
delta = (Delta) input.readObject();
keys = MarshallUtil.unmarshallCollection(input, ArrayList::new);
setFlagsBitSet(input.readLong());
commandInvocationId = CommandInvocationId.readFrom(input);
}
@Override
public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable {
return visitor.visitApplyDeltaCommand(ctx, this);
}
public Object[] getKeys() {
return keys.toArray();
}
public Object[] getCompositeKeys() {
DeltaCompositeKey[] compositeKeys = new DeltaCompositeKey[keys.size()];
int i = 0;
for (Object k : keys) {
compositeKeys[i++] = new DeltaCompositeKey(key, k);
}
return compositeKeys;
}
@Override
public LoadType loadType() {
return LoadType.OWNER;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ApplyDeltaCommand)) {
return false;
}
if (!super.equals(o)) {
return false;
}
ApplyDeltaCommand that = (ApplyDeltaCommand) o;
return keys.equals(that.keys);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + keys.hashCode();
}
@Override
public boolean isSuccessful() {
return true;
}
@Override
public boolean isConditional() {
return false;
}
@Override
public ValueMatcher getValueMatcher() {
return ValueMatcher.MATCH_ALWAYS;
}
@Override
public void setValueMatcher(ValueMatcher valueMatcher) {
// Do nothing
}
@Override
public void fail() {
throw new UnsupportedOperationException();
}
}