blob: 62f4f40cb9674e882c35f29ff29e670bf72872d8 [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.cassandra.distributed.shared;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.cassandra.distributed.api.IMessage;
import org.apache.cassandra.distributed.api.IMessageFilters;
public class MessageFilters implements IMessageFilters
{
private final List<Filter> inboundFilters = new CopyOnWriteArrayList<>();
private final List<Filter> outboundFilters = new CopyOnWriteArrayList<>();
public boolean permitInbound(int from, int to, IMessage msg)
{
return permit(inboundFilters, from, to, msg);
}
public boolean permitOutbound(int from, int to, IMessage msg)
{
return permit(outboundFilters, from, to, msg);
}
private static boolean permit(List<Filter> filters, int from, int to, IMessage msg)
{
for (Filter filter : filters)
{
if (filter.matches(from, to, msg))
return false;
}
return true;
}
public static class Filter implements IMessageFilters.Filter
{
final int[] from;
final int[] to;
final int[] verbs;
final Matcher matcher;
final List<Filter> parent;
Filter(int[] from, int[] to, int[] verbs, Matcher matcher, List<Filter> parent)
{
if (from != null)
{
from = from.clone();
Arrays.sort(from);
}
if (to != null)
{
to = to.clone();
Arrays.sort(to);
}
if (verbs != null)
{
verbs = verbs.clone();
Arrays.sort(verbs);
}
this.from = from;
this.to = to;
this.verbs = verbs;
this.matcher = matcher;
this.parent = Objects.requireNonNull(parent, "parent");
}
public int hashCode()
{
return (from == null ? 0 : Arrays.hashCode(from))
+ (to == null ? 0 : Arrays.hashCode(to))
+ (verbs == null ? 0 : Arrays.hashCode(verbs)
+ parent.hashCode());
}
public boolean equals(Object that)
{
return that instanceof Filter && equals((Filter) that);
}
public boolean equals(Filter that)
{
return Arrays.equals(from, that.from)
&& Arrays.equals(to, that.to)
&& Arrays.equals(verbs, that.verbs)
&& parent.equals(that.parent);
}
public Filter off()
{
parent.remove(this);
return this;
}
public Filter on()
{
parent.add(this);
return this;
}
public boolean matches(int from, int to, IMessage msg)
{
return (this.from == null || Arrays.binarySearch(this.from, from) >= 0)
&& (this.to == null || Arrays.binarySearch(this.to, to) >= 0)
&& (this.verbs == null || Arrays.binarySearch(this.verbs, msg.verb()) >= 0)
&& (this.matcher == null || this.matcher.matches(from, to, msg));
}
}
public class Builder implements IMessageFilters.Builder
{
int[] from;
int[] to;
int[] verbs;
Matcher matcher;
boolean inbound;
private Builder(boolean inbound)
{
this.inbound = inbound;
}
public Builder from(int... nums)
{
from = nums;
return this;
}
public Builder to(int... nums)
{
to = nums;
return this;
}
public IMessageFilters.Builder verbs(int... verbs)
{
this.verbs = verbs;
return this;
}
public IMessageFilters.Builder allVerbs()
{
this.verbs = null;
return this;
}
public IMessageFilters.Builder inbound(boolean inbound)
{
this.inbound = inbound;
return this;
}
public IMessageFilters.Builder messagesMatching(Matcher matcher)
{
this.matcher = matcher;
return this;
}
public IMessageFilters.Filter drop()
{
return new Filter(from, to, verbs, matcher, inbound ? inboundFilters : outboundFilters).on();
}
}
public IMessageFilters.Builder inbound(boolean inbound)
{
return new Builder(inbound);
}
@Override
public void reset()
{
inboundFilters.clear();
outboundFilters.clear();
}
}