blob: e5bb47d3165c06328720ea227d92b2b7849fa73a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.cluster;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteCompute;
import org.apache.ignite.IgniteEvents;
import org.apache.ignite.IgniteMessaging;
import org.apache.ignite.IgniteServices;
import org.apache.ignite.cluster.ClusterGroup;
import org.apache.ignite.cluster.ClusterMetrics;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.ClusterMetricsSnapshot;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.IgniteComputeImpl;
import org.apache.ignite.internal.IgniteEventsImpl;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.IgniteMessagingImpl;
import org.apache.ignite.internal.IgniteNodeAttributes;
import org.apache.ignite.internal.IgniteServicesImpl;
import org.apache.ignite.internal.IgnitionEx;
import org.apache.ignite.internal.executor.GridExecutorService;
import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
import org.apache.ignite.internal.processors.igfs.IgfsNodePredicate;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.resources.IgniteInstanceResource;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS;
/**
*
*/
public class ClusterGroupAdapter implements ClusterGroupEx, Externalizable {
/** */
private static final long serialVersionUID = 0L;
/** Kernal context. */
protected transient GridKernalContext ctx;
/** Compute. */
private transient IgniteComputeImpl compute;
/** Messaging. */
private transient IgniteMessagingImpl messaging;
/** Events. */
private transient IgniteEvents evts;
/** Services. */
private transient IgniteServices svcs;
/** Ignite instance name. */
private String igniteInstanceName;
/** Subject ID. */
protected UUID subjId;
/** Cluster group predicate. */
protected IgnitePredicate<ClusterNode> p;
/** Node IDs. */
private Set<UUID> ids;
/**
* Required by {@link Externalizable}.
*/
public ClusterGroupAdapter() {
// No-op.
}
/**
* @param subjId Subject ID.
* @param ctx Kernal context.
* @param p Predicate.
*/
protected ClusterGroupAdapter(@Nullable GridKernalContext ctx,
@Nullable UUID subjId,
@Nullable IgnitePredicate<ClusterNode> p) {
if (ctx != null)
setKernalContext(ctx);
this.subjId = subjId;
this.p = p;
ids = null;
}
/**
* @param ctx Kernal context.
* @param subjId Subject ID.
* @param ids Node IDs.
*/
protected ClusterGroupAdapter(@Nullable GridKernalContext ctx,
@Nullable UUID subjId,
Set<UUID> ids) {
if (ctx != null)
setKernalContext(ctx);
assert ids != null;
this.subjId = subjId;
this.ids = ids;
p = F.nodeForNodeIds(ids);
}
/**
* @param subjId Subject ID.
* @param ctx Grid kernal context.
* @param p Predicate.
* @param ids Node IDs.
*/
private ClusterGroupAdapter(@Nullable GridKernalContext ctx,
@Nullable UUID subjId,
@Nullable IgnitePredicate<ClusterNode> p,
Set<UUID> ids) {
if (ctx != null)
setKernalContext(ctx);
this.subjId = subjId;
this.p = p;
this.ids = ids;
if (p == null && ids != null)
this.p = F.nodeForNodeIds(ids);
}
/**
* <tt>ctx.gateway().readLock()</tt>
*/
protected void guard() {
assert ctx != null;
ctx.gateway().readLock();
}
/**
* <tt>ctx.gateway().readUnlock()</tt>
*/
protected void unguard() {
assert ctx != null;
ctx.gateway().readUnlock();
}
/**
* Sets kernal context.
*
* @param ctx Kernal context to set.
*/
public void setKernalContext(GridKernalContext ctx) {
assert ctx != null;
assert this.ctx == null;
this.ctx = ctx;
igniteInstanceName = ctx.igniteInstanceName();
}
/** {@inheritDoc} */
@Override public final Ignite ignite() {
assert ctx != null;
guard();
try {
return ctx.grid();
}
finally {
unguard();
}
}
/**
* @return {@link IgniteCompute} for this cluster group.
*/
public final IgniteCompute compute() {
if (compute == null) {
assert ctx != null;
compute = new IgniteComputeImpl(ctx, this, subjId);
}
return compute;
}
/**
* @return {@link IgniteMessaging} for this cluster group.
*/
public final IgniteMessaging message() {
if (messaging == null) {
assert ctx != null;
messaging = new IgniteMessagingImpl(ctx, this, false);
}
return messaging;
}
/**
* @return {@link IgniteEvents} for this cluster group.
*/
public final IgniteEvents events() {
if (evts == null) {
assert ctx != null;
evts = new IgniteEventsImpl(ctx, this, false);
}
return evts;
}
/**
* @return {@link IgniteServices} for this cluster group.
*/
public IgniteServices services() {
if (svcs == null) {
assert ctx != null;
svcs = new IgniteServicesImpl(ctx, this, false);
}
return svcs;
}
/**
* @return {@link ExecutorService} for this cluster group.
*/
public ExecutorService executorService() {
assert ctx != null;
return new GridExecutorService(this, ctx);
}
/** {@inheritDoc} */
@Override public final ClusterMetrics metrics() {
guard();
try {
if (nodes().isEmpty())
throw U.convertException(U.emptyTopologyException());
return new ClusterMetricsSnapshot(this);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public Collection<ClusterNode> nodes() {
guard();
try {
if (ids != null) {
if (ids.isEmpty())
return Collections.emptyList();
else if (ids.size() == 1) {
ClusterNode node = ctx.discovery().node(F.first(ids));
return node != null ? Collections.singleton(node) : Collections.<ClusterNode>emptyList();
}
else {
Collection<ClusterNode> nodes = new ArrayList<>(ids.size());
for (UUID id : ids) {
ClusterNode node = ctx.discovery().node(id);
if (node != null)
nodes.add(node);
}
return nodes;
}
}
else {
Collection<ClusterNode> all;
if (p instanceof DaemonFilter)
all = F.concat(false, ctx.discovery().daemonNodes(), ctx.discovery().allNodes());
else
all = ctx.discovery().allNodes();
return p != null ? F.view(all, p) : all;
}
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public Collection<String> hostNames() {
Set<String> res = new HashSet<>();
for (ClusterNode node : nodes())
res.addAll(node.hostNames());
return Collections.unmodifiableSet(res);
}
/** {@inheritDoc} */
@Override public final ClusterNode node(UUID id) {
A.notNull(id, "id");
guard();
try {
if (ids != null)
return ids.contains(id) ? ctx.discovery().node(id) : null;
else {
ClusterNode node = ctx.discovery().node(id);
return node != null && (p == null || p.apply(node)) ? node : null;
}
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public ClusterNode node() {
return F.first(nodes());
}
/** {@inheritDoc} */
@Override public IgnitePredicate<ClusterNode> predicate() {
return p != null ? p : F.<ClusterNode>alwaysTrue();
}
/** {@inheritDoc} */
@Override public ClusterGroup forPredicate(IgnitePredicate<ClusterNode> p) {
A.notNull(p, "p");
guard();
try {
if (p != null)
ctx.resource().injectGeneric(p);
return new ClusterGroupAdapter(ctx, subjId, this.p != null ? F.and(p, this.p) : p);
}
catch (IgniteCheckedException e) {
throw U.convertException(e);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public final ClusterGroup forAttribute(String name, @Nullable final Object val) {
A.notNull(name, "n");
return forPredicate(new AttributeFilter(name, val));
}
/** {@inheritDoc} */
@Override public ClusterGroup forServers() {
return forPredicate(new AttributeFilter(IgniteNodeAttributes.ATTR_CLIENT_MODE, false));
}
/** {@inheritDoc} */
@Override public ClusterGroup forClients() {
return forPredicate(new AttributeFilter(IgniteNodeAttributes.ATTR_CLIENT_MODE, true));
}
/** {@inheritDoc} */
@Override public final ClusterGroup forNode(ClusterNode node, ClusterNode... nodes) {
A.notNull(node, "node");
guard();
try {
Set<UUID> nodeIds;
if (F.isEmpty(nodes))
nodeIds = contains(node) ? Collections.singleton(node.id()) : Collections.<UUID>emptySet();
else {
nodeIds = U.newHashSet(nodes.length + 1);
for (ClusterNode n : nodes)
if (contains(n))
nodeIds.add(n.id());
if (contains(node))
nodeIds.add(node.id());
}
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public final ClusterGroup forNodes(Collection<? extends ClusterNode> nodes) {
A.notEmpty(nodes, "nodes");
guard();
try {
Set<UUID> nodeIds = U.newHashSet(nodes.size());
for (ClusterNode n : nodes)
if (contains(n))
nodeIds.add(n.id());
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public final ClusterGroup forNodeId(UUID id, UUID... ids) {
A.notNull(id, "id");
guard();
try {
Set<UUID> nodeIds;
if (F.isEmpty(ids))
nodeIds = contains(id) ? Collections.singleton(id) : Collections.<UUID>emptySet();
else {
nodeIds = U.newHashSet(ids.length + 1);
for (UUID id0 : ids) {
if (contains(id))
nodeIds.add(id0);
}
if (contains(id))
nodeIds.add(id);
}
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public final ClusterGroup forNodeIds(Collection<UUID> ids) {
A.notEmpty(ids, "ids");
guard();
try {
Set<UUID> nodeIds = U.newHashSet(ids.size());
for (UUID id : ids) {
if (contains(id))
nodeIds.add(id);
}
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public final ClusterGroup forOthers(ClusterNode node, ClusterNode... nodes) {
A.notNull(node, "node");
return forOthers(F.concat(false, node.id(), F.nodeIds(Arrays.asList(nodes))));
}
/** {@inheritDoc} */
@Override public ClusterGroup forOthers(ClusterGroup grp) {
A.notNull(grp, "grp");
if (ids != null) {
guard();
try {
Set<UUID> nodeIds = U.newHashSet(ids.size());
for (UUID id : ids) {
ClusterNode n = node(id);
if (n != null && !grp.predicate().apply(n))
nodeIds.add(id);
}
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
else
return forPredicate(F.not(grp.predicate()));
}
/** {@inheritDoc} */
@Override public final ClusterGroup forRemotes() {
return forOthers(Collections.singleton(ctx.localNodeId()));
}
/**
* @param excludeIds Node IDs.
* @return New cluster group.
*/
private ClusterGroup forOthers(Collection<UUID> excludeIds) {
assert excludeIds != null;
if (ids != null) {
guard();
try {
Set<UUID> nodeIds = U.newHashSet(ids.size());
for (UUID id : ids) {
if (!excludeIds.contains(id))
nodeIds.add(id);
}
return new ClusterGroupAdapter(ctx, subjId, nodeIds);
}
finally {
unguard();
}
}
else
return forPredicate(new OthersFilter(excludeIds));
}
/**
* @throws IllegalStateException In case of daemon node.
*/
private void checkDaemon() throws IllegalStateException {
if (ctx.isDaemon())
throw new IllegalStateException("Not applicable for the daemon node.");
}
/** {@inheritDoc} */
@Override public final ClusterGroup forCacheNodes(String cacheName) {
CU.validateCacheName(cacheName);
checkDaemon();
return forPredicate(new CachesFilter(cacheName, true, true, true));
}
/** {@inheritDoc} */
@Override public final ClusterGroup forDataNodes(String cacheName) {
CU.validateCacheName(cacheName);
checkDaemon();
return forPredicate(new CachesFilter(cacheName, true, false, false));
}
/** {@inheritDoc} */
@Override public final ClusterGroup forClientNodes(String cacheName) {
CU.validateCacheName(cacheName);
checkDaemon();
return forPredicate(new CachesFilter(cacheName, false, true, true));
}
/** {@inheritDoc} */
@Override public ClusterGroup forCacheNodes(String cacheName, boolean affNodes, boolean nearNodes,
boolean clientNodes) {
CU.validateCacheName(cacheName);
checkDaemon();
return forPredicate(new CachesFilter(cacheName, affNodes, nearNodes, clientNodes));
}
/** {@inheritDoc} */
@Override public ClusterGroup forIgfsMetadataDataNodes(String igfsName, String metaCacheName) {
assert metaCacheName != null;
return forPredicate(new IgfsNodePredicate(igfsName)).forDataNodes(metaCacheName);
}
/** {@inheritDoc} */
@Override public final ClusterGroup forHost(ClusterNode node) {
A.notNull(node, "node");
String macs = node.attribute(ATTR_MACS);
assert macs != null;
return forAttribute(ATTR_MACS, macs);
}
/** {@inheritDoc} */
@Override public final ClusterGroup forHost(String host, String... hosts) {
A.notNull(host, "host");
return forPredicate(new HostsFilter(host, hosts));
}
/** {@inheritDoc} */
@Override public final ClusterGroup forDaemons() {
return forPredicate(new DaemonFilter());
}
/** {@inheritDoc} */
@Override public final ClusterGroup forRandom() {
if (!F.isEmpty(ids))
return forNodeId(F.rand(ids));
Collection<ClusterNode> nodes = nodes();
if (nodes.isEmpty())
return new ClusterGroupAdapter(ctx, null, Collections.<UUID>emptySet());
return forNode(F.rand(nodes));
}
/** {@inheritDoc} */
@Override public ClusterGroup forOldest() {
return new AgeClusterGroup(this, true);
}
/** {@inheritDoc} */
@Override public ClusterGroup forYoungest() {
return new AgeClusterGroup(this, false);
}
/** {@inheritDoc} */
@Override public ClusterGroupEx forSubjectId(UUID subjId) {
if (subjId == null)
return this;
guard();
try {
return ids != null ? new ClusterGroupAdapter(ctx, subjId, ids) :
new ClusterGroupAdapter(ctx, subjId, p);
}
finally {
unguard();
}
}
/**
* @param n Node.
* @return Whether node belongs to this cluster group.
*/
private boolean contains(ClusterNode n) {
assert n != null;
return ids != null ? ids.contains(n.id()) : p == null || p.apply(n);
}
/**
* @param id Node ID.
* @return Whether node belongs to this cluster group.
*/
private boolean contains(UUID id) {
assert id != null;
if (ids != null)
return ids.contains(id);
else {
ClusterNode n = ctx.discovery().node(id);
return n != null && (p == null || p.apply(n));
}
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
U.writeString(out, igniteInstanceName);
U.writeUuid(out, subjId);
out.writeBoolean(ids != null);
if (ids != null)
out.writeObject(ids);
else
out.writeObject(p);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
igniteInstanceName = U.readString(in);
subjId = U.readUuid(in);
if (in.readBoolean())
ids = (Set<UUID>)in.readObject();
else
p = (IgnitePredicate<ClusterNode>)in.readObject();
}
/**
* Reconstructs object on unmarshalling.
*
* @return Reconstructed object.
* @throws ObjectStreamException Thrown in case of unmarshalling error.
*/
protected Object readResolve() throws ObjectStreamException {
try {
IgniteKernal g = IgnitionEx.localIgnite();
return ids != null ? new ClusterGroupAdapter(g.context(), subjId, ids) :
new ClusterGroupAdapter(g.context(), subjId, p);
}
catch (IllegalStateException e) {
throw U.withCause(new InvalidObjectException(e.getMessage()), e);
}
}
/**
*/
private static class CachesFilter implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** Cache name. */
private final String cacheName;
/** Affinity nodes. */
private boolean affNodes;
/** Near nodes. */
private boolean nearNodes;
/** Client nodes. */
private boolean clients;
/** Injected Ignite instance. */
@IgniteInstanceResource
private transient Ignite ignite;
/**
* @param cacheName Cache name.
*/
private CachesFilter(String cacheName, boolean affNodes, boolean nearNodes, boolean clients) {
this.cacheName = cacheName;
this.affNodes = affNodes;
this.nearNodes = nearNodes;
this.clients = clients;
}
/** {@inheritDoc} */
@SuppressWarnings("RedundantIfStatement")
@Override public boolean apply(ClusterNode n) {
GridDiscoveryManager disco = ((IgniteKernal)ignite).context().discovery();
if (affNodes && disco.cacheAffinityNode(n, cacheName))
return true;
if (!affNodes && disco.cacheAffinityNode(n, cacheName))
return false;
if (nearNodes && disco.cacheNearNode(n, cacheName))
return true;
if (clients && disco.cacheClientNode(n, cacheName))
return true;
return false;
}
}
/**
*/
private static class AttributeFilter implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** Name. */
private final String name;
/** Value. */
private final Object val;
/**
* @param name Name.
* @param val Value.
*/
private AttributeFilter(String name, Object val) {
this.name = name;
this.val = val;
}
/** {@inheritDoc} */
@Override public boolean apply(ClusterNode n) {
return val == null ? n.attributes().containsKey(name) : val.equals(n.attribute(name));
}
}
/**
*/
private static class HostsFilter implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** Hosts Names. */
private final Collection<String> validHostNames = new HashSet<>();
/**
* @param name First host name.
* @param names Host names
*/
private HostsFilter(String name, String... names) {
validHostNames.add(name);
if (names != null && (names.length > 0))
Collections.addAll(validHostNames, names);
}
/** {@inheritDoc} */
@Override public boolean apply(ClusterNode n) {
for (String hostName : n.hostNames()) {
if (validHostNames.contains(hostName))
return true;
}
return false;
}
}
/**
*/
private static class DaemonFilter implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** {@inheritDoc} */
@Override public boolean apply(ClusterNode n) {
return n.isDaemon();
}
}
/**
*/
private static class OthersFilter implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** */
private final Collection<UUID> nodeIds;
/**
* @param nodeIds Node IDs.
*/
private OthersFilter(Collection<UUID> nodeIds) {
this.nodeIds = nodeIds;
}
/** {@inheritDoc} */
@Override public boolean apply(ClusterNode n) {
return !nodeIds.contains(n.id());
}
}
/**
* Age-based cluster group.
*/
private static class AgeClusterGroup extends ClusterGroupAdapter {
/** Serialization version. */
private static final long serialVersionUID = 0L;
/** Oldest flag. */
private boolean isOldest;
/** State. */
private volatile AgeClusterGroupState state;
/**
* Required for {@link Externalizable}.
*/
public AgeClusterGroup() {
// No-op.
}
/**
* @param parent Parent cluster group.
* @param isOldest Oldest flag.
*/
private AgeClusterGroup(ClusterGroupAdapter parent, boolean isOldest) {
super(parent.ctx, parent.subjId, parent.p, parent.ids);
this.isOldest = isOldest;
reset();
}
/**
* Resets node.
*/
private synchronized void reset() {
guard();
try {
long lastTopVer = ctx.discovery().topologyVersion();
ClusterNode node = isOldest ? U.oldest(super.nodes(), null) : U.youngest(super.nodes(), null);
IgnitePredicate<ClusterNode> p = F.nodeForNodes(node);
state = new AgeClusterGroupState(node, p, lastTopVer);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public ClusterNode node() {
if (ctx.discovery().topologyVersion() != state.lastTopVer)
reset();
return state.node;
}
/** {@inheritDoc} */
@Override public Collection<ClusterNode> nodes() {
if (ctx.discovery().topologyVersion() != state.lastTopVer)
reset();
ClusterNode node = state.node;
return node == null ? Collections.<ClusterNode>emptyList() : Collections.singletonList(node);
}
/** {@inheritDoc} */
@Override public IgnitePredicate<ClusterNode> predicate() {
if (ctx.discovery().topologyVersion() != state.lastTopVer)
reset();
return state.p;
}
/** {@inheritDoc} */
@Override public ClusterGroup forPredicate(IgnitePredicate<ClusterNode> p) {
A.notNull(p, "p");
guard();
try {
if (p != null)
ctx.resource().injectGeneric(p);
return new ClusterGroupAdapter(ctx, this.subjId, new GroupPredicate(this, p));
}
catch (IgniteCheckedException e) {
throw U.convertException(e);
}
finally {
unguard();
}
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeBoolean(isOldest);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
isOldest = in.readBoolean();
}
/**
* Reconstructs object on unmarshalling.
*
* @return Reconstructed object.
* @throws ObjectStreamException Thrown in case of unmarshalling error.
*/
@Override protected Object readResolve() throws ObjectStreamException {
ClusterGroupAdapter parent = (ClusterGroupAdapter)super.readResolve();
return new AgeClusterGroup(parent, isOldest);
}
}
/**
* Container for age-based cluster group state.
*/
private static class AgeClusterGroupState {
/** Selected node. */
private final ClusterNode node;
/** Node predicate. */
private final IgnitePredicate<ClusterNode> p;
/** Last topology version. */
private final long lastTopVer;
/**
* @param node Node.
* @param p Predicate.
* @param lastTopVer Last topology version.
*/
public AgeClusterGroupState(ClusterNode node, IgnitePredicate<ClusterNode> p, long lastTopVer) {
this.node = node;
this.p = p;
this.lastTopVer = lastTopVer;
}
}
/**
* Dynamic cluster group based predicate.
*/
private static class GroupPredicate implements IgnitePredicate<ClusterNode> {
/** */
private static final long serialVersionUID = 0L;
/** Target cluster group. */
private final ClusterGroup grp;
/** Predicate. */
private final IgnitePredicate<ClusterNode> p;
/**
* @param grp Cluster group.
* @param p Predicate.
*/
public GroupPredicate(ClusterGroup grp, IgnitePredicate<ClusterNode> p) {
this.grp = grp;
this.p = p;
}
/** {@inheritDoc} */
@Override public boolean apply(ClusterNode node) {
A.notNull(node, "node is null");
return grp.predicate().apply(node) && p.apply(node);
}
/** {@inheritDoc} */
@Override public String toString() {
return getClass().getName() +
" [grp='" + grp.getClass().getName() +
"', p='" + p.getClass().getName() + "']";
}
}
}