Permalink
Browse files

Updated entity model specification, mapping, objects, and tests.

  • Loading branch information...
davemoore- committed Apr 5, 2018
1 parent 0f44e20 commit 5b28a26807785d12ab52e2b825d3efd05aa3437a
@@ -0,0 +1,95 @@
package io.zentity.model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.*;
public class Attribute {
public static final Set<String> VALID_TYPES = new HashSet<>(
Arrays.asList("string", "long", "integer", "short", "byte", "double", "float", "boolean")
);
private final String name;
private String type = "string";
public Attribute(String name, JsonNode json) throws ValidationException {
validateName(name);
this.name = name;
this.deserialize(json);
}
public Attribute(String name, String json) throws ValidationException, IOException {
validateName(name);
this.name = name;
this.deserialize(json);
}
public String name() {
return this.name;
}
public String type() {
return this.type;
}
public void type(JsonNode value) throws ValidationException {
validateType(value);
this.type = value.textValue();
}
private void validateName(String value) throws ValidationException {
if (value.matches("^\\s*$"))
throw new ValidationException("'attributes' has an attribute with empty name.");
}
private void validateType(JsonNode value) throws ValidationException {
if (!value.isTextual())
throw new ValidationException("'attributes." + this.name + ".type' must be a string.");
if (!VALID_TYPES.contains(value.textValue()))
throw new ValidationException("'attributes." + this.name + ".type' does not support the value '" + value.textValue() + "'.");
}
private void validateObject(JsonNode object) throws ValidationException {
if (!object.isObject())
throw new ValidationException("'attributes." + this.name + "' must be an object.");
}
/**
* Deserialize, validate, and hold the state of an attribute object of an entity model.
* Expected structure of the json variable:
* <pre>
* {
* "type": ATTRIBUTE_TYPE
* }
* </pre>
*
* @param json Attribute object of an entity model.
* @throws ValidationException
*/
public void deserialize(JsonNode json) throws ValidationException {
validateObject(json);
// Validate and hold the state of fields.
Iterator<Map.Entry<String, JsonNode>> fields = json.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String name = field.getKey();
JsonNode value = field.getValue();
switch (name) {
case "type":
this.type(value);
break;
default:
throw new ValidationException("'attributes." + this.name + "." + name + "' is not a recognized field.");
}
}
}
public void deserialize(String json) throws ValidationException, IOException {
deserialize(new ObjectMapper().readTree(json));
}
}
@@ -0,0 +1,144 @@
package io.zentity.model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.*;
public class Index {
public static final Set<String> REQUIRED_FIELDS = new HashSet<>(
Arrays.asList("fields")
);
private final String name;
private HashMap<String, IndexField> fields;
private HashMap<String, HashMap<String, IndexField>> attributeIndexFieldsMap = new HashMap<>();
public Index(String name, JsonNode json) throws ValidationException {
validateName(name);
this.name = name;
this.deserialize(json);
}
public Index(String name, String json) throws ValidationException, IOException {
validateName(name);
this.name = name;
this.deserialize(json);
}
public String name() {
return this.name;
}
public HashMap<String, HashMap<String, IndexField>> attributeIndexFieldsMap() {
return this.attributeIndexFieldsMap;
}
public HashMap<String, IndexField> fields() {
return this.fields;
}
public void fields(JsonNode value) throws ValidationException {
validateFields(value);
HashMap<String, IndexField> fields = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> children = value.fields();
while (children.hasNext()) {
Map.Entry<String, JsonNode> child = children.next();
String fieldName = child.getKey();
JsonNode fieldObject = child.getValue();
validateField(fieldName, fieldObject);
fields.put(fieldName, new IndexField(this.name, fieldName, fieldObject));
}
this.fields = fields;
this.rebuildAttributeIndexFieldsMap();
}
private void validateName(String value) throws ValidationException {
if (value.matches("^\\s*$"))
throw new ValidationException("'indices' has an index with an empty name.");
}
private void validateField(String fieldName, JsonNode fieldObject) throws ValidationException {
if (fieldName.equals(""))
throw new ValidationException("'indices." + this.name + ".fields' has a field with an empty name.");
if (!fieldObject.isObject())
throw new ValidationException("'indices." + this.name + ".fields." + fieldName + "' must be an object.");
if (fieldObject.size() == 0)
throw new ValidationException("'indices." + this.name + ".fields." + fieldName + "' must not be empty.");
}
private void validateFields(JsonNode value) throws ValidationException {
if (!value.isObject())
throw new ValidationException("'indices." + this.name + ".fields' must be an object.");
if (value.size() == 0)
throw new ValidationException("'indices." + this.name + ".fields' must not be empty.");
}
private void validateObject(JsonNode object) throws ValidationException {
if (!object.isObject())
throw new ValidationException("'indices." + this.name + "' must be an object.");
if (object.size() == 0)
throw new ValidationException("'indices." + this.name + "' is empty.");
}
/**
* Create a reverse index of attribute names to index fields for faster lookup of index fields by attributes
* during a resolution job.
*/
private void rebuildAttributeIndexFieldsMap() {
this.attributeIndexFieldsMap = new HashMap<>();
for (String indexFieldName : this.fields().keySet()) {
String attributeName = this.fields().get(indexFieldName).attribute();
if (!this.attributeIndexFieldsMap.containsKey(attributeName))
this.attributeIndexFieldsMap.put(attributeName, new HashMap<>());
if (!this.attributeIndexFieldsMap.get(attributeName).containsKey(indexFieldName))
this.attributeIndexFieldsMap.get(attributeName).put(indexFieldName, this.fields.get(indexFieldName));
}
}
/**
* Deserialize, validate, and hold the state of an index object of an entity model.
* Expected structure of the json variable:
* <pre>
* {
* "fields": {
* INDEX_FIELD_NAME: INDEX_FIELD_OBJECT
* ...
* }
* }
* </pre>
*
* @param json Index object of an entity model.
* @throws ValidationException
*/
public void deserialize(JsonNode json) throws ValidationException {
validateObject(json);
// Validate the existence of required fields.
for (String field : REQUIRED_FIELDS)
if (!json.has(field))
throw new ValidationException("'indices." + this.name + "' is missing required field '" + field + "'.");
// Validate and hold the state of fields.
Iterator<Map.Entry<String, JsonNode>> fields = json.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String name = field.getKey();
JsonNode value = field.getValue();
switch (name) {
case "fields":
this.fields(value);
break;
default:
throw new ValidationException("'indices." + this.name + "." + name + "' is not a recognized field.");
}
}
}
public void deserialize(String json) throws ValidationException, IOException {
deserialize(new ObjectMapper().readTree(json));
}
}
@@ -0,0 +1,130 @@
package io.zentity.model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.*;
public class IndexField {
public static final Set<String> REQUIRED_FIELDS = new HashSet<>(
Arrays.asList("attribute")
);
private final String index;
private final String name;
private String attribute;
private String matcher = null;
public IndexField(String index, String name, JsonNode json) throws ValidationException {
validateName(name);
this.index = index;
this.name = name;
this.deserialize(json);
}
public IndexField(String index, String name, String json) throws ValidationException, IOException {
validateName(name);
this.index = index;
this.name = name;
this.deserialize(json);
}
public String index() {
return this.index;
}
public String name() {
return this.name;
}
public String attribute() {
return this.attribute;
}
public void attribute(JsonNode value) throws ValidationException {
validateAttribute(value);
this.attribute = value.textValue();
}
public String matcher() {
return this.matcher;
}
public void matcher(JsonNode value) throws ValidationException {
validateMatcher(value);
this.matcher = value.isTextual() ? value.textValue() : null;
}
private void validateName(String value) throws ValidationException {
if (value.matches("^\\s*$"))
throw new ValidationException("'indices." + this.index + "' has a field with an empty name.");
}
private void validateAttribute(JsonNode value) throws ValidationException {
if (!value.isTextual())
throw new ValidationException("'indices." + this.index + "." + this.name + ".attribute' must be a string.");
if (value.textValue().matches("^\\s*$"))
throw new ValidationException("'indices." + this.index + "." + this.name + ".attribute' must not be empty.");
}
private void validateMatcher(JsonNode value) throws ValidationException {
if (!value.isTextual() && !value.isNull())
throw new ValidationException("'indices." + this.index + "." + this.name + ".matcher' must be a string or null.");
if (value.textValue().matches("^\\s*$"))
throw new ValidationException("'indices." + this.index + "." + this.name + ".matcher' must not be empty.");
}
private void validateObject(JsonNode object) throws ValidationException {
if (!object.isObject())
throw new ValidationException("'indices." + this.index + "." + this.name + "' must be an object.");
if (object.size() == 0)
throw new ValidationException("'indices." + this.index + "." + this.name + "' is empty.");
}
/**
* Deserialize, validate, and hold the state of a field object of an index field object of an entity model.
* Expected structure of the json variable:
* <pre>
* {
* "attribute": ATTRIBUTE_NAME,
* "matcher": MATCHER_NAME
* }
* </pre>
*
* @param json Index object of an entity model.
* @throws ValidationException
*/
public void deserialize(JsonNode json) throws ValidationException {
validateObject(json);
// Validate the existence of required fields.
for (String field : REQUIRED_FIELDS)
if (!json.has(field))
throw new ValidationException("'indices." + this.index + "." + this.name + "' is missing required field '" + field + "'.");
// Validate and hold the state of fields.
Iterator<Map.Entry<String, JsonNode>> fields = json.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String name = field.getKey();
JsonNode value = field.getValue();
switch (name) {
case "attribute":
this.attribute(value);
break;
case "matcher":
this.matcher(value);
break;
default:
throw new ValidationException("'indices." + this.index + "." + this.name + "." + name + "' is not a recognized field.");
}
}
}
public void deserialize(String json) throws ValidationException, IOException {
deserialize(new ObjectMapper().readTree(json));
}
}
Oops, something went wrong.

0 comments on commit 5b28a26

Please sign in to comment.