resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/JsonQueryERElement.java

239 lines
7.7 KiB
Java

package org.gcube.informationsystem.resourceregistry.queries.json.base;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.base.reference.Direction;
import org.gcube.informationsystem.base.reference.Element;
import org.gcube.informationsystem.model.reference.ModelElement;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaNotFoundException;
import org.gcube.informationsystem.resourceregistry.queries.operators.ConditionalOperator;
import org.gcube.informationsystem.resourceregistry.queries.operators.LogicalOperator;
import org.gcube.informationsystem.resourceregistry.types.TypesCache;
import org.gcube.informationsystem.utils.TypeUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class JsonQueryERElement {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
public static void validateType(String type, AccessType requiredAccessType) throws SchemaException, ResourceRegistryException {
AccessType accessType = TypesCache.getInstance().getCachedType(type).getAccessType();
if(!accessType.equals(requiredAccessType)) {
throw new InvalidQueryException(type + "is not an expected " + requiredAccessType.getName() + " type");
}
}
protected final ObjectMapper objectMapper;
protected final String type;
protected final JsonNode jsonNode;
protected final AccessType accessType;
protected final Set<String> fieldNamesToRemove;
protected Direction direction;
protected boolean entryPoint;
/**
* it indicates the number of properties in this.jsonNode
* This number is manipulated while analyzing the jsonNode
* to properly create the query.
*/
protected int size;
protected boolean traverseBack;
public JsonQueryERElement(JsonNode jsonQuery, AccessType accessType) throws SchemaException, ResourceRegistryException {
this.objectMapper = new ObjectMapper();
this.type = TypeUtility.getTypeName(jsonQuery);
this.jsonNode = jsonQuery;
this.size = jsonNode.size();
this.accessType = accessType;
this.entryPoint = false;
this.traverseBack = true;
this.fieldNamesToRemove = new HashSet<>();
this.fieldNamesToRemove.add(Element.TYPE_PROPERTY);
this.fieldNamesToRemove.add(ModelElement.SUPERTYPES_PROPERTY);
this.fieldNamesToRemove.add(ModelElement.EXPECTED_TYPE_PROPERTY);
validateType(this.type, this.accessType);
}
public String getType() {
return type;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public boolean isEntryPoint() {
return entryPoint;
}
public void setEntryPoint(boolean entryPoint) {
this.entryPoint = entryPoint;
this.traverseBack = !entryPoint;
}
public boolean isTraverseBack() {
return traverseBack;
}
public void setTraverseBack(boolean traverseBack) {
this.traverseBack = traverseBack;
}
public abstract StringBuffer analize(StringBuffer stringBuffer) throws SchemaNotFoundException, InvalidQueryException, SchemaException, ResourceRegistryException;
protected StringBuffer addConstraints(JsonNode jsonNode, LogicalOperator queryLogicalOperator, String fieldNamePrefix) throws InvalidQueryException {
StringBuffer stringBuffer = new StringBuffer();
if(queryLogicalOperator==null) {
queryLogicalOperator = LogicalOperator.AND;
}
JsonNode copiedJsonNode = jsonNode.deepCopy();
if(jsonNode.isObject()) {
ObjectNode objectNode = (ObjectNode) copiedJsonNode;
objectNode.remove(fieldNamesToRemove);
Iterator<String> iterator = objectNode.fieldNames();
boolean first = true;
while(iterator.hasNext()) {
String fieldName = iterator.next();
if(first) {
first = false;
}else {
stringBuffer.append(queryLogicalOperator.getLogicalOperator());
}
JsonNode node = objectNode.get(fieldName);
stringBuffer.append(evaluateNode(node, fieldName, fieldNamePrefix));
}
}
if(jsonNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) copiedJsonNode;
Iterator<JsonNode> iterator = arrayNode.iterator();
boolean first = true;
while(iterator.hasNext()) {
if(first) {
first = false;
}else {
stringBuffer.append(queryLogicalOperator.getLogicalOperator());
}
JsonNode node = iterator.next();
stringBuffer.append(evaluateNode(node, null, fieldNamePrefix));
}
}
return stringBuffer;
}
protected StringBuffer evaluateNode(JsonNode jsonNode, String fieldName, String fieldNamePrefix) throws InvalidQueryException {
StringBuffer stringBuffer = new StringBuffer();
if(LogicalOperator.getOperators().contains(fieldName)) {
LogicalOperator queryLogicalOperator = LogicalOperator.getQueryLogicalOperator(fieldName);
stringBuffer.append("(");
stringBuffer.append(addConstraints(jsonNode, queryLogicalOperator, fieldNamePrefix));
stringBuffer.append(")");
return stringBuffer;
}
if(ConditionalOperator.getOperators().contains(fieldName)) {
ConditionalOperator queryConditionalOperator = ConditionalOperator.getQueryComparisonOperator(fieldName);
if(queryConditionalOperator == ConditionalOperator.IN) {
throw new UnsupportedOperationException();
}
StringBuffer key = getKey(null, fieldNamePrefix);
StringBuffer value = getValue(jsonNode);
stringBuffer.append(addCondition(queryConditionalOperator, key, value));
return stringBuffer;
}
if(jsonNode.isObject()) {
StringBuffer newPrefix = new StringBuffer();
if(fieldNamePrefix!=null && fieldNamePrefix.compareTo("")!=0) {
newPrefix.append(fieldNamePrefix);
if(fieldName!=null && fieldName.compareTo("")!=0) {
newPrefix.append(".");
}
}
if(fieldName!=null && fieldName.compareTo("")!=0) {
newPrefix.append(fieldName);
}
stringBuffer.append(addConstraints(jsonNode, null, newPrefix.length()>0 ? newPrefix.toString() : null));
return stringBuffer;
}
if(jsonNode.isTextual() || jsonNode.isNumber()) {
StringBuffer key = getKey(fieldName, fieldNamePrefix);
StringBuffer value = getValue(jsonNode);
stringBuffer.append(addCondition(ConditionalOperator.EQ, key, value));
}
return stringBuffer;
}
protected StringBuffer addCondition(ConditionalOperator queryConditionalOperator, StringBuffer key, StringBuffer value) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(key);
stringBuffer.append(queryConditionalOperator.getConditionalOperator());
stringBuffer.append(value);
return stringBuffer;
}
protected StringBuffer getKey(String fieldName, String fieldNamePrefix) {
StringBuffer stringBuffer = new StringBuffer();
if(fieldNamePrefix!=null) {
stringBuffer.append(fieldNamePrefix);
if(fieldName!=null && fieldName.compareTo("")!=0) {
stringBuffer.append(".");
}
}
if(fieldName!=null) {
stringBuffer.append(fieldName);
}
return stringBuffer;
}
protected StringBuffer getValue(JsonNode jsonNode) {
StringBuffer stringBuffer = new StringBuffer();
String value = jsonNode.asText();
if(jsonNode.isNumber()) {
stringBuffer.append(value);
} else {
stringBuffer.append("\"");
stringBuffer.append(value);
stringBuffer.append("\"");
}
return stringBuffer;
}
}