diff --git a/backend/Dockerfile b/backend/Dockerfile
index e224ff95d..6198f4dc5 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,6 +1,5 @@
-#FROM maven:3.6.3-adoptopenjdk-14
-FROM maven:3.8-jdk-11
+FROM maven:3.9.6-eclipse-temurin-17
RUN mkdir /opt/ols && mkdir /opt/ols/backend && mkdir /opt/ols/ols-shared
COPY ./backend /opt/ols/backend
diff --git a/backend/pom.xml b/backend/pom.xml
index 838ec3ae5..24b8b525e 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -15,9 +15,9 @@
- 11
- 11
- 11
+ 17
+ 17
+ 17
@@ -32,11 +32,23 @@
2.8.9
-
- org.neo4j.driver
- neo4j-java-driver
- 4.4.1
-
+
+ org.neo4j.driver
+ neo4j-java-driver
+ 5.19.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb
+ 2.7.5
+
+
+
+ javax.persistence
+ javax.persistence-api
+ 2.2
+
org.springframework.boot
@@ -149,6 +161,18 @@
springdoc-openapi-ui
1.6.4
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+ compile
+
+
+ joda-time
+ joda-time
+ 2.13.0
+ compile
+
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/config/RestCallInterceptor.java b/backend/src/main/java/uk/ac/ebi/spot/ols/config/RestCallInterceptor.java
new file mode 100644
index 000000000..c019d6984
--- /dev/null
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/config/RestCallInterceptor.java
@@ -0,0 +1,31 @@
+package uk.ac.ebi.spot.ols.config;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import uk.ac.ebi.spot.ols.reststatistics.service.RestCallHandlerService;
+
+public class RestCallInterceptor implements HandlerInterceptor {
+ private final RestCallHandlerService restCallHandlerService;
+
+ @Autowired
+ public RestCallInterceptor(RestCallHandlerService restCallHandlerService) {
+ this.restCallHandlerService = restCallHandlerService;
+ }
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ if (!request.getRequestURL().toString().contains("/api")
+ || request.getRequestURL().toString().contains("/api/rest/statistics")) {
+ return true;
+ }
+
+
+ restCallHandlerService.handle(request);
+
+ return true;
+ }
+}
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/config/WebConfig.java b/backend/src/main/java/uk/ac/ebi/spot/ols/config/WebConfig.java
index c67a52c02..640772f91 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/config/WebConfig.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/config/WebConfig.java
@@ -2,13 +2,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-import org.springframework.http.MediaType;
-import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.*;
-import org.springframework.web.util.UrlPathHelper;
+import uk.ac.ebi.spot.ols.reststatistics.service.RestCallHandlerService;
/**
* @author Simon Jupp
@@ -25,6 +21,10 @@ public class WebConfig extends WebMvcConfigurerAdapter {
*
* @param configurer
*/
+
+ @Autowired
+ RestCallHandlerService restCallHandlerService;
+
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// UrlPathHelper urlPathHelper = new UrlPathHelper();
@@ -36,17 +36,15 @@ public void configurePathMatch(PathMatchConfigurer configurer) {
}
-// @Bean
-// MaintenanceInterceptor getMaintenanceInterceptor() {
-// return new MaintenanceInterceptor();
-// }
-
-// @Autowired
-// MaintenanceInterceptor interceptor;
-// @Override
-// public void addInterceptors(InterceptorRegistry registry) {
-// registry.addInterceptor(interceptor);
-// }
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(getRestCallInterceptor());
+ }
+
+ @Bean
+ public RestCallInterceptor getRestCallInterceptor() {
+ return new RestCallInterceptor(restCallHandlerService);
+ }
@Override
public void addCorsMappings(CorsRegistry registry) {
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/TopConceptEnum.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/TopConceptEnum.java
new file mode 100644
index 000000000..3a86e8c58
--- /dev/null
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/TopConceptEnum.java
@@ -0,0 +1,7 @@
+package uk.ac.ebi.spot.ols.controller.api.v1;
+
+public enum TopConceptEnum {
+ SCHEMA,
+ TOPCONCEPTOF_PROPERTY,
+ RELATIONSHIPS
+}
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1ApiUnavailable.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1ApiUnavailable.java
index 4452d07bf..dabe0309e 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1ApiUnavailable.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1ApiUnavailable.java
@@ -6,8 +6,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@@ -16,7 +15,7 @@
* @date 27/09/2016
* Samples, Phenotypes and Ontologies Team, EMBL-EBI
*/
-@Controller
+@RestController
public class V1ApiUnavailable {
@RequestMapping(path = "/api/unavailable", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET)
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1IndividualController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1IndividualController.java
index d5e4a4fc5..e3b5438a5 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1IndividualController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1IndividualController.java
@@ -30,6 +30,7 @@
* @date 18/08/2015
* Samples, Phenotypes and Ontologies Team, EMBL-EBI
*/
+
@Tag(name = "Individual Controller", description = "NOTE: For IRI parameters, the value must be URL encoded. " +
"For example, the IRI http://purl.obolibrary.org/obo/IAO_0000124 should be encoded as http%3A%252F%2Fpurl.obolibrary.org%2Fobo%2FIAO_0000124.")
@RestController
@@ -97,7 +98,8 @@ HttpEntity> getAllIndividuals(
return new ResponseEntity<>(assembler.toModel(terms, individualAssembler), HttpStatus.OK);
}
-
+
+
@RequestMapping(path = "/findByIdAndIsDefiningOntology/{iri}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
HttpEntity> getAllIndividualsByIdAndIsDefiningOntology(
@PathVariable("iri")
@@ -111,11 +113,11 @@ HttpEntity> getAllIndividualsByIdAndIsDefiningOntology(
decoded = UriUtils.decode(termId, "UTF-8");
return getAllIndividualsByIdAndIsDefiningOntology(decoded, null, null, lang, pageable, assembler);
- }
-
-
- @RequestMapping(path = "/findByIdAndIsDefiningOntology",
- produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE},
+ }
+
+
+ @RequestMapping(path = "/findByIdAndIsDefiningOntology",
+ produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE},
method = RequestMethod.GET)
HttpEntity> getAllIndividualsByIdAndIsDefiningOntology(
@RequestParam(value = "iri", required = false)
@@ -148,11 +150,11 @@ HttpEntity> getAllIndividualsByIdAndIsDefiningOntology(
return new ResponseEntity<>(assembler.toModel(terms, individualAssembler), HttpStatus.OK);
}
-
+
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "EntityModel not found")
@ExceptionHandler(ResourceNotFoundException.class)
public void handleError(HttpServletRequest req, Exception exception) {
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyController.java
index 79050ce62..bb59cc00a 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyController.java
@@ -7,6 +7,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.RepositoryLinksResource;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
@@ -22,10 +23,14 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import uk.ac.ebi.spot.ols.model.FilterOption;
import uk.ac.ebi.spot.ols.model.v1.V1Ontology;
import uk.ac.ebi.spot.ols.repository.v1.V1OntologyRepository;
+import java.lang.reflect.*;
+import java.util.*;
import javax.servlet.http.HttpServletRequest;
@@ -34,6 +39,7 @@
* @date 19/08/2015
* Samples, Phenotypes and Ontologies Team, EMBL-EBI
*/
+
@Tag(name = "Ontology Controller")
@RestController
@RequestMapping("/api/ontologies")
@@ -86,6 +92,65 @@ HttpEntity> getOntology(
return new ResponseEntity<>( documentAssembler.toModel(document), HttpStatus.OK);
}
+ @RequestMapping(path = "/filterby", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getOntologiesByMetadata(
+ @RequestParam(value = "schema", required = true) Collection schemas,
+ @RequestParam(value = "classification", required = true) Collection classifications,
+ @Parameter(description = "Set to true (default setting is false) for intersection (default behavior is union) of classifications.")
+ @RequestParam(value = "exclusive", required = false, defaultValue = "false") boolean exclusive,
+ @Parameter(description = "Use License option to filter based on license.label, license.logo and license.url variables. " +
+ "Use Composite Option to filter based on the objects (i.e. collection, subject) within the classifications variable. " +
+ "Use Linear option to filter based on String and Collection based variables.")
+ @RequestParam(value = "option", required = false, defaultValue = "LINEAR") FilterOption filterOption,
+ @PageableDefault(size = 100, page = 0) Pageable pageable,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ PagedResourcesAssembler assembler
+ ) throws ResourceNotFoundException {
+ Set tempSet = new HashSet();
+ if (filterOption == FilterOption.LINEAR)
+ tempSet = ontologyRepository.filter(schemas,classifications,exclusive, lang);
+ else if (filterOption == FilterOption.COMPOSITE)
+ tempSet = ontologyRepository.filterComposite(schemas,classifications,exclusive, lang);
+ else if (filterOption == FilterOption.LICENSE)
+ tempSet = ontologyRepository.filterLicense(schemas,classifications,exclusive,lang);
+ List tempList = new ArrayList();
+ tempList.addAll(tempSet);
+ final int start = (int)pageable.getOffset();
+ final int end = Math.min((start + pageable.getPageSize()), tempSet.size());
+ Page document = new PageImpl<>(tempList.subList(start, end), pageable, tempSet.size());
+
+ return new ResponseEntity<>( assembler.toModel(document, documentAssembler), HttpStatus.OK);
+ }
+
+ @RequestMapping(path = "/schemakeys", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> filterKeys(
+ @PageableDefault(size = 100, page = 0) Pageable pageable,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ PagedResourcesAssembler assembler){
+ Set tempSet = ontologyRepository.getSchemaKeys(lang);
+ List tempList = new ArrayList();
+ tempList.addAll(tempSet);
+ final int start = (int)pageable.getOffset();
+ final int end = Math.min((start + pageable.getPageSize()), tempSet.size());
+ Page document = new PageImpl<>(tempList.subList(start, end), pageable, tempSet.size());
+ return new ResponseEntity<>(document, HttpStatus.OK);
+ }
+
+ @RequestMapping(path = "/schemavalues", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> filterValues(
+ @RequestParam(value = "schema", required = true) Collection schemas,
+ @PageableDefault(size = 100, page = 0) Pageable pageable,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ PagedResourcesAssembler assembler){
+ Set tempSet = ontologyRepository.getSchemaValues(schemas,lang);
+ List tempList = new ArrayList();
+ tempList.addAll(tempSet);
+ final int start = (int)pageable.getOffset();
+ final int end = Math.min((start + pageable.getPageSize()), tempSet.size());
+ Page document = new PageImpl<>(tempList.subList(start, end), pageable, tempSet.size());
+ return new ResponseEntity<>(document, HttpStatus.OK);
+ }
+
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "EntityModel not found")
@ExceptionHandler(ResourceNotFoundException.class)
public void handleError(HttpServletRequest req, Exception exception) {
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyPropertyController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyPropertyController.java
index d823a9cbb..bb9e80325 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyPropertyController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyPropertyController.java
@@ -23,8 +23,10 @@
import org.springframework.web.util.UriUtils;
import uk.ac.ebi.spot.ols.model.v1.V1Property;
import uk.ac.ebi.spot.ols.repository.v1.V1JsTreeRepository;
+import uk.ac.ebi.spot.ols.repository.v1.V1JsTreeRepositoryExtn;
import uk.ac.ebi.spot.ols.repository.v1.V1PropertyRepository;
import uk.ac.ebi.spot.ols.service.Neo4jClient;
+import uk.ac.ebi.spot.ols.service.ViewMode;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
@@ -43,6 +45,9 @@ public class V1OntologyPropertyController {
@Autowired
V1JsTreeRepository jsTreeRepository;
+
+ @Autowired
+ V1JsTreeRepositoryExtn jsTreeRepositoryExtn;
@Autowired
Neo4jClient neo4jClient;
@@ -269,7 +274,7 @@ HttpEntity getJsTree(
try {
String decoded = UriUtils.decode(termId, "UTF-8");
- Object object= jsTreeRepository.getJsTreeForProperty(decoded, ontologyId, lang);
+ Object object= jsTreeRepositoryExtn.getJsTreeForPropertyByViewMode(decoded, ontologyId, lang, ViewMode.getFromShortName(viewMode), siblings);
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return new HttpEntity(ow.writeValueAsString(object));
} catch (JsonProcessingException e) {
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologySKOSConceptController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologySKOSConceptController.java
new file mode 100644
index 000000000..42a8a94d9
--- /dev/null
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologySKOSConceptController.java
@@ -0,0 +1,348 @@
+package uk.ac.ebi.spot.ols.controller.api.v1;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+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.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.data.web.PagedResourcesAssembler;
+import org.springframework.hateoas.MediaTypes;
+import org.springframework.hateoas.PagedModel;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.util.UriUtils;
+
+import uk.ac.ebi.spot.ols.model.Edge;
+import uk.ac.ebi.spot.ols.model.Node;
+import uk.ac.ebi.spot.ols.model.SKOSRelation;
+import uk.ac.ebi.spot.ols.model.v1.V1Term;
+import uk.ac.ebi.spot.ols.repository.v1.TreeNode;
+import uk.ac.ebi.spot.ols.repository.v1.V1TermRepository;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+/**
+ * @author Erhun Giray TUNCAY
+ * @email giray.tuncay@tib.eu
+ * TIB-Leibniz Information Center for Science and Technology
+ */
+@RestController
+@RequestMapping("/api/ontologies")
+@Tag(name = "v1-ontology-skos-controller", description = "SKOS concept hierarchies and relations extracted from individuals (instances) from a particular ontology in this service")
+public class V1OntologySKOSConceptController {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ @Autowired
+ private V1TermRepository termRepository;
+
+ @Autowired
+ V1TermAssembler termAssembler;
+
+ @Operation(description = "Get complete SKOS concept hierarchy or only top concepts based on alternative top concept identification methods and concept relations. If only top concepts are identified, they can be used to extract the following levels of the concept tree one by one using the /{onto}/conceptrelations/{iri} method with broader or narrower concept relations.")
+ @RequestMapping(path = "/{onto}/skos/tree", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity>> getSKOSConceptHierarchyByOntology(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "infer top concepts by schema (hasTopConcept) or TopConceptOf property or broader/narrower relationships", required = true)
+ @RequestParam(value = "find_roots", required = true, defaultValue = "SCHEMA") TopConceptEnum topConceptIdentification,
+ @Parameter(description = "infer from narrower or broader relationships", required = true)
+ @RequestParam(value = "narrower", required = true, defaultValue = "false") boolean narrower,
+ @Parameter(description = "Extract the whole tree with children or only the top concepts", required = true)
+ @RequestParam(value = "with_children", required = true, defaultValue = "false") boolean withChildren,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+ ontologyId = ontologyId.toLowerCase();
+ if (TopConceptEnum.RELATIONSHIPS == topConceptIdentification)
+ return new ResponseEntity<>(termRepository.conceptTreeWithoutTop(ontologyId,narrower,withChildren,obsoletes,lang,pageable), HttpStatus.OK);
+ else
+ return new ResponseEntity<>(termRepository.conceptTree(ontologyId,TopConceptEnum.SCHEMA == topConceptIdentification,narrower, withChildren,obsoletes,lang,pageable), HttpStatus.OK);
+ }
+
+ @Operation(description = "Display complete SKOS concept hierarchy or only top concepts based on alternative top concept identification methods and concept relations. If only top concepts are identified, they can be used to extract the following levels of the concept tree one by one using the /{onto}/displayconceptrelations/{iri} method with broader or narrower concept relations.")
+ @RequestMapping(path = "/{onto}/skos/displaytree", produces = {MediaType.TEXT_PLAIN_VALUE}, method = RequestMethod.GET)
+ @ResponseBody
+ HttpEntity displaySKOSConceptHierarchyByOntology(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "infer top concepts by schema (hasTopConcept) or TopConceptOf property or broader/narrower relationships", required = true)
+ @RequestParam(value = "find_roots", required = true, defaultValue = "SCHEMA") TopConceptEnum topConceptIdentification,
+ @Parameter(description = "infer from narrower or broader relationships", required = true)
+ @RequestParam(value = "narrower", required = true, defaultValue = "false") boolean narrower,
+ @Parameter(description = "Extract the whole tree with children or only the top concepts", required = true)
+ @RequestParam(value = "with_children", required = true, defaultValue = "false") boolean withChildren,
+ @Parameter(description = "display related concepts", required = true)
+ @RequestParam(value = "display_related", required = true, defaultValue = "false") boolean displayRelated,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+ ontologyId = ontologyId.toLowerCase();
+ List> rootIndividuals = null;
+ if(TopConceptEnum.RELATIONSHIPS == topConceptIdentification)
+ rootIndividuals = termRepository.conceptTreeWithoutTop(ontologyId,narrower,withChildren,obsoletes,lang,pageable);
+ else
+ rootIndividuals = termRepository.conceptTree(ontologyId,TopConceptEnum.SCHEMA == topConceptIdentification,narrower, withChildren,obsoletes,lang,pageable);
+ StringBuilder sb = new StringBuilder();
+ for (TreeNode root : rootIndividuals) {
+ sb.append(root.getIndex() + " , "+ root.getData().label + " , " + root.getData().iri).append("\n");
+ sb.append(generateConceptHierarchyTextByOntology(root, displayRelated));
+ }
+
+ return new HttpEntity(sb.toString());
+ }
+
+ @Operation(description = "Get partial SKOS concept hierarchy based on the encoded iri of the designated top concept")
+ @RequestMapping(path = "/{onto}/skos/{iri}/tree", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getSKOSConceptHierarchyByOntologyAndIri(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "infer from narrower or broader relationships", required = true)
+ @RequestParam(value = "narrower", required = true, defaultValue = "false") boolean narrower,
+ @Parameter(description = "index value for the root term", required = true)
+ @RequestParam(value = "index", required = true, defaultValue = "1") String index,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+ ontologyId = ontologyId.toLowerCase();
+ TreeNode topConcept = new TreeNode(new V1Term());
+ String decodedIri;
+ decodedIri = UriUtils.decode(iri, "UTF-8");
+ topConcept = termRepository.conceptSubTree(ontologyId, decodedIri, narrower, index, obsoletes, lang, pageable);
+
+ if (topConcept.getData().iri == null)
+ throw new ResourceNotFoundException("No roots could be found for " + ontologyId );
+ return new ResponseEntity<>(topConcept, HttpStatus.OK);
+ }
+
+ @Operation(description = "Display partial SKOS concept hierarchy based on the encoded iri of the designated top concept")
+ @RequestMapping(path = "/{onto}/skos/{iri}/displaytree", produces = {MediaType.TEXT_PLAIN_VALUE}, method = RequestMethod.GET)
+ @ResponseBody
+ HttpEntity displaySKOSConceptHierarchyByOntologyAndIri(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "infer from narrower or broader relationships", required = true)
+ @RequestParam(value = "narrower", required = true, defaultValue = "false") boolean narrower,
+ @Parameter(description = "display related concepts", required = true)
+ @RequestParam(value = "display_related", required = true, defaultValue = "false") boolean displayRelated,
+ @Parameter(description = "index value for the root term", required = true)
+ @RequestParam(value = "index", required = true, defaultValue = "1") String index,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+ ontologyId = ontologyId.toLowerCase();
+ TreeNode topConcept = new TreeNode(new V1Term());
+ String decodedIri;
+ StringBuilder sb = new StringBuilder();
+ decodedIri = UriUtils.decode(iri, "UTF-8");
+ topConcept = termRepository.conceptSubTree(ontologyId, decodedIri, narrower, index, obsoletes, lang, pageable);
+
+ sb.append(topConcept.getIndex() + " , "+ topConcept.getData().label + " , " + topConcept.getData().iri).append("\n");
+ sb.append(generateConceptHierarchyTextByOntology(topConcept, displayRelated));
+
+ return new HttpEntity(sb.toString());
+ }
+
+ @Operation(description = "Broader, Narrower and Related concept relations of a concept are listed in JSON if the concept iri is provided in encoded format.")
+ @RequestMapping(path = "/{onto}/skos/{iri}/relations", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ public HttpEntity> findRelatedConcepts(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "skos based concept relation type", required = true)
+ @RequestParam(value = "relation_type", required = true, defaultValue = "broader")
+ @Schema(type = "string", allowableValues = { "broader", "narrower", "related" }) String relationType,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable,
+ PagedResourcesAssembler assembler) {
+
+ ontologyId = ontologyId.toLowerCase();
+ List related = new ArrayList();
+ String decodedIri = UriUtils.decode(iri, "UTF-8");
+ related = termRepository.findRelated(ontologyId, decodedIri, relationType,lang);
+
+
+ final int start = (int)pageable.getOffset();
+ final int end = Math.min((start + pageable.getPageSize()), related.size());
+ Page conceptPage = new PageImpl<>(related.subList(start, end), pageable, related.size());
+
+ return new ResponseEntity<>( assembler.toModel(conceptPage), HttpStatus.OK);
+
+ }
+
+ @Operation(description = "Broader, Narrower and Related concept relations of a concept are displayed as text if the concept iri is provided in encoded format.")
+ @RequestMapping(path = "/{onto}/skos/{iri}/displayrelations", produces = {MediaType.TEXT_PLAIN_VALUE}, method = RequestMethod.GET)
+ @ResponseBody
+ public HttpEntity displayRelatedConcepts(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "skos based concept relation type", required = true)
+ @RequestParam(value = "relation_type", required = true, defaultValue = "broader")
+ @Schema(type = "string", allowableValues = { "broader", "narrower", "related" }) String relationType,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable,
+ PagedResourcesAssembler assembler) {
+ StringBuilder sb = new StringBuilder();
+ ontologyId = ontologyId.toLowerCase();
+ List related = new ArrayList();
+ String decodedIri = UriUtils.decode(iri, "UTF-8");
+ related = termRepository.findRelated(ontologyId, decodedIri, relationType,lang);
+
+ final int start = (int)pageable.getOffset();
+ final int end = Math.min((start + pageable.getPageSize()), related.size());
+ Page conceptPage = new PageImpl<>(related.subList(start, end), pageable, related.size());
+ int count = 0;
+ for (V1Term individual : conceptPage.getContent())
+ sb.append(++count).append(" , ").append(individual.label).append(" , ").append(individual.iri).append("\n");
+
+ return new HttpEntity<>( sb.toString());
+
+ }
+
+ @Operation(description = "Broader, Narrower and Related concept relations of a concept are listed in JSON if the concept iri is provided in encoded format. The relationship is identified indirectly based on the related concept's relation to the concept in question. This requires traversing all the available concepts and checking if they are related to the concept in question. For this reason, this method is relatively slower than the displayconceptrelations method. Nevertheless, it enables to identify unforeseen relations of the concept in question")
+ @RequestMapping(path = "/{onto}/skos/{iri}/indirectrelations", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ public HttpEntity> findRelatedConceptsIndirectly(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "skos based concept relation type", required = true)
+ @RequestParam(value = "relation_type", required = true, defaultValue = "broader")
+ @Schema(type = "string", allowableValues = { "broader", "narrower", "related" }) String relationType,
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+
+ ontologyId = ontologyId.toLowerCase();
+ List related = new ArrayList();
+ String decodedIri = UriUtils.decode(iri, "UTF-8");
+ related = termRepository.findRelatedIndirectly(ontologyId, decodedIri, relationType, obsoletes,lang,pageable);
+
+ return new ResponseEntity<>( related, HttpStatus.OK);
+
+ }
+
+ @Operation(description = "Broader, Narrower and Related concept relations of a concept are listed in JSON if the concept iri is provided in encoded format. The relationship is identified indirectly based on the related concept's relation to the concept in question. This requires traversing all the available concepts and checking if they are related to the concept in question. For this reason, this method is relatively slower than the displayconceptrelations method. Nevertheless, it enables to identify unforeseen relations of the concept in question")
+ @RequestMapping(path = "/{onto}/skos/{iri}/displayindirectrelations", produces = {MediaType.TEXT_PLAIN_VALUE}, method = RequestMethod.GET)
+ @ResponseBody
+ public HttpEntity displayRelatedConceptsIndirectly(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @Parameter(description = "skos based concept relation type", required = true)
+ @RequestParam(value = "relation_type", required = true, defaultValue = "broader")
+ @Schema(type = "string", allowableValues = { "broader", "narrower", "related" }) String relationType,
+ @Parameter(description = "Page size to retrieve individuals", required = true)
+ @RequestParam(value = "obsoletes", required = false) Boolean obsoletes,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ Pageable pageable) {
+ StringBuilder sb = new StringBuilder();
+ ontologyId = ontologyId.toLowerCase();
+ List related = new ArrayList();
+ String decodedIri = UriUtils.decode(iri, "UTF-8");
+ related = termRepository.findRelatedIndirectly(ontologyId, decodedIri, relationType, obsoletes,lang,pageable);
+
+ int count = 0;
+ for (V1Term individual : related)
+ sb.append(++count).append(" , ").append(individual.label).append(" , ").append(individual.iri).append("\n");
+
+
+ return new ResponseEntity<>( sb.toString(), HttpStatus.OK);
+
+ }
+
+ @Operation(description = "Node and Edge definitions needed to visualize the nodes that are directly related with the subject term. Ontology ID and encoded iri are required. ")
+ @RequestMapping(path = "/{onto}/skos/{iri}/graph", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ public HttpEntity retrieveImmediateGraph(
+ @Parameter(description = "ontology ID", required = true)
+ @PathVariable("onto") String ontologyId,
+ @Parameter(description = "encoded concept IRI", required = true)
+ @PathVariable("iri") String iri,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang){
+
+ List related = new ArrayList();
+ String decodedIri = UriUtils.decode(iri, "UTF-8");
+
+ V1Term subjectTerm = termRepository.findByOntologyAndIri(ontologyId, decodedIri, lang);
+
+ related = termRepository.findRelated(ontologyId, decodedIri, "related",lang);
+
+ List narrower = new ArrayList();
+ narrower = termRepository.findRelated(ontologyId, decodedIri, "narrower",lang);
+
+ List broader = new ArrayList();
+ broader = termRepository.findRelated(ontologyId, decodedIri, "broader",lang);
+
+ Set relatedNodes = new HashSet();
+ related.forEach(term -> relatedNodes.add(new Node(term.iri, term.label)));
+ Set narrowerNodes = new HashSet();
+ narrower.forEach(term -> narrowerNodes.add(new Node(term.iri, term.label)));
+ Set broaderNodes = new HashSet();
+ broader.forEach(term -> broaderNodes.add(new Node(term.iri, term.label)));
+
+ Set edges = new HashSet();
+ relatedNodes.forEach(node -> edges.add(new Edge(decodedIri, node.getIri(), "related", SKOSRelation.related.getPropertyName())));
+ narrowerNodes.forEach(node -> edges.add(new Edge(decodedIri, node.getIri(), "narrower",SKOSRelation.narrower.getPropertyName())));
+ broaderNodes.forEach(node -> edges.add(new Edge(decodedIri, node.getIri(), "broader",SKOSRelation.broader.getPropertyName())));
+
+ Set nodes = new HashSet();
+ nodes.add(new Node(decodedIri,subjectTerm.label));
+ nodes.addAll(relatedNodes);
+ nodes.addAll(broaderNodes);
+ nodes.addAll(narrowerNodes);
+
+
+ Map graph = new HashMap();
+ graph.put("nodes", nodes);
+ graph.put("edges", edges);
+ ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
+ try {
+ return new ResponseEntity<>(ow.writeValueAsString(graph),HttpStatus.OK);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public StringBuilder generateConceptHierarchyTextByOntology(TreeNode rootConcept, boolean displayRelated) {
+ StringBuilder sb = new StringBuilder();
+ for (TreeNode childConcept : rootConcept.getChildren()) {
+ sb.append(childConcept.getIndex() + " , "+ childConcept.getData().label + " , " + childConcept.getData().iri).append("\n");
+ sb.append(generateConceptHierarchyTextByOntology(childConcept,displayRelated));
+ }
+ if(displayRelated)
+ for (TreeNode relatedConcept : rootConcept.getRelated()) {
+ sb.append(relatedConcept.getIndex() + " , "+ relatedConcept.getData().label + " , " + relatedConcept.getData().iri).append("\n");
+ sb.append(generateConceptHierarchyTextByOntology(relatedConcept,displayRelated));
+ }
+ return sb;
+ }
+
+ @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Resource not found")
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public void handleError(HttpServletRequest req, Exception exception) {
+ }
+}
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyTermController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyTermController.java
index 297594482..a6fafc9df 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyTermController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1OntologyTermController.java
@@ -22,6 +22,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriUtils;
+import uk.ac.ebi.spot.ols.model.v1.V1Individual;
import uk.ac.ebi.spot.ols.model.v1.V1Term;
import uk.ac.ebi.spot.ols.repository.v1.V1GraphRepository;
import uk.ac.ebi.spot.ols.repository.v1.V1JsTreeRepository;
@@ -31,6 +32,12 @@
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import java.nio.charset.StandardCharsets;
+import uk.ac.ebi.spot.ols.repository.v1.V1JsTreeRepositoryExtn;
+import uk.ac.ebi.spot.ols.service.ViewMode;
/**
* @author Simon Jupp
@@ -51,11 +58,17 @@ public class V1OntologyTermController {
@Autowired
V1TermAssembler termAssembler;
+ @Autowired
+ V1IndividualAssembler individualAssembler;
+
@Autowired
V1PreferredRootTermAssembler preferredRootTermAssembler;
@Autowired
V1JsTreeRepository jsTreeRepository;
+
+ @Autowired
+ V1JsTreeRepositoryExtn jsTreeRepositoryExtn;
@Autowired
V1GraphRepository graphRepository;
@@ -406,6 +419,139 @@ HttpEntity> ancestors(@PathVariable("onto")
return new ResponseEntity<>( assembler.toModel(ancestors, termAssembler), HttpStatus.OK);
}
+ @RequestMapping(path = "/{onto}/terms/{iri}/superclasses", produces = {MediaType.APPLICATION_JSON_VALUE,
+ MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getSuperClasses(
+ @PathVariable("onto")
+ @Parameter(name = "onto",
+ description = "The ID of the ontology. For example for Data Use Ontology, the ID is duo.",
+ example = "duo") String ontologyId,
+ @PathVariable("iri")
+ @Parameter(name = "iri",
+ description = "The IRI of the term, this value must be single URL encoded",
+ example = "http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDUO_0000017") String termId,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ @Parameter(hidden = true) Pageable pageable,
+ @Parameter(hidden = true) PagedResourcesAssembler assembler) {
+
+ ontologyId = ontologyId.toLowerCase();
+
+ String decoded = UriUtils.decode(termId, "UTF-8");
+ String entityId = ontologyId+"+class+"+decoded;
+ Page superClasses = graphRepository.getSuperClassPaginated(entityId, lang, pageable);
+ if (superClasses == null)
+ throw new ResourceNotFoundException("No super classes could be found for " + ontologyId
+ + " and " + termId);
+
+ return new ResponseEntity<>( assembler.toModel(superClasses, termAssembler), HttpStatus.OK);
+ }
+
+ @RequestMapping(path = "/{onto}/terms/{iri}/equivalentclasses", produces = {MediaType.APPLICATION_JSON_VALUE,
+ MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getEquivalentClasses(
+ @PathVariable("onto")
+ @Parameter(name = "onto",
+ description = "The ID of the ontology. For example for Data Use Ontology, the ID is duo.",
+ example = "duo") String ontologyId,
+ @PathVariable("iri")
+ @Parameter(name = "iri",
+ description = "The IRI of the term, this value must be single URL encoded",
+ example = "http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDUO_0000017") String termId,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ @Parameter(hidden = true) Pageable pageable,
+ @Parameter(hidden = true) PagedResourcesAssembler assembler) {
+
+ ontologyId = ontologyId.toLowerCase();
+
+ String decoded = UriUtils.decode(termId, "UTF-8");
+ String entityId = ontologyId+"+class+"+decoded;
+ Page equivalentClasses = graphRepository.getEquivalentClassPaginated(entityId, lang, pageable);
+ if (equivalentClasses == null)
+ throw new ResourceNotFoundException("No equivalent classes could be found for " + ontologyId
+ + " and " + termId);
+
+ return new ResponseEntity<>( assembler.toModel(equivalentClasses, termAssembler), HttpStatus.OK);
+ }
+
+
+ @RequestMapping(path = "/{onto}/terms/{iri}/relatedfrom", produces = {MediaType.APPLICATION_JSON_VALUE,
+ MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getRelatedFrom(
+ @PathVariable("onto")
+ @Parameter(name = "onto",
+ description = "The ID of the ontology. For example for Data Use Ontology, the ID is duo.",
+ example = "duo") String ontologyId,
+ @PathVariable("iri")
+ @Parameter(name = "iri",
+ description = "The IRI of the term, this value must be single URL encoded",
+ example = "http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDUO_0000017") String termId,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ @Parameter(hidden = true) Pageable pageable,
+ @Parameter(hidden = true) PagedResourcesAssembler assembler) {
+
+ ontologyId = ontologyId.toLowerCase();
+
+ String decoded = UriUtils.decode(termId, "UTF-8");
+ String entityId = ontologyId+"+class+"+decoded;
+ Page relatedFroms = graphRepository.getRelatedFromPaginated(entityId, lang, pageable);
+ if (relatedFroms == null)
+ throw new ResourceNotFoundException("No related from terms could be found for " + ontologyId
+ + " and " + termId);
+
+ return new ResponseEntity<>( assembler.toModel(relatedFroms, termAssembler), HttpStatus.OK);
+ }
+
+ @RequestMapping(path = "/{onto}/terms/{iri}/instances", produces = {MediaType.APPLICATION_JSON_VALUE,
+ MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity> getInstances(
+ @PathVariable("onto")
+ @Parameter(name = "onto",
+ description = "The ID of the ontology. For example for Data Use Ontology, the ID is duo.",
+ example = "duo") String ontologyId,
+ @PathVariable("iri")
+ @Parameter(name = "iri",
+ description = "The IRI of the term, this value must be single URL encoded",
+ example = "http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDUO_0000017") String termId,
+ @RequestParam(value = "lang", required = false, defaultValue = "en") String lang,
+ @Parameter(hidden = true) Pageable pageable,
+ @Parameter(hidden = true) PagedResourcesAssembler assembler) {
+
+ ontologyId = ontologyId.toLowerCase();
+
+ String decoded = UriUtils.decode(termId, "UTF-8");
+ String entityId = ontologyId+"+class+"+decoded;
+ Page instances = graphRepository.getTermInstancesPaginated(entityId, lang, pageable);
+ if (instances == null)
+ throw new ResourceNotFoundException("No instances could be found for " + ontologyId
+ + " and " + termId);
+
+ return new ResponseEntity<>( assembler.toModel(instances, individualAssembler), HttpStatus.OK);
+ }
+
+ @RequestMapping(path = "/{onto}/terms/{iri}/json", produces = {MediaType.APPLICATION_JSON_VALUE,
+ MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
+ HttpEntity getJson(
+ @PathVariable("onto")
+ @Parameter(name = "onto",
+ description = "The ID of the ontology. For example for Data Use Ontology, the ID is duo.",
+ example = "duo") String ontologyId,
+ @PathVariable("iri")
+ @Parameter(name = "iri",
+ description = "The IRI of the term, this value must be single URL encoded",
+ example = "http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDUO_0000017") String termId) {
+
+ ontologyId = ontologyId.toLowerCase();
+
+ String decoded = UriUtils.decode(termId, "UTF-8");
+ String entityId = ontologyId+"+class+"+decoded;
+ String json = graphRepository.getTermJson(entityId);
+ if (json == null)
+ throw new ResourceNotFoundException("No _json could be found for " + ontologyId
+ + " and " + termId);
+
+ return new ResponseEntity<>( json, HttpStatus.OK);
+ }
+
@RequestMapping(path = "/{onto}/terms/{iri}/jstree",
produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE},
method = RequestMethod.GET)
@@ -425,8 +571,8 @@ HttpEntity graphJsTree(
ontologyId = ontologyId.toLowerCase();
try {
- String decodedTermId = UriUtils.decode(termId, "UTF-8");
- Object object= jsTreeRepository.getJsTreeForClass(decodedTermId, ontologyId, lang);
+ String decodedTermId = decodeUrl(termId);
+ Object object= jsTreeRepositoryExtn.getJsTreeForClassByViewMode(decodedTermId, ontologyId, lang, ViewMode.getFromShortName(viewMode), siblings);
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return new HttpEntity(ow.writeValueAsString(object));
} catch (JsonProcessingException e) {
@@ -485,7 +631,7 @@ HttpEntity graphJson(
Object object= graphRepository.getGraphForClass(decoded, ontologyId, lang);
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return new HttpEntity(ow.writeValueAsString(object));
- } catch (JsonProcessingException e) {
+ } catch (Exception e) {
e.printStackTrace();
}
throw new ResourceNotFoundException();
@@ -787,5 +933,13 @@ HttpEntity> termHierarchicalAncestorsByOntology(
public void handleError(HttpServletRequest req, Exception exception) {
}
+
+ private static String decodeUrl(String url) {
+ if(url.contains("%") || url.contains("+"))
+ {
+ return decodeUrl(java.net.URLDecoder.decode(url, StandardCharsets.UTF_8));
+ }
+ return url;
+ }
}
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1PropertyController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1PropertyController.java
index 2435371b7..15e1ae04f 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1PropertyController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1PropertyController.java
@@ -112,8 +112,8 @@ HttpEntity> getPropertiesByIriAndIsDefiningOntology(@Path
String decoded = null;
decoded = UriUtils.decode(termId, "UTF-8");
return getPropertiesByIdAndIsDefiningOntology(decoded, null, null, lang, pageable, assembler);
- }
-
+ }
+
@RequestMapping(path = "/findByIdAndIsDefiningOntology", produces = {MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE}, method = RequestMethod.GET)
HttpEntity> getPropertiesByIdAndIsDefiningOntology(
@RequestParam(value = "iri", required = false)
@@ -149,7 +149,7 @@ else if (oboId != null) {
return new ResponseEntity<>( assembler.toModel(terms, termAssembler), HttpStatus.OK);
}
-
+
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "EntityModel not found")
@ExceptionHandler(ResourceNotFoundException.class)
public void handleError(HttpServletRequest req, Exception exception) {
diff --git a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1SearchController.java b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1SearchController.java
index 55896fb00..139d27429 100644
--- a/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1SearchController.java
+++ b/backend/src/main/java/uk/ac/ebi/spot/ols/controller/api/v1/V1SearchController.java
@@ -20,8 +20,10 @@
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
+import io.swagger.v3.oas.annotations.Parameter;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,11 +31,10 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
-
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-
+import uk.ac.ebi.spot.ols.model.FilterOption;
import org.springframework.web.bind.annotation.RestController;
import uk.ac.ebi.spot.ols.repository.Validation;
import uk.ac.ebi.spot.ols.repository.solr.OlsSolrClient;
@@ -43,6 +44,7 @@
import uk.ac.ebi.spot.ols.repository.v1.V1OntologyRepository;
import uk.ac.ebi.spot.ols.repository.v1.mappers.AnnotationExtractor;
+
import static uk.ac.ebi.ols.shared.DefinedFields.*;
@@ -67,10 +69,18 @@ public void search(
@Parameter(name = "q",
description = "The terms to search. By default the search is performed over term labels, synonyms, descriptions, identifiers and annotation properties.",
example = "disease or liver+disease") String query,
+ @RequestParam(value = "schema", required = false) Collection schemas,
+ @RequestParam(value = "classification", required = false) Collection classifications,
@RequestParam(value = "ontology", required = false)
@Parameter(name = "ontology",
description = "Restrict a search to a set of ontologies e.g. ontology=efo,bfo",
example = "efo,bfo") Collection ontologies,
+ @Parameter(description = "Set to true (default setting is false) for intersection (default behavior is union) of classifications.")
+ @RequestParam(value = "exclusive", required = false, defaultValue = "false") boolean exclusive,
+ @Parameter(description = "Use License option to filter based on license.label, license.logo and license.url variables. " +
+ "Use Composite Option to filter based on the objects (i.e. collection, subject) within the classifications variable. " +
+ "Use Linear option to filter based on String and Collection based variables.")
+ @RequestParam(value = "option", required = false, defaultValue = "LINEAR") FilterOption filterOption,
@RequestParam(value = "type", required = false)
@Parameter(name = "type",
description = "Restrict a search to an entity type, one of {class,property,individual,ontology}",
@@ -122,6 +132,8 @@ public void search(
HttpServletResponse response
) throws IOException, SolrServerException {
+ ontologies = ontologyRepository.filterOntologyIDs(schemas,classifications,ontologies,exclusive,filterOption,lang);
+
final SolrQuery solrQuery = new SolrQuery(); // 1
if (queryFields == null) {
@@ -195,7 +207,7 @@ public void search(
if (groupField != null) {
solrQuery.addFilterQuery("{!collapse field=iri}");
- solrQuery.add("expand=true", "true");
+ solrQuery.add("expand", "true");
solrQuery.add("expand.rows", "100");
}
@@ -262,7 +274,8 @@ public void search(
QueryResponse qr = solrClient.dispatchSearch(solrQuery, "ols4_entities");
- List