resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/entities/EntityElementManagement.java

173 lines
7.2 KiB
Java

package org.gcube.informationsystem.resourceregistry.instances.base.entities;
import java.util.HashMap;
import java.util.Map;
import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.base.reference.entities.EntityElement;
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.entity.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.Utility;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.OEdge;
import com.orientechnologies.orient.core.record.OElement;
import com.orientechnologies.orient.core.record.OVertex;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class EntityElementManagement<E extends EntityElement> extends ElementManagement<OVertex> {
/**
* Provide a cache edge-internal-id -> RelationManagement
* this avoid to recreate the relationManagement of already visited edges
*/
@SuppressWarnings("rawtypes")
protected Map<String,RelationElementManagement> relationManagements;
protected EntityElementManagement(AccessType accessType) {
super(accessType);
this.ignoreKeys.add(EntityElement.HEADER_PROPERTY);
this.ignoreStartWithKeys.add(com.tinkerpop.blueprints.impls.orient.OrientVertex.CONNECTION_IN_PREFIX.toLowerCase());
this.ignoreStartWithKeys.add(com.tinkerpop.blueprints.impls.orient.OrientVertex.CONNECTION_OUT_PREFIX.toLowerCase());
this.ignoreStartWithKeys.add(com.tinkerpop.blueprints.impls.orient.OrientVertex.CONNECTION_IN_PREFIX.toUpperCase());
this.ignoreStartWithKeys.add(com.tinkerpop.blueprints.impls.orient.OrientVertex.CONNECTION_OUT_PREFIX.toUpperCase());
this.relationManagements = new HashMap<>();
}
protected EntityElementManagement(AccessType accessType, SecurityContext workingContext, ODatabaseDocument oDatabaseDocument) {
this(accessType);
this.oDatabaseDocument = oDatabaseDocument;
setWorkingContext(workingContext);
}
@SuppressWarnings("rawtypes")
/*
* 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(OEdge edge) throws ResourceRegistryException {
String id = edge.getIdentity().toString();
RelationElementManagement relationManagement = relationManagements.get(id);
if(relationManagement == null) {
relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(), oDatabaseDocument, edge);
relationManagements.put(id, relationManagement);
}
return relationManagement;
}
protected void addToRelationManagement(@SuppressWarnings("rawtypes") RelationElementManagement baseRelationManagement)
throws ResourceRegistryException {
OElement 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(Utility.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 OVertex createVertex() throws EntityAlreadyPresentException, ResourceRegistryException {
logger.trace("Going to create {} for {} ({}) using {}", OVertex.class.getSimpleName(), accessType.getName(),
elementType, jsonNode);
try {
if(oClass.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(), elementType);
throw new ResourceRegistryException(error);
}
OVertex vertexEntity = oDatabaseDocument.newVertex(elementType);
try {
if(uuid != null) {
OVertex v = getElement();
if(v != null) {
String error = String.format("A %s with UUID %s already exist", elementType, uuid.toString());
throw getSpecificERAlreadyPresentException(error);
}
}
} catch(NotFoundException e) {
try {
OElement el = ElementManagementUtility.getAnyElementByUUID(uuid);
String error = String.format("UUID %s is already used by another %s. This is not allowed.",
uuid.toString(),
(el instanceof OVertex) ? org.gcube.informationsystem.model.reference.entities.Entity.NAME :
org.gcube.informationsystem.model.reference.relations.Relation.NAME);
throw getSpecificERAvailableInAnotherContextException(error);
} catch(NotFoundException e1) {
// OK the UUID is not already used.
}
} catch(AvailableInAnotherContextException e) {
throw e;
}
this.element = vertexEntity;
if(accessType == AccessType.RESOURCE) {
// Facet and relation are created in calling method
} else {
ElementManagement.updateProperties(oClass, element, jsonNode, ignoreKeys, ignoreStartWithKeys);
}
logger.info("Created {} is {}", OVertex.class.getSimpleName(),
Utility.toJsonString(element, true));
return element;
} catch(ResourceRegistryException e) {
throw e;
} catch(Exception e) {
logger.trace("Error while creating {} for {} ({}) using {}", OVertex.class.getSimpleName(),
accessType.getName(), elementType, jsonNode, e);
throw new ResourceRegistryException("Error Creating " + elementType + " with " + jsonNode, e.getCause());
}
}
}