package org.batfish.question.assertion;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.batfish.common.Answerer;
import org.batfish.common.BatfishException;
import org.batfish.common.plugin.IBatfish;
import org.batfish.common.util.BatfishObjectMapper;
import org.batfish.datamodel.answers.AnswerElement;
import org.batfish.datamodel.assertion.AssertionAst;
import org.batfish.datamodel.questions.Question;
import org.batfish.question.QuestionPlugin;
import org.batfish.question.NodesQuestionPlugin.NodesAnswerer;
import org.batfish.question.NodesQuestionPlugin.NodesQuestion;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Configuration.ConfigurationBuilder;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
public class AssertQuestionPlugin extends QuestionPlugin {
public static class AssertAnswerElement implements AnswerElement {
private Boolean _fail;
private SortedMap<Integer, Assertion> _failing;
private SortedMap<Integer, Assertion> _passing;
public AssertAnswerElement() {
_failing = new TreeMap<>();
_passing = new TreeMap<>();
}
public Boolean getFail() {
return _fail;
}
public SortedMap<Integer, Assertion> getFailing() {
return _failing;
}
public SortedMap<Integer, Assertion> getPassing() {
return _passing;
}
public void setFail(Boolean fail) {
_fail = fail;
}
public void setFailing(SortedMap<Integer, Assertion> failing) {
_failing = failing;
}
public void setPassing(SortedMap<Integer, Assertion> passing) {
_passing = passing;
}
}
public static class AssertAnswerer extends Answerer {
public AssertAnswerer(Question question, IBatfish batfish) {
super(question, batfish);
}
@Override
public AnswerElement answer() {
ConfigurationBuilder b = new ConfigurationBuilder();
b.jsonProvider(new JacksonJsonNodeJsonProvider());
b.options(Option.ALWAYS_RETURN_LIST);
Configuration c = b.build();
AssertQuestion question = (AssertQuestion) _question;
List<Assertion> assertions = question.getAssertions();
_batfish.checkConfigurations();
NodesQuestion nodesQuestion = new NodesQuestion();
nodesQuestion.setSummary(false);
NodesAnswerer nodesAnswerer = new NodesAnswerer(nodesQuestion,
_batfish);
AnswerElement nodesAnswer = nodesAnswerer.answer();
BatfishObjectMapper mapper = new BatfishObjectMapper();
String nodesAnswerStr = null;
try {
nodesAnswerStr = mapper.writeValueAsString(nodesAnswer);
}
catch (IOException e) {
throw new BatfishException(
"Could not get JSON string from nodes answer", e);
}
Object jsonObject = JsonPath.parse(nodesAnswerStr, c).json();
Map<Integer, Assertion> failing = new ConcurrentHashMap<>();
Map<Integer, Assertion> passing = new ConcurrentHashMap<>();
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < assertions.size(); i++) {
indices.add(i);
}
final boolean[] fail = new boolean[1];
ConcurrentMap<String, ArrayNode> pathCache = new ConcurrentHashMap<>();
indices.parallelStream().forEach(i -> {
Assertion assertion = assertions.get(i);
String assertionText = assertion.getAssertion();
AssertionAst ast = _batfish.parseAssertion(assertionText);
if (ast.execute(_batfish, jsonObject, pathCache, c)) {
passing.put(i, assertion);
}
else {
failing.put(i, assertion);
synchronized (fail) {
fail[0] = true;
}
}
});
AssertAnswerElement answerElement = new AssertAnswerElement();
answerElement.setFail(fail[0]);
answerElement.getFailing().putAll(failing);
answerElement.getPassing().putAll(passing);
return answerElement;
}
}
// <question_page_comment>
/**
* Checks assertions.
*
* @type Assert misc
*
* @param assertions
* List of assertions
*/
public static class AssertQuestion extends Question {
private static final String ASSERTIONS_VAR = "assertions";
private List<Assertion> _assertions;
public AssertQuestion() {
_assertions = new ArrayList<>();
}
@JsonProperty(ASSERTIONS_VAR)
public List<Assertion> getAssertions() {
return _assertions;
}
@Override
public boolean getDataPlane() {
return false;
}
@Override
public String getName() {
return "assert";
}
@Override
public boolean getTraffic() {
return false;
}
@Override
public String prettyPrint() {
String retString = String.format("assert %s%s=\"%s\"",
prettyPrintBase(), ASSERTIONS_VAR, _assertions.toString());
return retString;
}
@JsonProperty(ASSERTIONS_VAR)
public void setAssertions(List<Assertion> assertions) {
_assertions = assertions;
}
}
@Override
protected Answerer createAnswerer(Question question, IBatfish batfish) {
return new AssertAnswerer(question, batfish);
}
@Override
protected Question createQuestion() {
return new AssertQuestion();
}
}