package org.infinispan.marshall.exts; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Collection; import java.util.Set; import org.infinispan.commands.RemoteCommandsFactory; import org.infinispan.commands.ReplicableCommand; import org.infinispan.commands.TopologyAffectedCommand; import org.infinispan.commands.functional.ReadOnlyKeyCommand; import org.infinispan.commands.functional.ReadOnlyManyCommand; import org.infinispan.commands.functional.ReadWriteKeyCommand; import org.infinispan.commands.functional.ReadWriteKeyValueCommand; import org.infinispan.commands.functional.ReadWriteManyCommand; import org.infinispan.commands.functional.ReadWriteManyEntriesCommand; import org.infinispan.commands.functional.TxReadOnlyKeyCommand; import org.infinispan.commands.functional.TxReadOnlyManyCommand; import org.infinispan.commands.functional.WriteOnlyKeyCommand; import org.infinispan.commands.functional.WriteOnlyKeyValueCommand; import org.infinispan.commands.functional.WriteOnlyManyCommand; import org.infinispan.commands.functional.WriteOnlyManyEntriesCommand; import org.infinispan.commands.read.DistributedExecuteCommand; import org.infinispan.commands.read.GetKeyValueCommand; import org.infinispan.commands.remote.CacheRpcCommand; import org.infinispan.commands.remote.GetKeysInGroupCommand; import org.infinispan.commands.write.ApplyDeltaCommand; import org.infinispan.commands.write.ClearCommand; import org.infinispan.commands.write.EvictCommand; import org.infinispan.commands.write.InvalidateCommand; import org.infinispan.commands.write.InvalidateL1Command; import org.infinispan.commands.write.PutKeyValueCommand; import org.infinispan.commands.write.PutMapCommand; import org.infinispan.commands.write.RemoveCommand; import org.infinispan.commands.write.RemoveExpiredCommand; import org.infinispan.commands.write.ReplaceCommand; import org.infinispan.commons.marshall.AbstractExternalizer; import org.infinispan.commons.util.Util; import org.infinispan.factories.GlobalComponentRegistry; import org.infinispan.manager.impl.ReplicableCommandManagerFunction; import org.infinispan.manager.impl.ReplicableCommandRunnable; import org.infinispan.marshall.DeltaAwareObjectOutput; import org.infinispan.marshall.core.Ids; import org.infinispan.topology.CacheTopologyControlCommand; import org.infinispan.util.ByteString; /** * ReplicableCommandExternalizer. * * @author Galder ZamarreƱo * @since 4.0 */ public class ReplicableCommandExternalizer extends AbstractExternalizer<ReplicableCommand> { private final RemoteCommandsFactory cmdFactory; private final GlobalComponentRegistry globalComponentRegistry; public ReplicableCommandExternalizer(RemoteCommandsFactory cmdFactory, GlobalComponentRegistry globalComponentRegistry) { this.cmdFactory = cmdFactory; this.globalComponentRegistry = globalComponentRegistry; } @Override public void writeObject(ObjectOutput output, ReplicableCommand command) throws IOException { writeCommandHeader(output, command); writeCommandParameters(output, command); } protected void writeCommandParameters(ObjectOutput output, ReplicableCommand command) throws IOException { DeltaAwareObjectOutput deltaAwareObjectOutput = output instanceof DeltaAwareObjectOutput ? (DeltaAwareObjectOutput) output : new DeltaAwareObjectOutput(output); command.writeTo(deltaAwareObjectOutput); if (command instanceof TopologyAffectedCommand) { output.writeInt(((TopologyAffectedCommand) command).getTopologyId()); } } protected void writeCommandHeader(ObjectOutput output, ReplicableCommand command) throws IOException { // To decide whether it's a core or user defined command, load them all and check Collection<Class<? extends ReplicableCommand>> moduleCommands = getModuleCommands(); // Write an indexer to separate commands defined external to the // infinispan core module from the ones defined via module commands if (moduleCommands != null && moduleCommands.contains(command.getClass())) output.writeByte(1); else output.writeByte(0); output.writeShort(command.getCommandId()); } @Override public ReplicableCommand readObject(ObjectInput input) throws IOException, ClassNotFoundException { ReplicableCommand replicableCommand = readCommandHeader(input); readCommandParameters(input, replicableCommand); return replicableCommand; } private ReplicableCommand readCommandHeader(ObjectInput input) throws IOException { byte type = input.readByte(); short methodId = input.readShort(); return cmdFactory.fromStream((byte) methodId, type); } void readCommandParameters(ObjectInput input, ReplicableCommand command) throws IOException, ClassNotFoundException { command.readFrom(input); if (command instanceof TopologyAffectedCommand) { ((TopologyAffectedCommand) command).setTopologyId(input.readInt()); } } protected CacheRpcCommand fromStream(byte id, byte type, ByteString cacheName) { return cmdFactory.fromStream(id, type, cacheName); } @Override public Integer getId() { return Ids.REPLICABLE_COMMAND; } @Override public Set<Class<? extends ReplicableCommand>> getTypeClasses() { //noinspection unchecked Set<Class<? extends ReplicableCommand>> coreCommands = Util.asSet( CacheTopologyControlCommand.class, DistributedExecuteCommand.class, GetKeyValueCommand.class, ClearCommand.class, EvictCommand.class, ApplyDeltaCommand.class, InvalidateCommand.class, InvalidateL1Command.class, PutKeyValueCommand.class, PutMapCommand.class, RemoveCommand.class, RemoveExpiredCommand.class, ReplaceCommand.class, GetKeysInGroupCommand.class, ReadOnlyKeyCommand.class, ReadOnlyManyCommand.class, ReadWriteKeyCommand.class, ReadWriteKeyValueCommand.class, WriteOnlyKeyCommand.class, WriteOnlyKeyValueCommand.class, WriteOnlyManyCommand.class, WriteOnlyManyEntriesCommand.class, ReadWriteManyCommand.class, ReadWriteManyEntriesCommand.class, TxReadOnlyKeyCommand.class, TxReadOnlyManyCommand.class, ReplicableCommandRunnable.class, ReplicableCommandManagerFunction.class); // Search only those commands that replicable and not cache specific replicable commands Collection<Class<? extends ReplicableCommand>> moduleCommands = globalComponentRegistry.getModuleProperties().moduleOnlyReplicableCommands(); if (moduleCommands != null && !moduleCommands.isEmpty()) coreCommands.addAll(moduleCommands); return coreCommands; } private Collection<Class<? extends ReplicableCommand>> getModuleCommands() { return globalComponentRegistry.getModuleProperties().moduleCommands(); } }