package org.infinispan.commands.remote; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.infinispan.commands.AbstractTopologyAffectedCommand; import org.infinispan.commands.VisitableCommand; import org.infinispan.commands.Visitor; import org.infinispan.container.entries.CacheEntry; import org.infinispan.context.InvocationContext; import org.infinispan.context.impl.FlagBitSets; import org.infinispan.distribution.group.impl.GroupFilter; import org.infinispan.distribution.group.impl.GroupManager; /** * {@link org.infinispan.commands.VisitableCommand} that fetches the keys belonging to a group. * * @author Pedro Ruivo * @since 7.0 */ public class GetKeysInGroupCommand extends AbstractTopologyAffectedCommand implements VisitableCommand { public static final byte COMMAND_ID = 43; private String groupName; /* local state to avoid checking everywhere if the node in which this command is executed is the group owner. */ private transient boolean isGroupOwner; private transient GroupManager groupManager; public GetKeysInGroupCommand(long flagsBitSet, String groupName) { this.groupName = groupName; setFlagsBitSet(flagsBitSet); } public GetKeysInGroupCommand() { } public GetKeysInGroupCommand setGroupManager(GroupManager groupManager) { this.groupManager = groupManager; return this; } @Override public Object perform(InvocationContext ctx) throws Throwable { final KeyValueCollector collector = ctx.isOriginLocal() ? new LocalContextKeyValueCollector() : new RemoteContextKeyValueCollector(); final GroupFilter<Object> filter = new GroupFilter<>(getGroupName(), groupManager); for (CacheEntry entry : ctx.getLookedUpEntries().values()) { if (!entry.isRemoved() && filter.accept(entry.getKey())) { collector.addCacheEntry(entry); } } return collector.getResult(); } @Override public byte getCommandId() { return COMMAND_ID; } @Override public void writeTo(ObjectOutput output) throws IOException { output.writeUTF(groupName); output.writeLong(FlagBitSets.copyWithoutRemotableFlags(getFlagsBitSet())); } @Override public void readFrom(ObjectInput input) throws IOException, ClassNotFoundException { groupName = input.readUTF(); setFlagsBitSet(input.readLong()); } @Override public boolean isReturnValueExpected() { return true; } @Override public boolean canBlock() { return false; } @Override public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable { return visitor.visitGetKeysInGroupCommand(ctx, this); } @Override public LoadType loadType() { return LoadType.OWNER; } public String getGroupName() { return groupName; } @Override public String toString() { return "GetKeysInGroupCommand{" + "groupName='" + groupName + '\'' + ", flags=" + printFlags() + '}'; } public boolean isGroupOwner() { return isGroupOwner; } public void setGroupOwner(boolean isGroupOwner) { this.isGroupOwner = isGroupOwner; } private interface KeyValueCollector { void addCacheEntry(CacheEntry entry); Object getResult(); } private static class LocalContextKeyValueCollector implements KeyValueCollector { private final Map<Object, Object> map; private LocalContextKeyValueCollector() { map = new HashMap<>(); } @Override public void addCacheEntry(CacheEntry entry) { map.put(entry.getKey(), entry.getValue()); } @Override public Object getResult() { return map; } } private static class RemoteContextKeyValueCollector implements KeyValueCollector { private final List<CacheEntry> list; private RemoteContextKeyValueCollector() { list = new LinkedList<>(); } @Override public void addCacheEntry(CacheEntry entry) { list.add(entry); } @Override public Object getResult() { return list; } } }