package org.gcube.informationsystem.resourceregistry.instances.base.relations; import java.util.UUID; import org.gcube.com.fasterxml.jackson.databind.JsonNode; 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.model.reference.relations.Relation; 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.relation.RelationNotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaException; import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException; import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext; import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement; import org.gcube.informationsystem.resourceregistry.instances.base.entities.EntityElementManagement; import org.gcube.informationsystem.resourceregistry.utils.Utility; import org.gcube.informationsystem.types.reference.entities.EntityType; import org.gcube.informationsystem.types.reference.relations.RelationType; import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.record.ODirection; import com.orientechnologies.orient.core.record.OEdge; import com.orientechnologies.orient.core.record.OVertex; /** * @author Luca Frosini (ISTI - CNR) */ public abstract class RelationElementManagement, TEM extends EntityElementManagement, SET extends EntityType, TET extends EntityType> extends ElementManagement> { public final static String IN = "in"; public final static String OUT = "out"; protected final Class sourceEntityClass; protected final Class targetEntityClass; protected SEM sourceEntityManagement; protected TEM targetEntityManagement; protected boolean includeSource; protected boolean includeTarget; protected RelationElementManagement(AccessType accessType, Class sourceEntityClass, Class targetEntityClass) { super(accessType); this.ignoreKeys.add(Relation.HEADER_PROPERTY); this.ignoreKeys.add(Relation.SOURCE_PROPERTY); this.ignoreKeys.add(Relation.TARGET_PROPERTY); this.ignoreKeys.add(IN.toLowerCase()); this.ignoreKeys.add(OUT.toLowerCase()); this.ignoreKeys.add(IN.toUpperCase()); this.ignoreKeys.add(OUT.toUpperCase()); this.sourceEntityClass = sourceEntityClass; this.targetEntityClass = targetEntityClass; this.sourceEntityManagement = null; this.targetEntityManagement = null; this.includeSource = true; this.includeTarget = true; } public void includeSource(boolean includeSource) { this.includeSource = includeSource; } public void includeTarget(boolean includeTarget) { this.includeTarget = includeTarget; } protected RelationElementManagement(AccessType accessType, Class sourceEntityClass, Class targetEntityClass, SecurityContext workingContext, ODatabaseDocument orientGraph) { this(accessType, sourceEntityClass, targetEntityClass); this.oDatabaseDocument = orientGraph; setWorkingContext(workingContext); } public SEM getSourceEntityManagement() throws ResourceRegistryException { if(sourceEntityManagement == null) { OVertex source = getElement().getVertex(ODirection.OUT); sourceEntityManagement = newSourceEntityManagement(); sourceEntityManagement.setElement(source); } sourceEntityManagement.setReload(reload); return sourceEntityManagement; } public TEM getTargetEntityManagement() throws ResourceRegistryException { if(targetEntityManagement == null) { OVertex target = getElement().getVertex(ODirection.IN); targetEntityManagement = newTargetEntityManagement(); targetEntityManagement.setElement(target); } targetEntityManagement.setReload(reload); return targetEntityManagement; } public void setSourceEntityManagement(SEM sourceEntityManagement) { this.sourceEntityManagement = sourceEntityManagement; } public void setTargetEntityManagement(TEM targetEntityManagement) { this.targetEntityManagement = targetEntityManagement; } @Override protected JsonNode createCompleteJsonNode() throws ResourceRegistryException { JsonNode relation = serializeSelfAsJsonNode(); try { if(includeSource) { EntityElementManagement sourceEntityManagement = getSourceEntityManagement(); ((ObjectNode) relation).replace(Relation.SOURCE_PROPERTY, sourceEntityManagement.serializeSelfAsJsonNode()); } if(includeTarget) { EntityElementManagement targetEntityManagement = getTargetEntityManagement(); ((ObjectNode) relation).replace(Relation.TARGET_PROPERTY, targetEntityManagement.serializeAsJsonNode()); } } catch(ResourceRegistryException e) { logger.error("Unable to correctly serialize {}. {}", element, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE, e); throw e; } catch(Exception e) { logger.error("Unable to correctly serialize {}. {}", element, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE, e); throw new ResourceRegistryException(e); } return relation; } protected abstract void checksourceAndTargetEntityCompliancy() throws NotFoundException, AvailableInAnotherContextException, SchemaViolationException, ResourceRegistryException; @Override protected OEdge reallyCreate() throws ResourceRegistryException { if(sourceEntityManagement == null) { if(!jsonNode.has(Relation.SOURCE_PROPERTY)) { throw new ResourceRegistryException("Error while creating relation. No source definition found"); } UUID sourceUUID = org.gcube.informationsystem.utils.Utility .getUUIDFromJsonNode(jsonNode.get(Relation.SOURCE_PROPERTY)); sourceEntityManagement = newSourceEntityManagement(); sourceEntityManagement.setUUID(sourceUUID); } if(targetEntityManagement == null) { targetEntityManagement = newTargetEntityManagement(); if(!jsonNode.has(Relation.TARGET_PROPERTY)) { throw new ResourceRegistryException( "Error while creating " + typeName + ". No target definition found"); } try { targetEntityManagement.setJsonNode(jsonNode.get(Relation.TARGET_PROPERTY)); } catch(SchemaException e) { StringBuilder errorMessage = new StringBuilder(); errorMessage.append("A "); errorMessage.append(typeName); errorMessage.append(" can be only created beetween "); errorMessage.append(sourceEntityManagement.getAccessType().getName()); errorMessage.append(" and "); errorMessage.append(targetEntityManagement.getAccessType().getName()); throw new SchemaViolationException(errorMessage.toString(), e); } try { targetEntityManagement.getElement(); } catch(Exception e) { targetEntityManagement.internalCreate(); } } OVertex source = (OVertex) getSourceEntityManagement().getElement(); OVertex target = (OVertex) getTargetEntityManagement().getElement(); checksourceAndTargetEntityCompliancy(); logger.trace("Going to create {} beetween {} -> {}", typeName, source.toString(), target.toString()); element = oDatabaseDocument.newEdge(source, target, typeName); updateProperties(oClass, element, jsonNode, ignoreKeys, ignoreStartWithKeys); return element; } protected abstract SEM newSourceEntityManagement() throws ResourceRegistryException; protected abstract TEM newTargetEntityManagement() throws ResourceRegistryException; @Override protected OEdge reallyUpdate() throws ResourceRegistryException { logger.debug("Trying to update {} : {}", typeName, jsonNode); OEdge edge = getElement(); updateProperties(oClass, edge, jsonNode, ignoreKeys, ignoreStartWithKeys); if(accessType.compareTo(AccessType.CONSISTS_OF) == 0) { JsonNode target = jsonNode.get(Relation.TARGET_PROPERTY); if(target != null) { targetEntityManagement = newTargetEntityManagement(); targetEntityManagement.setJsonNode(target); targetEntityManagement.internalUpdate(); } } logger.info("{} {} successfully updated", typeName, jsonNode); return edge; } @Override protected void reallyDelete() throws RelationNotFoundException, ResourceRegistryException { logger.debug("Going to remove {} with UUID {}. Related {}s will be detached.", accessType.getName(), uuid, targetEntityClass.getSimpleName()); affectedInstances.put(uuid, serializeAsAffectedInstance()); getElement().delete(); } }