package org.batfish.datamodel.questions; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.batfish.common.BatfishException; import org.batfish.common.util.BatfishObjectMapper; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "class") public abstract class Question implements IQuestion { public static class InstanceData { public static class Variable { public static enum Type { BOOLEAN("boolean", false), COMPARATOR("comparator", true), DOUBLE("double", false), FLOAT("float", false), INTEGER("integer", false), IP("ip", true), IP_PROTOCOL("ipProtocol", true), IP_WILDCARD("ipWildcard", true), JAVA_REGEX("javaRegex", true), JSON_PATH("jsonPath", true), JSON_PATH_REGEX("jsonPathRegex", true), LONG("long", false), PREFIX("prefix", true), PREFIX_RANGE("prefixRange", true), PROTOCOL("protocol", true), STRING("string", true), SUBRANGE("subrange", true); private static final Map<String, Type> MAP = initMap(); @JsonCreator public static Type fromString(String name) { Type value = MAP.get(name.toLowerCase()); if (value == null) { throw new BatfishException("No " + Type.class.getSimpleName() + " with name: '" + name + "'"); } return value; } private static synchronized Map<String, Type> initMap() { Map<String, Type> map = new HashMap<>(); for (Type value : Type.values()) { String name = value._name.toLowerCase(); map.put(name, value); } return Collections.unmodifiableMap(map); } private final String _name; private final boolean _stringType; private Type(String name, boolean stringType) { _name = name; _stringType = stringType; } @JsonValue public String getName() { return _name; } public boolean getStringType() { return _stringType; } } private static final String ALLOWED_VALUES_VAR = "allowedValues"; private static final String DESCRIPTION_VAR = "description"; private static final String MIN_ELEMENTS_VAR = "minElements"; private static final String MIN_LENGTH_VAR = "minLength"; private static final String OPTIONAL_VAR = "optional"; private static final String TYPE_VAR = "type"; private static final String VALUE_VAR = "value"; private SortedSet<String> _allowedValues; private String _description; private Integer _minElements; private Integer _minLength; private boolean _optional; private Type _type; private JsonNode _value; public Variable() { _allowedValues = new TreeSet<>(); } @JsonProperty(ALLOWED_VALUES_VAR) public SortedSet<String> getAllowedValues() { return _allowedValues; } @JsonProperty(DESCRIPTION_VAR) public String getDescription() { return _description; } @JsonProperty(MIN_ELEMENTS_VAR) public Integer getMinElements() { return _minElements; } @JsonProperty(MIN_LENGTH_VAR) public Integer getMinLength() { return _minLength; } @JsonProperty(OPTIONAL_VAR) public boolean getOptional() { return _optional; } @JsonProperty(TYPE_VAR) public Type getType() { return _type; } @JsonProperty(VALUE_VAR) public JsonNode getValue() { return _value; } @JsonProperty(ALLOWED_VALUES_VAR) public void setAllowedValues(SortedSet<String> allowedValues) { _allowedValues = allowedValues; } @JsonProperty(DESCRIPTION_VAR) public void setDescription(String description) { _description = description; } @JsonProperty(MIN_ELEMENTS_VAR) public void setMinElements(Integer minElements) { _minElements = minElements; } @JsonProperty(MIN_LENGTH_VAR) public void setMinLength(Integer minLength) { _minLength = minLength; } @JsonProperty(OPTIONAL_VAR) public void setOptional(boolean optional) { _optional = optional; } @JsonProperty(TYPE_VAR) public void setType(Type type) { _type = type; } @JsonProperty(VALUE_VAR) public void setValue(JsonNode value) { if (value != null && value.isNull()) { _value = null; } else { _value = value; } } } private static final String DESCRIPTION_VAR = "description"; private static final String INSTANCE_NAME_VAR = "instanceName"; private static final String LONG_DESCRIPTION_VAR = "longDescription"; private static final String TAGS_VAR = "tags"; private static final String VARIABLES_VAR = "variables"; private String _description; private String _instanceName; private String _longDescription; private SortedSet<String> _tags; private SortedMap<String, Variable> _variables; public InstanceData() { _tags = new TreeSet<>(); _variables = new TreeMap<>(); } @JsonProperty(DESCRIPTION_VAR) public String getDescription() { return _description; } @JsonProperty(INSTANCE_NAME_VAR) public String getInstanceName() { return _instanceName; } @JsonProperty(LONG_DESCRIPTION_VAR) public String getLongDescription() { return _longDescription; } @JsonProperty(TAGS_VAR) public SortedSet<String> getTags() { return _tags; } @JsonProperty(VARIABLES_VAR) public SortedMap<String, Variable> getVariables() { return _variables; } @JsonProperty(DESCRIPTION_VAR) public void setDescription(String description) { _description = description; } @JsonProperty(INSTANCE_NAME_VAR) public void setInstanceName(String instanceName) { _instanceName = instanceName; } @JsonProperty(LONG_DESCRIPTION_VAR) public void setLongDescription(String longDescription) { _longDescription = longDescription; } @JsonProperty(TAGS_VAR) public void setTags(SortedSet<String> tags) { _tags = tags; } @JsonProperty(VARIABLES_VAR) public void setVariables(SortedMap<String, Variable> variables) { _variables = variables; } } public static final String DIFFERENTIAL_VAR = "differential"; public static final String INNER_QUESTION_VAR = "innerQuestion"; public static final String INSTANCE_VAR = "instance"; private boolean _differential; private InstanceData _instance; public Question() { _differential = false; } @JsonIgnore public abstract boolean getDataPlane(); @JsonProperty(DIFFERENTIAL_VAR) public boolean getDifferential() { return _differential; } @JsonProperty(INSTANCE_VAR) public InstanceData getInstance() { return _instance; } @JsonIgnore public abstract String getName(); @JsonIgnore public abstract boolean getTraffic(); protected boolean isBaseParamKey(String paramKey) { switch (paramKey) { case DIFFERENTIAL_VAR: return true; default: return false; } } // by default, pretty printing is Json // override this function in derived classes to do something more meaningful public String prettyPrint() { ObjectMapper mapper = new BatfishObjectMapper(); try { return mapper.writeValueAsString(this); } catch (JsonProcessingException e) { throw new BatfishException("Failed to pretty-print question", e); } } protected String prettyPrintBase() { String retString = ""; // for brevity, print only if the values are non-default if (_differential) { retString += String.format("differential=%s", _differential); } if (retString == "") { return ""; } else { return retString + " | "; } } @JsonProperty(DIFFERENTIAL_VAR) public void setDifferential(boolean differential) { _differential = differential; } @JsonProperty(INSTANCE_VAR) public void setInstance(InstanceData instance) { _instance = instance; } @Override public String toFullJsonString() { ObjectMapper mapper = new BatfishObjectMapper(); mapper.setSerializationInclusion(Include.ALWAYS); try { return mapper.writeValueAsString(this); } catch (JsonProcessingException e) { throw new BatfishException( "Failed to convert question to full JSON string", e); } } @Override public String toJsonString() { ObjectMapper mapper = new BatfishObjectMapper(); try { return mapper.writeValueAsString(this); } catch (JsonProcessingException e) { throw new BatfishException("Failed to convert question to JSON string", e); } } }