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

181 lines
6.5 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.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.DBUtility;
import org.gcube.informationsystem.utils.TypeUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.arcadedb.database.Document;
import com.arcadedb.query.sql.executor.Result;
import com.arcadedb.query.sql.executor.ResultSet;
import com.arcadedb.remote.RemoteDatabase;
/**
* @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 RemoteDatabase database;
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 = TypeUtility.getTypeName(jsonQuery);
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 {
RemoteDatabase current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
database = null;
try {
SecurityContext securityContext = ContextUtility.getCurrentSecurityContext();
database = securityContext.getRemoteDatabase(PermissionMode.READER);
database.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));
ResultSet resultSet = database.command("sql", query, map);
ArrayNode arrayNode = objectMapper.createArrayNode();
while(resultSet.hasNext()) {
Result oResult = resultSet.next();
Document element = ElementManagementUtility.getElementFromOptional(oResult.getElement());
try {
JsonNode jsonNodeResult = null;
ElementManagement<?,?> erManagement = ElementManagementUtility.getERManagement(securityContext, database,
element);
// To support polymorphism we do not include ="TypeName" in query. So we need post processing filtering of results
String requestedType = entryPoint.getType();
String gotType = erManagement.getTypeName();
if(requestedType.compareTo(gotType)==0) {
erManagement.setAsEntryPoint();
jsonNodeResult = erManagement.serializeAsJsonNode();
arrayNode.add(jsonNodeResult);
continue;
}
CachedType<?> cachedType = TypesCache.getInstance().getCachedType(gotType);
if(cachedType.getSuperTypes().contains(requestedType)) {
erManagement.setAsEntryPoint();
jsonNodeResult = erManagement.serializeAsJsonNode();
arrayNode.add(jsonNodeResult);
continue;
}
} catch(ResourceRegistryException e) {
logger.error("Unable to correctly serialize {}. It will be excluded from results. {}",
element.toString(), DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
}
}
return objectMapper.writeValueAsString(arrayNode);
} catch(Exception e) {
throw new InvalidQueryException(e.getMessage());
} finally {
if(database != null) {
database.close();
}
// if(current!=null) {
// current.activateOnCurrentThread();
// }
}
}
}