package org.batfish.datamodel;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.batfish.common.util.CommonUtil;
import org.batfish.common.util.ComparableStructure;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaDescription;
@JsonSchemaDescription("Represents a named access-list whose matching criteria is restricted to regexes on community attributes sent with a bgp advertisement")
public class CommunityList extends ComparableStructure<String> {
private static final String LINES_VAR = "lines";
/**
*
*/
private static final long serialVersionUID = 1L;
private transient Set<Long> _deniedCache;
private boolean _invertMatch;
/**
* The list of lines that are checked in order against the community
* attribute(s) of a bgp advertisement
*/
private final List<CommunityListLine> _lines;
private transient Set<Long> _permittedCache;
/**
* Constructs a CommunityList with the given name for {@link #_name}, and
* lines for {@link #_lines}
*
* @param name
* @param lines
*/
@JsonCreator
public CommunityList(@JsonProperty(NAME_VAR) String name,
@JsonProperty(LINES_VAR) List<CommunityListLine> lines) {
super(name);
_lines = lines;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
CommunityList other = (CommunityList) obj;
return other._lines.equals(_lines);
}
@JsonPropertyDescription("Specifies whether or not lines should match the complement of their criteria (does not change whether a line permits or denies).")
public boolean getInvertMatch() {
return _invertMatch;
}
@JsonProperty(LINES_VAR)
@JsonPropertyDescription("The list of lines that are checked in order against the community attribute(s) of a bgp advertisement")
public List<CommunityListLine> getLines() {
return _lines;
}
private boolean newPermits(long community) {
boolean accept = false;
boolean match = false;
Boolean matchingLineAccepts = null;
for (CommunityListLine line : _lines) {
Pattern p = Pattern.compile(line.getRegex());
String communityStr = CommonUtil.longToCommunity(community);
Matcher matcher = p.matcher(communityStr);
if (matcher.find()) {
match = true;
matchingLineAccepts = line.getAction() == LineAction.ACCEPT;
break;
}
}
if (match) {
if (_invertMatch) {
accept = false;
}
else {
accept = matchingLineAccepts;
}
}
if (accept) {
_permittedCache.add(community);
}
else {
_deniedCache.add(community);
}
return accept;
}
public boolean permits(long community) {
// if (_permittedCache.contains(community)) {
// return true;
// }
// else if (_deniedCache.contains(community)) {
// return false;
// }
return newPermits(community);
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
_deniedCache = Collections.newSetFromMap(new ConcurrentHashMap<>());
_permittedCache = Collections.newSetFromMap(new ConcurrentHashMap<>());
}
public void setInvertMatch(boolean invertMatch) {
_invertMatch = invertMatch;
}
}