diff --git a/src/main/java/eu/dissco/core/translator/component/OrganisationNameComponent.java b/src/main/java/eu/dissco/core/translator/component/OrganisationNameComponent.java index 9ee1998..0ae9c76 100644 --- a/src/main/java/eu/dissco/core/translator/component/OrganisationNameComponent.java +++ b/src/main/java/eu/dissco/core/translator/component/OrganisationNameComponent.java @@ -16,20 +16,19 @@ public class OrganisationNameComponent { private final WebClient webClient; + private static final String NAMES = "names"; + private static final String ORG_NAME_ERROR = "Unable to retrieve organisationName"; @Cacheable("ror") public String getRorName(String ror) throws OrganisationException { log.info("Requesting organisation details for organisation: {} with ror", ror); - String url = "https://api.ror.org/organizations/" + ror; + String url = "https://api.ror.org/v2/organizations/" + ror; var response = webClient.get().uri(url).retrieve().bodyToMono(JsonNode.class) .publishOn(Schedulers.boundedElastic()); try { var json = response.toFuture().get(); if (json != null) { - var name = json.get("name"); - if (name != null) { - return name.asText(); - } + return getRorInstitutionName(json); } } catch (InterruptedException e) { log.error("Failed to make request to RoR service", e); @@ -38,7 +37,28 @@ public String getRorName(String ror) throws OrganisationException { log.error("Failed to make request to RoR service", e); } log.warn("Could not match name to a ROR id for: {}", url); - throw new OrganisationException("Unable to retrieve organisationName"); + throw new OrganisationException(ORG_NAME_ERROR); + } + + private static String getRorInstitutionName(JsonNode rorResult) throws OrganisationException { + try { + if (rorResult.get(NAMES).isArray() && !rorResult.get(NAMES).isEmpty()) { + for (var name : rorResult.get(NAMES)) { + for (var type : name.get("types")) { + if ("ror_display".equals(type.asText())) { + return name.get("value").asText(); + } + } + } + log.warn("No ror display names provided in ROR record. Using first name"); + return rorResult.get(NAMES).get(0).get("value").asText(); + } + log.error("Unable to parse ROR result {}", rorResult); + throw new OrganisationException(ORG_NAME_ERROR); + } catch (NullPointerException e) { + log.error("Unexpected ROR result {}", rorResult, e); + throw new OrganisationException(ORG_NAME_ERROR); + } } @Cacheable("wikidata") @@ -59,6 +79,6 @@ public String getWikiDataName(String wikidata) throws OrganisationException { log.error("Failed to make request to wikidata service", e); } log.warn("Could not match to an English (en) label to a wikidata id for: {}", url); - throw new OrganisationException("Unable to retrieve organisationName"); + throw new OrganisationException(ORG_NAME_ERROR); } } diff --git a/src/test/java/eu/dissco/core/translator/component/OrganisationNameComponentTest.java b/src/test/java/eu/dissco/core/translator/component/OrganisationNameComponentTest.java index 7fd7e89..640892b 100644 --- a/src/test/java/eu/dissco/core/translator/component/OrganisationNameComponentTest.java +++ b/src/test/java/eu/dissco/core/translator/component/OrganisationNameComponentTest.java @@ -1,5 +1,6 @@ package eu.dissco.core.translator.component; +import static eu.dissco.core.translator.TestUtils.MAPPER; import static eu.dissco.core.translator.TestUtils.loadResourceFile; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -7,14 +8,19 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import eu.dissco.core.translator.exception.OrganisationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.reactive.function.client.WebClient; @@ -64,6 +70,63 @@ void testGetRorId() throws Exception { assertThat(result).isEqualTo("The MuseumFactory"); } + @Test + void testGetRorIdFirst() throws Exception { + // Given + givenWebclient(); + given(jsonFuture.get()).willReturn( + mapper.readTree(""" + { + "names": [ + { + "lang": "nl", + "types": [ + "label" + ], + "value": "De MuseumFabriek" + } + ] + } + """)); + + // When + var result = rorComponent.getRorName(ROR); + + // Then + assertThat(result).isEqualTo("De MuseumFabriek"); + } + + @ParameterizedTest + @MethodSource("badRorResponse") + void testBadRorResponse(JsonNode rorResponse) throws Exception { + // Given + givenWebclient(); + given(jsonFuture.get()).willReturn(rorResponse); + + // When / Then + assertThrows(OrganisationException.class, () -> rorComponent.getRorName(ROR)); + + } + + private static Stream badRorResponse() throws JsonProcessingException { + return Stream.of( + Arguments.of( + MAPPER.readTree(""" + { + "names":"De MuseumFabriek" + } + """) + ), + Arguments.of( + MAPPER.readTree(""" + { + "names": ["De MuseumFabriek"] + } + """) + ) + ); + } + @Test void testWikidataId() throws Exception { // Given diff --git a/src/test/resources/organisation-name/example-ror.json b/src/test/resources/organisation-name/example-ror.json index 67797ff..9652c43 100644 --- a/src/test/resources/organisation-name/example-ror.json +++ b/src/test/resources/organisation-name/example-ror.json @@ -1,6 +1,29 @@ { "id": "https://ror.org/03srysw20", - "name": "The MuseumFactory", + "names": [ + { + "lang": null, + "types": [ + "acronym" + ], + "value": "DMF" + }, + { + "lang": "nl", + "types": [ + "label" + ], + "value": "De MuseumFabriek" + }, + { + "lang": "en", + "types": [ + "ror_display", + "label" + ], + "value": "The MuseumFactory" + } + ], "email_address": null, "ip_addresses": [], "established": 2008,