package org.infinispan.util.mocks; import static org.infinispan.xsite.XSiteAdminCommand.AdminOperation; import static org.infinispan.xsite.statetransfer.XSiteStateTransferControlCommand.StateTransferControl; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import javax.transaction.xa.Xid; import org.infinispan.Cache; import org.infinispan.atomic.Delta; import org.infinispan.commands.CancelCommand; import org.infinispan.commands.CommandsFactory; import org.infinispan.commands.CreateCacheCommand; import org.infinispan.commands.ReplicableCommand; import org.infinispan.commands.VisitableCommand; import org.infinispan.commands.control.LockControlCommand; 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.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.EntrySetCommand; import org.infinispan.commands.read.GetAllCommand; import org.infinispan.commands.read.GetCacheEntryCommand; import org.infinispan.commands.read.GetKeyValueCommand; import org.infinispan.commands.read.KeySetCommand; import org.infinispan.commands.read.SizeCommand; import org.infinispan.commands.remote.ClusteredGetAllCommand; import org.infinispan.commands.remote.ClusteredGetCommand; import org.infinispan.commands.remote.GetKeysInGroupCommand; import org.infinispan.commands.remote.SingleRpcCommand; import org.infinispan.commands.remote.recovery.CompleteTransactionCommand; import org.infinispan.commands.remote.recovery.GetInDoubtTransactionsCommand; import org.infinispan.commands.remote.recovery.GetInDoubtTxInfoCommand; import org.infinispan.commands.remote.recovery.TxCompletionNotificationCommand; import org.infinispan.commands.tx.CommitCommand; import org.infinispan.commands.tx.PrepareCommand; import org.infinispan.commands.tx.RollbackCommand; import org.infinispan.commands.tx.VersionedCommitCommand; import org.infinispan.commands.tx.VersionedPrepareCommand; import org.infinispan.commands.write.ApplyDeltaCommand; import org.infinispan.commands.write.BackupAckCommand; import org.infinispan.commands.write.BackupMultiKeyAckCommand; import org.infinispan.commands.write.BackupPutMapRpcCommand; import org.infinispan.commands.write.BackupWriteRpcCommand; import org.infinispan.commands.write.ClearCommand; import org.infinispan.commands.write.DataWriteCommand; import org.infinispan.commands.write.EvictCommand; import org.infinispan.commands.write.ExceptionAckCommand; import org.infinispan.commands.write.InvalidateCommand; 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.commands.write.WriteCommand; import org.infinispan.commons.api.functional.EntryView; import org.infinispan.factories.ComponentRegistry; import org.infinispan.functional.impl.Params; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.metadata.Metadata; import org.infinispan.remoting.transport.Address; import org.infinispan.statetransfer.StateChunk; import org.infinispan.statetransfer.StateRequestCommand; import org.infinispan.statetransfer.StateResponseCommand; import org.infinispan.stream.impl.StreamRequestCommand; import org.infinispan.stream.impl.StreamResponseCommand; import org.infinispan.test.TestingUtil; import org.infinispan.transaction.xa.GlobalTransaction; import org.infinispan.util.concurrent.ReclosableLatch; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.infinispan.xsite.SingleXSiteRpcCommand; import org.infinispan.xsite.XSiteAdminCommand; import org.infinispan.xsite.statetransfer.XSiteState; import org.infinispan.xsite.statetransfer.XSiteStatePushCommand; import org.infinispan.xsite.statetransfer.XSiteStateTransferControlCommand; /** * @author Mircea Markus * @since 5.2 */ public class ControlledCommandFactory implements CommandsFactory { private static Log log = LogFactory.getLog(ControlledCommandFactory.class); public final CommandsFactory actual; public final ReclosableLatch gate = new ReclosableLatch(true); public final AtomicInteger remoteCommandsReceived = new AtomicInteger(0); public final AtomicInteger blockTypeCommandsReceived = new AtomicInteger(0); public final List<ReplicableCommand> receivedCommands = new ArrayList<>(); public final Class<? extends ReplicableCommand> toBlock; public ControlledCommandFactory(CommandsFactory actual, Class<? extends ReplicableCommand> toBlock) { this.actual = actual; this.toBlock = toBlock; } public int received(Class<? extends ReplicableCommand> command) { int result = 0; for (ReplicableCommand r : receivedCommands) { if (r.getClass() == command) { result++; } } return result; } @Override public void initializeReplicableCommand(ReplicableCommand command, boolean isRemote) { log.tracef("Received command %s", command); receivedCommands.add(command); if (isRemote) { remoteCommandsReceived.incrementAndGet(); if (toBlock != null && command.getClass().isAssignableFrom(toBlock)) { blockTypeCommandsReceived.incrementAndGet(); try { gate.await(30, TimeUnit.SECONDS); log.tracef("gate is opened, processing the lock cleanup: %s", command); } catch (InterruptedException e) { throw new RuntimeException(e); } } } actual.initializeReplicableCommand(command, isRemote); } public static ControlledCommandFactory registerControlledCommandFactory(Cache cache, Class<? extends ReplicableCommand> toBlock) { ComponentRegistry componentRegistry = cache.getAdvancedCache().getComponentRegistry(); final ControlledCommandFactory ccf = new ControlledCommandFactory(componentRegistry.getCommandsFactory(), toBlock); TestingUtil.replaceField(ccf, "commandsFactory", componentRegistry, ComponentRegistry.class); componentRegistry.registerComponent(ccf, CommandsFactory.class); //hack: re-add the component registry to the GlobalComponentRegistry's "namedComponents" (CHM) in order to correctly publish it for // when it will be read by the InboundInvocationHandlder. InboundInvocationHandlder reads the value from the GlobalComponentRegistry.namedComponents before using it componentRegistry.getGlobalComponentRegistry().registerNamedComponentRegistry(componentRegistry, EmbeddedCacheManager.DEFAULT_CACHE_NAME); return ccf; } @Override public PutKeyValueCommand buildPutKeyValueCommand(Object key, Object value, Metadata metadata, long flagsBitSet) { return actual.buildPutKeyValueCommand(key, value, metadata, flagsBitSet); } @Override public RemoveCommand buildRemoveCommand(Object key, Object value, long flagsBitSet) { return actual.buildRemoveCommand(key, value, flagsBitSet); } @Override public InvalidateCommand buildInvalidateCommand(long flagsBitSet, Object... keys) { return actual.buildInvalidateCommand(flagsBitSet, keys); } @Override public InvalidateCommand buildInvalidateFromL1Command(long flagsBitSet, Collection<Object> keys) { return actual.buildInvalidateFromL1Command(flagsBitSet, keys); } @Override public InvalidateCommand buildInvalidateFromL1Command(Address origin, long flagsBitSet, Collection<Object> keys) { return actual.buildInvalidateFromL1Command(origin, flagsBitSet, keys); } @Override public RemoveExpiredCommand buildRemoveExpiredCommand(Object key, Object value, Long lifespan) { return actual.buildRemoveExpiredCommand(key, value, lifespan); } @Override public ReplaceCommand buildReplaceCommand(Object key, Object oldValue, Object newValue, Metadata metadata, long flagsBitSet) { return actual.buildReplaceCommand(key, oldValue, newValue, metadata, flagsBitSet); } @Override public SizeCommand buildSizeCommand(long flagsBitSet) { return actual.buildSizeCommand(flagsBitSet); } @Override public GetKeyValueCommand buildGetKeyValueCommand(Object key, long flagsBitSet) { return actual.buildGetKeyValueCommand(key, flagsBitSet); } @Override public GetAllCommand buildGetAllCommand(Collection<?> keys, long flagsBitSet, boolean returnEntries) { return actual.buildGetAllCommand(keys, flagsBitSet, returnEntries); } @Override public KeySetCommand buildKeySetCommand(long flagsBitSet) { return actual.buildKeySetCommand(flagsBitSet); } @Override public EntrySetCommand buildEntrySetCommand(long flagsBitSet) { return actual.buildEntrySetCommand(flagsBitSet); } @Override public PutMapCommand buildPutMapCommand(Map<?, ?> map, Metadata metadata, long flagsBitSet) { return actual.buildPutMapCommand(map, metadata, flagsBitSet); } @Override public ClearCommand buildClearCommand(long flagsBitSet) { return actual.buildClearCommand(flagsBitSet); } @Override public EvictCommand buildEvictCommand(Object key, long flagsBitSet) { return actual.buildEvictCommand(key, flagsBitSet); } @Override public PrepareCommand buildPrepareCommand(GlobalTransaction gtx, List<WriteCommand> modifications, boolean onePhaseCommit) { return actual.buildPrepareCommand(gtx, modifications, onePhaseCommit); } @Override public VersionedPrepareCommand buildVersionedPrepareCommand(GlobalTransaction gtx, List<WriteCommand> modifications, boolean onePhase) { return actual.buildVersionedPrepareCommand(gtx, modifications, onePhase); } @Override public CommitCommand buildCommitCommand(GlobalTransaction gtx) { return actual.buildCommitCommand(gtx); } @Override public VersionedCommitCommand buildVersionedCommitCommand(GlobalTransaction gtx) { return actual.buildVersionedCommitCommand(gtx); } @Override public RollbackCommand buildRollbackCommand(GlobalTransaction gtx) { return actual.buildRollbackCommand(gtx); } @Override public SingleRpcCommand buildSingleRpcCommand(ReplicableCommand call) { return actual.buildSingleRpcCommand(call); } @Override public ClusteredGetCommand buildClusteredGetCommand(Object key, long flagsBitSet) { return actual.buildClusteredGetCommand(key, flagsBitSet); } @Override public ClusteredGetAllCommand buildClusteredGetAllCommand(List<?> keys, long flagsBitSet, GlobalTransaction gtx) { return actual.buildClusteredGetAllCommand(keys, flagsBitSet, gtx); } @Override public LockControlCommand buildLockControlCommand(Collection<?> keys, long flagsBitSet, GlobalTransaction gtx) { return actual.buildLockControlCommand(keys, flagsBitSet, gtx); } @Override public LockControlCommand buildLockControlCommand(Object key, long flagsBitSet, GlobalTransaction gtx) { return actual.buildLockControlCommand(key, flagsBitSet, gtx); } @Override public LockControlCommand buildLockControlCommand(Collection<?> keys, long flagsBitSet) { return actual.buildLockControlCommand(keys, flagsBitSet); } @Override public StateRequestCommand buildStateRequestCommand(StateRequestCommand.Type subtype, Address sender, int viewId, Set<Integer> segments) { return actual.buildStateRequestCommand(subtype, sender, viewId, segments); } @Override public StateResponseCommand buildStateResponseCommand(Address sender, int topologyId, Collection<StateChunk> stateChunks) { return actual.buildStateResponseCommand(sender, topologyId, stateChunks); } @Override public String getCacheName() { return actual.getCacheName(); } @Override public GetInDoubtTransactionsCommand buildGetInDoubtTransactionsCommand() { return actual.buildGetInDoubtTransactionsCommand(); } @Override public TxCompletionNotificationCommand buildTxCompletionNotificationCommand(Xid xid, GlobalTransaction globalTransaction) { return actual.buildTxCompletionNotificationCommand(xid, globalTransaction); } @Override public <T> DistributedExecuteCommand<T> buildDistributedExecuteCommand(Callable<T> callable, Address sender, Collection keys) { return actual.buildDistributedExecuteCommand(callable, sender, keys); } @Override public GetInDoubtTxInfoCommand buildGetInDoubtTxInfoCommand() { return actual.buildGetInDoubtTxInfoCommand(); } @Override public CompleteTransactionCommand buildCompleteTransactionCommand(Xid xid, boolean commit) { return actual.buildCompleteTransactionCommand(xid, commit); } @Override public TxCompletionNotificationCommand buildTxCompletionNotificationCommand(long internalId) { return actual.buildTxCompletionNotificationCommand(internalId); } @Override public ApplyDeltaCommand buildApplyDeltaCommand(Object deltaAwareValueKey, Delta delta, Collection keys) { return actual.buildApplyDeltaCommand(deltaAwareValueKey, delta, keys); } @Override public CreateCacheCommand buildCreateCacheCommand(String cacheName, String cacheConfigurationName) { return actual.buildCreateCacheCommand(cacheName, cacheConfigurationName); } @Override public CancelCommand buildCancelCommandCommand(UUID commandUUID) { return actual.buildCancelCommandCommand(commandUUID); } @Override public CreateCacheCommand buildCreateCacheCommand(String tmpCacheName, String defaultTmpCacheConfigurationName, int size) { return actual.buildCreateCacheCommand(tmpCacheName, defaultTmpCacheConfigurationName, size); } @Override public XSiteStateTransferControlCommand buildXSiteStateTransferControlCommand(StateTransferControl control, String siteName) { return actual.buildXSiteStateTransferControlCommand(control, siteName); } @Override public XSiteAdminCommand buildXSiteAdminCommand(String siteName, AdminOperation op, Integer afterFailures, Long minTimeToWait) { return actual.buildXSiteAdminCommand(siteName, op, afterFailures, minTimeToWait); } @Override public XSiteStatePushCommand buildXSiteStatePushCommand(XSiteState[] chunk, long timeoutMillis) { return actual.buildXSiteStatePushCommand(chunk, timeoutMillis); } @Override public SingleXSiteRpcCommand buildSingleXSiteRpcCommand(VisitableCommand command) { return actual.buildSingleXSiteRpcCommand(command); } @Override public GetKeysInGroupCommand buildGetKeysInGroupCommand(long flagsBitSet, String groupName) { return actual.buildGetKeysInGroupCommand(flagsBitSet, groupName); } @Override public <K> StreamRequestCommand<K> buildStreamRequestCommand(Object id, boolean parallelStream, StreamRequestCommand.Type type, Set<Integer> segments, Set<K> keys, Set<K> excludedKeys, boolean includeLoader, Object terminalOperation) { return actual.buildStreamRequestCommand(id, parallelStream, type, segments, keys, excludedKeys, includeLoader, terminalOperation); } @Override public <R> StreamResponseCommand<R> buildStreamResponseCommand(Object identifier, boolean complete, Set<Integer> lostSegments, R response) { return actual.buildStreamResponseCommand(identifier, complete, lostSegments, response); } @Override public GetCacheEntryCommand buildGetCacheEntryCommand(Object key, long flagsBitSet) { return actual.buildGetCacheEntryCommand(key, flagsBitSet); } @Override public <K, V, R> ReadOnlyKeyCommand<K, V, R> buildReadOnlyKeyCommand(K key, Function<EntryView.ReadEntryView<K, V>, R> f) { return actual.buildReadOnlyKeyCommand(key, f); } @Override public <K, V, R> ReadOnlyManyCommand<K, V, R> buildReadOnlyManyCommand(Collection<? extends K> keys, Function<EntryView.ReadEntryView<K, V>, R> f) { return actual.buildReadOnlyManyCommand(keys, f); } @Override public <K, V> WriteOnlyKeyCommand<K, V> buildWriteOnlyKeyCommand(K key, Consumer<EntryView.WriteEntryView<V>> f, Params params) { return actual.buildWriteOnlyKeyCommand(key, f, params); } @Override public <K, V, R> ReadWriteKeyValueCommand<K, V, R> buildReadWriteKeyValueCommand(K key, V value, BiFunction<V, EntryView.ReadWriteEntryView<K, V>, R> f, Params params) { return actual.buildReadWriteKeyValueCommand(key, value, f, params); } @Override public <K, V, R> ReadWriteKeyCommand<K, V, R> buildReadWriteKeyCommand(K key, Function<EntryView.ReadWriteEntryView<K, V>, R> f, Params params) { return actual.buildReadWriteKeyCommand(key, f, params); } @Override public <K, V> WriteOnlyManyEntriesCommand<K, V> buildWriteOnlyManyEntriesCommand( Map<? extends K, ? extends V> entries, BiConsumer<V, EntryView.WriteEntryView<V>> f, Params params) { return actual.buildWriteOnlyManyEntriesCommand(entries, f, params); } @Override public <K, V> WriteOnlyKeyValueCommand<K, V> buildWriteOnlyKeyValueCommand(K key, V value, BiConsumer<V, EntryView.WriteEntryView<V>> f, Params params) { return actual.buildWriteOnlyKeyValueCommand(key, value, f, params); } @Override public <K, V> WriteOnlyManyCommand<K, V> buildWriteOnlyManyCommand(Collection<? extends K> keys, Consumer<EntryView.WriteEntryView<V>> f, Params params) { return actual.buildWriteOnlyManyCommand(keys, f, params); } @Override public <K, V, R> ReadWriteManyCommand<K, V, R> buildReadWriteManyCommand(Collection<? extends K> keys, Function<EntryView.ReadWriteEntryView<K, V>, R> f, Params params) { return actual.buildReadWriteManyCommand(keys, f, params); } @Override public <K, V, R> ReadWriteManyEntriesCommand<K, V, R> buildReadWriteManyEntriesCommand(Map<? extends K, ? extends V> entries, BiFunction<V, EntryView.ReadWriteEntryView<K, V>, R> f, Params params) { return actual.buildReadWriteManyEntriesCommand(entries, f, params); } @Override public BackupAckCommand buildBackupAckCommand(long id, int topologyId) { return actual.buildBackupAckCommand(id, topologyId); } @Override public BackupMultiKeyAckCommand buildBackupMultiKeyAckCommand(long id, int segment, int topologyId) { return actual.buildBackupMultiKeyAckCommand(id, segment, topologyId); } @Override public ExceptionAckCommand buildExceptionAckCommand(long id, Throwable throwable, int topologyId) { return actual.buildExceptionAckCommand(id, throwable, topologyId); } @Override public BackupWriteRpcCommand buildBackupWriteRpcCommand(DataWriteCommand command) { return actual.buildBackupWriteRpcCommand(command); } @Override public BackupPutMapRpcCommand buildBackupPutMapRpcCommand(PutMapCommand command) { return actual.buildBackupPutMapRpcCommand(command); } }