diff --git a/quadriga/pom.xml b/quadriga/pom.xml index 6b1b9fa6..939a6466 100644 --- a/quadriga/pom.xml +++ b/quadriga/pom.xml @@ -49,8 +49,8 @@ - - + + info @@ -112,7 +112,7 @@ org.mockito mockito-core - 3.8.0 + 4.11.0 test diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/AddNetworkApiController.java b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/AddNetworkApiController.java index 274f16e6..e258aac4 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/AddNetworkApiController.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/AddNetworkApiController.java @@ -19,6 +19,7 @@ import edu.asu.diging.quadriga.core.exception.NodeNotFoundException; import edu.asu.diging.quadriga.core.exceptions.CollectionNotFoundException; import edu.asu.diging.quadriga.core.exceptions.InvalidObjectIdException; +import edu.asu.diging.quadriga.core.exceptions.MappedTripleGroupNotFoundException; import edu.asu.diging.quadriga.core.model.MappedTripleGroup; import edu.asu.diging.quadriga.core.model.MappedTripleType; import edu.asu.diging.quadriga.core.service.EventGraphService; @@ -67,10 +68,11 @@ public HttpStatus processJson(@RequestBody Quadruple quadruple, @PathVariable St MappedTripleGroup mappedTripleGroup; try { mappedTripleGroup = mappedTripleGroupService.get(collectionId, MappedTripleType.DEFAULT_MAPPING); + logger.info("mapped triple found " + mappedTripleGroup); if(mappedTripleGroup == null) { return HttpStatus.NOT_FOUND; } - } catch(InvalidObjectIdException | CollectionNotFoundException e) { + } catch(InvalidObjectIdException | CollectionNotFoundException | MappedTripleGroupNotFoundException e) { logger.error("Couldn't submit network", e); return HttpStatus.NOT_FOUND; } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Metadata.java b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Metadata.java index 77d16419..74e6f6e8 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Metadata.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Metadata.java @@ -1,5 +1,6 @@ package edu.asu.diging.quadriga.api.v1.model; +import edu.asu.diging.quadriga.core.model.Context; import edu.asu.diging.quadriga.core.model.DefaultMapping; public class Metadata { diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/NodeData.java b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/NodeData.java index 18bce053..29c9d3a3 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/NodeData.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/NodeData.java @@ -1,5 +1,7 @@ package edu.asu.diging.quadriga.api.v1.model; +import edu.asu.diging.quadriga.core.model.Context; + public class NodeData { private String label; diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/config/PersistenceConfig.java b/quadriga/src/main/java/edu/asu/diging/quadriga/config/PersistenceConfig.java index 4083b72a..31445274 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/config/PersistenceConfig.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/config/PersistenceConfig.java @@ -24,7 +24,11 @@ @Configuration @PropertySource("classpath:config.properties") @EnableTransactionManagement -@EnableJpaRepositories(basePackages = { "edu.asu.diging.quadriga.core.data", "edu.asu.diging.simpleusers.core.data" }) +@EnableJpaRepositories(basePackages = { + "edu.asu.diging.quadriga.core.data", + "edu.asu.diging.quadriga.core.conceptpower.data", + "edu.asu.diging.simpleusers.core.data" +}) public class PersistenceConfig { @Autowired @@ -45,7 +49,10 @@ public DataSource dataSource() { public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); - em.setPackagesToScan(new String[] { "edu.asu.diging.quadriga.core.model", "edu.asu.diging.simpleusers.core.model" }); + em.setPackagesToScan(new String[] { "edu.asu.diging.quadriga.core.model", + "edu.asu.diging.quadriga.core.conceptpower.model", + "edu.asu.diging.simpleusers.core.model" + }); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptCacheRepository.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptCacheRepository.java new file mode 100644 index 00000000..7baa4317 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptCacheRepository.java @@ -0,0 +1,25 @@ +package edu.asu.diging.quadriga.core.conceptpower.data; + +import java.util.List; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; + +/** + * + * An interface used to retrieve data from conceptpower_concept_entry table that + * stores data extracted from ConceptPower + * + * @author poojakulkarni + * + */ +@Repository +public interface ConceptCacheRepository extends PagingAndSortingRepository { + + @Query("SELECT c from ConceptCache c WHERE ?1 in elements(c.alternativeUris)") + public List findConceptByAlternativeURI(String uri); + +} \ No newline at end of file diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptTypeRepository.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptTypeRepository.java new file mode 100644 index 00000000..17c8b7a9 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/data/ConceptTypeRepository.java @@ -0,0 +1,18 @@ +package edu.asu.diging.quadriga.core.conceptpower.data; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptType; + +/** + * An interface used to retrieve data from conceptpower_concept_type table that + * stores information for a concept's type extracted from ConceptPower + * + * @author poojakulkarni + * + */ +@Repository +public interface ConceptTypeRepository extends PagingAndSortingRepository { + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptCache.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptCache.java new file mode 100644 index 00000000..008c7f53 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptCache.java @@ -0,0 +1,250 @@ +package edu.asu.diging.quadriga.core.conceptpower.model; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; + +/** + * This class represents the 'conceptpower_concept_cache' table present in the + * database that stores cached concept data + * + * @author Digital Innovation Group + * + */ +@Entity +@Table(name = "conceptpower_concept_cache") +public class ConceptCache implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + @Id + private String uri; + private String id; + private String word; + private String pos; + + @Lob + private String description; + + private String conceptList; + private String typeId; + private boolean deleted; + private LocalDateTime lastUpdated; + + @ElementCollection + @LazyCollection(LazyCollectionOption.FALSE) + @CollectionTable(name = "conceptpower_alternative_uris") + private List alternativeUris; + + @ElementCollection + @LazyCollection(LazyCollectionOption.FALSE) + @CollectionTable(name = "conceptpower_equal_to") + private List equalTo; + + @ElementCollection + @LazyCollection(LazyCollectionOption.FALSE) + @CollectionTable(name = "conceptpower_wordnetids") + private List wordNetIds; + + private String creatorId; + + @Transient + private ConceptType conceptType; + + public ConceptCache() { + this.lastUpdated = LocalDateTime.now(); + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public String getPos() { + return pos; + } + + public void setPos(String pos) { + this.pos = pos; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getConceptList() { + return conceptList; + } + + public void setConceptList(String conceptList) { + this.conceptList = conceptList; + } + + public String getTypeId() { + return typeId; + } + + public void setTypeId(String typeId) { + this.typeId = typeId; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public LocalDateTime getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(LocalDateTime lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public List getAlternativeUris() { + return alternativeUris; + } + + public void setAlternativeUris(List alternativeUris) { + this.alternativeUris = alternativeUris; + } + + public List getEqualTo() { + return equalTo; + } + + public void setEqualTo(List equalTo) { + this.equalTo = equalTo; + } + + public List getWordNetIds() { + return wordNetIds; + } + + public void setWordNetIds(List wordNetIds) { + this.wordNetIds = wordNetIds; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public ConceptType getConceptType() { + return conceptType; + } + + public void setConceptType(ConceptType conceptType) { + this.conceptType = conceptType; + } + + /** + * Compares the old and new cache values to determine if a difference exists. + * + *If both old and new cache values are {@code null}, blank, or empty, no difference is present. + *If the old value is {@code null}, blank, or empty, and the new value is not {@code null}, blank, or empty, a difference is present. + *If the old value is not {@code null}, blank, or empty, and the new value is {@code null}, blank, or empty, a difference is present. + *If both values are not {@code null}, blank, or empty, their content must be compared to determine if a difference exists. + * + */ + @Override + public int compareTo(ConceptCache conceptCache) { + + if(isDifferentList(conceptCache.getAlternativeUris(), this.getAlternativeUris())) { + return -1; + } + if(isDifferentList(conceptCache.getEqualTo(), this.getEqualTo())) { + return -1; + } + if(isDifferentList(conceptCache.getWordNetIds(), this.getWordNetIds())) { + return -1; + } + if (isDifferentString(conceptCache.getConceptList(), this.getConceptList())) { + return -1; + } + if (isDifferentString(conceptCache.getCreatorId(), this.getCreatorId())) { + return -1; + } + if (isDifferentString(conceptCache.getDescription(), this.getDescription())) { + return -1; + } + if (isDifferentString(conceptCache.getId(), this.getId())) { + return -1; + } + if (isDifferentString(conceptCache.getPos(), this.getPos())) { + return -1; + } + if (isDifferentString(conceptCache.getTypeId(), this.getTypeId())) { + return -1; + } + if (isDifferentString(conceptCache.getUri(), this.getUri())) { + return -1; + } + if (isDifferentString(conceptCache.getWord(), this.getWord())) { + return -1; + } + return 0; + } + + private static boolean isDifferentString(String str1, String str2) { + if(!(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)) + && (StringUtils.isEmpty(str1) || !str1.equals(str2))) { + return true; + } + return false; + } + + private static boolean isDifferentList(List list1, List list2) { + if (!(isNullOrEmpty(list1) && isNullOrEmpty(list2) + && (isNullOrEmpty(list1) || !list1.equals(list2)))) { + return true; + } + return false; + } + + private static boolean isNullOrEmpty(List list) { + return list == null || list.isEmpty(); + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptType.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptType.java new file mode 100644 index 00000000..0b0ecf2d --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/model/ConceptType.java @@ -0,0 +1,94 @@ +package edu.asu.diging.quadriga.core.conceptpower.model; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.Table; + +import org.apache.commons.lang3.StringUtils; + +@Entity +@Table(name = "conceptpower_concept_type_cache") +public class ConceptType implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + @Id + private String id; + private String name; + private String uri; + + @Lob + private String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + /* + * If both old and new types are null/blank, nothing has changed + * If old value is null/blank, new value is not null/blank, difference present + * If old value is not null/blank, new value is null/blank, difference present + * If both are not null/blank, we need to check difference + * + */ + @Override + public int compareTo(ConceptType type) { + + if (type == null ) { + return -1; + } + if(isDifferentString(type.getId(), this.getId())) { + return -1; + } + if(isDifferentString(type.getDescription(), this.getDescription())) { + return -1; + } + if(isDifferentString(type.getName(), this.getName())) { + return -1; + } + if(isDifferentString(type.getUri(), this.getUri())) { + return -1; + } + return 0; + } + + private static boolean isDifferentString(String str1, String str2) { + if(!(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)) + && (StringUtils.isEmpty(str1) || !str1.equals(str2))) { + return true; + } + return false; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/AlternativeId.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/AlternativeId.java new file mode 100644 index 00000000..6a5bac54 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/AlternativeId.java @@ -0,0 +1,36 @@ +package edu.asu.diging.quadriga.core.conceptpower.reply.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "concept_id", "concept_uri" }) +public class AlternativeId { + + @JsonProperty("concept_id") + private String conceptId; + @JsonProperty("concept_uri") + private String conceptUri; + + @JsonProperty("concept_id") + public String getConceptId() { + return conceptId; + } + + @JsonProperty("concept_id") + public void setConceptId(String conceptId) { + this.conceptId = conceptId; + } + + @JsonProperty("concept_uri") + public String getConceptUri() { + return conceptUri; + } + + @JsonProperty("concept_uri") + public void setConceptUri(String conceptUri) { + this.conceptUri = conceptUri; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptEntry.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptEntry.java new file mode 100644 index 00000000..34dbacda --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptEntry.java @@ -0,0 +1,203 @@ + +package edu.asu.diging.quadriga.core.conceptpower.reply.model; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * + * This class represents the JSON response received from ConceptPower, with key + * 'conceptPowerEntry' under conceptPowerReply + * + * @author poojakulkarni + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "id", "lemma", "pos", "description", "conceptList", "type", "deleted", "concept_uri", "creator_id", + "equal_to", "modified_by", "similar_to", "synonym_ids", "wordnet_id", "alternativeIds" }) +public class ConceptEntry { + + @JsonProperty("id") + private String id; + @JsonProperty("lemma") + private String lemma; + @JsonProperty("pos") + private String pos; + @JsonProperty("description") + private String description; + @JsonProperty("conceptList") + private String conceptList; + @JsonProperty("type") + private Type type; + @JsonProperty("deleted") + private Boolean deleted; + @JsonProperty("concept_uri") + private String conceptUri; + @JsonProperty("creator_id") + private String creatorId; + @JsonProperty("equal_to") + private String equalTo; + @JsonProperty("modified_by") + private String modifiedBy; + @JsonProperty("similar_to") + private String similarTo; + @JsonProperty("synonym_ids") + private String synonymIds; + @JsonProperty("wordnet_id") + private String wordnetId; + @JsonProperty("alternativeIds") + private List alternativeIds = null; + + @JsonProperty("id") + public String getId() { + return id; + } + + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + @JsonProperty("lemma") + public String getLemma() { + return lemma; + } + + @JsonProperty("lemma") + public void setLemma(String lemma) { + this.lemma = lemma; + } + + @JsonProperty("pos") + public String getPos() { + return pos; + } + + @JsonProperty("pos") + public void setPos(String pos) { + this.pos = pos; + } + + @JsonProperty("description") + public String getDescription() { + return description; + } + + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + @JsonProperty("conceptList") + public String getConceptList() { + return conceptList; + } + + @JsonProperty("type") + public Type getType() { + return type; + } + + @JsonProperty("type") + public void setType(Type type) { + this.type = type; + } + + @JsonProperty("conceptList") + public void setConceptList(String conceptList) { + this.conceptList = conceptList; + } + + @JsonProperty("deleted") + public Boolean getDeleted() { + return deleted; + } + + @JsonProperty("deleted") + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + @JsonProperty("concept_uri") + public String getConceptUri() { + return conceptUri; + } + + @JsonProperty("concept_uri") + public void setConceptUri(String conceptUri) { + this.conceptUri = conceptUri; + } + + @JsonProperty("creator_id") + public String getCreatorId() { + return creatorId; + } + + @JsonProperty("creator_id") + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + @JsonProperty("equal_to") + public String getEqualTo() { + return equalTo; + } + + @JsonProperty("equal_to") + public void setEqualTo(String equalTo) { + this.equalTo = equalTo; + } + + @JsonProperty("modified_by") + public String getModifiedBy() { + return modifiedBy; + } + + @JsonProperty("modified_by") + public void setModifiedBy(String modifiedBy) { + this.modifiedBy = modifiedBy; + } + + @JsonProperty("similar_to") + public String getSimilarTo() { + return similarTo; + } + + @JsonProperty("similar_to") + public void setSimilarTo(String similarTo) { + this.similarTo = similarTo; + } + + @JsonProperty("synonym_ids") + public String getSynonymIds() { + return synonymIds; + } + + @JsonProperty("synonym_ids") + public void setSynonymIds(String synonymIds) { + this.synonymIds = synonymIds; + } + + @JsonProperty("wordnet_id") + public String getWordnetId() { + return wordnetId; + } + + @JsonProperty("wordnet_id") + public void setWordnetId(String wordnetId) { + this.wordnetId = wordnetId; + } + + @JsonProperty("alternativeIds") + public List getAlternativeIds() { + return alternativeIds; + } + + @JsonProperty("alternativeIds") + public void setAlternativeIds(List alternativeIds) { + this.alternativeIds = alternativeIds; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptPowerReply.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptPowerReply.java new file mode 100644 index 00000000..17f92115 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/ConceptPowerReply.java @@ -0,0 +1,46 @@ + +package edu.asu.diging.quadriga.core.conceptpower.reply.model; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * + * This class represents the JSON response received from ConceptPower, with key + * 'conceptPowerReply' + * + * @author poojakulkarni + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "conceptEntries", "pagination" }) +public class ConceptPowerReply { + + @JsonProperty("conceptEntries") + private List conceptEntries = null; + @JsonProperty("pagination") + private Object pagination; + + @JsonProperty("conceptEntries") + public List getConceptEntries() { + return conceptEntries; + } + + @JsonProperty("conceptEntries") + public void setConceptEntries(List conceptEntries) { + this.conceptEntries = conceptEntries; + } + + @JsonProperty("pagination") + public Object getPagination() { + return pagination; + } + + @JsonProperty("pagination") + public void setPagination(Object pagination) { + this.pagination = pagination; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/Type.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/Type.java new file mode 100644 index 00000000..bb3b6712 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/reply/model/Type.java @@ -0,0 +1,53 @@ +package edu.asu.diging.quadriga.core.conceptpower.reply.model; + +import java.util.HashMap; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "type_id", "type_uri", "type_name" }) +public class Type { + + @JsonProperty("type_id") + private String typeId; + @JsonProperty("type_uri") + private String typeUri; + @JsonProperty("type_name") + private String typeName; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + @JsonProperty("type_id") + public String getTypeId() { + return typeId; + } + + @JsonProperty("type_id") + public void setTypeId(String typeId) { + this.typeId = typeId; + } + + @JsonProperty("type_uri") + public String getTypeUri() { + return typeUri; + } + + @JsonProperty("type_uri") + public void setTypeUri(String typeUri) { + this.typeUri = typeUri; + } + + @JsonProperty("type_name") + public String getTypeName() { + return typeName; + } + + @JsonProperty("type_name") + public void setTypeName(String typeName) { + this.typeName = typeName; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptCacheService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptCacheService.java new file mode 100644 index 00000000..d2141e6f --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptCacheService.java @@ -0,0 +1,46 @@ +package edu.asu.diging.quadriga.core.conceptpower.service; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; + +/** + * A service for working with the ConceptCache entries in the database + * + * @author poojakulkarni + * + */ +public interface ConceptCacheService { + + /** + * This method gets a ConceptCache entry from the database If it is not present, + * it checks the alternative URIs to get a conceptCache entry + * + * @param uri used to check in alternativeUris + * @return a conceptCache entry + */ + public ConceptCache getConceptByUri(String uri); + + /** + * This method checks the AlternativeURIs ElementCollection of ConceptCache The + * Concept which has listed the provided URI as an alternativeURI would be + * returned + * + * @param uri to be checked as an alternativeURI + * @return a ConceptCache object from ConceptCache table + */ + public ConceptCache getConceptByAlternativeUri(String uri); + + /** + * This method saves the provided ConceptCache entity in the database + * + * @param conceptCache is the entity to be saved + */ + public void saveConceptCache(ConceptCache conceptCache); + + /** + * This method deleted the ConceptCache entry that matches the provided URI + * + * @param uri used to delete the ConceptCache entry + */ + public void deleteConceptCacheByUri(String uri); + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerConnectorService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerConnectorService.java new file mode 100644 index 00000000..ef9a1b9c --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerConnectorService.java @@ -0,0 +1,17 @@ +package edu.asu.diging.quadriga.core.conceptpower.service; + +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +/** + * A service that extracts XML data from ConceptPower using REST calls and + * parses the result into Java objects using JAXB model classes + * + * @author poojakulkarni + * + */ +public interface ConceptPowerConnectorService { + + public ConceptPowerReply getConceptPowerReply(String conceptURI) throws ConceptpowerNoResponseException; + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerService.java new file mode 100644 index 00000000..e8313707 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptPowerService.java @@ -0,0 +1,40 @@ +package edu.asu.diging.quadriga.core.conceptpower.service; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +/** + * This service is used to get concept data from ConceptPower + * + * @author poojakulkarni + * + */ +public interface ConceptPowerService { + + /** + * This method checks if Concept is present in DB If concept is present in DB & + * updated within last 2 days then it just returns the concept If concept is + * present in DB & is not updated within last 2 days, it calls conceptpower, + * gets latest concept data, updates the concept in the database and then + * returns the concept If concept is not present in DB, it calls conceptpower + * gets latest concept data, creates an entry for the concept in the database + * and returns the concept + * + * @param uri used to search entry in database or make a REST call to + * conceptpower + * @return the conceptCache database entry + * @throws ConceptpowerNoResponseException + */ + public ConceptCache getConceptByUri(String uri) throws ConceptpowerNoResponseException; + + /** + * This method maps the ConceptPowerReply object returned from ConceptPower to a + * ConceptCache object that would be stored in the database + * + * @param conceptPowerReply is the object used to generate a ConceptCache object + * @return the generated ConceptCache object + */ + public ConceptCache mapConceptPowerReplyToConceptCache(ConceptPowerReply conceptPowerReply); + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptTypeService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptTypeService.java new file mode 100644 index 00000000..103ae153 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/ConceptTypeService.java @@ -0,0 +1,9 @@ +package edu.asu.diging.quadriga.core.conceptpower.service; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptType; + +public interface ConceptTypeService { + + public void saveConceptType(ConceptType conceptType); + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImpl.java new file mode 100644 index 00000000..a17bf468 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImpl.java @@ -0,0 +1,48 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.asu.diging.quadriga.core.conceptpower.data.ConceptCacheRepository; +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptCacheService; + +@Service +public class ConceptCacheServiceImpl implements ConceptCacheService { + + @Autowired + private ConceptCacheRepository conceptCacheRepository; + + @Override + public ConceptCache getConceptByUri(String uri) { + ConceptCache conceptCache = conceptCacheRepository.findById(uri).orElse(null); + if (conceptCache == null) { + conceptCache = getConceptByAlternativeUri(uri); + } + return conceptCache; + } + + @Override + public ConceptCache getConceptByAlternativeUri(String uri) { + List conceptCacheList = conceptCacheRepository.findConceptByAlternativeURI(uri); + if (conceptCacheList != null && !conceptCacheList.isEmpty()) { + return conceptCacheList.get(0); + } + return null; + } + + @Override + public void saveConceptCache(ConceptCache conceptCache) { + conceptCacheRepository.save(conceptCache); + } + + @Override + public void deleteConceptCacheByUri(String uri) { + if (uri != null && !uri.isEmpty()) { + conceptCacheRepository.deleteById(uri); + } + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImpl.java new file mode 100644 index 00000000..019c32b9 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImpl.java @@ -0,0 +1,70 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerConnectorService; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +@Service +@PropertySource({ "classpath:config.properties" }) +public class ConceptPowerConnectorServiceImpl implements ConceptPowerConnectorService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Value("${conceptpower_base_url}") + private String conceptPowerBaseURL; + + @Value("${conceptpower_id_endpoint}") + private String conceptPowerIdEndpoint; + + private RestTemplate restTemplate; + + public ConceptPowerConnectorServiceImpl() { + restTemplate = new RestTemplate(); + } + + @Override + public ConceptPowerReply getConceptPowerReply(String conceptURI) throws ConceptpowerNoResponseException { + Map parameters = new HashMap<>(); + parameters.put("concept_uri", conceptURI); + String conceptPowerURL = conceptPowerBaseURL + conceptPowerIdEndpoint; + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity httpEntity = new HttpEntity<>(httpHeaders); + ResponseEntity response; + + try { + response = restTemplate.exchange(conceptPowerURL, + HttpMethod.GET, httpEntity, ConceptPowerReply.class, parameters); + if(response == null) { + throw new ConceptpowerNoResponseException("ConceptPower returned a null response for URI: " + conceptURI); + } + } + catch (HttpClientErrorException e) { + throw new ConceptpowerNoResponseException("Error occurred while contacting ConceptPower for URI: " + conceptURI,e); + } + catch(Exception e) { + throw new ConceptpowerNoResponseException("Unexpected error occurred while processing ConceptPower response for URI: " + conceptURI,e); + } + return response.getBody(); + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImpl.java new file mode 100644 index 00000000..6721bd73 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImpl.java @@ -0,0 +1,208 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptType; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptEntry; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.Type; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptCacheService; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerConnectorService; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerService; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptTypeService; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +@Service +public class ConceptPowerServiceImpl implements ConceptPowerService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ConceptCacheService conceptCacheService; + + @Autowired + private ConceptTypeService conceptTypeService; + + @Autowired + private ConceptPowerConnectorService conceptPowerConnectorService; + + @Value("${conceptCacheUpdateInterval}") + private Integer conceptCacheUpdateInterval; + + @Override + public ConceptCache getConceptByUri(String uri) throws ConceptpowerNoResponseException { + + ConceptCache conceptCache = conceptCacheService.getConceptByUri(uri); + + if (conceptCache == null || ChronoUnit.HOURS.between(conceptCache.getLastUpdated(), LocalDateTime.now()) >= conceptCacheUpdateInterval) { + conceptCache = saveConceptCacheFromConceptPowerReply(conceptCache, conceptPowerConnectorService.getConceptPowerReply(uri), uri); + } + return conceptCache; + } + + /** + * This method first saves the ConceptCache entry in the database which is + * mapped from ConceptPowerReply + * + * Then it saves the corresponding ConceptType entry in the database, if one + * exists + * + * After that, it checks if there are any concepts in the database which have + * the same URI as this concept's alternativeURIs. If such concepts exist, they + * will be deleted + * + * E.g.: Consider => Concepts => {AlternativeURIs} + * + * Existing Concepts in the database: C2 => {C2, C4}, C3 => {C3, C5} + * + * New Concept to be added to the database: C1 => {C1, C2, C3, C5} + * + * In this case, delete C2 and C3 from the database as C1 has listed C2 and C3 + * as alternatives If in the future, the concepts C2 or C3 are searched in the + * database, C1 will be returned + * + * @param conceptPowerReply is the object used to generate a ConceptCache object + * @param uri to be used for logging in case no ConceptCache entry + * was generated + */ + private ConceptCache saveConceptCacheFromConceptPowerReply(ConceptCache conceptCacheOld, ConceptPowerReply conceptPowerReply, String uri) { + ConceptCache conceptCache = mapConceptPowerReplyToConceptCache(conceptPowerReply); + + // Before returning, we need to check if we've updated ConceptCache or not + // If no diff was found, conceptCache won't be updated and 'lastUpdated' would stay the same + boolean updated = updateConceptCache(conceptCache, conceptCacheOld, uri); + + updated = updated || updateConceptType(conceptCache,conceptCacheOld); + + return updated ? conceptCache : conceptCacheOld; + } + + /** + * Updates Concept Type + * @param conceptCache + * @param conceptCacheOld + * @return + */ + private boolean updateConceptType(ConceptCache conceptCache, ConceptCache conceptCacheOld) { + if(conceptCache != null && conceptCache.getConceptType() != null) { + + ConceptType conceptType = conceptCache.getConceptType(); + ConceptType conceptTypeOld = null; + + if(conceptCacheOld != null) { + conceptTypeOld = conceptCacheOld.getConceptType(); + } + + // ConceptPower returned a concept type and either no conceptType entry exists in the DB + // or if one exists, it is different from the current conceptType entry + if (conceptType != null && (conceptTypeOld == null || conceptTypeOld.compareTo(conceptType) != 0)) { + + conceptCache.setConceptType(conceptType); + conceptTypeService.saveConceptType(conceptType); + return true; + } + } + return false; + } + + /** + * This method is to update concept cache. + * + * It checks if a concept is returned by conceptpower + * and no conceptcache exists in db or if it does, it is different from the current conceptCache entry + * and updates the conceptcache + * + * @param conceptCache + * @param conceptCacheOld + * @param uri + * + * @return + */ + private boolean updateConceptCache(ConceptCache conceptCache, ConceptCache conceptCacheOld, String uri) { + if (conceptCache != null && (conceptCacheOld == null || conceptCacheOld.compareTo(conceptCache) != 0)) { + conceptCacheService.saveConceptCache(conceptCache); + + Optional.ofNullable(conceptCache.getAlternativeUris()) + .ifPresent(nonNullAlternativeUris -> nonNullAlternativeUris + .stream() + .filter(alternativeUri -> alternativeUri != null) + .filter(nonNullAlternativeUri -> !nonNullAlternativeUri.equals(conceptCache.getUri())) + .forEach(alternativeUriValue -> conceptCacheService.deleteConceptCacheByUri(alternativeUriValue))); + return true; + + } else if(conceptCache == null) { + logger.error("ConceptPower did not return any concept entries for uri: " + uri); + + } + return false; + } + + @Override + public ConceptCache mapConceptPowerReplyToConceptCache(ConceptPowerReply conceptPowerReply) { + // If we get multiple ConceptPower entries in the reply, we use the first one + List conceptEntries = conceptPowerReply.getConceptEntries(); + ConceptCache conceptCache = null; + + if (conceptEntries == null || conceptEntries.isEmpty()) { + return conceptCache; + } + ConceptEntry conceptEntry = conceptEntries.get(0); + conceptCache = new ConceptCache(); + conceptCache.setUri(conceptEntry.getConceptUri()); + conceptCache.setConceptList(conceptEntry.getConceptList()); + conceptCache.setDescription(conceptEntry.getDescription()); + conceptCache.setPos(conceptEntry.getPos()); + conceptCache.setDeleted(conceptEntry.getDeleted() == null ? false : conceptEntry.getDeleted()); + conceptCache.setCreatorId(conceptEntry.getCreatorId()); + conceptCache.setWord(conceptEntry.getLemma()); + conceptCache.setId(conceptEntry.getId()); + + if (conceptEntry.getWordnetId() != null && !conceptEntry.getWordnetId().trim().equals("")) { + conceptCache.setWordNetIds(Arrays.asList(conceptEntry.getWordnetId().split(","))); + } else { + conceptCache.setWordNetIds(new ArrayList<>()); + } + + if (conceptEntry.getEqualTo() != null && !conceptEntry.getEqualTo().trim().equals("")) { + conceptCache.setEqualTo(Arrays.asList(conceptEntry.getEqualTo().split(","))); + } else { + conceptCache.setEqualTo(new ArrayList<>()); + } + + if(conceptEntry.getAlternativeIds() != null && !conceptEntry.getAlternativeIds().isEmpty()) { + conceptCache.setAlternativeUris( + conceptEntry.getAlternativeIds() + .stream() + .map(alternativeId -> alternativeId.getConceptUri()) + .filter(nullableAltUri -> nullableAltUri != null) + .filter(alternativeUri -> !alternativeUri.equals("")) + .collect(Collectors.toList())); + } + + if (conceptEntry.getType() != null) { + Type type = conceptEntry.getType(); + ConceptType conceptType = new ConceptType(); + conceptType.setUri(type.getTypeUri()); + conceptType.setId(type.getTypeId()); + conceptType.setName(type.getTypeName()); + conceptType.setDescription(""); + conceptCache.setConceptType(conceptType); + conceptCache.setTypeId(conceptEntry.getType().getTypeUri()); + } + return conceptCache; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptTypeServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptTypeServiceImpl.java new file mode 100644 index 00000000..b2563431 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptTypeServiceImpl.java @@ -0,0 +1,21 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.asu.diging.quadriga.core.conceptpower.data.ConceptTypeRepository; +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptType; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptTypeService; + +@Service +public class ConceptTypeServiceImpl implements ConceptTypeService { + + @Autowired + private ConceptTypeRepository conceptTypeRepository; + + @Override + public void saveConceptType(ConceptType conceptType) { + conceptTypeRepository.save(conceptType); + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/EventGraphRepository.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/EventGraphRepository.java index 3614428d..93b070d9 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/EventGraphRepository.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/EventGraphRepository.java @@ -4,12 +4,22 @@ import java.util.Optional; import org.bson.types.ObjectId; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; import edu.asu.diging.quadriga.core.model.EventGraph; public interface EventGraphRepository extends MongoRepository { + + public Optional> findByCollectionId(ObjectId collectionId); public Optional findFirstByCollectionIdOrderByCreationTimeDesc(ObjectId collectionId); + + public Optional> findByCollectionIdOrderByCreationTimeAsc(ObjectId collectionId, Pageable Pageable); + + public Optional> findByCollectionIdOrderByCreationTimeAsc(ObjectId collectionId); + } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/exceptions/ConceptpowerNoResponseException.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/exceptions/ConceptpowerNoResponseException.java new file mode 100644 index 00000000..ba38a7ac --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/exceptions/ConceptpowerNoResponseException.java @@ -0,0 +1,26 @@ +package edu.asu.diging.quadriga.core.exceptions; + +public class ConceptpowerNoResponseException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public ConceptpowerNoResponseException() { + super(); + } + + public ConceptpowerNoResponseException(String message, Throwable cause) { + super(message, cause); + } + + public ConceptpowerNoResponseException(String message) { + super(message); + } + + public ConceptpowerNoResponseException(Throwable cause) { + super(cause); + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Collection.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Collection.java index 6f6fe7f1..42ffd785 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Collection.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Collection.java @@ -21,6 +21,7 @@ public class Collection { private String owner; private OffsetDateTime creationTime; + private boolean archived; /** diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Context.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Context.java similarity index 80% rename from quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Context.java rename to quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Context.java index 12bbd452..c373bff3 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/api/v1/model/Context.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/Context.java @@ -1,14 +1,14 @@ -package edu.asu.diging.quadriga.api.v1.model; +package edu.asu.diging.quadriga.core.model; public class Context { - private String creator; + private String creator; - private String creationTime; + private String creationTime; - private String creationPlace; + private String creationPlace; - private String sourceUri; + private String sourceUri; public String getCreator() { return creator; diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/EventGraph.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/EventGraph.java index e1ca81d3..eb6bb987 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/EventGraph.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/model/EventGraph.java @@ -13,6 +13,8 @@ public class EventGraph { private DefaultMapping defaultMapping; private OffsetDateTime creationTime; private ObjectId collectionId; + private Context context; + private String submittingApp; public EventGraph() {} @@ -61,6 +63,14 @@ public void setCollectionId(ObjectId collectionId) { this.collectionId = collectionId; } + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + public String getSubmittingApp() { return submittingApp; } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/CollectionManager.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/CollectionManager.java index e43497fa..e19dfdf0 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/CollectionManager.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/CollectionManager.java @@ -38,6 +38,7 @@ public interface CollectionManager { /** * + * Edits an existing Collection and updates it in the db * @param id of the collection that needs to be updated * @param name will be the updated name value @@ -66,7 +67,21 @@ public interface CollectionManager { * @throws InvalidObjectIdException if collectionId couldn't be converted to ObjectId */ public Collection deleteCollection(String id) throws CollectionNotFoundException, InvalidObjectIdException; - + + /** + * This method checks whether a collection with given collectionId exists and + * returns the collection if it exists. + * If it doesn't exist, it simply throws an exception + * + * @param collectionId is the id of the collection to be checked + * @return the Collection entry found in the database + * @throws InvalidObjectIdException if collectionId couldn't be conveted to + * ObjectId + * @throws CollectionNotFoundException if collection with given collectionId + * does't exist + */ + public Collection getCollection(String collectionId) throws InvalidObjectIdException, CollectionNotFoundException; + /** * This method returns the number of default mappings present in the collection * One MappedTripleGroup will exist for the "DefaultMappings" for this collection diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/EventGraphService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/EventGraphService.java index 8683c821..81c9ee7b 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/EventGraphService.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/EventGraphService.java @@ -3,6 +3,8 @@ import java.util.List; import org.bson.types.ObjectId; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import edu.asu.diging.quadriga.api.v1.model.Graph; import edu.asu.diging.quadriga.core.exceptions.InvalidObjectIdException; @@ -32,6 +34,20 @@ public interface EventGraphService { * @return total count */ public long getNumberOfSubmittedNetworks(ObjectId collectionId); + + /** + * Returns all event graphs by collection id + * @param collectionId + * @param size + * @param page + * @return + */ + public Page findAllEventGraphsByCollectionId(ObjectId collectionId, Pageable pageable); + + + public List findAllEventGraphsByCollectionId(ObjectId collectionId); + + /** * Maps the network to events and saves it in the database diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/MappedTripleGroupService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/MappedTripleGroupService.java index 0784eb66..3ab83ff8 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/MappedTripleGroupService.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/MappedTripleGroupService.java @@ -30,6 +30,6 @@ public MappedTripleGroup updateName(String mappedTripleGroupId, String name) throws InvalidObjectIdException, MappedTripleGroupNotFoundException; public MappedTripleGroup get(String collectionId, MappedTripleType mappedTripleType) - throws InvalidObjectIdException, CollectionNotFoundException; + throws InvalidObjectIdException, CollectionNotFoundException, MappedTripleGroupNotFoundException; } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/CollectionManagerImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/CollectionManagerImpl.java index 1f4c53e7..f0170e60 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/CollectionManagerImpl.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/CollectionManagerImpl.java @@ -124,6 +124,18 @@ public Collection deleteCollection(String id) throws CollectionNotFoundException throw new CollectionNotFoundException("CollectionId: " + id); } } + + /* (non-Javadoc) + * @see edu.asu.diging.quadriga.core.service.ICollectionManager#getCollection(java.lang.String) + */ + @Override + public Collection getCollection(String collectionId) throws InvalidObjectIdException, CollectionNotFoundException { + Collection collection = findCollection(collectionId); + if (collection == null) { + throw new CollectionNotFoundException("CollectionId: " + collectionId); + } + return collection; + } /* (non-Javadoc) * @see edu.asu.diging.quadriga.core.service.CollectionManager#findCollections(java.lang.String, java.util.List, org.springframework.data.domain.Pageable) diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImpl.java index 629bd61d..b0bbab54 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImpl.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImpl.java @@ -6,6 +6,8 @@ import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import edu.asu.diging.quadriga.api.v1.model.Graph; @@ -37,6 +39,16 @@ public void saveEventGraphs(List events) { } } + @Override + public List findAllEventGraphsByCollectionId(ObjectId collectionId) { + return repo.findByCollectionIdOrderByCreationTimeAsc(collectionId).orElse(null); + } + + @Override + public Page findAllEventGraphsByCollectionId(ObjectId collectionId, Pageable pageable) { + return repo.findByCollectionIdOrderByCreationTimeAsc(collectionId, pageable).orElse(null); + } + @Override public EventGraph findLatestEventGraphByCollectionId(ObjectId collectionId) { return repo.findFirstByCollectionIdOrderByCreationTimeDesc(collectionId).orElse(null); @@ -58,6 +70,7 @@ public void mapNetworkAndSave(Graph graph, String collectionId) { eventGraphs.forEach(e -> { e.setCollectionId(new ObjectId(collectionId)); e.setDefaultMapping(graph.getMetadata().getDefaultMapping()); + e.setContext(graph.getMetadata().getContext()); /* * FIXME: * diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/MappedTripleGroupServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/MappedTripleGroupServiceImpl.java index 845e7d33..c43d71d1 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/MappedTripleGroupServiceImpl.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/service/impl/MappedTripleGroupServiceImpl.java @@ -2,6 +2,9 @@ import org.bson.types.ObjectId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -23,6 +26,9 @@ public class MappedTripleGroupServiceImpl implements MappedTripleGroupService { @Autowired private CollectionManager collectionManager; + + private Logger logger = LoggerFactory.getLogger(getClass()); + /** * Converts the given collectionId into an ObjectId and persists a @@ -135,17 +141,24 @@ public MappedTripleGroup updateName(String mappedTripleGroupId, String name) * ObjectId * @throws CollectionNotFoundException if a collection for given collectionId * doesn't exist + * @throws MappedTripleGroupNotFoundException */ @Override public MappedTripleGroup get(String collectionId, MappedTripleType mappedTripleType) - throws InvalidObjectIdException, CollectionNotFoundException { + throws InvalidObjectIdException, CollectionNotFoundException, MappedTripleGroupNotFoundException { MappedTripleGroup mappedTripleGroup = findByCollectionIdAndMappingType(collectionId, mappedTripleType); // In case this is a new collection, or existing collection but new mapping type for that collection // we create a new MappedTripleGroup entry if (mappedTripleGroup == null) { mappedTripleGroup = add(collectionId, mappedTripleType); + + // If mappedTripleGroup add fails + if (mappedTripleGroup == null) { + throw new MappedTripleGroupNotFoundException("Couldn't find or persist a new MappedTripleGroup entry for collectionId: " + collectionId); + } } + return mappedTripleGroup; } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/DisplayCollectionController.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/DisplayCollectionController.java index b6814130..8c653bb5 100644 --- a/quadriga/src/main/java/edu/asu/diging/quadriga/web/DisplayCollectionController.java +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/DisplayCollectionController.java @@ -1,18 +1,45 @@ package edu.asu.diging.quadriga.web; +import javax.servlet.http.HttpServletRequest; + +import java.util.ArrayList; +import java.util.Collections; +import java.time.ZoneId; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import java.time.ZoneId; +import java.util.List; +import java.util.stream.Collectors; + +import org.bson.types.ObjectId; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; + +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.support.RequestContextUtils; + +import edu.asu.diging.quadriga.core.exceptions.CollectionNotFoundException; + import edu.asu.diging.quadriga.core.exceptions.InvalidObjectIdException; import edu.asu.diging.quadriga.core.model.Collection; import edu.asu.diging.quadriga.core.model.EventGraph; import edu.asu.diging.quadriga.core.service.CollectionManager; import edu.asu.diging.quadriga.core.service.EventGraphService; +import edu.asu.diging.quadriga.core.service.MappedTripleGroupService; +import edu.asu.diging.quadriga.core.service.PredicateManager; @Controller public class DisplayCollectionController { @@ -22,34 +49,51 @@ public class DisplayCollectionController { @Autowired private EventGraphService eventGraphService; - + private Logger logger = LoggerFactory.getLogger(getClass()); - @RequestMapping(value = "/auth/collections/{id}", method = RequestMethod.GET) - public String get(@PathVariable String id, Model model) { - + @RequestMapping(value = "/auth/collections/{collectionId}", method = RequestMethod.GET) + public String get( @RequestParam(value = "0", required = false) Integer page, @RequestParam(value="10", required = false) Integer size, @PathVariable String collectionId, Model model) { + + // Get collection details Collection collection; try { - collection = collectionManager.findCollection(id); + collection = collectionManager.findCollection(collectionId); if(collection == null) { - logger.error("Couldn't find collection: ", id); + logger.error("Couldn't find collection: ", collectionId); return "error404Page"; } } catch (InvalidObjectIdException e) { logger.error("Couldn't find collection ", e); return "error404Page"; } - + + model.addAttribute("collection", collection); + + model.addAttribute("size", size); + EventGraph latestNetwork = eventGraphService.findLatestEventGraphByCollectionId(collection.getId()); model.addAttribute("latestNetwork", latestNetwork); - model.addAttribute("collection", collection); + + Pageable paging = PageRequest.of(page, size); + + // Get all EventGraphs for this collection + Page eventGraphsList = eventGraphService.findAllEventGraphsByCollectionId(collection.getId(), paging); + + long numberOfSubmittedNetworks = eventGraphService.getNumberOfSubmittedNetworks(collection.getId()); + + + model.addAttribute("networks", eventGraphsList.getContent()); + model.addAttribute("totalPages", eventGraphsList.getTotalPages()); + model.addAttribute("pageNumber", page); + model.addAttribute("collection", collection); model.addAttribute("numberOfSubmittedNetworks", numberOfSubmittedNetworks); + model.addAttribute("collection", collection); // Get default mappings from Concepts model.addAttribute("defaultMappings", collectionManager.getNumberOfDefaultMappings(collection.getId().toString())); return "auth/displayCollection"; - - } + } } diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/NetworkController.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/NetworkController.java new file mode 100644 index 00000000..72dc18fe --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/NetworkController.java @@ -0,0 +1,61 @@ +package edu.asu.diging.quadriga.web; + +import java.util.List; + +import org.apache.commons.validator.routines.UrlValidator; +import org.bson.types.ObjectId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import edu.asu.diging.quadriga.core.model.EventGraph; +import edu.asu.diging.quadriga.core.service.EventGraphService; +import edu.asu.diging.quadriga.web.service.GraphCreationService; + +@Controller +public class NetworkController { + + @Autowired + private EventGraphService eventGraphService; + + @Autowired + private GraphCreationService graphCreationService; + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @RequestMapping(value = "/auth/collections/{collectionId}/network/") + public String get(@PathVariable String collectionId, + @RequestParam(value = "sourceUri", required = true) String sourceUri, Model model) { + + if (!isSourceUriValid(sourceUri)) { + logger.error("Invalid sourceUri: " + sourceUri); + return "error404Page"; + } + + List eventGraphs = eventGraphService.findAllEventGraphsByCollectionId(new ObjectId(collectionId)); + + if (eventGraphs == null) { + logger.error("No network found for collectionId: " + collectionId); + return "error404Page"; + } + + model.addAttribute("elements", graphCreationService.createGraph(eventGraphs)); + model.addAttribute("sourceURI", sourceUri); + + model.addAttribute("creator", eventGraphs.get(0).getContext().getCreator()); + model.addAttribute("appName", eventGraphs.get(0).getSubmittingApp()); + model.addAttribute("creationTime", eventGraphs.get(0).getCreationTime()); + return "auth/displayNetwork"; + } + + private boolean isSourceUriValid(String sourceURI) { + UrlValidator urlValidator = new UrlValidator(new String[] { "http", "https" }); + return urlValidator.isValid(sourceURI); + } + +} \ No newline at end of file diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphData.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphData.java new file mode 100644 index 00000000..cf3adc99 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphData.java @@ -0,0 +1,15 @@ +package edu.asu.diging.quadriga.web.model; + +public class GraphData { + + private String id; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + +} \ No newline at end of file diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphEdgeData.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphEdgeData.java new file mode 100644 index 00000000..254ad5c2 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphEdgeData.java @@ -0,0 +1,28 @@ +package edu.asu.diging.quadriga.web.model; + +public class GraphEdgeData extends GraphData { + + private String source; + private String target; + private String eventGraphId; + + public String getSource() { + return source; + } + public void setSource(String source) { + this.source = source; + } + public String getTarget() { + return target; + } + public void setTarget(String target) { + this.target = target; + } + public String getEventGraphId() { + return eventGraphId; + } + public void setEventGraphId(String eventGraphId) { + this.eventGraphId = eventGraphId; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElement.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElement.java new file mode 100644 index 00000000..1d745e6b --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElement.java @@ -0,0 +1,15 @@ +package edu.asu.diging.quadriga.web.model; + +public class GraphElement { + + private GraphData data; + + public GraphData getData() { + return data; + } + + public void setData(GraphData data) { + this.data = data; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElements.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElements.java new file mode 100644 index 00000000..c0a21a78 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphElements.java @@ -0,0 +1,23 @@ +package edu.asu.diging.quadriga.web.model; + +import java.util.List; + +public class GraphElements { + + private List nodes; + private List edges; + + public List getNodes() { + return nodes; + } + public void setNodes(List nodes) { + this.nodes = nodes; + } + public List getEdges() { + return edges; + } + public void setEdges(List edges) { + this.edges = edges; + } + +} \ No newline at end of file diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeData.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeData.java new file mode 100644 index 00000000..ad18407a --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeData.java @@ -0,0 +1,51 @@ +package edu.asu.diging.quadriga.web.model; + +import java.util.List; + +public class GraphNodeData extends GraphData { + + private int group; + private String label; + private String description; + private String uri; + private List eventGraphIds; + private List alternativeUris; + + public int getGroup() { + return group; + } + public void setGroup(int group) { + this.group = group; + } + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + public List getEventGraphIds() { + return eventGraphIds; + } + public void setEventGraphIds(List eventGraphIds) { + this.eventGraphIds = eventGraphIds; + } + public List getAlternativeUris() { + return alternativeUris; + } + public void setAlternativeUris(List alternativeUris) { + this.alternativeUris = alternativeUris; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeType.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeType.java new file mode 100644 index 00000000..0b9ad30c --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/GraphNodeType.java @@ -0,0 +1,22 @@ +package edu.asu.diging.quadriga.web.model; + +public enum GraphNodeType { + + PREDICATE(0), + SUBJECT(1), + OBJECT(1); + + /** + * Corresponds to the group in GraphNodeData. + */ + private int groupId; + + private GraphNodeType(int groupId) { + this.groupId = groupId; + } + + public int getGroupId() { + return groupId; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/Network.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/Network.java new file mode 100644 index 00000000..b6c41696 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/model/Network.java @@ -0,0 +1,42 @@ +package edu.asu.diging.quadriga.web.model; + +import java.time.ZonedDateTime; + +/** + * A model to display networks on the collection page + * @author poojakulkarni + * + */ +public class Network { + + private String sourceURI; + private ZonedDateTime creationTime; + private String creator; + private String appName; + + public String getSourceURI() { + return sourceURI; + } + public void setSourceURI(String sourceURI) { + this.sourceURI = sourceURI; + } + public ZonedDateTime getCreationTime() { + return creationTime; + } + public void setCreationTime(ZonedDateTime zonedDateTime) { + this.creationTime = zonedDateTime; + } + public String getCreator() { + return creator; + } + public void setCreator(String creator) { + this.creator = creator; + } + public String getAppName() { + return appName; + } + public void setAppName(String appName) { + this.appName = appName; + } + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/GraphCreationService.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/GraphCreationService.java new file mode 100644 index 00000000..802cd44f --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/GraphCreationService.java @@ -0,0 +1,122 @@ +package edu.asu.diging.quadriga.web.service; + +import java.util.List; +import java.util.Map; + +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; +import edu.asu.diging.quadriga.core.model.EventGraph; +import edu.asu.diging.quadriga.core.model.events.AppellationEvent; +import edu.asu.diging.quadriga.core.model.events.RelationEvent; +import edu.asu.diging.quadriga.web.model.GraphData; +import edu.asu.diging.quadriga.web.model.GraphElements; +import edu.asu.diging.quadriga.web.model.GraphNodeData; +import edu.asu.diging.quadriga.web.model.GraphNodeType; + +/** + * This class is used as a service to create a network graph for the Cytoscape JS + * library. Any class that wants to have a custom implementation of graph creation + * for CytoscapeJS should implement this service. + * + * @author poojakulkarni + * + */ +public interface GraphCreationService { + + /** + * Creates a graph in the form that could be understood by Cytoscape: + * + * elements: { + * nodes: { + * [ + * {data: {id: "", group: "", label: ""}}, + * {data: {id: "", group: "", label: ""}} + * ] + * }, + * edges: { + * [ + * {data: {id: "", source: "", target: ""}}, + * {data: {id: "", source: "", target: ""}}, + * {data: {id: "", source: "", target: ""}} + * ] + * } + * } + * + * @param eventGraph is the source of data for creating the graph + * @return a GraphElements object that resembles the above JSON structure + */ + public GraphElements createGraph(List eventGraph); + + /** + * This method creates nodes and edges for subject, object and predicate nodes + * For a predicate node, the event type is always appellation event and the predicate node is created + * + * For subject and object, if the event type is appellation then the nodes that are created are leaf + * nodes + * But if event type is relation event, this method is called recursively to because every relation event + * itself has subject, object and predicate + * + * After the nodes are created, both subject and object are linked to the predicate node by creating edges + * One edge goes from subject to predicate, another one from object to predicate + * + * The predicate node's id is returned to the parent of the subtree, so that it could + * be linked to its parent's predicate + * + * @param event is the relation event for which the method createes subject, object and predicate nodes + * @param graphNodes maintain the list of nodes created + * @param graphEdges maintain the list of edges created + * @param uniqueNodes maintains a map that links every unique sourceURI to its corresponding node + * @param eventGraphId is the id of the current EventGraph + * @return + * @throws ConceptpowerNoResponseException + */ + public String createNodesAndEdges(RelationEvent event, List graphNodes, List graphEdges, + Map uniqueNodes, String eventGraphId) throws ConceptpowerNoResponseException; + + /** + * Creates a predicate node using the event data and adds it to list of graph nodes + * + * @param graphNodes list to maintain all current graph nodes + * @param event is an appellation event that contains data to be set to the node + * @return the id of the created predicate node + * @throws ConceptpowerNoResponseException + */ + public String createPredicateNode(List graphNodes, AppellationEvent event, String eventGraphId) throws ConceptpowerNoResponseException; + + /** + * Checks if the unique nodes map contains the same sourceURI as the node to be created + * If yes, returns this node + * Else it creates a subject or object node using the event data and adds it to the list of graph nodes + * and the map of unique nodes with key as sourceURI and value as the node object itself + * + * @param graphNodes list to maintain all current graph nodes + * @param event is an appellation event that contains data to be set to the node + * @param uniqueNodes map to maintain nodes with unique sourceURI that can be reused + * @param graphNodeType indicates whether node to be created is subject or object node to accordingly set group id + * @return the id of an existing node from unique nodes or the newly created node + * @throws ConceptpowerNoResponseException + */ + + public String createSubjectOrObjectNode(List graphNodes, AppellationEvent event, Map uniqueNodes, GraphNodeType graphNodeType, String eventGraphId) throws ConceptpowerNoResponseException; + + /** + * Creates a GraphNodeData object and sets details such as id, label, group + * + * @param event is the appellation event for which node is being created + * @param graphNodeType used to set group id + * @return the created GraphNodeData object + * @throws ConceptpowerNoResponseException + */ + public GraphNodeData createNode(AppellationEvent event, GraphNodeType graphNodeType, String eventGraphId) throws ConceptpowerNoResponseException; + + /** + * Creates that edge that links the provided source and target using their IDs and it to + * the list of graphEdges + * + * @param graphEdges is the list that maintains all edges created for the graph + * @param sourceId is the source node's id to be linked to the target + * @param targetId is the target node's id to be linked to the source + */ + public void createEdge(List graphEdges, String sourceId, String targetId, String eventGraphId); + + +} diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImpl.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImpl.java new file mode 100644 index 00000000..84864776 --- /dev/null +++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImpl.java @@ -0,0 +1,195 @@ +package edu.asu.diging.quadriga.web.service.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bson.types.ObjectId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerService; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; +import edu.asu.diging.quadriga.core.model.EventGraph; +import edu.asu.diging.quadriga.core.model.elements.Relation; +import edu.asu.diging.quadriga.core.model.events.AppellationEvent; +import edu.asu.diging.quadriga.core.model.events.RelationEvent; +import edu.asu.diging.quadriga.web.model.GraphData; +import edu.asu.diging.quadriga.web.model.GraphEdgeData; +import edu.asu.diging.quadriga.web.model.GraphElement; +import edu.asu.diging.quadriga.web.model.GraphElements; +import edu.asu.diging.quadriga.web.model.GraphNodeData; +import edu.asu.diging.quadriga.web.model.GraphNodeType; +import edu.asu.diging.quadriga.web.service.GraphCreationService; + +@Service +public class GraphCreationServiceImpl implements GraphCreationService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ConceptPowerService conceptPowerService; + + @Override + public GraphElements createGraph(List eventGraphs){ + + List graphEdges = new ArrayList<>(); + List graphNodes = new ArrayList<>(); + Map uniqueNodes = new HashMap(); + + eventGraphs.stream() + .filter(eventGraph -> eventGraph.getRootEvent() instanceof RelationEvent) + .forEach(validEventGraph -> { + try { + createNodesAndEdges((RelationEvent) (validEventGraph.getRootEvent()), + graphNodes, graphEdges, uniqueNodes, validEventGraph.getId().toString()); + } + catch (ConceptpowerNoResponseException e) { + logger.error("Could not create graph for id : "+validEventGraph.getId(), e); + } + }); + + GraphElements graphElements = new GraphElements(); + graphElements.setNodes(wrapInGraphElements(graphNodes)); + graphElements.setEdges(wrapInGraphElements(graphEdges)); + + return graphElements; + } + + @Override + public String createNodesAndEdges(RelationEvent event, List graphNodes, List graphEdges, + Map uniqueNodes, String eventGraphId) throws ConceptpowerNoResponseException { + Relation relation = event.getRelation(); + String predicateNodeId = null; + String subjectNodeId = null; + String objectNodeId = null; + + if (relation.getPredicate() != null) { + predicateNodeId = createPredicateNode(graphNodes, relation.getPredicate(), eventGraphId); + } else { + logger.error("A predicate is missing in one of the relations for EventGraph: " + eventGraphId); + } + + if (relation.getSubject() != null) { + if (relation.getSubject() instanceof RelationEvent) { + subjectNodeId = createNodesAndEdges((RelationEvent) relation.getSubject(), graphNodes, graphEdges, + uniqueNodes, eventGraphId); + } else { + subjectNodeId = createSubjectOrObjectNode(graphNodes, (AppellationEvent) relation.getSubject(), + uniqueNodes, GraphNodeType.SUBJECT, eventGraphId); + } + } else { + logger.error("A subject is missing in one of the relations for EventGraph: " + eventGraphId); + } + + if (relation.getObject() != null) { + if (relation.getObject() instanceof RelationEvent) { + objectNodeId = createNodesAndEdges((RelationEvent) relation.getObject(), graphNodes, graphEdges, + uniqueNodes, eventGraphId); + } else { + objectNodeId = createSubjectOrObjectNode(graphNodes, (AppellationEvent) relation.getObject(), + uniqueNodes, GraphNodeType.OBJECT, eventGraphId); + } + } else { + logger.error("An object is missing in one of the relations for EventGraph: " + eventGraphId); + } + + if(subjectNodeId != null && predicateNodeId != null) { + createEdge(graphEdges, subjectNodeId, predicateNodeId, eventGraphId); + } + + if(objectNodeId != null && predicateNodeId != null) { + createEdge(graphEdges, objectNodeId, predicateNodeId, eventGraphId); + } + + return predicateNodeId; + } + + @Override + public String createPredicateNode(List graphNodes, AppellationEvent event, String eventGraphId) throws ConceptpowerNoResponseException { + GraphNodeData predicateNode = createNode(event, GraphNodeType.PREDICATE, eventGraphId); + graphNodes.add(predicateNode); + return predicateNode.getId(); + } + + @Override + public String createSubjectOrObjectNode(List graphNodes, AppellationEvent event, + Map uniqueNodes, GraphNodeType graphNodeType, String eventGraphId) throws ConceptpowerNoResponseException { + String sourceUri = event.getTerm().getInterpretation().getSourceURI(); + GraphNodeData node; + + if (sourceUri != null && uniqueNodes.containsKey(sourceUri)) { + node = uniqueNodes.get(sourceUri); + node.getEventGraphIds().add(eventGraphId); + return node.getId(); + } + + node = createNode(event, graphNodeType, eventGraphId); + graphNodes.add(node); + uniqueNodes.put(sourceUri, node); + + if(sourceUri != null && !sourceUri.equals("") && node.getAlternativeUris() != null) { + node.getAlternativeUris() + .stream() + .filter(nullableAltUri -> nullableAltUri != null) + .filter(alternativeUri -> !alternativeUri.equals("") && !alternativeUri.equals(sourceUri)) + .forEach(alternativeUriValue -> uniqueNodes.put(alternativeUriValue, node)); + } + + return node.getId(); + } + + @Override + public GraphNodeData createNode(AppellationEvent event, GraphNodeType graphNodeType, String eventGraphId) throws ConceptpowerNoResponseException { + + GraphNodeData node = new GraphNodeData(); + node.setId(new ObjectId().toString()); + node.setGroup(graphNodeType.getGroupId()); + node.setEventGraphIds(new ArrayList(Collections.singletonList(eventGraphId))); + + String sourceURI = event.getTerm().getInterpretation().getSourceURI(); + + if (sourceURI != null && sourceURI.contains("www.digitalhps.org")) { + + node.setUri(sourceURI); + ConceptCache conceptCache = conceptPowerService.getConceptByUri(sourceURI); + + if (conceptCache != null) { + node.setLabel(conceptCache.getWord()); + node.setDescription(conceptCache.getDescription()); + node.setAlternativeUris(conceptCache.getAlternativeUris()); + } + } else { + // Need to get data from viaf if viaf URL is present, but doesn't seem to be part of story Q20-19 + node.setLabel(event.getTerm().getPrintedRepresentation().getTermParts().iterator().next().getExpression()); + } + + return node; + } + + @Override + public void createEdge(List graphEdges, String sourceId, String targetId, String eventGraphId) { + GraphEdgeData edge = new GraphEdgeData(); + edge.setId(new ObjectId().toString()); + edge.setSource(sourceId); + edge.setTarget(targetId); + edge.setEventGraphId(eventGraphId); + graphEdges.add(edge); + } + + private List wrapInGraphElements(List dataList) { + List elements = new ArrayList<>(); + dataList.forEach(data -> { + GraphElement element = new GraphElement(); + element.setData(data); + elements.add(element); + }); + return elements; + } + +} diff --git a/quadriga/src/main/resources/config.properties b/quadriga/src/main/resources/config.properties index 220dc200..96a2aed2 100644 --- a/quadriga/src/main/resources/config.properties +++ b/quadriga/src/main/resources/config.properties @@ -6,6 +6,9 @@ db.password=${db.password} neo4j.url=${neo4j.url} neo4j.database=${neo4j.database} +conceptpower_base_url=${conceptpower.base.url} +conceptpower_id_endpoint=/rest/Concept?id={concept_uri} + citesphere_client_id=${citesphere.client.id} citesphere_client_secret=${citesphere.client.secret} citesphere_base_url=${citesphere.base.url} @@ -13,3 +16,4 @@ citesphere_token_endpoint=/api/oauth/token citesphere_check_token_endpoint=/api/oauth/check_token citesphere_get_apps_endpoint=/api/v1/admin/apps citesphere_scopes=read +conceptCacheUpdateInterval=2 diff --git a/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html b/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html index c880ade4..60c8c0c8 100644 --- a/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html +++ b/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html @@ -28,20 +28,84 @@

No networks submitted to this coll Last network submitted by:

- +

Mappings

+ +
+ +
# Mappings Triples
1 Default Mappings
+ +

Networks

+ + + + + + + + + + + + + + + + + + +
#NameDate and TimeAction
+ + Graph for text submitted by + from + + + + Visualize + +
+ + diff --git a/quadriga/src/main/webapp/WEB-INF/views/auth/displayNetwork.html b/quadriga/src/main/webapp/WEB-INF/views/auth/displayNetwork.html new file mode 100644 index 00000000..eeeefe18 --- /dev/null +++ b/quadriga/src/main/webapp/WEB-INF/views/auth/displayNetwork.html @@ -0,0 +1,195 @@ + + +Quadriga 2.0 + + + + + + +
+

Network page

+
+
+
+
+
+ +
+
+

+ Source URI: +

+

+

+ Network name: +

+

+ Graph submitted by from +

+

+ Submitted on: +

+

+
+
+
+
+ +
+
+ + Select a node to view concept inforrmation + +
+
+
+
+ +
+
+ Select a node to view text occurences +
+
+
+
+ +
+
+ + \ No newline at end of file diff --git a/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImplTest.java b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImplTest.java new file mode 100644 index 00000000..d37332f3 --- /dev/null +++ b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptCacheServiceImplTest.java @@ -0,0 +1,146 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Optional; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import edu.asu.diging.quadriga.core.conceptpower.data.ConceptCacheRepository; +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; + +public class ConceptCacheServiceImplTest { + + @Mock + private ConceptCacheRepository conceptCacheRepository; + + @InjectMocks + private ConceptCacheServiceImpl conceptCacheServiceImpl; + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + public void test_getConceptByAlternativeUri_oneConcept_success() { + ConceptCache conceptCache1 = new ConceptCache(); + + String uri = "URI-2"; + String altURI = "URI-1"; + + conceptCache1.setUri(uri); + conceptCache1.setAlternativeUris(Collections.singletonList(altURI)); + + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(altURI)) + .thenReturn(Collections.singletonList(conceptCache1)); + + ConceptCache altConceptCache = conceptCacheServiceImpl.getConceptByAlternativeUri(altURI); + + Assert.assertEquals(1, altConceptCache.getAlternativeUris().size()); + Assert.assertEquals(altURI, altConceptCache.getAlternativeUris().get(0)); + Assert.assertEquals(uri, altConceptCache.getUri()); + + } + + @Test + public void test_getConceptByAlternativeUri_twoConcepts_success() { + ConceptCache conceptCache1 = new ConceptCache(); + ConceptCache conceptCache2 = new ConceptCache(); + + String uri1 = "URI-2"; + String uri2 = "URI-3"; + String altURI = "URI-1"; + + conceptCache1.setUri(uri1); + conceptCache2.setUri(uri2); + + conceptCache1.setAlternativeUris(Collections.singletonList(altURI)); + conceptCache2.setAlternativeUris(Collections.singletonList(altURI)); + + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(altURI)) + .thenReturn(Arrays.asList(conceptCache1, conceptCache2)); + + ConceptCache altConceptCache = conceptCacheServiceImpl.getConceptByAlternativeUri(altURI); + + Assert.assertEquals(1, altConceptCache.getAlternativeUris().size()); + Assert.assertEquals(altURI, altConceptCache.getAlternativeUris().get(0)); + Assert.assertEquals(uri1, altConceptCache.getUri()); + + } + + @Test + public void test_getConceptByAlternativeUri_nullConcepts() { + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(Mockito.anyString())) + .thenReturn(null); + ConceptCache conceptCache = conceptCacheServiceImpl.getConceptByAlternativeUri("uri"); + + Assert.assertNull(conceptCache); + } + + @Test + public void test_getConceptByAlternativeUri_emptyConceptList() { + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(Mockito.anyString())) + .thenReturn(new ArrayList()); + ConceptCache conceptCache = conceptCacheServiceImpl.getConceptByAlternativeUri("uri"); + + Assert.assertNull(conceptCache); + } + + @Test + public void test_getConceptByUri_conceptExists() { + ConceptCache conceptCache = new ConceptCache(); + String uri = "URI-1"; + conceptCache.setUri(uri); + + Mockito.when(conceptCacheRepository.findById(uri)).thenReturn(Optional.of(conceptCache)); + + ConceptCache foundConceptCache = conceptCacheServiceImpl.getConceptByUri(uri); + + Assert.assertEquals(uri, foundConceptCache.getUri()); + } + + @Test + public void test_getConceptByUri_altConceptExists() { + ConceptCache conceptCache = new ConceptCache(); + String uri = "URI-1"; + conceptCache.setUri(uri); + + Mockito.when(conceptCacheRepository.findById(uri)).thenReturn(Optional.ofNullable(null)); + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(uri)).thenReturn(Collections.singletonList(conceptCache)); + + ConceptCache foundConceptCache = conceptCacheServiceImpl.getConceptByUri(uri); + + Assert.assertEquals(uri, foundConceptCache.getUri()); + } + + @Test + public void test_getConceptByUri_noConceptExists() { + + Mockito.when(conceptCacheRepository.findById(Mockito.anyString())).thenReturn(Optional.ofNullable(null)); + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(Mockito.anyString())).thenReturn(null); + + ConceptCache foundConceptCache = conceptCacheServiceImpl.getConceptByUri("URI-1"); + + Assert.assertNull(foundConceptCache); + } + + @Test + public void test_getConceptByUri_altConceptEmptyList() { + + Mockito.when(conceptCacheRepository.findById(Mockito.anyString())).thenReturn(Optional.ofNullable(null)); + Mockito.when(conceptCacheRepository.findConceptByAlternativeURI(Mockito.anyString())).thenReturn(new ArrayList<>()); + + ConceptCache foundConceptCache = conceptCacheServiceImpl.getConceptByUri("URI-1"); + + Assert.assertNull(foundConceptCache); + } + +} diff --git a/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImplTest.java b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImplTest.java new file mode 100644 index 00000000..05f4ab76 --- /dev/null +++ b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerConnectorServiceImplTest.java @@ -0,0 +1,114 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptEntry; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +@RunWith(MockitoJUnitRunner.class) +public class ConceptPowerConnectorServiceImplTest { + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private ConceptPowerConnectorServiceImpl conceptPowerConnectorServiceImpl; + + private String conceptPowerBaseUrl; + + private String conceptPowerIdUrl; + + private String conceptPowerURL; + + @Before + public void setUp() { + conceptPowerBaseUrl = "https://chps.asu.edu/conceptpower"; + conceptPowerIdUrl = "/rest/Concept?id={concept_uri}"; + conceptPowerURL = conceptPowerBaseUrl + conceptPowerIdUrl; + + ReflectionTestUtils.setField(conceptPowerConnectorServiceImpl, "conceptPowerBaseURL", conceptPowerBaseUrl); + + MockitoAnnotations.openMocks(this); + } + + + @Test + public void test_getConceptPowerReply_success() throws ConceptpowerNoResponseException { + String conceptUri = "http://www.digitalhps.org/concepts/WID-09972010-N-01-cousin"; + String lemma = "cousin"; + + Map parameters = new HashMap<>(); + parameters.put("concept_uri", conceptUri); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity httpEntity = new HttpEntity<>(httpHeaders); + + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(conceptUri); + conceptEntry.setLemma(lemma); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ResponseEntity responseEntity = new ResponseEntity<>(conceptPowerReply, HttpStatus.ACCEPTED); + + Mockito.when(restTemplate.exchange(conceptPowerURL, HttpMethod.GET, httpEntity, ConceptPowerReply.class, parameters)) + .thenReturn(responseEntity); + + ConceptPowerReply replyFromResponse = conceptPowerConnectorServiceImpl.getConceptPowerReply(conceptUri); + + Assert.assertNotNull(replyFromResponse.getConceptEntries()); + Assert.assertEquals(conceptUri, replyFromResponse.getConceptEntries().get(0).getConceptUri()); + Assert.assertEquals(lemma, replyFromResponse.getConceptEntries().get(0).getLemma()); + } + + @Test + public void test_getConceptPowerReply_conceptpowerNoResponsetException() throws ConceptpowerNoResponseException { + String conceptUri = "http://www.digitalhps.org/concepts/WID-09972010-N-01-cousin"; + String lemma = "cousin"; + + Map parameters = new HashMap<>(); + parameters.put("concept_uri", conceptUri); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity httpEntity = new HttpEntity<>(httpHeaders); + + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(conceptUri); + conceptEntry.setLemma(lemma); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + Mockito.when(restTemplate.exchange(conceptPowerURL, HttpMethod.GET, httpEntity, ConceptPowerReply.class, parameters)) + .thenThrow(HttpClientErrorException.class); + + Assert.assertThrows(ConceptpowerNoResponseException.class,() -> conceptPowerConnectorServiceImpl.getConceptPowerReply(conceptUri).getClass()); + } + +} diff --git a/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImplTest.java b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImplTest.java new file mode 100644 index 00000000..9cdb9e19 --- /dev/null +++ b/quadriga/src/test/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImplTest.java @@ -0,0 +1,723 @@ +package edu.asu.diging.quadriga.core.conceptpower.service.impl; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptType; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.AlternativeId; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptEntry; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.ConceptPowerReply; +import edu.asu.diging.quadriga.core.conceptpower.reply.model.Type; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptCacheService; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerConnectorService; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptTypeService; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; + +public class ConceptPowerServiceImplTest { + + @Mock + private ConceptCacheService conceptCacheService; + + @Mock + private ConceptTypeService conceptTypeService; + + @Mock + private ConceptPowerConnectorService conceptPowerConnectorService; + + @InjectMocks + private ConceptPowerServiceImpl conceptPowerServiceImpl; + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullConceptEntries() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertNull(conceptCache); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_twoConceptEntries() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry1 = new ConceptEntry(); + ConceptEntry conceptEntry2 = new ConceptEntry(); + + String uri1 = "URI-1"; + String uri2 = "URI-2"; + + conceptEntry1.setConceptUri(uri1); + conceptEntry2.setConceptUri(uri2); + + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry1, conceptEntry2)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + + Assert.assertEquals(uri1, conceptCache.getUri()); + + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_basePropertiesSuccess() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + String uri = "http://www.digitalhps.org/concepts/WID-09972010-N-01-cousin"; + String description = "the child of your aunt or uncle"; + String pos = "NOUN"; + String conceptList = "Sample conceptList"; + String creatorId = "CreatorId"; + String word = "cousin"; + + boolean deleted = false; + conceptEntry.setConceptUri(uri); + conceptEntry.setDescription(description); + conceptEntry.setPos(pos); + conceptEntry.setConceptList(conceptList); + conceptEntry.setDeleted(deleted); + conceptEntry.setCreatorId(creatorId); + conceptEntry.setLemma(word); + + String expectedId = "WID-09972010-N-01-cousin"; + conceptEntry.setId(expectedId); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + + Assert.assertEquals(uri, conceptCache.getUri()); + Assert.assertEquals(description, conceptCache.getDescription()); + Assert.assertEquals(expectedId, conceptCache.getId()); + Assert.assertEquals(conceptList, conceptCache.getConceptList()); + Assert.assertFalse(conceptCache.isDeleted()); + Assert.assertEquals(creatorId, conceptCache.getCreatorId()); + Assert.assertEquals(word, conceptCache.getWord()); + + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullUri() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertNull(conceptCache.getUri()); + Assert.assertNull(conceptCache.getId()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_blankUri() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + String uri = ""; + conceptEntry.setConceptUri(uri); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertEquals(uri, conceptCache.getUri()); + Assert.assertNull(conceptCache.getId()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_uriWithoutForwrdaSlash() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + String uri = "URI-1"; + conceptEntry.setConceptUri(uri); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertEquals(uri, conceptCache.getUri()); + Assert.assertNull(conceptCache.getId()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullWordNetIds() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getWordNetIds().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_emptyWordNetIds() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setWordnetId(""); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getWordNetIds().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_onlyWhitespacesInWordNetIds() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setWordnetId(" "); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getWordNetIds().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_oneWordNetId() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + String wordNet = "wordnet1"; + conceptEntry.setWordnetId(wordNet); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[] {wordNet}, conceptCache.getWordNetIds().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_moreThanOneWordNetId() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + String wordNet1 = "wordnet1"; + String wordNet2 = "wordnet2"; + String wordNet3 = "wordnet3"; + + conceptEntry.setWordnetId(String.join(",", wordNet1, wordNet2, wordNet3)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[] {wordNet1, wordNet2, wordNet3}, conceptCache.getWordNetIds().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullEqualTos() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getEqualTo().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_emptyEqualTos() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setEqualTo(""); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getEqualTo().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_onlyWhitespacesInEqualTos() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setEqualTo(" "); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getEqualTo().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_oneEqualTo() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + String equalTo = "equalTo"; + conceptEntry.setEqualTo(equalTo); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[] {equalTo}, conceptCache.getEqualTo().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_moreThanOneEqualTos() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + String equalTo1 = "equalTo1"; + String equalTo2 = "equalTo2"; + String equalTo3 = "equalTo3"; + + conceptEntry.setEqualTo(String.join(",", equalTo1, equalTo2, equalTo3)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[] {equalTo1, equalTo2, equalTo3}, conceptCache.getEqualTo().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullAltUris() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertNull(conceptCache.getAlternativeUris()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_emptyAltUris() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setAlternativeIds(new ArrayList<>()); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertNull(conceptCache.getAlternativeUris()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_nullAltConceptUri() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + AlternativeId alternativeId = new AlternativeId(); + conceptEntry.setAlternativeIds(Collections.singletonList(alternativeId)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getAlternativeUris().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_blankAltConceptUri() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + AlternativeId alternativeId = new AlternativeId(); + alternativeId.setConceptUri(""); + conceptEntry.setAlternativeIds(Collections.singletonList(alternativeId)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertTrue(conceptCache.getAlternativeUris().isEmpty()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_oneAltId() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + AlternativeId alternativeId = new AlternativeId(); + String conceptUri = "URI-1"; + alternativeId.setConceptUri(conceptUri); + + conceptEntry.setAlternativeIds(Collections.singletonList(alternativeId)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[]{conceptUri}, conceptCache.getAlternativeUris().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_moreThanOneAltId() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + AlternativeId alternativeId1 = new AlternativeId(); + AlternativeId alternativeId2 = new AlternativeId(); + AlternativeId alternativeId3 = new AlternativeId(); + String conceptUri1 = "URI-1"; + String conceptUri2 = "URI-2"; + String conceptUri3 = "URI-3"; + + alternativeId1.setConceptUri(conceptUri1); + alternativeId2.setConceptUri(conceptUri2); + alternativeId3.setConceptUri(conceptUri3); + + conceptEntry.setAlternativeIds(Arrays.asList(alternativeId1, alternativeId2, alternativeId3)); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertArrayEquals(new String[]{conceptUri1, conceptUri2, conceptUri3}, conceptCache.getAlternativeUris().toArray()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_conceptTypeNull() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + Assert.assertNull(conceptCache.getConceptType()); + Assert.assertNull(conceptCache.getTypeId()); + } + + @Test + public void test_mapConceptPowerReplyToConceptCache_conceptTypeNotNull() { + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + String uri = "URI-1"; + String id = "ID1"; + String name = "Sample Name"; + String expectedDescription = ""; + + Type type = new Type(); + type.setTypeId(id); + type.setTypeName(name); + type.setTypeUri(uri); + + conceptEntry.setType(type); + conceptPowerReply.setConceptEntries(Collections.singletonList(conceptEntry)); + + ConceptCache conceptCache = conceptPowerServiceImpl.mapConceptPowerReplyToConceptCache(conceptPowerReply); + + Assert.assertEquals(uri, conceptCache.getConceptType().getUri()); + Assert.assertEquals(uri, conceptCache.getTypeId()); + Assert.assertEquals(id, conceptCache.getConceptType().getId()); + Assert.assertEquals(name, conceptCache.getConceptType().getName()); + Assert.assertEquals(expectedDescription, conceptCache.getConceptType().getDescription()); + } + + @Test + public void test_getConceptByUri_noConceptInDB() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(null); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + Mockito.doNothing().when(conceptCacheService).saveConceptCache(Mockito.any(ConceptCache.class)); + + ConceptCache conceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, conceptCache.getUri()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdatedToday_noDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now()); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdatedToday_posDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String posOld = "NOUN"; + String posNew = "VERB"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now()); + conceptCache.setPos(posOld); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setPos(posNew); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertNotEquals(posOld, foundConceptCache.getPos()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_noDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + + LocalDateTime threeDaysBack = LocalDateTime.now().minusDays(3); + conceptCache.setLastUpdated(threeDaysBack); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(threeDaysBack, foundConceptCache.getLastUpdated()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_posDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String posOld = "NOUN"; + String posNew = "VERB"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setPos(posOld); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setPos(posNew); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + Mockito.doNothing().when(conceptCacheService).saveConceptCache(Mockito.any(ConceptCache.class)); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(posNew, foundConceptCache.getPos()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_oldPosNullNewPosNotNull() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String posOld = null; + String posNew = "VERB"; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setPos(posOld); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setPos(posNew); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + Mockito.doNothing().when(conceptCacheService).saveConceptCache(Mockito.any(ConceptCache.class)); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(posNew, foundConceptCache.getPos()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_oldPosNotNullNewPosNull() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String posOld = "NOUN"; + String posNew = null; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setPos(posOld); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setPos(posNew); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + Mockito.doNothing().when(conceptCacheService).saveConceptCache(Mockito.any(ConceptCache.class)); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertNull(foundConceptCache.getPos()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_oldPosAndNewPosNull() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String posOld = null; + String posNew = null; + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setPos(posOld); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setPos(posNew); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + Mockito.doNothing().when(conceptCacheService).saveConceptCache(Mockito.any(ConceptCache.class)); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertNull(foundConceptCache.getPos()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_altUrisNoDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String altURI = "ALT-URI-1"; + + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setAlternativeUris(Arrays.asList(sourceURI, altURI)); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + AlternativeId altURI1 = new AlternativeId(); + AlternativeId altURI2 = new AlternativeId(); + + altURI1.setConceptUri(sourceURI); + altURI2.setConceptUri(altURI); + + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setAlternativeIds(Arrays.asList(altURI1, altURI2)); + + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(sourceURI, foundConceptCache.getAlternativeUris().get(0)); + Assert.assertEquals(altURI, foundConceptCache.getAlternativeUris().get(1)); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_altUrisDiffPresent() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String altURI = "ALT-URI-1"; + String altURIDiff = "ALT-URI-2"; + + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + conceptCache.setAlternativeUris(Arrays.asList(sourceURI, altURI)); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + + AlternativeId altURI1 = new AlternativeId(); + AlternativeId altURI2 = new AlternativeId(); + AlternativeId altURI3 = new AlternativeId(); + + altURI1.setConceptUri(sourceURI); + altURI2.setConceptUri(altURI); + altURI3.setConceptUri(altURIDiff); + + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setAlternativeIds(Arrays.asList(altURI1, altURI2, altURI3)); + + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(sourceURI, foundConceptCache.getAlternativeUris().get(0)); + Assert.assertEquals(altURI, foundConceptCache.getAlternativeUris().get(1)); + Assert.assertEquals(altURIDiff, foundConceptCache.getAlternativeUris().get(2)); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_typeNoDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String nameOld = "NAME-1"; + String nameNew = "NAME-1"; + LocalDateTime threeDaysBack = LocalDateTime.now().minusDays(3); + + ConceptType conceptType = new ConceptType(); + conceptType.setName(nameOld); + + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setConceptType(conceptType); + conceptCache.setLastUpdated(threeDaysBack); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + Type type = new Type(); + type.setTypeName(nameNew); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setType(type); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(nameNew, foundConceptCache.getConceptType().getName()); + Assert.assertEquals(threeDaysBack, foundConceptCache.getLastUpdated()); + } + + @Test + public void test_getConceptByUri_conceptPresentInDB_lastUpdated3DaysBack_typeNameDiff() throws ConceptpowerNoResponseException { + String sourceURI = "URI-1"; + String nameOld = "NAME-1"; + String nameNew = "NAME-2"; + + ConceptType conceptType = new ConceptType(); + conceptType.setName(nameOld); + + ConceptCache conceptCache = new ConceptCache(); + conceptCache.setUri(sourceURI); + conceptCache.setConceptType(conceptType); + conceptCache.setLastUpdated(LocalDateTime.now().minusDays(3)); + + ConceptPowerReply conceptPowerReply = new ConceptPowerReply(); + ConceptEntry conceptEntry = new ConceptEntry(); + Type type = new Type(); + type.setTypeName(nameNew); + conceptEntry.setConceptUri(sourceURI); + conceptEntry.setType(type); + conceptPowerReply.setConceptEntries(Arrays.asList(conceptEntry)); + + Mockito.when(conceptCacheService.getConceptByUri(sourceURI)).thenReturn(conceptCache); + Mockito.when(conceptPowerConnectorService.getConceptPowerReply(sourceURI)).thenReturn(conceptPowerReply); + + ConceptCache foundConceptCache = conceptPowerServiceImpl.getConceptByUri(sourceURI); + Assert.assertEquals(sourceURI, foundConceptCache.getUri()); + Assert.assertEquals(nameNew, foundConceptCache.getConceptType().getName()); + } +} diff --git a/quadriga/src/test/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImplTest.java b/quadriga/src/test/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImplTest.java index 3321b297..05cfa85b 100644 --- a/quadriga/src/test/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImplTest.java +++ b/quadriga/src/test/java/edu/asu/diging/quadriga/core/service/impl/EventGraphServiceImplTest.java @@ -6,6 +6,7 @@ import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -78,6 +79,16 @@ public void test_findLatestEventGraphByCollectionId_success() throws Interrupted } + @Test + public void test_findLatestEventGraphByCollectionId_failure() { + ObjectId collectionObjectId = new ObjectId(); + + Mockito.when(eventGraphRepository.findFirstByCollectionIdOrderByCreationTimeDesc(collectionObjectId)) + .thenReturn(Optional.ofNullable(null)); + + Assert.assertNull(eventGraphServiceImpl.findLatestEventGraphByCollectionId(collectionObjectId)); + } + @Test public void test_countEventGraphsBy_success() throws InterruptedException { ObjectId collectionObjectId = new ObjectId(); diff --git a/quadriga/src/test/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImplTest.java b/quadriga/src/test/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImplTest.java new file mode 100644 index 00000000..804dab3e --- /dev/null +++ b/quadriga/src/test/java/edu/asu/diging/quadriga/web/service/impl/GraphCreationServiceImplTest.java @@ -0,0 +1,369 @@ +package edu.asu.diging.quadriga.web.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bson.types.ObjectId; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import edu.asu.diging.quadriga.core.conceptpower.model.ConceptCache; +import edu.asu.diging.quadriga.core.conceptpower.service.ConceptPowerService; +import edu.asu.diging.quadriga.core.exceptions.ConceptpowerNoResponseException; +import edu.asu.diging.quadriga.core.model.EventGraph; +import edu.asu.diging.quadriga.core.model.elements.Concept; +import edu.asu.diging.quadriga.core.model.elements.Relation; +import edu.asu.diging.quadriga.core.model.elements.Term; +import edu.asu.diging.quadriga.core.model.events.AppellationEvent; +import edu.asu.diging.quadriga.core.model.events.RelationEvent; +import edu.asu.diging.quadriga.web.model.GraphData; +import edu.asu.diging.quadriga.web.model.GraphElement; +import edu.asu.diging.quadriga.web.model.GraphElements; +import edu.asu.diging.quadriga.web.model.GraphNodeData; +import edu.asu.diging.quadriga.web.model.GraphNodeType; + +public class GraphCreationServiceImplTest { + + @Mock + private ConceptPowerService conceptPowerService; + + @InjectMocks + private GraphCreationServiceImpl graphCreationServiceImpl; + + private static List> sampleEventGraphLists = new ArrayList<>(); + private static ConceptCache subject1, subject2; + private static ConceptCache predicate1, predicate2; + private static ConceptCache object1; + + @BeforeClass + public static void setUpOnceBeforeAllTests() { + createSampleEventGraphs(sampleEventGraphLists); + createSampleConceptCache(); + } + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + public void test_createGraph_singleLevelGraph_success() throws ConceptpowerNoResponseException { + List singleEventGraphList = sampleEventGraphLists.get(0); + EventGraph eventGraph = singleEventGraphList.get(0); + String[] eventGraphIds = new String[] { eventGraph.getId().toString() }; + + String subjectSourceURI = "http://www.digitalhps.org/concepts/albert-einstein"; + String predicateSourceURI = "http://www.digitalhps.org/concepts/married"; + String objectSourceURI = "http://www.digitalhps.org/concepts/elsa-einstein"; + + Mockito.when(conceptPowerService.getConceptByUri(subjectSourceURI)).thenReturn(subject1); + Mockito.when(conceptPowerService.getConceptByUri(predicateSourceURI)).thenReturn(predicate1); + Mockito.when(conceptPowerService.getConceptByUri(objectSourceURI)).thenReturn(object1); + + GraphElements graphElements = graphCreationServiceImpl.createGraph(singleEventGraphList); + + List nodes = graphElements.getNodes(); + List edges = graphElements.getEdges(); + + Assert.assertEquals(3, nodes.size()); + Assert.assertEquals(2, edges.size()); + nodes.forEach(node -> Assert.assertNotNull(node.getData())); + edges.forEach(edge -> Assert.assertNotNull(edge.getData())); + + GraphNodeData predicateNode = (GraphNodeData) nodes.get(0).getData(); + GraphNodeData subjectNode = (GraphNodeData) nodes.get(1).getData(); + GraphNodeData objectNode = (GraphNodeData) nodes.get(2).getData(); + + Assert.assertEquals(1, subjectNode.getGroup()); + Assert.assertEquals(0, predicateNode.getGroup()); + Assert.assertEquals(1, objectNode.getGroup()); + + Assert.assertEquals("Albert Einstein", subjectNode.getLabel()); + Assert.assertEquals("married", predicateNode.getLabel()); + Assert.assertEquals("Elsa Einstein", objectNode.getLabel()); + + Assert.assertEquals("Albert Einstein was a German-born theoretical physicist", subjectNode.getDescription()); + Assert.assertEquals("a person who is married; \"we invited several young marrieds\"", + predicateNode.getDescription()); + Assert.assertEquals("Elsa Einstein was the second wife and cousin of Albert Einstein", + objectNode.getDescription()); + + Assert.assertEquals(subjectSourceURI, subjectNode.getUri()); + Assert.assertEquals(predicateSourceURI, predicateNode.getUri()); + Assert.assertEquals(objectSourceURI, objectNode.getUri()); + + Assert.assertArrayEquals(eventGraphIds, subjectNode.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, predicateNode.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, objectNode.getEventGraphIds().toArray()); + + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/albert-einstein", + "http://www.digitalhps.org/concepts/albert-einstein-alt" }, + subjectNode.getAlternativeUris().toArray()); + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/WID-10295819-N-01-married", + "http://www.digitalhps.org/concepts/WID-10295819-N-02-married" }, + predicateNode.getAlternativeUris().toArray()); + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/elsa-einstein", + "http://www.digitalhps.org/concepts/elsa-einstein-alt" }, + objectNode.getAlternativeUris().toArray()); + } + + @Test + public void test_createGraph_nestedEventGraph_success() throws ConceptpowerNoResponseException { + List nestedEventGraphList = sampleEventGraphLists.get(1); + EventGraph eventGraph = nestedEventGraphList.get(0); + String[] eventGraphIds = new String[] { eventGraph.getId().toString() }; + + String subjectSourceURI = "http://www.digitalhps.org/concepts/albert-einstein"; + String predicateSourceURI = "http://www.digitalhps.org/concepts/married"; + String subjectSourceURI2 = "http://www.digitalhps.org/concepts/cousin"; + String predicateSourceURI2 = "http://www.digitalhps.org/concepts/be"; + String objectSourceURI = "http://www.digitalhps.org/concepts/elsa-einstein"; + + Mockito.when(conceptPowerService.getConceptByUri(subjectSourceURI)).thenReturn(subject1); + Mockito.when(conceptPowerService.getConceptByUri(predicateSourceURI)).thenReturn(predicate1); + Mockito.when(conceptPowerService.getConceptByUri(objectSourceURI)).thenReturn(object1); + Mockito.when(conceptPowerService.getConceptByUri(subjectSourceURI2)).thenReturn(subject2); + Mockito.when(conceptPowerService.getConceptByUri(predicateSourceURI2)).thenReturn(predicate2); + + GraphElements graphElements = graphCreationServiceImpl.createGraph(nestedEventGraphList); + + List nodes = graphElements.getNodes(); + List edges = graphElements.getEdges(); + + Assert.assertEquals(5, nodes.size()); + Assert.assertEquals(4, edges.size()); + nodes.forEach(node -> Assert.assertNotNull(node.getData())); + edges.forEach(edge -> Assert.assertNotNull(edge.getData())); + + GraphNodeData predicateNode = (GraphNodeData) nodes.get(0).getData(); + GraphNodeData subjectNode = (GraphNodeData) nodes.get(1).getData(); + GraphNodeData predicateNode2 = (GraphNodeData) nodes.get(2).getData(); + GraphNodeData subjectNode2 = (GraphNodeData) nodes.get(3).getData(); + GraphNodeData objectNode = (GraphNodeData) nodes.get(4).getData(); + + Assert.assertEquals(1, subjectNode.getGroup()); + Assert.assertEquals(0, predicateNode.getGroup()); + Assert.assertEquals(1, objectNode.getGroup()); + Assert.assertEquals(1, subjectNode2.getGroup()); + Assert.assertEquals(0, predicateNode2.getGroup()); + + Assert.assertEquals("Albert Einstein", subjectNode.getLabel()); + Assert.assertEquals("married", predicateNode.getLabel()); + Assert.assertEquals("cousin", subjectNode2.getLabel()); + Assert.assertEquals("be", predicateNode2.getLabel()); + Assert.assertEquals("Elsa Einstein", objectNode.getLabel()); + + Assert.assertEquals("Albert Einstein was a German-born theoretical physicist", subjectNode.getDescription()); + Assert.assertEquals("a person who is married; \"we invited several young marrieds\"", + predicateNode.getDescription()); + Assert.assertEquals("the child of your aunt or uncle", subjectNode2.getDescription()); + Assert.assertEquals( + "be identical to; be someone or something; \"The president of the company is John Smith\"; \"This is my house\"", + predicateNode2.getDescription()); + Assert.assertEquals("Elsa Einstein was the second wife and cousin of Albert Einstein", + objectNode.getDescription()); + + Assert.assertEquals(subjectSourceURI, subjectNode.getUri()); + Assert.assertEquals(predicateSourceURI, predicateNode.getUri()); + Assert.assertEquals(subjectSourceURI2, subjectNode2.getUri()); + Assert.assertEquals(predicateSourceURI2, predicateNode2.getUri()); + Assert.assertEquals(objectSourceURI, objectNode.getUri()); + + Assert.assertArrayEquals(eventGraphIds, subjectNode.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, predicateNode.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, subjectNode2.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, predicateNode2.getEventGraphIds().toArray()); + Assert.assertArrayEquals(eventGraphIds, objectNode.getEventGraphIds().toArray()); + + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/albert-einstein", + "http://www.digitalhps.org/concepts/albert-einstein-alt" }, + subjectNode.getAlternativeUris().toArray()); + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/WID-10295819-N-01-married", + "http://www.digitalhps.org/concepts/WID-10295819-N-02-married" }, + predicateNode.getAlternativeUris().toArray()); + Assert.assertArrayEquals(new String[] { "http://www.digitalhps.org/concepts/cousin", + "http://www.digitalhps.org/concepts/cousin-2" }, + subjectNode2.getAlternativeUris().toArray()); + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/be", "http://www.digitalhps.org/concepts/be-2" }, + predicateNode2.getAlternativeUris().toArray()); + Assert.assertArrayEquals( + new String[] { "http://www.digitalhps.org/concepts/elsa-einstein", + "http://www.digitalhps.org/concepts/elsa-einstein-alt" }, + objectNode.getAlternativeUris().toArray()); + } + + @Test + public void test_createSubjectOrObjectNode_testUniqueNodesDoesntContain() throws ConceptpowerNoResponseException { + List nodes = new ArrayList<>(); + Map uniqueNodes = new HashMap<>(); + String sourceURI = "http://www.digitalhps.org/concepts/albert-einstein"; + AppellationEvent subject = (AppellationEvent) ((RelationEvent) (sampleEventGraphLists.get(0).get(0) + .getRootEvent())).getRelation().getSubject(); + graphCreationServiceImpl.createSubjectOrObjectNode(nodes, subject, uniqueNodes, GraphNodeType.SUBJECT, + new ObjectId().toString()); + Assert.assertTrue(uniqueNodes.containsKey(sourceURI)); + Assert.assertEquals(sourceURI, ((GraphNodeData) uniqueNodes.get(sourceURI)).getUri()); + } + + @Test + public void test_createSubjectOrObjectNode_testUniqueNodesContains() throws ConceptpowerNoResponseException { + List nodes = new ArrayList<>(); + Map uniqueNodes = new HashMap<>(); + String sourceURI = "http://www.digitalhps.org/concepts/albert-einstein"; + + GraphNodeData node = new GraphNodeData(); + node.setUri(sourceURI); + ObjectId eventGraphId1 = new ObjectId(); + ObjectId eventGraphId2 = new ObjectId(); + ObjectId nodeId = new ObjectId(); + node.setId(nodeId.toString()); + + ArrayList eventGraphIds = new ArrayList<>(); + eventGraphIds.add(eventGraphId1.toString()); + node.setEventGraphIds(eventGraphIds); + + uniqueNodes.put(sourceURI, node); + + AppellationEvent subject = (AppellationEvent) ((RelationEvent) (sampleEventGraphLists.get(0).get(0) + .getRootEvent())).getRelation().getSubject(); + + graphCreationServiceImpl.createSubjectOrObjectNode(nodes, subject, uniqueNodes, GraphNodeType.SUBJECT, + eventGraphId2.toString()); + + GraphNodeData foundNode = (GraphNodeData) uniqueNodes.get(sourceURI); + Assert.assertTrue(uniqueNodes.containsKey(sourceURI)); + Assert.assertEquals(sourceURI, foundNode.getUri()); + Assert.assertEquals(eventGraphId1.toString(), foundNode.getEventGraphIds().get(0)); + Assert.assertEquals(eventGraphId2.toString(), foundNode.getEventGraphIds().get(1)); + } + + private static void createSampleEventGraphs(List> sampleEventGraphs) { + + RelationEvent rootEvent = new RelationEvent(); + Relation relation = new Relation(); + + AppellationEvent subject = new AppellationEvent(); + Term term = new Term(); + Concept interpretation = new Concept(); + interpretation.setSourceURI("http://www.digitalhps.org/concepts/albert-einstein"); + term.setInterpretation(interpretation); + subject.setTerm(term); + + AppellationEvent predicate = new AppellationEvent(); + Term term3 = new Term(); + Concept interpretation3 = new Concept(); + interpretation3.setSourceURI("http://www.digitalhps.org/concepts/married"); + term3.setInterpretation(interpretation3); + predicate.setTerm(term3); + + AppellationEvent object = new AppellationEvent(); + Term term2 = new Term(); + Concept interpretation2 = new Concept(); + interpretation2.setSourceURI("http://www.digitalhps.org/concepts/elsa-einstein"); + term2.setInterpretation(interpretation2); + object.setTerm(term2); + + relation.setSubject(subject); + relation.setObject(object); + relation.setPredicate(predicate); + + rootEvent.setRelation(relation); + + EventGraph eventGraph = new EventGraph(rootEvent); + eventGraph.setId(new ObjectId()); + + List singleEventGraphList = Collections.singletonList(eventGraph); + sampleEventGraphs.add(singleEventGraphList); + + RelationEvent rootEvent2 = new RelationEvent(); + RelationEvent object2 = new RelationEvent(); + Relation baseRelation = new Relation(); + Relation objectRelation = new Relation(); + + AppellationEvent subject2 = new AppellationEvent(); + Term termSubject2 = new Term(); + Concept interpretationSubject2 = new Concept(); + interpretationSubject2.setSourceURI("http://www.digitalhps.org/concepts/cousin"); + termSubject2.setInterpretation(interpretationSubject2); + subject2.setTerm(termSubject2); + + AppellationEvent predicate2 = new AppellationEvent(); + Term termPredicate2 = new Term(); + Concept interpretationPredicate2 = new Concept(); + interpretationPredicate2.setSourceURI("http://www.digitalhps.org/concepts/be"); + termPredicate2.setInterpretation(interpretationPredicate2); + predicate2.setTerm(termPredicate2); + + objectRelation.setSubject(subject2); + objectRelation.setPredicate(predicate2); + objectRelation.setObject(object); + object2.setRelation(objectRelation); + baseRelation.setSubject(subject); + baseRelation.setPredicate(predicate); + baseRelation.setObject(object2); + rootEvent2.setRelation(baseRelation); + + EventGraph eventGraph2 = new EventGraph(rootEvent2); + eventGraph2.setId(new ObjectId()); + + List nestedEventGraphList = Collections.singletonList(eventGraph2); + sampleEventGraphs.add(nestedEventGraphList); + + } + + private static void createSampleConceptCache() { + + subject1 = new ConceptCache(); + subject1.setUri("http://www.digitalhps.org/concepts/albert-einstein"); + subject1.setWord("Albert Einstein"); + subject1.setDescription("Albert Einstein was a German-born theoretical physicist"); + subject1.setAlternativeUris(Arrays.asList("http://www.digitalhps.org/concepts/albert-einstein", + "http://www.digitalhps.org/concepts/albert-einstein-alt")); + + predicate1 = new ConceptCache(); + predicate1.setUri("http://www.digitalhps.org/concepts/WID-10295819-N-01-married"); + predicate1.setWord("married"); + predicate1.setDescription("a person who is married; \"we invited several young marrieds\""); + predicate1.setAlternativeUris(Arrays.asList("http://www.digitalhps.org/concepts/WID-10295819-N-01-married", + "http://www.digitalhps.org/concepts/WID-10295819-N-02-married")); + + object1 = new ConceptCache(); + object1.setWord("Elsa Einstein"); + object1.setUri("http://www.digitalhps.org/concepts/elsa-einstein"); + object1.setDescription("Elsa Einstein was the second wife and cousin of Albert Einstein"); + object1.setAlternativeUris(Arrays.asList("http://www.digitalhps.org/concepts/elsa-einstein", + "http://www.digitalhps.org/concepts/elsa-einstein-alt")); + + subject2 = new ConceptCache(); + subject2.setUri("http://www.digitalhps.org/concepts/cousin"); + subject2.setWord("cousin"); + subject2.setDescription("the child of your aunt or uncle"); + subject2.setAlternativeUris(Arrays.asList("http://www.digitalhps.org/concepts/cousin", + "http://www.digitalhps.org/concepts/cousin-2")); + + predicate2 = new ConceptCache(); + predicate2.setUri("http://www.digitalhps.org/concepts/be"); + predicate2.setWord("be"); + predicate2.setDescription( + "be identical to; be someone or something; \"The president of the company is John Smith\"; \"This is my house\""); + predicate2.setAlternativeUris( + Arrays.asList("http://www.digitalhps.org/concepts/be", "http://www.digitalhps.org/concepts/be-2")); + } + +}