From 27cec7ec31f91105ecb88c5ec6db928985048032 Mon Sep 17 00:00:00 2001 From: Luca Frosini Date: Wed, 27 Jan 2021 21:57:06 +0100 Subject: [PATCH] Add to Context deny to add a resource without adding at least a facet. Added a test to check the service behave properly --- .../instances/base/ElementManagement.java | 2 +- .../model/entities/ResourceManagement.java | 54 ++++++ .../instances/multicontext/BasicTest.java | 167 +++++++++++++++++- 3 files changed, 216 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/ElementManagement.java b/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/ElementManagement.java index 917909f..112d4af 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/ElementManagement.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/ElementManagement.java @@ -780,7 +780,7 @@ public abstract class ElementManagement { return affectedInstances; } catch(ResourceRegistryException e) { - logger.error("Unable to add {} with UUID {} to Context with UUID {}", elementType, uuid, contextUUID); + logger.error("Unable to add {} with UUID {} to Context with UUID {} - Cause is {}", elementType, uuid, contextUUID, e.getMessage()); if(oDatabaseDocument != null) { oDatabaseDocument.rollback(); } diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/instances/model/entities/ResourceManagement.java b/src/main/java/org/gcube/informationsystem/resourceregistry/instances/model/entities/ResourceManagement.java index 63a3b1c..2ecdcba 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/instances/model/entities/ResourceManagement.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/instances/model/entities/ResourceManagement.java @@ -1,14 +1,20 @@ package org.gcube.informationsystem.resourceregistry.instances.model.entities; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import java.util.UUID; import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.informationsystem.base.reference.AccessType; +import org.gcube.informationsystem.context.reference.entities.Context; +import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; 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.entity.resource.ResourceAlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.resource.ResourceAvailableInAnotherContextException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.resource.ResourceNotFoundException; @@ -224,6 +230,54 @@ public class ResourceManagement extends EntityManagement { return true; } + @Override + protected Map reallyAddToContext(SecurityContext targetSecurityContext) + throws ContextException, ResourceRegistryException { + + Map affectedInstances = new HashMap<>(); + + if(!dryRunContextSharing) { + targetSecurityContext.addElement(getElement(), oDatabaseDocument); + } + + /* + * DO NOT UNCOMMENT + * // affectedInstances.put(uuid, serializeSelfOnly()); + * the instance is added in internalAddToContext() function after + * the update of Header metadata i.e. modifiedBy, lastUpdateTime + */ + + Iterable edges = getElement().getEdges(ODirection.OUT); + + int facetCounter = 0; + + for(OEdge edge : edges) { + RelationManagement relationManagement = getRelationManagement(edge); + relationManagement.setDryRunContextSharing(dryRunContextSharing); + relationManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing); + Map resourceCharacterisationInstances = relationManagement.internalAddToContext(targetSecurityContext); + if(relationManagement instanceof ConsistsOfManagement) { + facetCounter = facetCounter + resourceCharacterisationInstances.size(); + } + affectedInstances.putAll(resourceCharacterisationInstances); + } + + if(facetCounter == 0) { + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append("Any "); + stringBuffer.append(Resource.NAME); + stringBuffer.append(" must "); + stringBuffer.append(ConsistsOf.NAME); + stringBuffer.append(" at least of one "); + stringBuffer.append(Facet.NAME); + stringBuffer.append(" in any "); + stringBuffer.append(Context.NAME); + throw new ResourceRegistryException(stringBuffer.toString()); + } + + return affectedInstances; + } + public String all(boolean polymorphic) throws ResourceRegistryException { try { oDatabaseDocument = getWorkingContext().getDatabaseDocument(PermissionMode.READER); diff --git a/src/test/java/org/gcube/informationsystem/resourceregistry/instances/multicontext/BasicTest.java b/src/test/java/org/gcube/informationsystem/resourceregistry/instances/multicontext/BasicTest.java index c6cfa75..1b6258c 100644 --- a/src/test/java/org/gcube/informationsystem/resourceregistry/instances/multicontext/BasicTest.java +++ b/src/test/java/org/gcube/informationsystem/resourceregistry/instances/multicontext/BasicTest.java @@ -23,6 +23,7 @@ import org.gcube.informationsystem.base.reference.IdentifiableElement; import org.gcube.informationsystem.context.reference.entities.Context; import org.gcube.informationsystem.model.impl.properties.HeaderImpl; import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl; +import org.gcube.informationsystem.model.reference.entities.Entity; import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.properties.Header; @@ -31,6 +32,7 @@ import org.gcube.informationsystem.model.reference.properties.PropagationConstra import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint; import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; +import org.gcube.informationsystem.model.reference.relations.Relation; import org.gcube.informationsystem.resourceregistry.ContextTest; import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache; import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCacheRenewal; @@ -88,6 +90,8 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.orientechnologies.orient.core.record.ODirection; + /** * @author Luca Frosini (ISTI - CNR) */ @@ -188,12 +192,161 @@ public class BasicTest extends ContextTest { Assert.assertTrue(deleted); } - // TODO test add to context to a resource with only one facet and add propagation constraint to unpropagate. - // TODO test remove from context to a facet which is the only facet that characterise a Resource. + @Test(expected = ResourceRegistryException.class) + public void testResourceWithOnlyOneFacet() throws Exception { + EService eService = new EServiceImpl(); + + SoftwareFacet softwareFacet = new SoftwareFacetImpl(); + softwareFacet.setGroup("InformationSystem"); + softwareFacet.setName("resource-registry"); + softwareFacet.setVersion("1.1.0"); + + PropagationConstraint propagationConstraint = new PropagationConstraintImpl(); + propagationConstraint.setAddConstraint(AddConstraint.unpropagate); + propagationConstraint.setRemoveConstraint(RemoveConstraint.cascade); + + IsIdentifiedBy isIdentifiedBy = new IsIdentifiedByImpl( + eService, softwareFacet, propagationConstraint); + eService.addFacet(isIdentifiedBy); + + ResourceManagement resourceManagement = new ResourceManagement(); + resourceManagement.setElementType(EService.NAME); + resourceManagement.setJson(ElementMapper.marshal(eService)); + + String json = resourceManagement.create(); + logger.debug("Created : {}", json); + eService = ElementMapper.unmarshal(EService.class, json); + logger.debug("Unmarshalled {} {}", EService.NAME, eService); + + /*------------------------------------------------------------------------*/ + + logger.debug("Switching to another context"); + ContextTest.setContextByName(ALTERNATIVE_TEST_SCOPE); + + try { + addToContextThenTestIfBehaveProperly(eService, true); + }finally { + UUID eServiceUUID = eService.getHeader().getUUID(); + resourceManagement = new ResourceManagement(); + resourceManagement.setUUID(eServiceUUID); + boolean deleted = resourceManagement.delete(); + Assert.assertTrue(deleted); + } + } - protected Map getAddedExpectedInstances(Resource r) { + protected Map getRemovedExpectedInstances(Resource r) { Map expected = new HashMap<>(); expected.put(r.getHeader().getUUID(), r); + // TODO query + + for(IsRelatedTo isRelatedTo : r.getIsRelatedTo()) { + // TODO + if(isRelatedTo.getPropagationConstraint().getRemoveConstraint() == RemoveConstraint.cascade) { + expected.put(isRelatedTo.getHeader().getUUID(), isRelatedTo); + expected.putAll(getRemovedExpectedInstances(isRelatedTo.getTarget())); + + // TODO + } + + if(isRelatedTo.getPropagationConstraint().getRemoveConstraint() == RemoveConstraint.cascadeWhenOrphan) { + expected.put(isRelatedTo.getHeader().getUUID(), isRelatedTo); + expected.putAll(getRemovedExpectedInstances(isRelatedTo.getTarget())); + + // TODO + + // TODO + } + } + for(ConsistsOf consistsOf : r.getConsistsOf()) { + if(consistsOf.getPropagationConstraint().getRemoveConstraint() == RemoveConstraint.cascade || consistsOf.getPropagationConstraint().getRemoveConstraint() == RemoveConstraint.cascadeWhenOrphan ) { + expected.put(consistsOf.getHeader().getUUID(), consistsOf); + Facet facet = consistsOf.getTarget(); + expected.put(facet.getHeader().getUUID(), facet); + } + } + return expected; + } + + protected void removeFromContextThenTestIfBehaveProperly(Resource r, boolean dryRun) throws ResourceRegistryException { + Map expectedInstances = getRemovedExpectedInstances(r); + + ResourceManagement resourceManagement = new ResourceManagement(); + resourceManagement.setElementType(TypeMapper.getType(r.getClass())); + resourceManagement.setUUID(r.getHeader().getUUID()); + resourceManagement.setDryRunContextSharing(dryRun); + UUID contextUUID = ContextUtility.getCurrentSecurityContext().getUUID(); + Map affectedInstances = resourceManagement.removeFromContext(contextUUID); + + SortedSet expectedInstancesUUID = new TreeSet<>(expectedInstances.keySet()); + SortedSet affectedInstancesUUID = new TreeSet<>(affectedInstances.keySet()); + + logger.trace("Expected Instances are {} : {}", expectedInstancesUUID.size(), expectedInstancesUUID); + logger.trace("Affected Instances are {} : {}", affectedInstancesUUID.size(), affectedInstancesUUID); + + Assert.assertTrue(expectedInstancesUUID.size()==affectedInstancesUUID.size()); + + Assert.assertTrue(expectedInstancesUUID.containsAll(affectedInstancesUUID)); + Assert.assertTrue(affectedInstancesUUID.containsAll(expectedInstancesUUID)); + + + for(UUID uuid : affectedInstances.keySet()) { + + Element element = expectedInstances.get(uuid); + String expectedType = TypeMapper.getType(element.getClass()); + + JsonNode affectedJsonNode = affectedInstances.get(uuid); + String affectedType = affectedJsonNode.get(Element.CLASS_PROPERTY).asText(); + + Assert.assertTrue(affectedType.compareTo(expectedType)==0); + + } + + } + + interface RelationConstraint { + + public boolean mustBeAdded(Relation r); + + } + + protected Resource getAndAddIsRelatedTo(Resource r, RelationConstraint relationConstraint) throws ResourceRegistryException, Exception { + ResourceManagement resourceManagement = new ResourceManagement(); + String resourceType = TypeMapper.getType(r); + // resourceManagement.setElementType(resourceType); + UUID resourceUUID = r.getHeader().getUUID(); + // resourceManagement.setUUID(resourceUUID); + String ret = resourceManagement.query(IsRelatedTo.NAME, resourceType, resourceUUID, ODirection.OUT, true, new HashMap<>()); + @SuppressWarnings("rawtypes") + List isRelatedToList = ElementMapper.unmarshalList(IsRelatedTo.class, ret); + for(@SuppressWarnings("rawtypes") IsRelatedTo isRelatedTo : isRelatedToList) { + @SuppressWarnings("unchecked") + boolean mustBeAdded = relationConstraint.mustBeAdded(isRelatedTo); + if(mustBeAdded) { + @SuppressWarnings("unchecked") + IsRelatedTo irt = (IsRelatedTo) isRelatedTo; + r.attachResource(irt); + } + } + return r; + } + + + + protected Map getAddedExpectedInstances(Resource r) throws ResourceRegistryException, Exception { + Map expected = new HashMap<>(); + expected.put(r.getHeader().getUUID(), r); + + RelationConstraint propagateConstraint = new RelationConstraint() { + + @Override + public boolean mustBeAdded(Relation r) { + return r.getPropagationConstraint().getAddConstraint() == AddConstraint.propagate; + } + + }; + + r = getAndAddIsRelatedTo(r, propagateConstraint); + for(IsRelatedTo isRelatedTo : r.getIsRelatedTo()) { if(isRelatedTo.getPropagationConstraint().getAddConstraint() == AddConstraint.propagate) { expected.put(isRelatedTo.getHeader().getUUID(), isRelatedTo); @@ -210,10 +363,11 @@ public class BasicTest extends ContextTest { return expected; } - protected void addToContextThenTestIfBehaveProperly(Resource r, boolean dryRun) throws ResourceRegistryException { + protected void addToContextThenTestIfBehaveProperly(Resource r, boolean dryRun) throws ResourceRegistryException, Exception { Map expectedInstances = getAddedExpectedInstances(r); ResourceManagement resourceManagement = new ResourceManagement(); + resourceManagement.setElementType(TypeMapper.getType(r)); resourceManagement.setUUID(r.getHeader().getUUID()); resourceManagement.setDryRunContextSharing(dryRun); UUID contextUUID = ContextUtility.getCurrentSecurityContext().getUUID(); @@ -361,6 +515,7 @@ public class BasicTest extends ContextTest { hostingNodeInstances.put(consistsOf.getTarget().getHeader().getUUID(), consistsOf.getTarget()); } + /* IsRelatedToManagement isRelatedToManagement = new IsRelatedToManagement(); isRelatedToManagement.setElementType(Activates.NAME); isRelatedToManagement.setUUID(activatedUUID); @@ -373,11 +528,11 @@ public class BasicTest extends ContextTest { activates = unmarshalledActivates; hostingNode.attachResource(activates); - + */ /* ------------------------------------------------------------------ */ - logger.debug("Switching to another scope"); + logger.debug("Switching to another context"); ContextTest.setContextByName(ALTERNATIVE_TEST_SCOPE); addToContextThenTestIfBehaveProperly(hostingNode, true);