package org.infinispan.stream.impl;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import org.infinispan.commands.TopologyAffectedCommand;
import org.infinispan.commands.remote.BaseRpcCommand;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.remoting.transport.Address;
import org.infinispan.util.ByteString;
import org.infinispan.util.concurrent.CompletableFutures;
/**
* Stream request command that is sent to remote nodes handle execution of remote intermediate and terminal operations.
* @param <K> the key type
*/
public class StreamRequestCommand<K> extends BaseRpcCommand implements TopologyAffectedCommand {
public static final byte COMMAND_ID = 47;
private LocalStreamManager lsm;
private Object id;
private Type type;
private boolean parallelStream;
private Set<Integer> segments;
private Set<K> keys;
private Set<K> excludedKeys;
private boolean includeLoader;
private Object terminalOperation;
private int topologyId = -1;
@Override
public int getTopologyId() {
return topologyId;
}
@Override
public void setTopologyId(int topologyId) {
this.topologyId = topologyId;
}
public Object getId() {
return id;
}
public enum Type {
TERMINAL,
TERMINAL_REHASH,
TERMINAL_KEY,
TERMINAL_KEY_REHASH;
private static final Type[] CACHED_VALUES = values();
}
// Only here for CommandIdUniquenessTest
private StreamRequestCommand() { super(null); }
public StreamRequestCommand(ByteString cacheName) {
super(cacheName);
}
public StreamRequestCommand(ByteString cacheName, Address origin, Object id, boolean parallelStream, Type type,
Set<Integer> segments, Set<K> keys, Set<K> excludedKeys, boolean includeLoader,
Object terminalOperation) {
super(cacheName);
setOrigin(origin);
this.id = id;
this.parallelStream = parallelStream;
this.type = type;
this.segments = segments;
this.keys = keys;
this.excludedKeys = excludedKeys;
this.includeLoader = includeLoader;
this.terminalOperation = terminalOperation;
}
@Inject
public void inject(LocalStreamManager lsm) {
this.lsm = lsm;
}
@Override
public CompletableFuture<Object> invokeAsync() throws Throwable {
switch (type) {
case TERMINAL:
lsm.streamOperation(id, getOrigin(), parallelStream, segments, keys, excludedKeys, includeLoader,
(TerminalOperation) terminalOperation);
break;
case TERMINAL_REHASH:
lsm.streamOperationRehashAware(id, getOrigin(), parallelStream, segments, keys, excludedKeys, includeLoader,
(TerminalOperation) terminalOperation);
break;
case TERMINAL_KEY:
lsm.streamOperation(id, getOrigin(), parallelStream, segments, keys, excludedKeys, includeLoader,
(KeyTrackingTerminalOperation) terminalOperation);
break;
case TERMINAL_KEY_REHASH:
lsm.streamOperationRehashAware(id, getOrigin(), parallelStream, segments, keys, excludedKeys, includeLoader,
(KeyTrackingTerminalOperation) terminalOperation);
break;
}
return CompletableFutures.completedNull();
}
@Override
public byte getCommandId() {
return COMMAND_ID;
}
@Override
public void writeTo(ObjectOutput output) throws IOException {
output.writeObject(getOrigin());
output.writeObject(id);
output.writeBoolean(parallelStream);
MarshallUtil.marshallEnum(type, output);
MarshallUtil.marshallCollection(segments, output);
MarshallUtil.marshallCollection(keys, output);
MarshallUtil.marshallCollection(excludedKeys, output);
output.writeBoolean(includeLoader);
output.writeObject(terminalOperation);
}
@Override
public void readFrom(ObjectInput input) throws IOException, ClassNotFoundException {
setOrigin((Address) input.readObject());
id = input.readObject();
parallelStream = input.readBoolean();
type = MarshallUtil.unmarshallEnum(input, ordinal -> Type.CACHED_VALUES[ordinal]);
segments = MarshallUtil.unmarshallCollectionUnbounded(input, HashSet::new);
keys = MarshallUtil.unmarshallCollectionUnbounded(input, HashSet::new);
excludedKeys = MarshallUtil.unmarshallCollectionUnbounded(input, HashSet::new);
includeLoader = input.readBoolean();
terminalOperation = input.readObject();
}
@Override
public boolean isReturnValueExpected() {
return false;
}
@Override
public boolean canBlock() {
return true;
}
}