Index: core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java =================================================================== --- core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java (revision 2387) +++ core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java (revision ) @@ -1,5 +1,6 @@ package org.infinispan.test; +import org.infinispan.AdvancedCache; import org.infinispan.Cache; import org.infinispan.config.Configuration; import org.infinispan.distribution.BaseDistFunctionalTest; @@ -273,4 +274,12 @@ public Address address(int cacheIndex) { return cache(cacheIndex).getAdvancedCache().getRpcManager().getAddress(); } + + public AdvancedCache advancedCache(int i) { + return cache(i).getAdvancedCache(); -} + } + + public AdvancedCache advancedCache(int i, String cacheName) { + return cache(i, cacheName).getAdvancedCache(); + } +} Index: core/src/main/java/org/infinispan/marshall/Ids.java =================================================================== --- core/src/main/java/org/infinispan/marshall/Ids.java (revision 2372) +++ core/src/main/java/org/infinispan/marshall/Ids.java (revision ) @@ -117,4 +117,6 @@ static final byte BYTE_ARRAY_KEY = 57; static final byte TOPOLOGY_ADDRESS = 58; static final byte TOPOLOGY_VIEW = 59; + static final byte GENERIC_VISITABLE_COMMAND = 60; + } Index: core/src/main/java/org/infinispan/commands/CommandsFactory.java =================================================================== --- core/src/main/java/org/infinispan/commands/CommandsFactory.java (revision 2326) +++ core/src/main/java/org/infinispan/commands/CommandsFactory.java (revision ) @@ -53,6 +53,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Properties; /** * A factory to build commands, initializing and injecting dependencies accordingly. Commands built for a specific, @@ -288,4 +289,7 @@ RehashControlCommand buildRehashControlCommand(RehashControlCommand.Type subtype, Address sender, Map state, ConsistentHash oldCH, ConsistentHash newCH, List
leaversHandled); + + public GenericVisitableCommand buildGenericVisitableCommand(boolean shouldInvoke, Properties params); + } Index: core/src/main/java/org/infinispan/marshall/jboss/ConstantObjectTable.java =================================================================== --- core/src/main/java/org/infinispan/marshall/jboss/ConstantObjectTable.java (revision 2328) +++ core/src/main/java/org/infinispan/marshall/jboss/ConstantObjectTable.java (revision ) @@ -27,6 +27,7 @@ import org.infinispan.atomic.ClearOperation; import org.infinispan.atomic.PutOperation; import org.infinispan.atomic.RemoveOperation; +import org.infinispan.commands.GenericVisitableCommand; import org.infinispan.commands.RemoteCommandsFactory; import org.infinispan.commands.control.LockControlCommand; import org.infinispan.commands.control.RehashControlCommand; @@ -149,6 +150,7 @@ MARSHALLABLES.add(RollbackCommand.class.getName()); MARSHALLABLES.add(InvalidateL1Command.class.getName()); MARSHALLABLES.add(LockControlCommand.class.getName()); + MARSHALLABLES.add(GenericVisitableCommand.class.getName()); MARSHALLABLES.add(RehashControlCommand.class.getName()); MARSHALLABLES.add(ImmortalCacheEntry.class.getName()); Index: core/src/main/java/org/infinispan/commands/GenericVisitableCommand.java =================================================================== --- core/src/main/java/org/infinispan/commands/GenericVisitableCommand.java (revision ) +++ core/src/main/java/org/infinispan/commands/GenericVisitableCommand.java (revision ) @@ -0,0 +1,60 @@ +package org.infinispan.commands; + +import org.infinispan.context.InvocationContext; +import org.infinispan.marshall.Ids; +import org.infinispan.marshall.Marshallable; +import org.infinispan.marshall.exts.ReplicableCommandExternalizer; + +import java.util.Map; + +/** + * // TODO: Document this + * + * @author Mircea.Markus@jboss.com + * @since 4.2 + */ +@Marshallable(externalizer = ReplicableCommandExternalizer.class, id = Ids.GENERIC_VISITABLE_COMMAND) +public class GenericVisitableCommand implements VisitableCommand { + public static final byte COMMAND_ID = Ids.GENERIC_VISITABLE_COMMAND; + + public GenericVisitableCommand(boolean shouldInvoke, Map params) { + this.shouldInvoke = shouldInvoke; + this.params = params; + } + + private boolean shouldInvoke; + private Map params; + + public GenericVisitableCommand() { + // TODO: Customise this generated block + } + + public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable { + return visitor.visitGenericCommand(ctx, this); + } + + public boolean shouldInvoke(InvocationContext ctx) { + return shouldInvoke; + } + + public Object perform(InvocationContext ctx) throws Throwable { + return null; + } + + public byte getCommandId() { + return Ids.GENERIC_VISITABLE_COMMAND; + } + + public Map getParams() { + return params; + } + + public Object[] getParameters() { + return new Object[]{shouldInvoke, params}; + } + + public void setParameters(int commandId, Object[] parameters) { + this.shouldInvoke = (Boolean)parameters[0]; + this.params = (Map) parameters[1]; + } +} Index: core/src/main/java/org/infinispan/commands/Visitor.java =================================================================== --- core/src/main/java/org/infinispan/commands/Visitor.java (revision 604) +++ core/src/main/java/org/infinispan/commands/Visitor.java (revision ) @@ -85,4 +85,6 @@ // locking commands Object visitLockControlCommand(TxInvocationContext ctx, LockControlCommand command) throws Throwable; + + Object visitGenericCommand(InvocationContext ctx, GenericVisitableCommand genericVisitableCommand) throws Throwable; } \ No newline at end of file Index: core/src/test/java/org/infinispan/commands/GenericVisitableCommandTest.java =================================================================== --- core/src/test/java/org/infinispan/commands/GenericVisitableCommandTest.java (revision ) +++ core/src/test/java/org/infinispan/commands/GenericVisitableCommandTest.java (revision ) @@ -0,0 +1,42 @@ +package org.infinispan.commands; + +import org.infinispan.config.Configuration; +import org.infinispan.context.InvocationContext; +import org.infinispan.interceptors.base.CommandInterceptor; +import org.infinispan.test.MultipleCacheManagersTest; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.Map; + +/** + * @author Mircea.Markus@jboss.com + * @since 4.2 + */ +@Test(testName = "commands.GenericVisitableCommandTest", groups = "functional") +public class GenericVisitableCommandTest extends MultipleCacheManagersTest { + private FooInterceptor interceptor; + + @Override + protected void createCacheManagers() throws Throwable { + addClusterEnabledCacheManagers(Configuration.CacheMode.REPL_SYNC, 2); + interceptor = new FooInterceptor(); + advancedCache(1).addInterceptor(interceptor, 1); + } + + public void testSuccessfulReplication() { + Map params = Collections.singletonMap("k","v"); + advancedCache(0).getRpcManager().broadcastRpcCommand(new GenericVisitableCommand(true, params), true); + assert interceptor.received.get("k").equals("v"); + } + + public static class FooInterceptor extends CommandInterceptor { + Map received; + + @Override + public Object visitGenericCommand(InvocationContext ctx, GenericVisitableCommand genericVisitableCommand) throws Throwable { + received = genericVisitableCommand.getParams(); + return invokeNextInterceptor(ctx, genericVisitableCommand); + } + } +} Index: core/src/main/java/org/infinispan/commands/RemoteCommandsFactory.java =================================================================== --- core/src/main/java/org/infinispan/commands/RemoteCommandsFactory.java (revision 2327) +++ core/src/main/java/org/infinispan/commands/RemoteCommandsFactory.java (revision ) @@ -111,6 +111,9 @@ case RehashControlCommand.COMMAND_ID: command = new RehashControlCommand(transport); break; + case GenericVisitableCommand.COMMAND_ID: + command = new GenericVisitableCommand(); + break; default: throw new CacheException("Unknown command id " + id + "!"); } Index: core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java =================================================================== --- core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java (revision 2372) +++ core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java (revision ) @@ -69,6 +69,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; /** @@ -341,4 +342,8 @@ ConsistentHash newCH, List
leavers) { return new RehashControlCommand(cacheName, type, sender, state, oldCH, newCH, leavers, this); } + + public GenericVisitableCommand buildGenericVisitableCommand(boolean shouldInvoke, Properties params) { + return new GenericVisitableCommand(shouldInvoke, params); -} + } +} Index: core/src/main/java/org/infinispan/commands/AbstractVisitor.java =================================================================== --- core/src/main/java/org/infinispan/commands/AbstractVisitor.java (revision 604) +++ core/src/main/java/org/infinispan/commands/AbstractVisitor.java (revision ) @@ -117,6 +117,10 @@ return handleDefault(ctx, invalidateCommand); } + public Object visitGenericCommand(InvocationContext ctx, GenericVisitableCommand genericVisitableCommand) throws Throwable { + return handleDefault(ctx, genericVisitableCommand); + } + /** * A default handler for all commands visited. This is called for any visit method called, unless a visit command is * appropriately overridden.