174 lines
6.9 KiB
Java
174 lines
6.9 KiB
Java
package org.gcube.informationsystem.resourceregistry.instances.base.entities;
|
|
|
|
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.com.fasterxml.jackson.databind.node.ObjectNode;
|
|
import org.gcube.informationsystem.base.reference.AccessType;
|
|
import org.gcube.informationsystem.base.reference.entities.EntityElement;
|
|
import org.gcube.informationsystem.base.reference.relations.RelationElement;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.entities.EntityAlreadyPresentException;
|
|
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
|
|
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement;
|
|
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
|
|
import org.gcube.informationsystem.resourceregistry.instances.base.relations.RelationElementManagement;
|
|
import org.gcube.informationsystem.resourceregistry.utils.DBUtility;
|
|
import org.gcube.informationsystem.types.reference.entities.EntityType;
|
|
|
|
import com.arcadedb.database.Document;
|
|
import com.arcadedb.graph.Edge;
|
|
import com.arcadedb.graph.MutableVertex;
|
|
import com.arcadedb.graph.Vertex;
|
|
import com.arcadedb.remote.RemoteDatabase;
|
|
|
|
/**
|
|
* @author Luca Frosini (ISTI - CNR)
|
|
*/
|
|
public abstract class EntityElementManagement<E extends EntityElement, ET extends EntityType> extends ElementManagement<Vertex, ET> {
|
|
|
|
public final static String IN_PREFIX = "in_";
|
|
public final static String OUT_PREFIX = "out_";
|
|
|
|
/**
|
|
* Provide a cache edge-internal-id -> RelationManagement
|
|
* this avoid to recreate the relationManagement of already visited edges
|
|
*/
|
|
protected Map<String,RelationElementManagement<?,?,?,?>> relationManagements;
|
|
|
|
protected EntityElementManagement(AccessType accessType) {
|
|
super(accessType);
|
|
|
|
this.ignoreStartWithKeys.add(IN_PREFIX.toLowerCase());
|
|
this.ignoreStartWithKeys.add(OUT_PREFIX.toLowerCase());
|
|
this.ignoreStartWithKeys.add(IN_PREFIX.toUpperCase());
|
|
this.ignoreStartWithKeys.add(OUT_PREFIX.toUpperCase());
|
|
|
|
this.relationManagements = new HashMap<>();
|
|
|
|
}
|
|
|
|
protected EntityElementManagement(AccessType accessType, SecurityContext workingContext, RemoteDatabase database) {
|
|
this(accessType);
|
|
this.database = database;
|
|
setWorkingContext(workingContext);
|
|
}
|
|
|
|
/*
|
|
* It works perfectly in case of any kind of update. In case of use from create
|
|
* the cache does not work by using the ID because until commit the edge has a
|
|
* fake id starting with - (minus) sign. This not imply any collateral effect
|
|
* but a better solution is a desiderata.
|
|
*/
|
|
protected RelationElementManagement<?,?,?,?> getBaseRelationManagement(Edge edge) throws ResourceRegistryException {
|
|
String id = edge.getIdentity().toString();
|
|
RelationElementManagement<?,?,?,?> relationManagement = relationManagements.get(id);
|
|
if(relationManagement == null) {
|
|
relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(), database, edge);
|
|
relationManagements.put(id, relationManagement);
|
|
}
|
|
return relationManagement;
|
|
}
|
|
|
|
protected void addToRelationManagement(RelationElementManagement<?,?,?,?> baseRelationManagement)
|
|
throws ResourceRegistryException {
|
|
Document elem = baseRelationManagement.getElement();
|
|
String id = elem.getIdentity().toString();
|
|
if(relationManagements.get(id) != null && relationManagements.get(id) != baseRelationManagement) {
|
|
StringBuilder errorMessage = new StringBuilder();
|
|
errorMessage.append("Two different instance of ");
|
|
errorMessage.append(baseRelationManagement.getClass().getSimpleName());
|
|
errorMessage.append(" point to the same ");
|
|
errorMessage.append(elem.getClass().getSimpleName());
|
|
errorMessage.append(". ");
|
|
errorMessage.append(DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
throw new ResourceRegistryException(errorMessage.toString());
|
|
}
|
|
relationManagements.put(id, baseRelationManagement);
|
|
}
|
|
|
|
protected static JsonNode addRelation(JsonNode sourceResource, JsonNode relation, String arrayKey)
|
|
throws ResourceRegistryException {
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
ArrayNode relationArray = objectMapper.createArrayNode();
|
|
try {
|
|
if(sourceResource.has(arrayKey)) {
|
|
relationArray = (ArrayNode) sourceResource.get(arrayKey);
|
|
}
|
|
relationArray.add(relation);
|
|
|
|
((ObjectNode) sourceResource).replace(arrayKey, relationArray);
|
|
} catch(Exception e) {
|
|
throw new ResourceRegistryException(e);
|
|
}
|
|
return sourceResource;
|
|
}
|
|
|
|
protected Vertex createVertex() throws EntityAlreadyPresentException, ResourceRegistryException {
|
|
|
|
logger.trace("Going to create {} for {} ({}) using {}", Vertex.class.getSimpleName(), accessType.getName(),
|
|
typeName, jsonNode);
|
|
|
|
try {
|
|
|
|
// TODO
|
|
// if(documentType.isAbstract()) {
|
|
// String error = String.format(
|
|
// "Trying to create an instance of %s of type %s which is abstract. The operation will be aborted.",
|
|
// accessType.getName(), typeName);
|
|
// throw new ResourceRegistryException(error);
|
|
// }
|
|
|
|
try {
|
|
if(uuid != null) {
|
|
Vertex v = getElement();
|
|
if(v != null) {
|
|
String error = String.format("A %s with UUID %s already exist", typeName, uuid.toString());
|
|
throw getSpecificAlreadyPresentException(error);
|
|
}
|
|
}
|
|
|
|
} catch(NotFoundException e) {
|
|
try {
|
|
Document el = ElementManagementUtility.getAnyElementByUUID(uuid);
|
|
String error = String.format("UUID %s is already used by another Element. This is not allowed.",
|
|
uuid.toString(),
|
|
(el instanceof Vertex) ? EntityElement.NAME : RelationElement.NAME);
|
|
throw new ResourceRegistryException(error);
|
|
|
|
} catch(NotFoundException e1) {
|
|
// OK the UUID is not already used.
|
|
}
|
|
} catch(AvailableInAnotherContextException e) {
|
|
throw e;
|
|
}
|
|
|
|
MutableVertex vertexEntity = database.newVertex(typeName);
|
|
this.element = vertexEntity;
|
|
|
|
if(accessType == AccessType.RESOURCE) {
|
|
// Facet and relation are created in calling method
|
|
} else {
|
|
updateProperties(documentType, element, jsonNode, ignoreKeys, ignoreStartWithKeys);
|
|
}
|
|
|
|
logger.info("Created {} is {}", Vertex.class.getSimpleName(),
|
|
DBUtility.getAsStringForLogging(element));
|
|
|
|
return element;
|
|
} catch(ResourceRegistryException e) {
|
|
throw e;
|
|
} catch(Exception e) {
|
|
logger.trace("Error while creating {} for {} ({}) using {}", Vertex.class.getSimpleName(),
|
|
accessType.getName(), typeName, jsonNode, e);
|
|
throw new ResourceRegistryException("Error Creating " + typeName + " with " + jsonNode, e.getCause());
|
|
}
|
|
}
|
|
|
|
}
|