Creating TypeDefinition and PropertyDefinition as types which can be
managed in IS
This commit is contained in:
parent
eaa4f82841
commit
fa2e3d5983
|
@ -85,11 +85,11 @@ public class Type {
|
||||||
this.intValue = intValue;
|
this.intValue = intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getStringValue() {
|
public String getStringValue() {
|
||||||
return stringValue;
|
return stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getIntValue() {
|
public int getIntValue() {
|
||||||
return intValue;
|
return intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,13 @@
|
||||||
package org.gcube.informationsystem.types;
|
package org.gcube.informationsystem.types;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.TypeVariable;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.gcube.informationsystem.base.reference.ISManageable;
|
import org.gcube.informationsystem.base.reference.ISManageable;
|
||||||
import org.gcube.informationsystem.base.reference.properties.Property;
|
import org.gcube.informationsystem.types.impl.entities.TypeDefinitionImpl;
|
||||||
import org.gcube.informationsystem.model.reference.entities.Entity;
|
import org.gcube.informationsystem.types.reference.TypeDefinition;
|
||||||
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.model.reference.relations.Relation;
|
|
||||||
import org.gcube.informationsystem.types.Type.OType;
|
|
||||||
import org.gcube.informationsystem.types.annotations.Abstract;
|
|
||||||
import org.gcube.informationsystem.types.annotations.ISProperty;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
@ -39,32 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
*/
|
*/
|
||||||
public class TypeBinder {
|
public class TypeBinder {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(TypeBinder.class);
|
|
||||||
|
|
||||||
private static final String EDGE_CLASS_NAME = "E";
|
|
||||||
private static final String VERTEX_CLASS_NAME = "V";
|
|
||||||
|
|
||||||
private final static String NAME = "NAME";
|
private final static String NAME = "NAME";
|
||||||
private final static String DESCRIPTION = "DESCRIPTION";
|
|
||||||
|
|
||||||
public final static String UUID_PATTERN = "^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}$";
|
|
||||||
public final static String URI_PATTERN = null;
|
|
||||||
public final static String URL_PATTERN = null;
|
|
||||||
|
|
||||||
public static String getType(Class<? extends ISManageable> clz){
|
|
||||||
return getStaticStringFieldByName(clz, NAME, clz.getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getStaticStringFieldByName(Class<? extends ISManageable> type, String fieldName, String defaultValue){
|
|
||||||
Field field;
|
|
||||||
try {
|
|
||||||
field = type.getDeclaredField(fieldName);
|
|
||||||
field.setAccessible(true);
|
|
||||||
return (String) field.get(null);
|
|
||||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String serializeTypeDefinition(TypeDefinition typeDefinition) throws Exception{
|
public static String serializeTypeDefinition(TypeDefinition typeDefinition) throws Exception{
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
@ -94,343 +46,23 @@ public class TypeBinder {
|
||||||
return mapper.readValue(json, type);
|
return mapper.readValue(json, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class<?> getGenericClass(java.lang.reflect.Type type){
|
|
||||||
TypeVariable<?> typeVariable = (TypeVariable<?>) type;
|
|
||||||
java.lang.reflect.Type[] bounds = typeVariable.getBounds();
|
|
||||||
java.lang.reflect.Type t = bounds[0];
|
|
||||||
return (Class<?>) t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TypeDefinition createTypeDefinition(Class<? extends ISManageable> clz) {
|
public static TypeDefinition createTypeDefinition(Class<? extends ISManageable> clz) {
|
||||||
TypeDefinition typeDefinition = new TypeDefinition();
|
TypeDefinition typeDefinition = new TypeDefinitionImpl(clz);
|
||||||
|
|
||||||
typeDefinition.name = getType(clz);
|
|
||||||
typeDefinition.description = getStaticStringFieldByName(clz, DESCRIPTION, "");
|
|
||||||
typeDefinition.abstractType = false;
|
|
||||||
|
|
||||||
if(clz.isAnnotationPresent(Abstract.class)){
|
|
||||||
typeDefinition.abstractType = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Entity.class.isAssignableFrom(clz)) {
|
|
||||||
if(Resource.class.isAssignableFrom(clz)){
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, Resource.class, Entity.NAME);
|
|
||||||
}else{
|
|
||||||
if(Facet.class.isAssignableFrom(clz)){
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, Facet.class, Entity.NAME);
|
|
||||||
} else {
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, Entity.class, VERTEX_CLASS_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(Relation.class.isAssignableFrom(clz)){
|
|
||||||
if(IsRelatedTo.class.isAssignableFrom(clz)){
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, IsRelatedTo.class, Relation.NAME);
|
|
||||||
} else if(ConsistsOf.class.isAssignableFrom(clz)) {
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, ConsistsOf.class, Relation.NAME);
|
|
||||||
} else {
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, Relation.class, EDGE_CLASS_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
java.lang.reflect.Type[] typeParameters = clz.getTypeParameters();
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends ISManageable> sourceClass = (Class<? extends ISManageable>) getGenericClass(typeParameters[0]);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends ISManageable> targetClass = (Class<? extends ISManageable>) getGenericClass(typeParameters[1]);
|
|
||||||
|
|
||||||
typeDefinition.sourceType = getType(sourceClass);
|
|
||||||
typeDefinition.targetType = getType(targetClass);
|
|
||||||
|
|
||||||
} else if(Property.class.isAssignableFrom(clz)){
|
|
||||||
typeDefinition.superClasses = retrieveSuperClasses(clz, Property.class, clz == Property.class ? null : Property.NAME);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Serialization required");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Resource.class.isAssignableFrom(clz)){
|
|
||||||
typeDefinition.properties = retrieveListOfProperties(clz);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace("{} : {} ", clz, typeDefinition);
|
|
||||||
return typeDefinition;
|
return typeDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<PropertyDefinition> retrieveListOfProperties(Class<?> type){
|
public static String getType(Class<? extends ISManageable> clz){
|
||||||
Set<PropertyDefinition> properties = new HashSet<>();
|
return getStaticStringFieldByName(clz, NAME, clz.getSimpleName());
|
||||||
for (Method m : type.getDeclaredMethods()){
|
|
||||||
m.setAccessible(true);
|
|
||||||
if(m.isAnnotationPresent(ISProperty.class)){
|
|
||||||
if(m.isBridge()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ISProperty propAnnotation = m.getAnnotation(ISProperty.class);
|
|
||||||
PropertyDefinition prop = getProperty(propAnnotation, m);
|
|
||||||
properties.add(prop);
|
|
||||||
logger.trace("Property {} retrieved in type {} ", prop, type.getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPropertyNameFromMethodName(Method method){
|
|
||||||
String name = method.getName();
|
|
||||||
if(name.startsWith("get")){
|
|
||||||
name = name.replace("get", "");
|
|
||||||
|
|
||||||
}
|
|
||||||
if(name.startsWith("is")){
|
|
||||||
name = name.replace("is", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(name.length() > 0){
|
|
||||||
name = Character.toLowerCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropertyDefinition getProperty(ISProperty propertyAnnotation, Method method){
|
public static String getStaticStringFieldByName(Class<? extends ISManageable> type, String fieldName, String defaultValue){
|
||||||
String name = propertyAnnotation.name().isEmpty()?getPropertyNameFromMethodName(method):propertyAnnotation.name();
|
Field field;
|
||||||
PropertyDefinition propertyDefinition = new PropertyDefinition();
|
try {
|
||||||
propertyDefinition.name = name;
|
field = type.getDeclaredField(fieldName);
|
||||||
propertyDefinition.description = propertyAnnotation.description();
|
field.setAccessible(true);
|
||||||
propertyDefinition.mandatory= propertyAnnotation.mandatory();
|
return (String) field.get(null);
|
||||||
propertyDefinition.notnull = !propertyAnnotation.nullable();
|
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||||
propertyDefinition.readonly = propertyAnnotation.readonly();
|
return defaultValue;
|
||||||
if(propertyAnnotation.max()>0) propertyDefinition.max = propertyAnnotation.max();
|
|
||||||
if(propertyAnnotation.max()>=propertyAnnotation.min() && propertyAnnotation.min()>0) propertyDefinition.min = propertyAnnotation.min();
|
|
||||||
if(!propertyAnnotation.regexpr().isEmpty()) propertyDefinition.regexp = propertyAnnotation.regexpr();
|
|
||||||
|
|
||||||
logger.trace("Looking for property type {}", method.getReturnType());
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends ISManageable> type = (Class<? extends ISManageable>) method.getReturnType();
|
|
||||||
propertyDefinition.type = OType.PROPERTY.getIntValue();
|
|
||||||
|
|
||||||
if(Property.class.isAssignableFrom(type)){
|
|
||||||
if(type != Property.class){
|
|
||||||
propertyDefinition.linkedClass = getType(type);
|
|
||||||
}
|
|
||||||
}else if (Type.getTypeByClass(type)!=null) {
|
|
||||||
propertyDefinition.type = Type.getTypeByClass(type).getIntValue();
|
|
||||||
if(propertyDefinition.type > 9 && propertyDefinition.type <= 12){
|
|
||||||
java.lang.reflect.Type genericReturnType = method.getGenericReturnType();
|
|
||||||
logger.trace("Generic Return Type {} for method {}", genericReturnType, method);
|
|
||||||
|
|
||||||
java.lang.reflect.Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
|
|
||||||
|
|
||||||
java.lang.reflect.Type genericType = null;
|
|
||||||
for(java.lang.reflect.Type t : actualTypeArguments){
|
|
||||||
logger.trace("Generic Return Type {} for method {} - Actual Type Argument : {}", genericReturnType, method, t);
|
|
||||||
genericType = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends ISManageable> genericClass = (Class<? extends ISManageable>) genericType;
|
|
||||||
OType linkedOType = Type.getTypeByClass(genericClass);
|
|
||||||
if(linkedOType!=null){
|
|
||||||
propertyDefinition.linkedType = linkedOType.getIntValue();
|
|
||||||
}else{
|
|
||||||
propertyDefinition.linkedClass = getType(genericClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if((propertyDefinition.regexp==null || propertyDefinition.regexp.compareTo("")==0 )&& propertyDefinition.type==OType.STRING.getIntValue()){
|
|
||||||
if(Enum.class.isAssignableFrom(type)){
|
|
||||||
Object[] constants = type.getEnumConstants();
|
|
||||||
StringBuilder stringBuilder = new StringBuilder("^(");
|
|
||||||
for(int i=0; i<constants.length; i++){
|
|
||||||
stringBuilder.append(constants[i].toString());
|
|
||||||
if(i<constants.length-1){
|
|
||||||
stringBuilder.append("|");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stringBuilder.append(")$");
|
|
||||||
propertyDefinition.regexp = stringBuilder.toString();
|
|
||||||
}
|
|
||||||
if(UUID.class.isAssignableFrom(type)){
|
|
||||||
propertyDefinition.regexp = UUID_PATTERN;
|
|
||||||
}
|
|
||||||
if(URI.class.isAssignableFrom(type)){
|
|
||||||
propertyDefinition.regexp = URI_PATTERN;
|
|
||||||
}
|
|
||||||
if(URL.class.isAssignableFrom(type)){
|
|
||||||
propertyDefinition.regexp = URL_PATTERN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(propertyDefinition.regexp!=null && propertyDefinition.regexp.compareTo("")==0){
|
|
||||||
propertyDefinition.regexp = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Type " + type.getSimpleName() + " not reconized");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return propertyDefinition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> retrieveSuperClasses(Class<? extends ISManageable> type, Class<? extends ISManageable> baseClass, String topSuperClass){
|
|
||||||
Set<String> interfaceList = new HashSet<>();
|
|
||||||
|
|
||||||
if(type==baseClass){
|
|
||||||
interfaceList.add(topSuperClass);
|
|
||||||
return interfaceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?>[] interfaces = type.getInterfaces();
|
|
||||||
|
|
||||||
for (Class<?> interfaceClass : interfaces) {
|
|
||||||
|
|
||||||
if(!baseClass.isAssignableFrom(interfaceClass)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends ISManageable> clz = (Class<? extends ISManageable>) interfaceClass;
|
|
||||||
interfaceList.add(getType(clz));
|
|
||||||
}
|
|
||||||
|
|
||||||
return interfaceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown=true)
|
|
||||||
public static class TypeDefinition {
|
|
||||||
|
|
||||||
protected String name;
|
|
||||||
protected String description;
|
|
||||||
@JsonProperty(value="abstract")
|
|
||||||
protected boolean abstractType;
|
|
||||||
protected Set<String> superClasses;
|
|
||||||
protected Set<PropertyDefinition> properties;
|
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
protected String sourceType;
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
protected String targetType;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "TypeDefinition ["
|
|
||||||
+ "name=" + name
|
|
||||||
+ (sourceType==null ? "" : "(" + sourceType + "->" + targetType + ")")
|
|
||||||
+ ", description=" + description
|
|
||||||
+ ", abstract=" + abstractType
|
|
||||||
+ ", superClasses=" + superClasses
|
|
||||||
+ ", properties=" + properties
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAbstract() {
|
|
||||||
return abstractType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getSuperClasses() {
|
|
||||||
return superClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<PropertyDefinition> getProperties() {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSourceType() {
|
|
||||||
return sourceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTargetType() {
|
|
||||||
return targetType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown=true)
|
|
||||||
public static class PropertyDefinition {
|
|
||||||
|
|
||||||
private String name= "";
|
|
||||||
private String description= "";
|
|
||||||
private boolean mandatory = false;
|
|
||||||
private boolean readonly = false;
|
|
||||||
private boolean notnull = false;
|
|
||||||
private Integer max= null;
|
|
||||||
private Integer min= null;
|
|
||||||
private String regexp= null;
|
|
||||||
private Integer linkedType = null;
|
|
||||||
private String linkedClass = null;
|
|
||||||
private Integer type=null;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMandatory() {
|
|
||||||
return mandatory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReadonly() {
|
|
||||||
return readonly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotnull() {
|
|
||||||
return notnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMax() {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMin() {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRegexp() {
|
|
||||||
return regexp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getLinkedType() {
|
|
||||||
return linkedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLinkedClass() {
|
|
||||||
return linkedClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public String getTypeStringValue() {
|
|
||||||
if(type==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return OType.values()[type].getStringValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Property [name=" + name + ", description=" + description
|
|
||||||
+ ", mandatory=" + mandatory + ", readonly=" + readonly
|
|
||||||
+ ", notnull=" + notnull + ", max=" + max + ", min="
|
|
||||||
+ min + ", regexpr=" + regexp + ", type = " + type
|
|
||||||
+ " (" + getTypeStringValue() + "), linkedType = " + linkedType + ", linkedClass = "
|
|
||||||
+ linkedClass + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.gcube.informationsystem.model.reference.entities.Entity;
|
import org.gcube.informationsystem.model.reference.entities.Entity;
|
||||||
import org.gcube.informationsystem.types.TypeBinder;
|
import org.gcube.informationsystem.types.TypeBinder;
|
||||||
import org.gcube.informationsystem.types.TypeBinder.PropertyDefinition;
|
import org.gcube.informationsystem.types.reference.properties.PropertyDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
package org.gcube.informationsystem.types.impl.entities;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.gcube.informationsystem.base.reference.ISManageable;
|
||||||
|
import org.gcube.informationsystem.base.reference.properties.Property;
|
||||||
|
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.relations.ConsistsOf;
|
||||||
|
import org.gcube.informationsystem.model.reference.relations.IsRelatedTo;
|
||||||
|
import org.gcube.informationsystem.model.reference.relations.Relation;
|
||||||
|
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.impl.properties.PropertyDefinitionImpl;
|
||||||
|
import org.gcube.informationsystem.types.reference.TypeDefinition;
|
||||||
|
import org.gcube.informationsystem.types.reference.properties.PropertyDefinition;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown=true)
|
||||||
|
public class TypeDefinitionImpl implements TypeDefinition {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(TypeDefinitionImpl.class);
|
||||||
|
|
||||||
|
private static final String EDGE_CLASS_NAME = "E";
|
||||||
|
private static final String VERTEX_CLASS_NAME = "V";
|
||||||
|
|
||||||
|
private final static String DESCRIPTION = "DESCRIPTION";
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
protected String description;
|
||||||
|
@JsonProperty(value="abstract")
|
||||||
|
protected boolean abstractType;
|
||||||
|
protected Set<String> superClasses;
|
||||||
|
protected Set<PropertyDefinition> properties;
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
protected String sourceType;
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
protected String targetType;
|
||||||
|
|
||||||
|
private static Set<String> retrieveSuperClasses(Class<? extends ISManageable> type, Class<? extends ISManageable> baseClass, String topSuperClass){
|
||||||
|
Set<String> interfaceList = new HashSet<>();
|
||||||
|
|
||||||
|
if(type==baseClass){
|
||||||
|
interfaceList.add(topSuperClass);
|
||||||
|
return interfaceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?>[] interfaces = type.getInterfaces();
|
||||||
|
|
||||||
|
for (Class<?> interfaceClass : interfaces) {
|
||||||
|
|
||||||
|
if(!baseClass.isAssignableFrom(interfaceClass)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends ISManageable> clz = (Class<? extends ISManageable>) interfaceClass;
|
||||||
|
interfaceList.add(TypeBinder.getType(clz));
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<PropertyDefinition> retrieveListOfProperties(Class<?> type){
|
||||||
|
Set<PropertyDefinition> properties = new HashSet<>();
|
||||||
|
for (Method m : type.getDeclaredMethods()){
|
||||||
|
m.setAccessible(true);
|
||||||
|
if(m.isAnnotationPresent(ISProperty.class)){
|
||||||
|
if(m.isBridge()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ISProperty propAnnotation = m.getAnnotation(ISProperty.class);
|
||||||
|
PropertyDefinition prop = new PropertyDefinitionImpl(propAnnotation, m);
|
||||||
|
properties.add(prop);
|
||||||
|
logger.trace("Property {} retrieved in type {} ", prop, type.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> getGenericClass(java.lang.reflect.Type type){
|
||||||
|
TypeVariable<?> typeVariable = (TypeVariable<?>) type;
|
||||||
|
java.lang.reflect.Type[] bounds = typeVariable.getBounds();
|
||||||
|
java.lang.reflect.Type t = bounds[0];
|
||||||
|
return (Class<?>) t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeDefinitionImpl(Class<? extends ISManageable> clz) {
|
||||||
|
this.name = TypeBinder.getType(clz);
|
||||||
|
this.description = TypeBinder.getStaticStringFieldByName(clz, DESCRIPTION, "");
|
||||||
|
this.abstractType = false;
|
||||||
|
|
||||||
|
if(clz.isAnnotationPresent(Abstract.class)){
|
||||||
|
this.abstractType = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Entity.class.isAssignableFrom(clz)) {
|
||||||
|
if(Resource.class.isAssignableFrom(clz)){
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, Resource.class, Entity.NAME);
|
||||||
|
}else{
|
||||||
|
if(Facet.class.isAssignableFrom(clz)){
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, Facet.class, Entity.NAME);
|
||||||
|
} else {
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, Entity.class, VERTEX_CLASS_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(Relation.class.isAssignableFrom(clz)){
|
||||||
|
if(IsRelatedTo.class.isAssignableFrom(clz)){
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, IsRelatedTo.class, Relation.NAME);
|
||||||
|
} else if(ConsistsOf.class.isAssignableFrom(clz)) {
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, ConsistsOf.class, Relation.NAME);
|
||||||
|
} else {
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, Relation.class, EDGE_CLASS_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
java.lang.reflect.Type[] typeParameters = clz.getTypeParameters();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends ISManageable> sourceClass = (Class<? extends ISManageable>) getGenericClass(typeParameters[0]);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends ISManageable> targetClass = (Class<? extends ISManageable>) getGenericClass(typeParameters[1]);
|
||||||
|
|
||||||
|
this.sourceType = TypeBinder.getType(sourceClass);
|
||||||
|
this.targetType = TypeBinder.getType(targetClass);
|
||||||
|
|
||||||
|
} else if(Property.class.isAssignableFrom(clz)){
|
||||||
|
this.superClasses = retrieveSuperClasses(clz, Property.class, clz == Property.class ? null : Property.NAME);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Serialization required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Resource.class.isAssignableFrom(clz)){
|
||||||
|
this.properties = retrieveListOfProperties(clz);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.trace("{} : {} ", clz, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TypeDefinition ["
|
||||||
|
+ "name=" + name
|
||||||
|
+ (sourceType==null ? "" : "(" + sourceType + "->" + targetType + ")")
|
||||||
|
+ ", description=" + description
|
||||||
|
+ ", abstract=" + abstractType
|
||||||
|
+ ", superClasses=" + superClasses
|
||||||
|
+ ", properties=" + properties
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return abstractType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getSuperClasses() {
|
||||||
|
return superClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<PropertyDefinition> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceType() {
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,205 @@
|
||||||
|
package org.gcube.informationsystem.types.impl.properties;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.gcube.informationsystem.base.reference.ISManageable;
|
||||||
|
import org.gcube.informationsystem.base.reference.properties.Property;
|
||||||
|
import org.gcube.informationsystem.types.Type;
|
||||||
|
import org.gcube.informationsystem.types.Type.OType;
|
||||||
|
import org.gcube.informationsystem.types.TypeBinder;
|
||||||
|
import org.gcube.informationsystem.types.annotations.ISProperty;
|
||||||
|
import org.gcube.informationsystem.types.impl.entities.TypeDefinitionImpl;
|
||||||
|
import org.gcube.informationsystem.types.reference.properties.PropertyDefinition;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown=true)
|
||||||
|
public class PropertyDefinitionImpl implements PropertyDefinition {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(TypeDefinitionImpl.class);
|
||||||
|
|
||||||
|
public final static String UUID_PATTERN = "^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}$";
|
||||||
|
public final static String URI_PATTERN = null;
|
||||||
|
public final static String URL_PATTERN = null;
|
||||||
|
|
||||||
|
private String name= "";
|
||||||
|
private String description= "";
|
||||||
|
private boolean mandatory = false;
|
||||||
|
private boolean readonly = false;
|
||||||
|
private boolean notnull = false;
|
||||||
|
private Integer max= null;
|
||||||
|
private Integer min= null;
|
||||||
|
private String regexp= null;
|
||||||
|
private Integer linkedType = null;
|
||||||
|
private String linkedClass = null;
|
||||||
|
private Integer type=null;
|
||||||
|
|
||||||
|
private static String getPropertyNameFromMethodName(Method method){
|
||||||
|
String name = method.getName();
|
||||||
|
if(name.startsWith("get")){
|
||||||
|
name = name.replace("get", "");
|
||||||
|
|
||||||
|
}
|
||||||
|
if(name.startsWith("is")){
|
||||||
|
name = name.replace("is", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name.length() > 0){
|
||||||
|
name = Character.toLowerCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyDefinitionImpl(ISProperty propertyAnnotation, Method method) {
|
||||||
|
String name = propertyAnnotation.name().isEmpty()?getPropertyNameFromMethodName(method):propertyAnnotation.name();
|
||||||
|
this.name = name;
|
||||||
|
this.description = propertyAnnotation.description();
|
||||||
|
this.mandatory= propertyAnnotation.mandatory();
|
||||||
|
this.notnull = !propertyAnnotation.nullable();
|
||||||
|
this.readonly = propertyAnnotation.readonly();
|
||||||
|
if(propertyAnnotation.max()>0) this.max = propertyAnnotation.max();
|
||||||
|
if(propertyAnnotation.max()>=propertyAnnotation.min() && propertyAnnotation.min()>0) this.min = propertyAnnotation.min();
|
||||||
|
if(!propertyAnnotation.regexpr().isEmpty()) this.regexp = propertyAnnotation.regexpr();
|
||||||
|
|
||||||
|
logger.trace("Looking for property type {}", method.getReturnType());
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends ISManageable> type = (Class<? extends ISManageable>) method.getReturnType();
|
||||||
|
this.type = OType.PROPERTY.getIntValue();
|
||||||
|
|
||||||
|
if(Property.class.isAssignableFrom(type)){
|
||||||
|
if(type != Property.class){
|
||||||
|
this.linkedClass = TypeBinder.getType(type);
|
||||||
|
}
|
||||||
|
}else if (Type.getTypeByClass(type)!=null) {
|
||||||
|
this.type = Type.getTypeByClass(type).getIntValue();
|
||||||
|
if(this.type > 9 && this.type <= 12){
|
||||||
|
java.lang.reflect.Type genericReturnType = method.getGenericReturnType();
|
||||||
|
logger.trace("Generic Return Type {} for method {}", genericReturnType, method);
|
||||||
|
|
||||||
|
java.lang.reflect.Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
|
||||||
|
|
||||||
|
java.lang.reflect.Type genericType = null;
|
||||||
|
for(java.lang.reflect.Type t : actualTypeArguments){
|
||||||
|
logger.trace("Generic Return Type {} for method {} - Actual Type Argument : {}", genericReturnType, method, t);
|
||||||
|
genericType = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends ISManageable> genericClass = (Class<? extends ISManageable>) genericType;
|
||||||
|
OType linkedOType = Type.getTypeByClass(genericClass);
|
||||||
|
if(linkedOType!=null){
|
||||||
|
this.linkedType = linkedOType.getIntValue();
|
||||||
|
}else{
|
||||||
|
this.linkedClass = TypeBinder.getType(genericClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if((this.regexp==null || this.regexp.compareTo("")==0 )&& this.type==OType.STRING.getIntValue()){
|
||||||
|
if(Enum.class.isAssignableFrom(type)){
|
||||||
|
Object[] constants = type.getEnumConstants();
|
||||||
|
StringBuilder stringBuilder = new StringBuilder("^(");
|
||||||
|
for(int i=0; i<constants.length; i++){
|
||||||
|
stringBuilder.append(constants[i].toString());
|
||||||
|
if(i<constants.length-1){
|
||||||
|
stringBuilder.append("|");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringBuilder.append(")$");
|
||||||
|
this.regexp = stringBuilder.toString();
|
||||||
|
}
|
||||||
|
if(UUID.class.isAssignableFrom(type)){
|
||||||
|
this.regexp = UUID_PATTERN;
|
||||||
|
}
|
||||||
|
if(URI.class.isAssignableFrom(type)){
|
||||||
|
this.regexp = URI_PATTERN;
|
||||||
|
}
|
||||||
|
if(URL.class.isAssignableFrom(type)){
|
||||||
|
this.regexp = URL_PATTERN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.regexp!=null && this.regexp.compareTo("")==0){
|
||||||
|
this.regexp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Type " + type.getSimpleName() + " not reconized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMandatory() {
|
||||||
|
return mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReadonly() {
|
||||||
|
return readonly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotnull() {
|
||||||
|
return notnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegexp() {
|
||||||
|
return regexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLinkedType() {
|
||||||
|
return linkedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLinkedClass() {
|
||||||
|
return linkedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getTypeStringValue() {
|
||||||
|
if(type==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return OType.values()[type].getStringValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Property [name=" + name + ", description=" + description
|
||||||
|
+ ", mandatory=" + mandatory + ", readonly=" + readonly
|
||||||
|
+ ", notnull=" + notnull + ", max=" + max + ", min="
|
||||||
|
+ min + ", regexpr=" + regexp + ", type = " + type
|
||||||
|
+ " (" + getTypeStringValue() + "), linkedType = " + linkedType + ", linkedClass = "
|
||||||
|
+ linkedClass + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.gcube.informationsystem.types.reference;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.gcube.informationsystem.types.reference.properties.PropertyDefinition;
|
||||||
|
|
||||||
|
public interface TypeDefinition {
|
||||||
|
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
public String getDescription();
|
||||||
|
|
||||||
|
public boolean isAbstract();
|
||||||
|
|
||||||
|
public Set<String> getSuperClasses();
|
||||||
|
|
||||||
|
public Set<PropertyDefinition> getProperties();
|
||||||
|
|
||||||
|
public String getSourceType();
|
||||||
|
|
||||||
|
public String getTargetType();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package org.gcube.informationsystem.types.reference.properties;
|
||||||
|
|
||||||
|
public interface PropertyDefinition {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue