diff --git a/src/main/java/org/gcube/informationsystem/types/OrientDBType.java b/src/main/java/org/gcube/informationsystem/types/OrientDBType.java index a52dd8e..1507356 100644 --- a/src/main/java/org/gcube/informationsystem/types/OrientDBType.java +++ b/src/main/java/org/gcube/informationsystem/types/OrientDBType.java @@ -31,6 +31,7 @@ import java.util.Set; import java.util.UUID; import org.gcube.informationsystem.model.reference.properties.Property; +import org.gcube.informationsystem.utils.TypeVersion; /** * @author Lucio Lelii (ISTI - CNR) @@ -143,6 +144,7 @@ public class OrientDBType { TYPES_BY_CLASS.put(URI.class, OType.STRING); TYPES_BY_CLASS.put(URL.class, OType.STRING); TYPES_BY_CLASS.put(UUID.class, OType.STRING); + TYPES_BY_CLASS.put(TypeVersion.class, OType.STRING); } diff --git a/src/main/java/org/gcube/informationsystem/types/impl/TypeImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/TypeImpl.java index e1b5e57..4f258d5 100644 --- a/src/main/java/org/gcube/informationsystem/types/impl/TypeImpl.java +++ b/src/main/java/org/gcube/informationsystem/types/impl/TypeImpl.java @@ -6,9 +6,11 @@ import java.lang.reflect.TypeVariable; import java.util.HashSet; import java.util.Set; +import org.gcube.com.fasterxml.jackson.annotation.JsonGetter; 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.Element; import org.gcube.informationsystem.base.reference.entities.EntityElement; import org.gcube.informationsystem.base.reference.properties.PropertyElement; @@ -23,6 +25,7 @@ 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; @@ -42,7 +45,7 @@ public class TypeImpl implements Type { protected String name; protected String description; - protected String version; + protected TypeVersion version; @JsonProperty(value="abstract") protected boolean abstractType; protected Set superClasses; @@ -135,7 +138,8 @@ public class TypeImpl implements Type { protected TypeImpl(Class clz) { this.name = TypeMapper.getType(clz); this.description = TypeMapper.getStaticStringFieldByName(clz, DESCRIPTION, ""); - this.version = TypeMapper.getStaticStringFieldByName(clz, VERSION, "1.0.0"); + String versionString = TypeMapper.getStaticStringFieldByName(clz, VERSION, "1.0.0"); + this.version = new TypeVersion(versionString); this.abstractType = false; if(clz.isAnnotationPresent(Abstract.class)){ @@ -166,9 +170,19 @@ public class TypeImpl implements Type { } @Override - public String getVersion() { + public TypeVersion getVersion() { return version; } + + @JsonGetter(value=VERSION_PROPERTY) + protected String getVersionAsString() { + return version.toString(); + } + + @JsonSetter(value = VERSION_PROPERTY) + protected void setVersion(String version) { + this.version = new TypeVersion(version); + } @Override public boolean isAbstract() { diff --git a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java index eb3c5ca..18dcb42 100644 --- a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java +++ b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java @@ -16,6 +16,7 @@ import org.gcube.informationsystem.types.TypeMapper; import org.gcube.informationsystem.types.annotations.ISProperty; import org.gcube.informationsystem.types.impl.TypeImpl; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; +import org.gcube.informationsystem.utils.TypeVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,9 +31,10 @@ public final class PropertyDefinitionImpl implements PropertyDefinition { private static Logger logger = LoggerFactory.getLogger(TypeImpl.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; + public final static String UUID_REGEX = "^([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_REGEX = null; + public final static String URL_REGEX = null; + public final static String TYPE_VERSION_REGEX = "^(0|([1-9][0-9]{0,}))\\.(0|([1-9][0-9]{0,}))\\.(0|([1-9][0-9]{0,}))$"; private String name= ""; private String description= ""; @@ -126,14 +128,18 @@ public final class PropertyDefinitionImpl implements PropertyDefinition { this.regexp = stringBuilder.toString(); } if(UUID.class.isAssignableFrom(type)){ - this.regexp = UUID_PATTERN; + this.regexp = UUID_REGEX; } if(URI.class.isAssignableFrom(type)){ - this.regexp = URI_PATTERN; + this.regexp = URI_REGEX; } if(URL.class.isAssignableFrom(type)){ - this.regexp = URL_PATTERN; + this.regexp = URL_REGEX; } + if(TypeVersion.class.isAssignableFrom(type)){ + this.regexp = TYPE_VERSION_REGEX; + } + } if(this.regexp!=null && this.regexp.compareTo("")==0){ diff --git a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyTypeImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyTypeImpl.java index 8da818f..049411c 100644 --- a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyTypeImpl.java +++ b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyTypeImpl.java @@ -27,6 +27,8 @@ public final class PropertyTypeImpl

extends TypeImpl super(clz); this.superClasses = retrieveSuperClasses(clz, PropertyElement.class, clz == PropertyElement.class ? null : PropertyElement.NAME); + + this.properties = retrieveListOfProperties(clz); } @Override diff --git a/src/main/java/org/gcube/informationsystem/types/reference/Type.java b/src/main/java/org/gcube/informationsystem/types/reference/Type.java index b371637..411b46e 100644 --- a/src/main/java/org/gcube/informationsystem/types/reference/Type.java +++ b/src/main/java/org/gcube/informationsystem/types/reference/Type.java @@ -6,6 +6,7 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.gcube.informationsystem.base.reference.IdentifiableElement; import org.gcube.informationsystem.types.annotations.Abstract; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; +import org.gcube.informationsystem.utils.TypeVersion; @Abstract @JsonIgnoreProperties(ignoreUnknown=true) @@ -24,8 +25,8 @@ public interface Type extends IdentifiableElement { public String getName(); public String getDescription(); - - public String getVersion(); + + public TypeVersion getVersion(); public boolean isAbstract(); diff --git a/src/main/java/org/gcube/informationsystem/types/reference/properties/Changelog.java b/src/main/java/org/gcube/informationsystem/types/reference/properties/Changelog.java new file mode 100644 index 0000000..f719f10 --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/types/reference/properties/Changelog.java @@ -0,0 +1,23 @@ +package org.gcube.informationsystem.types.reference.properties; + +import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.gcube.com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.gcube.informationsystem.base.reference.properties.PropertyElement; +import org.gcube.informationsystem.types.annotations.ISProperty; +import org.gcube.informationsystem.types.impl.properties.PropertyDefinitionImpl; +import org.gcube.informationsystem.utils.TypeVersion; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonDeserialize(as = PropertyDefinitionImpl.class) +public interface Changelog extends PropertyElement { + + public static final String VERSION_PROPERTY = "version"; + public static final String CHANGE_PROPERTY = "changelog"; + + @ISProperty(name = VERSION_PROPERTY, readonly = true, mandatory = true, nullable = false, regexpr = "") + public TypeVersion getVersion(); + + @ISProperty(name = CHANGE_PROPERTY, readonly = true, mandatory = true, nullable = false) + public String getChange(); + +} diff --git a/src/main/java/org/gcube/informationsystem/utils/TypeVersion.java b/src/main/java/org/gcube/informationsystem/utils/TypeVersion.java new file mode 100644 index 0000000..5c8416b --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/utils/TypeVersion.java @@ -0,0 +1,113 @@ +package org.gcube.informationsystem.utils; + +import java.util.regex.Pattern; + +import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore; +import org.gcube.informationsystem.types.impl.properties.PropertyDefinitionImpl; + +public class TypeVersion implements Comparable { + + public final static String TYPE_VERSION_REGEX = PropertyDefinitionImpl.TYPE_VERSION_REGEX; + + public final static Pattern TYPE_VERSION_PATTERN; + + static { + TYPE_VERSION_PATTERN = Pattern.compile(TYPE_VERSION_REGEX); + } + + @JsonIgnore + protected int major; + @JsonIgnore + protected int minor; + @JsonIgnore + protected int revision; + + protected TypeVersion(){} + + public TypeVersion(String version) { + setVersion(version); + } + + public TypeVersion(int major, int minor, int revision) { + this.major = major; + this.minor = minor; + this.revision = revision; + } + + public void setVersion(String version) { + if(!TYPE_VERSION_PATTERN.matcher(version).matches()) { + throw new RuntimeException("The provided version (i.e. " + version + ") MUST respect the regex " + TYPE_VERSION_REGEX); + } + String[] parts = version.split("\\."); + this.major = Integer.valueOf(parts[0]); + this.minor = Integer.valueOf(parts[1]); + this.revision = Integer.valueOf(parts[2]); + } + + public int getMajor() { + return major; + } + + protected void setMajor(int major) { + this.major = major; + } + + public int getMinor() { + return minor; + } + + protected void setMinor(int minor) { + this.minor = minor; + } + + public int getRevision() { + return revision; + } + + protected void setRevision(int revision) { + this.revision = revision; + } + + @Override + public String toString() { + return major + "." + minor + "." + revision; + } + @Override + public int compareTo(TypeVersion other) { + if(other == null) { + return 1; + } + + int compare = Integer.compare(major, other.major); + if(compare!=0) { + return compare; + } + + compare = Integer.compare(minor, other.minor); + if(compare!=0) { + return compare; + } + + compare = Integer.compare(revision, other.revision); + return compare; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TypeVersion other = (TypeVersion) obj; + if (major != other.major) + return false; + if (minor != other.minor) + return false; + if (revision != other.revision) + return false; + return true; + } + +} \ No newline at end of file diff --git a/src/test/java/org/gcube/informationsystem/types/SerializationTest.java b/src/test/java/org/gcube/informationsystem/types/SerializationTest.java index 28d068b..f9ba317 100644 --- a/src/test/java/org/gcube/informationsystem/types/SerializationTest.java +++ b/src/test/java/org/gcube/informationsystem/types/SerializationTest.java @@ -24,6 +24,7 @@ import org.gcube.informationsystem.types.reference.relations.ConsistsOfType; import org.gcube.informationsystem.types.reference.relations.IsRelatedToType; import org.gcube.informationsystem.types.reference.relations.RelationType; import org.gcube.informationsystem.utils.ElementMapper; +import org.gcube.informationsystem.utils.TypeVersion; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -155,6 +156,11 @@ public class SerializationTest { public void testTypeSerialization() throws Exception { String serialized = TypeMapper.serializeType(Header.class); logger.info(serialized); + @SuppressWarnings("unchecked") + PropertyType

propertyType = (PropertyType
) TypeMapper.deserializeTypeDefinition(serialized); + TypeVersion typeVersion = propertyType.getVersion(); + logger.debug("Version {}", typeVersion.toString()); + logger.info(ElementMapper.marshal(propertyType)); } } diff --git a/src/test/java/org/gcube/informationsystem/utils/TypeVersionTest.java b/src/test/java/org/gcube/informationsystem/utils/TypeVersionTest.java new file mode 100644 index 0000000..dc39627 --- /dev/null +++ b/src/test/java/org/gcube/informationsystem/utils/TypeVersionTest.java @@ -0,0 +1,29 @@ +package org.gcube.informationsystem.utils; + +import org.junit.Assert; +import org.junit.Test; + +public class TypeVersionTest { + + String[] validVersions = new String[] {"1.0.0", "13.23.45", "1.12.3"}; + String[] inValidVersions = new String[] {"1.0", "01.23.45", "1.02.3"}; + + @Test + public void testPatterns() throws Exception { + for(String version : validVersions) { + TypeVersion typeVersion = new TypeVersion(version); + Assert.assertTrue(version.compareTo(typeVersion.toString())==0); + } + + for(String version : inValidVersions) { + try { + TypeVersion typeVersion = new TypeVersion(version); + throw new Exception("The version " + version + " is not valid but the validation succeded. Parsed version is " + typeVersion.toString()); + }catch (RuntimeException e) { + // OK + } + } + + } + +}