From 6a3688cc89bee6640feda4b6cfc72f4d752914f5 Mon Sep 17 00:00:00 2001 From: Luca Frosini Date: Wed, 15 Jan 2020 11:55:39 +0100 Subject: [PATCH] Adding the possibility to define the Resource Schema refs #18213 --- .../model/reference/entities/Resource.java | 11 +++ .../types/annotations/ResourceSchema.java | 11 +-- .../annotations/ResourceSchemaEntry.java | 11 ++- .../ResourceSchemaRelatedEntry.java | 46 +++++++++ .../types/impl/TypeDefinitionImpl.java | 81 +++++++++++++--- .../ResourceEntryDefinitionImpl.java | 97 +++++++++++++++++++ .../properties/ResourceEntryDefinition.java | 51 ++++++++++ 7 files changed, 286 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaRelatedEntry.java create mode 100644 src/main/java/org/gcube/informationsystem/types/impl/properties/ResourceEntryDefinitionImpl.java create mode 100644 src/main/java/org/gcube/informationsystem/types/reference/properties/ResourceEntryDefinition.java diff --git a/src/main/java/org/gcube/informationsystem/model/reference/entities/Resource.java b/src/main/java/org/gcube/informationsystem/model/reference/entities/Resource.java index bc59181..8226a87 100644 --- a/src/main/java/org/gcube/informationsystem/model/reference/entities/Resource.java +++ b/src/main/java/org/gcube/informationsystem/model/reference/entities/Resource.java @@ -9,6 +9,9 @@ import java.util.UUID; import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; import org.gcube.informationsystem.types.annotations.Abstract; +import org.gcube.informationsystem.types.annotations.ResourceSchema; +import org.gcube.informationsystem.types.annotations.ResourceSchemaEntry; +import org.gcube.informationsystem.types.annotations.ResourceSchemaRelatedEntry; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -20,6 +23,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Abstract @JsonIgnoreProperties(ignoreUnknown=true) // @JsonDeserialize(as=ResourceImpl.class) Do not uncomment to manage subclasses +@ResourceSchema( + facets={ + @ResourceSchemaEntry(relation=ConsistsOf.class, facet=Facet.class, min=1, description="Any Resource consists of one or more Facets which describes the different aspects of the resource."), + }, + resources= { + @ResourceSchemaRelatedEntry(source=Resource.class, relation=IsRelatedTo.class, target=Resource.class, description="Any Resource can be related to any other resource.") + } +) public interface Resource extends Entity { public static final String NAME = "Resource"; //Resource.class.getSimpleName(); diff --git a/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchema.java b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchema.java index e91ff70..5b1b7d8 100644 --- a/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchema.java +++ b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchema.java @@ -5,21 +5,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.gcube.informationsystem.model.reference.entities.Entity; -import org.gcube.informationsystem.types.TypeBinder; -import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; - /** * @author Luca Frosini (ISTI - CNR) - * It is used by {@link TypeBinder} to identify which getter method are - * related to and {@link Entity} {@link PropertyDefinition}. - * The name of the property is obtained by removing "get" or "is" from method - * name and lower casing the first letter. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ResourceSchema { - ResourceSchemaEntry[] value(); + ResourceSchemaEntry[] facets() default {}; + ResourceSchemaRelatedEntry[] resources() default {}; } diff --git a/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaEntry.java b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaEntry.java index b622d07..8be728e 100644 --- a/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaEntry.java +++ b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaEntry.java @@ -11,6 +11,8 @@ import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.types.TypeBinder; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * @author Luca Frosini (ISTI - CNR) * It is used by {@link TypeBinder} to identify which getter method are @@ -23,12 +25,17 @@ import org.gcube.informationsystem.types.reference.properties.PropertyDefinition public @interface ResourceSchemaEntry { @SuppressWarnings("rawtypes") - Class consistOfType() default ConsistsOf.class; - Class targetFacetType() default Facet.class; + @JsonProperty + Class relation() default ConsistsOf.class; + @JsonProperty + Class facet() default Facet.class; + @JsonProperty String description() default ""; + @JsonProperty int min() default 0; + @JsonProperty int max() default -1; diff --git a/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaRelatedEntry.java b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaRelatedEntry.java new file mode 100644 index 0000000..2286a98 --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/types/annotations/ResourceSchemaRelatedEntry.java @@ -0,0 +1,46 @@ +package org.gcube.informationsystem.types.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.gcube.informationsystem.model.reference.entities.Entity; +import org.gcube.informationsystem.model.reference.entities.Resource; +import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; +import org.gcube.informationsystem.types.TypeBinder; +import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author Luca Frosini (ISTI - CNR) + * It is used by {@link TypeBinder} to identify which getter method are + * related to and {@link Entity} {@link PropertyDefinition}. + * The name of the property is obtained by removing "get" or "is" from method + * name and lower casing the first letter. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ResourceSchemaRelatedEntry { + + @JsonProperty + Class source() default Resource.class; + + @SuppressWarnings("rawtypes") + @JsonProperty + Class relation() default IsRelatedTo.class; + + @JsonProperty + Class target() default Resource.class; + + @JsonProperty + String description() default ""; + + @JsonProperty + int min() default 0; + + @JsonProperty + int max() default -1; + +} diff --git a/src/main/java/org/gcube/informationsystem/types/impl/TypeDefinitionImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/TypeDefinitionImpl.java index 38e6b6a..207b9fc 100644 --- a/src/main/java/org/gcube/informationsystem/types/impl/TypeDefinitionImpl.java +++ b/src/main/java/org/gcube/informationsystem/types/impl/TypeDefinitionImpl.java @@ -3,7 +3,9 @@ package org.gcube.informationsystem.types.impl; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.TypeVariable; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.gcube.informationsystem.base.impl.ERImpl; @@ -15,12 +17,17 @@ import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.types.TypeBinder; import org.gcube.informationsystem.types.annotations.Abstract; import org.gcube.informationsystem.types.annotations.ISProperty; +import org.gcube.informationsystem.types.annotations.ResourceSchema; +import org.gcube.informationsystem.types.annotations.ResourceSchemaEntry; +import org.gcube.informationsystem.types.annotations.ResourceSchemaRelatedEntry; import org.gcube.informationsystem.types.impl.entities.EntityTypeDefinitionImpl; import org.gcube.informationsystem.types.impl.properties.PropertyDefinitionImpl; import org.gcube.informationsystem.types.impl.properties.PropertyTypeDefinitionImpl; +import org.gcube.informationsystem.types.impl.properties.ResourceEntryDefinitionImpl; import org.gcube.informationsystem.types.impl.relations.RelationTypeDefinitionImpl; import org.gcube.informationsystem.types.reference.TypeDefinition; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; +import org.gcube.informationsystem.types.reference.properties.ResourceEntryDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,6 +53,8 @@ public class TypeDefinitionImpl extends ERImpl implements TypeDefinition { protected boolean abstractType; protected Set superClasses; protected Set properties; + protected List facets; + protected List resources; protected static Set retrieveSuperClasses(Class type, Class baseClass, String topSuperClass){ Set interfaceList = new HashSet<>(); @@ -104,16 +113,27 @@ public class TypeDefinitionImpl extends ERImpl implements TypeDefinition { @SuppressWarnings({"rawtypes", "unchecked"}) public static TypeDefinition getInstance(Class clz) { - if(BaseEntity.class.isAssignableFrom(clz)) { - return new EntityTypeDefinitionImpl((Class) clz); - } else if(BaseRelation.class.isAssignableFrom(clz)){ - return new RelationTypeDefinitionImpl((Class>) clz); - } else if(BaseProperty.class.isAssignableFrom(clz)){ - return new PropertyTypeDefinitionImpl(clz); - } else if(TypeDefinition.class.isAssignableFrom(clz)) { - return new TypeDefinitionImpl(clz); - } else { - throw new RuntimeException("Serialization required"); + TypeDefinition typeDefinition = null; + try { + if(BaseEntity.class.isAssignableFrom(clz)) { + typeDefinition = new EntityTypeDefinitionImpl((Class) clz); + return typeDefinition; + } else if(BaseRelation.class.isAssignableFrom(clz)){ + typeDefinition = new RelationTypeDefinitionImpl((Class>) clz); + return typeDefinition; + } else if(BaseProperty.class.isAssignableFrom(clz)){ + typeDefinition = new PropertyTypeDefinitionImpl(clz); + return typeDefinition; + } else if(TypeDefinition.class.isAssignableFrom(clz)) { + typeDefinition = new TypeDefinitionImpl(clz); + return typeDefinition; + } else { + throw new RuntimeException("Serialization required"); + } + } finally { + if(typeDefinition!=null) { + logger.debug("{} : {} ", clz, typeDefinition); + } } } @@ -130,9 +150,40 @@ public class TypeDefinitionImpl extends ERImpl implements TypeDefinition { if(!Resource.class.isAssignableFrom(clz)){ this.properties = retrieveListOfProperties(clz); + }else { + @SuppressWarnings("unchecked") + Class r = (Class) clz; + setResourceSchemaEntries(r); } - logger.trace("{} : {} ", clz, this); + } + + private void setResourceSchemaEntries(Class clz){ + if(clz.isAnnotationPresent(ResourceSchema.class)) { + this.facets = new ArrayList<>(); + this.resources = new ArrayList<>(); + ResourceSchema[] resourceSchemaArray = clz.getAnnotationsByType(ResourceSchema.class); + for(ResourceSchemaEntry resourceSchemaEntry : resourceSchemaArray[0].facets()) { + ResourceEntryDefinitionImpl resourceSchemaEntryDefinition = new ResourceEntryDefinitionImpl(); + resourceSchemaEntryDefinition.setSource(TypeBinder.getType(clz)); + resourceSchemaEntryDefinition.setRelation(TypeBinder.getType(resourceSchemaEntry.relation())); + resourceSchemaEntryDefinition.setTarget(TypeBinder.getType(resourceSchemaEntry.facet())); + resourceSchemaEntryDefinition.setDescription(resourceSchemaEntry.description()); + resourceSchemaEntryDefinition.setMin(resourceSchemaEntry.min()); + resourceSchemaEntryDefinition.setMax(resourceSchemaEntry.max()); + this.facets.add(resourceSchemaEntryDefinition); + } + for(ResourceSchemaRelatedEntry resourceSchemaRelatedEntry : resourceSchemaArray[0].resources()) { + ResourceEntryDefinition resourceSchemaEntryDefinition = new ResourceEntryDefinitionImpl(); + resourceSchemaEntryDefinition.setSource(TypeBinder.getType(resourceSchemaRelatedEntry.source())); + resourceSchemaEntryDefinition.setRelation(TypeBinder.getType(resourceSchemaRelatedEntry.relation())); + resourceSchemaEntryDefinition.setTarget(TypeBinder.getType(resourceSchemaRelatedEntry.target())); + resourceSchemaEntryDefinition.setDescription(resourceSchemaRelatedEntry.description()); + resourceSchemaEntryDefinition.setMin(resourceSchemaRelatedEntry.min()); + resourceSchemaEntryDefinition.setMax(resourceSchemaRelatedEntry.max()); + this.resources.add(resourceSchemaEntryDefinition); + } + } } @Override @@ -159,5 +210,13 @@ public class TypeDefinitionImpl extends ERImpl implements TypeDefinition { public Set getProperties() { return properties; } + + public List getFacets() { + return facets; + } + + public List getResources() { + return resources; + } } diff --git a/src/main/java/org/gcube/informationsystem/types/impl/properties/ResourceEntryDefinitionImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/properties/ResourceEntryDefinitionImpl.java new file mode 100644 index 0000000..f046b55 --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/types/impl/properties/ResourceEntryDefinitionImpl.java @@ -0,0 +1,97 @@ +/** + * + */ +package org.gcube.informationsystem.types.impl.properties; + +import org.gcube.informationsystem.base.impl.properties.BasePropertyImpl; +import org.gcube.informationsystem.types.reference.properties.ResourceEntryDefinition; + +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * @author Luca Frosini (ISTI - CNR) + */ +@JsonTypeName(value=ResourceEntryDefinition.NAME) +public final class ResourceEntryDefinitionImpl extends BasePropertyImpl implements ResourceEntryDefinition { + + /** + * Generated Serial Version UID + */ + private static final long serialVersionUID = -531978995960170532L; + + protected String source; + protected String relation; + protected String target; + protected String description; + protected Integer min; + protected Integer max; + + public ResourceEntryDefinitionImpl() { + super(); + } + + @Override + public String getSource() { + return source; + } + + @Override + public void setSource(String source) { + this.source = source; + } + + @Override + public String getRelation() { + return relation; + } + + @Override + public void setRelation(String relation) { + this.relation = relation; + } + + @Override + public String getTarget() { + return target; + } + + @Override + public void setTarget(String target) { + this.target = target; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public Integer getMin() { + return min; + } + + @Override + public void setMin(Integer min) { + this.min = min; + } + + @Override + public Integer getMax() { + return max; + } + + @Override + public void setMax(Integer max) { + if(max<=0) { + this.max = null; + }else { + this.max = max; + } + } + +} diff --git a/src/main/java/org/gcube/informationsystem/types/reference/properties/ResourceEntryDefinition.java b/src/main/java/org/gcube/informationsystem/types/reference/properties/ResourceEntryDefinition.java new file mode 100644 index 0000000..cbbb7f8 --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/types/reference/properties/ResourceEntryDefinition.java @@ -0,0 +1,51 @@ +package org.gcube.informationsystem.types.reference.properties; + +import org.gcube.informationsystem.base.reference.properties.BaseProperty; +import org.gcube.informationsystem.types.annotations.ISProperty; +import org.gcube.informationsystem.types.impl.properties.ResourceEntryDefinitionImpl; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +@JsonDeserialize(as=ResourceEntryDefinitionImpl.class) +public interface ResourceEntryDefinition extends BaseProperty { + + public static final String NAME = "ResourceEntryDefinition"; // ResourceSchemaEntryDefinition.class.getSimpleName(); + + public static final String SOURCE_PROPERTY = "source"; + public static final String RELATION_PROPERTY = "relation"; + public static final String TARGET_PROPERTY = "target"; + public static final String DESCRIPTION_PROPERTY = "description"; + public static final String MIN_PROPERTY = "min"; + public static final String MAX_PROPERTY = "max"; + + @ISProperty(name = SOURCE_PROPERTY, readonly = true, mandatory = true, nullable = false) + public String getSource(); + + public void setSource(String source); + + @ISProperty(name = RELATION_PROPERTY, readonly = true, mandatory = true, nullable = false) + public String getRelation(); + + public void setRelation(String relation); + + @ISProperty(name = TARGET_PROPERTY, readonly = true, mandatory = true, nullable = false) + public String getTarget(); + + public void setTarget(String target); + + @ISProperty(name = DESCRIPTION_PROPERTY, readonly = true, mandatory = true, nullable = false) + public String getDescription(); + + public void setDescription(String description); + + @ISProperty(name = MIN_PROPERTY, readonly = false, mandatory = true, nullable = false) + public Integer getMin(); + + public void setMin(Integer min); + + @ISProperty(name = MAX_PROPERTY, readonly = false, mandatory = true, nullable = true) + public Integer getMax(); + + public void setMax(Integer max); + +} \ No newline at end of file