resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/instances/model/relations/RelationManagement.java

749 lines
29 KiB
Java
Raw Normal View History

2019-11-06 12:14:27 +01:00
package org.gcube.informationsystem.resourceregistry.instances.model.relations;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
2020-07-07 17:15:22 +02:00
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;
2021-02-05 17:50:16 +01:00
import org.gcube.informationsystem.context.reference.entities.Context;
import org.gcube.informationsystem.model.reference.entities.Entity;
import org.gcube.informationsystem.model.reference.entities.Resource;
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint;
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.AddConstraint;
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint;
import org.gcube.informationsystem.model.reference.relations.Relation;
2021-02-05 17:50:16 +01:00
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.context.ContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.relation.RelationNotFoundException;
2020-01-27 17:07:37 +01:00
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.instances.base.relations.RelationElementManagement;
2021-02-05 17:50:16 +01:00
import org.gcube.informationsystem.resourceregistry.instances.model.ERManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.EntityManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.FacetManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.ResourceManagement;
import org.gcube.informationsystem.resourceregistry.utils.HeaderUtility;
import org.gcube.informationsystem.resourceregistry.utils.PropagationConstraintOrient;
import org.gcube.informationsystem.resourceregistry.utils.Utility;
import org.gcube.informationsystem.utils.ElementMapper;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.ODirection;
import com.orientechnologies.orient.core.record.OEdge;
import com.orientechnologies.orient.core.record.OVertex;
import com.orientechnologies.orient.core.record.impl.ODocument;
/**
* @author Luca Frosini (ISTI - CNR)
*/
2019-11-08 12:29:32 +01:00
public abstract class RelationManagement<T extends EntityManagement<? extends Entity>>
2021-02-05 17:50:16 +01:00
extends RelationElementManagement<ResourceManagement, T> implements ERManagement {
2021-01-25 17:38:19 +01:00
/**
2021-02-05 17:50:16 +01:00
* By the default the system execute the the operation of
* context sharing so this variable is initialised as false.
*
* Setting this variable to false the system just simulate
* the operation of context sharing
* i.e. AddToContext, RemoveFromContext.
*
* This option can also be used in conjunction with
* {@link ElementManagement#honourPropagationConstraintsInContextSharing}=false.
* This allow to simulate a sharing operation which requires
* do not honour the propagation constraints.
2021-01-25 17:38:19 +01:00
*/
2021-02-05 17:50:16 +01:00
protected boolean dryRunContextSharing;
2021-01-25 17:38:19 +01:00
2021-02-05 17:50:16 +01:00
/**
* By the default the system honour the propagation constraints
* so this variable is initialised as true.
*
* To revert a previous operation or for particular a maintenance
* we could request to the service do not honour the propagation
* constraints but under certain conditions and with some limitation
* only.
* These limitation are required to keep the system in a consistent
* state.
* In fact, this directive is only valid for Resources and IsRelatedTo
* relations. We need to take in account that to add an
* IsRelatedTo to a context always the source and target
* Resources must be in such a Context.
* Please also take into account that adding a Resource
* to a context always imply to honour the propagation constraints
* of ConsistsOf relations. In fact, a resource must be characterised
* least by one facet in any context it belongs. Giving that we
* cannot made assumption on which facets must be used.
* A way could be to consider just the facets are mandatory for such a
* Resource Type, but the type could not have mandatory facets
* (even every Resource Type in the gCube Model has one mandatory facet).
* As counterpart, when a Resource is removed from a Context all the facets
* charactering it must be removed.
*
* This option can also be used in conjunction with
* {@link ElementManagement#dryRunContextSharing}=true.
* This allow to simulate a sharing operation which requires
* do not honour the propagation constraints.
*/
protected boolean honourPropagationConstraintsInContextSharing;
public boolean isDryRunContextSharing() {
return dryRunContextSharing;
}
public void setDryRunContextSharing(boolean dryRunContextSharing) {
this.dryRunContextSharing = dryRunContextSharing;
}
public boolean isHonourPropagationConstraintsInContextSharing() {
return honourPropagationConstraintsInContextSharing;
2021-01-25 17:38:19 +01:00
}
2021-02-05 17:50:16 +01:00
public void setHonourPropagationConstraintsInContextSharing(boolean honourPropagationConstraintsInContextSharing) {
this.honourPropagationConstraintsInContextSharing = honourPropagationConstraintsInContextSharing;
}
public final PropagationConstraint defaultPropagationConstraint;
2019-11-08 12:29:32 +01:00
protected RelationManagement(AccessType accessType, Class<? extends Entity> targetEntityClass, PropagationConstraint defaultPropagationConstraint) {
super(accessType, Resource.class, targetEntityClass);
this.defaultPropagationConstraint = defaultPropagationConstraint;
this.superClassesToBeExcluded.add(AccessType.RELATION_ELEMENT.getName());
this.superClassesToBeExcluded.add(AccessType.RELATION.getName());
2021-02-05 17:50:16 +01:00
/*
* By the default the system execute the the operation of
* context sharing so this variable is initialised as false.
*/
this.dryRunContextSharing = false;
/*
* By the default the system honour the propagation constraints
* so this variable is initialised as true.
*/
this.honourPropagationConstraintsInContextSharing = true;
}
protected PropagationConstraint propagationConstraint;
2021-02-05 17:50:16 +01:00
@Override
public OEdge getElement() throws NotFoundException, AvailableInAnotherContextException, ResourceRegistryException {
try {
element = super.getElement();
} catch(NotFoundException e) {
try {
retrieveElementFromAnyContext();
throw getSpecificERAvailableInAnotherContextException(elementType == null ? accessType.getName()
: elementType + " with UUID " + uuid + " is available in another "
+ Context.class.getSimpleName());
} catch(AvailableInAnotherContextException e1) {
throw e1;
} catch(Exception e1) {
throw e;
}
} catch(ResourceRegistryException e) {
throw e;
} catch(Exception e) {
throw new ResourceRegistryException(e);
}
return element;
}
/*
* Needed for ResourceManagement.serializeAsJson() function to check that
* sourceEntityManagement is the same of the instance is creating this
* RelationManagement. TODO Look for a workaround
*/
public ResourceManagement giveMeSourceEntityManagementAsIs() throws ResourceRegistryException {
return sourceEntityManagement;
}
public ResourceManagement getSourceEntityManagement() throws ResourceRegistryException {
if(sourceEntityManagement == null) {
OVertex source = getElement().getVertex(ODirection.OUT);
sourceEntityManagement = newSourceEntityManagement();
sourceEntityManagement.setElement(source);
}
sourceEntityManagement.setReload(reload);
return sourceEntityManagement;
}
public T 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(ResourceManagement resourceManagement) {
this.sourceEntityManagement = resourceManagement;
}
public void setTargetEntityManagement(T targetEntityManagement) {
this.targetEntityManagement = targetEntityManagement;
}
@Override
public JsonNode serializeAsJson() throws ResourceRegistryException {
return serializeAsJson(true, true);
}
public JsonNode serializeAsJson(boolean includeSource, boolean includeTarget) throws ResourceRegistryException {
JsonNode relation = serializeSelfOnly();
try {
if(includeSource) {
EntityManagement<? extends Resource> sourceEntityManagement = getSourceEntityManagement();
((ObjectNode) relation).replace(Relation.SOURCE_PROPERTY, sourceEntityManagement.serializeSelfOnly());
}
if(includeTarget) {
2019-11-08 12:29:32 +01:00
EntityManagement<? extends Entity> targetEntityManagement = getTargetEntityManagement();
((ObjectNode) relation).replace(Relation.TARGET_PROPERTY, targetEntityManagement.serializeAsJson());
}
} 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 Map<String,JsonNode> fullSerialize(Map<String,JsonNode> visitedSourceResources)
throws ResourceRegistryException {
OVertex source = getElement().getVertex(ODirection.OUT);
String id = source.getIdentity().toString();
JsonNode sourceResource = visitedSourceResources.get(id);
ResourceManagement resourceManagement = null;
if(sourceResource == null) {
resourceManagement = (ResourceManagement) ElementManagementUtility.getEntityManagement(getWorkingContext(),
oDatabaseDocument, source);
if(this instanceof IsRelatedToManagement) {
sourceResource = resourceManagement.serializeAsJson();
} else if(this instanceof ConsistsOfManagement) {
sourceResource = resourceManagement.serializeSelfOnly();
} else {
String error = String.format("{%s is not a %s nor a %s. %s", this,
IsRelatedToManagement.class.getSimpleName(), ConsistsOfManagement.class.getSimpleName(),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
throw new ResourceRegistryException(error);
}
}
if(this instanceof IsRelatedToManagement) {
sourceResource = ResourceManagement.addIsRelatedTo(sourceResource, serializeAsJson());
} else if(this instanceof ConsistsOfManagement) {
sourceResource = ResourceManagement.addConsistsOf(sourceResource, serializeAsJson());
} else {
String error = String.format("{%s is not a %s nor a %s. %s", this,
IsRelatedToManagement.class.getSimpleName(), ConsistsOfManagement.class.getSimpleName(),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
throw new ResourceRegistryException(error);
}
visitedSourceResources.put(id, sourceResource);
return visitedSourceResources;
}
protected PropagationConstraintOrient getPropagationConstraint(ODocument oDocument)
throws ResourceRegistryException {
PropagationConstraintOrient propagationConstraintOrient = new PropagationConstraintOrient();
PropagationConstraint propagationConstraint = null;
if(oDocument == null) {
propagationConstraint = defaultPropagationConstraint;
} else if(oDocument instanceof PropagationConstraintOrient) {
propagationConstraint = (PropagationConstraint) oDocument;
} else {
try {
propagationConstraint = ElementMapper.unmarshal(PropagationConstraint.class, oDocument.toJSON());
} catch(Exception e) {
logger.warn("Unable to recreate {}. {}", PropagationConstraint.NAME,
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
}
}
AddConstraint addConstraint = propagationConstraint.getAddConstraint();
if(addConstraint == null) {
addConstraint = defaultPropagationConstraint.getAddConstraint();
logger.warn("Unable to get {}. Default value ({}) will be used", AddConstraint.class.getSimpleName(),
addConstraint);
}
propagationConstraintOrient.setAddConstraint(addConstraint);
RemoveConstraint removeConstraint = propagationConstraint.getRemoveConstraint();
if(removeConstraint == null) {
removeConstraint = defaultPropagationConstraint.getRemoveConstraint();
logger.warn("Unable to get {}. Default value ({}) will be used", RemoveConstraint.class.getSimpleName(),
removeConstraint);
}
propagationConstraintOrient.setRemoveConstraint(removeConstraint);
return propagationConstraintOrient;
}
protected void checkPropagationConstraint() throws ResourceRegistryException {
Object object = getElement().getProperty(Relation.PROPAGATION_CONSTRAINT_PROPERTY);
PropagationConstraintOrient pc = getPropagationConstraint((ODocument) object);
getElement().setProperty(Relation.PROPAGATION_CONSTRAINT_PROPERTY, pc, OType.EMBEDDED);
}
@Override
protected OEdge reallyCreate() throws ResourceRegistryException {
element = super.reallyCreate();
checkPropagationConstraint();
logger.info("{} successfully created", elementType);
return element;
}
protected ResourceManagement newSourceEntityManagement() throws ResourceRegistryException {
2021-02-10 15:45:48 +01:00
ResourceManagement resourceManagement = new ResourceManagement();
resourceManagement.setWorkingContext(getWorkingContext());
resourceManagement.setoDatabaseDocument(oDatabaseDocument);
return resourceManagement;
}
protected abstract T newTargetEntityManagement() throws ResourceRegistryException;
@Override
protected OEdge reallyUpdate() throws ResourceRegistryException {
logger.debug("Trying to update {} : {}", elementType, jsonNode);
OEdge edge = getElement();
2021-02-08 16:26:58 +01:00
updateProperties(oClass, edge, jsonNode, ignoreKeys, ignoreStartWithKeys);
if(accessType.compareTo(AccessType.CONSISTS_OF) == 0) {
JsonNode target = jsonNode.get(Relation.TARGET_PROPERTY);
if(target != null) {
2021-02-10 15:45:48 +01:00
FacetManagement facetManagement = new FacetManagement();
facetManagement.setWorkingContext(getWorkingContext());
facetManagement.setoDatabaseDocument(oDatabaseDocument);
facetManagement.setJsonNode(target);
facetManagement.internalUpdate();
}
}
logger.info("{} {} successfully updated", elementType, jsonNode);
return edge;
}
2021-02-05 17:50:16 +01:00
protected Map<UUID,JsonNode> reallyAddToContext(SecurityContext targetSecurityContext)
throws ContextException, ResourceRegistryException {
getElement();
Map<UUID,JsonNode> affectedInstances = new HashMap<>();
if(honourPropagationConstraintsInContextSharing) {
AddConstraint addConstraint = AddConstraint.unpropagate;
try {
propagationConstraint = Utility.getPropertyDocument(PropagationConstraint.class, element,
Relation.PROPAGATION_CONSTRAINT_PROPERTY);
if(propagationConstraint.getAddConstraint() != null) {
addConstraint = propagationConstraint.getAddConstraint();
} else {
String error = String.format("%s.%s in %s is null. %s", Relation.PROPAGATION_CONSTRAINT_PROPERTY,
PropagationConstraint.ADD_PROPERTY, Utility.toJsonString(element, true),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
logger.error(error);
throw new ResourceRegistryException(error);
}
} catch(Exception e) {
String error = String.format("Error while getting %s from %s while performing AddToContext. %s",
Relation.PROPAGATION_CONSTRAINT_PROPERTY, Utility.toJsonString(element, true),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
logger.warn(error);
throw new ResourceRegistryException(error, e);
}
switch(addConstraint) {
case propagate:
/*
* The relation must be added only in the case the target vertex must be added.
* Otherwise we have a relation which point to an entity outside of the context.
*/
T targetEntityManagement = getTargetEntityManagement();
targetEntityManagement.setDryRunContextSharing(dryRunContextSharing);
targetEntityManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing);
affectedInstances.putAll(targetEntityManagement.internalAddToContext(targetSecurityContext));
if(!dryRunContextSharing) {
targetSecurityContext.addElement(getElement(), oDatabaseDocument);
}
/*
* DO NOT UNCOMMENT
* // affectedInstances.put(uuid, serializeSelfOnly());
* the relation instance is added in internalAddToContext() function after
* the update of Header metadata i.e. modifiedBy, lastUpdateTime
*/
break;
case unpropagate:
break;
default:
break;
}
}else {
if(!dryRunContextSharing) {
targetSecurityContext.addElement(getElement(), oDatabaseDocument);
}
/*
* DO NOT UNCOMMENT
* // affectedInstances.put(uuid, serializeSelfOnly());
* the relation instance is added in internalAddToContext() function after
* the update of Header metadata i.e. modifiedBy, lastUpdateTime
*/
}
return affectedInstances;
}
public Map<UUID,JsonNode> internalAddToContext(SecurityContext targetSecurityContext)
throws ContextException, ResourceRegistryException {
try {
Map<UUID,JsonNode> affectedInstances = reallyAddToContext(targetSecurityContext);
if(propagationConstraint.getAddConstraint()==PropagationConstraint.AddConstraint.propagate) {
if(!dryRunContextSharing) {
HeaderUtility.updateModifiedByAndLastUpdate(element);
element.save();
}
affectedInstances.put(uuid, serializeSelfOnly());
}
return affectedInstances;
} catch(ResourceRegistryException e) {
throw e;
} catch(Exception e) {
throw new ResourceRegistryException(
"Error Adding " + elementType + " to " + targetSecurityContext.toString(), e.getCause());
}
}
2021-01-25 17:38:19 +01:00
public Map<UUID,JsonNode> forcedAddToContext(SecurityContext targetSecurityContext)
throws ContextException, ResourceRegistryException {
getElement();
2021-01-25 17:38:19 +01:00
Map<UUID,JsonNode> affectedInstances = new HashMap<>();
/* Adding source to Context */
ResourceManagement resourceManagement = getSourceEntityManagement();
resourceManagement.setDryRunContextSharing(dryRunContextSharing);
resourceManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing);
affectedInstances.putAll(resourceManagement.internalAddToContext(targetSecurityContext));
/* Adding target to Context */
T targetEntityManagement = getTargetEntityManagement();
targetEntityManagement.setDryRunContextSharing(dryRunContextSharing);
targetEntityManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing);
2021-01-25 17:38:19 +01:00
affectedInstances.putAll(getTargetEntityManagement().internalAddToContext(targetSecurityContext));
if(!dryRunContextSharing) {
targetSecurityContext.addElement(getElement(), oDatabaseDocument);
}
2021-01-25 17:38:19 +01:00
affectedInstances.put(uuid, serializeSelfOnly());
2021-01-25 17:38:19 +01:00
return affectedInstances;
}
2021-02-05 17:50:16 +01:00
public Map<UUID,JsonNode> addToContext(UUID contextUUID) throws NotFoundException, ContextException {
logger.debug("Going to add {} with UUID {} to Context with UUID {}", accessType.getName(), uuid, contextUUID);
try {
oDatabaseDocument = ContextUtility.getAdminSecurityContext().getDatabaseDocument(PermissionMode.WRITER);
SecurityContext targetSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(contextUUID);
Map<UUID,JsonNode> added = forcedAddToContext(targetSecurityContext);
oDatabaseDocument.commit();
logger.info("{} with UUID {} successfully added to Context with UUID {}", accessType.getName(), uuid,
contextUUID);
return added;
} catch(Exception e) {
logger.error("Unable to add {} with UUID {} to Context with UUID {}", accessType.getName(), uuid,
contextUUID, e);
if(oDatabaseDocument != null) {
oDatabaseDocument.rollback();
}
throw new ContextException(e);
} finally {
if(oDatabaseDocument != null) {
oDatabaseDocument.close();
}
}
}
2021-01-25 17:38:19 +01:00
protected Map<UUID,JsonNode> reallyRemoveFromContext(SecurityContext targetSecurityContext)
throws ContextException, ResourceRegistryException {
getElement();
2021-01-25 17:38:19 +01:00
Map<UUID,JsonNode> affectedInstances = new HashMap<>();
RemoveConstraint removeConstraint = RemoveConstraint.keep;
try {
propagationConstraint = Utility.getPropertyDocument(PropagationConstraint.class, element,
Relation.PROPAGATION_CONSTRAINT_PROPERTY);
if(propagationConstraint.getRemoveConstraint() != null) {
removeConstraint = propagationConstraint.getRemoveConstraint();
} else {
String error = String.format("%s.%s in %s is null. %s", Relation.PROPAGATION_CONSTRAINT_PROPERTY,
PropagationConstraint.REMOVE_PROPERTY, Utility.toJsonString(element, true),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
logger.error(error);
throw new ResourceRegistryException(error);
}
} catch(Exception e) {
String error = String.format("Error while getting %s from %s while performing RemoveFromContext. %s",
Relation.PROPAGATION_CONSTRAINT_PROPERTY, Utility.toJsonString(element, true),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
logger.error(error);
throw new ResourceRegistryException(error, e);
}
/*
* In any removeConstraint value the relation MUST be removed from context to
* avoid to have edge having a source outside of the context.
*/
if(!dryRunContextSharing) {
targetSecurityContext.removeElement(getElement(), oDatabaseDocument);
}
2021-01-25 17:38:19 +01:00
affectedInstances.put(uuid, serializeSelfOnly());
T targetEntityManagement = getTargetEntityManagement();
targetEntityManagement.setDryRunContextSharing(dryRunContextSharing);
targetEntityManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing);
switch(removeConstraint) {
case cascade:
affectedInstances.putAll(targetEntityManagement.internalRemoveFromContext(targetSecurityContext));
break;
case cascadeWhenOrphan:
OVertex target = (OVertex) targetEntityManagement.getElement();
Iterable<OEdge> iterable = target.getEdges(ODirection.IN);
Iterator<OEdge> iterator = iterable.iterator();
int count = 0;
OEdge edge = null;
while(iterator.hasNext()) {
edge = (OEdge) iterator.next();
OEdge thisOEdge = (OEdge) getElement();
if(edge.compareTo(thisOEdge) != 0) {
if(thisOEdge.getVertex(ODirection.OUT).compareTo(edge.getVertex(ODirection.OUT)) != 0) {
count++;
break;
}
/*
* else{ ContextUtility.removeFromActualContext(orientGraph, edge); }
*/
}
}
if(count > 0) {
logger.trace(
2021-01-25 17:38:19 +01:00
"{} point to {} which is not orphan ({} exists). Giving {} directive, it will be not remove from {}.",
element, target, edge, removeConstraint, targetSecurityContext);
} else {
affectedInstances.putAll(targetEntityManagement.internalRemoveFromContext(targetSecurityContext));
}
break;
case keep:
break;
default:
break;
}
2021-01-25 17:38:19 +01:00
return affectedInstances;
}
2021-02-05 17:50:16 +01:00
public Map<UUID,JsonNode> internalRemoveFromContext(SecurityContext targetSecurityContext)
throws ContextException, ResourceRegistryException {
try {
Map<UUID,JsonNode> affectedInstances = reallyRemoveFromContext(targetSecurityContext);
if(!dryRunContextSharing) {
HeaderUtility.updateModifiedByAndLastUpdate(element);
element.save();
}
affectedInstances.put(uuid, serializeSelfOnly());
return affectedInstances;
} catch(ResourceRegistryException e) {
throw e;
} catch(Exception e) {
throw new ResourceRegistryException(
"Error Removing " + elementType + " from " + targetSecurityContext.toString(), e.getCause());
}
}
public Map<UUID,JsonNode> removeFromContext(UUID contextUUID)
throws NotFoundException, ContextException, ResourceRegistryException {
logger.debug("Going to remove {} with UUID {} from Context with UUID {}", elementType, uuid, contextUUID);
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
try {
oDatabaseDocument = ContextUtility.getAdminSecurityContext().getDatabaseDocument(PermissionMode.WRITER);
oDatabaseDocument.begin();
SecurityContext targetSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(contextUUID);
Map<UUID,JsonNode> affectedInstances = internalRemoveFromContext(targetSecurityContext);
oDatabaseDocument.commit();
logger.info("{} with UUID {} successfully removed from Context with UUID {}", elementType, uuid, contextUUID);
return affectedInstances;
} catch(ResourceRegistryException e) {
logger.error("Unable to remove {} with UUID {} from Context with UUID {}", elementType, uuid, contextUUID);
if(oDatabaseDocument != null) {
oDatabaseDocument.rollback();
}
throw e;
} catch(Exception e) {
logger.error("Unable to remove {} with UUID {} from Context with UUID {}", elementType, uuid, contextUUID,
e);
if(oDatabaseDocument != null) {
oDatabaseDocument.rollback();
}
throw new ContextException(e);
} finally {
if(oDatabaseDocument != null) {
oDatabaseDocument.close();
}
if(current!=null) {
current.activateOnCurrentThread();
}
}
}
@Override
protected boolean reallyDelete() throws RelationNotFoundException, ResourceRegistryException {
logger.debug("Going to remove {} with UUID {}. Related {}s will be detached.", accessType.getName(), uuid,
targetEntityClass.getSimpleName());
getElement();
RemoveConstraint removeConstraint = RemoveConstraint.keep;
try {
PropagationConstraint propagationConstraint = Utility.getPropertyDocument(PropagationConstraint.class,
element, Relation.PROPAGATION_CONSTRAINT_PROPERTY);
if(propagationConstraint.getRemoveConstraint() != null) {
removeConstraint = propagationConstraint.getRemoveConstraint();
} else {
String error = String.format("%s.%s in %s is null. %s", Relation.PROPAGATION_CONSTRAINT_PROPERTY,
PropagationConstraint.REMOVE_PROPERTY, Utility.toJsonString(element, true),
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
logger.error(error);
throw new ResourceRegistryException(error);
}
} catch(Exception e) {
logger.warn("Error while getting {} from {}. Assuming {}. {}", Relation.PROPAGATION_CONSTRAINT_PROPERTY,
Utility.toJsonString(element, true), removeConstraint, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
}
OVertex target = getTargetEntityManagement().getElement();
element.delete();
switch(removeConstraint) {
case cascade:
getTargetEntityManagement().internalDelete();
break;
case cascadeWhenOrphan:
Iterable<OEdge> iterable = target.getEdges(ODirection.IN);
Iterator<OEdge> iterator = iterable.iterator();
if(iterator.hasNext()) {
logger.trace("{} point to {} which is not orphan. Giving {} directive, it will be keep.", element,
target, removeConstraint);
} else {
getTargetEntityManagement().internalDelete();
}
break;
case keep:
break;
default:
break;
}
return true;
}
@SuppressWarnings("unchecked")
protected Collection<JsonNode> serializeEdges(Iterable<ODocument> edges, boolean postFilterPolymorphic)
throws ResourceRegistryException {
Map<String,JsonNode> visitedSourceResources = new HashMap<>();
for(ODocument d : edges) {
OEdge edge = (OEdge) d;
// TODO check because it was using compare
if(postFilterPolymorphic && getOClass().isSubClassOf(elementType)) {
continue;
}
RelationManagement<T> relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(),
oDatabaseDocument, edge);
visitedSourceResources = relationManagement.fullSerialize(visitedSourceResources);
}
return visitedSourceResources.values();
}
protected String serializeJsonNodeCollectionAsString(Collection<JsonNode> collection) throws ResourceRegistryException {
try {
ObjectMapper objectMapper = new ObjectMapper();
ArrayNode arrayNode = objectMapper.valueToTree(collection);
return objectMapper.writeValueAsString(arrayNode);
} catch(Exception e) {
throw new ResourceRegistryException(e);
}
}
@Override
public String reallyGetAll(boolean polymorphic) throws ResourceRegistryException {
Iterable<ODocument> edges = oDatabaseDocument.browseClass(elementType, polymorphic);
Collection<JsonNode> collection = serializeEdges(edges, false);
return serializeJsonNodeCollectionAsString(collection);
}
}