package org.gcube.informationsystem.types.impl; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.gcube.com.fasterxml.jackson.annotation.JsonGetter; import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore; import org.gcube.com.fasterxml.jackson.annotation.JsonInclude; import org.gcube.com.fasterxml.jackson.annotation.JsonInclude.Include; import org.gcube.com.fasterxml.jackson.annotation.JsonProperty; import org.gcube.com.fasterxml.jackson.annotation.JsonSetter; import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.base.reference.Element; import org.gcube.informationsystem.base.reference.entities.EntityElement; import org.gcube.informationsystem.base.reference.properties.PropertyElement; import org.gcube.informationsystem.base.reference.relations.RelationElement; import org.gcube.informationsystem.model.reference.properties.Header; import org.gcube.informationsystem.types.TypeMapper; import org.gcube.informationsystem.types.annotations.Abstract; import org.gcube.informationsystem.types.annotations.ISProperty; import org.gcube.informationsystem.types.impl.entities.EntityTypeImpl; import org.gcube.informationsystem.types.impl.properties.PropertyDefinitionImpl; import org.gcube.informationsystem.types.impl.properties.PropertyTypeImpl; import org.gcube.informationsystem.types.impl.relations.RelationTypeImpl; import org.gcube.informationsystem.types.reference.Type; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; import org.gcube.informationsystem.utils.TypeVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class TypeImpl implements Type { private static Logger logger = LoggerFactory.getLogger(TypeImpl.class); /** * Generated Serial version UID */ private static final long serialVersionUID = -4333954207969059451L; /* public final static String DESCRIPTION = "DESCRIPTION"; public final static String VERSION = "VERSION"; public final static String CHANGELOG = "CHANGELOG"; */ public static final Map DEFAULT_CHANGELOG_MAP; private static final Map DEFAULT_CHANGELOG_MAP_KEY_AS_STRING; static { DEFAULT_CHANGELOG_MAP = new HashMap<>(); DEFAULT_CHANGELOG_MAP.put(new TypeVersion(TypeVersion.MINIMAL_VERSION_STRING), TypeVersion.MINIMAL_VERSION_DESCRIPTION); DEFAULT_CHANGELOG_MAP_KEY_AS_STRING = new HashMap<>(); DEFAULT_CHANGELOG_MAP_KEY_AS_STRING.put(TypeVersion.MINIMAL_VERSION_STRING, TypeVersion.MINIMAL_VERSION_DESCRIPTION); } protected Header header; protected String name; protected String description; protected TypeVersion version; @JsonProperty(value = CHANGELOG_PROPERTY, required = false) @JsonInclude(Include.NON_NULL) protected Map changelog; @JsonProperty(value = "abstract") protected boolean abstractType; protected Set superClasses; protected Set properties; protected Set retrieveSuperClasses(Class type, Class baseClass, String topSuperClass) { Set interfaceList = new HashSet<>(); if (type == baseClass) { if (topSuperClass != null) { interfaceList.add(topSuperClass); } return interfaceList; } Class[] interfaces = type.getInterfaces(); for (Class interfaceClass : interfaces) { if (!baseClass.isAssignableFrom(interfaceClass)) { continue; } @SuppressWarnings("unchecked") Class clz = (Class) interfaceClass; interfaceList.add(TypeMapper.getType(clz)); } return interfaceList; } protected Set retrieveListOfProperties(Class type) { Set 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()); } } if(properties.size()==0) { properties = null; } return properties; } protected 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]; if (t instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) t; return (Class) parameterizedType.getRawType(); } return (Class) t; } @SuppressWarnings({ "rawtypes", "unchecked" }) public static Type getInstance(Class clz) { Type typeDefinition = null; try { if (EntityElement.class.isAssignableFrom(clz)) { typeDefinition = EntityTypeImpl.getEntityTypeDefinitionInstance((Class) clz); return typeDefinition; } else if (RelationElement.class.isAssignableFrom(clz)) { typeDefinition = RelationTypeImpl .getRelationTypeDefinitionInstance((Class>) clz); return typeDefinition; } else if (PropertyElement.class.isAssignableFrom(clz)) { typeDefinition = new PropertyTypeImpl(clz); return typeDefinition; } else if (Type.class.isAssignableFrom(clz)) { typeDefinition = new TypeImpl(clz); return typeDefinition; } else { throw new RuntimeException("Serialization required"); } } finally { if (typeDefinition != null) { logger.debug("{} : {} ", clz, typeDefinition); } } } protected TypeImpl() { } protected TypeImpl(Class clz) { this.name = TypeMapper.getType(clz); this.description = TypeMapper.getTypeDescription(clz); this.version = TypeMapper.getTypeVersion(clz); this.changelog = TypeMapper.getTypeChangelog(clz); this.abstractType = false; if (clz.isAnnotationPresent(Abstract.class)) { this.abstractType = true; } } @Override public Header getHeader() { return header; } @Override public void setHeader(Header header) { this.header = header; } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public TypeVersion getVersion() { return version; } @JsonGetter(value = VERSION_PROPERTY) public String getVersionAsString() { return version.toString(); } @JsonSetter(value = VERSION_PROPERTY) public void setVersion(String version) { this.version = new TypeVersion(version); } @Override public Map getChangelog() { return changelog; } @JsonGetter(value = CHANGELOG_PROPERTY) @JsonInclude(Include.NON_NULL) public Map getChangelogWithVersionAsString() { if(this.changelog==null) { return DEFAULT_CHANGELOG_MAP_KEY_AS_STRING; } Map map = new HashMap<>(); for (TypeVersion typeVersion : changelog.keySet()) { map.put(typeVersion.toString(), changelog.get(typeVersion)); } return map; } @JsonSetter(value=CHANGELOG_PROPERTY) public void setChangelog(Map changelog) { if(changelog==null) { this.changelog = DEFAULT_CHANGELOG_MAP; return; } this.changelog = new HashMap<>(); for (String version : changelog.keySet()) { this.changelog.put(new TypeVersion(version), changelog.get(version)); } } @Override public boolean isAbstract() { return abstractType; } @Override public Set getSuperClasses() { return superClasses; } @JsonInclude(Include.NON_EMPTY) public Set getProperties() { return properties; } @Override @JsonIgnore public AccessType getAccessType() { return null; } }