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

179 lines
6.6 KiB
Java

package org.gcube.informationsystem.resourceregistry.queries.json;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
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.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.base.reference.Direction;
import org.gcube.informationsystem.base.reference.Element;
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.contexts.ContextUtility;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
import org.gcube.informationsystem.resourceregistry.queries.json.base.JsonQueryERElement;
import org.gcube.informationsystem.resourceregistry.queries.json.base.entities.JsonQueryFacet;
import org.gcube.informationsystem.resourceregistry.queries.json.base.entities.JsonQueryResource;
import org.gcube.informationsystem.resourceregistry.queries.json.base.relations.JsonQueryConsistsOf;
import org.gcube.informationsystem.resourceregistry.queries.json.base.relations.JsonQueryIsRelatedTo;
import org.gcube.informationsystem.resourceregistry.types.CachedType;
import org.gcube.informationsystem.resourceregistry.types.TypesCache;
import org.gcube.informationsystem.resourceregistry.utils.Utility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.OElement;
import com.orientechnologies.orient.core.sql.executor.OResult;
import com.orientechnologies.orient.core.sql.executor.OResultSet;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class JsonQuery {
private static Logger logger = LoggerFactory.getLogger(JsonQuery.class);
private static final Integer UNBOUNDED_LIMIT = -1;
protected ObjectMapper objectMapper;
protected JsonNode jsonQuery;
protected JsonQueryERElement entryPoint;
protected ODatabaseDocument oDatabaseDocument;
public JsonQuery() {
this.objectMapper = new ObjectMapper();
}
public void setJsonQuery(JsonNode jsonQuery) {
this.jsonQuery = jsonQuery;
}
public void setJsonQuery(String jsonQuery) throws InvalidQueryException {
try {
this.jsonQuery = objectMapper.readTree(jsonQuery);
} catch (IOException e) {
throw new InvalidQueryException(e);
}
}
public static JsonQueryERElement getJsonQueryERElement(JsonNode jsonQuery) throws SchemaNotFoundException, SchemaException, ResourceRegistryException {
String type = jsonQuery.get(Element.CLASS_PROPERTY).asText();
AccessType accessType = TypesCache.getInstance().getCachedType(type).getAccessType();
JsonQueryERElement jsonQueryERElement = null;
switch (accessType) {
case RESOURCE:
jsonQueryERElement = new JsonQueryResource(jsonQuery);
jsonQueryERElement.setDirection(Direction.OUT);
break;
case FACET:
jsonQueryERElement = new JsonQueryFacet(jsonQuery);
break;
case IS_RELATED_TO:
jsonQueryERElement = new JsonQueryIsRelatedTo(jsonQuery);
break;
case CONSISTS_OF:
jsonQueryERElement = new JsonQueryConsistsOf(jsonQuery);
break;
default:
throw new InvalidQueryException(String.format("%s is not querable", type.toString()));
}
return jsonQueryERElement;
}
public StringBuffer createQuery() throws SchemaException, InvalidQueryException, ResourceRegistryException {
entryPoint = getJsonQueryERElement(jsonQuery);
entryPoint.setEntryPoint(true);
return entryPoint.analize(new StringBuffer());
}
public String query() throws InvalidQueryException, ResourceRegistryException {
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
oDatabaseDocument = null;
try {
SecurityContext securityContext = ContextUtility.getCurrentSecurityContext();
oDatabaseDocument = securityContext.getDatabaseDocument(PermissionMode.READER);
oDatabaseDocument.begin();
StringBuffer stringBuffer = createQuery();
stringBuffer.append(" limit :limit");
Map<String, Object> map = new HashMap<>();
map.put("limit", JsonQuery.UNBOUNDED_LIMIT);
String query = stringBuffer.toString();
logger.trace("Going to execute the following query:\n{} \n from the JSONQuery\n{}", query, objectMapper.writeValueAsString(jsonQuery));
OResultSet resultSet = oDatabaseDocument.query(query, map);
ArrayNode arrayNode = objectMapper.createArrayNode();
while(resultSet.hasNext()) {
OResult oResult = resultSet.next();
OElement element = ElementManagementUtility.getElementFromOptional(oResult.getElement());
try {
JsonNode jsonNodeResult = null;
ElementManagement<?,?> erManagement = ElementManagementUtility.getERManagement(securityContext, oDatabaseDocument,
element);
// To support polymorphism we do not include @class="TypeName" in query. So we need post processing filtering of results
String requestedType = entryPoint.getType();
String gotType = erManagement.getTypeName();
if(requestedType.compareTo(gotType)==0) {
jsonNodeResult = erManagement.serializeAsJsonNode();
arrayNode.add(jsonNodeResult);
continue;
}
CachedType<?> cachedType = TypesCache.getInstance().getCachedType(gotType);
if(cachedType.getSuperTypes().contains(requestedType)) {
jsonNodeResult = erManagement.serializeAsJsonNode();
arrayNode.add(jsonNodeResult);
continue;
}
} catch(ResourceRegistryException e) {
logger.error("Unable to correctly serialize {}. It will be excluded from results. {}",
element.toString(), Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
}
}
return objectMapper.writeValueAsString(arrayNode);
} catch(Exception e) {
throw new InvalidQueryException(e.getMessage());
} finally {
if(oDatabaseDocument != null) {
oDatabaseDocument.close();
}
if(current!=null) {
current.activateOnCurrentThread();
}
}
}
}