Implemented strategy to properly check resource sanity in case a delete

has been requested for a ConsistsOf or a Facet.
This commit is contained in:
Luca Frosini 2021-03-04 21:57:01 +01:00
parent 42bb1a217a
commit 5a94aadce5
7 changed files with 216 additions and 25 deletions

View File

@ -446,7 +446,11 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
public boolean internalDelete() throws NotFoundException, ResourceRegistryException { public boolean internalDelete() throws NotFoundException, ResourceRegistryException {
setOperation(Operation.DELETE); setOperation(Operation.DELETE);
return reallyDelete(); boolean deleted = reallyDelete();
if(deleted) {
sanityCheck();
}
return deleted;
} }
public void setElement(El element) throws ResourceRegistryException { public void setElement(El element) throws ResourceRegistryException {
@ -1111,14 +1115,15 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
return superClasses; return superClasses;
} }
*/ */
/*
public boolean isAvailableOnContext(OElement element, SecurityContext securityContext) { public boolean isAvailableOnContext(SecurityContext securityContext) {
try { try {
return securityContext.isElementInContext(element); return securityContext.isElementInContext(element);
} catch (ResourceRegistryException e) { } catch (ResourceRegistryException e) {
return false; return false;
} }
} }
*/
protected String getNotNullErrorMessage(String fieldName) { protected String getNotNullErrorMessage(String fieldName) {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();

View File

@ -1,11 +1,15 @@
package org.gcube.informationsystem.resourceregistry.instances.model.entities; package org.gcube.informationsystem.resourceregistry.instances.model.entities;
import java.util.Map;
import java.util.UUID;
import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Facet;
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; 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.facet.FacetAlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetAlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetAvailableInAnotherContextException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetAvailableInAnotherContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetNotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.facet.FacetNotFoundException;
@ -23,6 +27,8 @@ import com.orientechnologies.orient.core.record.OVertex;
*/ */
public class FacetManagement extends EntityManagement<Facet, FacetType> { public class FacetManagement extends EntityManagement<Facet, FacetType> {
protected ResourceManagement resourceManagement;
public FacetManagement() { public FacetManagement() {
super(AccessType.FACET); super(AccessType.FACET);
} }
@ -60,9 +66,25 @@ public class FacetManagement extends EntityManagement<Facet, FacetType> {
return facet; return facet;
} }
@Override
protected Map<UUID,JsonNode> reallyRemoveFromContext()
throws ContextException, ResourceRegistryException {
if(entryPoint) {
OVertex oVertex = getElement().getVertices(ODirection.IN).iterator().next();
resourceManagement = new ResourceManagement();
resourceManagement.setElement(oVertex);
}
return super.reallyRemoveFromContext();
}
@Override @Override
protected boolean reallyDelete() throws FacetNotFoundException, ResourceRegistryException { protected boolean reallyDelete() throws FacetNotFoundException, ResourceRegistryException {
getElement().delete(); if(entryPoint) {
OVertex oVertex = getElement().getVertices(ODirection.IN).iterator().next();
resourceManagement = new ResourceManagement();
resourceManagement.setElement(oVertex);
}
element.delete();
return true; return true;
} }
@ -85,9 +107,11 @@ public class FacetManagement extends EntityManagement<Facet, FacetType> {
} }
ODatabaseDocument targetSecurityContextODatabaseDocument = null; ODatabaseDocument targetSecurityContextODatabaseDocument = null;
try { try {
OVertex oVertex = getElement().getVertices(ODirection.IN).iterator().next(); if(resourceManagement==null) {
ResourceManagement resourceManagement = new ResourceManagement(); OVertex oVertex = getElement().getVertices(ODirection.IN).iterator().next();
resourceManagement.setElement(oVertex); ResourceManagement resourceManagement = new ResourceManagement();
resourceManagement.setElement(oVertex);
}
switch (operation) { switch (operation) {
case CREATE: case DELETE: case CREATE: case DELETE:
resourceManagement.setWorkingContext(getWorkingContext()); resourceManagement.setWorkingContext(getWorkingContext());
@ -108,6 +132,8 @@ public class FacetManagement extends EntityManagement<Facet, FacetType> {
resourceManagement.setOperation(operation); resourceManagement.setOperation(operation);
resourceManagement.sanityCheck(); resourceManagement.sanityCheck();
}catch (ResourceRegistryException e) {
throw e;
}catch (Exception e) { }catch (Exception e) {
throw new ResourceRegistryException(e); throw new ResourceRegistryException(e);
}finally { }finally {

View File

@ -15,6 +15,7 @@ import org.gcube.informationsystem.model.reference.entities.Facet;
import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.entities.Resource;
import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo;
import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextException; import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextException;
@ -25,6 +26,7 @@ import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.Schema
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException; import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode; import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility; import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
import org.gcube.informationsystem.resourceregistry.instances.model.Operation;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.ConsistsOfManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.ConsistsOfManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.RelationManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.RelationManagement;
@ -391,6 +393,10 @@ public class ResourceManagement extends EntityManagement<Resource, ResourceType>
*/ */
@Override @Override
public void sanityCheck() throws SchemaViolationException, ResourceRegistryException { public void sanityCheck() throws SchemaViolationException, ResourceRegistryException {
if(entryPoint && operation == Operation.DELETE) {
return;
}
TypesCache typesCache = TypesCache.getInstance(); TypesCache typesCache = TypesCache.getInstance();
Set<LinkedEntity> consistsOfFacetConstraints = getResourceTypeConstraint(); Set<LinkedEntity> consistsOfFacetConstraints = getResourceTypeConstraint();
@ -400,10 +406,75 @@ public class ResourceManagement extends EntityManagement<Resource, ResourceType>
Iterable<OEdge> edges = getElement().getEdges(ODirection.OUT); Iterable<OEdge> edges = getElement().getEdges(ODirection.OUT);
for(OEdge edge : edges) { for(OEdge edge : edges) {
RelationManagement<?,?> relationManagement = getRelationManagement(edge);
if(!(relationManagement instanceof ConsistsOfManagement)) { String id = edge.getIdentity().toString();
continue; RelationManagement<?,?> relationManagement = relationManagements.get(id);
if(entryPoint) {
switch (operation) {
case ADD_TO_CONTEXT:
if(relationManagement == null) {
try {
relationManagement = ElementManagementUtility.getRelationManagement(targetSecurityContext, oDatabaseDocument, edge);
relationManagements.put(id, relationManagement);
}catch (AvailableInAnotherContextException e) {
continue;
}
}else {
/*
* The relation has been already managed in add to context so it has been added to the targetSecurityContext.
* The transaction is not yet committed so we need to consider as part of context without trying to load from
* DB with dedicated security connection.
*/
}
break;
case REMOVE_FROM_CONTEXT:
if(relationManagement != null) {
/*
* The relation has been removed from the targetContext but it has not been committed.
* We must consider as not available in targetSecurityContext
*/
continue;
}else {
relationManagement = ElementManagementUtility.getRelationManagement(targetSecurityContext, oDatabaseDocument, edge);
relationManagements.put(id, relationManagement);
}
break;
case CREATE: case UPDATE:
if(relationManagement == null) {
relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(), oDatabaseDocument, edge);
relationManagements.put(id, relationManagement);
/*
* Here the AvailableInAnotherContextException should not occur because the connection to the DB is with the
* context role and not with admin as in addToContext/removeFromContext
*/
}else {
/*
* During create and update the relation could be still not be in the context because the
* transaction is still to be committed. We use the pending instance of relation management
* to evaluate the instance.
*/
}
break;
default:
break;
}
}else {
if(relationManagement==null) {
relationManagement = getRelationManagement(edge);
}
} }
if(!(relationManagement instanceof ConsistsOfManagement)) {
continue;
}
String consistsOfType = relationManagement.getTypeName(); String consistsOfType = relationManagement.getTypeName();
String facetType = relationManagement.getTargetEntityManagement().getTypeName(); String facetType = relationManagement.getTargetEntityManagement().getTypeName();

View File

@ -109,16 +109,16 @@ public class ConsistsOfManagement extends RelationManagement<FacetManagement, Fa
ODatabaseDocument targetSecurityContextODatabaseDocument = null; ODatabaseDocument targetSecurityContextODatabaseDocument = null;
try { try {
OVertex oVertex = getElement().getVertex(ODirection.OUT); ResourceManagement resourceManagement = getSourceEntityManagement();
ResourceManagement resourceManagement = new ResourceManagement();
resourceManagement.setElement(oVertex);
switch (operation) { switch (operation) {
case CREATE: case DELETE: case CREATE: case DELETE:
resourceManagement.setWorkingContext(getWorkingContext());
resourceManagement.setODatabaseDocument(oDatabaseDocument);
break; break;
case ADD_TO_CONTEXT: case REMOVE_FROM_CONTEXT: case ADD_TO_CONTEXT: case REMOVE_FROM_CONTEXT:
resourceManagement = new ResourceManagement();
resourceManagement.setElementType(sourceEntityManagement.getTypeName());
resourceManagement.setUUID(sourceEntityManagement.getUUID());
resourceManagement.setWorkingContext(targetSecurityContext); resourceManagement.setWorkingContext(targetSecurityContext);
targetSecurityContextODatabaseDocument = targetSecurityContext.getDatabaseDocument(PermissionMode.READER); targetSecurityContextODatabaseDocument = targetSecurityContext.getDatabaseDocument(PermissionMode.READER);
resourceManagement.setODatabaseDocument(targetSecurityContextODatabaseDocument); resourceManagement.setODatabaseDocument(targetSecurityContextODatabaseDocument);
@ -128,9 +128,10 @@ public class ConsistsOfManagement extends RelationManagement<FacetManagement, Fa
// You should not be here // You should not be here
return; return;
} }
resourceManagement.setOperation(operation);
resourceManagement.sanityCheck(); resourceManagement.sanityCheck();
}catch (ResourceRegistryException e) {
throw e;
}catch (Exception e) { }catch (Exception e) {
throw new ResourceRegistryException(e); throw new ResourceRegistryException(e);
}finally { }finally {

View File

@ -580,6 +580,8 @@ public abstract class RelationManagement<T extends EntityManagement<? extends En
throws ContextException, ResourceRegistryException { throws ContextException, ResourceRegistryException {
getElement(); getElement();
getSourceEntityManagement().getElement();
Map<UUID,JsonNode> affectedInstances = new HashMap<>(); Map<UUID,JsonNode> affectedInstances = new HashMap<>();
RemoveConstraint removeConstraint = RemoveConstraint.keep; RemoveConstraint removeConstraint = RemoveConstraint.keep;
@ -733,6 +735,8 @@ public abstract class RelationManagement<T extends EntityManagement<? extends En
getElement(); getElement();
getSourceEntityManagement().getElement();
RemoveConstraint removeConstraint = RemoveConstraint.keep; RemoveConstraint removeConstraint = RemoveConstraint.keep;
try { try {

View File

@ -31,7 +31,10 @@ import org.gcube.informationsystem.model.reference.relations.IsRelatedTo;
import org.gcube.informationsystem.resourceregistry.ContextTest; import org.gcube.informationsystem.resourceregistry.ContextTest;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.query.InvalidQueryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.query.InvalidQueryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility; import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.FacetManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.ResourceManagement; import org.gcube.informationsystem.resourceregistry.instances.model.entities.ResourceManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.ConsistsOfManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.ConsistsOfManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement;
@ -230,7 +233,94 @@ public class ERManagementTest extends ContextTest {
return configuration; return configuration;
} }
@Test
public void testCreateEServiceAndDeleteRequiredFacet() throws Exception {
EService eService = instantiateValidEService();
ResourceManagement resourceManagement = new ResourceManagement();
resourceManagement.setElementType(EService.NAME);
resourceManagement.setJson(ElementMapper.marshal(eService));
String createEServiceString = resourceManagement.create();
EService createEService = ElementMapper.unmarshal(EService.class, createEServiceString);
@SuppressWarnings("unchecked")
IsIdentifiedBy<EService, SoftwareFacet> isIdentifiedBy = (IsIdentifiedBy<EService, SoftwareFacet>) createEService.getConsistsOf(IsIdentifiedBy.class).get(0);
ConsistsOfManagement consistsOfManagement = new ConsistsOfManagement();
consistsOfManagement.setElementType(IsIdentifiedBy.NAME);
consistsOfManagement.setUUID(isIdentifiedBy.getHeader().getUUID());
try {
consistsOfManagement.delete();
throw new Exception("You should not be able to delete a mandatory ConsistsOf");
}catch (SchemaViolationException e) {
// As expected
}catch (Exception e) {
resourceManagement.delete();
throw e;
}
SoftwareFacet softwareFacet = isIdentifiedBy.getTarget();
FacetManagement facetManagement = new FacetManagement();
facetManagement.setElementType(SoftwareFacet.NAME);
facetManagement.setUUID(softwareFacet.getHeader().getUUID());
try {
facetManagement.delete();
throw new Exception("You should not be able to delete a mandatory Facet");
}catch (SchemaViolationException e) {
// As expected
}catch (Exception e) {
resourceManagement.delete();
throw e;
}
resourceManagement.delete();
}
@Test
public void testCreateEServiceAndRemoveFromContextRequiredFacet() throws Exception {
EService eService = instantiateValidEService();
ResourceManagement resourceManagement = new ResourceManagement();
resourceManagement.setElementType(EService.NAME);
resourceManagement.setJson(ElementMapper.marshal(eService));
String createEServiceString = resourceManagement.create();
EService createEService = ElementMapper.unmarshal(EService.class, createEServiceString);
@SuppressWarnings("unchecked")
IsIdentifiedBy<EService, SoftwareFacet> isIdentifiedBy = (IsIdentifiedBy<EService, SoftwareFacet>) createEService.getConsistsOf(IsIdentifiedBy.class).get(0);
ConsistsOfManagement consistsOfManagement = new ConsistsOfManagement();
consistsOfManagement.setElementType(IsIdentifiedBy.NAME);
consistsOfManagement.setUUID(isIdentifiedBy.getHeader().getUUID());
try {
consistsOfManagement.removeFromContext(ContextUtility.getCurrentSecurityContext().getUUID());
throw new Exception("You should not be able to delete a mandatory ConsistsOf");
}catch (SchemaViolationException e) {
// As expected
}catch (Exception e) {
resourceManagement.delete();
throw e;
}
SoftwareFacet softwareFacet = isIdentifiedBy.getTarget();
FacetManagement facetManagement = new FacetManagement();
facetManagement.setElementType(SoftwareFacet.NAME);
facetManagement.setUUID(softwareFacet.getHeader().getUUID());
try {
facetManagement.removeFromContext(ContextUtility.getCurrentSecurityContext().getUUID());
throw new Exception("You should not be able to delete a mandatory Facet");
}catch (SchemaViolationException e) {
// As expected
}catch (Exception e) {
resourceManagement.delete();
throw e;
}
resourceManagement.delete();
}
@Test @Test
public void testCreateFacetWithAdditionlEncryptedField() throws Exception { public void testCreateFacetWithAdditionlEncryptedField() throws Exception {

View File

@ -12,7 +12,6 @@ import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.informationsystem.base.reference.IdentifiableElement; import org.gcube.informationsystem.base.reference.IdentifiableElement;
import org.gcube.informationsystem.context.reference.entities.Context; import org.gcube.informationsystem.context.reference.entities.Context;
import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl; import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl;
import org.gcube.informationsystem.model.reference.entities.Facet;
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint; 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.AddConstraint;
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint; import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint;
@ -35,15 +34,10 @@ import org.gcube.informationsystem.resourceregistry.instances.model.entities.Res
import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement; import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement;
import org.gcube.informationsystem.utils.ElementMapper; import org.gcube.informationsystem.utils.ElementMapper;
import org.gcube.resourcemanagement.model.impl.entities.facets.CPUFacetImpl; import org.gcube.resourcemanagement.model.impl.entities.facets.CPUFacetImpl;
import org.gcube.resourcemanagement.model.impl.entities.facets.SoftwareFacetImpl;
import org.gcube.resourcemanagement.model.impl.entities.resources.EServiceImpl;
import org.gcube.resourcemanagement.model.impl.relations.consistsof.IsIdentifiedByImpl;
import org.gcube.resourcemanagement.model.impl.relations.isrelatedto.ActivatesImpl; import org.gcube.resourcemanagement.model.impl.relations.isrelatedto.ActivatesImpl;
import org.gcube.resourcemanagement.model.reference.entities.facets.CPUFacet; import org.gcube.resourcemanagement.model.reference.entities.facets.CPUFacet;
import org.gcube.resourcemanagement.model.reference.entities.facets.SoftwareFacet;
import org.gcube.resourcemanagement.model.reference.entities.resources.EService; import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode; import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode;
import org.gcube.resourcemanagement.model.reference.relations.consistsof.IsIdentifiedBy;
import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.Activates; import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.Activates;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;