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..6bfd58a3 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
@@ -1,5 +1,11 @@
package edu.asu.diging.quadriga.api.v1;
+import java.time.OffsetDateTime;
+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;
@@ -8,6 +14,7 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -19,6 +26,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;
@@ -60,23 +68,24 @@ public HttpStatus processJson(@RequestBody Quadruple quadruple, @PathVariable St
logger.error("Quadruple not present in network submission request for collectionId: " + collectionId);
return HttpStatus.BAD_REQUEST;
}
-
+
// Next, we check whether a collection and mappedTripleGroup is present
// Every time a new network is submitted, the triple in that network has to be added as the
// default MappedTripleGroup for given collectionId
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;
}
eventGraphService.mapNetworkAndSave(quadruple.getGraph(), collectionId);
-
+
try {
// The new MappedTripleGroup's Id has to be added to Concepts and Predicates
mappedTripleService.storeMappedGraph(quadruple.getGraph(), mappedTripleGroup);
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..4e238b80
--- /dev/null
+++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/conceptpower/service/impl/ConceptPowerServiceImpl.java
@@ -0,0 +1,209 @@
+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);
+
+ conceptCacheUpdateInterval=0;
+ 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..c11812df 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,26 @@
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> findByCollectionIdOrderByCreationTimeDesc(ObjectId collectionId);
+
+ @Query(value = "{'context.sourceUri': ?0}")
+ public Optional> findByContextSourceUri(String sourceURI);
+
public Optional findFirstByCollectionIdOrderByCreationTimeDesc(ObjectId collectionId);
+
+ public Optional> findByCollectionId(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/data/neo4j/PredicateRepository.java b/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/neo4j/PredicateRepository.java
index 16ea2d6a..721a634e 100644
--- a/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/neo4j/PredicateRepository.java
+++ b/quadriga/src/main/java/edu/asu/diging/quadriga/core/data/neo4j/PredicateRepository.java
@@ -5,6 +5,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
+
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
@@ -14,7 +15,7 @@
public interface PredicateRepository extends Neo4jRepository {
public Optional> findByMappedTripleGroupId(String mappedTripleGroupId);
-
+
public Optional> findByMappedTripleGroupId(String mappedTripleGroupId, Pageable paging);
@Query("MATCH (p{mappedTripleGroupId:$mappedTripleGroupId})-[r:PREDICATE]->() RETURN COUNT(p)")
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..dc886711 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
@@ -17,10 +17,13 @@ public class Collection {
private ObjectId _id;
private String name;
+
private String description;
+
private String owner;
private OffsetDateTime creationTime;
+
private boolean archived;
/**
@@ -51,6 +54,7 @@ public String getDescription() {
public void setDescription(String description) {
this.description = description;
}
+
public String getOwner() {
return owner;
}
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..9d89b3e4 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,12 +13,18 @@ public class EventGraph {
private DefaultMapping defaultMapping;
private OffsetDateTime creationTime;
private ObjectId collectionId;
+ private String appName;
+ private Context context;
+
private String submittingApp;
- public EventGraph() {}
+ public EventGraph() {
+ this.creationTime = OffsetDateTime.now();
+ }
public EventGraph(CreationEvent root) {
this.rootEvent = root;
+ this.creationTime = OffsetDateTime.now();
}
public ObjectId getId() {
@@ -61,6 +67,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;
}
@@ -68,5 +82,13 @@ public String getSubmittingApp() {
public void setSubmittingApp(String submittingApp) {
this.submittingApp = submittingApp;
}
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
}
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..fad2fc5f 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
@@ -23,7 +23,10 @@ public interface CollectionManager {
/**
* Finds a collection from the collection table by id
+ *
* @param id used to look up the collection in mongodb
+ * @throws InvalidObjectIdException if the id passed is not a hex string
+ *
* @return Collection Instance that is found from the database
*
**/
@@ -38,6 +41,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
@@ -62,10 +66,26 @@ public interface CollectionManager {
/**
* Deletes a collection from collection table by id
* @param id used to look up the collection in database
+ *
* @return collection details if it is archived
+ * @throws CollectionNotFoundException in case the collection for the given id is missing
* @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
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..5bebed60 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,8 +3,11 @@
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;
import edu.asu.diging.quadriga.core.model.EventGraph;
@@ -18,14 +21,15 @@ public interface EventGraphService {
public void saveEventGraphs(List graphs);
/**
- * Finds all eventGraphs mapped to a collection in the descending order of creation time
+ * Finds the latest eventGraph mapped to a collection in the descending order of creation time
*
- * @param collectionId is the id used to finds all eventGraphs
+ * @param collectionId is the id used to finds the latest eventGraph
+ * @return the latest eventGraph
* @return a list of eventGraphs in descending order
* @throws InvalidObjectIdException if the collectionId contains non-hexadecimal characters
*/
public EventGraph findLatestEventGraphByCollectionId(ObjectId collectionId);
-
+
/**
* Groups the event graphs mapped to a collection by source uri and returns the total count.
* @param collectionId
@@ -33,10 +37,30 @@ public interface EventGraphService {
*/
public long getNumberOfSubmittedNetworks(ObjectId collectionId);
+ /**
+ * Finds all eventGraphs mapped to a collection in the descending order of creation time
+ *
+ * @param collectionId is the id used to finds all eventGraphs
+ *
+ * @param pageable used to specify page number and size per page
+ * @return a list of eventGraphs in descending order
+ */
+ public Page findAllEventGraphsByCollectionId(ObjectId collectionId, Pageable pageable);
+
+ public List findAllEventGraphsByCollectionId(ObjectId collectionId);
+
/**
* Maps the network to events and saves it in the database
* @param graph
* @param collectionId
*/
public void mapNetworkAndSave(Graph graph, String collectionId);
+
+ /**
+ * Finds event graphs by sourceURI
+ *
+ * @param sourceURI used for searching eventGraph
+ */
+ public List findEventGraphsBySourceURI(String sourceURI);
+
}
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..1132ec32 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
@@ -1,9 +1,11 @@
package edu.asu.diging.quadriga.core.service.impl;
import java.time.OffsetDateTime;
+
+import java.util.Objects;
+
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.stream.Collectors;
import org.bson.types.ObjectId;
@@ -66,7 +68,7 @@ public Collection addCollection(String name, String description, String owner, L
}
/* (non-Javadoc)
- * @see edu.asu.diging.quadriga.core.service.CollectionManager#findCollection(java.lang.String)
+ * @see edu.asu.diging.quadriga.core.service.ICollectionManager#findCollection(java.lang.String)
*/
@Override
public Collection findCollection(String id) throws InvalidObjectIdException {
@@ -124,6 +126,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)
@@ -183,5 +197,4 @@ public Page findByArchived(boolean archived,int pageInt,int sizeInt)
return collectionRepo.findByArchived(archived, PageRequest.of(pageInt, sizeInt));
}
-
}
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..cb2e51a6 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,12 +6,16 @@
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;
import edu.asu.diging.quadriga.core.data.EventGraphRepository;
import edu.asu.diging.quadriga.core.model.EventGraph;
+
import edu.asu.diging.quadriga.core.model.events.CreationEvent;
+
import edu.asu.diging.quadriga.core.mongo.EventGraphDao;
import edu.asu.diging.quadriga.core.service.EventGraphService;
import edu.asu.diging.quadriga.core.service.NetworkMapper;
@@ -37,6 +41,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);
@@ -49,6 +63,11 @@ public long getNumberOfSubmittedNetworks(ObjectId collectionId) {
return eventGraphDao.countEventGraphsByCollectionId(collectionId);
}
+
+ @Override
+ public List findEventGraphsBySourceURI(String sourceURI) {
+ return repo.findByContextSourceUri(sourceURI).orElse(null);
+ }
@Override
public void mapNetworkAndSave(Graph graph, String collectionId) {
@@ -58,6 +77,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/legacy/service/impl/RepositoryManager.java b/quadriga/src/main/java/edu/asu/diging/quadriga/legacy/service/impl/RepositoryManager.java
index ad754225..c492df7c 100644
--- a/quadriga/src/main/java/edu/asu/diging/quadriga/legacy/service/impl/RepositoryManager.java
+++ b/quadriga/src/main/java/edu/asu/diging/quadriga/legacy/service/impl/RepositoryManager.java
@@ -40,6 +40,7 @@ public List processXMLandStoretoDb(String xml, String type) throws URISy
creationEventList = xmlToObject.parseXML(xml);
List flattenedlist = creationEventList.stream().flatMap(List::stream)
.map(event ->new EventGraph(event)).collect(Collectors.toList());
+
elementDao.saveEventGraphs(flattenedlist);
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..a5a8a54a 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,48 @@
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.model.MappedTripleGroup;
+import edu.asu.diging.quadriga.core.model.MappedTripleType;
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;
+import edu.asu.diging.quadriga.web.model.Network;
@Controller
public class DisplayCollectionController {
@@ -22,34 +52,119 @@ public class DisplayCollectionController {
@Autowired
private EventGraphService eventGraphService;
-
+
+ @Autowired
+ private MappedTripleGroupService mappedTripleGroupService;
+
+ @Autowired
+ private PredicateManager predicateManager;
+
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(required = false) Integer page , @RequestParam(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);
+
+
+ //Determine page number and size for network pagination
+ page = (page == null || page < 0) ? 0 : page - 1;
+ size = (size == null || size < 1) ? 10 : size;
+
+ model.addAttribute("size", size);
+
EventGraph latestNetwork = eventGraphService.findLatestEventGraphByCollectionId(collection.getId());
model.addAttribute("latestNetwork", latestNetwork);
+
+ Pageable paging = PageRequest.of(page, size);
+
+ // Get all EventGraphs for this collection
+ Page eventGraphsList = eventGraphService.findAllEventGraphsByCollectionId(collection.getId(), paging);
+
+ if (!eventGraphsList.isEmpty()) {
+ // Latest EventGraph will be for the last network submitted
+ EventGraph lastNetwork = eventGraphService.findLatestEventGraphByCollectionId(collection.getId());
+ model.addAttribute("lastNetworkSubmittedAt", lastNetwork.getCreationTime().atZoneSameInstant(ZoneId.systemDefault()));
+ model.addAttribute("lastNetworkSubmittedBy", lastNetwork.getAppName());
+
+ // Every EventGraph with same sourceURI belongs to the same network
+ // Group all EventGraphs with the same sourceURI together to get all networks
+ Map> groupedEventGraphs = groupEventGraphs(eventGraphsList);
+ List networks = new ArrayList<>();
+
+ groupedEventGraphs.forEach((sourceURI, eventGraphsInNetwork) -> {
+ Network network = new Network();
+ network.setSourceURI(sourceURI);
+ // The EventGraph that has the oldest creation date & time will be the network's creation date & time
+ EventGraph firstEventGraph = Collections.min(eventGraphsInNetwork, (eventGraph1, eventGraph2) -> eventGraph1
+ .getCreationTime().compareTo(eventGraph2.getCreationTime()));
+ network.setCreationTime(firstEventGraph.getCreationTime().atZoneSameInstant(ZoneId.systemDefault()));
+ network.setCreator(firstEventGraph.getContext().getCreator());
+ network.setAppName(firstEventGraph.getAppName());
+ networks.add(network);
+ });
+ // Sort networks as per the creation time
+ networks.sort((network1, network2) -> network2.getCreationTime().compareTo(network1.getCreationTime()));
+
+ // Add pagination to the networks as per determined page number and size
+ model.addAttribute("networks", networks.subList(page * size, Math.min(networks.size(), page * size + size)));
+ model.addAttribute("totalPages", networks.size() % 10 == 0 ? (networks.size()/size) : (networks.size()/size + 1));
+ model.addAttribute("pageNumber", page);
+ model.addAttribute("numberOfSubmittedNetworks", networks.size());
+ }
+
+// model.addAttribute("networks", eventGraphsList.getContent());
+// model.addAttribute("totalPages", eventGraphsList.getTotalPages());
+// model.addAttribute("pageNumber", page);
model.addAttribute("collection", collection);
- long numberOfSubmittedNetworks = eventGraphService.getNumberOfSubmittedNetworks(collection.getId());
- model.addAttribute("numberOfSubmittedNetworks", numberOfSubmittedNetworks);
-
+// model.addAttribute("numberOfSubmittedNetworks", numberOfSubmittedNetworks);
+// model.addAttribute("collection", collection);
+
// Get default mappings from Concepts
model.addAttribute("defaultMappings", collectionManager.getNumberOfDefaultMappings(collection.getId().toString()));
return "auth/displayCollection";
-
+
}
+ /**
+ * This method returns the number of default mappings present in the collection
+ * One MappedTripleGroup will exist for the "DefaultMappings" for this collection
+ * To get this number of default mappings, this method will check how many 'Predicates' have
+ * this mappedTripleGroupId linked to them
+ * This is because every default mapping has one predicate
+ * So, if the MappedTripleGroupId is present on n predicates, this collection
+ * must have n defaultMappings
+ *
+ * @param collectionId used to find mappedTripleGroupId
+ * @return the number of default mappings
+ */
+ private int getNumberOfDefaultMappings(String collectionId) {
+ try {
+ MappedTripleGroup mappedTripleGroup = mappedTripleGroupService.findByCollectionIdAndMappingType(collectionId, MappedTripleType.DEFAULT_MAPPING);
+ if(mappedTripleGroup != null) {
+ return predicateManager.countPredicatesByMappedTripleGroup(mappedTripleGroup.get_id().toString());
+ }
+
+ } catch (InvalidObjectIdException | CollectionNotFoundException e) {
+ logger.error("Couldn't find number of default mappings for collection ",e);
+ }
+ return 0;
+ }
+
+ private Map> groupEventGraphs(Page eventGraphsList) {
+ return eventGraphsList.stream().collect(Collectors.groupingBy(eventGraph -> eventGraph.getContext().getSourceUri()));
+ }
}
diff --git a/quadriga/src/main/java/edu/asu/diging/quadriga/web/ListCollectionController.java b/quadriga/src/main/java/edu/asu/diging/quadriga/web/ListCollectionController.java
index 0d29af49..e712251c 100644
--- a/quadriga/src/main/java/edu/asu/diging/quadriga/web/ListCollectionController.java
+++ b/quadriga/src/main/java/edu/asu/diging/quadriga/web/ListCollectionController.java
@@ -56,6 +56,7 @@ public String list(@RequestParam(defaultValue = "1", required = false, value = "
PageRequest.of(pageInt, sizeInt)));
model.addAttribute("username", simpleUser.getUsername());
}
+
return "auth/showcollections";
}
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..4132c97d
--- /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, predicateNodeId, objectNodeId, 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..0a0b26a9 100644
--- a/quadriga/src/main/resources/config.properties
+++ b/quadriga/src/main/resources/config.properties
@@ -6,9 +6,11 @@ db.password=${db.password}
neo4j.url=${neo4j.url}
neo4j.database=${neo4j.database}
+conceptpower_base_url=https://chps.asu.edu/conceptpower
+conceptpower_id_url=/rest/Concept?id={concept_uri}
citesphere_client_id=${citesphere.client.id}
citesphere_client_secret=${citesphere.client.secret}
-citesphere_base_url=${citesphere.base.url}
+citesphere_base_url=https://diging-dev.asu.edu/citesphere-review
citesphere_token_endpoint=/api/oauth/token
citesphere_check_token_endpoint=/api/oauth/check_token
citesphere_get_apps_endpoint=/api/v1/admin/apps
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..1d0a7f86 100644
--- a/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html
+++ b/quadriga/src/main/webapp/WEB-INF/views/auth/displayCollection.html
@@ -21,6 +21,7 @@ Description:
No networks submitted to this collection yet!
Number of submitted networks:
+
Last network submitted time:
@@ -28,20 +29,84 @@ No networks submitted to this coll
Last network submitted by:
-
+ Mappings
+
+
+ | # |
Mappings |
Triples |
+ | 1 |
Default Mappings |
|
+
+ Networks
+
+
+
+
+ | # |
+ Name |
+ Date and Time |
+ Action |
+
+
+
+
+ |
+
+
+ Graph for text submitted by
+ from
+
+ |
+ |
+
+
+ Visualize
+
+ |
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+ Source URI:
+
+
+
+ Network name:
+
+
+ Graph submitted by from
+
+
+ Submitted on:
+
+
+
+
+
+
+
+
+
+
+ Select a node to view concept inforrmation
+
+
+
+
+
+
+
+
+ Select a node to view text occurences
+
+
+
+
+
+
+
+
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..55bc97fe
--- /dev/null
+++ b/quadriga/src/main/webapp/WEB-INF/views/auth/displayNetwork.html
@@ -0,0 +1,252 @@
+
+