Instances are now validate with the defined schema #18216 and #7355

This commit is contained in:
Luca Frosini 2021-02-23 17:31:46 +01:00
parent 151ad9add4
commit 83ca22a15e
8 changed files with 144 additions and 25 deletions

View File

@ -4,13 +4,16 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [v4.1.0-SNAPSHOT]
- Prepared Query has been fixed to properly consider polymorphic parameter and provided constraint [#20298]
- Added type update but the API is not exposed via REST [#20316]
- Generalised the definition of the type of a property [#20516]
- Add/Remove to/from Context return the list of affected instances and not just success or failure code [#20555]
- Added the possibility to have a dry run Add/Remove to/from Context [#20530]
- Relation source-target instace types are validated against Relation schema [#7355]
- The instances are validated with the defined schema [#18216]
- Added Types Cache [#18496]
- Superclasses in instances are ordered and does not include internal basic types [#20517]
- Redesigned Sharing REST collection [#20530][#20555]
- Added the possibility to have a dry run Add/Remove to/from Context [#20530]
- Add/Remove to/from Context return the list of affected instances and not just success or failure code [#20555]
- Generalised the definition of the type of a property [#20516]
- Added type update but the API is not exposed via REST [#20316]
- Prepared Query has been fixed to properly consider polymorphic parameter and provided constraint [#20298]
## [v4.0.0]

View File

@ -5,6 +5,7 @@ import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.context.reference.entities.Context;
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.isparentof.IsParentOfAlreadyPresentException;
@ -114,4 +115,10 @@ public class IsParentOfManagement extends RelationElementManagement<ContextManag
// Nothing to do
}
@Override
protected void checksourceAndTargetEntityCompliancy() throws NotFoundException, AvailableInAnotherContextException,
SchemaViolationException, ResourceRegistryException {
// The compliancy is ensured by the code
}
}

View File

@ -46,6 +46,7 @@ import org.gcube.informationsystem.resourceregistry.utils.HeaderOrient;
import org.gcube.informationsystem.resourceregistry.utils.HeaderUtility;
import org.gcube.informationsystem.resourceregistry.utils.Utility;
import org.gcube.informationsystem.types.reference.Type;
import org.gcube.informationsystem.types.reference.entities.ResourceType;
import org.gcube.informationsystem.types.reference.properties.PropertyDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -1093,6 +1094,20 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
return stringBuffer.toString();
}
protected boolean typeSatified(TypesCache typesCache, String requiredType, String effectiveType) throws SchemaException, ResourceRegistryException {
if(requiredType.compareTo(effectiveType)==0) {
return true;
}
@SuppressWarnings("unchecked")
CachedType<ResourceType> cachedType = (CachedType<ResourceType>) typesCache.getCachedType(requiredType);
if(cachedType.getSubTypes().contains(effectiveType)) {
return true;
}
return false;
}
/*
* Get not only the properties defined in the type but also the properties
* defined in the super types

View File

@ -7,9 +7,12 @@ 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;
@ -117,6 +120,8 @@ public abstract class RelationElementManagement<SEM extends EntityElementManagem
return relation;
}
protected abstract void checksourceAndTargetEntityCompliancy() throws NotFoundException, AvailableInAnotherContextException, SchemaViolationException, ResourceRegistryException;
@Override
protected OEdge reallyCreate() throws ResourceRegistryException {
@ -164,8 +169,7 @@ public abstract class RelationElementManagement<SEM extends EntityElementManagem
OVertex source = (OVertex) getSourceEntityManagement().getElement();
OVertex target = (OVertex) getTargetEntityManagement().getElement();
// TODO check source and target type compatibility
checksourceAndTargetEntityCompliancy();
logger.trace("Going to create {} beetween {} -> {}", typeName, source.toString(), target.toString());

View File

@ -366,20 +366,6 @@ public class ResourceManagement extends EntityManagement<Resource, ResourceType>
return stringBuffer.toString();
}
protected boolean typeSatified(TypesCache typesCache, String requiredType, String effectiveType) throws SchemaException, ResourceRegistryException {
if(requiredType.compareTo(effectiveType)==0) {
return true;
}
@SuppressWarnings("unchecked")
CachedType<ResourceType> cachedType = (CachedType<ResourceType>) typesCache.getCachedType(requiredType);
if(cachedType.getSubTypes().contains(effectiveType)) {
return true;
}
return false;
}
protected boolean constraintSatisfied(TypesCache typesCache, LinkedEntity constraint, String consistsOfType, String facetType) throws SchemaException, ResourceRegistryException {
String requiredSourceResourceType = constraint.getSource();
if(!typeSatified(typesCache, requiredSourceResourceType, typeName)) {

View File

@ -11,6 +11,7 @@ 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;
import org.gcube.informationsystem.base.reference.relations.RelationElement;
import org.gcube.informationsystem.context.reference.entities.Context;
import org.gcube.informationsystem.model.reference.entities.Entity;
import org.gcube.informationsystem.model.reference.entities.Resource;
@ -23,6 +24,7 @@ import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundExcep
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;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode;
@ -33,11 +35,13 @@ 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.types.TypesCache;
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.types.reference.entities.EntityType;
import org.gcube.informationsystem.types.reference.entities.ResourceType;
import org.gcube.informationsystem.types.reference.relations.RelationType;
import org.gcube.informationsystem.utils.ElementMapper;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
@ -165,12 +169,10 @@ public abstract class RelationManagement<T extends EntityManagement<? extends En
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
* RelationManagement.
*/
public ResourceManagement giveMeSourceEntityManagementAsIs() throws ResourceRegistryException {
return sourceEntityManagement;
@ -341,6 +343,46 @@ public abstract class RelationManagement<T extends EntityManagement<? extends En
protected abstract T newTargetEntityManagement() throws ResourceRegistryException;
protected String getEntityTypeNotValidErrroMessage(String entityPosition, String requiredType, String effectiveType) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("The ");
stringBuffer.append(entityPosition);
stringBuffer.append(" instance of the relation ");
stringBuffer.append(typeName);
stringBuffer.append(" is of type ");
stringBuffer.append(effectiveType);
stringBuffer.append(" which is not a specialisation of ");
stringBuffer.append(requiredType);
stringBuffer.append(".");
return stringBuffer.toString();
}
@Override
protected void checksourceAndTargetEntityCompliancy() throws NotFoundException, AvailableInAnotherContextException, SchemaViolationException, ResourceRegistryException {
String sourceType = sourceEntityManagement.getTypeName();
String targetType = targetEntityManagement.getTypeName();
RelationType<ResourceType, TET> relationType = getCachedType().getType();
ResourceType resourceType = relationType.getSource();
TET tet = relationType.getTarget();
String requiredSourceType = resourceType.getName();
String requiredTargetType = tet.getName();
TypesCache typesCache = TypesCache.getInstance();
if(!typeSatified(typesCache, requiredSourceType, sourceType)) {
String message = getEntityTypeNotValidErrroMessage(RelationElement.SOURCE_PROPERTY, requiredSourceType, sourceType);
throw new SchemaViolationException(message);
}
if(!typeSatified(typesCache, requiredTargetType, targetType)) {
String message = getEntityTypeNotValidErrroMessage(RelationElement.TARGET_PROPERTY, requiredTargetType, targetType);
throw new SchemaViolationException(message);
}
}
@Override
protected OEdge reallyUpdate() throws ResourceRegistryException {

View File

@ -5,11 +5,13 @@ import java.util.HashMap;
import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.model.reference.relations.Relation;
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
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.SchemaAlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaNotFoundException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
import org.gcube.informationsystem.resourceregistry.dbinitialization.DatabaseEnvironment;
@ -209,4 +211,10 @@ public abstract class RelationTypeDefinitionManagement<T extends EntityTypeDefin
return rtdm;
}
@Override
protected void checksourceAndTargetEntityCompliancy() throws NotFoundException, AvailableInAnotherContextException,
SchemaViolationException, ResourceRegistryException {
// The compliancy is ensured by the code
}
}

View File

@ -0,0 +1,54 @@
package org.gcube.informationsystem.resourceregistry.instances;
import org.gcube.informationsystem.resourceregistry.ContextTest;
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.instances.model.entities.ResourceManagement;
import org.gcube.informationsystem.resourceregistry.instances.model.relations.IsRelatedToManagement;
import org.gcube.resourcemanagement.model.reference.entities.resources.Configuration;
import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.Activates;
import org.junit.Test;
public class InvalidInstancesTest extends ContextTest {
public static final String ESERVICE = SmartgearResourcesTest.ESERVICE;
public static final String ACTIVATES = "{\"header\": {\"@class\": \"Header\",\"creator\": \"luca.frosini\",\"creationTime\": \"2021-02-23 16:45:58.358 +0100\",\"modifiedBy\": \"luca.frosini\",\"uuid\": \"83e9ece1-326c-4d24-a515-0fc6e68f31ef\",\"lastUpdateTime\": \"2021-02-23 16:45:58.358 +0100\"},\"propagationConstraint\": {\"@class\": \"PropagationConstraint\",\"add\": \"propagate\",\"remove\": \"cascade\"},\"@class\": \"Activates\",\"@superClasses\": [\"IsRelatedTo\"],\"source\": {\"header\": {\"@class\": \"Header\",\"creator\": \"luca.frosini\",\"creationTime\": \"2021-02-23 16:45:58.297 +0100\",\"modifiedBy\": \"luca.frosini\",\"uuid\": \"bf665e49-7c54-4984-bafe-a021757a7423\",\"lastUpdateTime\": \"2021-02-23 16:45:58.297 +0100\"},\"@class\": \"Configuration\"},\"target\": {\"header\": {\"@class\": \"Header\",\"creator\": \"luca.frosini\",\"creationTime\": \"2021-02-23 16:45:58.128 +0100\",\"modifiedBy\": \"luca.frosini\",\"uuid\": \"3ace4bd0-e5cd-49a3-97a8-a0a9468ce6d4\",\"lastUpdateTime\": \"2021-02-23 16:45:58.128 +0100\"},\"@class\": \"EService\"}}";
public static final String CONFIGURATION = "{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.382 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"bf665e49-7c54-4984-bafe-a021757a7423\",\"lastUpdateTime\":\"2021-02-23 16:45:58.382 +0100\"},\"@class\":\"Configuration\",\"@superClasses\":[\"ConfigurationTemplate\",\"GCubeResource\",\"Resource\"],\"consistsOf\":[{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.378 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"2233f303-497f-433d-9338-6ca16de34c1a\",\"lastUpdateTime\":\"2021-02-23 16:45:58.378 +0100\"},\"propagationConstraint\":{\"@class\":\"PropagationConstraint\",\"add\":\"propagate\",\"remove\":\"cascadeWhenOrphan\"},\"@class\":\"IsIdentifiedBy\",\"@superClasses\":[\"ConsistsOf\"],\"source\":{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.382 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"bf665e49-7c54-4984-bafe-a021757a7423\",\"lastUpdateTime\":\"2021-02-23 16:45:58.382 +0100\"},\"@class\":\"Configuration\",\"@superClasses\":[\"ConfigurationTemplate\",\"GCubeResource\",\"Resource\"]},\"target\":{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.375 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"5efc4c1f-f784-4682-a694-896bd7a3f321\",\"lastUpdateTime\":\"2021-02-23 16:45:58.375 +0100\"},\"type\":\"STRING\",\"persistent\":\"false\",\"value\":\"TEST\",\"@class\":\"IdentifierFacet\",\"@superClasses\":[\"ConsistsOf\"]}},{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.381 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"15055c47-32a1-412c-b6d8-c0d4c831cb95\",\"lastUpdateTime\":\"2021-02-23 16:45:58.381 +0100\"},\"propagationConstraint\":{\"@class\":\"PropagationConstraint\",\"add\":\"propagate\",\"remove\":\"cascadeWhenOrphan\"},\"@class\":\"ConsistsOf\",\"@superClasses\":[\"ConsistsOf\"],\"source\":{\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.382 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"bf665e49-7c54-4984-bafe-a021757a7423\",\"lastUpdateTime\":\"2021-02-23 16:45:58.382 +0100\"},\"@class\":\"Configuration\",\"@superClasses\":[\"ConfigurationTemplate\",\"GCubeResource\",\"Resource\"]},\"target\":{\"name\":\"test\",\"header\":{\"@class\":\"Header\",\"creator\":\"luca.frosini\",\"creationTime\":\"2021-02-23 16:45:58.380 +0100\",\"modifiedBy\":\"luca.frosini\",\"uuid\":\"9b71f04c-6f5d-4133-87aa-f37445e206b6\",\"lastUpdateTime\":\"2021-02-23 16:45:58.380 +0100\"},\"value\":\"test\",\"@class\":\"SimplePropertyFacet\",\"@superClasses\":[\"ConsistsOf\"]}}]}";
@Test(expected = SchemaViolationException.class)
public void createInvalidIsRealtedTo() throws Exception {
ResourceManagement configurationManagement = new ResourceManagement();
ResourceManagement eServiceManagement = new ResourceManagement();
try {
configurationManagement.setElementType(Configuration.NAME);
configurationManagement.setJson(CONFIGURATION);
configurationManagement.create();
eServiceManagement.setElementType(EService.NAME);
eServiceManagement.setJson(ESERVICE);
eServiceManagement.create();
/*
* Trying to create a relation activates between a Configuration and EService
* The creation MUST fails raising SchemaViolationException because the
* Activates relation is between two Service
*
* The only way to try to create it is using static string because Java classes
* already deny to create and instance of Activates
*
* Here we want to test how the service behave if a client does not behave properly
*/
IsRelatedToManagement isRelatedToManagement = new IsRelatedToManagement();
isRelatedToManagement.setElementType(Activates.NAME);
isRelatedToManagement.setJson(ACTIVATES);
isRelatedToManagement.create();
}finally {
configurationManagement.delete();
eServiceManagement.delete();
}
}
}