package eu.dnetlib.dhp.schema.oaf; import java.beans.Transient; import java.io.Serializable; import java.util.*; /** * Relation models any edge between two nodes in the OpenAIRE graph. It has a source id and a target id pointing to * graph node identifiers, and it is further characterised by the semantic of the link through the fields relType, * subRelType and relClass. Provenance information is modeled according to the dataInfo element and collectedFrom, while * individual relationship types can provide extra information via the properties field. */ public class Relation extends Oaf implements Serializable { public enum RELTYPE { resultResult, resultProject, resultOrganization, projectOrganization, datasourceOrganization, organizationOrganization; } public enum SUBRELTYPE { affiliation, citation, dedup, outcome, part, participation, provision, relationship, review, similarity, supplement, version; public static boolean exists(String subreltype) { try { SUBRELTYPE.valueOf(subreltype); return true; } catch (IllegalArgumentException | NullPointerException e) { return false; } } } public enum RELCLASS { IsVersionOf, IsSourceOf, isMergedIn, IsIdenticalTo, Documents, IsAmongTopNSimilarDocuments, IsSupplementedBy, IsObsoletedBy, Continues, IsParentOf, IsReferencedBy, IsCitedBy, Compiles, IsPreviousVersionOf, HasPart, IsDocumentedBy, HasAmongTopNSimilarDocuments, isParticipant, hasAuthorInstitution, IsRelatedTo, Requires, Describes, IsReviewedBy, IsContinuedBy, provides, IsChildOf, IsDescribedBy, IsNewVersionOf, IsPartOf, HasVersion, hasParticipant, isAuthorInstitutionOf, IsVariantFormOf, isProducedBy, IsMetadataFor, HasAssociationWith, Cites, IsRequiredBy, IsOriginalFormOf, IsSupplementTo, IsMetadataOf, References, IsCompiledBy, isProvidedBy, merges, IsDerivedFrom, Obsoletes, Reviews, isSimilarTo, isDifferentFrom, produces; public static boolean exists(String relclass) { try { RELCLASS.valueOf(relclass); return true; } catch (IllegalArgumentException | NullPointerException e) { return false; } } @Transient public SUBRELTYPE getSubRel() { switch (this) { case isParticipant: case hasParticipant: return SUBRELTYPE.participation; case isAuthorInstitutionOf: case hasAuthorInstitution: return SUBRELTYPE.affiliation; case isMergedIn: case merges: case isSimilarTo: case isDifferentFrom: return SUBRELTYPE.dedup; case isProducedBy: case produces: return SUBRELTYPE.outcome; case isProvidedBy: case provides: return SUBRELTYPE.provision; case IsAmongTopNSimilarDocuments: case HasAmongTopNSimilarDocuments: return SUBRELTYPE.similarity; case IsSupplementedBy: case IsSupplementTo: return SUBRELTYPE.supplement; case IsPartOf: case HasPart: return SUBRELTYPE.part; case IsCitedBy: case Cites: return SUBRELTYPE.citation; case IsIdenticalTo: case IsReferencedBy: case References: case IsContinuedBy: case Continues: case IsDocumentedBy: case Documents: case IsDerivedFrom: case IsSourceOf: case IsRelatedTo: case IsCompiledBy: case Compiles: case IsDescribedBy: case Describes: case IsMetadataFor: case IsMetadataOf: case HasAssociationWith: case IsRequiredBy: case Requires: case IsChildOf: case IsParentOf: return SUBRELTYPE.relationship; case IsPreviousVersionOf: case IsNewVersionOf: case IsVariantFormOf: case IsOriginalFormOf: case IsObsoletedBy: case Obsoletes: case IsVersionOf: case HasVersion: return SUBRELTYPE.version; case IsReviewedBy: case Reviews: return SUBRELTYPE.review; } // makes the compiler happy throw new IllegalArgumentException("missing SubRel mapping for" + this); } /** * This mehtod is an implementation of the valueOF case insensitive * @param value the input Value * @return the RELCLASS */ public static RELCLASS lookUp(String value) { Optional rvlaue = Arrays.stream(RELCLASS.values()).filter(e -> e.name().equalsIgnoreCase(value)).findAny(); if (rvlaue.isPresent()) return rvlaue.get(); throw new IllegalArgumentException("value: "+value+" not found"); } @Transient public RELCLASS getInverse() { switch (this) { case IsVersionOf: return HasVersion; case IsSourceOf: return IsDerivedFrom; case isMergedIn: return merges; case IsIdenticalTo: return IsIdenticalTo; case Documents: return IsDocumentedBy; case IsAmongTopNSimilarDocuments: return HasAmongTopNSimilarDocuments; case IsSupplementedBy: return IsSupplementTo; case IsObsoletedBy: return Obsoletes; case Continues: return IsContinuedBy; case IsParentOf: return IsChildOf; case IsReferencedBy: return References; case IsCitedBy: return Cites; case Compiles: return IsCompiledBy; case IsPreviousVersionOf: return IsNewVersionOf; case HasPart: return IsPartOf; case IsDocumentedBy: return Documents; case HasAmongTopNSimilarDocuments: return IsAmongTopNSimilarDocuments; case isParticipant: return hasParticipant; case hasAuthorInstitution: return isAuthorInstitutionOf; case IsRelatedTo: return IsRelatedTo; case Requires: return IsRequiredBy; case Describes: return IsDescribedBy; case IsReviewedBy: return Reviews; case IsContinuedBy: return Continues; case provides: return isProvidedBy; case IsChildOf: return IsParentOf; case IsDescribedBy: return Describes; case IsNewVersionOf: return IsPreviousVersionOf; case IsPartOf: return HasPart; case HasVersion: return IsVersionOf; case hasParticipant: return isParticipant; case isAuthorInstitutionOf: return hasAuthorInstitution; case IsVariantFormOf: return IsOriginalFormOf; case isProducedBy: return produces; case IsMetadataFor: return IsMetadataOf; case Cites: return IsCitedBy; case IsRequiredBy: return Requires; case IsOriginalFormOf: return IsVariantFormOf; case IsSupplementTo: return IsSupplementedBy; case IsMetadataOf: return IsMetadataFor; case References: return IsReferencedBy; case IsCompiledBy: return Compiles; case isProvidedBy: return provides; case merges: return isMergedIn; case IsDerivedFrom: return IsSourceOf; case Obsoletes: return IsObsoletedBy; case Reviews: return IsReviewedBy; case produces: return isProducedBy; case isSimilarTo: return isSimilarTo; case isDifferentFrom: return isDifferentFrom; } // makes the compiler happy throw new IllegalArgumentException("missing inverse mapping for" + this); } } /** * Main relationship classifier, values include 'resultResult', 'resultProject', 'resultOrganization', etc. */ private RELTYPE relType; /** * Further classifies a relationship, values include 'affiliation', 'similarity', 'supplement', etc. */ private SUBRELTYPE subRelType; /** * Indicates the direction of the relationship, values include 'isSupplementTo', 'isSupplementedBy', 'merges, * 'isMergedIn'. */ private RELCLASS relClass; /** * The source entity id. */ private String source; /** * The target entity id. */ private String target; /** * Was this relationship authoritatively validated? */ private Boolean validated; /** * When was this relationship authoritatively validated. */ private String validationDate; private List provenance; /** * List of relation specific properties. Values include 'similarityLevel', indicating the similarity score between a * pair of publications. */ private List properties = new ArrayList<>(); public RELTYPE getRelType() { return relType; } public void setRelType(final RELTYPE relType) { this.relType = relType; } public SUBRELTYPE getSubRelType() { return subRelType; } public void setSubRelType(final SUBRELTYPE subRelType) { this.subRelType = subRelType; } public RELCLASS getRelClass() { return relClass; } public void setRelClass(final RELCLASS relClass) { this.relClass = relClass; } public String getSource() { return source; } public void setSource(final String source) { this.source = source; } public String getTarget() { return target; } public void setTarget(final String target) { this.target = target; } public List getProperties() { return properties; } public void setProperties(List properties) { this.properties = properties; } public Boolean getValidated() { return Objects.nonNull(validated) && validated; } public void setValidated(Boolean validated) { this.validated = validated; } public String getValidationDate() { return validationDate; } public void setValidationDate(String validationDate) { this.validationDate = validationDate; } public List getProvenance() { return provenance; } public void setProvenance(List provenance) { this.provenance = provenance; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Relation relation = (Relation) o; return relType.equals(relation.relType) && subRelType.equals(relation.subRelType) && relClass.equals(relation.relClass) && source.equals(relation.source) && target.equals(relation.target); } public Relation inverse() { final Relation inverse = new Relation(); inverse.setSource(this.target); inverse.setTarget(this.source); inverse.setRelClass(this.relClass.getInverse()); inverse.setRelType(this.relType); inverse.setSubRelType(this.subRelType); inverse.setProperties(this.properties); inverse.setValidated(validated); inverse.setProvenance(provenance); inverse.setValidationDate(validationDate); return inverse; } @Override public int hashCode() { return Objects.hash(relType, subRelType, relClass, source, target, provenance); } }