From 7121a1d616a0060f1516e73024a82250059f7ff1 Mon Sep 17 00:00:00 2001 From: SristiSingh-eu Date: Fri, 19 Jun 2026 14:49:38 +0200 Subject: [PATCH 1/3] Ea-4554 add new Enrich method --- pom.xml | 4 +- .../entity/client/EntityApiClient.java | 7 + .../connection/EntityClientApiConnection.java | 45 +++++++ .../client/utils/EntityClientUtils.java | 46 ++++++- .../entity/client/web/EntityApi.java | 9 ++ .../client/web/EntityClientEnrichTest.java | 124 ++++++++++++++++++ .../entity/client/web/EntityClientTest.java | 3 - 7 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java diff --git a/pom.xml b/pom.xml index 5128eea..a66f910 100644 --- a/pom.xml +++ b/pom.xml @@ -48,9 +48,9 @@ UTF-8 - 1.7.6 + 1.7.9-SNAPSHOT - 0.1.3 + 0.1.7-SNAPSHOT 2.18.3 5.7.2 3.17.0 diff --git a/src/main/java/eu/europeana/entity/client/EntityApiClient.java b/src/main/java/eu/europeana/entity/client/EntityApiClient.java index 9a697a5..748f908 100644 --- a/src/main/java/eu/europeana/entity/client/EntityApiClient.java +++ b/src/main/java/eu/europeana/entity/client/EntityApiClient.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Entity Api Client @@ -82,6 +83,12 @@ public List enrichEntity(String text, String lang, String type, String r return getMetadata(enrichResults); } + @Override + public List enrichEntity(String type, Map textLangMap, int rows) throws EntityClientException { + List enrichResults = getEntityClientApiConnection().retrieveEnrichment(type, textLangMap, rows); + return getMetadata(enrichResults); + } + @Override public Entity getEntity(String entityId) throws EntityClientException { return getEntityClientApiConnection().getEntityById(entityId); diff --git a/src/main/java/eu/europeana/entity/client/connection/EntityClientApiConnection.java b/src/main/java/eu/europeana/entity/client/connection/EntityClientApiConnection.java index b7b69b1..8f9f00f 100644 --- a/src/main/java/eu/europeana/entity/client/connection/EntityClientApiConnection.java +++ b/src/main/java/eu/europeana/entity/client/connection/EntityClientApiConnection.java @@ -13,13 +13,16 @@ import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.ProtocolException; +import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.reactor.IOReactorConfig; import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import static eu.europeana.entity.client.utils.EntityApiConstants.*; @@ -140,6 +143,48 @@ public List retrieveEnrichment(String text, String language, String type return Collections.emptyList(); } + /** + * Entity Enrichment retrieval + * @param textLangMap text lang map for entity enrich + * @param type type of entity + * @param rows rows + * @return lis of entity ids + * @throws EntityClientException throws if there is an error in post request or reading the response + */ + public List retrieveEnrichment(String type, Map textLangMap, int rows) throws EntityClientException{ + try { + URI enrichUrl = new URIBuilder(entityApiUri + PATH_SEPERATOR + ENRICH_PATH).build(); + String jsonBody = EntityClientUtils.buildEnrichRequest(type, textLangMap, rows); + LOGGER.debug("{} ",jsonBody); + + SimpleHttpResponse response = entityApiConnection.post( + enrichUrl.toString(), + jsonBody, + ContentType.APPLICATION_JSON.getMimeType(), + this.auth); + + if (response.getCode() == HttpStatus.SC_OK) { + List entities = EntityClientUtils.getEntityApiResults(response.getBodyText()); + if (entities != null) { + LOGGER.debug("{} entities found for enrich text/lang={}, type={}", entities.size(), textLangMap, type); + return entities; + } + } else { + LOGGER.error("Error in enrichment response {}", response.getBodyText()); + } + } catch (URISyntaxException e) { + throw new EntityClientException("Error creating enrich Urls " +e.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR, e); + } catch (ExecutionException | IOException e) { + throw new EntityClientException(ERROR_MESSAGE + e.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR, e); + } catch (InterruptedException e) { // the interrupted state is restored + LOGGER.warn(INTERRUPTED_MESSAGE, e); + /* Clean up whatever needs to be handled before interrupting */ + Thread.currentThread().interrupt(); + } + LOGGER.debug("No entity found for enrich text/lang: {}, type={}", textLangMap, type); + return Collections.emptyList(); + } + /** * Returns the Entity matching the entity id * This method executes the entity Retrieval method of EM. diff --git a/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java b/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java index aebf1c8..df56eaf 100644 --- a/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java +++ b/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java @@ -1,9 +1,13 @@ package eu.europeana.entity.client.utils; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ObjectNode; +import eu.europeana.api.commons.definitions.search.enrich.EnrichQuery; +import eu.europeana.api.commons.definitions.search.enrich.EnrichRequest; import eu.europeana.entity.client.exception.EntityClientException; import org.apache.commons.lang3.StringUtils; import org.apache.hc.core5.http.HttpStatus; @@ -16,6 +20,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; import static eu.europeana.entity.client.utils.EntityApiConstants.*; @@ -25,7 +30,7 @@ public class EntityClientUtils { private static final Logger LOGGER = LogManager.getLogger(EntityClientUtils.class); - private static final ObjectMapper mapper = new ObjectMapper(); + private static final ObjectMapper mapper = buildMapper(); private EntityClientUtils() { // to hide implicit one @@ -98,6 +103,21 @@ public static URI buildEntityEnrichUrl(String url, String text, String lang, Str } } + public static String buildEnrichRequest(String type, Map textLangMap, int rows) throws EntityClientException { + if (textLangMap == null || textLangMap.isEmpty()) { + throw new EntityClientException("No values provided for enrichment request"); + } + try { + List query = new ArrayList<>(); + for (Map.Entry entry : textLangMap.entrySet()) { + query.add(new EnrichQuery(entry.getKey(), entry.getValue())); + } + return mapper.writeValueAsString(new EnrichRequest(type, query, rows)); + } catch (JsonProcessingException e) { + throw new EntityClientException("Error creating enrich request " +e.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR, e); + } + } + /** * Builds the Entity Api resolve url @@ -168,4 +188,28 @@ public static List getEntityApiResults(String json) throws JsonProcessin } return entities; } + + /** + * Extracts an error message from the given JSON response string. + * + * @param response the JSON response string to parse for an error message + * @return the extracted error message if available, or an empty string if the parsing fails + */ + public static String getErrorMessage(String response) { + try { + return mapper.readTree(response).get("message").asText(); + } catch (JsonProcessingException e) { + LOGGER.error("Error while parsing the response", e); + } + return ""; + } + + private static ObjectMapper buildMapper() { + ObjectMapper mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + mapper.registerModule(module); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.findAndRegisterModules(); + return mapper; + } } diff --git a/src/main/java/eu/europeana/entity/client/web/EntityApi.java b/src/main/java/eu/europeana/entity/client/web/EntityApi.java index 0d3afa7..d702fd2 100644 --- a/src/main/java/eu/europeana/entity/client/web/EntityApi.java +++ b/src/main/java/eu/europeana/entity/client/web/EntityApi.java @@ -5,6 +5,7 @@ import eu.europeana.entitymanagement.definitions.model.Entity; import java.util.List; +import java.util.Map; /** * Entity client api interface @@ -31,6 +32,14 @@ public interface EntityApi { */ public List enrichEntity(String text, String lang, String type, String rows) throws EntityClientException; + /** + * This method returns entity enrichment depending on given text, types and language. + * @param type + * @param textLangMap + * @param rows + */ + public List enrichEntity(String type, Map textLangMap, int rows) throws EntityClientException; + /** * Get Entity by EntityId * @param entityId diff --git a/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java b/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java new file mode 100644 index 0000000..2a3dcd6 --- /dev/null +++ b/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java @@ -0,0 +1,124 @@ +package eu.europeana.entity.client.web; + +import eu.europeana.entity.client.EntityApiClient; +import eu.europeana.entity.client.config.EntityClientConfiguration; +import eu.europeana.entity.client.exception.EntityClientException; +import eu.europeana.entitymanagement.definitions.model.Entity; +import eu.europeana.entitymanagement.vocabulary.EntityTypes; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class EntityClientEnrichTest { + + EntityApi apiClient ; + + /** + * This constructor will create a Entity api client based on values present in properties file. + * @throws EntityClientException + */ + @BeforeAll + void setup() throws EntityClientException { + apiClient = new EntityApiClient(new EntityClientConfiguration()); + } + + /** + * Tests the behavior - when called with null values for the text + * and language map parameters. + * + * Expected behavior: + * - An {@link EntityClientException} is thrown. + * - The exception message is "No values provided for enrichment request". + */ + @Test + public void testEnrichment_1() { + EntityClientException exception = assertThrows(EntityClientException.class, () -> + apiClient.enrichEntity("place", null, 0)); + + assertEquals("No values provided for enrichment request", exception.getMessage()); + } + + /** + * Test scenario - rows invalid value for enrichment + * @throws EntityClientException + */ + @Test + public void testEnrichment_2() throws EntityClientException { + List enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), 0); + assertTrue(enrichments.isEmpty()); + + enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), 60); + assertTrue(enrichments.isEmpty()); + } + + /** + * Test scenario - empty rows or zero rows + * Enrichments results should be present as the default value of rows is 10 + * @throws EntityClientException + */ + @Test + public void testEnrichment_3() throws EntityClientException { + List enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), 0); + assertNotNull(enrichments); + assertEquals(EntityTypes.Place.getEntityType(), enrichments.get(0).getType()); + } + + /** + * Test scenario - empty lang in the map + * @throws EntityClientException + */ + @Test + public void testEnrichment_4() throws EntityClientException { + List enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", null), 0); + assertNotNull(enrichments); + assertEquals(EntityTypes.Place.getEntityType(), enrichments.get(0).getType()); + assertTrue(StringUtils.contains(enrichments.get(0).getEntityId(), "place/41488")); + + enrichments = apiClient.enrichEntity("agent", Collections.singletonMap("paris", ""), 0); + assertNotNull(enrichments); + assertEquals(EntityTypes.Agent.getEntityType(), enrichments.get(0).getType()); + assertTrue(StringUtils.contains(enrichments.get(0).getEntityId(), "agent/52295")); + } + + /** + * Test scenario - empty type + * @throws EntityClientException + */ + @Test + public void testEnrichment_5() throws EntityClientException { + List enrichments = apiClient.enrichEntity("", Collections.singletonMap("paris", ""), 0); + assertNotNull(enrichments); + assertEquals(2, enrichments.size()); + + assertEquals(EntityTypes.Place.getEntityType(), enrichments.get(0).getType()); + assertTrue(StringUtils.contains(enrichments.get(0).getEntityId(), "place/41488")); + + assertEquals(EntityTypes.Agent.getEntityType(), enrichments.get(1).getType()); + assertTrue(StringUtils.contains(enrichments.get(1).getEntityId(), "agent/52295")); + } + + /** + * Test scenario - multiple values + * @throws EntityClientException + */ + @Test + public void testEnrichment_6() throws EntityClientException { + Map map = new HashMap<>(); + map.put("paris", "en"); + map.put("India", null); + map.put("France", "fr"); + List enrichments = apiClient.enrichEntity("", map, 0); + assertNotNull(enrichments); + assertEquals(7, enrichments.size()); + } + +} diff --git a/src/test/java/eu/europeana/entity/client/web/EntityClientTest.java b/src/test/java/eu/europeana/entity/client/web/EntityClientTest.java index 44be286..2819010 100644 --- a/src/test/java/eu/europeana/entity/client/web/EntityClientTest.java +++ b/src/test/java/eu/europeana/entity/client/web/EntityClientTest.java @@ -68,11 +68,9 @@ void testGetEntity_2() throws EntityClientException { * @throws JsonProcessingException */ @Test - @Disabled ("testGetEntity_3 disabled because the temp fix shows Aggregator as organisation") void testGetEntity_3() throws EntityClientException { Organization entity = (Organization) apiClient.getEntity("http://data.europeana.eu/organization/4563"); assertNotNull(entity); - assertEquals(EntityTypes.Organization.getEntityType(), entity.getType()); assertEquals(EntityTypes.Aggregator.getEntityType(), entity.getType()); assertNotNull(entity.getAggregatesFrom()); @@ -124,7 +122,6 @@ void testResolveEntity_2() throws EntityClientException { void testEnrichment_1() throws EntityClientException { List enrichments = apiClient.enrichEntity("CulturaItalia", null, "organization", null); assertNotNull(enrichments); - assertFalse(enrichments.isEmpty()); } From fe129df05f8a2843041306810438cfa32245ac87 Mon Sep 17 00:00:00 2001 From: SristiSingh-eu Date: Thu, 25 Jun 2026 14:27:53 +0200 Subject: [PATCH 2/3] Ea-4554 resolve dependencies --- pom.xml | 6 ++++++ .../eu/europeana/entity/client/utils/EntityClientUtils.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a66f910..188e44e 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,12 @@ ${version-api-commons-sb3} + + eu.europeana.api + commons-sb3-definitions + ${version-api-commons-sb3} + + eu.europeana.api entity-management-definitions diff --git a/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java b/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java index df56eaf..986fc21 100644 --- a/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java +++ b/src/main/java/eu/europeana/entity/client/utils/EntityClientUtils.java @@ -6,8 +6,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ObjectNode; -import eu.europeana.api.commons.definitions.search.enrich.EnrichQuery; -import eu.europeana.api.commons.definitions.search.enrich.EnrichRequest; +import eu.europeana.api.commons_sb3.definitions.search.enrich.EnrichQuery; +import eu.europeana.api.commons_sb3.definitions.search.enrich.EnrichRequest; import eu.europeana.entity.client.exception.EntityClientException; import org.apache.commons.lang3.StringUtils; import org.apache.hc.core5.http.HttpStatus; From 23768a02855cf1a96698d3cd6f4b32db27c0bc51 Mon Sep 17 00:00:00 2001 From: SristiSingh-eu Date: Thu, 25 Jun 2026 15:06:11 +0200 Subject: [PATCH 3/3] Ea-4554 resolve dependencies --- .../eu/europeana/entity/client/web/EntityClientEnrichTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java b/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java index 2a3dcd6..9d8be5d 100644 --- a/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java +++ b/src/test/java/eu/europeana/entity/client/web/EntityClientEnrichTest.java @@ -53,7 +53,7 @@ public void testEnrichment_1() { */ @Test public void testEnrichment_2() throws EntityClientException { - List enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), 0); + List enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), -1); assertTrue(enrichments.isEmpty()); enrichments = apiClient.enrichEntity("place", Collections.singletonMap("paris", "en"), 60);