resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/ermanagement/entity/EntityManagement.java

536 lines
15 KiB
Java
Raw Normal View History

/**
*
*/
package org.gcube.informationsystem.resourceregistry.ermanagement.entity;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.codehaus.jettison.json.JSONObject;
import org.gcube.informationsystem.model.embedded.Header;
import org.gcube.informationsystem.model.entity.Entity;
import org.gcube.informationsystem.model.entity.Facet;
import org.gcube.informationsystem.model.entity.Resource;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.EntityAlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.EntityNotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetNotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.resource.ResourceNotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaNotFoundException;
import org.gcube.informationsystem.resourceregistry.context.SecurityContextMapper;
import org.gcube.informationsystem.resourceregistry.context.SecurityContextMapper.PermissionMode;
import org.gcube.informationsystem.resourceregistry.ermanagement.ERManagement;
import org.gcube.informationsystem.resourceregistry.ermanagement.relation.RelationManagement;
import org.gcube.informationsystem.resourceregistry.resources.impl.SchemaManagementImpl;
import org.gcube.informationsystem.resourceregistry.resources.utils.ContextUtility;
import org.gcube.informationsystem.resourceregistry.resources.utils.HeaderUtility;
import org.gcube.informationsystem.resourceregistry.resources.utils.Utility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.tinkerpop.blueprints.impls.orient.OrientVertex;
import com.tinkerpop.blueprints.impls.orient.OrientVertexType;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class EntityManagement<E extends Entity> {
private static Logger logger = LoggerFactory
.getLogger(EntityManagement.class);
public final String AT = "@";
public final String UNDERSCORE = "_";
protected final Set<String> ignoreKeys;
protected final Set<String> ignoreStartWithKeys;
protected final Class<E> entityClass;
protected final String baseType;
protected OrientGraph orientGraph;
protected UUID uuid;
protected JsonNode jsonNode;
protected String entityType;
protected Vertex vertex;
protected EntityManagement(Class<E> entityClass) {
this.ignoreKeys = new HashSet<String>();
this.ignoreKeys.add(Entity.HEADER_PROPERTY);
this.ignoreStartWithKeys = new HashSet<String>();
this.ignoreStartWithKeys.add(OrientVertex.CONNECTION_IN_PREFIX
.toLowerCase());
this.ignoreStartWithKeys.add(OrientVertex.CONNECTION_OUT_PREFIX
.toLowerCase());
this.ignoreStartWithKeys.add(OrientVertex.CONNECTION_IN_PREFIX
.toUpperCase());
this.ignoreStartWithKeys.add(OrientVertex.CONNECTION_OUT_PREFIX
.toUpperCase());
this.ignoreStartWithKeys.add(AT);
this.ignoreStartWithKeys.add(UNDERSCORE);
this.entityClass = entityClass;
if (Facet.class.isAssignableFrom(entityClass)) {
this.baseType = Facet.NAME;
} else if (Resource.class.isAssignableFrom(entityClass)) {
this.baseType = Resource.NAME;
} else {
this.baseType = Entity.NAME;
}
}
protected EntityManagement(Class<E> entityClass, OrientGraph orientGraph) {
this(entityClass);
this.orientGraph = orientGraph;
}
public void setVertex(Vertex vertex) throws ResourceRegistryException {
if (vertex == null) {
throw new ResourceRegistryException("Trying to set null Vertex in "
+ this);
}
this.vertex = vertex;
this.uuid = HeaderUtility.getHeader(vertex).getUUID();
}
public void setUUID(UUID uuid) throws ResourceRegistryException {
this.uuid = uuid;
if (jsonNode != null) {
checkUUIDMatch();
}
}
public void setJSON(JsonNode jsonNode) throws ResourceRegistryException {
this.jsonNode = jsonNode;
checkJSON();
}
public void setJSON(String jsonRepresentation)
throws ResourceRegistryException {
ObjectMapper mapper = new ObjectMapper();
try {
this.jsonNode = mapper.readTree(jsonRepresentation);
} catch (IOException e) {
throw new ResourceRegistryException(e);
}
checkJSON();
}
protected void checkJSON() throws ResourceRegistryException {
if (uuid == null) {
try {
uuid = org.gcube.informationsystem.impl.utils.Utility
.getUUIDFromJsonNode(jsonNode);
} catch (Exception e) {
}
} else {
checkUUIDMatch();
}
if (this.entityType == null) {
this.entityType = ERManagement.getClassProperty(jsonNode);
} else {
checkEntityMatch();
}
}
public void setEntityType(String entityType)
throws ResourceRegistryException {
this.entityType = entityType;
if (entityType == null || entityType.compareTo("") == 0) {
if (Facet.class.isAssignableFrom(entityClass)) {
entityType = Facet.NAME;
}
if (Resource.class.isAssignableFrom(entityClass)) {
entityType = Resource.NAME;
}
}
if (jsonNode != null) {
checkEntityMatch();
}
}
protected void checkEntityMatch() throws ResourceRegistryException {
String type = ERManagement.getClassProperty(jsonNode);
if (type != null && type.compareTo(entityType) != 0) {
String error = String
.format("Declared resourceType does not match with json representation %s!=%s",
entityType, type);
logger.trace(error);
throw new ResourceRegistryException(error);
}
try {
SchemaManagementImpl.getTypeSchema(entityType, baseType);
} catch (SchemaNotFoundException e) {
throw e;
}
}
protected void checkUUIDMatch() throws ResourceRegistryException {
Header header = null;
try {
header = HeaderUtility.getHeader(jsonNode, false);
} catch (Exception e) {
throw new ResourceRegistryException(e);
}
if (header != null) {
UUID resourceUUID = header.getUUID();
if (resourceUUID.compareTo(uuid) != 0) {
String error = String
.format("UUID provided in header (%s) differs from the one (%s) used to identify the %s instance",
resourceUUID.toString(), uuid.toString(),
entityType);
throw new ResourceRegistryException(error);
}
}
}
public Vertex getVertex() throws EntityNotFoundException,
ResourceRegistryException {
try {
if (vertex == null) {
vertex = Utility.getElementByUUID(orientGraph,
entityType == null ? baseType : entityType, uuid,
Vertex.class);
}
return vertex;
} catch (ResourceRegistryException e) {
if (Resource.class.isAssignableFrom(entityClass)) {
throw new ResourceNotFoundException(e);
} else if (Facet.class.isAssignableFrom(entityClass)) {
throw new FacetNotFoundException(e);
} else {
throw e;
}
}
}
protected Vertex createVertex() throws EntityAlreadyPresentException,
ResourceRegistryException {
logger.trace("Going to create {} for {} ({}) using {}",
Vertex.class.getSimpleName(), baseType, entityType, jsonNode);
try {
Vertex vertexEntity = orientGraph.addVertex("class:" + entityType);
try {
Vertex v = getVertex();
if (v != null) {
String error = String.format(
"A %s with UUID %s already exist", entityType,
uuid.toString());
throw new EntityAlreadyPresentException(error);
}
} catch (EntityAlreadyPresentException e) {
throw e;
} catch (Exception e) {
// no header or no header with uuid is provided and it is fine
}
this.vertex = vertexEntity;
Header entityHeader = HeaderUtility.getHeader(jsonNode, true);
if (entityHeader != null) {
vertex.setProperty(Entity.HEADER_PROPERTY, entityHeader);
} else {
entityHeader = HeaderUtility.addHeader(vertex, null);
}
if (Resource.class.isAssignableFrom(entityClass)) {
// Facet and relation are created in calling method
} else {
ERManagement.updateProperties(vertex, jsonNode, ignoreKeys,
ignoreStartWithKeys);
}
ContextUtility.addToActualContext(orientGraph, vertex);
((OrientVertex) vertex).save();
logger.info("Created {} is {}", Vertex.class.getSimpleName(),
Utility.toJsonString((OrientVertex) vertex, true));
return vertex;
} catch (ResourceRegistryException e) {
throw e;
} catch (Exception e) {
logger.trace("Error while creating {} for {} ({}) using {}",
Vertex.class.getSimpleName(), baseType, entityType,
jsonNode, e);
throw new ResourceRegistryException("Error Creating " + entityType
+ " with " + jsonNode, e.getCause());
}
}
public abstract String serialize() throws ResourceRegistryException;
public abstract JSONObject serializeAsJson()
throws ResourceRegistryException;
public abstract Vertex reallyCreate() throws EntityAlreadyPresentException,
ResourceRegistryException;
public abstract Vertex reallyUpdate() throws EntityNotFoundException,
ResourceRegistryException;
public abstract boolean reallyDelete() throws EntityNotFoundException,
ResourceRegistryException;
public boolean reallyAddToContext() throws ContextException,
ResourceRegistryException {
ContextUtility.addToActualContext(orientGraph, getVertex());
Iterable<Edge> edges = vertex.getEdges(Direction.OUT);
for (Edge edge : edges) {
@SuppressWarnings("rawtypes")
RelationManagement relationManagement = RelationManagement
.getRelationManagement(orientGraph, edge);
relationManagement.reallyAddToContext();
}
return true;
}
public boolean reallyRemoveFromContext() throws ContextException,
ResourceRegistryException {
ContextUtility.removeFromActualContext(orientGraph, getVertex());
Iterable<Edge> edges = vertex.getEdges(Direction.OUT);
for (Edge edge : edges) {
@SuppressWarnings("rawtypes")
RelationManagement relationManagement = RelationManagement
.getRelationManagement(orientGraph, edge);
relationManagement.reallyRemoveFromContext();
}
return true;
}
@SuppressWarnings("rawtypes")
public static EntityManagement getEntityManagement(OrientGraph orientGraph,
Vertex vertex) throws ResourceRegistryException {
OrientVertexType orientVertexType = ((OrientVertex) vertex).getType();
EntityManagement entityManagement = null;
if (orientVertexType.isSubClassOf(Resource.NAME)) {
entityManagement = new ResourceManagement(orientGraph);
} else if (orientVertexType.isSubClassOf(Facet.NAME)) {
entityManagement = new FacetManagement(orientGraph);
} else {
String error = String.format("{%s is not a %s nor a %s. "
+ "This is really strange and should not occur. "
+ "Please Investigate it.", vertex, Resource.NAME,
Facet.NAME);
throw new ResourceRegistryException(error);
}
entityManagement.setVertex(vertex);
return entityManagement;
}
public String create() throws EntityAlreadyPresentException,
ResourceRegistryException {
try {
orientGraph = ContextUtility
.getActualSecurityContextGraph(PermissionMode.WRITER);
reallyCreate();
orientGraph.commit();
return serialize();
} catch (ResourceRegistryException e) {
if (orientGraph != null) {
orientGraph.rollback();
}
throw e;
} catch (Exception e) {
if (orientGraph != null) {
orientGraph.rollback();
}
throw new ResourceRegistryException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
public String read() throws EntityNotFoundException,
ResourceRegistryException {
try {
orientGraph = ContextUtility
.getActualSecurityContextGraph(PermissionMode.READER);
getVertex();
return serialize();
} catch (ResourceRegistryException e) {
throw e;
} catch (Exception e) {
throw new ResourceRegistryException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
public String update() throws EntityNotFoundException,
ResourceRegistryException {
try {
orientGraph = ContextUtility
.getActualSecurityContextGraph(PermissionMode.WRITER);
reallyUpdate();
orientGraph.commit();
return serialize();
} catch (ResourceRegistryException e) {
if (orientGraph != null) {
orientGraph.rollback();
}
throw e;
} catch (Exception e) {
logger.debug("Unable to update {} with UUID {} usign {}", baseType,
uuid, jsonNode, e);
if (orientGraph != null) {
orientGraph.rollback();
}
throw new ResourceRegistryException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
public boolean delete() throws FacetNotFoundException,
ResourceRegistryException {
logger.debug("Going to delete {} with UUID {}", baseType, uuid);
try {
orientGraph = ContextUtility
.getActualSecurityContextGraph(PermissionMode.WRITER);
boolean deleted = reallyDelete();
orientGraph.commit();
logger.info("{} with UUID {} was successfully deleted.", baseType,
uuid);
return deleted;
} catch (ResourceRegistryException e) {
logger.error("Unable to delete {} with UUID {}", baseType, uuid, e);
if (orientGraph != null) {
orientGraph.rollback();
}
throw e;
} catch (Exception e) {
logger.error("Unable to delete {} with UUID {}", baseType, uuid, e);
if (orientGraph != null) {
orientGraph.rollback();
}
throw new ResourceRegistryException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
public boolean addToContext() throws ContextException {
logger.debug("Going to add {} with UUID {} to actual Context",
baseType, uuid);
try {
orientGraph = SecurityContextMapper.getSecurityContextFactory(
SecurityContextMapper.ADMIN_SECURITY_CONTEXT_UUID,
PermissionMode.WRITER).getTx();
boolean added = reallyAddToContext();
orientGraph.commit();
logger.info("{} with UUID {} successfully added to actual Context",
baseType, uuid);
return added;
} catch (Exception e) {
logger.error("Unable to add {} with UUID {} to actual Context",
baseType, uuid, e);
if (orientGraph != null) {
orientGraph.rollback();
}
throw new ContextException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
public boolean removeFromContext() throws ContextException {
logger.debug("Going to remove {} with UUID {} from actual Context",
baseType, uuid);
try {
orientGraph = SecurityContextMapper.getSecurityContextFactory(
SecurityContextMapper.ADMIN_SECURITY_CONTEXT_UUID,
PermissionMode.WRITER).getTx();
boolean removed = reallyRemoveFromContext();
orientGraph.commit();
logger.info(
"{} with UUID {} successfully removed from actual Context",
baseType, uuid);
return removed;
} catch (Exception e) {
logger.error(
"Unable to remove {} with UUID {} from actual Context",
baseType, uuid, e);
if (orientGraph != null) {
orientGraph.rollback();
}
throw new ContextException(e);
} finally {
if (orientGraph != null) {
orientGraph.shutdown();
}
}
}
}