package org.batfish.common;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.antlr.v4.runtime.ParserRuleContext;
import org.batfish.grammar.BatfishCombinedParser;
import org.batfish.grammar.ParseTreePrettyPrinter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@JsonSerialize(using = Warnings.Serializer.class)
@JsonDeserialize(using = Warnings.Deserializer.class)
public class Warnings implements Serializable {
public static class Deserializer extends JsonDeserializer<Warnings> {
@Override
public Warnings deserialize(JsonParser parser, DeserializationContext ctx)
throws IOException, JsonProcessingException {
JsonNode node = parser.getCodec().readTree(parser);
Warnings warnings = new Warnings();
if (node.has(PEDANTIC_VAR)) {
JsonNode warningsNode = node.get(PEDANTIC_VAR);
fillWarningList(warnings._pedanticWarnings, warningsNode);
}
if (node.has(RED_FLAGS_VAR)) {
JsonNode warningsNode = node.get(RED_FLAGS_VAR);
fillWarningList(warnings._redFlagWarnings, warningsNode);
}
if (node.has(UNIMPLEMENTED_VAR)) {
JsonNode warningsNode = node.get(UNIMPLEMENTED_VAR);
fillWarningList(warnings._unimplementedWarnings, warningsNode);
}
return warnings;
}
private void fillWarningList(List<Warning> warnings, JsonNode node) {
for (Iterator<Entry<String, JsonNode>> iter = node.fields(); iter
.hasNext();) {
Entry<String, JsonNode> e = iter.next();
String msg = e.getValue().asText();
int colonIndex = msg.indexOf(":");
String tag = msg.substring(0, colonIndex);
String text = msg.substring(colonIndex + 2, msg.length());
Warning warning = new Warning(text, tag);
warnings.add(warning);
}
}
}
public static class Serializer extends JsonSerializer<Warnings> {
@Override
public void serialize(Warnings value, JsonGenerator jgen,
SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
if (!value._pedanticWarnings.isEmpty()) {
jgen.writeFieldName(PEDANTIC_VAR);
jgen.writeStartObject();
for (int i = 0; i < value._pedanticWarnings.size(); i++) {
Warning taggedWarning = value._pedanticWarnings.get(i);
String text = taggedWarning.getFirst();
String tag = taggedWarning.getSecond();
String msg = tag + ": " + text;
jgen.writeFieldName(Integer.toString(i + 1));
jgen.writeString(msg);
}
jgen.writeEndObject();
}
if (!value._redFlagWarnings.isEmpty()) {
jgen.writeFieldName(RED_FLAGS_VAR);
jgen.writeStartObject();
for (int i = 0; i < value._redFlagWarnings.size(); i++) {
Warning taggedWarning = value._redFlagWarnings.get(i);
String text = taggedWarning.getFirst();
String tag = taggedWarning.getSecond();
String msg = tag + ": " + text;
jgen.writeFieldName(Integer.toString(i + 1));
jgen.writeString(msg);
}
jgen.writeEndObject();
}
if (!value._unimplementedWarnings.isEmpty()) {
jgen.writeFieldName(UNIMPLEMENTED_VAR);
jgen.writeStartObject();
for (int i = 0; i < value._unimplementedWarnings.size(); i++) {
Warning taggedWarning = value._unimplementedWarnings.get(i);
String text = taggedWarning.getFirst();
String tag = taggedWarning.getSecond();
String msg = tag + ": " + text;
jgen.writeFieldName(Integer.toString(i + 1));
jgen.writeString(msg);
}
jgen.writeEndObject();
}
jgen.writeEndObject();
}
}
private static final String MISCELLANEOUS = "MISCELLANEOUS";
private static final String PEDANTIC_VAR = "Pedantic complaints";
private static final String RED_FLAGS_VAR = "Red flags";
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String UNIMPLEMENTED_VAR = "Unimplemented features";
private transient boolean _pedanticAsError;
private transient boolean _pedanticRecord;
protected final List<Warning> _pedanticWarnings;
private transient boolean _printParseTree;
private transient boolean _redFlagAsError;
private transient boolean _redFlagRecord;
protected final List<Warning> _redFlagWarnings;
private transient boolean _unimplementedAsError;
private transient boolean _unimplementedRecord;
protected final List<Warning> _unimplementedWarnings;
public Warnings() {
_pedanticWarnings = new ArrayList<>();
_redFlagWarnings = new ArrayList<>();
_unimplementedWarnings = new ArrayList<>();
}
public Warnings(boolean pedanticAsError, boolean pedanticRecord,
boolean redFlagAsError, boolean redFlagRecord,
boolean unimplementedAsError, boolean unimplementedRecord,
boolean printParseTree) {
this();
_pedanticAsError = pedanticAsError;
_pedanticRecord = pedanticRecord;
_printParseTree = printParseTree;
_redFlagAsError = redFlagAsError;
_redFlagRecord = redFlagRecord;
_unimplementedAsError = unimplementedAsError;
_unimplementedRecord = unimplementedRecord;
}
public List<Warning> getPedanticWarnings() {
return _pedanticWarnings;
}
public List<Warning> getRedFlagWarnings() {
return _redFlagWarnings;
}
public List<Warning> getUnimplementedWarnings() {
return _unimplementedWarnings;
}
@JsonIgnore
public boolean isEmpty() {
return _pedanticWarnings.isEmpty() && _redFlagWarnings.isEmpty()
&& _unimplementedWarnings.isEmpty();
}
public void pedantic(String msg) {
pedantic(msg, MISCELLANEOUS);
}
public void pedantic(String msg, String tag) {
if (_pedanticAsError) {
throw new PedanticBatfishException(msg);
}
else if (_pedanticRecord) {
_pedanticWarnings.add(new Warning(msg, tag));
}
}
public void redFlag(String msg) {
redFlag(msg, MISCELLANEOUS);
}
public void redFlag(String msg, String tag) {
if (_redFlagAsError) {
throw new RedFlagBatfishException(msg);
}
else if (_redFlagRecord) {
_redFlagWarnings.add(new Warning(msg, tag));
}
}
public void todo(ParserRuleContext ctx, String feature,
BatfishCombinedParser<?, ?> parser, String text) {
if (!_unimplementedRecord && !_unimplementedAsError) {
return;
}
String prefix = "WARNING: UNIMPLEMENTED: "
+ (_unimplementedWarnings.size() + 1) + ": ";
StringBuilder sb = new StringBuilder();
List<String> ruleNames = Arrays.asList(parser.getParser().getRuleNames());
String ruleStack = ctx.toString(ruleNames);
sb.append(
prefix + "Missing implementation for top (leftmost) parser rule in stack: '"
+ ruleStack + "'.\n");
sb.append(prefix + "Unimplemented feature: " + feature + "\n");
sb.append(prefix + "Rule context follows:\n");
int start = ctx.start.getStartIndex();
int startLine = ctx.start.getLine();
int end = ctx.stop.getStopIndex();
String ruleText = text.substring(start, end + 1);
String[] ruleTextLines = ruleText.split("\\n");
for (int line = startLine, i = 0; i < ruleTextLines.length; line++, i++) {
String contextPrefix = prefix + " line " + line + ": ";
sb.append(contextPrefix + ruleTextLines[i] + "\n");
}
if (_printParseTree) {
sb.append(prefix + "Parse tree follows:\n");
String parseTreePrefix = prefix + "PARSE TREE: ";
String parseTreeText = ParseTreePrettyPrinter.print(ctx, parser);
String[] parseTreeLines = parseTreeText.split("\n");
for (String parseTreeLine : parseTreeLines) {
sb.append(parseTreePrefix + parseTreeLine + "\n");
}
}
String warning = sb.toString();
if (_unimplementedAsError) {
throw new UnimplementedBatfishException(warning);
}
else {
_unimplementedWarnings
.add(new Warning(sb.toString(), "UNIMPLEMENTED"));
}
}
public void unimplemented(String msg) {
unimplemented(msg, MISCELLANEOUS);
}
public void unimplemented(String msg, String tag) {
if (_unimplementedAsError) {
throw new UnimplementedBatfishException(msg);
}
else if (_unimplementedRecord) {
_unimplementedWarnings.add(new Warning(msg, tag));
}
}
}