Adding the possibility to define the Resource Schema refs #18213

This commit is contained in:
Luca Frosini 2020-01-15 11:55:39 +01:00
parent eb62faa7a9
commit 6a3688cc89
7 changed files with 286 additions and 22 deletions

View File

@ -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();

View File

@ -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 {};
}

View File

@ -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<? extends ConsistsOf> consistOfType() default ConsistsOf.class;
Class<? extends Facet> targetFacetType() default Facet.class;
@JsonProperty
Class<? extends ConsistsOf> relation() default ConsistsOf.class;
@JsonProperty
Class<? extends Facet> facet() default Facet.class;
@JsonProperty
String description() default "";
@JsonProperty
int min() default 0;
@JsonProperty
int max() default -1;

View File

@ -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<? extends Resource> source() default Resource.class;
@SuppressWarnings("rawtypes")
@JsonProperty
Class<? extends IsRelatedTo> relation() default IsRelatedTo.class;
@JsonProperty
Class<? extends Resource> target() default Resource.class;
@JsonProperty
String description() default "";
@JsonProperty
int min() default 0;
@JsonProperty
int max() default -1;
}

View File

@ -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<String> superClasses;
protected Set<PropertyDefinition> properties;
protected List<ResourceEntryDefinition> facets;
protected List<ResourceEntryDefinition> resources;
protected static <ISM extends ISManageable> Set<String> retrieveSuperClasses(Class<? extends ISM> type, Class<ISM> baseClass, String topSuperClass){
Set<String> interfaceList = new HashSet<>();
@ -104,16 +113,27 @@ public class TypeDefinitionImpl extends ERImpl implements TypeDefinition {
@SuppressWarnings({"rawtypes", "unchecked"})
public static TypeDefinition getInstance(Class<? extends ISManageable> clz) {
if(BaseEntity.class.isAssignableFrom(clz)) {
return new EntityTypeDefinitionImpl((Class<? extends BaseEntity>) clz);
} else if(BaseRelation.class.isAssignableFrom(clz)){
return new RelationTypeDefinitionImpl((Class<? extends BaseRelation<?,?>>) 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<? extends BaseEntity>) clz);
return typeDefinition;
} else if(BaseRelation.class.isAssignableFrom(clz)){
typeDefinition = new RelationTypeDefinitionImpl((Class<? extends BaseRelation<?,?>>) 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<? extends Resource> r = (Class<? extends Resource>) clz;
setResourceSchemaEntries(r);
}
logger.trace("{} : {} ", clz, this);
}
private void setResourceSchemaEntries(Class<? extends Resource> 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<PropertyDefinition> getProperties() {
return properties;
}
public List<ResourceEntryDefinition> getFacets() {
return facets;
}
public List<ResourceEntryDefinition> getResources() {
return resources;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}